Browse Source

Merge branch 'dev_des' of http://123.60.98.226:3000/jiazhipeng/EpicSoul into dev_des

dev_des
zhangminghao 4 weeks ago
parent
commit
d6b67b3ef8
  1. 669
      components/WaterfallLayout.vue
  2. 6
      pages.json
  3. 18
      pages/index/iSoul.vue
  4. 290
      pages/index/timeShopBank.vue
  5. 404
      pages/notes/detail.vue
  6. 397
      pages/notes/publish.vue
  7. 2
      static/js/CommonFunction.js
  8. 4
      static/js/request.js
  9. 72
      subPackages/haveFeeling/detail.vue
  10. 1113
      subPackages/haveFeeling/detailAll.vue
  11. 67
      subPackages/haveFeeling/list.vue
  12. 1295
      uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue

669
components/WaterfallLayout.vue

@ -1,299 +1,384 @@
<template> <template>
<view class="waterfall-layout"> <view class="waterfall-layout">
<view class="waterfall-container"> <!-- 空状态 -->
<!-- 左列 --> <view v-if="!leftItems.length && !rightItems.length" class="empty-state">
<view class="column"> <text class="empty-title">暂无内容</text>
<view v-for="(item, index) in leftItems" :key="item.id || index" class="waterfall-item" <text class="empty-desc">快来发布第一篇笔记吧</text>
@click="handleItemClick(item)"> </view>
<image v-if="item.image" :src="showImg(item.image)" class="item-image" mode="aspectFill" />
<view class="item-content"> <!-- 瀑布流内容 -->
<text v-if="item.title" class="item-title">{{ item.title }}</text> <view v-else class="waterfall-container">
<view class="item-footer"> <!-- 左列 -->
<view class="user-info"> <view class="column">
<image <view
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100" v-for="(item, index) in leftItems"
class="user-avatar" mode="aspectFill" /> :key="item.id || index"
<text class="username">风景之旅</text> class="waterfall-item"
</view> @click="handleItemClick(index, leftItems)"
<view class="like-info"> >
<image :src="showImg('/uploads/20250731/0260884d7a44a483885a026da524e0b8.png')" <image
style="height: 22rpx;width: 25rpx;"></image> v-if="item.coverImage"
<text class="like-count">100</text> :src="item.coverImage && item.coverImage.split(',')[0]"
</view> class="item-image"
</view> mode="aspectFill"
</view> />
</view> <view class="item-content">
</view> <text v-if="item.title" class="item-title">{{ item.title }}</text>
<view class="item-footer">
<!-- 右列 --> <view class="user-info">
<view class="column"> <image
<view v-for="(item, index) in rightItems" :key="item.id || index" class="waterfall-item" :src="item.headImg"
@click="handleItemClick(item)"> class="user-avatar"
<image v-if="item.image" :src="showImg(item.image)" class="item-image" mode="aspectFill" /> mode="aspectFill"
<view class="item-content"> />
<text v-if="item.title" class="item-title">{{ item.title }}</text> <text class="username">{{ item.nickname }}</text>
<view class="item-footer"> </view>
<view class="user-info"> <view class="like-info">
<image <image
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100" v-if="!item.userLiked"
class="user-avatar" mode="aspectFill" /> src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png"
<text class="username">风景之旅</text> style="height: 22rpx; width: 25rpx"
</view> ></image>
<view class="like-info"> <image
<image :src="showImg('/uploads/20250731/0260884d7a44a483885a026da524e0b8.png')" v-else
style="height: 22rpx;width: 25rpx;"></image> src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png"
<text class="like-count">120</text> style="height: 22rpx; width: 25rpx"
</view> ></image>
</view> <text class="like-count">{{ item.likeCount || 0 }}</text>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 右列 -->
<view class="column">
<view
v-for="(item, index) in rightItems"
:key="item.id || index"
class="waterfall-item"
@click="handleItemClick(index, rightItems)"
>
<image
v-if="item.coverImage"
:src="item.coverImage && item.coverImage.split(',')[0]"
class="item-image"
mode="aspectFill"
/>
<view class="item-content">
<text v-if="item.title" class="item-title">{{ item.title }}</text>
<view class="item-footer">
<view class="user-info">
<image
:src="item.headImg"
class="user-avatar"
mode="aspectFill"
/>
<text class="username"
>{{ item.nickname }}{{ item.nickname
}}{{ item.nickname }}</text
>
</view>
<view class="like-info">
<image
v-if="!item.userLiked"
src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png"
style="height: 22rpx; width: 25rpx"
></image>
<image
v-else
src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png"
style="height: 22rpx; width: 25rpx"
></image>
<text class="like-count">{{ item.likeCount || 0 }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template> </template>
<script> <script>
export default { export default {
name: "WaterfallLayout", name: "WaterfallLayout",
props: { props: {
// //
items: { items: {
type: Array, type: Array,
default: () => [], default: () => [],
}, },
// 2 // 2
columnCount: { columnCount: {
type: Number, type: Number,
default: 2, default: 2,
}, },
// rpx // rpx
columnGap: { columnGap: {
type: Number, type: Number,
default: 16, default: 16,
}, },
// rpx // rpx
itemGap: { itemGap: {
type: Number, type: Number,
default: 16, default: 16,
}, },
}, },
data() { data() {
return { return {
leftItems: [], leftItems: [],
rightItems: [], rightItems: [],
}; };
}, },
watch: { watch: {
items: { items: {
handler(newItems) { handler(newItems) {
this.calculateLayout(newItems); this.calculateLayout(newItems);
}, },
immediate: true, immediate: true,
deep: true, deep: true,
}, },
}, },
mounted() { mounted() {
this.calculateLayout(this.items); this.calculateLayout(this.items);
}, },
methods: { methods: {
// DOM // DOM
getColumnHeight(columnRef) { getColumnHeight(columnRef) {
if (!columnRef) return 0; if (!columnRef) return 0;
const query = uni.createSelectorQuery().in(this); const query = uni.createSelectorQuery().in(this);
return new Promise((resolve) => { return new Promise((resolve) => {
query.select(columnRef).boundingClientRect((data) => { query
resolve(data ? data.height : 0); .select(columnRef)
}).exec(); .boundingClientRect((data) => {
}); resolve(data ? data.height : 0);
}, })
.exec();
// });
calculateLayout(items) { },
if (!items || !items.length) {
this.leftItems = []; //
this.rightItems = []; calculateLayout(items) {
return; if (!items || !items.length) {
} this.leftItems = [];
this.rightItems = [];
// return;
this.leftItems = []; }
this.rightItems = [];
//
// this.leftItems = [];
for (let i = 0; i < items.length; i++) { this.rightItems = [];
this.addItem(items[i]);
} //
}, for (let i = 0; i < items.length; i++) {
this.addItem(items[i]);
// }
addItem(item) { },
//
if (this.leftItems.length <= this.rightItems.length) { //
this.leftItems.push(item); addItem(item) {
} else { //
this.rightItems.push(item); if (this.leftItems.length <= this.rightItems.length) {
} this.leftItems.push(item);
}, } else {
this.rightItems.push(item);
// }
clearItems() { },
this.leftItems = [];
this.rightItems = []; //
this.$emit("items-cleared"); clearItems() {
}, this.leftItems = [];
this.rightItems = [];
// this.$emit("items-cleared");
handleItemClick(item) { },
this.$emit("item-click", item);
}, //
handleItemClick(index, list) {
// this.$emit("item-click", list[index]);
getAllItems() { },
return [...this.leftItems, ...this.rightItems];
}, //
getAllItems() {
// return [...this.leftItems, ...this.rightItems];
removeItem(itemId) { },
//
let index = this.leftItems.findIndex(item => item.id === itemId); //
if (index !== -1) { removeItem(itemId) {
this.leftItems.splice(index, 1); //
this.$emit("item-removed", itemId); let index = this.leftItems.findIndex((item) => item.id === itemId);
return; if (index !== -1) {
} this.leftItems.splice(index, 1);
this.$emit("item-removed", itemId);
// return;
index = this.rightItems.findIndex(item => item.id === itemId); }
if (index !== -1) {
this.rightItems.splice(index, 1); //
this.$emit("item-removed", itemId); index = this.rightItems.findIndex((item) => item.id === itemId);
} if (index !== -1) {
}, this.rightItems.splice(index, 1);
}, this.$emit("item-removed", itemId);
}; }
},
},
};
</script> </script>
<style scoped> <style scoped>
.waterfall-layout { .waterfall-layout {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
.waterfall-container { /* 空状态样式 */
display: flex; .empty-state {
gap: 16rpx; display: flex;
padding: 0 20rpx; flex-direction: column;
box-sizing: border-box; align-items: center;
} justify-content: center;
padding: 160rpx 40rpx;
.column { text-align: center;
flex: 1; }
display: flex;
flex-direction: column; .empty-icon {
gap: 16rpx; width: 240rpx;
} height: 240rpx;
margin-bottom: 40rpx;
.waterfall-item { opacity: 0.6;
box-sizing: border-box; }
border-radius: 12rpx;
background: #fff; .empty-title {
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); font-size: 32rpx;
overflow: hidden; color: #666;
transition: transform 0.2s ease; margin-bottom: 16rpx;
} font-weight: 500;
}
.waterfall-item:active {
transform: scale(0.98); .empty-desc {
} font-size: 28rpx;
color: #999;
.item-image { line-height: 1.4;
width: 100%; }
height: 476rpx;
object-fit: cover; .waterfall-container {
} display: flex;
gap: 16rpx;
.item-content { padding: 0 20rpx;
padding: 16rpx; box-sizing: border-box;
} }
.item-title { .column {
font-size: 28rpx; flex: 1;
font-weight: 600; display: flex;
color: #333; flex-direction: column;
line-height: 1.3; gap: 16rpx;
margin-bottom: 12rpx; }
display: -webkit-box;
-webkit-box-orient: vertical; .waterfall-item {
-webkit-line-clamp: 2; box-sizing: border-box;
overflow: hidden; border-radius: 12rpx;
text-overflow: ellipsis; background: #fff;
} box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
.item-desc { transition: transform 0.2s ease;
font-size: 24rpx; }
color: #666;
line-height: 1.4; .waterfall-item:active {
margin-bottom: 16rpx; transform: scale(0.98);
display: -webkit-box; }
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; .item-image {
overflow: hidden; width: 100%;
text-overflow: ellipsis; height: 476rpx;
} object-fit: cover;
}
.item-tags {
display: flex; .item-content {
flex-wrap: wrap; padding: 16rpx;
gap: 8rpx; }
margin-bottom: 16rpx;
} .item-title {
font-size: 28rpx;
.tag { font-weight: 600;
padding: 4rpx 12rpx; color: #333;
background: #f5f5f5; line-height: 1.3;
color: #666; margin-bottom: 12rpx;
font-size: 20rpx; display: -webkit-box;
border-radius: 12rpx; -webkit-box-orient: vertical;
white-space: nowrap; -webkit-line-clamp: 2;
} overflow: hidden;
text-overflow: ellipsis;
.item-footer { }
display: flex;
justify-content: space-between; .item-desc {
align-items: center; font-size: 24rpx;
margin-top: 16rpx; color: #666;
} line-height: 1.4;
margin-bottom: 16rpx;
.user-info { display: -webkit-box;
display: flex; -webkit-box-orient: vertical;
align-items: center; -webkit-line-clamp: 2;
gap: 12rpx; overflow: hidden;
} text-overflow: ellipsis;
}
.user-avatar {
width: 32rpx; .item-tags {
height: 32rpx; display: flex;
border-radius: 50%; flex-wrap: wrap;
} gap: 8rpx;
margin-bottom: 16rpx;
.username { }
font-size: 22rpx;
color: #666; .tag {
} padding: 4rpx 12rpx;
background: #f5f5f5;
.like-info { color: #666;
display: flex; font-size: 20rpx;
align-items: center; border-radius: 12rpx;
gap: 6rpx; white-space: nowrap;
} }
.like-icon { .item-footer {
font-size: 24rpx; display: flex;
color: #ff6b6b; justify-content: space-between;
} align-items: center;
margin-top: 16rpx;
.like-count { }
font-size: 22rpx;
color: #666; .user-info {
} display: flex;
</style> align-items: center;
gap: 12rpx;
}
.user-avatar {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
}
.username {
font-size: 22rpx;
color: #666;
width: 160rpx;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.like-info {
display: flex;
align-items: center;
gap: 6rpx;
}
.like-icon {
font-size: 24rpx;
color: #ff6b6b;
}
.like-count {
font-size: 22rpx;
color: #666;
}
</style>

6
pages.json

@ -272,6 +272,12 @@
"navigationBarTitleText": "订单详情" "navigationBarTitleText": "订单详情"
} }
}, },
{
"path": "haveFeeling/detailAll",
"style": {
"navigationBarTitleText": "订单详情"
}
},
{ {
"path": "haveFeeling/logistics", "path": "haveFeeling/logistics",
"style": { "style": {

18
pages/index/iSoul.vue

@ -234,6 +234,7 @@
</view> </view>
<view class="goods-card"> <view class="goods-card">
<image <image
@click="gotoPath('/subPackages/haveFeeling/list')"
:src=" :src="
showImg('/uploads/20250729/a010feb51e3f195563fb440f9235cc8b.png') showImg('/uploads/20250729/a010feb51e3f195563fb440f9235cc8b.png')
" "
@ -716,19 +717,14 @@ export default {
break; break;
case "待发货": case "待发货":
uni.navigateTo({ uni.navigateTo({
url: "/subPackages/order/trades?status=POST", url: "/subPackages/haveFeeling/list?status=2",
});
break;
case "退货/退款":
uni.navigateTo({
url: "/subPackages/order/trades?status=WAIT_REFUND",
});
break;
case "评价":
uni.navigateTo({
url: "/subPackages/order/trades?status=WAIT_COMMENT",
}); });
break; break;
default:
uni.showToast({
title:'功能暂未开放',
icon:'none'
})
} }
}, },
// //

290
pages/index/timeShopBank.vue

@ -9,22 +9,21 @@
:page-id="'timeShopBank_page'" :page-id="'timeShopBank_page'"
:style-type="'timeShop'" :style-type="'timeShop'"
/> />
<view class="desc-box"> <view class="desc-box">
<view class=""> <view class=""> 欢迎来到旅行时间行你的精神财富储蓄所 </view>
欢迎来到旅行时间行你的精神财富储蓄所 <view class="">
</view> 在这里你的每一次人文漫游每一次灵感闪现都值得被郑重记录我们鼓励你分享高质量的图文笔记将旅途中的美与感动化为这座精神星球上的璀璨星辰
<view class=""> </view>
在这里你的每一次人文漫游每一次灵感闪现都值得被郑重记录我们鼓励你分享高质量的图文笔记将旅途中的美与感动化为这座精神星球上的璀璨星辰 <view class="">
</view> 为他人的美好驻足点赞留言每一次真诚的互动都是在为你的时间银行存入一笔宝贵的精神货币这些资产不仅可以兑换独家福利与实体好物更能为你解锁专属的荣誉身份让你成为这座星球上最闪耀的共创者
<view class=""> </view>
为他人的美好驻足点赞留言每一次真诚的互动都是在为你的时间银行存入一笔宝贵的精神货币这些资产不仅可以兑换独家福利与实体好物更能为你解锁专属的荣誉身份让你成为这座星球上最闪耀的共创者 <view class=""> 即刻发布你的第一篇笔记开启你的财富积累之旅吧 </view>
</view> </view>
<view class="">
即刻发布你的第一篇笔记开启你的财富积累之旅吧 <image
</view> style="width: 700rpx; height: 14rpx; margin: 20rpx auto; display: block"
</view> :src="showImg('/uploads/20250829/f7214bc2a4f4e236561de893ca7b9113.png')"
></image>
<image style="width: 700rpx;height: 14rpx;margin: 20rpx auto;display: block;" :src="showImg('/uploads/20250829/f7214bc2a4f4e236561de893ca7b9113.png')"></image>
<!-- Tab切换组件 --> <!-- Tab切换组件 -->
<view class="tab-container"> <view class="tab-container">
@ -44,7 +43,7 @@
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="content-area"> <view class="content-area">
<view v-if="currentTab == 0" class="notes-content"> <view v-if="currentTab == 0" class="notes-content">
<view class="fab-container"> <view class="fab-container">
<image <image
:src=" :src="
@ -62,34 +61,35 @@
style="margin-top: 20rpx" style="margin-top: 20rpx"
/> />
</view> </view>
<!-- <view v-if="currentTab === 0" class="follow-content recommend-content"> <!-- <view v-if="currentTab === 0" class="follow-content recommend-content">
<text class="coming-soon">笔记功能开发中...</text> <text class="coming-soon">笔记功能开发中...</text>
</view> --> </view> -->
<!-- 关注tab内容 --> <!-- 关注tab内容 -->
<view v-if="currentTab == 1" class="follow-content "> <view v-if="currentTab == 1" class="follow-content">
<FollowTab /> <FollowTab />
<!-- <text class="coming-soon">关注功能开发中...</text> --> <!-- <text class="coming-soon">关注功能开发中...</text> -->
</view> </view>
<!-- 推荐tab内容 --> <!-- 推荐tab内容 -->
<view v-if="currentTab == 2" class="notes-content"> <view v-if="currentTab == 2" class="notes-content">
<view class="fab-container"> <view class="fab-container">
<image <image
:src=" @click="goToPublish"
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png') :src="
" showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
style="width: 91rpx; height: 91rpx" "
></image> style="width: 91rpx; height: 91rpx"
</view> ></image>
<WaterfallLayout </view>
:items="waterfallItems" <WaterfallLayout
:column-count="2" :items="waterfallItems"
:column-gap="16" :column-count="2"
:item-gap="16" :column-gap="16"
@item-click="handleItemClick" :item-gap="16"
style="margin-top: 20rpx" @item-click="handleItemClick"
/> style="margin-top: 20rpx"
</view> />
</view>
</view> </view>
<!-- 控制按钮 --> <!-- 控制按钮 -->
@ -126,94 +126,29 @@ export default {
}, },
data() { data() {
return { return {
currentTab: 0, // "" currentTab: 2, // ""
tabs: [ tabs: [
{ name: "笔记", id: "notes" }, { name: "笔记", id: "notes" },
{ name: "关注", id: "follow" }, { name: "关注", id: "follow" },
{ name: "推荐", id: "recommend" }, { name: "推荐", id: "recommend" },
], ],
waterfallItems: [ waterfallItems: [],
{ //
title: "生命的扶持|风景之旅", pageNum: 1,
image: "/uploads/20250824/2cf1f49920b911c9d14e4abf3b67a59c.png", pageSize: 10,
}, loading: false,
{ hasMore: true,
title: "苏州丨园林之美 鱼戏莲叶间心随鱼鸟闲",
image: "/uploads/20250824/c209044a821630158f6e6771805682a7.png",
},
{
title: "蘇州|你一句春不晚,我便出现在真江南",
image: "/uploads/20250824/74101a77233375625282209392dc69e3.png",
},
{
title: "收好这天然氧吧",
image: "/uploads/20250824/e0ab7fd0483d05742451e8f10ab3ce24.png",
},
],
autoAddEnabled: false, autoAddEnabled: false,
// URL
images: [
"/uploads/20250824/2cf1f49920b911c9d14e4abf3b67a59c.png",
"https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?auto=format&fit=crop&w=800",
"https://images.unsplash.com/photo-1441974231531-c6227db76b6e?auto=format&fit=crop&w=800",
"https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=800",
"https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?auto=format&fit=crop&w=800",
],
//
avatars: [
"https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100",
"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=100",
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=100",
"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=100",
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=100",
],
//
usernames: [
"杨璐摄影",
"旅行者小王",
"风景猎人",
"自然探索者",
"摄影师阿明",
],
//
shortTitles: ["城市风光", "自然美景", "湖光山色", "森林小径", "日出东方"],
mediumTitles: [
"繁华都市的夜景与灯光",
"壮丽的山脉与蓝天白云",
"宁静的湖泊与秋日树木",
"蜿蜒的小路穿过金色森林",
"清晨第一缕阳光照亮大地",
],
longTitles: [
"现代都市天际线在黄昏时分展现出迷人的轮廓,灯火辉煌的建筑倒映在水面上",
"雄伟的山脉在云雾缭绕中若隐若现,展现出大自然的壮丽与神秘",
"平静如镜的湖面倒映着五彩斑斓的秋叶,构成一幅完美的自然画卷",
"阳光透过茂密的树叶,在铺满落叶的林间小路上投下斑驳的光影",
"清晨的太阳从地平线缓缓升起,金色的光芒洒满整个大地,带来新的一天",
],
descriptions: [
"探索城市中隐藏的美丽角落,发现不为人知的风景",
"大自然的鬼斧神工创造了无数令人惊叹的景观",
"水与山的完美结合,创造出宁静致远的意境",
"漫步在森林中,感受大自然的清新与宁静",
"日出时分的美景总能带给人们希望和力量",
],
tagsList: [
["城市", "摄影", "旅行"],
["自然", "山脉", "探险"],
["湖泊", "秋天", "风景"],
["森林", "小路", "自然"],
["日出", "早晨", "美景"],
],
}; };
}, },
onLoad() { onLoad() {
this.initializeData();
this.userInfo = this.userInfo =
(uni.getStorageSync("userInfo") && (uni.getStorageSync("userInfo") &&
JSON.parse(uni.getStorageSync("userInfo"))) || JSON.parse(uni.getStorageSync("userInfo"))) ||
this.$store.state.user.userInfo || this.$store.state.user.userInfo ||
{}; {};
//
this.getRecommendList(1);
}, },
onShow() { onShow() {
if (this.userInfo && this.userInfo.id) { if (this.userInfo && this.userInfo.id) {
@ -242,50 +177,46 @@ export default {
}); });
}); });
}, },
//
getRandomItem() {
const titleType =
Math.random() > 0.5
? Math.random() > 0.5
? this.longTitles
: this.mediumTitles
: this.shortTitles;
return {
id: Date.now() + Math.floor(Math.random() * 1000),
title: titleType[Math.floor(Math.random() * titleType.length)],
image: this.images[Math.floor(Math.random() * this.images.length)],
// description:
// this.descriptions[
// Math.floor(Math.random() * this.descriptions.length)
// ],
// tags: this.tagsList[Math.floor(Math.random() * this.tagsList.length)],
//
user: {
avatar: this.avatars[Math.floor(Math.random() * this.avatars.length)],
name: this.usernames[
Math.floor(Math.random() * this.usernames.length)
],
},
likes: Math.floor(Math.random() * 999) + 1, // 1-999
};
},
// //
initializeData() { getRecommendList(type = 1) {
const initialItems = []; if (this.loading) return;
for (let i = 0; i < 20; i++) {
initialItems.push(this.getRandomItem());
}
// this.waterfallItems = initialItems;
},
// this.loading = true;
addRandomItem() { const params = {
const newItem = this.getRandomItem(); pageNum: this.pageNum,
// this.waterfallItems.push(newItem); pageSize: this.pageSize,
}, type: type, // 0: tab, 1: tab
};
this.Post(params, "/framework/note/list", "DES")
.then((res) => {
if (res.code === 200 && res.rows) {
const newItems = res.rows || [];
if (this.pageNum === 1) {
//
this.waterfallItems = newItems;
} else {
//
this.waterfallItems.push(...newItems);
}
//
this.hasMore = newItems.length === this.pageSize;
}
})
.catch((error) => {
console.error("获取推荐列表失败:", error);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
})
.finally(() => {
this.loading = false;
});
},
// //
clearAllItems() { clearAllItems() {
uni.showModal({ uni.showModal({
@ -301,9 +232,10 @@ export default {
// //
handleItemClick(item) { handleItemClick(item) {
console.log(item);
// //
uni.navigateTo({ uni.navigateTo({
url: `/pages/notes/detail`, url: `/pages/notes/detail?id=${item.id}`,
}); });
}, },
@ -319,16 +251,17 @@ export default {
// //
handleAutoAddRequest() { handleAutoAddRequest() {
this.addRandomItem(); this.loadMoreItems();
}, },
// //
loadMoreItems() { loadMoreItems() {
const newItems = []; if (!this.loading && this.hasMore) {
for (let i = 0; i < 10; i++) { this.pageNum++;
newItems.push(this.getRandomItem()); // tabtype: 0-, 1-
const type = this.currentTab === 0 ? 0 : 1;
this.getRecommendList(type);
} }
// this.waterfallItems.push(...newItems);
}, },
// Tab // Tab
@ -341,8 +274,14 @@ export default {
// tab // tab
loadTabContent(tabId) { loadTabContent(tabId) {
// tabId // tabId
// if (tabId === "notes") {
this.initializeData(); // tab:
this.pageNum = 1;
this.waterfallItems = [];
this.hasMore = true;
this.getRecommendList(0);
}
// tab
}, },
}, },
}; };
@ -498,6 +437,7 @@ page {
.content-area { .content-area {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
padding: 10rpx 0;
} }
.notes-content { .notes-content {
@ -521,20 +461,20 @@ page {
color: #999; color: #999;
} }
} }
.desc-box{ .desc-box {
padding: 0 20rpx; padding: 0 20rpx;
color: #616161; color: #616161;
margin: 30rpx 0; margin: 30rpx 0;
font-size: 24rpx; font-size: 24rpx;
padding: 0 40rpx; padding: 0 40rpx;
view{ view {
margin-bottom: 20rpx; margin-bottom: 20rpx;
&:nth-child(1){ &:nth-child(1) {
font-size: 24rpx; font-size: 24rpx;
font-weight: bold; font-weight: bold;
margin-bottom: 20rpx; margin-bottom: 20rpx;
} }
} }
} }
/* 自定义样式已移至WaterfallLayout组件内部 */ /* 自定义样式已移至WaterfallLayout组件内部 */

404
pages/notes/detail.vue

@ -14,14 +14,10 @@
@change="swiperChange" @change="swiperChange"
> >
<swiper-item v-for="(item, index) in topBanner" :key="index"> <swiper-item v-for="(item, index) in topBanner" :key="index">
<image <image class="top-banner" :src="item" mode="aspectFill" @click="previewImage(item)"></image>
class="top-banner"
:src="showImg(item)"
mode="aspectFill"
></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
<view class="dot-container"> <view class="dot-container">
<view <view
:class="['dot-line', index == swiperIndex ? 'active' : '']" :class="['dot-line', index == swiperIndex ? 'active' : '']"
@ -31,28 +27,26 @@
</view> </view>
</view> </view>
<!-- 内容卡片 --> <!-- 内容卡片 -->
<view class="content-card"> <view class="content-card">
<!-- 作者信息 --> <!-- 作者信息 -->
<view class="author-section"> <view class="author-section">
<image <image
class="author-avatar" class="author-avatar"
:src="showImg(noteDetail.user.avatar)" :src="noteDetail.headImg"
mode="aspectFill" mode="aspectFill"
/> />
<view class="author-info"> <view class="author-info">
<text class="author-name">{{ noteDetail.user.name }}</text> <text class="author-name">{{ noteDetail.nickname }}</text>
</view> </view>
<view <!-- <view
class="follow-btn" class="follow-btn"
:class="{ followed: noteDetail.user.isFollowed }" :class="{ followed: noteDetail.user.isFollowed }"
@click="toggleFollow" @click="toggleFollow"
> >
{{ noteDetail.user.isFollowed ? "已关注" : "关注" }} {{ noteDetail.user.isFollowed ? "已关注" : "关注" }}
</view> </view> -->
</view> </view>
<!-- 笔记标题 --> <!-- 笔记标题 -->
<view class="note-title"> <view class="note-title">
{{ noteDetail.title }} {{ noteDetail.title }}
@ -70,13 +64,29 @@
<!-- 笔记内容 --> <!-- 笔记内容 -->
<view class="note-content"> <view class="note-content">
<text class="content-text">{{ noteDetail.content }}</text> <view class="content-text">{{ noteDetail.content }}</view>
<!-- 标签名称 -->
<view class="tag-names" v-if="noteDetail.tagNames">
<text
v-for="(tag, index) in noteDetail.tagNames"
:key="index"
class="tag-link"
@click="handleTagClick(tag)"
>#{{ tag }}</text
>
</view>
</view> </view>
</view> </view>
<view class="" style="width: auto;height: 1rpx;background-color: #999999;margin: 60rpx 32rpx;"> <view
class=""
</view> style="
width: auto;
height: 1rpx;
background-color: #999999;
margin: 60rpx 32rpx;
"
>
</view>
<!-- 评论区域 --> <!-- 评论区域 -->
<view class="comments-section"> <view class="comments-section">
<view class="comments-header"> <view class="comments-header">
@ -113,31 +123,41 @@
<!-- 底部评论输入框 --> <!-- 底部评论输入框 -->
<view class="comment-input-section-box"> <view class="comment-input-section-box">
<view class="comment-input-section"> <view class="comment-input-section">
<input <input
class="comment-input" class="comment-input"
v-model="commentText" v-model="commentText"
placeholder="写下你的想法..." placeholder="写下你的想法..."
@confirm="submitComment" @confirm="submitComment"
/> />
<button <button
class="send-btn" class="send-btn"
@click="submitComment" @click="submitComment"
:disabled="!commentText.trim()" :disabled="!commentText.trim()"
> >
发送 发送
</button> </button>
<view class="like-section"> <view class="like-section" @click="toggleLike">
<image class="like-icon" mode="widthFix" :src="showImg('/uploads/20250826/3f4c0ccaaaccbef50bf8c5c27ff6a87b.png')"></image> <image
<!-- <text class="like-icon"
class="like-icon" mode="widthFix"
:class="{ liked: noteDetail.isLiked }" :src="
@click="toggleLike" !noteDetail.userLiked
></text ? showImg(
> --> 'https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png'
<text class="like-count">{{ noteDetail.likes }}</text> )
</view> : showImg(
</view> 'https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png'
)
"
></image>
<text
class="like-count"
:class="{ 'liked-text': noteDetail.userLiked }"
>{{ noteDetail.likeCount }}</text
>
</view>
</view>
</view> </view>
</view> </view>
</template> </template>
@ -154,8 +174,8 @@ export default {
return { return {
noteId: "", noteId: "",
commentText: "", commentText: "",
topBanner: ["/uploads/20250826/17356ed4dcdeedcd13de60ca28909d22.png"], topBanner: [],
swiperIndex: 0, swiperIndex: 0,
noteDetail: { noteDetail: {
id: "", id: "",
title: "", title: "",
@ -165,12 +185,8 @@ export default {
likes: 0, likes: 0,
isLiked: false, isLiked: false,
createTime: "", createTime: "",
user: { tagNames: [],
id: "",
name: "",
avatar: "",
isFollowed: false,
},
comments: [], comments: [],
}, },
}; };
@ -180,20 +196,41 @@ export default {
this.noteId = options.id; this.noteId = options.id;
this.loadNoteDetail(); this.loadNoteDetail();
} else { } else {
this.loadMockData(); uni.showToast({
title: "笔记ID不存在",
icon: "none",
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
} }
}, },
methods: { methods: {
swiperChange(e) { swiperChange(e) {
this.swiperIndex = e.detail.current; this.swiperIndex = e.detail.current;
}, },
// //
async loadNoteDetail() { async loadNoteDetail() {
try { try {
uni.showLoading({ title: "加载中..." }); uni.showLoading({ title: "加载中..." });
// API // API
const res = await this.getNoteDetail(this.noteId); const res = await this.Post(
this.noteDetail = res.data; { noteId: this.noteId },
"/framework/note/getInfo/" + this.noteId,
"DES"
);
if (res.code === 200) {
this.noteDetail = res.data;
this.noteDetail.tagNames = this.noteDetail.tagNames.split(",");
console.log(this.noteDetail.tagNames);
//
this.topBanner = this.noteDetail.coverImage.split(",");
} else {
uni.showToast({
title: res.msg || "加载失败",
icon: "none",
});
}
} catch (error) { } catch (error) {
console.error("加载笔记详情失败:", error); console.error("加载笔记详情失败:", error);
uni.showToast({ uni.showToast({
@ -232,8 +269,7 @@ export default {
user: { user: {
id: "user002", id: "user002",
name: "@小新", name: "@小新",
avatar: avatar: "/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
"/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
}, },
}, },
{ {
@ -244,8 +280,7 @@ export default {
user: { user: {
id: "user003", id: "user003",
name: "Mr.曾", name: "Mr.曾",
avatar: avatar: "/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
"/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
}, },
}, },
], ],
@ -255,24 +290,82 @@ export default {
// //
previewImage(imageUrl) { previewImage(imageUrl) {
uni.previewImage({ uni.previewImage({
urls: [imageUrl], urls: this.topBanner,
current: imageUrl, current: imageUrl,
}); });
}, },
// //
toggleFollow() { async toggleFollow() {
this.noteDetail.user.isFollowed = !this.noteDetail.user.isFollowed; try {
uni.showToast({ const action = this.noteDetail.user.isFollowed ? "cancel" : "follow";
title: this.noteDetail.user.isFollowed ? "已关注" : "取消关注", const res = await this.Post(
icon: "none", {
}); method: "POST",
userId: this.noteDetail.user.id,
action: action,
},
"/framework/user/follow",
"DES"
);
if (res.code === 200) {
this.noteDetail.user.isFollowed = !this.noteDetail.user.isFollowed;
uni.showToast({
title: this.noteDetail.user.isFollowed ? "已关注" : "取消关注",
icon: "success",
});
} else {
uni.showToast({
title:
res.msg || (action === "follow" ? "关注失败" : "取消关注失败"),
icon: "none",
});
}
} catch (error) {
console.error("关注操作失败:", error);
uni.showToast({
title: "操作失败",
icon: "none",
});
}
}, },
// //
toggleLike() { async toggleLike() {
this.noteDetail.isLiked = !this.noteDetail.isLiked; try {
this.noteDetail.likes += this.noteDetail.isLiked ? 1 : -1; const action = this.noteDetail.isLiked ? "cancel" : "like";
const res = await this.Post(
{
method: "POST",
noteId: this.noteId,
action: action,
},
"/framework/note/like",
"DES"
);
if (res.code === 200) {
this.noteDetail.isLiked = !this.noteDetail.isLiked;
this.noteDetail.likes += this.noteDetail.isLiked ? 1 : -1;
//
if (res.data && res.data.likeCount !== undefined) {
this.noteDetail.likes = res.data.likeCount;
}
} else {
uni.showToast({
title: res.msg || (action === "like" ? "点赞失败" : "取消点赞失败"),
icon: "none",
});
}
} catch (error) {
console.error("点赞操作失败:", error);
uni.showToast({
title: "操作失败",
icon: "none",
});
}
}, },
// //
@ -281,25 +374,42 @@ export default {
return; return;
} }
const newComment = { try {
id: "comment" + Date.now(), uni.showLoading({ title: "提交中..." });
content: this.commentText, const res = await this.Post(
createTime: new Date().toISOString(), {
user: { method: "POST",
id: "current_user", noteId: this.noteId,
name: "我", content: this.commentText,
avatar: },
"https://des.dayunyuanjian.cn/epicSoul/avatar-current.png", "/framework/note/comment/add",
}, "DES"
}; );
this.noteDetail.comments.unshift(newComment); if (res.code === 200) {
this.commentText = ""; //
this.loadNoteDetail();
uni.showToast({ this.commentText = "";
title: "评论成功",
icon: "success", uni.showToast({
}); title: "评论成功",
icon: "success",
});
} else {
uni.showToast({
title: res.msg || "评论失败",
icon: "none",
});
}
} catch (error) {
console.error("提交评论失败:", error);
uni.showToast({
title: "评论失败",
icon: "none",
});
} finally {
uni.hideLoading();
}
}, },
// //
@ -311,17 +421,29 @@ export default {
return `${year}/${month}/${day}`; return `${year}/${month}/${day}`;
}, },
// API - //
async getNoteDetail(noteId) { showImg(img) {
return new Promise((resolve) => { if (!img) return "/static/image/default-avatar.png";
setTimeout(() => { if (img.indexOf("https://") !== -1 || img.indexOf("http://") !== -1) {
this.loadMockData(); return img;
resolve({ } else {
code: 200, return this.NEWAPIURLIMG + img;
data: this.noteDetail, }
}); },
}, 100);
}); //
handleTagClick(tag) {
console.log("标签点击:", tag);
//
// uni.showToast({
// title: `: ${tag}`,
// icon: "none",
// });
// 使
// uni.navigateTo({
// url: `/pages/tags/detail?tag=${encodeURIComponent(tag)}`
// });
}, },
}, },
}; };
@ -382,10 +504,10 @@ export default {
font-size: 28rpx; font-size: 28rpx;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
border: 2rpx solid #02fcfc; border: 2rpx solid #02fcfc;
color: #333333; color: #333333;
background-color: white; background-color: white;
padding: 12rpx 30rpx; padding: 12rpx 30rpx;
&.followed { &.followed {
background: #ccc; background: #ccc;
} }
@ -433,7 +555,21 @@ padding: 12rpx 30rpx;
font-size: 30rpx; font-size: 30rpx;
line-height: 1.6; line-height: 1.6;
color: #333; color: #333;
font-weight: 500; font-weight: 500;
word-break: break-all;
}
.tag-names {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 24rpx;
.tag-link {
font-size: 28rpx;
color: #0066cc;
font-weight: 500;
}
} }
} }
@ -491,22 +627,22 @@ padding: 12rpx 30rpx;
} }
} }
} }
.comment-input-section-box{ .comment-input-section-box {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
z-index: 999; z-index: 999;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1); box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
border-top: 1rpx solid #f0f0f0; border-top: 1rpx solid #f0f0f0;
background: #fff; background: #fff;
} }
// //
.comment-input-section { .comment-input-section {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 24rpx 32rpx 0; padding: 24rpx 32rpx 0;
padding-bottom: max(env(safe-area-inset-bottom),24rpx); padding-bottom: max(env(safe-area-inset-bottom), 24rpx);
.comment-input { .comment-input {
flex: 1; flex: 1;
@ -542,7 +678,7 @@ padding: 12rpx 30rpx;
gap: 8rpx; gap: 8rpx;
.like-icon { .like-icon {
width:36rpx; width: 36rpx;
transition: color 0.3s; transition: color 0.3s;
&.liked { &.liked {
color: #ff4757; color: #ff4757;
@ -552,7 +688,11 @@ padding: 12rpx 30rpx;
.like-count { .like-count {
font-size: 30rpx; font-size: 30rpx;
color: #666; color: #666;
font-weight: bold; font-weight: bold;
&.liked-text {
color: #ff4757;
}
} }
} }
} }

397
pages/notes/publish.vue

@ -4,32 +4,20 @@
<view class="content-scroll"> <view class="content-scroll">
<!-- 图片区域 --> <!-- 图片区域 -->
<view class="image-section"> <view class="image-section">
<view class="image-grid"> <uni-file-picker
<!-- 已选图片 --> v-model="selectedImages"
<view mode="grid"
class="image-item" file-mediatype="image"
v-for="(image, index) in selectedImages" file-extname="png,jpg,jpeg"
:key="index" :auto-upload="false"
> @select="onImageSelect"
<image class="image-preview" :src="image" mode="aspectFill" /> @delete="onImageDelete"
<view class="image-delete" @click="removeImage(index)"> ></uni-file-picker>
<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>
<!-- 标题区域 --> <!-- 标题区域 -->
<view class="title-section"> <view class="title-section">
<textarea <input
class="title-input" class="title-input"
v-model="noteForm.title" v-model="noteForm.title"
placeholder="请输入标题..." placeholder="请输入标题..."
@ -51,31 +39,44 @@
<!-- 快速标签区域 --> <!-- 快速标签区域 -->
<view class="quick-tags-section"> <view class="quick-tags-section">
<view class="quick-tags-list"> <view class="section-title">快速标签</view>
<view <scroll-view
class="quick-tag-item" class="quick-tags-scroll"
v-for="tag in quickTags" scroll-x="true"
:key="tag" show-scrollbar="false"
@click="insertQuickTag(tag)" >
> <view class="quick-tags-list">
#{{ tag }} <view
class="quick-tag-item"
v-for="tag in quickTags"
:key="tag"
@click="insertQuickTag(tag)"
>
#{{ tag.name }}
</view>
</view> </view>
</view> </scroll-view>
</view> </view>
<!-- 已添加标签 --> <!-- 已添加标签 -->
<view class="selected-tags-section" v-if="noteForm.tags.length"> <view class="selected-tags-section" v-if="noteForm.tags.length">
<view class="selected-tags-list"> <scroll-view
<view class="selected-tags-scroll"
class="selected-tag-item" scroll-x
v-for="(tag, index) in noteForm.tags" :show-scrollbar="false"
:key="index" >
@click="removeTag(index)" <view class="selected-tags-list">
> <view
<text class="tag-text">#{{ tag }}</text> class="selected-tag-item"
<text class="tag-close">×</text> v-for="(tag, index) in noteForm.tags"
:key="index"
@click="removeTag(index)"
>
<view class="tag-text">#{{ tag.name }}</view>
<view class="tag-close">×</view>
</view>
</view> </view>
</view> </scroll-view>
</view> </view>
<!-- 底部占位 --> <!-- 底部占位 -->
@ -84,9 +85,7 @@
<!-- 底部发布按钮 --> <!-- 底部发布按钮 -->
<view class="bottom-publish"> <view class="bottom-publish">
<button class="publish-btn" @click="publishNote" :disabled="!canPublish"> <button class="publish-btn" @click="publishNote">发布笔记</button>
发布笔记
</button>
</view> </view>
</view> </view>
</template> </template>
@ -100,29 +99,48 @@ export default {
noteForm: { noteForm: {
title: "", title: "",
content: "", content: "",
tags: [], tags: [], // {id, name}
images: [], images: [],
}, },
quickTags: [ quickTags: [], //
"阅读体验", imageStyles: {
"时间力", height: "200rpx", //
"读书笔记", width: "200rpx", //
"生活感悟", },
"学习心得",
"思考",
],
}; };
}, },
computed: { computed: {
canPublish() { canPublish() {
return ( return (
this.noteForm.title.trim() || (this.noteForm.title.trim() || this.noteForm.content.trim()) &&
this.noteForm.content.trim() || this.selectedImages &&
this.selectedImages.length > 0 this.selectedImages.length > 0
); );
}, },
}, },
mounted() {
this.getTagList();
},
methods: { methods: {
//
async getTagList() {
try {
const res = await this.Post({}, "/framework/tag/list", "DES");
if (res && res.data) {
this.quickTags = res.data;
}
} catch (error) {
console.error("获取标签列表失败:", error);
//
this.quickTags = [
{ id: "1", name: "DES" },
{ id: "2", name: "AGENT" },
{ id: "3", name: "时间银行" },
{ id: "4", name: "阅读体验" },
{ id: "5", name: "时间力" },
];
}
},
// //
goBack() { goBack() {
if (this.canPublish) { if (this.canPublish) {
@ -140,33 +158,29 @@ export default {
} }
}, },
// //
chooseImage() { onImageSelect(e) {
const remainingCount = 9 - this.selectedImages.length; console.log("选择图片·:", e);
uni.chooseImage({ // selectedImagesv-model
count: remainingCount, this.uploadNewImages(e.tempFiles || []);
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) { onImageDelete(e) {
this.selectedImages.splice(index, 1); let index = e.index;
this.noteForm.images = [...this.selectedImages]; // selectedImagesv-modelnoteForm.images
// selectedImagesnoteForm.images
if (this.noteForm.images && this.noteForm.images.length > index) {
this.noteForm.images.splice(index, 1);
}
}, },
// //
insertQuickTag(tag) { insertQuickTag(tag) {
if (!this.noteForm.tags.includes(tag)) { //
this.noteForm.tags.push(tag); const existingTag = this.noteForm.tags.find((t) => t.id === tag.id);
if (!existingTag) {
this.noteForm.tags.unshift(tag);
} }
}, },
@ -175,11 +189,100 @@ export default {
this.noteForm.tags.splice(index, 1); this.noteForm.tags.splice(index, 1);
}, },
//
async uploadSingleImage(file) {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync("userInfo")
? JSON.parse(uni.getStorageSync("userInfo")).token
: "";
uni.uploadFile({
url: this.NEWAPIURL_DES + "/system/oss/upload", //
filePath: file.url || file.path,
name: "file",
header: {
token: token || "",
// token
},
success: (res) => {
console.log(res);
try {
const data = JSON.parse(res.data);
if (data.code === 200) {
resolve(data.data.url); // URL
} else {
reject(new Error(data.message || "上传失败"));
}
} catch (e) {
reject(new Error("解析响应失败"));
}
},
fail: (err) => {
reject(err);
},
});
});
},
//
async uploadNewImages(newFiles) {
if (!newFiles || newFiles.length === 0) {
return;
}
try {
uni.showLoading({ title: "上传图片中..." });
const uploadPromises = newFiles.map((file) =>
this.uploadSingleImage(file)
);
const uploadedUrls = await Promise.all(uploadPromises);
// URLnoteForm.images
this.noteForm.images = [
...(this.noteForm.images || []),
...uploadedUrls,
];
uni.hideLoading();
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error.message || "图片上传失败",
icon: "none",
});
}
},
//
async uploadImages() {
if (!this.selectedImages || this.selectedImages.length === 0) {
return [];
}
const uploadPromises = this.selectedImages.map((file) =>
this.uploadSingleImage(file)
);
try {
const uploadedUrls = await Promise.all(uploadPromises);
return uploadedUrls;
} catch (error) {
throw new Error("图片上传失败: " + error.message);
}
},
// //
async publishNote() { async publishNote() {
if (!this.canPublish) { console.log(this.noteForm, "0000");
if (!this.noteForm.images || this.noteForm.images.length === 0) {
uni.showToast({ uni.showToast({
title: "请添加内容", title: "请至少选择一张图片",
icon: "none",
});
return;
}
if (!this.noteForm.title.trim() && !this.noteForm.content.trim()) {
uni.showToast({
title: "请添加标题或内容",
icon: "none", icon: "none",
}); });
return; return;
@ -187,45 +290,41 @@ export default {
try { try {
uni.showLoading({ title: "发布中..." }); uni.showLoading({ title: "发布中..." });
//
// API
await this.submitNote(this.noteForm); await this.submitNote(this.noteForm);
uni.hideLoading(); uni.hideLoading();
uni.showToast({ uni.showToast({
title: "发布成功", title: "发布成功",
icon: "success", icon: "none",
duration: 2000, duration: 2000,
}); });
// //
setTimeout(() => { setTimeout(() => {
uni.navigateBack(); uni.navigateBack();
}, 1500); }, 800);
} catch (error) { } catch (error) {
uni.hideLoading(); uni.hideLoading();
uni.showToast({ uni.showToast({
title: "发布失败,请重试", title: error.message || "发布失败,请重试",
icon: "none", icon: "none",
}); });
} }
}, },
// API //
async submitNote(noteData) { async submitNote(noteData) {
return new Promise((resolve, reject) => { // API
setTimeout(() => { const formData = {
console.log("发布笔记数据:", noteData); title: noteData.title,
resolve({ content: noteData.content,
code: 200, tags: noteData.tags.map((tag) => tag.id).join(","), // ID
message: "发布成功", coverImage: noteData.images.join(","), // URL
data: { method: "POST",
id: "note_" + Date.now(), };
...noteData,
}, return this.Post(formData, "/framework/note/addNote", "DES");
});
}, 1500);
});
}, },
}, },
}; };
@ -243,7 +342,6 @@ export default {
.content-scroll { .content-scroll {
flex: 1; flex: 1;
padding: 0 30rpx; padding: 0 30rpx;
width: 690rpx;
} }
// //
@ -251,59 +349,6 @@ export default {
margin: 32rpx 0; margin: 32rpx 0;
padding-bottom: 32rpx; padding-bottom: 32rpx;
border-bottom: 1rpx solid #f0f0f0; 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;
}
}
} }
// //
@ -334,7 +379,7 @@ export default {
.content-input { .content-input {
width: 100%; width: 100%;
min-height: 300rpx; min-height: 300rpx;
font-size: 32rpx; font-size: 28rpx;
line-height: 1.6; line-height: 1.6;
color: #333; color: #333;
border: none; border: none;
@ -347,20 +392,33 @@ export default {
.quick-tags-section { .quick-tags-section {
margin: 24rpx 0; margin: 24rpx 0;
.section-title {
font-size: 28rpx;
color: #666;
margin-bottom: 25rpx;
}
.quick-tags-scroll {
width: 100%;
white-space: nowrap;
}
.quick-tags-list { .quick-tags-list {
display: flex; display: inline-flex;
flex-wrap: wrap;
gap: 16rpx; gap: 16rpx;
padding-right: 32rpx;
width: max-content;
.quick-tag-item { .quick-tag-item {
flex-shrink: 0;
padding: 16rpx 24rpx; padding: 16rpx 24rpx;
background: #f8f9fa; background: #f8f9fa;
border: 1rpx solid #e0e0e0;
border-radius: 32rpx; border-radius: 32rpx;
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
white-space: nowrap;
&:active { &:active {
background: #e9ecef; background: #e9ecef;
@ -376,28 +434,36 @@ export default {
padding-top: 24rpx; padding-top: 24rpx;
border-top: 1rpx solid #f0f0f0; border-top: 1rpx solid #f0f0f0;
.selected-tags-scroll {
width: 100%;
white-space: nowrap;
}
.selected-tags-list { .selected-tags-list {
display: flex; display: inline-flex;
flex-wrap: wrap;
gap: 16rpx; gap: 16rpx;
padding-right: 32rpx;
width: max-content;
.selected-tag-item { .selected-tag-item {
flex-shrink: 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8rpx; gap: 8rpx;
padding: 12rpx 20rpx; padding: 12rpx 20rpx;
background: #ff4757; background: linear-gradient(135deg, #fffdb7e6 0%, #97fffab5 100%);
border-radius: 32rpx; border-radius: 32rpx;
cursor: pointer; cursor: pointer;
white-space: nowrap;
.tag-text { .tag-text {
font-size: 26rpx; font-size: 26rpx;
color: #fff; color: #333;
} }
.tag-close { .tag-close {
font-size: 24rpx; font-size: 24rpx;
color: #fff; color: #333;
opacity: 0.8; opacity: 0.8;
margin-left: 8rpx; margin-left: 8rpx;
} }
@ -410,7 +476,7 @@ export default {
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
background: #fff; background: #fff;
border-top: 1rpx solid #f0f0f0; border-top: 1rpx solid #f0f0f0;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); padding-bottom: max(24rpx, env(safe-area-inset-bottom));
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -419,16 +485,15 @@ export default {
.publish-btn { .publish-btn {
width: 100%; width: 100%;
height: 88rpx; height: 88rpx;
background: #ff4757; color: #333333;
color: #fff;
border-radius: 44rpx; border-radius: 44rpx;
font-size: 32rpx; font-size: 32rpx;
font-weight: 600; font-weight: 600;
border: none; border: none;
transition: all 0.3s ease; transition: all 0.3s ease;
background: linear-gradient(135deg, #fffdb7e6 0%, #97fffab5 100%);
&:disabled { &:disabled {
background: #ccc; background: linear-gradient(135deg, #ccc 0%, #ccc 100%);
} }
&:not(:disabled):active { &:not(:disabled):active {
@ -438,7 +503,7 @@ export default {
} }
.bottom-placeholder { .bottom-placeholder {
height: 140rpx; height: 180rpx;
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom)); padding-bottom: calc(24rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(24rpx + env(safe-area-inset-bottom)); padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
} }

2
static/js/CommonFunction.js

@ -356,7 +356,7 @@ Vue.prototype.getSubscribeMessage = () => {
tmplIds: templateIds, tmplIds: templateIds,
complete(res) { complete(res) {
uni.navigateTo({ uni.navigateTo({
url: '/subPackages/order/trades' url: '/subPackages/haveFeeling/list'
}) })
} }
}) })

4
static/js/request.js

@ -8,9 +8,9 @@ const DEV_API_URL = 'http://1.13.193.49';
// const PROD_API_URL = 'https://epic.js-dyyj.com'; // const PROD_API_URL = 'https://epic.js-dyyj.com';
const PROD_API_URL = 'http://1.13.193.49'; const PROD_API_URL = 'http://1.13.193.49';
const NEWAPIURL = process.env.NODE_ENV === 'development' ? DEV_API_URL : PROD_API_URL; const NEWAPIURL = process.env.NODE_ENV === 'development' ? DEV_API_URL : PROD_API_URL;
const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
// const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; // const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
// const DEV_API_URL_DES = 'http://1.13.193.49:8083/xcx'; // const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const DEV_API_URL_DES = 'http://192.168.124.8:8083/xcx';
// const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; // const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const NEWAPIURL_DES = process.env.NODE_ENV === 'development' ? DEV_API_URL_DES : PROD_API_URL_DES; const NEWAPIURL_DES = process.env.NODE_ENV === 'development' ? DEV_API_URL_DES : PROD_API_URL_DES;

72
subPackages/haveFeeling/detail.vue

@ -67,7 +67,7 @@
> >
</view> </view>
<view class="summary-row"> <view class="summary-row">
<text class="summary-label">应付金额</text> <text class="summary-label">金额</text>
<text class="summary-value" <text class="summary-value"
>¥{{ orderDetail.totalAmount || "0.00" }}</text >¥{{ orderDetail.totalAmount || "0.00" }}</text
> >
@ -79,7 +79,7 @@
> >
</view> </view>
<view class="summary-row total-row"> <view class="summary-row total-row">
<text class="summary-label">付金额</text> <text class="summary-label">付金额</text>
<text class="summary-value total-amount" <text class="summary-value total-amount"
>¥{{ orderDetail.payAmount || "0.00" }}</text >¥{{ orderDetail.payAmount || "0.00" }}</text
> >
@ -159,6 +159,13 @@
> >
去支付 去支付
</button> </button>
<button
class="action-btn-bottom cancel-btn"
@click="handleOrderAction('cancel')"
v-if="orderDetail.status === 0"
>
取消订单
</button>
<!-- <button <!-- <button
class="action-btn-bottom" class="action-btn-bottom"
@click="handleOrderAction('logistics')" @click="handleOrderAction('logistics')"
@ -370,9 +377,54 @@ export default {
case "aftersale": case "aftersale":
this.applyAfterSale(); this.applyAfterSale();
break; break;
case "cancel":
this.cancelOrder();
break;
} }
}, },
//
cancelOrder() {
uni.showModal({
title: "取消订单",
content: "确定要取消该订单吗?",
success: (res) => {
if (res.confirm) {
this.cancelOrderApi();
}
},
});
},
// API
cancelOrderApi() {
uni.showLoading({
title: "取消中...",
});
this.Post(
{ parentOrderNo: this.orderDetail.orderNo },
`/framework/ygOrder/cancel`,
"DES"
).then((res) => {
uni.hideLoading();
if (res.code == 200) {
uni.showToast({
title: "订单已取消",
icon: "success",
});
setTimeout(() => {
this.loadOrderDetail();
}, 800);
} else {
uni.showToast({
title: res.msg || "取消订单失败",
icon: "none",
});
}
});
},
// //
goToPay() { goToPay() {
let order = this.orderDetail; let order = this.orderDetail;
@ -393,7 +445,16 @@ export default {
signType: res.data.wxInfo.signType, signType: res.data.wxInfo.signType,
timeStamp: res.data.wxInfo.timeStamp, timeStamp: res.data.wxInfo.timeStamp,
success: () => { success: () => {
this.loadOrderDetail(); // this.loadOrderDetail();
uni.showToast({
title: "支付成功",
icon: "success",
});
setTimeout(() => {
uni.navigateBack({
delta: 1,
});
}, 800);
}, },
fail() { fail() {
// uni.navigateTo({ // uni.navigateTo({
@ -876,6 +937,11 @@ export default {
color: #ffffff; color: #ffffff;
} }
&.cancel-btn {
background-color: #ff3b30;
color: #ffffff;
}
&.contact-btn { &.contact-btn {
background-color: #007aff; background-color: #007aff;
color: #ffffff; color: #ffffff;

1113
subPackages/haveFeeling/detailAll.vue

File diff suppressed because it is too large

67
subPackages/haveFeeling/list.vue

@ -25,16 +25,16 @@
<view <view
class="order-item" class="order-item"
v-for="order in orderList" v-for="order in orderList"
:key="order.id"
@click="goToOrderDetail(order)" @click="goToOrderDetail(order)"
> >
<!-- 订单头部 - 供应商信息 --> <!-- 订单头部 - 供应商信息 -->
<view class="order-header"> <view class="order-header">
<view class="supplier-info"> <view class="supplier-info">
<view class="supplier-name">{{ <view class="supplier-name" v-if="order.status==0||order.status==-1">有感商品订单</view>
order.supplierName || "默认供应商" <view class="supplier-name" v-else>{{
}}</view> order.supplierName || "默认供应商"
<view class="order-number">订单号{{ order.orderNo }}</view> }}</view>
<view class="order-number">订单号{{ ( order.status==0||order.status==-1)?order.parentOrderNo:order.orderNo }}</view>
</view> </view>
<view class="order-status-wrapper"> <view class="order-status-wrapper">
<text class="status-name" :class="[getStatusClass(order.status)]">{{ <text class="status-name" :class="[getStatusClass(order.status)]">{{
@ -42,7 +42,6 @@
}}</text> }}</text>
</view> </view>
</view> </view>
<!-- 商品列表 --> <!-- 商品列表 -->
<view class="goods-section"> <view class="goods-section">
<view class="goods-list"> <view class="goods-list">
@ -78,9 +77,9 @@
<!-- 订单底部 --> <!-- 订单底部 -->
<view class="order-footer"> <view class="order-footer">
<view class="order-info"> <view class="order-info" >
<view class="order-total-section"> <view class="order-total-section">
<text class="total-label">实付</text> <!-- <text class="total-label">{{(order.status==0)?'':'实付'}}</text> -->
<text class="order-total">¥{{ order.payAmount || 0 }}</text> <text class="order-total">¥{{ order.payAmount || 0 }}</text>
</view> </view>
<view class="order-time">{{ order.createTime }}</view> <view class="order-time">{{ order.createTime }}</view>
@ -222,15 +221,29 @@ export default {
pageSize: this.pageSize, pageSize: this.pageSize,
status: this.tabs[this.currentTab].status, status: this.tabs[this.currentTab].status,
}; };
let url = ''
if(this.currentTab==0||this.currentTab==1){
url = "/framework/ygOrder/parent/pageList"
}else{
url = "/framework/ygOrder/pageList"
}
this.Post( this.Post(
{ {
...params, ...params,
}, },
"/framework/ygOrder/pageList", url,
"DES" "DES"
).then((res) => { ).then((res) => {
if (res.code == 200) { if (res.code == 200) {
if(this.currentTab==0||this.currentTab==1){
let orderItems = []
res.rows.forEach(item =>{
item.orderItems = []
item.orders.forEach(_item =>{
item.orderItems.push(..._item.orderItems)
})
})
}
this.orderList.push(...res.rows); this.orderList.push(...res.rows);
console.log(this.orderList); console.log(this.orderList);
this.hasMore = res.rows.length === this.pageSize; this.hasMore = res.rows.length === this.pageSize;
@ -426,9 +439,17 @@ export default {
// //
goToOrderDetail(order) { goToOrderDetail(order) {
uni.navigateTo({ console.log(order)
url: `/subPackages/haveFeeling/detail?id=${order.id}`, if(order.status==-1||order.status==0){
}); uni.navigateTo({
url: `/subPackages/haveFeeling/detailAll?id=${order.orderNo}`,
});
}else{
uni.navigateTo({
url: `/subPackages/haveFeeling/detail?id=${order.orderNo}`,
});
}
}, },
}, },
}; };
@ -568,28 +589,28 @@ $bg-light: #f7fafc;
letter-spacing: 0.5rpx; letter-spacing: 0.5rpx;
&.status-pending { &.status-pending {
background: #fff3cd; background: #ff9500;
color: #856404; color: #ffffff;
} }
&.status-paid { &.status-paid {
background: #e6f3ff; background: #007aff;
color: #0c5460; color: #ffffff;
} }
&.status-cancelled { &.status-cancelled {
background: #f8d7da; background: #ff3b30;
color: #721c24; color: #ffffff;
} }
&.status-shipping { &.status-shipping {
background: #d4edda; background: #34c759;
color: #155724; color: #ffffff;
} }
&.status-completed { &.status-completed {
background: #d1ecf1; background: #48bb78;
color: #0c5460; color: #ffffff;
} }
} }

1295
uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue

File diff suppressed because it is too large
Loading…
Cancel
Save