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> |
@ -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