完成供需API接口对接

dev
lynn 6 months ago
parent be2b86ad2a
commit 61faf51f9f

@ -40,6 +40,8 @@ let apiApp = {
// 供应需求
supplyDemandSave: '/api/mobile/supply-demand/save',
supplyDemandList: '/api/mobile/supply-demand/index',
supplyDemandDetail: '/api/mobile/supply-demand/detail',
}
// 此处第二个参数vm就是我们在页面使用的this你可以通过vm获取vuex等操作
@ -90,6 +92,8 @@ const install = (Vue, vm) => {
// 供应需求
let supplyDemandSave = (params = {}) => vm.$u.post(apiApp.supplyDemandSave, params);
let supplyDemandList = (params = {}) => vm.$u.get(apiApp.supplyDemandList, params);
let supplyDemandDetail = (params = {}) => vm.$u.get(apiApp.supplyDemandDetail, params);
// 将各个定义的接口名称统一放进对象挂载到vm.$u.api(因为vm就是this也即this.$u.api)下
vm.$u.api = {
@ -132,6 +136,8 @@ const install = (Vue, vm) => {
// 供应需求
supplyDemandSave,
supplyDemandList,
supplyDemandDetail,
};
}

@ -1,67 +1,83 @@
<template>
<view class="container" v-if="detail.user">
<view class="container" v-if="detail">
<view class="user-info-header">
<u-avatar :text="detail.user.name.charAt(0)" size="80"></u-avatar>
<u-avatar :src="detail.user && detail.user.headimgurl || 'https://via.placeholder.com/80'" size="80"></u-avatar>
<view class="user-details">
<text class="user-name">{{ detail.user.name }}</text>
<text class="post-time">{{ detail.time }}</text>
<text class="user-name">{{ detail.user && detail.user.name || detail.user && detail.user.nickname || '匿名用户' }}</text>
<text class="post-time">{{ detail.created_at }}</text>
</view>
<view class="stats">
<text class="type-badge">{{ detail.type === 'supply' ? '供应' : '需求' }}</text>
<text class="views">{{ detail.messageCount }}人私信 {{ detail.viewCount }}浏览</text>
<text class="type-badge" :class="detail.type === 1 ? 'supply' : 'demand'">{{ detail.type === 1 ? '供应' : '需求' }}</text>
<text class="views">{{ detail.contact_count }}人私信 {{ detail.view_count }}浏览</text>
</view>
</view>
<view class="content-card">
<text class="title">{{ detail.title }}</text>
<text class="description">{{ detail.description }}</text>
<!-- <image class="content-image" :src="detail.image" mode="widthFix"></image> -->
<view class="tags">
<text v-for="tag in detail.tags" :key="tag" class="tag">{{ tag }}</text>
<text class="description">{{ detail.content }}</text>
<view class="tags" v-if="detail.tag">
<text v-for="tag in detail.tag.split(',')" :key="tag" class="tag">{{ tag }}</text>
</view>
</view>
<view class="footer">
<view class="footer-action">
<u-icon name="star" size="40"></u-icon>
<text>收藏</text>
<view class="footer-action" @click="toggleCollect">
<u-icon :name="isCollected ? 'star-fill' : 'star'" size="40" :color="isCollected ? '#f29100' : '#606266'"></u-icon>
<text :style="{ color: isCollected ? '#f29100' : '#606266' }">收藏</text>
</view>
<u-button type="primary" shape="circle" class="message-btn">私信</u-button>
<u-button type="primary" shape="circle" class="message-btn" @click="goToChat"></u-button>
</view>
</view>
</template>
<script>
import uAvatar from '@/uview-ui/components/u-avatar/u-avatar.vue';
import uIcon from '@/uview-ui/components/u-icon/u-icon.vue';
import uButton from '@/uview-ui/components/u-button/u-button.vue';
export default {
components: {
uAvatar,
uIcon,
uButton
},
data() {
return {
detail: {}
detail: null,
isCollected: false
}
},
onLoad(options) {
// , options.id
console.log("页面ID:", options.id)
console.log("页面ID:", options.id);
this.fetchDetailData(options.id);
},
methods: {
fetchDetailData(id) {
//
this.detail = {
id: id,
user: {
id: 'user123',
name: '张云',
avatar: '' // avatar an be used here if available
},
time: '2小时前',
type: 'supply',
messageCount: 16,
viewCount: 265,
title: '提供企业管理咨询服务',
description: '专业企业管理咨询团队, 具有10年以上行业经验, 擅长企业战略规划、组织架构优化、流程梳理等。已服务过多家上市公司专业企业管理咨询团队, 具有10年以上行业经验, 擅长企业战略规划、组织架构优化、流程梳理等。',
image: 'https://via.placeholder.com/700x300.png/E8E8E8/A9A9A9?text=专业诚信敬业高能', // Placeholder image
tags: ['管理咨询', '战略规划', '管理咨询']
};
this.$u.api.supplyDemandDetail({ id: id }).then(res => {
console.log('详情数据:', res);
if (res && res.id) {
this.detail = res;
} else {
this.$u.toast('获取详情失败');
}
}).catch(err => {
console.error('获取详情失败:', err);
this.$u.toast('网络错误,请重试');
});
},
toggleCollect() {
this.isCollected = !this.isCollected;
this.$u.toast(this.isCollected ? '收藏成功' : '取消收藏');
},
goToChat() {
if (this.detail && this.detail.user && this.detail.user.id) {
const userName = this.detail.user.name || this.detail.user.nickname || '匿名用户';
uni.navigateTo({
url: `/packages/chat/chatWindow?userId=${this.detail.user.id}&userName=${userName}`
});
} else {
this.$u.toast('用户信息不完整');
}
}
}
}
@ -106,12 +122,20 @@
.type-badge {
font-size: 24rpx;
background-color: #fdf3e8;
color: #C9A36D;
padding: 8rpx 15rpx;
border-radius: 10rpx;
}
.type-badge.supply {
background-color: #fff0e6;
color: #f29100;
}
.type-badge.demand {
background-color: #e6f0ff;
color: #007aff;
}
.views {
font-size: 24rpx;
color: #909399;

@ -1,31 +1,31 @@
<template>
<view class="container">
<view class="search-bar">
<u-search placeholder="请输入关键词" v-model="keyword" :show-action="false"></u-search>
<u-search placeholder="请输入关键词" v-model="keyword" :show-action="false" @search="search" @input="onSearchInput"></u-search>
</view>
<u-tabs :list="tabs" :is-scroll="false" :current="currentTab" @change="changeTab"></u-tabs>
<view class="list-container">
<view v-for="item in filteredList" :key="item.id" class="list-item">
<view v-for="item in list" :key="item.id" class="list-item">
<view class="item-header">
<view :class="['type-badge', item.type === 'supply' ? 'supply' : 'demand']">{{ item.type === 'supply' ? '供应' : '需求' }}</view>
<text class="time">{{ item.time }}</text>
<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.description }}</text>
<view class="tags">
<text v-for="tag in item.tags" :key="tag" class="tag">{{ tag }}</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.avatar" size="60"></u-avatar>
<text class="user-name">{{ item.user.name }}</text>
<u-avatar :src="item.user_avatar || 'https://via.placeholder.com/60'" 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.user)">
<view class="view-button view-button-msg" @click="goToChat(item)">
<text class="button-text">私信</text>
</view>
</view>
@ -40,13 +40,22 @@
<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
uLoadmore,
uTabs,
uLine,
uAvatar
},
data() {
return {
base,
keyword: '',
currentTab: 0,
tabs: [{
@ -56,52 +65,96 @@
}, {
name: '需求'
}],
list: [{
id: 1,
type: 'supply',
time: '2小时前',
title: '提供企业管理咨询服务',
description: '专业企业管理咨询团队具有10年以上行业经验擅长企业战略规划、组织架构优化、流程梳理等。已服务过多家上市公司...',
tags: ['管理咨询', '战略规划', '管理咨询'],
user: {
name: '张云',
avatar: 'https://via.placeholder.com/60'
}
},
{
id: 2,
type: 'demand',
time: '2小时前',
title: '提供企业管理咨询服务',
description: '我们是一家初创公司目前在开发一款AI智能客服产品需要寻找有经验的技术合作伙伴共同推进项目发展...',
tags: ['AI', '技术合作', '客服系统'],
user: {
name: '李经理',
avatar: 'https://via.placeholder.com/60'
}
}
],
status: 'nomore'
list: [],
page: 1,
pageSize: 10,
status: 'loadmore',
loading: false
}
},
computed: {
filteredList() {
let list = this.list;
if (this.currentTab === 1) {
list = list.filter(item => item.type === 'supply');
} else if (this.currentTab === 2) {
list = list.filter(item => item.type === 'demand');
}
if (this.keyword) {
list = list.filter(item => item.title.includes(this.keyword) || item.description.includes(this.keyword));
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();
}
return list;
}
},
methods: {
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
};
// tabtype
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({
@ -113,10 +166,10 @@
url: `/packages/supply/detail?id=${id}`
})
},
goToChat(user) {
// id
goToChat(item) {
//
uni.navigateTo({
url: `/packages/chat/chatWindow?userId=${user.id}`
url: `/packages/chat/chatWindow?userId=${item.user_id}&userName=${item.user_name}`
})
}
}
@ -189,6 +242,8 @@
line-height: 1.6;
margin-bottom: 30rpx;
display: block;
max-height: 120rpx; /* 约3行文字的高度 */
overflow: hidden;
}
.tags {

Loading…
Cancel
Save