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. 211
      components/WaterfallLayout.vue
  2. 6
      pages.json
  3. 18
      pages/index/iSoul.vue
  4. 204
      pages/index/timeShopBank.vue
  5. 272
      pages/notes/detail.vue
  6. 365
      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. 59
      subPackages/haveFeeling/list.vue
  12. 541
      uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue

211
components/WaterfallLayout.vue

@ -1,24 +1,50 @@
<template> <template>
<view class="waterfall-layout"> <view class="waterfall-layout">
<view class="waterfall-container"> <!-- 空状态 -->
<view v-if="!leftItems.length && !rightItems.length" class="empty-state">
<text class="empty-title">暂无内容</text>
<text class="empty-desc">快来发布第一篇笔记吧</text>
</view>
<!-- 瀑布流内容 -->
<view v-else class="waterfall-container">
<!-- 左列 --> <!-- 左列 -->
<view class="column"> <view class="column">
<view v-for="(item, index) in leftItems" :key="item.id || index" class="waterfall-item" <view
@click="handleItemClick(item)"> v-for="(item, index) in leftItems"
<image v-if="item.image" :src="showImg(item.image)" class="item-image" mode="aspectFill" /> :key="item.id || index"
class="waterfall-item"
@click="handleItemClick(index, leftItems)"
>
<image
v-if="item.coverImage"
:src="item.coverImage && item.coverImage.split(',')[0]"
class="item-image"
mode="aspectFill"
/>
<view class="item-content"> <view class="item-content">
<text v-if="item.title" class="item-title">{{ item.title }}</text> <text v-if="item.title" class="item-title">{{ item.title }}</text>
<view class="item-footer"> <view class="item-footer">
<view class="user-info"> <view class="user-info">
<image <image
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100" :src="item.headImg"
class="user-avatar" mode="aspectFill" /> class="user-avatar"
<text class="username">风景之旅</text> mode="aspectFill"
/>
<text class="username">{{ item.nickname }}</text>
</view> </view>
<view class="like-info"> <view class="like-info">
<image :src="showImg('/uploads/20250731/0260884d7a44a483885a026da524e0b8.png')" <image
style="height: 22rpx;width: 25rpx;"></image> v-if="!item.userLiked"
<text class="like-count">100</text> 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>
@ -27,22 +53,44 @@
<!-- 右列 --> <!-- 右列 -->
<view class="column"> <view class="column">
<view v-for="(item, index) in rightItems" :key="item.id || index" class="waterfall-item" <view
@click="handleItemClick(item)"> v-for="(item, index) in rightItems"
<image v-if="item.image" :src="showImg(item.image)" class="item-image" mode="aspectFill" /> :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"> <view class="item-content">
<text v-if="item.title" class="item-title">{{ item.title }}</text> <text v-if="item.title" class="item-title">{{ item.title }}</text>
<view class="item-footer"> <view class="item-footer">
<view class="user-info"> <view class="user-info">
<image <image
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=100" :src="item.headImg"
class="user-avatar" mode="aspectFill" /> class="user-avatar"
<text class="username">风景之旅</text> mode="aspectFill"
/>
<text class="username"
>{{ item.nickname }}{{ item.nickname
}}{{ item.nickname }}</text
>
</view> </view>
<view class="like-info"> <view class="like-info">
<image :src="showImg('/uploads/20250731/0260884d7a44a483885a026da524e0b8.png')" <image
style="height: 22rpx;width: 25rpx;"></image> v-if="!item.userLiked"
<text class="like-count">120</text> 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>
@ -53,7 +101,7 @@
</template> </template>
<script> <script>
export default { export default {
name: "WaterfallLayout", name: "WaterfallLayout",
props: { props: {
// //
@ -101,9 +149,12 @@
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
.select(columnRef)
.boundingClientRect((data) => {
resolve(data ? data.height : 0); resolve(data ? data.height : 0);
}).exec(); })
.exec();
}); });
}, },
@ -143,8 +194,8 @@
}, },
// //
handleItemClick(item) { handleItemClick(index, list) {
this.$emit("item-click", item); this.$emit("item-click", list[index]);
}, },
// //
@ -155,7 +206,7 @@
// //
removeItem(itemId) { removeItem(itemId) {
// //
let index = this.leftItems.findIndex(item => item.id === itemId); let index = this.leftItems.findIndex((item) => item.id === itemId);
if (index !== -1) { if (index !== -1) {
this.leftItems.splice(index, 1); this.leftItems.splice(index, 1);
this.$emit("item-removed", itemId); this.$emit("item-removed", itemId);
@ -163,60 +214,90 @@
} }
// //
index = this.rightItems.findIndex(item => item.id === itemId); index = this.rightItems.findIndex((item) => item.id === itemId);
if (index !== -1) { if (index !== -1) {
this.rightItems.splice(index, 1); this.rightItems.splice(index, 1);
this.$emit("item-removed", itemId); 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;
} }
/* 空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 160rpx 40rpx;
text-align: center;
}
.empty-icon {
width: 240rpx;
height: 240rpx;
margin-bottom: 40rpx;
opacity: 0.6;
}
.empty-title {
font-size: 32rpx;
color: #666;
margin-bottom: 16rpx;
font-weight: 500;
}
.empty-desc {
font-size: 28rpx;
color: #999;
line-height: 1.4;
}
.waterfall-container { .waterfall-container {
display: flex; display: flex;
gap: 16rpx; gap: 16rpx;
padding: 0 20rpx; padding: 0 20rpx;
box-sizing: border-box; box-sizing: border-box;
} }
.column { .column {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16rpx; gap: 16rpx;
} }
.waterfall-item { .waterfall-item {
box-sizing: border-box; box-sizing: border-box;
border-radius: 12rpx; border-radius: 12rpx;
background: #fff; background: #fff;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
overflow: hidden; overflow: hidden;
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
.waterfall-item:active { .waterfall-item:active {
transform: scale(0.98); transform: scale(0.98);
} }
.item-image { .item-image {
width: 100%; width: 100%;
height: 476rpx; height: 476rpx;
object-fit: cover; object-fit: cover;
} }
.item-content { .item-content {
padding: 16rpx; padding: 16rpx;
} }
.item-title { .item-title {
font-size: 28rpx; font-size: 28rpx;
font-weight: 600; font-weight: 600;
color: #333; color: #333;
@ -227,9 +308,9 @@
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.item-desc { .item-desc {
font-size: 24rpx; font-size: 24rpx;
color: #666; color: #666;
line-height: 1.4; line-height: 1.4;
@ -239,61 +320,65 @@
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.item-tags { .item-tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8rpx; gap: 8rpx;
margin-bottom: 16rpx; margin-bottom: 16rpx;
} }
.tag { .tag {
padding: 4rpx 12rpx; padding: 4rpx 12rpx;
background: #f5f5f5; background: #f5f5f5;
color: #666; color: #666;
font-size: 20rpx; font-size: 20rpx;
border-radius: 12rpx; border-radius: 12rpx;
white-space: nowrap; white-space: nowrap;
} }
.item-footer { .item-footer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-top: 16rpx; margin-top: 16rpx;
} }
.user-info { .user-info {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12rpx; gap: 12rpx;
} }
.user-avatar { .user-avatar {
width: 32rpx; width: 32rpx;
height: 32rpx; height: 32rpx;
border-radius: 50%; border-radius: 50%;
} }
.username { .username {
font-size: 22rpx; font-size: 22rpx;
color: #666; color: #666;
} width: 160rpx;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.like-info { .like-info {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6rpx; gap: 6rpx;
} }
.like-icon { .like-icon {
font-size: 24rpx; font-size: 24rpx;
color: #ff6b6b; color: #ff6b6b;
} }
.like-count { .like-count {
font-size: 22rpx; font-size: 22rpx;
color: #666; color: #666;
} }
</style> </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'
})
} }
}, },
// //

204
pages/index/timeShopBank.vue

@ -10,21 +10,20 @@
:style-type="'timeShop'" :style-type="'timeShop'"
/> />
<view class="desc-box"> <view class="desc-box">
<view class=""> <view class=""> 欢迎来到旅行时间行你的精神财富储蓄所 </view>
欢迎来到旅行时间行你的精神财富储蓄所
</view>
<view class=""> <view class="">
在这里你的每一次人文漫游每一次灵感闪现都值得被郑重记录我们鼓励你分享高质量的图文笔记将旅途中的美与感动化为这座精神星球上的璀璨星辰 在这里你的每一次人文漫游每一次灵感闪现都值得被郑重记录我们鼓励你分享高质量的图文笔记将旅途中的美与感动化为这座精神星球上的璀璨星辰
</view> </view>
<view class=""> <view class="">
为他人的美好驻足点赞留言每一次真诚的互动都是在为你的时间银行存入一笔宝贵的精神货币这些资产不仅可以兑换独家福利与实体好物更能为你解锁专属的荣誉身份让你成为这座星球上最闪耀的共创者 为他人的美好驻足点赞留言每一次真诚的互动都是在为你的时间银行存入一笔宝贵的精神货币这些资产不仅可以兑换独家福利与实体好物更能为你解锁专属的荣誉身份让你成为这座星球上最闪耀的共创者
</view> </view>
<view class=""> <view class=""> 即刻发布你的第一篇笔记开启你的财富积累之旅吧 </view>
即刻发布你的第一篇笔记开启你的财富积累之旅吧
</view>
</view> </view>
<image style="width: 700rpx;height: 14rpx;margin: 20rpx auto;display: block;" :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">
@ -62,11 +61,11 @@
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>
@ -75,6 +74,7 @@
<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
@click="goToPublish"
:src=" :src="
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png') showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
" "
@ -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), getRecommendList(type = 1) {
title: titleType[Math.floor(Math.random() * titleType.length)], if (this.loading) return;
image: this.images[Math.floor(Math.random() * this.images.length)],
// description: this.loading = true;
// this.descriptions[ const params = {
// Math.floor(Math.random() * this.descriptions.length) pageNum: this.pageNum,
// ], pageSize: this.pageSize,
// tags: this.tagsList[Math.floor(Math.random() * this.tagsList.length)], type: type, // 0: tab, 1: tab
//
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
}; };
},
// this.Post(params, "/framework/note/list", "DES")
initializeData() { .then((res) => {
const initialItems = []; if (res.code === 200 && res.rows) {
for (let i = 0; i < 20; i++) { const newItems = res.rows || [];
initialItems.push(this.getRandomItem());
if (this.pageNum === 1) {
//
this.waterfallItems = newItems;
} else {
//
this.waterfallItems.push(...newItems);
} }
// this.waterfallItems = initialItems;
},
// //
addRandomItem() { this.hasMore = newItems.length === this.pageSize;
const newItem = this.getRandomItem(); }
// this.waterfallItems.push(newItem); })
.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,15 +461,15 @@ 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;

272
pages/notes/detail.vue

@ -14,11 +14,7 @@
@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>
@ -31,27 +27,25 @@
</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">
@ -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 class="" style="width: auto;height: 1rpx;background-color: #999999;margin: 60rpx 32rpx;">
</view> </view>
<view
class=""
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">
@ -127,15 +137,25 @@
> >
发送 发送
</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"
:class="{ liked: noteDetail.isLiked }" mode="widthFix"
@click="toggleLike" :src="
></text !noteDetail.userLiked
> --> ? showImg(
<text class="like-count">{{ noteDetail.likes }}</text> 'https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png'
)
: showImg(
'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>
@ -154,7 +174,7 @@ export default {
return { return {
noteId: "", noteId: "",
commentText: "", commentText: "",
topBanner: ["/uploads/20250826/17356ed4dcdeedcd13de60ca28909d22.png"], topBanner: [],
swiperIndex: 0, swiperIndex: 0,
noteDetail: { noteDetail: {
id: "", id: "",
@ -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,7 +196,13 @@ 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: {
@ -191,9 +213,24 @@ export default {
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(
{ noteId: this.noteId },
"/framework/note/getInfo/" + this.noteId,
"DES"
);
if (res.code === 200) {
this.noteDetail = res.data; 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() {
try {
const action = this.noteDetail.user.isFollowed ? "cancel" : "follow";
const res = await this.Post(
{
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; this.noteDetail.user.isFollowed = !this.noteDetail.user.isFollowed;
uni.showToast({ uni.showToast({
title: this.noteDetail.user.isFollowed ? "已关注" : "取消关注", 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", icon: "none",
}); });
}
}, },
// //
toggleLike() { async toggleLike() {
try {
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.isLiked = !this.noteDetail.isLiked;
this.noteDetail.likes += this.noteDetail.isLiked ? 1 : -1; 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: "提交中..." });
const res = await this.Post(
{
method: "POST",
noteId: this.noteId,
content: this.commentText, content: this.commentText,
createTime: new Date().toISOString(),
user: {
id: "current_user",
name: "我",
avatar:
"https://des.dayunyuanjian.cn/epicSoul/avatar-current.png",
}, },
}; "/framework/note/comment/add",
"DES"
);
this.noteDetail.comments.unshift(newComment); if (res.code === 200) {
//
this.loadNoteDetail();
this.commentText = ""; this.commentText = "";
uni.showToast({ uni.showToast({
title: "评论成功", title: "评论成功",
icon: "success", 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)}`
// });
}, },
}, },
}; };
@ -384,8 +506,8 @@ export default {
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;
} }
@ -434,6 +556,20 @@ padding: 12rpx 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,7 +627,7 @@ padding: 12rpx 30rpx;
} }
} }
} }
.comment-input-section-box{ .comment-input-section-box {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -506,7 +642,7 @@ padding: 12rpx 30rpx;
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;
@ -553,6 +689,10 @@ padding: 12rpx 30rpx;
font-size: 30rpx; font-size: 30rpx;
color: #666; color: #666;
font-weight: bold; font-weight: bold;
&.liked-text {
color: #ff4757;
}
} }
} }
} }

365
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,6 +39,12 @@
<!-- 快速标签区域 --> <!-- 快速标签区域 -->
<view class="quick-tags-section"> <view class="quick-tags-section">
<view class="section-title">快速标签</view>
<scroll-view
class="quick-tags-scroll"
scroll-x="true"
show-scrollbar="false"
>
<view class="quick-tags-list"> <view class="quick-tags-list">
<view <view
class="quick-tag-item" class="quick-tag-item"
@ -58,13 +52,19 @@
:key="tag" :key="tag"
@click="insertQuickTag(tag)" @click="insertQuickTag(tag)"
> >
#{{ 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">
<scroll-view
class="selected-tags-scroll"
scroll-x
:show-scrollbar="false"
>
<view class="selected-tags-list"> <view class="selected-tags-list">
<view <view
class="selected-tag-item" class="selected-tag-item"
@ -72,10 +72,11 @@
:key="index" :key="index"
@click="removeTag(index)" @click="removeTag(index)"
> >
<text class="tag-text">#{{ tag }}</text> <view class="tag-text">#{{ tag.name }}</view>
<text class="tag-close">×</text> <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,7 +377,52 @@ 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",
});
} }
});
}, },
// //
@ -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

59
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>
<view class="supplier-name" v-else>{{
order.supplierName || "默认供应商" order.supplierName || "默认供应商"
}}</view> }}</view>
<view class="order-number">订单号{{ order.orderNo }}</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) {
console.log(order)
if(order.status==-1||order.status==0){
uni.navigateTo({ uni.navigateTo({
url: `/subPackages/haveFeeling/detail?id=${order.id}`, 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;
} }
} }

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

@ -4,9 +4,18 @@
<text class="file-title">{{ title }}</text> <text class="file-title">{{ title }}</text>
<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text> <text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
</view> </view>
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly" <upload-image
:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview" v-if="fileMediatype === 'image' && showType === 'grid'"
:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile"> :readonly="readonly"
:image-styles="imageStyles"
:files-list="filesList"
:limit="limitLength"
:disablePreview="disablePreview"
:delIcon="delIcon"
@uploadFiles="uploadFiles"
@choose="choose"
@delFile="delFile"
>
<slot> <slot>
<view class="is-add"> <view class="is-add">
<view class="icon-add"></view> <view class="icon-add"></view>
@ -14,30 +23,38 @@
</view> </view>
</slot> </slot>
</upload-image> </upload-image>
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly" <upload-file
:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon" v-if="fileMediatype !== 'image' || showType !== 'grid'"
@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile"> :readonly="readonly"
:list-styles="listStyles"
:files-list="filesList"
:showType="showType"
:delIcon="delIcon"
@uploadFiles="uploadFiles"
@choose="choose"
@delFile="delFile"
>
<slot><button type="primary" size="mini">选择文件</button></slot> <slot><button type="primary" size="mini">选择文件</button></slot>
</upload-file> </upload-file>
</view> </view>
</template> </template>
<script> <script>
import { import {
chooseAndUploadFile, chooseAndUploadFile,
uploadCloudFiles uploadCloudFiles,
} from './choose-and-upload-file.js' } from "./choose-and-upload-file.js";
import { import {
get_file_ext, get_file_ext,
get_extname, get_extname,
get_files_and_is_max, get_files_and_is_max,
get_file_info, get_file_info,
get_file_data get_file_data,
} from './utils.js' } from "./utils.js";
import uploadImage from './upload-image.vue' import uploadImage from "./upload-image.vue";
import uploadFile from './upload-file.vue' import uploadFile from "./upload-file.vue";
let fileInput = null let fileInput = null;
/** /**
* FilePicker 文件选择上传 * FilePicker 文件选择上传
* @description 文件选择上传组件可以选择图片视频等任意文件并上传到当前绑定的服务空间 * @description 文件选择上传组件可以选择图片视频等任意文件并上传到当前绑定的服务空间
* @tutorial https://ext.dcloud.net.cn/plugin?id=4079 * @tutorial https://ext.dcloud.net.cn/plugin?id=4079
@ -78,184 +95,192 @@
* @event {Function} fail 上传失败触发 * @event {Function} fail 上传失败触发
* @event {Function} delete 文件从列表移除时触发 * @event {Function} delete 文件从列表移除时触发
*/ */
export default { export default {
name: 'uniFilePicker', name: "uniFilePicker",
components: { components: {
uploadImage, uploadImage,
uploadFile uploadFile,
}, },
options: { options: {
virtualHost: true virtualHost: true,
}, },
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'], emits: [
"select",
"success",
"fail",
"progress",
"delete",
"update:modelValue",
"input",
],
props: { props: {
// #ifdef VUE3 // #ifdef VUE3
modelValue: { modelValue: {
type: [Array, Object], type: [Array, Object],
default () { default() {
return [] return [];
} },
}, },
// #endif // #endif
// #ifndef VUE3 // #ifndef VUE3
value: { value: {
type: [Array, Object], type: [Array, Object],
default () { default() {
return [] return [];
} },
}, },
// #endif // #endif
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
disablePreview: { disablePreview: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
delIcon: { delIcon: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
// //
autoUpload: { autoUpload: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
// h5 // h5
limit: { limit: {
type: [Number, String], type: [Number, String],
default: 9 default: 9,
}, },
// grid | list | list-card // grid | list | list-card
mode: { mode: {
type: String, type: String,
default: 'grid' default: "grid",
}, },
// image/video/all // image/video/all
fileMediatype: { fileMediatype: {
type: String, type: String,
default: 'image' default: "image",
}, },
// //
fileExtname: { fileExtname: {
type: [Array, String], type: [Array, String],
default () { default() {
return [] return [];
} },
}, },
title: { title: {
type: String, type: String,
default: '' default: "",
}, },
listStyles: { listStyles: {
type: Object, type: Object,
default () { default() {
return { return {
// //
border: true, border: true,
// 线 // 线
dividline: true, dividline: true,
// 线 // 线
borderStyle: {} borderStyle: {},
} };
} },
}, },
imageStyles: { imageStyles: {
type: Object, type: Object,
default () { default() {
return { return {
width: 'auto', width: "auto",
height: 'auto' height: "auto",
} };
} },
}, },
readonly: { readonly: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
returnType: { returnType: {
type: String, type: String,
default: 'array' default: "array",
}, },
sizeType: { sizeType: {
type: Array, type: Array,
default () { default() {
return ['original', 'compressed'] return ["original", "compressed"];
} },
}, },
sourceType: { sourceType: {
type: Array, type: Array,
default () { default() {
return ['album', 'camera'] return ["album", "camera"];
} },
} },
}, },
data() { data() {
return { return {
files: [], files: [],
localValue: [] localValue: [],
} };
}, },
watch: { watch: {
// #ifndef VUE3 // #ifndef VUE3
value: { value: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
this.setValue(newVal, oldVal) this.setValue(newVal, oldVal);
}, },
immediate: true immediate: true,
}, },
// #endif // #endif
// #ifdef VUE3 // #ifdef VUE3
modelValue: { modelValue: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
this.setValue(newVal, oldVal) this.setValue(newVal, oldVal);
}, },
immediate: true immediate: true,
}, },
// #endif // #endif
}, },
computed: { computed: {
filesList() { filesList() {
let files = [] let files = [];
this.files.forEach(v => { this.files.forEach((v) => {
files.push(v) files.push(v);
}) });
return files return files;
}, },
showType() { showType() {
if (this.fileMediatype === 'image') { if (this.fileMediatype === "image") {
return this.mode return this.mode;
} }
return 'list' return "list";
}, },
limitLength() { limitLength() {
if (this.returnType === 'object') { if (this.returnType === "object") {
return 1 return 1;
} }
if (!this.limit) { if (!this.limit) {
return 1 return 1;
} }
if (this.limit >= 9) { if (this.limit >= 9) {
return 9 return 9;
}
return this.limit
} }
return this.limit;
},
}, },
created() { created() {
// TODO // TODO
if (!(uniCloud.config && uniCloud.config.provider)) { if (!(uniCloud.config && uniCloud.config.provider)) {
this.noSpace = true this.noSpace = true;
uniCloud.chooseAndUploadFile = chooseAndUploadFile uniCloud.chooseAndUploadFile = chooseAndUploadFile;
} }
this.form = this.getForm('uniForms') this.form = this.getForm("uniForms");
this.formItem = this.getForm('uniFormsItem') this.formItem = this.getForm("uniFormsItem");
if (this.form && this.formItem) { if (this.form && this.formItem) {
if (this.formItem.name) { if (this.formItem.name) {
this.rename = this.formItem.name this.rename = this.formItem.name;
this.form.inputChildrens.push(this) this.form.inputChildrens.push(this);
} }
} }
}, },
@ -266,89 +291,91 @@
*/ */
clearFiles(index) { clearFiles(index) {
if (index !== 0 && !index) { if (index !== 0 && !index) {
this.files = [] this.files = [];
this.$nextTick(() => { this.$nextTick(() => {
this.setEmit() this.setEmit();
}) });
} else { } else {
this.files.splice(index, 1) this.files.splice(index, 1);
} }
this.$nextTick(() => { this.$nextTick(() => {
this.setEmit() this.setEmit();
}) });
}, },
/** /**
* 公开用户使用继续上传 * 公开用户使用继续上传
*/ */
upload() { upload() {
let files = [] let files = [];
this.files.forEach((v, index) => { this.files.forEach((v, index) => {
if (v.status === 'ready' || v.status === 'error') { if (v.status === "ready" || v.status === "error") {
files.push(Object.assign({}, v)) files.push(Object.assign({}, v));
} }
}) });
return this.uploadFiles(files) return this.uploadFiles(files);
}, },
async setValue(newVal, oldVal) { async setValue(newVal, oldVal) {
const newData = async (v) => { const newData = async (v) => {
const reg = /cloud:\/\/([\w.]+\/?)\S*/ const reg = /cloud:\/\/([\w.]+\/?)\S*/;
let url = '' let url = "";
if(v.fileID){ if (v.fileID) {
url = v.fileID url = v.fileID;
}else{ } else {
url = v.url url = v.url;
} }
if (reg.test(url)) { if (reg.test(url)) {
v.fileID = url v.fileID = url;
v.url = await this.getTempFileURL(url) v.url = await this.getTempFileURL(url);
}
if(v.url) v.path = v.url
return v
} }
if (this.returnType === 'object') { if (v.url) v.path = v.url;
return v;
};
if (this.returnType === "object") {
if (newVal) { if (newVal) {
await newData(newVal) await newData(newVal);
} else { } else {
newVal = {} newVal = {};
} }
} else { } else {
if (!newVal) newVal = [] if (!newVal) newVal = [];
for(let i =0 ;i < newVal.length ;i++){ for (let i = 0; i < newVal.length; i++) {
let v = newVal[i] let v = newVal[i];
await newData(v) await newData(v);
} }
} }
this.localValue = newVal this.localValue = newVal;
if (this.form && this.formItem &&!this.is_reset) { if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false this.is_reset = false;
this.formItem.setValue(this.localValue) this.formItem.setValue(this.localValue);
} }
let filesData = Object.keys(newVal).length > 0 ? newVal : []; let filesData = Object.keys(newVal).length > 0 ? newVal : [];
this.files = [].concat(filesData) this.files = [].concat(filesData);
}, },
/** /**
* 选择文件 * 选择文件
*/ */
choose() { choose() {
if (this.disabled) return;
if (this.disabled) return if (
if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType === this.files.length >= Number(this.limitLength) &&
'array') { this.showType !== "grid" &&
this.returnType === "array"
) {
uni.showToast({ uni.showToast({
title: `您最多选择 ${this.limitLength} 个文件`, title: `您最多选择 ${this.limitLength} 个文件`,
icon: 'none' icon: "none",
}) });
return return;
} }
this.chooseFiles() this.chooseFiles();
}, },
/** /**
* 选择文件并上传 * 选择文件并上传
*/ */
chooseFiles() { chooseFiles() {
const _extname = get_extname(this.fileExtname) const _extname = get_extname(this.fileExtname);
// //
uniCloud uniCloud
.chooseAndUploadFile({ .chooseAndUploadFile({
@ -360,16 +387,16 @@
extension: _extname.length > 0 ? _extname : undefined, extension: _extname.length > 0 ? _extname : undefined,
count: this.limitLength - this.files.length, //9 count: this.limitLength - this.files.length, //9
onChooseFile: this.chooseFileCallback, onChooseFile: this.chooseFileCallback,
onUploadProgress: progressEvent => { onUploadProgress: (progressEvent) => {
this.setProgress(progressEvent, progressEvent.index) this.setProgress(progressEvent, progressEvent.index);
} },
})
.then(result => {
this.setSuccessAndError(result.tempFiles)
}) })
.catch(err => { .then((result) => {
console.log('选择失败', err) this.setSuccessAndError(result.tempFiles);
}) })
.catch((err) => {
console.log("选择失败", err);
});
}, },
/** /**
@ -377,46 +404,44 @@
* @param {Object} res * @param {Object} res
*/ */
async chooseFileCallback(res) { async chooseFileCallback(res) {
const _extname = get_extname(this.fileExtname) const _extname = get_extname(this.fileExtname);
const is_one = (Number(this.limitLength) === 1 && const is_one =
(Number(this.limitLength) === 1 &&
this.disablePreview && this.disablePreview &&
!this.disabled) || !this.disabled) ||
this.returnType === 'object' this.returnType === "object";
// //
if (is_one) { if (is_one) {
this.files = [] this.files = [];
} }
let { let { filePaths, files } = get_files_and_is_max(res, _extname);
filePaths,
files
} = get_files_and_is_max(res, _extname)
if (!(_extname && _extname.length > 0)) { if (!(_extname && _extname.length > 0)) {
filePaths = res.tempFilePaths filePaths = res.tempFilePaths;
files = res.tempFiles files = res.tempFiles;
} }
let currentData = [] let currentData = [];
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
if (this.limitLength - this.files.length <= 0) break if (this.limitLength - this.files.length <= 0) break;
files[i].uuid = Date.now() files[i].uuid = Date.now();
let filedata = await get_file_data(files[i], this.fileMediatype) let filedata = await get_file_data(files[i], this.fileMediatype);
filedata.progress = 0 filedata.progress = 0;
filedata.status = 'ready' filedata.status = "ready";
this.files.push(filedata) this.files.push(filedata);
currentData.push({ currentData.push({
...filedata, ...filedata,
file: files[i] file: files[i],
}) });
} }
this.$emit('select', { this.$emit("select", {
tempFiles: currentData, tempFiles: currentData,
tempFilePaths: filePaths tempFilePaths: filePaths,
}) });
res.tempFiles = files res.tempFiles = files;
// //
if (!this.autoUpload || this.noSpace) { if (!this.autoUpload || this.noSpace) {
res.tempFiles = [] res.tempFiles = [];
} }
}, },
@ -425,70 +450,73 @@
* @param {Object} e * @param {Object} e
*/ */
uploadFiles(files) { uploadFiles(files) {
files = [].concat(files) files = [].concat(files);
return uploadCloudFiles.call(this, files, 5, res => { return uploadCloudFiles
this.setProgress(res, res.index, true) .call(this, files, 5, (res) => {
this.setProgress(res, res.index, true);
}) })
.then(result => { .then((result) => {
this.setSuccessAndError(result) this.setSuccessAndError(result);
return result; return result;
}) })
.catch(err => { .catch((err) => {
console.log(err) console.log(err);
}) });
}, },
/** /**
* 成功或失败 * 成功或失败
*/ */
async setSuccessAndError(res, fn) { async setSuccessAndError(res, fn) {
let successData = [] let successData = [];
let errorData = [] let errorData = [];
let tempFilePath = [] let tempFilePath = [];
let errorTempFilePath = [] let errorTempFilePath = [];
for (let i = 0; i < res.length; i++) { for (let i = 0; i < res.length; i++) {
const item = res[i] const item = res[i];
const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index const index = item.uuid
? this.files.findIndex((p) => p.uuid === item.uuid)
: item.index;
if (index === -1 || !this.files) break if (index === -1 || !this.files) break;
if (item.errMsg === 'request:fail') { if (item.errMsg === "request:fail") {
this.files[index].url = item.path this.files[index].url = item.path;
this.files[index].status = 'error' this.files[index].status = "error";
this.files[index].errMsg = item.errMsg this.files[index].errMsg = item.errMsg;
// this.files[index].progress = -1 // this.files[index].progress = -1
errorData.push(this.files[index]) errorData.push(this.files[index]);
errorTempFilePath.push(this.files[index].url) errorTempFilePath.push(this.files[index].url);
} else { } else {
this.files[index].errMsg = '' this.files[index].errMsg = "";
this.files[index].fileID = item.url this.files[index].fileID = item.url;
const reg = /cloud:\/\/([\w.]+\/?)\S*/ const reg = /cloud:\/\/([\w.]+\/?)\S*/;
if (reg.test(item.url)) { if (reg.test(item.url)) {
this.files[index].url = await this.getTempFileURL(item.url) this.files[index].url = await this.getTempFileURL(item.url);
}else{ } else {
this.files[index].url = item.url this.files[index].url = item.url;
} }
this.files[index].status = 'success' this.files[index].status = "success";
this.files[index].progress += 1 this.files[index].progress += 1;
successData.push(this.files[index]) successData.push(this.files[index]);
tempFilePath.push(this.files[index].fileID) tempFilePath.push(this.files[index].fileID);
} }
} }
if (successData.length > 0) { if (successData.length > 0) {
this.setEmit() this.setEmit();
// //
this.$emit('success', { this.$emit("success", {
tempFiles: this.backObject(successData), tempFiles: this.backObject(successData),
tempFilePaths: tempFilePath tempFilePaths: tempFilePath,
}) });
} }
if (errorData.length > 0) { if (errorData.length > 0) {
this.$emit('fail', { this.$emit("fail", {
tempFiles: this.backObject(errorData), tempFiles: this.backObject(errorData),
tempFilePaths: errorTempFilePath tempFilePaths: errorTempFilePath,
}) });
} }
}, },
@ -499,22 +527,26 @@
* @param {Object} type * @param {Object} type
*/ */
setProgress(progressEvent, index, type) { setProgress(progressEvent, index, type) {
const fileLenth = this.files.length const fileLenth = this.files.length;
const percentNum = (index / fileLenth) * 100 const percentNum = (index / fileLenth) * 100;
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total) const percentCompleted = Math.round(
let idx = index (progressEvent.loaded * 100) / progressEvent.total
);
let idx = index;
if (!type) { if (!type) {
idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid) idx = this.files.findIndex(
(p) => p.uuid === progressEvent.tempFile.uuid
);
} }
if (idx === -1 || !this.files[idx]) return if (idx === -1 || !this.files[idx]) return;
// fix by mehaotian 100 -1 // fix by mehaotian 100 -1
this.files[idx].progress = percentCompleted - 1 this.files[idx].progress = percentCompleted - 1;
// //
this.$emit('progress', { this.$emit("progress", {
index: idx, index: idx,
progress: parseInt(percentCompleted), progress: parseInt(percentCompleted),
tempFile: this.files[idx] tempFile: this.files[idx],
}) });
}, },
/** /**
@ -522,14 +554,15 @@
* @param {Object} index * @param {Object} index
*/ */
delFile(index) { delFile(index) {
this.$emit('delete', { this.$emit("delete", {
tempFile: this.files[index], tempFile: this.files[index],
tempFilePath: this.files[index].url tempFilePath: this.files[index].url,
}) index,
this.files.splice(index, 1) });
this.files.splice(index, 1);
this.$nextTick(() => { this.$nextTick(() => {
this.setEmit() this.setEmit();
}) });
}, },
/** /**
@ -537,34 +570,34 @@
* @param {Object} name * @param {Object} name
*/ */
getFileExt(name) { getFileExt(name) {
const last_len = name.lastIndexOf('.') const last_len = name.lastIndexOf(".");
const len = name.length const len = name.length;
return { return {
name: name.substring(0, last_len), name: name.substring(0, last_len),
ext: name.substring(last_len + 1, len) ext: name.substring(last_len + 1, len),
} };
}, },
/** /**
* 处理返回事件 * 处理返回事件
*/ */
setEmit() { setEmit() {
let data = [] let data = [];
if (this.returnType === 'object') { if (this.returnType === "object") {
data = this.backObject(this.files)[0] data = this.backObject(this.files)[0];
this.localValue = data?data:null this.localValue = data ? data : null;
} else { } else {
data = this.backObject(this.files) data = this.backObject(this.files);
if (!this.localValue) { if (!this.localValue) {
this.localValue = [] this.localValue = [];
} }
this.localValue = [...data] this.localValue = [...data];
} }
// #ifdef VUE3 // #ifdef VUE3
this.$emit('update:modelValue', this.localValue) this.$emit("update:modelValue", this.localValue);
// #endif // #endif
// #ifndef VUE3 // #ifndef VUE3
this.$emit('input', this.localValue) this.$emit("input", this.localValue);
// #endif // #endif
}, },
@ -573,8 +606,8 @@
* @param {Object} files * @param {Object} files
*/ */
backObject(files) { backObject(files) {
let newFilesData = [] let newFilesData = [];
files.forEach(v => { files.forEach((v) => {
newFilesData.push({ newFilesData.push({
extname: v.extname, extname: v.extname,
fileType: v.fileType, fileType: v.fileType,
@ -582,23 +615,23 @@
name: v.name, name: v.name,
path: v.path, path: v.path,
size: v.size, size: v.size,
fileID:v.fileID, fileID: v.fileID,
url: v.url url: v.url,
}) });
}) });
return newFilesData return newFilesData;
}, },
async getTempFileURL(fileList) { async getTempFileURL(fileList) {
fileList = { fileList = {
fileList: [].concat(fileList) fileList: [].concat(fileList),
} };
const urls = await uniCloud.getTempFileURL(fileList) const urls = await uniCloud.getTempFileURL(fileList);
return urls.fileList[0].tempFileURL || '' return urls.fileList[0].tempFileURL || "";
}, },
/** /**
* 获取父元素实例 * 获取父元素实例
*/ */
getForm(name = 'uniForms') { getForm(name = "uniForms") {
let parent = this.$parent; let parent = this.$parent;
let parentName = parent.$options.name; let parentName = parent.$options.name;
while (parentName !== name) { while (parentName !== name) {
@ -607,57 +640,57 @@
parentName = parent.$options.name; parentName = parent.$options.name;
} }
return parent; return parent;
} },
} },
} };
</script> </script>
<style> <style>
.uni-file-picker { .uni-file-picker {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
/* #endif */ /* #endif */
flex: 1; flex: 1;
} }
.uni-file-picker__header { .uni-file-picker__header {
padding-top: 5px; padding-top: 5px;
padding-bottom: 10px; padding-bottom: 10px;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
justify-content: space-between; justify-content: space-between;
} }
.file-title { .file-title {
font-size: 14px; font-size: 14px;
color: #333; color: #333;
} }
.file-count { .file-count {
font-size: 14px; font-size: 14px;
color: #999; color: #999;
} }
.is-add { .is-add {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.icon-add { .icon-add {
width: 50px; width: 50px;
height: 5px; height: 5px;
background-color: #f1f1f1; background-color: #f1f1f1;
border-radius: 2px; border-radius: 2px;
} }
.rotate { .rotate {
position: absolute; position: absolute;
transform: rotate(90deg); transform: rotate(90deg);
} }
</style> </style>

Loading…
Cancel
Save