feat: migrate to PostgreSQL GORM and MinIO file storage

Use UUID models and soft deletion, persist file relationships with deduplicated monthly MinIO objects, and add admin file management. Update mini-program media handling and add local dev configuration.
This commit is contained in:
2026-11-01 11:48:45 +08:00
parent 0530523750
commit 4934a69581
94 changed files with 4686 additions and 2147 deletions
+16 -87
View File
@@ -1,3 +1,4 @@
const { uploadReference } = require('../../utils/file-media');
const { getLayout } = require('../../utils/layout');
// pages/publish/publish.js - 统一发布页(增强版编辑器)
const { api, API_BASE, uploadFileCompat } = require('../../utils/request');
@@ -50,7 +51,7 @@ Page({
onLoad: function(options) {
this.setData(getLayout());
var type = options.type || 'timeline';
var editId = options.edit ? parseInt(options.edit) : 0;
var editId = options.edit ? String(options.edit) : "";
var cfg = TYPE_CONFIG[type] || TYPE_CONFIG['timeline'];
var titleText = editId ? '编辑事件' : cfg.title;
var btnText = editId ? '保存修改' : cfg.btn;
@@ -173,7 +174,7 @@ Page({
repeat_unit: item.repeat_unit || ''
};
// 加载背景图
var bgPath = item.bg_image || '';
var bgPath = item.bg_image_file_id || item.bg_image || '';
var bgUrl = bgPath ? require('../../utils/request').getImageUrl(bgPath) : '';
var repeatOptionIdx = 0;
if (form.repeat_interval > 0 && form.repeat_unit) {
@@ -384,9 +385,8 @@ Page({
name: 'file',
formData: { sub_dir: 'timeline_bg' }
});
bgImagePath = uploadRes && (uploadRes.path || uploadRes.url || '');
} catch(e) {}
wx.hideLoading();
bgImagePath = uploadReference(uploadRes);
} finally { wx.hideLoading(); }
}
var result;
if (editId) {
@@ -451,93 +451,22 @@ Page({
},
_uploadAlbumCover: async function(filePath) {
try {
var data = await uploadFileCompat({
url: API_BASE + '/upload',
filePath: filePath,
name: 'file',
formData: { sub_dir: 'albums' }
});
// 兼容不同响应格式:{path:'...'} 或 {success:true, path:'...'} 或 {url:'...'}
var path = data && (data.path || data.url || '');
if (!path) {
// 内容安全检测失败:抛出错误提示用户
if (data && data.error) {
throw data;
}
console.error('封面上传返回无路径', JSON.stringify(data), '错误码:', data && data.code);
// 尝试重新上传一次
try {
var retryData = await uploadFileCompat({
url: API_BASE + '/upload',
filePath: filePath,
name: 'file',
formData: { sub_dir: 'albums' }
});
var retryPath = retryData && (retryData.path || retryData.url || '');
if (retryPath) {
console.log('封面上传重试成功');
return retryPath;
}
} catch(retryErr) {
console.error('封面上传重试也失败', retryErr, '错误码:', retryErr && retryErr.code);
}
}
return path;
} catch(e) {
// 内容安全违规错误:直接抛出,中断发布并提示用户
if (e && e.error) {
throw e;
}
console.error('封面上传失败', e, '错误码:', e && e.code);
return '';
}
return this._uploadMedia(filePath, 'albums');
},
_uploadDiaryImage: async function(filePath) {
try {
var data = await uploadFileCompat({
url: API_BASE + '/upload',
filePath: filePath,
name: 'file',
formData: { sub_dir: 'diaries' }
});
// 兼容不同响应格式:{path:'...'} 或 {success:true, path:'...'} 或 {url:'...'}
var path = data && (data.path || data.url || '');
if (!path) {
// 内容安全检测失败:抛出错误提示用户
if (data && data.error) {
throw data;
}
console.error('日记图片上传返回无路径', JSON.stringify(data), '错误码:', data && data.code);
// 尝试重新上传一次
try {
var retryData = await uploadFileCompat({
url: API_BASE + '/upload',
filePath: filePath,
name: 'file',
formData: { sub_dir: 'diaries' }
});
var retryPath = retryData && (retryData.path || retryData.url || '');
if (retryPath) {
console.log('日记图片重试上传成功');
return retryPath;
}
} catch(retryErr) {
console.error('日记图片重试上传也失败', retryErr, '错误码:', retryErr && retryErr.code);
}
}
return path;
} catch(e) {
// 内容安全违规错误:直接抛出,中断发布并提示用户
if (e && e.error) {
throw e;
}
console.error('日记图片上传失败', e, '错误码:', e && e.code);
return '';
}
return this._uploadMedia(filePath, 'diaries');
},
_uploadMedia: async function(filePath, subDir) {
var data = await uploadFileCompat({
url: API_BASE + '/upload',
filePath: filePath,
name: 'file',
formData: { sub_dir: subDir }
});
return uploadReference(data);
},
// ===== 背景图 =====
chooseBgImage: function() {
var self = this;