21 changed files with 6352 additions and 1857 deletions
@ -0,0 +1,52 @@ |
|||||
|
import QQMapWX from '@/libs/qqmap-wx-jssdk1.2/qqmap-wx-jssdk.js'; |
||||
|
//获取位置信息
|
||||
|
async function getLocationInfo() { |
||||
|
return new Promise((resolve) => { |
||||
|
//位置信息默认数据
|
||||
|
let location = { |
||||
|
longitude: 0, |
||||
|
latitude: 0, |
||||
|
province: '', |
||||
|
city: '', |
||||
|
area: '', |
||||
|
street: '', |
||||
|
address: '', |
||||
|
}; |
||||
|
uni.getLocation({ |
||||
|
type: 'gcj02', |
||||
|
success(res) { |
||||
|
location.longitude = res.longitude; |
||||
|
location.latitude = res.latitude; |
||||
|
// 腾讯地图Api
|
||||
|
const qqmapsdk = new QQMapWX({ |
||||
|
key: 'X5YBZ-ES6K3-Q6E3P-RUVXH-2R5ZQ-ERBFG', //这里填写自己申请的key
|
||||
|
}); |
||||
|
qqmapsdk.reverseGeocoder({ |
||||
|
location, |
||||
|
success(response) { |
||||
|
console.log(response) |
||||
|
let info = response.result; |
||||
|
location.province = info.address_component.province; |
||||
|
location.cityCode = info.ad_info.city_code.slice(3); |
||||
|
location.city = info.address_component.city; |
||||
|
location.area = info.address_component.district; |
||||
|
location.street = info.address_component.street; |
||||
|
location.address = info.address; |
||||
|
resolve(location); |
||||
|
}, |
||||
|
fail(e){ |
||||
|
console.log(e,'地址信息报错') |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
fail(err) { |
||||
|
console.log(err); |
||||
|
resolve(location); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
//导出
|
||||
|
module.exports = { |
||||
|
getLocationInfo, |
||||
|
}; |
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,631 @@ |
|||||
|
<template> |
||||
|
<view class="note-detail-container"> |
||||
|
<!-- 笔记内容区域 --> |
||||
|
<view class="content-scroll" > |
||||
|
<!-- 作者信息 --> |
||||
|
<view class="author-section"> |
||||
|
<image |
||||
|
class="author-avatar" |
||||
|
:src="noteDetail.user.avatar" |
||||
|
mode="aspectFill" |
||||
|
/> |
||||
|
<view class="author-info"> |
||||
|
<text class="author-name">{{ noteDetail.user.name }}</text> |
||||
|
<text class="publish-time">{{ |
||||
|
formatTime(noteDetail.createTime) |
||||
|
}}</text> |
||||
|
</view> |
||||
|
<button |
||||
|
class="follow-btn" |
||||
|
:class="{ followed: noteDetail.user.isFollowed }" |
||||
|
@click="toggleFollow" |
||||
|
> |
||||
|
{{ noteDetail.user.isFollowed ? "已关注" : "+ 关注" }} |
||||
|
</button> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 笔记标题 --> |
||||
|
<view class="note-title"> |
||||
|
{{ noteDetail.title }} |
||||
|
</view> |
||||
|
|
||||
|
<!-- 笔记主图 --> |
||||
|
<view class="note-image-container" v-if="noteDetail.image"> |
||||
|
<image |
||||
|
class="note-image" |
||||
|
:src="noteDetail.image" |
||||
|
mode="aspectFill" |
||||
|
@click="previewImage(noteDetail.image)" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 笔记内容 --> |
||||
|
<view class="note-content"> |
||||
|
<text class="content-text">{{ noteDetail.content }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 标签 --> |
||||
|
<view |
||||
|
class="tags-section" |
||||
|
v-if="noteDetail.tags && noteDetail.tags.length" |
||||
|
> |
||||
|
<view class="tag-item" v-for="tag in noteDetail.tags" :key="tag"> |
||||
|
#{{ tag }} |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 互动数据 --> |
||||
|
<view class="interaction-section"> |
||||
|
<view class="interaction-item" @click="toggleLike"> |
||||
|
<text class="interaction-icon" :class="{ liked: noteDetail.isLiked }" |
||||
|
>♥</text |
||||
|
> |
||||
|
<text class="interaction-text">{{ noteDetail.likes }}</text> |
||||
|
</view> |
||||
|
<view class="interaction-item" @click="toggleCollect"> |
||||
|
<text |
||||
|
class="interaction-icon" |
||||
|
:class="{ collected: noteDetail.isCollected }" |
||||
|
>★</text |
||||
|
> |
||||
|
<text class="interaction-text">{{ noteDetail.collects }}</text> |
||||
|
</view> |
||||
|
<view class="interaction-item" @click="showShareMenu"> |
||||
|
<text class="interaction-icon">↗</text> |
||||
|
<text class="interaction-text">分享</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 评论区域 --> |
||||
|
<view class="comments-section"> |
||||
|
<view class="comments-header"> |
||||
|
<text class="comments-title" |
||||
|
>评论 ({{ noteDetail.comments.length }})</text |
||||
|
> |
||||
|
</view> |
||||
|
|
||||
|
<view |
||||
|
class="comment-item" |
||||
|
v-for="comment in noteDetail.comments" |
||||
|
:key="comment.id" |
||||
|
> |
||||
|
<image |
||||
|
class="comment-avatar" |
||||
|
:src="comment.user.avatar" |
||||
|
mode="aspectFill" |
||||
|
/> |
||||
|
<view class="comment-content"> |
||||
|
<view class="comment-header"> |
||||
|
<text class="comment-user">{{ comment.user.name }}</text> |
||||
|
<text class="comment-time">{{ |
||||
|
formatTime(comment.createTime) |
||||
|
}}</text> |
||||
|
</view> |
||||
|
<text class="comment-text">{{ comment.content }}</text> |
||||
|
<view class="comment-actions"> |
||||
|
<view class="comment-like" @click="toggleCommentLike(comment)"> |
||||
|
<text class="like-icon" :class="{ liked: comment.isLiked }" |
||||
|
>♥</text |
||||
|
> |
||||
|
<text class="like-count">{{ comment.likes }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 底部占位 --> |
||||
|
<view class="bottom-placeholder"></view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 底部评论输入框 --> |
||||
|
<view class="comment-input-section"> |
||||
|
<input |
||||
|
class="comment-input" |
||||
|
v-model="commentText" |
||||
|
placeholder="写下你的想法..." |
||||
|
@confirm="submitComment" |
||||
|
/> |
||||
|
<button |
||||
|
class="send-btn" |
||||
|
@click="submitComment" |
||||
|
:disabled="!commentText.trim()" |
||||
|
> |
||||
|
发送 |
||||
|
</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import headerVue from "@/components/header.vue"; |
||||
|
|
||||
|
export default { |
||||
|
name: "NoteDetail", |
||||
|
components: { |
||||
|
headerVue, |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
noteId: "", |
||||
|
commentText: "", |
||||
|
noteDetail: { |
||||
|
id: "", |
||||
|
title: "", |
||||
|
content: "", |
||||
|
image: "", |
||||
|
tags: [], |
||||
|
likes: 0, |
||||
|
collects: 0, |
||||
|
isLiked: false, |
||||
|
isCollected: false, |
||||
|
createTime: "", |
||||
|
user: { |
||||
|
id: "", |
||||
|
name: "", |
||||
|
avatar: "", |
||||
|
isFollowed: false, |
||||
|
}, |
||||
|
comments: [], |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
onLoad(options) { |
||||
|
if (options.id) { |
||||
|
this.noteId = options.id; |
||||
|
this.loadNoteDetail(); |
||||
|
} else { |
||||
|
this.loadMockData(); |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
// 加载笔记详情 |
||||
|
async loadNoteDetail() { |
||||
|
try { |
||||
|
uni.showLoading({ title: "加载中..." }); |
||||
|
// 模拟API调用 |
||||
|
const res = await this.getNoteDetail(this.noteId); |
||||
|
this.noteDetail = res.data; |
||||
|
} catch (error) { |
||||
|
console.error("加载笔记详情失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "加载失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} finally { |
||||
|
uni.hideLoading(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 加载模拟数据 |
||||
|
loadMockData() { |
||||
|
this.noteDetail = { |
||||
|
id: "mock001", |
||||
|
title: "这里是用户发布内容的标题", |
||||
|
content: |
||||
|
"这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容这里是用户发布的内容", |
||||
|
image: "https://picsum.photos/800/600", |
||||
|
tags: ["时间力", "阅读体验"], |
||||
|
likes: 128, |
||||
|
collects: 64, |
||||
|
isLiked: false, |
||||
|
isCollected: false, |
||||
|
createTime: "2024-01-15 14:30:00", |
||||
|
user: { |
||||
|
id: "user001", |
||||
|
name: "杨璐摄影", |
||||
|
avatar: |
||||
|
"https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100", |
||||
|
isFollowed: false, |
||||
|
}, |
||||
|
comments: [ |
||||
|
{ |
||||
|
id: "comment001", |
||||
|
content: "很棒的分享,学到了很多!", |
||||
|
likes: 5, |
||||
|
isLiked: false, |
||||
|
createTime: "2024-01-15 15:00:00", |
||||
|
user: { |
||||
|
id: "user002", |
||||
|
name: "读书爱好者", |
||||
|
avatar: |
||||
|
"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=100", |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
id: "comment002", |
||||
|
content: "感谢分享,很有启发性的内容", |
||||
|
likes: 3, |
||||
|
isLiked: false, |
||||
|
createTime: "2024-01-15 16:20:00", |
||||
|
user: { |
||||
|
id: "user003", |
||||
|
name: "时间管理达人", |
||||
|
avatar: |
||||
|
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=100", |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
// 预览图片 |
||||
|
previewImage(imageUrl) { |
||||
|
uni.previewImage({ |
||||
|
urls: [imageUrl], |
||||
|
current: imageUrl, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 切换关注状态 |
||||
|
toggleFollow() { |
||||
|
this.noteDetail.user.isFollowed = !this.noteDetail.user.isFollowed; |
||||
|
uni.showToast({ |
||||
|
title: this.noteDetail.user.isFollowed ? "已关注" : "取消关注", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 切换点赞状态 |
||||
|
toggleLike() { |
||||
|
this.noteDetail.isLiked = !this.noteDetail.isLiked; |
||||
|
this.noteDetail.likes += this.noteDetail.isLiked ? 1 : -1; |
||||
|
}, |
||||
|
|
||||
|
// 切换收藏状态 |
||||
|
toggleCollect() { |
||||
|
this.noteDetail.isCollected = !this.noteDetail.isCollected; |
||||
|
this.noteDetail.collects += this.noteDetail.isCollected ? 1 : -1; |
||||
|
}, |
||||
|
|
||||
|
// 显示分享菜单 |
||||
|
showShareMenu() { |
||||
|
uni.share({ |
||||
|
provider: "weixin", |
||||
|
scene: "WXSceneSession", |
||||
|
type: 0, |
||||
|
href: `https://example.com/notes/${this.noteDetail.id}`, |
||||
|
title: this.noteDetail.title, |
||||
|
summary: this.noteDetail.content.substring(0, 100), |
||||
|
imageUrl: this.noteDetail.image, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 切换评论点赞 |
||||
|
toggleCommentLike(comment) { |
||||
|
comment.isLiked = !comment.isLiked; |
||||
|
comment.likes += comment.isLiked ? 1 : -1; |
||||
|
}, |
||||
|
|
||||
|
// 提交评论 |
||||
|
async submitComment() { |
||||
|
if (!this.commentText.trim()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const newComment = { |
||||
|
id: "comment" + Date.now(), |
||||
|
content: this.commentText, |
||||
|
likes: 0, |
||||
|
isLiked: false, |
||||
|
createTime: new Date().toISOString(), |
||||
|
user: { |
||||
|
id: "current_user", |
||||
|
name: "当前用户", |
||||
|
avatar: |
||||
|
"https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100", |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
this.noteDetail.comments.unshift(newComment); |
||||
|
this.commentText = ""; |
||||
|
|
||||
|
uni.showToast({ |
||||
|
title: "评论成功", |
||||
|
icon: "success", |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 格式化时间 |
||||
|
formatTime(timeString) { |
||||
|
const time = new Date(timeString); |
||||
|
const now = new Date(); |
||||
|
const diff = now.getTime() - time.getTime(); |
||||
|
|
||||
|
if (diff < 60 * 1000) { |
||||
|
return "刚刚"; |
||||
|
} else if (diff < 60 * 60 * 1000) { |
||||
|
return Math.floor(diff / (60 * 1000)) + "分钟前"; |
||||
|
} else if (diff < 24 * 60 * 60 * 1000) { |
||||
|
return Math.floor(diff / (60 * 60 * 1000)) + "小时前"; |
||||
|
} else { |
||||
|
return time.toLocaleDateString(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 模拟API - 获取笔记详情 |
||||
|
async getNoteDetail(noteId) { |
||||
|
return new Promise((resolve) => { |
||||
|
setTimeout(() => { |
||||
|
this.loadMockData(); |
||||
|
resolve({ |
||||
|
code: 200, |
||||
|
data: this.noteDetail, |
||||
|
}); |
||||
|
}, 500); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.note-detail-container { |
||||
|
min-height: 100vh; |
||||
|
background: #fff; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.content-scroll { |
||||
|
flex: 1; |
||||
|
padding: 0 32rpx; |
||||
|
} |
||||
|
|
||||
|
// 作者信息 |
||||
|
.author-section { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 32rpx 0; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
.author-avatar { |
||||
|
width: 80rpx; |
||||
|
height: 80rpx; |
||||
|
border-radius: 40rpx; |
||||
|
margin-right: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.author-info { |
||||
|
flex: 1; |
||||
|
|
||||
|
.author-name { |
||||
|
display: block; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
margin-bottom: 8rpx; |
||||
|
} |
||||
|
|
||||
|
.publish-time { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.follow-btn { |
||||
|
border-radius: 30rpx; |
||||
|
font-size: 24rpx; |
||||
|
border: 2rpx solid #ff4757; |
||||
|
background: transparent; |
||||
|
color: #ff4757; |
||||
|
font-weight: 600; |
||||
|
|
||||
|
&.followed { |
||||
|
background: #ff4757; |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 笔记标题 |
||||
|
.note-title { |
||||
|
font-size: 40rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
line-height: 1.4; |
||||
|
margin: 32rpx 0; |
||||
|
} |
||||
|
|
||||
|
// 笔记图片 |
||||
|
.note-image-container { |
||||
|
margin: 32rpx 0; |
||||
|
|
||||
|
.note-image { |
||||
|
width: 100%; |
||||
|
max-height: 800rpx; |
||||
|
border-radius: 16rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 笔记内容 |
||||
|
.note-content { |
||||
|
margin: 32rpx 0; |
||||
|
|
||||
|
.content-text { |
||||
|
font-size: 32rpx; |
||||
|
line-height: 1.6; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 标签 |
||||
|
.tags-section { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 16rpx; |
||||
|
margin: 32rpx 0; |
||||
|
|
||||
|
.tag-item { |
||||
|
padding: 12rpx 24rpx; |
||||
|
background: #f8f9fa; |
||||
|
border-radius: 32rpx; |
||||
|
font-size: 24rpx; |
||||
|
color: #666; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 互动区域 |
||||
|
.interaction-section { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 48rpx; |
||||
|
padding: 32rpx 0; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
.interaction-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8rpx; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
.interaction-icon { |
||||
|
font-size: 32rpx; |
||||
|
color: #999; |
||||
|
transition: color 0.3s; |
||||
|
|
||||
|
&.liked { |
||||
|
color: #ff4757; |
||||
|
} |
||||
|
|
||||
|
&.collected { |
||||
|
color: #ffd700; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.interaction-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 评论区域 |
||||
|
.comments-section { |
||||
|
margin: 32rpx 0; |
||||
|
|
||||
|
.comments-header { |
||||
|
margin-bottom: 32rpx; |
||||
|
|
||||
|
.comments-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.comment-item { |
||||
|
display: flex; |
||||
|
margin-bottom: 32rpx; |
||||
|
|
||||
|
.comment-avatar { |
||||
|
width: 64rpx; |
||||
|
height: 64rpx; |
||||
|
border-radius: 32rpx; |
||||
|
margin-right: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.comment-content { |
||||
|
flex: 1; |
||||
|
|
||||
|
.comment-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
margin-bottom: 12rpx; |
||||
|
|
||||
|
.comment-user { |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.comment-time { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.comment-text { |
||||
|
font-size: 30rpx; |
||||
|
line-height: 1.5; |
||||
|
color: #333; |
||||
|
margin-bottom: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.comment-actions { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.comment-like { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8rpx; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
.like-icon { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
|
||||
|
&.liked { |
||||
|
color: #ff4757; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.like-count { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 底部评论输入 |
||||
|
.comment-input-section { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 24rpx 32rpx; |
||||
|
background: #fff; |
||||
|
border-top: 1rpx solid #f0f0f0; |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index: 999; |
||||
|
.comment-input { |
||||
|
flex: 1; |
||||
|
height: 80rpx; |
||||
|
background: #f8f9fa; |
||||
|
border-radius: 40rpx; |
||||
|
padding: 0 32rpx; |
||||
|
font-size: 28rpx; |
||||
|
border: none; |
||||
|
margin-right: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.send-btn { |
||||
|
width: 120rpx; |
||||
|
height: 60rpx; |
||||
|
line-height: 60rpx; |
||||
|
background: #ff4757; |
||||
|
color: #fff; |
||||
|
border-radius: 40rpx; |
||||
|
font-size: 28rpx; |
||||
|
border: none; |
||||
|
font-weight: 600; |
||||
|
|
||||
|
&:disabled { |
||||
|
background: #ccc; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bottom-placeholder { |
||||
|
height: 130rpx; |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom)); |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,445 @@ |
|||||
|
<template> |
||||
|
<view class="publish-container"> |
||||
|
<!-- 内容区域 --> |
||||
|
<view class="content-scroll"> |
||||
|
<!-- 图片区域 --> |
||||
|
<view class="image-section"> |
||||
|
<view class="image-grid"> |
||||
|
<!-- 已选图片 --> |
||||
|
<view |
||||
|
class="image-item" |
||||
|
v-for="(image, index) in selectedImages" |
||||
|
:key="index" |
||||
|
> |
||||
|
<image class="image-preview" :src="image" mode="aspectFill" /> |
||||
|
<view class="image-delete" @click="removeImage(index)"> |
||||
|
<text class="delete-icon">×</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- 添加图片按钮 --> |
||||
|
<view |
||||
|
class="add-image-btn" |
||||
|
@click="chooseImage" |
||||
|
v-if="selectedImages.length < 9" |
||||
|
> |
||||
|
<text class="add-icon">+</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 标题区域 --> |
||||
|
<view class="title-section"> |
||||
|
<textarea |
||||
|
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="quick-tags-list"> |
||||
|
<view |
||||
|
class="quick-tag-item" |
||||
|
v-for="tag in quickTags" |
||||
|
:key="tag" |
||||
|
@click="insertQuickTag(tag)" |
||||
|
> |
||||
|
#{{ tag }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 已添加标签 --> |
||||
|
<view class="selected-tags-section" v-if="noteForm.tags.length"> |
||||
|
<view class="selected-tags-list"> |
||||
|
<view |
||||
|
class="selected-tag-item" |
||||
|
v-for="(tag, index) in noteForm.tags" |
||||
|
:key="index" |
||||
|
@click="removeTag(index)" |
||||
|
> |
||||
|
<text class="tag-text">#{{ tag }}</text> |
||||
|
<text class="tag-close">×</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 底部占位 --> |
||||
|
<view class="bottom-placeholder"></view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 底部发布按钮 --> |
||||
|
<view class="bottom-publish"> |
||||
|
<button class="publish-btn" @click="publishNote" :disabled="!canPublish"> |
||||
|
发布笔记 |
||||
|
</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: "PublishNote", |
||||
|
data() { |
||||
|
return { |
||||
|
selectedImages: [], |
||||
|
noteForm: { |
||||
|
title: "", |
||||
|
content: "", |
||||
|
tags: [], |
||||
|
images: [], |
||||
|
}, |
||||
|
quickTags: [ |
||||
|
"阅读体验", |
||||
|
"时间力", |
||||
|
"读书笔记", |
||||
|
"生活感悟", |
||||
|
"学习心得", |
||||
|
"思考", |
||||
|
], |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
canPublish() { |
||||
|
return ( |
||||
|
this.noteForm.title.trim() || |
||||
|
this.noteForm.content.trim() || |
||||
|
this.selectedImages.length > 0 |
||||
|
); |
||||
|
}, |
||||
|
}, |
||||
|
methods: { |
||||
|
// 返回上一页 |
||||
|
goBack() { |
||||
|
if (this.canPublish) { |
||||
|
uni.showModal({ |
||||
|
title: "确认退出", |
||||
|
content: "退出后内容将不会保存,确定要退出吗?", |
||||
|
success: (res) => { |
||||
|
if (res.confirm) { |
||||
|
uni.navigateBack(); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
} else { |
||||
|
uni.navigateBack(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 选择图片 |
||||
|
chooseImage() { |
||||
|
const remainingCount = 9 - this.selectedImages.length; |
||||
|
uni.chooseImage({ |
||||
|
count: remainingCount, |
||||
|
sizeType: ["original", "compressed"], |
||||
|
sourceType: ["album", "camera"], |
||||
|
success: (res) => { |
||||
|
this.selectedImages.push(...res.tempFilePaths); |
||||
|
this.noteForm.images = [...this.selectedImages]; |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.error("选择图片失败:", err); |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 移除图片 |
||||
|
removeImage(index) { |
||||
|
this.selectedImages.splice(index, 1); |
||||
|
this.noteForm.images = [...this.selectedImages]; |
||||
|
}, |
||||
|
|
||||
|
// 插入快速标签 |
||||
|
insertQuickTag(tag) { |
||||
|
if (!this.noteForm.tags.includes(tag)) { |
||||
|
this.noteForm.tags.push(tag); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 移除标签 |
||||
|
removeTag(index) { |
||||
|
this.noteForm.tags.splice(index, 1); |
||||
|
}, |
||||
|
|
||||
|
// 发布笔记 |
||||
|
async publishNote() { |
||||
|
if (!this.canPublish) { |
||||
|
uni.showToast({ |
||||
|
title: "请添加内容", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
uni.showLoading({ title: "发布中..." }); |
||||
|
|
||||
|
// 模拟发布API调用 |
||||
|
await this.submitNote(this.noteForm); |
||||
|
|
||||
|
uni.hideLoading(); |
||||
|
uni.showToast({ |
||||
|
title: "发布成功", |
||||
|
icon: "success", |
||||
|
duration: 2000, |
||||
|
}); |
||||
|
|
||||
|
// 延迟跳转,让用户看到成功提示 |
||||
|
setTimeout(() => { |
||||
|
uni.navigateBack(); |
||||
|
}, 1500); |
||||
|
} catch (error) { |
||||
|
uni.hideLoading(); |
||||
|
uni.showToast({ |
||||
|
title: "发布失败,请重试", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 提交笔记(模拟API) |
||||
|
async submitNote(noteData) { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
setTimeout(() => { |
||||
|
console.log("发布笔记数据:", noteData); |
||||
|
resolve({ |
||||
|
code: 200, |
||||
|
message: "发布成功", |
||||
|
data: { |
||||
|
id: "note_" + Date.now(), |
||||
|
...noteData, |
||||
|
}, |
||||
|
}); |
||||
|
}, 1500); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.publish-container { |
||||
|
min-height: 100vh; |
||||
|
background: #fff; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
// 内容区域 |
||||
|
.content-scroll { |
||||
|
flex: 1; |
||||
|
padding: 0 30rpx; |
||||
|
width: 690rpx; |
||||
|
} |
||||
|
|
||||
|
// 图片区域 |
||||
|
.image-section { |
||||
|
margin: 32rpx 0; |
||||
|
padding-bottom: 32rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
.image-grid { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(3, 1fr); |
||||
|
gap: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.image-item { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
aspect-ratio: 1; |
||||
|
border-radius: 16rpx; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
.image-preview { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
.image-delete { |
||||
|
position: absolute; |
||||
|
top: 8rpx; |
||||
|
right: 8rpx; |
||||
|
width: 48rpx; |
||||
|
height: 48rpx; |
||||
|
background: rgba(0, 0, 0, 0.6); |
||||
|
border-radius: 24rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.delete-icon { |
||||
|
font-size: 32rpx; |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.add-image-btn { |
||||
|
width: 100%; |
||||
|
aspect-ratio: 1; |
||||
|
border: 2rpx dashed #ddd; |
||||
|
border-radius: 16rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
background: #fafafa; |
||||
|
|
||||
|
.add-icon { |
||||
|
font-size: 48rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 标题区域 |
||||
|
.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: 32rpx; |
||||
|
line-height: 1.6; |
||||
|
color: #333; |
||||
|
border: none; |
||||
|
padding: 0; |
||||
|
resize: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 快速标签区域 |
||||
|
.quick-tags-section { |
||||
|
margin: 24rpx 0; |
||||
|
|
||||
|
.quick-tags-list { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 16rpx; |
||||
|
|
||||
|
.quick-tag-item { |
||||
|
padding: 16rpx 24rpx; |
||||
|
background: #f8f9fa; |
||||
|
border: 1rpx solid #e0e0e0; |
||||
|
border-radius: 32rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
&:active { |
||||
|
background: #e9ecef; |
||||
|
transform: scale(0.96); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 已选标签区域 |
||||
|
.selected-tags-section { |
||||
|
margin: 24rpx 0; |
||||
|
padding-top: 24rpx; |
||||
|
border-top: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
.selected-tags-list { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 16rpx; |
||||
|
|
||||
|
.selected-tag-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8rpx; |
||||
|
padding: 12rpx 20rpx; |
||||
|
background: #ff4757; |
||||
|
border-radius: 32rpx; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
.tag-text { |
||||
|
font-size: 26rpx; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.tag-close { |
||||
|
font-size: 24rpx; |
||||
|
color: #fff; |
||||
|
opacity: 0.8; |
||||
|
margin-left: 8rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 底部发布按钮 |
||||
|
.bottom-publish { |
||||
|
padding: 24rpx 32rpx; |
||||
|
background: #fff; |
||||
|
border-top: 1rpx solid #f0f0f0; |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index: 100; |
||||
|
.publish-btn { |
||||
|
width: 100%; |
||||
|
height: 88rpx; |
||||
|
background: #ff4757; |
||||
|
color: #fff; |
||||
|
border-radius: 44rpx; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
border: none; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
&:disabled { |
||||
|
background: #ccc; |
||||
|
} |
||||
|
|
||||
|
&:not(:disabled):active { |
||||
|
transform: scale(0.98); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bottom-placeholder { |
||||
|
height: 140rpx; |
||||
|
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom)); |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
} |
||||
|
</style> |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,339 @@ |
|||||
|
<template> |
||||
|
<view class="memorial-detail"> |
||||
|
<!-- 主图区域 --> |
||||
|
<view class="main-image-section"> |
||||
|
<image |
||||
|
:src="showImg(detailInfo.image)" |
||||
|
mode="aspectFill" |
||||
|
class="main-image" |
||||
|
@click="previewMainImage" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 数字资产信息卡片 --> |
||||
|
<view class="asset-info-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="asset-title">{{ detailInfo.title }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">发行数量:</text> |
||||
|
<text class="info-value">{{ detailInfo.totalSupply }}份</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="divider"></view> |
||||
|
|
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">数字资产所有方:</text> |
||||
|
<text class="info-value">{{ detailInfo.owner }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">数字资产权利方:</text> |
||||
|
<text class="info-value">{{ detailInfo.rightHolder }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">数字资产所有方:</text> |
||||
|
<text class="info-value">{{ detailInfo.assetOwner }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 收藏信息 --> |
||||
|
<view class="collection-info"> |
||||
|
<view class="collection-header">— 收藏信息 —</view> |
||||
|
<view class="collector-info"> |
||||
|
<text class="collector-label">收藏者</text> |
||||
|
<text class="collector-name">{{ detailInfo.collector }}</text> |
||||
|
<text class="collection-number">编号</text> |
||||
|
<text class="collection-code">{{ detailInfo.collectionCode }}</text> |
||||
|
<text class="collection-time-label">收藏时间</text> |
||||
|
<text class="collection-time">{{ detailInfo.collectionTime }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 认证信息卡片 --> |
||||
|
<view class="cert-info-card"> |
||||
|
<view class="cert-header">— 认证信息 —</view> |
||||
|
|
||||
|
<view class="cert-row"> |
||||
|
<text class="cert-label">权证码</text> |
||||
|
<text class="cert-value">{{ detailInfo.certificateCode }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="cert-row"> |
||||
|
<text class="cert-label">合约地址</text> |
||||
|
<text class="cert-value">{{ detailInfo.contractAddress }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="cert-row"> |
||||
|
<text class="cert-label">交易HASH</text> |
||||
|
<text class="cert-value">{{ detailInfo.transactionHash }}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="cert-row"> |
||||
|
<text class="cert-label">钱包地址</text> |
||||
|
<text class="cert-value">{{ detailInfo.walletAddress }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 藏品详情卡片 --> |
||||
|
<view class="product-detail-card"> |
||||
|
<view class="product-header">— 藏品详情 —</view> |
||||
|
<view class="product-content"> |
||||
|
<!-- 这里可以放置藏品的详细描述内容 --> |
||||
|
<text class="product-description">{{ detailInfo.description }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: "MemorialDetail", |
||||
|
data() { |
||||
|
return { |
||||
|
detailInfo: { |
||||
|
id: "", |
||||
|
title: "这里是数字资产的名称", |
||||
|
totalSupply: "2000", |
||||
|
owner: "XXX博物馆", |
||||
|
rightHolder: "江苏大运河公司", |
||||
|
assetOwner: "江苏大运河公司", |
||||
|
collector: "XXX用户", |
||||
|
collectionCode: "#001-0050/1000", |
||||
|
collectionTime: "2025-085-04 15:20:20", |
||||
|
certificateCode: "SUA-DA-01-20250729A123456-001-0050/1000-v1", |
||||
|
contractAddress: "0xd4efaba236f7c110fe85fcbcde5489a7a3c71ec3", |
||||
|
transactionHash: "0xd412da236f7c110fe81ewl5fcbcde5489a7a3c7", |
||||
|
walletAddress: "0x8df5d733a0dd127022f7740be4f9c10ec8a23b", |
||||
|
image: "/uploads/20250729/42fe2364167c2342076c4e094df3d288.png", |
||||
|
description: "这里是藏品的详细描述信息...", |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
onLoad(options) { |
||||
|
// 获取传入的参数 |
||||
|
if (options.id) { |
||||
|
this.loadDetailInfo(options.id); |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
// 加载详情信息 |
||||
|
async loadDetailInfo(id) { |
||||
|
try { |
||||
|
// 这里应该调用实际的API获取详情数据 |
||||
|
// const response = await this.getMemorialDetail(id); |
||||
|
// this.detailInfo = response.data; |
||||
|
|
||||
|
// 模拟数据加载 |
||||
|
console.log("加载纪念册详情,ID:", id); |
||||
|
} catch (error) { |
||||
|
console.error("加载详情失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "加载失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 预览主图 |
||||
|
previewMainImage() { |
||||
|
const imageUrl = this.showImg(this.detailInfo.image); |
||||
|
uni.previewImage({ |
||||
|
urls: [imageUrl], |
||||
|
current: imageUrl, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 图片路径处理 |
||||
|
showImg(img) { |
||||
|
if (!img) return ""; |
||||
|
if (img.startsWith("http")) { |
||||
|
return img; |
||||
|
} |
||||
|
const NEWAPIURL = "https://epic.js-dyyj.com"; |
||||
|
return `${NEWAPIURL}${img}`; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.memorial-detail { |
||||
|
min-height: 100vh; |
||||
|
background: #f8f9fa; |
||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||
|
} |
||||
|
|
||||
|
// 主图区域 |
||||
|
.main-image-section { |
||||
|
width: 100%; |
||||
|
height: 600rpx; |
||||
|
background: #f0f0f0; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.main-image { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
object-fit: cover; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 通用卡片样式 |
||||
|
.asset-info-card, |
||||
|
.cert-info-card, |
||||
|
.product-detail-card { |
||||
|
margin: 20rpx; |
||||
|
background: white; |
||||
|
border-radius: 16rpx; |
||||
|
padding: 32rpx; |
||||
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); |
||||
|
} |
||||
|
|
||||
|
// 数字资产信息卡片 |
||||
|
.asset-info-card { |
||||
|
.card-header { |
||||
|
margin-bottom: 32rpx; |
||||
|
|
||||
|
.asset-title { |
||||
|
font-size: 36rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
line-height: 1.4; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.info-row { |
||||
|
display: flex; |
||||
|
margin-bottom: 20rpx; |
||||
|
align-items: flex-start; |
||||
|
|
||||
|
.info-label { |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
margin-right: 16rpx; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.info-value { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.divider { |
||||
|
height: 1rpx; |
||||
|
background: #e0e0e0; |
||||
|
margin: 24rpx 0; |
||||
|
} |
||||
|
|
||||
|
// 收藏信息 |
||||
|
.collection-info { |
||||
|
margin-top: 40rpx; |
||||
|
padding: 32rpx; |
||||
|
background: #f8f9fa; |
||||
|
border-radius: 12rpx; |
||||
|
border: 2rpx solid #e0e0e0; |
||||
|
|
||||
|
.collection-header { |
||||
|
text-align: center; |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 24rpx; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.collector-info { |
||||
|
display: grid; |
||||
|
grid-template-columns: auto auto; |
||||
|
gap: 16rpx 24rpx; |
||||
|
text-align: center; |
||||
|
|
||||
|
.collector-label, |
||||
|
.collection-number, |
||||
|
.collection-time-label { |
||||
|
font-size: 24rpx; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.collector-name, |
||||
|
.collection-code, |
||||
|
.collection-time { |
||||
|
font-size: 26rpx; |
||||
|
color: #333; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.collection-code { |
||||
|
font-family: "Courier New", monospace; |
||||
|
} |
||||
|
|
||||
|
.collection-time { |
||||
|
font-family: "Courier New", monospace; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 认证信息卡片 |
||||
|
.cert-info-card { |
||||
|
.cert-header { |
||||
|
text-align: center; |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 32rpx; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.cert-row { |
||||
|
margin-bottom: 24rpx; |
||||
|
padding-bottom: 20rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
&:last-child { |
||||
|
margin-bottom: 0; |
||||
|
padding-bottom: 0; |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.cert-label { |
||||
|
display: block; |
||||
|
font-size: 26rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 8rpx; |
||||
|
} |
||||
|
|
||||
|
.cert-value { |
||||
|
display: block; |
||||
|
font-size: 24rpx; |
||||
|
color: #333; |
||||
|
font-family: "Courier New", monospace; |
||||
|
word-break: break-all; |
||||
|
line-height: 1.5; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 藏品详情卡片 |
||||
|
.product-detail-card { |
||||
|
.product-header { |
||||
|
text-align: center; |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 32rpx; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.product-content { |
||||
|
.product-description { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,219 @@ |
|||||
|
<template> |
||||
|
<view class="memorial-album"> |
||||
|
<!-- 纪念册网格 --> |
||||
|
<view class="memorial-grid"> |
||||
|
<view |
||||
|
class="memorial-item" |
||||
|
v-for="(item, index) in memorialItems" |
||||
|
:key="index" |
||||
|
@click="goToDetail(item)" |
||||
|
> |
||||
|
<view class="memorial-card"> |
||||
|
<image |
||||
|
:src="showImg(item.image)" |
||||
|
mode="aspectFill" |
||||
|
class="memorial-image" |
||||
|
/> |
||||
|
<view class="memorial-info"> |
||||
|
<text class="memorial-title">{{ item.title }}</text> |
||||
|
<text class="memorial-code">{{ item.code }}</text> |
||||
|
<text class="memorial-status">{{ item.status }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: "MemorialAlbum", |
||||
|
data() { |
||||
|
return { |
||||
|
memorialItems: [ |
||||
|
{ |
||||
|
id: 1, |
||||
|
title: "香在苏州|世界美食之都", |
||||
|
code: "#001-0050/1000", |
||||
|
status: "XXX博物馆", |
||||
|
image: "/uploads/20250729/42fe2364167c2342076c4e094df3d288.png", |
||||
|
}, |
||||
|
{ |
||||
|
id: 2, |
||||
|
title: "香在苏州|世界美食之都", |
||||
|
code: "#001-0050/1000", |
||||
|
status: "XXX博物馆", |
||||
|
image: "/uploads/20250729/105755e9b2e570e46b96d54ed61abe51.png", |
||||
|
}, |
||||
|
{ |
||||
|
id: 3, |
||||
|
title: "香在苏州|世界美食之都", |
||||
|
code: "#001-0050/1000", |
||||
|
status: "XXX博物馆", |
||||
|
image: "/uploads/20250729/105755e9b2e570e46b96d54ed61abe51.png", |
||||
|
}, |
||||
|
{ |
||||
|
id: 4, |
||||
|
title: "香在苏州|世界美食之都", |
||||
|
code: "#001-0050/1000", |
||||
|
status: "XXX博物馆", |
||||
|
image: "/uploads/20250729/42fe2364167c2342076c4e094df3d288.png", |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}, |
||||
|
methods: { |
||||
|
// 返回上一页 |
||||
|
goBack() { |
||||
|
uni.navigateBack(); |
||||
|
}, |
||||
|
|
||||
|
// 跳转到详情页面 |
||||
|
goToDetail(item) { |
||||
|
uni.navigateTo({ |
||||
|
url: `/subPackages/memorialAlbum/detail?id=${item.id}`, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 图片预览 |
||||
|
previewImage(imagePath) { |
||||
|
const imageUrl = this.showImg(imagePath); |
||||
|
uni.previewImage({ |
||||
|
urls: [imageUrl], |
||||
|
current: imageUrl, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 图片路径处理 |
||||
|
showImg(img) { |
||||
|
if (!img) return ""; |
||||
|
if (img.startsWith("http")) { |
||||
|
return img; |
||||
|
} |
||||
|
// 这里需要根据你的项目实际情况调整API地址 |
||||
|
const NEWAPIURL = "https://epic.js-dyyj.com"; |
||||
|
return `${NEWAPIURL}${img}`; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.memorial-album { |
||||
|
min-height: 100vh; |
||||
|
background: #f8f9fa; |
||||
|
padding-bottom: env(safe-area-inset-bottom); |
||||
|
} |
||||
|
|
||||
|
// 顶部导航 |
||||
|
.nav-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding: 20rpx 30rpx; |
||||
|
background: white; |
||||
|
border-bottom: 1rpx solid #eee; |
||||
|
position: sticky; |
||||
|
top: 0; |
||||
|
z-index: 100; |
||||
|
} |
||||
|
|
||||
|
.nav-back { |
||||
|
width: 60rpx; |
||||
|
height: 60rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.nav-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.nav-placeholder { |
||||
|
width: 60rpx; |
||||
|
} |
||||
|
|
||||
|
// 纪念册网格 |
||||
|
.memorial-grid { |
||||
|
padding: 30rpx; |
||||
|
display: grid; |
||||
|
grid-template-columns: 1fr 1fr; |
||||
|
gap: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.memorial-item { |
||||
|
background: white; |
||||
|
border-radius: 16rpx; |
||||
|
overflow: hidden; |
||||
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); |
||||
|
transition: transform 0.2s ease; |
||||
|
|
||||
|
&:active { |
||||
|
transform: scale(0.98); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.memorial-card { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.memorial-image { |
||||
|
width: 100% !important; |
||||
|
height: 460rpx !important; |
||||
|
background: #f5f5f5; |
||||
|
display: block; |
||||
|
object-fit: cover; |
||||
|
} |
||||
|
|
||||
|
.memorial-info { |
||||
|
padding: 28rpx 24rpx; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 12rpx; |
||||
|
} |
||||
|
|
||||
|
.memorial-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
line-height: 1.4; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 1; |
||||
|
-webkit-box-orient: vertical; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.memorial-code { |
||||
|
font-size: 26rpx; |
||||
|
color: #666; |
||||
|
font-family: "Courier New", monospace; |
||||
|
} |
||||
|
|
||||
|
.memorial-status { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
// 响应式处理 |
||||
|
@media screen and (max-width: 400px) { |
||||
|
.memorial-grid { |
||||
|
padding: 20rpx; |
||||
|
gap: 15rpx; |
||||
|
} |
||||
|
|
||||
|
.memorial-image { |
||||
|
height: 460rpx !important; // 保持较高的高度,即使在小屏幕上 |
||||
|
} |
||||
|
|
||||
|
.memorial-info { |
||||
|
padding: 24rpx 20rpx; |
||||
|
} |
||||
|
|
||||
|
.memorial-title { |
||||
|
font-size: 28rpx; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,772 @@ |
|||||
|
<template> |
||||
|
<view class="confirm-container"> |
||||
|
<scroll-view class="content-scroll" scroll-y> |
||||
|
<!-- 收货地址 --> |
||||
|
<view class="address-section"> |
||||
|
<!-- 有地址时显示 --> |
||||
|
<view class="section-header" @click="selectAddress" v-if="address.name"> |
||||
|
<view class="address-info"> |
||||
|
<view class="user-info"> |
||||
|
<text class="username">{{ address.name }}</text> |
||||
|
<text class="phone">{{ formatPhone(address.phone) }}</text> |
||||
|
<text class="default-tag" v-if="address.isDefault">默认地址</text> |
||||
|
</view> |
||||
|
<view class="address-detail"> |
||||
|
<text>{{ address.fullAddress }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<uni-icons type="right" size="16" color="#c0c4cc" /> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 没有地址时显示 --> |
||||
|
<view class="empty-address" @click="selectAddress" v-else> |
||||
|
<view class="empty-address-content"> |
||||
|
<uni-icons type="location" size="24" color="#c0c4cc" /> |
||||
|
<view class="empty-address-text"> |
||||
|
<text class="empty-title">请选择收货地址</text> |
||||
|
<text class="empty-tip">点击添加收货地址信息</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<uni-icons type="right" size="16" color="#c0c4cc" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 预约日期 --> |
||||
|
<view class="date-section"> |
||||
|
<view class="section-title"> |
||||
|
<text>预约日期</text> |
||||
|
<text class="required">*</text> |
||||
|
</view> |
||||
|
<view class="date-picker-container"> |
||||
|
<uni-datetime-picker |
||||
|
v-model="selectedDate" |
||||
|
type="date" |
||||
|
:clear-icon="false" |
||||
|
placeholder="请选择预约日期" |
||||
|
@change="onDateChange" |
||||
|
> |
||||
|
<view class="date-input"> |
||||
|
<text class="date-text" :class="{ placeholder: !selectedDate }"> |
||||
|
{{ selectedDate || "请选择预约日期" }} |
||||
|
</text> |
||||
|
<uni-icons type="calendar" size="18" color="#c0c4cc" /> |
||||
|
</view> |
||||
|
</uni-datetime-picker> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 商品信息 --> |
||||
|
<view class="goods-section"> |
||||
|
<view class="section-title"> |
||||
|
<text>IP资产供应商:{{ supplier || "苏州XXX博物馆" }}</text> |
||||
|
</view> |
||||
|
<view class="goods-card" v-for="item in 4"> |
||||
|
<image |
||||
|
class="goods-image" |
||||
|
:src="goodsInfo.image || '/static/image/goods-default.jpg'" |
||||
|
mode="aspectFill" |
||||
|
/> |
||||
|
<view class="goods-info"> |
||||
|
<text class="goods-name">{{ |
||||
|
goodsInfo.name || "食在苏州 | 世界美食之都巡礼+实物探真" |
||||
|
}}</text> |
||||
|
<text class="goods-desc">{{ |
||||
|
goodsInfo.desc || "商品规格信息描述" |
||||
|
}}</text> |
||||
|
<text class="goods-price">¥{{ goodsInfo.price || "699.00" }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 履约方式 --> |
||||
|
<!-- <view class="delivery-section"> |
||||
|
<view class="section-row" @click="selectDeliveryMethod"> |
||||
|
<text class="section-label">履约方式</text> |
||||
|
<view class="section-value"> |
||||
|
<text :class="{ placeholder: !deliveryMethod }"> |
||||
|
{{ deliveryMethod || "预约发货+到店核销 >" }} |
||||
|
</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> --> |
||||
|
|
||||
|
<!-- 备注 --> |
||||
|
<view class="note-section"> |
||||
|
<view class="section-row"> |
||||
|
<text class="section-label">备注</text> |
||||
|
<view class="note-input"> |
||||
|
<input |
||||
|
v-model="note" |
||||
|
placeholder="选填" |
||||
|
placeholder-class="placeholder" |
||||
|
maxlength="200" |
||||
|
/> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 费用明细 --> |
||||
|
<view class="cost-section"> |
||||
|
<view class="cost-item"> |
||||
|
<text class="cost-label">商品金额</text> |
||||
|
<text class="cost-value">¥{{ goodsInfo.price || "699.00" }}</text> |
||||
|
</view> |
||||
|
<view class="cost-item"> |
||||
|
<text class="cost-label">运费</text> |
||||
|
<text class="cost-value">{{ shipping || "预约发货时计算" }}</text> |
||||
|
</view> |
||||
|
<view class="cost-item"> |
||||
|
<text class="cost-label">优惠券</text> |
||||
|
<text class="cost-value coupon">{{ coupon || "无可用 >" }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="submit-section-content" style="height: 230rpx"> </view> |
||||
|
</scroll-view> |
||||
|
|
||||
|
<!-- 底部提交区域 --> |
||||
|
<view |
||||
|
class=" " |
||||
|
style="position: fixed; width: 100%; bottom: 0; z-index: 98" |
||||
|
> |
||||
|
<view class="submit-section"> |
||||
|
<view class="total-price"> |
||||
|
<text class="total-amount">¥{{ totalAmount || "699.00" }}</text> |
||||
|
</view> |
||||
|
<button class="submit-btn" @click="submitOrder">提交订单</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
// 收货地址信息 |
||||
|
address: { |
||||
|
name: "", |
||||
|
phone: "", |
||||
|
fullAddress: "", |
||||
|
isDefault: false, |
||||
|
}, |
||||
|
// 选中的日期 |
||||
|
selectedDate: "", |
||||
|
// 商品信息 |
||||
|
goodsInfo: { |
||||
|
id: "", |
||||
|
name: "", |
||||
|
desc: "", |
||||
|
price: "", |
||||
|
image: "", |
||||
|
}, |
||||
|
// 供应商 |
||||
|
supplier: "", |
||||
|
// 履约方式 |
||||
|
deliveryMethod: "", |
||||
|
// 备注 |
||||
|
note: "", |
||||
|
// 运费 |
||||
|
shipping: "", |
||||
|
// 优惠券 |
||||
|
coupon: "", |
||||
|
// 总金额 |
||||
|
totalAmount: "", |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
onLoad(options) { |
||||
|
// 接收页面参数 |
||||
|
if (options.goodsId) { |
||||
|
this.loadGoodsInfo(options.goodsId); |
||||
|
} |
||||
|
if (options.goodsName) { |
||||
|
this.goodsInfo.name = decodeURIComponent(options.goodsName); |
||||
|
} |
||||
|
this.loadDefaultAddress(); |
||||
|
|
||||
|
// 监听地址选择事件 |
||||
|
uni.$on("addressSelected", this.handleAddressSelected); |
||||
|
}, |
||||
|
|
||||
|
onShow() { |
||||
|
// 从地址选择页面返回时,优先检查用户选择的地址 |
||||
|
const hasSelectedAddress = this.checkSelectedAddress(); |
||||
|
// 如果没有选择地址且当前也没有地址,才加载默认地址 |
||||
|
if (!hasSelectedAddress && !this.address.id) { |
||||
|
this.loadDefaultAddress(); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
onUnload() { |
||||
|
// 移除事件监听 |
||||
|
uni.$off("addressSelected", this.handleAddressSelected); |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
// 返回上一页 |
||||
|
goBack() { |
||||
|
uni.navigateBack(); |
||||
|
}, |
||||
|
|
||||
|
// 处理地址选择事件 |
||||
|
handleAddressSelected(data) { |
||||
|
if (data.fromPage === "orderConfirm") { |
||||
|
this.updateAddressInfo(data.address); |
||||
|
console.log("地址已更新:", this.address); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 更新地址信息的统一方法 |
||||
|
updateAddressInfo(addressData) { |
||||
|
this.address = { |
||||
|
id: addressData.id, |
||||
|
name: addressData.name, |
||||
|
phone: addressData.tel, |
||||
|
fullAddress: addressData.address || this.getFullAddress(addressData), |
||||
|
isDefault: addressData.is_default == 1, |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
// 检查storage中的选中地址 |
||||
|
checkSelectedAddress() { |
||||
|
try { |
||||
|
const selectedAddress = uni.getStorageSync("selectedAddress"); |
||||
|
if (selectedAddress) { |
||||
|
this.updateAddressInfo(selectedAddress); |
||||
|
// 清除storage |
||||
|
uni.removeStorageSync("selectedAddress"); |
||||
|
return true; // 表示找到了选中的地址 |
||||
|
} |
||||
|
return false; |
||||
|
} catch (error) { |
||||
|
console.error("读取选中地址失败:", error); |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 获取完整地址 |
||||
|
getFullAddress(addressData) { |
||||
|
const province = addressData.province_text || ""; |
||||
|
const city = addressData.city_text || ""; |
||||
|
const district = addressData.district_text || ""; |
||||
|
const detail = addressData.detail_addr || ""; |
||||
|
return `${province}${city}${district}${detail}`; |
||||
|
}, |
||||
|
|
||||
|
// 格式化手机号 |
||||
|
formatPhone(phone) { |
||||
|
if (!phone) return ""; |
||||
|
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2"); |
||||
|
}, |
||||
|
|
||||
|
// 选择收货地址 |
||||
|
selectAddress() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/subPackages/user/travelerList?from=orderConfirm", |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 日期变化回调 |
||||
|
onDateChange(date) { |
||||
|
this.selectedDate = date; |
||||
|
console.log("选择的日期:", date); |
||||
|
}, |
||||
|
|
||||
|
// 选择履约方式 |
||||
|
selectDeliveryMethod() { |
||||
|
const itemList = ["预约发货+到店核销", "预约发货+快递配送", "到店自提"]; |
||||
|
|
||||
|
uni.showActionSheet({ |
||||
|
itemList: itemList, |
||||
|
success: (res) => { |
||||
|
this.deliveryMethod = itemList[res.tapIndex]; |
||||
|
console.log("选择的履约方式:", this.deliveryMethod); |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.log("取消选择履约方式"); |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 加载商品信息 |
||||
|
async loadGoodsInfo(goodsId) { |
||||
|
try { |
||||
|
// 这里调用实际的API接口获取商品详情 |
||||
|
const goodsData = await this.getGoodsDetail(goodsId); |
||||
|
this.goodsInfo = goodsData; |
||||
|
this.supplier = goodsData.supplier; |
||||
|
this.totalAmount = goodsData.price; |
||||
|
} catch (error) { |
||||
|
console.error("加载商品信息失败:", error); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 加载默认地址 |
||||
|
async loadDefaultAddress() { |
||||
|
try { |
||||
|
// 这里调用实际的API接口获取默认地址 |
||||
|
const addressData = await this.getDefaultAddress(); |
||||
|
if (addressData && !this.address.id) { |
||||
|
// 只有当前没有地址时才设置默认地址 |
||||
|
this.updateAddressInfo(addressData); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error("加载默认地址失败:", error); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 提交订单 |
||||
|
async submitOrder() { |
||||
|
// 验证必填项 |
||||
|
if (!this.selectedDate) { |
||||
|
uni.showToast({ |
||||
|
title: "请选择预约日期", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!this.deliveryMethod) { |
||||
|
uni.showToast({ |
||||
|
title: "请选择履约方式", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!this.address.name) { |
||||
|
uni.showToast({ |
||||
|
title: "请选择收货地址", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
uni.showLoading({ |
||||
|
title: "提交中...", |
||||
|
}); |
||||
|
|
||||
|
const orderData = { |
||||
|
goodsId: this.goodsInfo.id, |
||||
|
addressId: this.address.id, |
||||
|
deliveryDate: this.selectedDate, |
||||
|
deliveryMethod: this.deliveryMethod, |
||||
|
note: this.note, |
||||
|
totalAmount: this.totalAmount, |
||||
|
}; |
||||
|
|
||||
|
const result = await this.createOrder(orderData); |
||||
|
|
||||
|
uni.hideLoading(); |
||||
|
|
||||
|
if (result.success) { |
||||
|
uni.showToast({ |
||||
|
title: "订单提交成功", |
||||
|
icon: "success", |
||||
|
}); |
||||
|
|
||||
|
// 跳转到订单详情或订单列表 |
||||
|
setTimeout(() => { |
||||
|
uni.redirectTo({ |
||||
|
url: "/subPackages/orderQy/detail?orderId=" + result.orderId, |
||||
|
}); |
||||
|
}, 1500); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
uni.hideLoading(); |
||||
|
console.error("提交订单失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "提交失败,请重试", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// API接口 - 获取商品详情 |
||||
|
async getGoodsDetail(goodsId) { |
||||
|
// 模拟API数据 |
||||
|
return new Promise((resolve) => { |
||||
|
setTimeout(() => { |
||||
|
resolve({ |
||||
|
id: goodsId, |
||||
|
name: "食在苏州 | 世界美食之都巡礼+实物探真", |
||||
|
desc: "商品规格信息描述", |
||||
|
price: "699.00", |
||||
|
image: "/static/image/goods-sample.jpg", |
||||
|
supplier: "苏州XXX博物馆", |
||||
|
}); |
||||
|
}, 500); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// API接口 - 获取默认地址 |
||||
|
async getDefaultAddress() { |
||||
|
// 模拟API数据 |
||||
|
return new Promise((resolve) => { |
||||
|
setTimeout(() => { |
||||
|
resolve({ |
||||
|
id: 1, |
||||
|
name: "XX先生", |
||||
|
tel: "18312341234", |
||||
|
address: "江苏省苏州市姑苏区XXXXXX", |
||||
|
province_text: "江苏省", |
||||
|
city_text: "苏州市", |
||||
|
district_text: "姑苏区", |
||||
|
detail_addr: "XXXXXX", |
||||
|
is_default: 1, |
||||
|
}); |
||||
|
}, 500); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// API接口 - 创建订单 |
||||
|
async createOrder(orderData) { |
||||
|
// 模拟API调用 |
||||
|
return new Promise((resolve) => { |
||||
|
setTimeout(() => { |
||||
|
resolve({ |
||||
|
success: true, |
||||
|
orderId: "EQ" + Date.now(), |
||||
|
}); |
||||
|
}, 1000); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
// 主题色彩变量 |
||||
|
$primary-color: #667eea; |
||||
|
$secondary-color: #f8f9fa; |
||||
|
$text-primary: #2d3748; |
||||
|
$text-secondary: #718096; |
||||
|
$text-muted: #a0aec0; |
||||
|
$border-color: #e2e8f0; |
||||
|
$success-color: #48bb78; |
||||
|
$warning-color: #ed8936; |
||||
|
$danger-color: #f56565; |
||||
|
$bg-light: #f7fafc; |
||||
|
|
||||
|
.confirm-container { |
||||
|
height: 100vh; |
||||
|
background-color: $bg-light; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.content-scroll { |
||||
|
flex: 1; |
||||
|
padding: 20rpx; |
||||
|
width: 710rpx; |
||||
|
} |
||||
|
|
||||
|
// 通用section样式 |
||||
|
.section-header, |
||||
|
.section-row { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 24rpx 30rpx; |
||||
|
background-color: #ffffff; |
||||
|
border-radius: 16rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.section-title { |
||||
|
font-size: 28rpx; |
||||
|
color: $text-primary; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 16rpx; |
||||
|
|
||||
|
.required { |
||||
|
color: $danger-color; |
||||
|
margin-left: 4rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 收货地址 |
||||
|
.address-section { |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.address-info { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.user-info { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 12rpx; |
||||
|
gap: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.username { |
||||
|
font-size: 28rpx; |
||||
|
color: $text-primary; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
.phone { |
||||
|
font-size: 24rpx; |
||||
|
color: $text-secondary; |
||||
|
} |
||||
|
|
||||
|
.default-tag { |
||||
|
font-size: 20rpx; |
||||
|
color: $primary-color; |
||||
|
background-color: rgba(102, 126, 234, 0.1); |
||||
|
padding: 4rpx 12rpx; |
||||
|
border-radius: 12rpx; |
||||
|
} |
||||
|
|
||||
|
.address-detail { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-secondary; |
||||
|
line-height: 1.4; |
||||
|
} |
||||
|
|
||||
|
// 空地址状态 |
||||
|
.empty-address { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 24rpx 30rpx; |
||||
|
background-color: #ffffff; |
||||
|
border-radius: 16rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
border: 2rpx dashed $border-color; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
&:active { |
||||
|
background-color: rgba(102, 126, 234, 0.02); |
||||
|
border-color: $primary-color; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.empty-address-content { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.empty-address-text { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 6rpx; |
||||
|
} |
||||
|
|
||||
|
.empty-title { |
||||
|
font-size: 28rpx; |
||||
|
color: $text-primary; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.empty-tip { |
||||
|
font-size: 24rpx; |
||||
|
color: $text-muted; |
||||
|
} |
||||
|
|
||||
|
// 预约日期 |
||||
|
.date-section { |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.date-picker-container { |
||||
|
background-color: #ffffff; |
||||
|
border-radius: 16rpx; |
||||
|
padding: 24rpx 30rpx; |
||||
|
} |
||||
|
|
||||
|
.date-input { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.date-text { |
||||
|
font-size: 28rpx; |
||||
|
color: $text-primary; |
||||
|
|
||||
|
&.placeholder { |
||||
|
color: $text-muted; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 商品信息 |
||||
|
.goods-section { |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.goods-card { |
||||
|
display: flex; |
||||
|
background-color: #ffffff; |
||||
|
border-radius: 16rpx; |
||||
|
padding: 24rpx; |
||||
|
gap: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.goods-image { |
||||
|
width: 120rpx; |
||||
|
height: 120rpx; |
||||
|
border-radius: 12rpx; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.goods-info { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 12rpx; |
||||
|
} |
||||
|
|
||||
|
.goods-name { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-primary; |
||||
|
font-weight: 600; |
||||
|
line-height: 1.4; |
||||
|
} |
||||
|
|
||||
|
.goods-desc { |
||||
|
font-size: 24rpx; |
||||
|
color: $text-secondary; |
||||
|
line-height: 1.3; |
||||
|
} |
||||
|
|
||||
|
.goods-price { |
||||
|
font-size: 32rpx; |
||||
|
color: $danger-color; |
||||
|
font-weight: 600; |
||||
|
margin-top: auto; |
||||
|
} |
||||
|
|
||||
|
// 履约方式 |
||||
|
.delivery-section { |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.section-label { |
||||
|
font-size: 28rpx; |
||||
|
color: $text-primary; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.section-value { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
text { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-primary; |
||||
|
|
||||
|
&.placeholder { |
||||
|
color: $text-muted; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 备注 |
||||
|
.note-section { |
||||
|
margin-bottom: 24rpx; |
||||
|
|
||||
|
.section-row { |
||||
|
align-items: flex-start; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.note-input { |
||||
|
flex: 1; |
||||
|
margin-left: 40rpx; |
||||
|
|
||||
|
input { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-primary; |
||||
|
text-align: right; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.placeholder { |
||||
|
color: $text-muted; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 费用明细 |
||||
|
.cost-section { |
||||
|
background-color: #ffffff; |
||||
|
border-radius: 16rpx; |
||||
|
padding: 24rpx 30rpx; |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.cost-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 16rpx 0; |
||||
|
|
||||
|
&:not(:last-child) { |
||||
|
border-bottom: 1px solid $border-color; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.cost-label { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-primary; |
||||
|
} |
||||
|
|
||||
|
.cost-value { |
||||
|
font-size: 26rpx; |
||||
|
color: $text-primary; |
||||
|
|
||||
|
&.coupon { |
||||
|
color: $text-muted; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 底部提交区域 |
||||
|
.submit-section { |
||||
|
flex-shrink: 0; // 防止被压缩 |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding: 24rpx 30rpx; |
||||
|
background-color: #ffffff; |
||||
|
border-top: 1px solid $border-color; |
||||
|
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04); |
||||
|
|
||||
|
// 添加安全区域适配 |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
} |
||||
|
|
||||
|
.submit-section-content { |
||||
|
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); |
||||
|
} |
||||
|
|
||||
|
.total-price { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.total-amount { |
||||
|
font-size: 36rpx; |
||||
|
color: $danger-color; |
||||
|
font-weight: 600; |
||||
|
font-family: "SF Mono", "Monaco", "Cascadia Code", monospace; |
||||
|
} |
||||
|
|
||||
|
.submit-btn { |
||||
|
background-color: $text-primary; |
||||
|
color: #ffffff; |
||||
|
border: none; |
||||
|
border-radius: 32rpx; |
||||
|
padding: 4rpx 48rpx; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 600; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
&:active { |
||||
|
transform: scale(0.95); |
||||
|
background-color: rgba(45, 55, 72, 0.8); |
||||
|
} |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue