You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
371 lines
7.9 KiB
371 lines
7.9 KiB
<template>
|
|
<view class="container">
|
|
<view class="search-bar">
|
|
<view class="search-header">
|
|
<view class="my-posts-button" @click="toggleMyPosts">
|
|
<u-icon name="edit-pen" color="#fff" size="32"></u-icon>
|
|
<text class="my-posts-text">我发布的</text>
|
|
</view>
|
|
<view class="my-posts-button" @click="goToProfile">
|
|
<u-icon name="chat" color="#fff" size="32"></u-icon>
|
|
<text class="my-posts-text">我的私信</text>
|
|
</view>
|
|
<view class="search-input-container">
|
|
<u-search placeholder="请输入关键词" v-model="keyword" :show-action="false" @search="search" @input="onSearchInput"></u-search>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<u-tabs :list="tabs" :is-scroll="false" :current="currentTab" @change="changeTab"></u-tabs>
|
|
<view class="list-container">
|
|
<view v-for="item in list" :key="item.id" class="list-item">
|
|
<view class="item-header">
|
|
<view :class="['type-badge', item.type === 1 ? 'supply' : 'demand']">{{ item.type === 1 ? '供应' : '需求' }}</view>
|
|
<text class="time">{{ item.created_at }}</text>
|
|
</view>
|
|
<text class="title">{{ item.title }}</text>
|
|
<text class="description">{{ item.content }}</text>
|
|
<view class="tags" v-if="item.tag">
|
|
<text v-for="tag in item.tag.split(',')" :key="tag" class="tag">{{ tag }}</text>
|
|
</view>
|
|
<u-line color="#e8e8e8" margin="20rpx 0" />
|
|
<view class="item-footer">
|
|
<view class="user-info">
|
|
<u-avatar :src="item.user.headimgurl || ''" size="60"></u-avatar>
|
|
<text class="user-name">{{ item.user.name || '匿名用户' }}</text>
|
|
</view>
|
|
<view class="actions">
|
|
<view class="view-button view-button-check" @click="goToDetail(item.id)">
|
|
<text class="button-text">查看</text>
|
|
</view>
|
|
<view class="view-button view-button-msg" @click="goToChat(item)">
|
|
<text class="button-text">私信</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<u-loadmore :status="status" nomore-text="已经到底了~" />
|
|
</view>
|
|
<image class="publish-image" :src="base.imgHost('publish.png')" @click="goToPublish"></image>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import uSearch from '@/uview-ui/components/u-search/u-search.vue';
|
|
import uLoadmore from '@/uview-ui/components/u-loadmore/u-loadmore.vue';
|
|
import uTabs from '@/uview-ui/components/u-tabs/u-tabs.vue';
|
|
import uLine from '@/uview-ui/components/u-line/u-line.vue';
|
|
import uAvatar from '@/uview-ui/components/u-avatar/u-avatar.vue';
|
|
import { base } from '@/common/util.js';
|
|
|
|
export default {
|
|
components: {
|
|
uSearch,
|
|
uLoadmore,
|
|
uTabs,
|
|
uLine,
|
|
uAvatar
|
|
},
|
|
data() {
|
|
return {
|
|
base,
|
|
keyword: '',
|
|
currentTab: 0,
|
|
tabs: [{
|
|
name: '全部'
|
|
}, {
|
|
name: '供应'
|
|
}, {
|
|
name: '需求'
|
|
}],
|
|
list: [],
|
|
page: 1,
|
|
pageSize: 10,
|
|
status: 'loadmore',
|
|
loading: false
|
|
}
|
|
},
|
|
onLoad() {
|
|
this.fetchList();
|
|
},
|
|
onReachBottom() {
|
|
if (this.status === 'loadmore' && !this.loading) {
|
|
this.page++;
|
|
this.fetchList();
|
|
}
|
|
},
|
|
watch: {
|
|
keyword(newVal, oldVal) {
|
|
// 当关键词被清空时,自动刷新数据
|
|
if (oldVal && !newVal) {
|
|
this.page = 1;
|
|
this.list = [];
|
|
this.status = 'loadmore';
|
|
this.fetchList();
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
goToProfile() {
|
|
uni.navigateTo({
|
|
url: '/packages/chat/index'
|
|
});
|
|
},
|
|
changeTab(index) {
|
|
this.currentTab = index;
|
|
this.page = 1;
|
|
this.list = [];
|
|
this.status = 'loadmore';
|
|
this.fetchList();
|
|
},
|
|
search() {
|
|
this.page = 1;
|
|
this.list = [];
|
|
this.status = 'loadmore';
|
|
this.fetchList();
|
|
},
|
|
onSearchInput(value) {
|
|
// 当输入框内容变化时,可以在这里添加防抖逻辑
|
|
// 目前 watch 已经处理了清空的情况
|
|
},
|
|
fetchList() {
|
|
if (this.loading) return;
|
|
this.loading = true;
|
|
|
|
const params = {
|
|
page: this.page,
|
|
pageSize: this.pageSize
|
|
};
|
|
|
|
// 根据当前tab设置type参数
|
|
if (this.currentTab === 1) {
|
|
params.type = 1; // 供应
|
|
} else if (this.currentTab === 2) {
|
|
params.type = 2; // 需求
|
|
}
|
|
|
|
// 如果有搜索关键词
|
|
if (this.keyword) {
|
|
params.keyword = this.keyword;
|
|
}
|
|
|
|
this.$u.api.supplyDemandList(params).then(res => {
|
|
|
|
// res 直接就是 supplyDemands 对象
|
|
const supplyDemands = res.supplyDemands;
|
|
const newList = supplyDemands.data || [];
|
|
|
|
if (this.page === 1) {
|
|
this.list = newList;
|
|
} else {
|
|
this.list = [...this.list, ...newList];
|
|
}
|
|
|
|
// 判断是否还有更多数据
|
|
if (supplyDemands.current_page >= supplyDemands.last_page) {
|
|
this.status = 'nomore';
|
|
} else {
|
|
this.status = 'loadmore';
|
|
}
|
|
}).catch(err => {
|
|
console.error('获取供需列表失败:', err);
|
|
this.$u.toast('网络错误,请重试');
|
|
}).finally(() => {
|
|
this.loading = false;
|
|
});
|
|
},
|
|
goToPublish() {
|
|
uni.navigateTo({
|
|
url: '/packages/supply/publish'
|
|
})
|
|
},
|
|
goToDetail(id) {
|
|
uni.navigateTo({
|
|
url: `/packages/supply/detail?id=${id}`
|
|
})
|
|
},
|
|
goToChat(item) {
|
|
// 传递用户信息到聊天页面
|
|
uni.navigateTo({
|
|
url: `/packages/chat/chatWindow?userId=${item.user_id}&userName=${item.user.name}&supplyDemandId=${item.id}`
|
|
})
|
|
},
|
|
toggleMyPosts() {
|
|
// 跳转到我的发布页面
|
|
uni.navigateTo({
|
|
url: '/packages/supply/my-posts'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.container {
|
|
background-color: #f5f5f5;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.search-bar {
|
|
padding: 20rpx;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.search-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.my-posts-button {
|
|
display: flex;
|
|
align-items: center;
|
|
background: linear-gradient(to right, #e3ccb2, #cba579);
|
|
padding: 20rpx 30rpx;
|
|
border-radius: 60rpx;
|
|
box-shadow: 0 4rpx 12rpx rgba(203, 165, 121, 0.3);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.my-posts-button:active {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
.my-posts-text {
|
|
color: #fff;
|
|
font-size: 28rpx;
|
|
font-weight: 500;
|
|
margin-left: 10rpx;
|
|
}
|
|
|
|
.search-input-container {
|
|
flex: 1;
|
|
}
|
|
|
|
.list-container {
|
|
background: linear-gradient(to bottom, #e9f2fa, #e9f2fa);
|
|
padding: 20rpx;
|
|
min-height: calc(100vh - 180rpx);
|
|
/* Adjust as needed */
|
|
}
|
|
|
|
.list-item {
|
|
background-color: #fff;
|
|
border-radius: 20rpx;
|
|
padding: 25rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.item-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15rpx;
|
|
}
|
|
|
|
.type-badge {
|
|
font-size: 24rpx;
|
|
padding: 8rpx 15rpx;
|
|
border-radius: 10rpx;
|
|
}
|
|
|
|
.supply {
|
|
background-color: #fff0e6;
|
|
color: #f29100;
|
|
}
|
|
|
|
.demand {
|
|
background-color: #e6f0ff;
|
|
color: #007aff;
|
|
}
|
|
|
|
.time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
|
|
.title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
display: block;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.description {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
margin-bottom: 30rpx;
|
|
display: block;
|
|
max-height: 120rpx; /* 约3行文字的高度 */
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.tag {
|
|
background-color: #f5f5f5;
|
|
color: #666;
|
|
font-size: 24rpx;
|
|
padding: 8rpx 15rpx;
|
|
border-radius: 30rpx;
|
|
margin-right: 15rpx;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.item-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.user-info {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.user-name {
|
|
font-size: 28rpx;
|
|
margin-left: 15rpx;
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.view-button {
|
|
width: 150rpx;
|
|
height: 60rpx;
|
|
border-radius: 30rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.view-button-check {
|
|
background: linear-gradient(to right, #e3ccb2, #cba579);
|
|
margin-right: 20rpx;
|
|
}
|
|
|
|
.view-button-msg {
|
|
background: linear-gradient(to right, #5d5ebc, #12099a);
|
|
}
|
|
|
|
.button-text {
|
|
color: white;
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.publish-image {
|
|
position: fixed;
|
|
bottom: 80rpx;
|
|
right: 0rpx;
|
|
width: 180rpx;
|
|
height: 140rpx;
|
|
z-index: 99;
|
|
}
|
|
</style> |