You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
12 KiB
510 lines
12 KiB
<template>
|
|
<view class="publish-container">
|
|
<!-- 内容区域 -->
|
|
<view class="content-scroll">
|
|
<!-- 图片区域 -->
|
|
<view class="image-section">
|
|
<uni-file-picker
|
|
v-model="selectedImages"
|
|
mode="grid"
|
|
file-mediatype="image"
|
|
file-extname="png,jpg,jpeg"
|
|
:auto-upload="false"
|
|
@select="onImageSelect"
|
|
@delete="onImageDelete"
|
|
></uni-file-picker>
|
|
</view>
|
|
|
|
<!-- 标题区域 -->
|
|
<view class="title-section">
|
|
<input
|
|
class="title-input"
|
|
v-model="noteForm.title"
|
|
placeholder="请输入标题..."
|
|
maxlength="100"
|
|
auto-height
|
|
/>
|
|
</view>
|
|
|
|
<!-- 详情区域 -->
|
|
<view class="content-section">
|
|
<textarea
|
|
class="content-input"
|
|
v-model="noteForm.content"
|
|
placeholder="分享你的想法..."
|
|
maxlength="2000"
|
|
auto-height
|
|
/>
|
|
</view>
|
|
|
|
<!-- 快速标签区域 -->
|
|
<view class="quick-tags-section">
|
|
<view class="section-title">快速标签</view>
|
|
<scroll-view
|
|
class="quick-tags-scroll"
|
|
scroll-x="true"
|
|
show-scrollbar="false"
|
|
>
|
|
<view class="quick-tags-list">
|
|
<view
|
|
class="quick-tag-item"
|
|
v-for="tag in quickTags"
|
|
:key="tag"
|
|
@click="insertQuickTag(tag)"
|
|
>
|
|
#{{ tag.name }}
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 已添加标签 -->
|
|
<view class="selected-tags-section" v-if="noteForm.tags.length">
|
|
<scroll-view
|
|
class="selected-tags-scroll"
|
|
scroll-x
|
|
:show-scrollbar="false"
|
|
>
|
|
<view class="selected-tags-list">
|
|
<view
|
|
class="selected-tag-item"
|
|
v-for="(tag, index) in noteForm.tags"
|
|
:key="index"
|
|
@click="removeTag(index)"
|
|
>
|
|
<view class="tag-text">#{{ tag.name }}</view>
|
|
<view class="tag-close">×</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 底部占位 -->
|
|
<view class="bottom-placeholder"></view>
|
|
</view>
|
|
|
|
<!-- 底部发布按钮 -->
|
|
<view class="bottom-publish">
|
|
<button class="publish-btn" @click="publishNote">发布笔记</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: "PublishNote",
|
|
data() {
|
|
return {
|
|
selectedImages: [],
|
|
noteForm: {
|
|
title: "",
|
|
content: "",
|
|
tags: [], // 存储选中的标签对象 {id, name}
|
|
images: [],
|
|
},
|
|
quickTags: [], // 从接口获取的标签列表
|
|
imageStyles: {
|
|
height: "200rpx", // 边框高度
|
|
width: "200rpx", // 边框宽度
|
|
},
|
|
};
|
|
},
|
|
computed: {
|
|
canPublish() {
|
|
return (
|
|
(this.noteForm.title.trim() || this.noteForm.content.trim()) &&
|
|
this.selectedImages &&
|
|
this.selectedImages.length > 0
|
|
);
|
|
},
|
|
},
|
|
mounted() {
|
|
this.getTagList();
|
|
},
|
|
methods: {
|
|
// 获取标签列表
|
|
async getTagList() {
|
|
try {
|
|
const res = await this.Post({}, "/framework/tag/list", "DES");
|
|
if (res && res.data) {
|
|
this.quickTags = res.data;
|
|
}
|
|
} catch (error) {
|
|
console.error("获取标签列表失败:", error);
|
|
// 如果接口失败,可以设置默认标签
|
|
this.quickTags = [
|
|
{ id: "1", name: "DES" },
|
|
{ id: "2", name: "AGENT" },
|
|
{ id: "3", name: "时间银行" },
|
|
{ id: "4", name: "阅读体验" },
|
|
{ id: "5", name: "时间力" },
|
|
];
|
|
}
|
|
},
|
|
// 返回上一页
|
|
goBack() {
|
|
if (this.canPublish) {
|
|
uni.showModal({
|
|
title: "确认退出",
|
|
content: "退出后内容将不会保存,确定要退出吗?",
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.navigateBack();
|
|
}
|
|
},
|
|
});
|
|
} else {
|
|
uni.navigateBack();
|
|
}
|
|
},
|
|
|
|
// 图片选择事件
|
|
onImageSelect(e) {
|
|
console.log("选择图片·:", e);
|
|
// selectedImages已经通过v-model自动更新,立即上传新选择的图片
|
|
this.uploadNewImages(e.tempFiles || []);
|
|
},
|
|
|
|
// 图片删除事件
|
|
onImageDelete(e) {
|
|
let index = e.index;
|
|
// selectedImages已经通过v-model自动更新,需要同步更新noteForm.images
|
|
// 根据当前selectedImages的数量来调整noteForm.images
|
|
if (this.noteForm.images && this.noteForm.images.length > index) {
|
|
this.noteForm.images.splice(index, 1);
|
|
}
|
|
},
|
|
|
|
// 插入快速标签
|
|
insertQuickTag(tag) {
|
|
// 检查是否已经添加了该标签
|
|
const existingTag = this.noteForm.tags.find((t) => t.id === tag.id);
|
|
if (!existingTag) {
|
|
this.noteForm.tags.unshift(tag);
|
|
}
|
|
},
|
|
|
|
// 移除标签
|
|
removeTag(index) {
|
|
this.noteForm.tags.splice(index, 1);
|
|
},
|
|
|
|
// 上传单个图片文件
|
|
async uploadSingleImage(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const token = uni.getStorageSync("userInfo")
|
|
? JSON.parse(uni.getStorageSync("userInfo")).token
|
|
: "";
|
|
uni.uploadFile({
|
|
url: this.NEWAPIURL_DES + "/system/oss/upload", // 替换为你的上传接口
|
|
filePath: file.url || file.path,
|
|
name: "file",
|
|
header: {
|
|
token: token || "",
|
|
// 添加必要的请求头,如token等
|
|
},
|
|
success: (res) => {
|
|
console.log(res);
|
|
try {
|
|
const data = JSON.parse(res.data);
|
|
if (data.code === 200) {
|
|
resolve(data.data.url); // 返回服务器返回的图片URL
|
|
} else {
|
|
reject(new Error(data.message || "上传失败"));
|
|
}
|
|
} catch (e) {
|
|
reject(new Error("解析响应失败"));
|
|
}
|
|
},
|
|
fail: (err) => {
|
|
reject(err);
|
|
},
|
|
});
|
|
});
|
|
},
|
|
|
|
// 上传新选择的图片
|
|
async uploadNewImages(newFiles) {
|
|
if (!newFiles || newFiles.length === 0) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
uni.showLoading({ title: "上传图片中..." });
|
|
|
|
const uploadPromises = newFiles.map((file) =>
|
|
this.uploadSingleImage(file)
|
|
);
|
|
const uploadedUrls = await Promise.all(uploadPromises);
|
|
|
|
// 将上传成功的URL添加到noteForm.images中
|
|
this.noteForm.images = [
|
|
...(this.noteForm.images || []),
|
|
...uploadedUrls,
|
|
];
|
|
uni.hideLoading();
|
|
} catch (error) {
|
|
uni.hideLoading();
|
|
uni.showToast({
|
|
title: error.message || "图片上传失败",
|
|
icon: "none",
|
|
});
|
|
}
|
|
},
|
|
|
|
// 批量上传图片(保留原方法,用于其他场景)
|
|
async uploadImages() {
|
|
if (!this.selectedImages || this.selectedImages.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const uploadPromises = this.selectedImages.map((file) =>
|
|
this.uploadSingleImage(file)
|
|
);
|
|
|
|
try {
|
|
const uploadedUrls = await Promise.all(uploadPromises);
|
|
return uploadedUrls;
|
|
} catch (error) {
|
|
throw new Error("图片上传失败: " + error.message);
|
|
}
|
|
},
|
|
|
|
// 发布笔记
|
|
async publishNote() {
|
|
console.log(this.noteForm, "0000");
|
|
if (!this.noteForm.images || this.noteForm.images.length === 0) {
|
|
uni.showToast({
|
|
title: "请至少选择一张图片",
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
if (!this.noteForm.title.trim() && !this.noteForm.content.trim()) {
|
|
uni.showToast({
|
|
title: "请添加标题或内容",
|
|
icon: "none",
|
|
});
|
|
return;
|
|
}
|
|
|
|
try {
|
|
uni.showLoading({ title: "发布中..." });
|
|
// 图片已经在选择时上传,直接提交表单
|
|
await this.submitNote(this.noteForm);
|
|
|
|
uni.hideLoading();
|
|
uni.showToast({
|
|
title: "发布成功",
|
|
icon: "none",
|
|
duration: 2000,
|
|
});
|
|
|
|
// 延迟跳转,让用户看到成功提示
|
|
setTimeout(() => {
|
|
uni.navigateBack();
|
|
}, 800);
|
|
} catch (error) {
|
|
uni.hideLoading();
|
|
uni.showToast({
|
|
title: error.message || "发布失败,请重试",
|
|
icon: "none",
|
|
});
|
|
}
|
|
},
|
|
|
|
// 提交笔记
|
|
async submitNote(noteData) {
|
|
// 格式化数据以符合API要求
|
|
const formData = {
|
|
title: noteData.title,
|
|
content: noteData.content,
|
|
tags: noteData.tags.map((tag) => tag.id).join(","), // 标签ID逗号分隔
|
|
coverImage: noteData.images.join(","), // 图片URL逗号分隔
|
|
method: "POST",
|
|
};
|
|
|
|
return this.Post(formData, "/framework/note/addNote", "DES");
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.publish-container {
|
|
min-height: 100vh;
|
|
background: #fff;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
// 内容区域
|
|
.content-scroll {
|
|
flex: 1;
|
|
padding: 0 30rpx;
|
|
}
|
|
|
|
// 图片区域
|
|
.image-section {
|
|
margin: 32rpx 0;
|
|
padding-bottom: 32rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
// 标题区域
|
|
.title-section {
|
|
margin: 32rpx 0;
|
|
padding-bottom: 32rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
.title-input {
|
|
width: 100%;
|
|
min-height: 60rpx;
|
|
font-size: 36rpx;
|
|
font-weight: 600;
|
|
line-height: 1.4;
|
|
color: #333;
|
|
border: none;
|
|
padding: 0;
|
|
resize: none;
|
|
}
|
|
}
|
|
|
|
// 详情区域
|
|
.content-section {
|
|
margin: 32rpx 0;
|
|
padding-bottom: 32rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
.content-input {
|
|
width: 100%;
|
|
min-height: 300rpx;
|
|
font-size: 28rpx;
|
|
line-height: 1.6;
|
|
color: #333;
|
|
border: none;
|
|
padding: 0;
|
|
resize: none;
|
|
}
|
|
}
|
|
|
|
// 快速标签区域
|
|
.quick-tags-section {
|
|
margin: 24rpx 0;
|
|
|
|
.section-title {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
margin-bottom: 25rpx;
|
|
}
|
|
|
|
.quick-tags-scroll {
|
|
width: 100%;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.quick-tags-list {
|
|
display: inline-flex;
|
|
gap: 16rpx;
|
|
padding-right: 32rpx;
|
|
width: max-content;
|
|
|
|
.quick-tag-item {
|
|
flex-shrink: 0;
|
|
padding: 16rpx 24rpx;
|
|
background: #f8f9fa;
|
|
border-radius: 32rpx;
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
white-space: nowrap;
|
|
|
|
&:active {
|
|
background: #e9ecef;
|
|
transform: scale(0.96);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 已选标签区域
|
|
.selected-tags-section {
|
|
margin: 24rpx 0;
|
|
padding-top: 24rpx;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
|
.selected-tags-scroll {
|
|
width: 100%;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.selected-tags-list {
|
|
display: inline-flex;
|
|
gap: 16rpx;
|
|
padding-right: 32rpx;
|
|
width: max-content;
|
|
|
|
.selected-tag-item {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
padding: 12rpx 20rpx;
|
|
background: linear-gradient(135deg, #fffdb7e6 0%, #97fffab5 100%);
|
|
border-radius: 32rpx;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
|
|
.tag-text {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
}
|
|
|
|
.tag-close {
|
|
font-size: 24rpx;
|
|
color: #333;
|
|
opacity: 0.8;
|
|
margin-left: 8rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 底部发布按钮
|
|
.bottom-publish {
|
|
padding: 24rpx 32rpx;
|
|
background: #fff;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
padding-bottom: max(24rpx, env(safe-area-inset-bottom));
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
.publish-btn {
|
|
width: 100%;
|
|
height: 88rpx;
|
|
color: #333333;
|
|
border-radius: 44rpx;
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
border: none;
|
|
transition: all 0.3s ease;
|
|
background: linear-gradient(135deg, #fffdb7e6 0%, #97fffab5 100%);
|
|
&:disabled {
|
|
background: linear-gradient(135deg, #ccc 0%, #ccc 100%);
|
|
}
|
|
|
|
&:not(:disabled):active {
|
|
transform: scale(0.98);
|
|
}
|
|
}
|
|
}
|
|
|
|
.bottom-placeholder {
|
|
height: 180rpx;
|
|
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom));
|
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
|
}
|
|
</style>
|
|
|