Files
gaoYuJournal/miniprogram/pages/main/journal-editor/index.ts
2025-12-11 00:46:11 +08:00

393 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// pages/main/journal-editor/index.ts
import Events from "../../../utils/Events";
import Time from "../../../utils/Time";
import Toolkit from "../../../utils/Toolkit";
import config from "../../../config/index";
import { Location, MediaItem, MediaItemType, WechatMediaItem } from "../../../types/UI";
import { Journal, JournalType } from "../../../types/Journal";
import { MediaAttachExt, MediaAttachType } from "../../../types/Attachment";
interface JournalEditorData {
id?: number;
idea: string;
date: string;
time: string;
type: JournalType;
mediaList: MediaItem[];
newMediaList: WechatMediaItem[];
location?: Location;
isAuthLocation: boolean;
isLoading: boolean;
saveText: string;
isSaving: boolean;
saveProgress: number;
mediaItemTypeEnum: any;
deleteDialogVisible: boolean;
deleteConfirmText: string;
}
Page({
data: <JournalEditorData>{
id: undefined,
idea: "",
date: "2025-06-28",
time: "16:00",
type: JournalType.NORMAL,
mediaList: [],
newMediaList: [],
location: undefined,
saveText: "保存",
isSaving: false,
saveProgress: 0,
isLoading: true,
mediaItemTypeEnum: {
...MediaItemType
},
isAuthLocation: false,
deleteDialogVisible: false,
deleteConfirmText: ""
},
async onLoad(options: any) {
// 授权定位
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 });
});
}
// 获取日记 ID
const id = options.id ? parseInt(options.id) : undefined;
if (!id) {
wx.showToast({
title: "缺少日志 ID",
icon: "error"
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
return;
}
this.setData({ id });
await this.loadJournalDetail(id);
},
/** 加载日记详情 */
async loadJournalDetail(id: number) {
wx.showLoading({ title: "加载中...", mask: true });
try {
const journal: Journal = await new Promise((resolve, reject) => {
wx.request({
url: `${config.url}/journal/${id}`,
method: "POST",
header: {
Key: wx.getStorageSync("key")
},
success: (res: any) => {
if (res.data.code === 20000) {
resolve(res.data.data);
} else {
reject(new Error(res.data.message || "加载失败"));
}
},
fail: reject
});
});
const items = journal.items || [];
const thumbItems = items.filter((item) => item.attachType === MediaAttachType.THUMB);
const mediaList: MediaItem[] = thumbItems.map((thumbItem) => {
const ext = thumbItem.ext = JSON.parse(thumbItem.ext!.toString()) as MediaAttachExt;
const thumbURL = `${config.url}/attachment/read/${thumbItem.mongoId}`;
const sourceURL = `${config.url}/attachment/read/${ext.sourceMongoId}`;
return {
type: ext.isVideo ? MediaItemType.VIDEO : MediaItemType.IMAGE,
thumbURL,
sourceURL,
size: thumbItem.size || 0,
attachmentId: thumbItem.id
} as MediaItem;
});
this.setData({
idea: journal.idea || "",
date: Time.toDate(journal.createdAt),
time: Time.toTime(journal.createdAt),
type: journal.type,
location: journal.location ? {
lat: journal.lat,
lng: journal.lng,
text: journal.location
} : undefined,
mediaList,
isLoading: false
});
wx.hideLoading();
} catch (err: any) {
wx.hideLoading();
wx.showToast({
title: err.message || "加载失败",
icon: "error"
});
setTimeout(() => {
wx.navigateBack();
}, 1500);
}
},
onChangeType(e: any) {
const { value } = e.detail;
this.setData({ type: value });
},
/** 选择位置 */
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 newMedia = tempFiles.map(item => {
return {
type: (<any>MediaItemType)[item.fileType.toUpperCase()],
path: item.tempFilePath,
thumbPath: item.thumbTempFilePath,
size: item.size,
duration: item.duration,
raw: item
} as WechatMediaItem;
});
that.setData({
newMediaList: [...that.data.newMediaList, ...newMedia]
});
wx.hideLoading();
}
});
},
/** 预览附件 */
preview(e: WechatMiniprogram.BaseEvent) {
const isNewMedia = e.currentTarget.dataset.newMedia;
const index = e.currentTarget.dataset.index;
const sources = this.data.mediaList.map(item => ({
url: item.sourceURL,
type: MediaItemType[item.type].toLowerCase()
}));
const newSources = this.data.newMediaList.map(item => ({
url: item.path,
type: MediaItemType[item.type].toLowerCase()
}));
const allSources = [...sources, ...newSources];
const currentIndex = isNewMedia ? this.data.mediaList.length + index : index;
wx.previewMedia({
current: currentIndex,
sources: allSources as WechatMiniprogram.MediaSource[]
});
},
/** 删除附件 */
deleteMedia(e: WechatMiniprogram.BaseEvent) {
const isNewMedia = e.currentTarget.dataset.newMedia;
const index = e.currentTarget.dataset.index;
if (isNewMedia) {
const mediaList = [...this.data.mediaList];
mediaList.splice(index, 1);
this.setData({ mediaList });
} else {
const newMediaList = [...this.data.newMediaList];
newMediaList.splice(index, 1);
this.setData({ newMediaList });
}
},
/** 取消编辑 */
cancel() {
wx.navigateBack();
},
/** 删除记录 */
deleteJournal() {
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();
},
/** 执行删除 */
executeDelete() {
wx.showLoading({ title: "删除中...", mask: true });
wx.request({
url: `${config.url}/journal/delete`,
method: "POST",
header: {
Key: wx.getStorageSync("key"),
"Content-Type": "application/json"
},
data: {
id: this.data.id
},
success: (res: any) => {
wx.hideLoading();
if (res.data.code === 20000 || res.statusCode === 200) {
Events.emit("JOURNAL_REFRESH");
Events.emit("JOURNAL_LIST_REFRESH");
wx.showToast({
title: "删除成功",
icon: "success"
});
setTimeout(() => {
wx.navigateBack();
}, 1000);
} else {
wx.showToast({
title: res.data.message || "删除失败",
icon: "error"
});
}
},
fail: () => {
wx.hideLoading();
wx.showToast({
title: "删除失败",
icon: "error"
});
}
});
},
/** 保存 */
save() {
const handleFail = () => {
wx.showToast({ title: "保存失败", icon: "error" });
this.setData({
saveText: "保存",
isSaving: false
});
};
this.setData({
saveText: "正在保存..",
isSaving: true
});
// 收集保留的附件 ID缩略图 ID
const attachmentIds = this.data.mediaList.map(item => item.attachmentId);
// 上传新媒体文件
const uploadFiles = new Promise<string[]>((resolve, reject) => {
const total = this.data.newMediaList.length;
let completed = 0;
if (total === 0) {
resolve([]);
return;
}
this.setData({
saveProgress: 0,
});
// 上传临时文件
const uploadPromises = this.data.newMediaList.map((item) => {
return new Promise<string>((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({
saveProgress: (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({
saveProgress: 1,
});
resolve(tempFileIds);
}).catch(reject);
});
// 提交保存
uploadFiles.then((tempFileIds) => {
wx.request({
url: `${config.url}/journal/update`,
method: "POST",
header: {
Key: wx.getStorageSync("key")
},
data: {
id: this.data.id,
idea: this.data.idea,
type: this.data.type,
lat: this.data.location?.lat,
lng: this.data.location?.lng,
location: this.data.location?.text,
createdAt: new Date(`${this.data.date}T${this.data.time}:00`).getTime(),
// 保留的现有附件 ID
attachmentIds,
// 新上传的临时文件 ID
tempFileIds
},
success: async (resp: any) => {
if (resp.data.code === 20000 || resp.statusCode === 200) {
Events.emit("JOURNAL_REFRESH");
Events.emit("JOURNAL_LIST_REFRESH");
wx.showToast({ title: "保存成功", icon: "success" });
this.setData({
saveText: "保存",
isSaving: false,
});
await Toolkit.sleep(1000);
wx.navigateBack();
} else {
handleFail();
}
},
fail: handleFail
});
}).catch(handleFail);
}
});