// pages/main/journal-creater/index.ts import Events from "../../../utils/Events"; import Time from "../../../utils/Time"; import Toolkit from "../../../utils/Toolkit"; import config from "../../../config/index"; enum MediaItemType { IMAGE, VIDEO } type MediaItem = { type: MediaItemType; path: string; thumbPath: string; size: number; duration: number | undefined; raw: any; } export type Location = { lat: number; lng: number; text?: string; } interface JournalEditorData { idea: string; date: string; time: string; mediaList: MediaItem[]; location?: Location; qqMapSDK?: any; isAuthLocation: boolean; } Page({ data: { idea: "", date: "2025-06-28", time: "16:00", mediaList: [], location: undefined, submitText: "提交", isSubmitting: false, submitProgress: 0, mediaItemTypeEnum: { ...MediaItemType }, isAuthLocation: false }, async onLoad() { // 授权定位 const setting = await wx.getSetting(); wx.setStorageSync("isAuthLocation", setting.authSetting["scope.userLocation"]); let isAuthLocation = JSON.parse(wx.getStorageSync("isAuthLocation")); this.setData({ isAuthLocation }); if (!isAuthLocation) { wx.authorize({ scope: "scope.userLocation" }).then(() => { isAuthLocation = true; this.setData({ isAuthLocation }); }); } const unixTime = new Date().getTime(); this.setData({ date: Time.toDate(unixTime), time: Time.toTime(unixTime) }); // 获取默认定位 wx.getLocation({ type: "gcj02" }).then(resp => { this.setData({ location: { lat: resp.latitude, lng: resp.longitude }, }); const argLoc = `location=${this.data.location!.lat},${this.data.location!.lng}`; const argKey = "key=WW5BZ-J4LCM-UIT6I-65MXY-Z5HDT-VRFFU"; wx.request({ url: `https://apis.map.qq.com/ws/geocoder/v1/?${argLoc}&${argKey}`, success: res => { if (res.statusCode === 200) { this.setData({ location: { lat: this.data.location!.lat, lng: this.data.location!.lng, text: (res.data as any).result?.formatted_addresses?.recommend } }); } } }); }); }, async chooseLocation() { const location = await wx.chooseLocation({}); this.setData({ location: { lat: location.latitude, lng: location.longitude, text: location.name } }); }, addMedia() { const that = this; wx.chooseMedia({ mediaType: ["mix"], sourceType: ["album", "camera"], camera: "back", success(res) { wx.showLoading({ title: "加载中..", mask: true }) const tempFiles = res.tempFiles; const mediaList = tempFiles.map(item => { return { type: (MediaItemType)[item.fileType.toUpperCase()], path: item.tempFilePath, thumbPath: item.thumbTempFilePath, size: item.size, duration: item.duration, raw: item } as MediaItem; }); that.setData({ mediaList: [...that.data.mediaList, ...mediaList] }); wx.hideLoading(); } }) }, clearMedia() { wx.showModal({ title: "提示", content: "确认清空已选照片或视频吗?", confirmText: "清空", confirmColor: "#E64340", cancelText: "取消", success: res => { if (res.confirm) { this.setData({ mediaList: [] }); } } }) }, preview(e: WechatMiniprogram.BaseEvent) { wx.previewMedia({ current: e.currentTarget.dataset.index, sources: this.data.mediaList.map(item => { return { url: item.path, type: MediaItemType[item.type].toLowerCase() } as WechatMiniprogram.MediaSource; }) }); }, deleteMedia(e: WechatMiniprogram.BaseEvent) { const index = e.currentTarget.dataset.index; const mediaList = [...this.data.mediaList]; mediaList.splice(index, 1); this.setData({ mediaList }); }, cancel() { wx.switchTab({ url: "/pages/main/journal/index", }) }, submit() { const handleFail = () => { wx.showToast({ title: "上传失败", icon: "error" }); this.setData({ submitText: "提交", isSubmitting: false }) }; this.setData({ submitText: "正在提交..", isSubmitting: true }) // 获取 openId const getOpenId = new Promise((resolve, reject) => { wx.login({ success: (res) => { if (res.code) { wx.request({ url: `${config.url}/journal/openid`, method: "POST", header: { Key: wx.getStorageSync("key") }, data: { code: res.code }, success: (resp) => { const data = resp.data as any; if (data.code === 20000) { resolve(data.data); } else { reject(new Error("获取 openId 失败")); } }, fail: () => reject(new Error("获取 openId 请求失败")) }); } else { reject(new Error("获取登录凭证失败")); } }, fail: () => reject(new Error("登录失败")) }); }); // 文件上传 const uploadFiles = new Promise((resolve, reject) => { const mediaList = this.data.mediaList || []; const total = mediaList.length; let completed = 0; if (total === 0) { resolve([]); return; } // 更新进度初始状态 this.setData({ submitProgress: 0, }); const uploadPromises = mediaList.map((item) => { return new Promise((uploadResolve, uploadReject) => { wx.uploadFile({ url: `${config.url}/temp/file/upload`, filePath: item.path, name: "file", success: (resp) => { const result = JSON.parse(resp.data); if (result && result.code === 20000) { completed++; // 更新进度 this.setData({ submitProgress: (completed / total), }); uploadResolve(result.data[0].id); } else { uploadReject(new Error(`文件上传失败: ${result?.message || '未知错误'}`)); } }, fail: (err) => uploadReject(new Error(`文件上传失败: ${err.errMsg}`)) }); }); }); // 并行执行所有文件上传 Promise.all(uploadPromises).then((tempFileIds) => { this.setData({ submitProgress: 1, }); resolve(tempFileIds); }).catch(reject); }); // 并行执行获取 openId 和文件上传 Promise.all([getOpenId, uploadFiles]).then(([openId, tempFileIds]) => { wx.request({ url: `${config.url}/journal/create`, method: "POST", header: { Key: wx.getStorageSync("key") }, data: { type: "NORMAL", idea: this.data.idea, createdAt: Date.parse(`${this.data.date} ${this.data.time}`), lat: this.data.location?.lat, lng: this.data.location?.lng, location: this.data.location?.text, pusher: openId, tempFileIds }, success: async (resp: any) => { Events.emit("JOURNAL_REFRESH"); wx.showToast({ title: "提交成功", icon: "success" }); this.setData({ idea: "", mediaList: [], submitText: "提交", isSubmitting: false, }); await Toolkit.sleep(1000); wx.switchTab({ url: "/pages/main/journal/index", }) }, fail: handleFail }); }).catch(handleFail); } });