init: initial commit
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
const { getLayout } = require('../../utils/layout');
|
||||
const { api, API_BASE, getImageUrl, uploadFileCompat } = require('../../utils/request');
|
||||
|
||||
var MOOD_OPTIONS = ['😊', '🥰', '😢', '😤', '😴', '🤩', '🥺', '😎', '🤔', '😭', '😋', '😌'];
|
||||
var WEATHER_OPTIONS = ['☀️', '⛅', '☁️', '🌧️', '⛈️', '❄️', '🌤️', '🌥️', '🌈', '🌪️', '🌫️', '🌙'];
|
||||
|
||||
Page({
|
||||
onResize: function() { this.setData(getLayout()); },
|
||||
data: { loading: true, loadError: false,
|
||||
diaryId: 0,
|
||||
form: { title: '', content: '' },
|
||||
tempImages: [],
|
||||
existingImages: [],
|
||||
submitting: false,
|
||||
contentLength: 0
|
||||
},
|
||||
|
||||
onLoad: function(options) {
|
||||
this.setData(getLayout());
|
||||
var id = options.id;
|
||||
if (!id) {
|
||||
wx.showToast({ title: '参数错误', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({ diaryId: parseInt(id) });
|
||||
this.loadDiary();
|
||||
},
|
||||
|
||||
loadDiary: async function() {
|
||||
if (this._pageLoading) return;
|
||||
this._pageLoading = true;
|
||||
this.setData({loading:true, loadError:false});
|
||||
try {
|
||||
var data = await api.diaryDetail(this.data.diaryId);
|
||||
var title = data.title || '';
|
||||
var content = data.content || '';
|
||||
var imgs = data.images || [];
|
||||
if (typeof imgs === 'string') {
|
||||
try { imgs = JSON.parse(imgs); } catch(e) { imgs = []; }
|
||||
}
|
||||
if (!Array.isArray(imgs)) imgs = [];
|
||||
var tempImages = imgs.map(function(p) { return getImageUrl(p); });
|
||||
this.setData({
|
||||
'form.title': title,
|
||||
'form.content': content,
|
||||
'form.lat': data.lat || 0,
|
||||
'form.lng': data.lng || 0,
|
||||
'form.location': data.location || '',
|
||||
tempImages: tempImages,
|
||||
existingImages: imgs,
|
||||
contentLength: content.length
|
||||
});
|
||||
} catch (e) {
|
||||
this.setData({loadError:true});
|
||||
wx.showToast({ title: '加载日记失败', icon: 'none' });
|
||||
}
|
||||
finally { this._pageLoading = false; this.setData({loading:false}); }
|
||||
},
|
||||
|
||||
onTitleInput: function(e) {
|
||||
this.setData({ 'form.title': e.detail.value });
|
||||
},
|
||||
onContentInput: function(e) {
|
||||
var val = e.detail.value || '';
|
||||
this.setData({ 'form.content': val, contentLength: val.length });
|
||||
},
|
||||
|
||||
chooseImages: function() {
|
||||
var self = this;
|
||||
wx.chooseImage({
|
||||
count: 9 - this.data.tempImages.length,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: function(res) {
|
||||
self.setData({ tempImages: self.data.tempImages.concat(res.tempFilePaths) });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ===== 删除单张图片 =====
|
||||
removeImage: function(e) {
|
||||
var index = parseInt(e.currentTarget.dataset.index);
|
||||
var images = this.data.tempImages;
|
||||
var existing = this.data.existingImages;
|
||||
images.splice(index, 1);
|
||||
existing.splice(index, 1);
|
||||
this.setData({ tempImages: images, existingImages: existing });
|
||||
},
|
||||
|
||||
submit: async function() {
|
||||
if (this.data.loading || this.data.loadError) return;
|
||||
if (this.data.submitting) return;
|
||||
var content = this.data.form.content;
|
||||
if (!content || !content.trim()) {
|
||||
wx.showToast({ title: '请填写日记内容', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
this.setData({ submitting: true });
|
||||
|
||||
try {
|
||||
var uploadPaths = [];
|
||||
var existing = this.data.existingImages || [];
|
||||
var temps = this.data.tempImages || [];
|
||||
|
||||
// 判断哪些是新上传的图片(tempFilePaths 以 http 开头的是已有图片,否则是新选的)
|
||||
for (var i = 0; i < temps.length; i++) {
|
||||
var p = temps[i];
|
||||
if (p.indexOf('http') === 0) {
|
||||
// 已有图片,用原始路径
|
||||
uploadPaths.push(existing[i] || '');
|
||||
} else {
|
||||
// 新图片,需要上传
|
||||
wx.showLoading({ title: '上传图片中...' });
|
||||
var res = await this._uploadImage(p);
|
||||
wx.hideLoading();
|
||||
if (res) uploadPaths.push(res);
|
||||
}
|
||||
}
|
||||
|
||||
await api.diaryUpdate({
|
||||
id: this.data.diaryId,
|
||||
title: this.data.form.title || '',
|
||||
content: content.trim(),
|
||||
images: uploadPaths,
|
||||
// 保留原有地理位置(编辑时位置不变)
|
||||
lat: this.data.form.lat || 0,
|
||||
lng: this.data.form.lng || 0,
|
||||
location: this.data.form.location || ''
|
||||
});
|
||||
|
||||
// 清除详情页缓存
|
||||
|
||||
wx.showToast({ title: '修改成功 ✨', icon: 'success' });
|
||||
setTimeout(function() { wx.navigateBack(); }, 1500);
|
||||
} catch (e) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: (e && (e.error || e.message || e.errMsg)) || '修改失败', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ submitting: false });
|
||||
}
|
||||
},
|
||||
|
||||
_uploadImage: async function(filePath) {
|
||||
try {
|
||||
var data = await uploadFileCompat({
|
||||
url: API_BASE + '/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
formData: { sub_dir: 'diaries' }
|
||||
});
|
||||
var path = data && (data.path || data.url || '');
|
||||
if (!path) {
|
||||
// 内容安全检测失败:抛出错误提示用户
|
||||
if (data && data.error) {
|
||||
throw data;
|
||||
}
|
||||
try {
|
||||
var retryData = await uploadFileCompat({
|
||||
url: API_BASE + '/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
formData: { sub_dir: 'diaries' }
|
||||
});
|
||||
path = retryData && (retryData.path || retryData.url || '');
|
||||
} catch(retryErr) {
|
||||
console.error('图片上传重试失败', retryErr);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
} catch(e) {
|
||||
// 内容安全违规错误:直接抛出,中断发布并提示用户
|
||||
if (e && e.error) {
|
||||
throw e;
|
||||
}
|
||||
console.error('图片上传失败', e);
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
goBack: function() {
|
||||
wx.navigateBack();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"disableScroll": true,
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {
|
||||
"app-nav": "/components/app-nav/app-nav",
|
||||
"page-state": "/components/page-state/page-state"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<view class="app-shell app-shell--secondary" style="{{layoutStyle}}">
|
||||
<launch-transition />
|
||||
<app-nav title="编辑日记" back="{{true}}" />
|
||||
<scroll-view class="page-bg" scroll-y show-scrollbar="{{false}}" style="height:100vh;">
|
||||
<view class="container"><page-state wx:if="{{loading}}" kind="loading" title="正在加载日记" /><page-state wx:elif="{{loadError}}" kind="error" title="日记加载失败" action="重试" bind:action="loadDiary" /><block wx:else>
|
||||
<!-- 标题 -->
|
||||
<view class="input-group">
|
||||
<label>标题(选填)</label>
|
||||
<input class="input diary-title-input" placeholder="给日记起个标题..." value="{{form.title}}" bindinput="onTitleInput" maxlength="100" />
|
||||
</view>
|
||||
|
||||
<!-- 内容编辑器(支持换行) -->
|
||||
<view class="input-group editor-group">
|
||||
<view class="editor-header">
|
||||
<label>内容</label>
|
||||
<text class="char-count {{contentLength > 5000 ? 'char-warn' : ''}}">{{contentLength}}/5000</text>
|
||||
</view>
|
||||
<textarea class="input textarea diary-editor" placeholder="想写些什么..." value="{{form.content}}" bindinput="onContentInput" maxlength="5000" auto-height />
|
||||
</view>
|
||||
|
||||
<!-- 图片(可删除) -->
|
||||
<view class="input-group">
|
||||
<view class="editor-header">
|
||||
<label>图片</label>
|
||||
<text class="img-count">{{tempImages.length}}/9</text>
|
||||
</view>
|
||||
<view class="img-picker-row">
|
||||
<view wx:for="{{tempImages}}" wx:key="*this" class="img-picker-wrap">
|
||||
<image class="img-picker-thumb" src="{{item}}" mode="aspectFill" />
|
||||
<view class="img-picker-del" bindtap="removeImage" data-index="{{index}}" hover-class="del-hover">
|
||||
<text>✕</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="img-picker-add" bindtap="chooseImages" wx:if="{{tempImages.length < 9}}">
|
||||
<text class="add-icon">+</text>
|
||||
<text class="add-text">添加图片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button class="btn btn-primary submit-btn" bindtap="submit" hover-class="none" loading="{{submitting}}">保存修改</button>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,142 @@
|
||||
@import '../../styles/common.wxss';
|
||||
|
||||
.container { padding: 84rpx 32rpx 300rpx; }
|
||||
page { background: linear-gradient(180deg, #F4E2E3 0%, #FAF5EE 55%, #FAF5EE 100%); height: 100vh; overflow: hidden; }
|
||||
|
||||
/* ===== 输入框美化 ===== */
|
||||
.input-group { margin-bottom: 36rpx; }
|
||||
.input-group label {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
color: #888;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 28rpx 32rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.input:focus {
|
||||
border-color: #FF6B81;
|
||||
box-shadow: 0 0 0 6rpx rgba(255,107,129,0.08);
|
||||
}
|
||||
.textarea {
|
||||
min-height: 200rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* ===== 日记标题输入框 ===== */
|
||||
.diary-title-input {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
padding: 28rpx 32rpx;
|
||||
}
|
||||
|
||||
/* ===== 编辑器头部(标签+计数) ===== */
|
||||
.editor-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.editor-header label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.char-count {
|
||||
font-size: 22rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
.char-warn {
|
||||
color: #ff6b6b;
|
||||
font-weight: 600;
|
||||
}
|
||||
.img-count {
|
||||
font-size: 22rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
/* ===== 日记编辑器 ===== */
|
||||
.diary-editor {
|
||||
min-height: 300rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 1.7;
|
||||
padding: 28rpx 32rpx;
|
||||
}
|
||||
|
||||
/* ===== 图片选择(可删除) ===== */
|
||||
.img-picker-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.img-picker-wrap {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: visible;
|
||||
}
|
||||
.img-picker-thumb {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #eee;
|
||||
}
|
||||
.img-picker-del {
|
||||
position: absolute;
|
||||
top: -12rpx;
|
||||
right: -12rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,71,87,0.9);
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(255,71,87,0.3);
|
||||
z-index: 2;
|
||||
}
|
||||
.del-hover {
|
||||
transform: scale(1.2);
|
||||
background: #ff4757;
|
||||
}
|
||||
.img-picker-add {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
border: 2rpx dashed #ddd;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6rpx;
|
||||
}
|
||||
.img-picker-add .add-icon {
|
||||
font-size: 48rpx;
|
||||
color: #ccc;
|
||||
line-height: 1;
|
||||
}
|
||||
.img-picker-add .add-text {
|
||||
font-size: 20rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* ===== 提交按钮 ===== */
|
||||
.submit-btn {
|
||||
margin-top: 40rpx;
|
||||
margin-bottom: 80rpx;
|
||||
}
|
||||
|
||||
@import '../../styles/design.wxss';
|
||||
|
||||
@import '../../styles/journal.wxss';
|
||||
Reference in New Issue
Block a user