Browse Source

在线分享,搜索,详情,列表,分类。个人中心

master
ZhaoYang 2 weeks ago
parent
commit
b34a015c4d
  1. 7
      app.json
  2. 55
      pages/home/home.js
  3. 64
      pages/home/home.wxml
  4. 83
      pages/home/home.wxss
  5. 7
      pages/personal/personal.js
  6. 2
      pages/personal/personal.wxml
  7. 317
      pagesA/pages/attestation/attestation.js
  8. 4
      pagesA/pages/attestation/attestation.json
  9. 185
      pagesA/pages/attestation/attestation.wxml
  10. 546
      pagesA/pages/attestation/attestation.wxss
  11. 34
      pagesB/pages/experienceDetails/experienceDetails.js
  12. 4
      pagesB/pages/experienceDetails/experienceDetails.json
  13. 46
      pagesB/pages/experienceDetails/experienceDetails.wxml
  14. 146
      pagesB/pages/experienceDetails/experienceDetails.wxss
  15. 206
      pagesB/pages/experienceList/experienceList.js
  16. 4
      pagesB/pages/experienceList/experienceList.json
  17. 80
      pagesB/pages/experienceList/experienceList.wxml
  18. 332
      pagesB/pages/experienceList/experienceList.wxss
  19. 587
      pagesB/pages/forumlist/forumlist.js
  20. 1
      pagesB/pages/forumlist/forumlist.json
  21. 288
      pagesB/pages/forumlist/forumlist.wxml
  22. 998
      pagesB/pages/forumlist/forumlist.wxss
  23. 421
      pagesB/pages/onlineAsk/onlineAsk.js
  24. 66
      pagesB/pages/onlineAsk/onlineAsk.wxml
  25. 30
      pagesB/pages/onlineAsk/onlineAsk.wxss
  26. 44
      utils/api.js
  27. 3
      utils/baseUrl.js

7
app.json

@ -18,7 +18,8 @@
"pages/expert/expert",
"pages/expertChat/expertChat",
"pages/medicine/medicine",
"pages/medicineDetails/medicineDetails"
"pages/medicineDetails/medicineDetails",
"pages/attestation/attestation"
]
},
{
@ -31,7 +32,9 @@
"pages/administrativeDivision/administrativeDivision",
"pages/wzDetails/wzDetails",
"pages/spDetails/spDetails",
"pages/forumlist/forumlist"
"pages/forumlist/forumlist",
"pages/experienceList/experienceList",
"pages/experienceDetails/experienceDetails"
],
"independent": true
}

55
pages/home/home.js

@ -9,6 +9,7 @@ Page({
// 通知公告数据
currentNotice: 0,
noticeList: [],
forum:[]
},
@ -17,7 +18,6 @@ Page({
http.UserInfo({
data:{},
success:res=>{
console.log(789,res);
this.setData({
user:res.data.area
})
@ -25,6 +25,36 @@ Page({
})
},
// 在线问答列表
getforumList(){
http.forumList({
data:{},
success:res=>{
const zxwd = []
zxwd.push(res.rows[0])
this.setData({
forum:zxwd
})
}
})
},
// 经验分享列表
getexperience(){
http.experience({
data:{},
success:res=>{
console.log(111,res);
const zyfx = []
zyfx.push(res.rows[0])
this.setData({
suffer:zyfx
})
}
})
},
// 轮播
getCarousel() {
@ -115,9 +145,26 @@ Page({
},
// 问答详情
bindTw() {
bindTw(e) {
console.log(e);
const id = e.currentTarget.dataset.id
wx.navigateTo({
url: `/pagesB/pages/onlineAsk/onlineAsk?id=${id}`,
})
},
// 经验分享列表
viewexperience(){
wx.navigateTo({
url: '/pagesB/pages/experienceList/experienceList',
})
},
// 经验分享详情
bindfx(e){
const id = e.currentTarget.dataset.id
wx.navigateTo({
url: '/pagesB/pages/onlineAsk/onlineAsk',
url: `/pagesB/pages/experienceDetails/experienceDetails?id=${id}`,
})
},
@ -150,6 +197,8 @@ Page({
this.getDisaster()
this.getCarousel()
this.getLocation()
this.getforumList()
this.getexperience()
},
onShow() {

64
pages/home/home.wxml

@ -15,7 +15,6 @@
<image src="/pages/images/dw.png" mode="" />
<view>{{user.name}}</view>
</view>
</view>
<!-- AI问诊 -->
@ -120,28 +119,77 @@
<!-- 问题列表 -->
<view class="question-card placeholder" bind:tap="bindTw">
<view class="question-card placeholder" wx:for="{{forum}}" bind:tap="bindTw" data-id="{{item.id}}">
<view class="question-meta">
<view class="question-tag">
<text class="tag-text">发烧、流鼻涕、越来越瘦是什么原因?应该怎么治疗?</text>
<text class="tag-text">{{item.title}}</text>
</view>
</view>
<view class="question-info">
<view class="user-info">
<image src="/pages/images/tx.png" class="user-avatar"></image>
<image src="{{baseUrl+item.avatar}}" class="user-avatar"></image>
<view class="user-detail">
<view class="user-name">内蒙古养殖户</view>
<view class="user-location">
<text>内蒙古阿拉善左旗</text>
<view class="user-name">{{item.nickName}}</view>
</view>
</view>
<view class="time-info">
{{item.createdAt}}
</view>
</view>
<!-- 底部信息 -->
<view class="post-footer">
<view class="post-meta">
<view class="meta-item">
<image class="meta-icon" src="/pagesB/images/hf.png" mode="aspectFit"></image>
<text class="meta-count">{{item.answerCount || 0}}</text>
</view>
<view class="meta-item">
<image class="meta-icon" src="/pagesB/images/lll.png" mode="aspectFit"></image>
<text class="meta-count">{{item.viewCount || 0}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 经验分享板块 -->
<view class="user-question-section">
<!-- 标题区域 -->
<view class="question-header" bind:tap="bindwdlist">
<view class="question-title">
<view class="title-text1_1">经验分享</view>
<view class="title-sub">分享自己养殖经验</view>
</view>
<view class="view-all1_1" bindtap="viewexperience">
查看全部
</view>
</view>
<!-- 问题列表 -->
<view class="question-card placeholder" wx:for="{{suffer}}" bind:tap="bindfx" data-id="{{item.id}}">
<view class="question-meta">
<view class="question-tag">
<text class="tag-text">{{item.title}}</text>
</view>
</view>
<view class="question-info">
<view class="user-info">
<image src="{{baseUrl+item.vetAvatar}}" class="user-avatar"></image>
<view class="user-detail">
<view class="user-name">{{item.vetName}}</view>
</view>
</view>
<view class="time-info">
2025-12-25
{{item.publishTime}}
</view>
</view>
</view>
</view>
</view>
</view>

83
pages/home/home.wxss

@ -429,7 +429,7 @@
.title-text {
font-size: 38rpx;
font-weight: bold;
color: #333;
color: #7ad1cb;
margin-bottom: 8rpx;
position: relative;
padding-left: 20rpx;
@ -447,12 +447,37 @@
border-radius: 4rpx;
}
.title-text1_1 {
font-size: 38rpx;
font-weight: bold;
color: #7499C8;
margin-bottom: 8rpx;
position: relative;
padding-left: 20rpx;
}
.title-text1_1::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 8rpx;
height: 32rpx;
background: #79b2d3;
border-radius: 4rpx;
}
.title-sub {
font-size: 24rpx;
color: #999;
padding-left: 20rpx;
}
.view-all {
display: flex;
align-items: center;
@ -470,6 +495,21 @@
}
.view-all1_1{
display: flex;
align-items: center;
font-size: 26rpx;
color: #608ac0;
padding: 12rpx 24rpx;
background: rgba(96, 192, 185, 0.1);
border-radius: 30rpx;
transition: all 0.3s ease;
}
.view-all1_1:active {
background: rgba(131, 158, 199, 0.2);
transform: scale(0.98);
}
@ -537,16 +577,6 @@
margin-bottom: 6rpx;
}
.user-location {
display: flex;
align-items: center;
gap: 6rpx;
}
.user-location text {
font-size: 22rpx;
color: #999;
}
.time-info {
font-size: 22rpx;
@ -555,3 +585,34 @@
padding: 6rpx 16rpx;
border-radius: 16rpx;
}
.post-footer {
display: flex;
align-items: center;
justify-content: flex-end;
}
.post-meta {
display: flex;
align-items: center;
gap: 25rpx;
}
.meta-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.meta-icon {
width: 28rpx;
height: 28rpx;
opacity: 0.5;
}
.meta-count {
font-size: 26rpx;
font-weight: 600;
color: #64748b;
}

7
pages/personal/personal.js

@ -28,6 +28,13 @@ Page({
this.loadUserInfo();
},
// 跳转实名认证
bindrz(){
wx.navigateTo({
url: '/pagesA/pages/attestation/attestation',
})
},
onShow() {
},

2
pages/personal/personal.wxml

@ -57,7 +57,7 @@
<image class="item-icon" src="/pages/images/smrz.png"></image>
<text class="item-title">实名认证</text>
</view>
<view class="item-status {{userInfo.isVerified ? 'verified' : ''}}">
<view class="item-status {{userInfo.isVerified ? 'verified' : ''}}" bind:tap="bindrz">
{{userInfo.isVerified ? '已认证' : '去认证'}}
</view>
</view>

317
pagesA/pages/attestation/attestation.js

@ -0,0 +1,317 @@
// pages/real-name-auth/real-name-auth.js
Page({
data: {
// 表单数据
name: '',
phone: '',
smsCode: '',
// 焦点状态
nameFocus: false,
phoneFocus: false,
codeFocus: false,
// 错误提示
nameError: '',
phoneError: '',
smsCodeError: '',
// 验证码相关
canSendCode: false,
countdown: 0,
countdownTimer: null,
// 协议状态
agreed: false,
// 提交状态
canSubmit: false,
isSubmitting: false,
// 弹窗
showSuccessModal: false
},
onLoad() {
this.checkForm();
},
onUnload() {
// 清除定时器
if (this.data.countdownTimer) {
clearInterval(this.data.countdownTimer);
}
},
// 姓名输入处理
onNameInput(e) {
const name = e.detail.value.trim();
let nameError = '';
if (name && !/^[\u4e00-\u9fa5]{2,10}$/.test(name)) {
nameError = '姓名应为2-10个汉字';
}
this.setData({
name: name,
nameError: nameError
}, () => {
this.checkForm();
this.checkCanSendCode();
});
},
onNameFocus() {
this.setData({ nameFocus: true });
},
onNameBlur() {
this.setData({ nameFocus: false });
},
// 手机号输入处理
onPhoneInput(e) {
const phone = e.detail.value.trim();
let phoneError = '';
if (phone && !/^1[3-9]\d{9}$/.test(phone)) {
phoneError = '请输入正确的手机号码';
}
this.setData({
phone: phone,
phoneError: phoneError
}, () => {
this.checkForm();
this.checkCanSendCode();
});
},
onPhoneFocus() {
this.setData({ phoneFocus: true });
},
onPhoneBlur() {
this.setData({ phoneFocus: false });
},
// 验证码输入处理
onSmsCodeInput(e) {
const smsCode = e.detail.value.trim();
let smsCodeError = '';
if (smsCode && !/^\d{6}$/.test(smsCode)) {
smsCodeError = '请输入6位数字验证码';
}
this.setData({
smsCode: smsCode,
smsCodeError: smsCodeError
}, () => {
this.checkForm();
});
},
onCodeFocus() {
this.setData({ codeFocus: true });
},
onCodeBlur() {
this.setData({ codeFocus: false });
},
// 检查是否可以发送验证码
checkCanSendCode() {
const { name, phone, nameError, phoneError } = this.data;
const canSendCode = name && phone && !nameError && !phoneError;
this.setData({ canSendCode });
},
// 发送验证码
async sendSmsCode() {
const { name, phone, countdown } = this.data;
if (countdown > 0) return;
// 验证手机号格式
if (!/^1[3-9]\d{9}$/.test(phone)) {
this.setData({ phoneError: '请输入正确的手机号码' });
return;
}
// 显示加载
wx.showLoading({
title: '发送中...',
mask: true
});
try {
// 模拟发送验证码请求
await new Promise(resolve => setTimeout(resolve, 1500));
wx.hideLoading();
// 发送成功
wx.showToast({
title: '验证码已发送',
icon: 'success',
duration: 2000
});
// 开始倒计时
this.startCountdown();
} catch (error) {
wx.hideLoading();
wx.showToast({
title: '发送失败,请重试',
icon: 'error',
duration: 2000
});
}
},
// 开始倒计时
startCountdown() {
this.setData({ countdown: 60 });
const timer = setInterval(() => {
let { countdown } = this.data;
countdown--;
if (countdown <= 0) {
clearInterval(timer);
this.setData({
countdown: 0,
countdownTimer: null
});
} else {
this.setData({
countdown: countdown,
countdownTimer: timer
});
}
}, 1000);
},
// 协议处理
toggleAgreement() {
this.setData({
agreed: !this.data.agreed
}, () => {
this.checkForm();
});
},
viewAgreement() {
wx.navigateTo({
url: '/pages/web-view/web-view?url=' + encodeURIComponent('https://your-domain.com/agreement')
});
},
viewPrivacy() {
wx.navigateTo({
url: '/pages/web-view/web-view?url=' + encodeURIComponent('https://your-domain.com/privacy')
});
},
// 检查表单
checkForm() {
const {
name,
phone,
smsCode,
nameError,
phoneError,
smsCodeError,
agreed
} = this.data;
const isValid = name &&
phone &&
smsCode &&
!nameError &&
!phoneError &&
!smsCodeError &&
agreed;
this.setData({
canSubmit: isValid
});
},
// 提交认证
async submitAuth() {
if (!this.data.canSubmit || this.data.isSubmitting) return;
this.setData({ isSubmitting: true });
// 验证数据
const { name, phone, smsCode } = this.data;
// 最终验证
if (!/^[\u4e00-\u9fa5]{2,10}$/.test(name)) {
this.setData({
nameError: '姓名应为2-10个汉字',
isSubmitting: false
});
return;
}
if (!/^1[3-9]\d{9}$/.test(phone)) {
this.setData({
phoneError: '请输入正确的手机号码',
isSubmitting: false
});
return;
}
if (!/^\d{6}$/.test(smsCode)) {
this.setData({
smsCodeError: '请输入6位数字验证码',
isSubmitting: false
});
return;
}
try {
// 模拟API请求
await new Promise(resolve => setTimeout(resolve, 2000));
// 提交成功
this.setData({
isSubmitting: false,
showSuccessModal: true
});
// 保存认证信息到本地
wx.setStorageSync('realNameAuth', {
name: name,
phone: phone,
certified: true,
certifiedTime: new Date().getTime()
});
} catch (error) {
this.setData({ isSubmitting: false });
wx.showToast({
title: '认证失败,请重试',
icon: 'error',
duration: 2000
});
}
},
// 成功弹窗处理
closeSuccessModal() {
this.setData({ showSuccessModal: false });
},
// 前往首页
goToHome() {
this.closeSuccessModal();
wx.switchTab({
url: '/pages/index/index'
});
}
});

4
pagesA/pages/attestation/attestation.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"实名认证",
"usingComponents": {}
}

185
pagesA/pages/attestation/attestation.wxml

@ -0,0 +1,185 @@
<!-- pages/real-name-auth/real-name-auth.wxml -->
<view class="auth-container">
<!-- 顶部装饰 -->
<view class="top-decoration">
<view class="decoration-circle circle-1"></view>
<view class="decoration-circle circle-2"></view>
<view class="decoration-circle circle-3"></view>
</view>
<!-- 头部 -->
<view class="header">
<image class="logo" src="/assets/icons/sheep-logo.svg" mode="aspectFit"></image>
<view class="brand-name">与牧同行</view>
<view class="page-title">实名认证</view>
<view class="page-subtitle">开启您的牧业伙伴之旅</view>
</view>
<!-- 表单卡片 -->
<view class="form-card">
<!-- 表单标题 -->
<view class="card-header">
<view class="card-title">
<image class="title-icon" src="/assets/icons/id-card.svg" mode="aspectFit"></image>
<text>身份信息</text>
</view>
<view class="card-hint">请填写您的真实信息</view>
</view>
<!-- 姓名输入 -->
<view class="input-group">
<view class="input-label">
<image class="label-icon" src="/assets/icons/user.svg" mode="aspectFit"></image>
<text>真实姓名</text>
</view>
<view class="input-wrapper">
<input
class="name-input"
placeholder="请输入您的真实姓名"
placeholder-class="placeholder"
value="{{name}}"
bindinput="onNameInput"
focus="{{nameFocus}}"
bindfocus="onNameFocus"
bindblur="onNameBlur"
/>
<view class="input-border"></view>
<view class="input-focus-border {{nameFocus ? 'active' : ''}}"></view>
</view>
<view class="input-hint {{nameError ? 'error' : ''}}">
{{nameError || '请务必使用真实姓名'}}
</view>
</view>
<!-- 手机号输入 -->
<view class="input-group">
<view class="input-label">
<image class="label-icon" src="/assets/icons/phone.svg" mode="aspectFit"></image>
<text>手机号码</text>
</view>
<view class="input-wrapper">
<input
class="phone-input"
placeholder="请输入您的手机号码"
placeholder-class="placeholder"
value="{{phone}}"
bindinput="onPhoneInput"
type="number"
maxlength="11"
focus="{{phoneFocus}}"
bindfocus="onPhoneFocus"
bindblur="onPhoneBlur"
/>
<view class="input-border"></view>
<view class="input-focus-border {{phoneFocus ? 'active' : ''}}"></view>
</view>
<view class="input-hint {{phoneError ? 'error' : ''}}">
{{phoneError || '用于接收重要通知'}}
</view>
</view>
<!-- 验证码 -->
<view class="input-group">
<view class="input-label">
<image class="label-icon" src="/assets/icons/sms.svg" mode="aspectFit"></image>
<text>验证码</text>
</view>
<view class="code-input-wrapper">
<view class="code-input-container">
<input
class="code-input"
placeholder="请输入验证码"
placeholder-class="placeholder"
value="{{smsCode}}"
bindinput="onSmsCodeInput"
type="number"
maxlength="6"
focus="{{codeFocus}}"
bindfocus="onCodeFocus"
bindblur="onCodeBlur"
/>
<view class="input-border"></view>
<view class="input-focus-border {{codeFocus ? 'active' : ''}}"></view>
</view>
<button
class="send-code-btn {{!canSendCode ? 'disabled' : ''}} {{countdown > 0 ? 'counting' : ''}}"
bindtap="sendSmsCode"
disabled="{{!canSendCode || countdown > 0}}"
hover-class="btn-hover"
>
<view class="btn-content">
<image wx:if="{{countdown === 0}}" class="sms-icon" src="/assets/icons/send.svg" mode="aspectFit"></image>
<!-- <text>{{countdown > 0 ? `${countdown}s后重发` : '发送验证码'}}</text> -->
</view>
</button>
</view>
<view class="input-hint {{smsCodeError ? 'error' : ''}}">
{{smsCodeError || '输入6位数字验证码'}}
</view>
</view>
</view>
<!-- 协议 -->
<view class="agreement-card">
<label class="agreement-item" bindtap="toggleAgreement">
<view class="checkbox {{agreed ? 'checked' : ''}}">
<image wx:if="{{agreed}}" class="check-icon" src="/assets/icons/check.svg" mode="aspectFit"></image>
</view>
<view class="agreement-text">
我已阅读并同意
<text class="link" bindtap="viewAgreement">《用户服务协议》</text>
<text class="link" bindtap="viewPrivacy">《隐私政策》</text>
</view>
</label>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button
class="submit-btn {{canSubmit ? 'active' : 'disabled'}}"
bindtap="submitAuth"
disabled="{{!canSubmit}}"
hover-class="submit-btn-hover"
loading="{{isSubmitting}}"
>
<view class="btn-inner">
<text>{{isSubmitting ? '提交中...' : '完成认证'}}</text>
<image wx:if="{{!isSubmitting}}" class="arrow-icon" src="/assets/icons/arrow-right.svg" mode="aspectFit"></image>
</view>
</button>
<view class="submit-hint">
认证成功后,您将享受与牧同行的专属服务
</view>
</view>
<!-- 底部装饰 -->
<view class="bottom-decoration">
<image class="sheep-illustration" src="/assets/illustrations/sheep.svg" mode="aspectFit"></image>
<view class="decoration-text">
<text class="highlight">与牧同行</text>,伴您每一次成长
</view>
</view>
<!-- 成功弹窗 -->
<view class="success-modal {{showSuccessModal ? 'show' : ''}}">
<view class="modal-mask" bindtap="closeSuccessModal"></view>
<view class="modal-content">
<view class="modal-icon">
<image class="success-icon" src="/assets/icons/success.svg" mode="aspectFit"></image>
</view>
<view class="modal-title">认证成功!</view>
<view class="modal-message">
欢迎加入<text class="brand-highlight">与牧同行</text>大家庭
</view>
<view class="modal-subtitle">
您已成功完成实名认证,开始享受专属服务吧!
</view>
<button class="modal-btn" bindtap="goToHome">
<image class="home-icon" src="/assets/icons/home.svg" mode="aspectFit"></image>
<text>前往首页</text>
</button>
</view>
</view>
</view>

546
pagesA/pages/attestation/attestation.wxss

@ -0,0 +1,546 @@
/* pages/real-name-auth/real-name-auth.wxss */
/* 基础样式 */
.auth-container {
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
position: relative;
overflow: hidden;
padding: 40rpx 0 100rpx;
}
/* 顶部装饰 */
.top-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 300rpx;
overflow: hidden;
z-index: 0;
}
.decoration-circle {
position: absolute;
border-radius: 50%;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.1) 100%);
}
.circle-1 {
width: 400rpx;
height: 400rpx;
top: -200rpx;
right: -100rpx;
}
.circle-2 {
width: 300rpx;
height: 300rpx;
top: -150rpx;
left: -100rpx;
}
.circle-3 {
width: 200rpx;
height: 200rpx;
top: 100rpx;
left: 50%;
margin-left: -100rpx;
}
/* 头部 */
.header {
text-align: center;
padding: 40rpx 0 60rpx;
position: relative;
z-index: 1;
}
.logo {
width: 120rpx;
height: 120rpx;
margin: 0 auto 24rpx;
}
.brand-name {
font-size: 48rpx;
font-weight: bold;
color: #2c3e50;
margin-bottom: 16rpx;
letter-spacing: 4rpx;
}
.page-title {
font-size: 36rpx;
color: #2c3e50;
font-weight: 600;
margin-bottom: 12rpx;
}
.page-subtitle {
font-size: 28rpx;
color: #7f8c8d;
}
/* 表单卡片 */
.form-card {
background: white;
border-radius: 32rpx;
padding: 48rpx 40rpx;
margin: 0 40rpx 30rpx;
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.08);
position: relative;
z-index: 1;
animation: slideUp 0.6s ease-out;
}
.card-header {
margin-bottom: 40rpx;
}
.card-title {
display: flex;
align-items: center;
font-size: 32rpx;
font-weight: 600;
color: #2c3e50;
margin-bottom: 12rpx;
}
.title-icon {
width: 36rpx;
height: 36rpx;
margin-right: 16rpx;
}
.card-hint {
font-size: 26rpx;
color: #95a5a6;
}
/* 输入组 */
.input-group {
margin-bottom: 48rpx;
}
.input-label {
display: flex;
align-items: center;
margin-bottom: 20rpx;
font-size: 28rpx;
color: #2c3e50;
font-weight: 500;
}
.label-icon {
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
}
.input-wrapper,
.code-input-container {
position: relative;
}
.name-input,
.phone-input,
.code-input {
width: 100%;
height: 88rpx;
font-size: 28rpx;
color: #2c3e50;
padding: 0 24rpx;
background: #f8f9fa;
border-radius: 16rpx;
transition: all 0.3s ease;
}
.placeholder {
color: #bdc3c7;
font-size: 28rpx;
}
.input-border {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2rpx solid transparent;
border-radius: 16rpx;
pointer-events: none;
}
.input-focus-border {
position: absolute;
top: -2rpx;
left: -2rpx;
right: -2rpx;
bottom: -2rpx;
border: 4rpx solid transparent;
border-radius: 18rpx;
opacity: 0;
transition: all 0.3s ease;
pointer-events: none;
}
.input-focus-border.active {
opacity: 1;
border-color: rgba(52, 152, 219, 0.3);
}
.input-hint {
font-size: 24rpx;
color: #95a5a6;
margin-top: 12rpx;
min-height: 36rpx;
transition: all 0.3s ease;
}
.input-hint.error {
color: #e74c3c;
}
/* 验证码区域 */
.code-input-wrapper {
display: flex;
align-items: center;
gap: 20rpx;
}
.code-input-container {
flex: 1;
}
.send-code-btn {
min-width: 200rpx;
height: 88rpx;
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
border-radius: 16rpx;
font-size: 26rpx;
color: white;
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4rpx 20rpx rgba(52, 152, 219, 0.3);
}
.send-code-btn::after {
border: none;
}
.btn-content {
display: flex;
align-items: center;
justify-content: center;
}
.sms-icon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
.send-code-btn.disabled {
background: #bdc3c7;
box-shadow: none;
opacity: 0.6;
}
.send-code-btn.counting {
background: #95a5a6;
}
.btn-hover {
opacity: 0.9;
transform: translateY(-2rpx);
}
/* 协议 */
.agreement-card {
background: white;
border-radius: 24rpx;
padding: 32rpx 40rpx;
margin: 0 40rpx 40rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
}
.agreement-item {
display: flex;
align-items: flex-start;
}
.checkbox {
width: 36rpx;
height: 36rpx;
border: 2rpx solid #bdc3c7;
border-radius: 8rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.3s ease;
}
.checkbox.checked {
background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
border-color: transparent;
}
.check-icon {
width: 20rpx;
height: 20rpx;
}
.agreement-text {
font-size: 26rpx;
color: #2c3e50;
line-height: 1.4;
flex: 1;
}
.link {
color: #3498db;
text-decoration: none;
}
/* 提交按钮 */
.submit-section {
padding: 0 40rpx;
position: relative;
z-index: 1;
}
.submit-btn {
width: 100%;
height: 100rpx;
background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
border-radius: 50rpx;
font-size: 32rpx;
color: white;
font-weight: 600;
padding: 0;
margin: 0;
transition: all 0.3s ease;
box-shadow: 0 10rpx 40rpx rgba(46, 204, 113, 0.4);
}
.submit-btn::after {
border: none;
}
.submit-btn.disabled {
background: #bdc3c7;
box-shadow: none;
opacity: 0.7;
}
.btn-inner {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.arrow-icon {
width: 32rpx;
height: 32rpx;
margin-left: 12rpx;
opacity: 0.9;
}
.submit-btn-hover {
opacity: 0.9;
transform: translateY(-2rpx);
}
.submit-hint {
text-align: center;
font-size: 26rpx;
color: #7f8c8d;
margin-top: 24rpx;
}
/* 底部装饰 */
.bottom-decoration {
text-align: center;
margin-top: 60rpx;
position: relative;
z-index: 1;
animation: fadeInUp 0.8s ease-out 0.3s both;
}
.sheep-illustration {
width: 200rpx;
height: 150rpx;
margin-bottom: 20rpx;
opacity: 0.8;
}
.decoration-text {
font-size: 28rpx;
color: #7f8c8d;
}
.highlight {
color: #3498db;
font-weight: 600;
}
/* 成功弹窗 */
.success-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.success-modal.show {
opacity: 1;
visibility: visible;
}
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10rpx);
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.9);
width: 600rpx;
background: white;
border-radius: 32rpx;
padding: 60rpx 40rpx;
text-align: center;
opacity: 0;
transition: all 0.3s ease;
}
.success-modal.show .modal-content {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.modal-icon {
width: 120rpx;
height: 120rpx;
background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 32rpx;
}
.success-icon {
width: 60rpx;
height: 60rpx;
}
.modal-title {
font-size: 40rpx;
font-weight: bold;
color: #2c3e50;
margin-bottom: 20rpx;
}
.modal-message {
font-size: 32rpx;
color: #2c3e50;
margin-bottom: 16rpx;
}
.brand-highlight {
color: #3498db;
font-weight: 600;
}
.modal-subtitle {
font-size: 26rpx;
color: #7f8c8d;
margin-bottom: 40rpx;
line-height: 1.5;
}
.modal-btn {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
border-radius: 50rpx;
height: 88rpx;
font-size: 30rpx;
color: white;
font-weight: 600;
padding: 0 60rpx;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
}
.modal-btn::after {
border: none;
}
.home-icon {
width: 32rpx;
height: 32rpx;
}
/* 动画 */
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(50rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式 */
@media (max-width: 480px) {
.form-card,
.agreement-card,
.submit-section {
margin-left: 30rpx;
margin-right: 30rpx;
}
.code-input-wrapper {
flex-direction: column;
gap: 20rpx;
}
.send-code-btn {
min-width: 100%;
}
}

34
pagesB/pages/experienceDetails/experienceDetails.js

@ -0,0 +1,34 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
id: '', // 文章ID
baseUrl:baseUrl,
detail: {} // 文章详情数据
},
onLoad(options) {
this.getexperienceDetails(options)
},
// 经验分享详情
getexperienceDetails(options){
http.experienceDetails({
data:{
id:options.id
},
success:res=>{
console.log(1111,res);
var ch ='<img src="/dev-api'
const mmg = res.data.content.replace(new RegExp(ch, 'g'), '<img src="' + baseUrl)
const images = mmg.replace(/\<img/g, '<img style="width:100%;display:block; border-radius:3px;"');
this.setData({
detail:res.data,
content:images
})
}
})
},
})

4
pagesB/pages/experienceDetails/experienceDetails.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText": "分享详情",
"usingComponents": {}
}

46
pagesB/pages/experienceDetails/experienceDetails.wxml

@ -0,0 +1,46 @@
<view class="page-container">
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y="true">
<!-- 文章头部 -->
<view class="article-header">
<!-- 分类标签 -->
<view class="category-tag">
<text class="category-text">{{detail.categoryName}}</text>
</view>
<!-- 标题 -->
<view class="article-title">{{detail.title}}</view>
<!-- 作者信息和发布时间 -->
<view class="article-meta">
<view class="author-info">
<image src="{{baseUrl+detail.vetAvatar}}" class="author-avatar"></image>
<view class="author-details">
<text class="author-name">{{detail.vetName}}</text>
<text class="publish-time">{{detail.publishTime}}</text>
</view>
</view>
<!-- 浏览量 -->
<view class="view-info">
<image src="/pagesB/images/lll.png" class="view-icon"></image>
<text class="view-count">{{detail.viewCount}}次浏览</text>
</view>
</view>
</view>
<!-- 文章内容 -->
<view class="article-content">
<!-- 摘要 -->
<view wx:if="{{detail.summary}}" class="article-summary">
{{detail.summary}}
</view>
<!-- 正文内容 -->
<view class="article-body">
<rich-text class="content-text" space="emsp" nodes="{{content}}"></rich-text>
</view>
</view>
</scroll-view>
</view>

146
pagesB/pages/experienceDetails/experienceDetails.wxss

@ -0,0 +1,146 @@
.page-container {
background-color: #f5f7fa;
min-height: 100vh;
box-sizing: border-box;
}
/* 内容区域 */
.content-scroll {
height: 100vh;
padding-top: calc(88rpx + var(--status-bar-height));
box-sizing: border-box;
}
/* 文章头部 */
.article-header {
background-color: white;
padding: 40rpx 32rpx 32rpx;
margin-bottom: 20rpx;
}
.category-tag {
display: inline-block;
background-color: #E8F3FF;
padding: 8rpx 20rpx;
border-radius: 24rpx;
margin-bottom: 24rpx;
}
.category-text {
font-size: 24rpx;
color: #4A90E2;
font-weight: 500;
}
.article-title {
font-size: 40rpx;
color: #1a1a1a;
font-weight: 700;
line-height: 1.4;
margin-bottom: 32rpx;
}
.article-meta {
display: flex;
align-items: center;
justify-content: space-between;
}
.author-info {
display: flex;
align-items: center;
flex: 1;
}
.author-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
margin-right: 16rpx;
border: 2rpx solid #f0f0f0;
}
.author-details {
display: flex;
flex-direction: column;
}
.author-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 4rpx;
}
.publish-time {
font-size: 24rpx;
color: #999;
}
.view-info {
display: flex;
align-items: center;
}
.view-icon {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
opacity: 0.7;
}
.view-count {
font-size: 26rpx;
color: #999;
}
/* 文章内容 */
.article-content {
background-color: white;
padding: 32rpx;
}
.article-summary {
font-size: 30rpx;
color: #666;
line-height: 1.6;
margin-bottom: 32rpx;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
border-left: 4rpx solid #4A90E2;
}
.article-body {
font-size: 30rpx;
line-height: 1.8;
color: #333;
}
.content-text {
font-size: 30rpx;
line-height: 1.8;
color: #333;
white-space: pre-line;
}
.content-text p {
margin-bottom: 32rpx;
}
/* 响应式调整 */
@media (max-width: 375px) {
.article-header,
.article-content {
padding: 24rpx;
}
.article-title {
font-size: 36rpx;
}
.content-text {
font-size: 28rpx;
}
}

206
pagesB/pages/experienceList/experienceList.js

@ -0,0 +1,206 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
// 搜索文本
searchText: '',
baseUrl: baseUrl,
// 当前选中的分类
activeCategory: '',
// 分类数据
categories: [],
// 经验分享列表
experienceList: [],
// 分页参数
pageNum: 1,
pageSize: 10,
total: 0,
// 加载状态
loading: false,
hasMore: true,
// 搜索防抖定时器
searchTimer: null
},
onLoad() {
// 获取分类数据
this.getCategories()
// 获取经验分享列表
this.getExperienceList(true)
},
// 获取经验分享列表
getExperienceList(isRefresh = false) {
if (this.data.loading) return
const params = {
pageNum: isRefresh ? 1 : this.data.pageNum,
pageSize: this.data.pageSize
}
// 添加搜索关键词
if (this.data.searchText) {
params.searchKey = this.data.searchText.trim()
}
// 添加分类筛选
if (this.data.activeCategory) {
params.categoryName = this.data.activeCategory
}
this.setData({ loading: true })
http.experience({
data: params,
success: res => {
console.log('经验列表数据:', res)
if (res.code === 200) {
const newList = isRefresh ? res.rows : [...this.data.experienceList, ...res.rows]
const total = res.total || 0
const hasMore = newList.length < total
this.setData({
experienceList: newList,
total: total,
hasMore: hasMore,
pageNum: isRefresh ? 2 : this.data.pageNum + 1,
loading: false
})
} else {
wx.showToast({
title: res.msg || '加载失败',
icon: 'none'
})
this.setData({ loading: false })
}
},
fail: err => {
console.error('请求失败:', err)
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
})
this.setData({ loading: false })
}
})
},
// 获取分类数据
getCategories() {
http.experiencezd({
data: {
categoryName: 'category_id'
},
success: res => {
console.log('分类数据:', res)
if (res.code === 200) {
this.setData({
categories: res.data || []
})
}
},
fail: err => {
console.error('获取分类失败:', err)
}
})
},
// 处理搜索输入(带防抖)
onSearchInput(e) {
const searchText = e.detail.value
this.setData({
searchText: searchText
})
// 清除之前的定时器
if (this.data.searchTimer) {
clearTimeout(this.data.searchTimer)
}
// 设置新的定时器,500ms后执行搜索
const timer = setTimeout(() => {
this.handleSearch()
}, 500)
this.setData({
searchTimer: timer
})
},
// 搜索确认
onSearchConfirm() {
if (this.data.searchTimer) {
clearTimeout(this.data.searchTimer)
}
this.handleSearch()
},
// 执行搜索
handleSearch() {
this.setData({
pageNum: 1,
hasMore: true
})
this.getExperienceList(true)
},
// 清空搜索
clearSearch() {
this.setData({
searchText: '',
pageNum: 1,
hasMore: true
})
this.getExperienceList(true)
},
// 分类点击事件
onCategoryTap(e) {
const categoryId = e.currentTarget.dataset.id
if (this.data.activeCategory === categoryId) {
return
}
this.setData({
activeCategory: categoryId,
pageNum: 1,
hasMore: true
})
this.getExperienceList(true)
},
// 滚动到底部加载更多
onScrollToLower() {
if (!this.data.loading && this.data.hasMore) {
this.getExperienceList()
}
},
// 点击加载更多
loadMoreData() {
if (!this.data.loading && this.data.hasMore) {
this.getExperienceList()
}
},
// 经验分享点击事件
onExperienceTap(e) {
const id = e.currentTarget.dataset.id
wx.navigateTo({
url: `/pagesB/pages/experienceDetails/experienceDetails?id=${id}`,
})
},
onUnload() {
// 清理定时器
if (this.data.searchTimer) {
clearTimeout(this.data.searchTimer)
}
}
})

4
pagesB/pages/experienceList/experienceList.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText": "经验分享",
"usingComponents": {}
}

80
pagesB/pages/experienceList/experienceList.wxml

@ -0,0 +1,80 @@
<view class="page-container">
<!-- 搜索栏 -->
<view class="search-container">
<view class="search-box">
<image src="/pagesB/images/sou.png" class="search-icon"></image>
<input placeholder="搜索经验分享..." placeholder-class="placeholder" bindinput="onSearchInput" bindconfirm="onSearchConfirm" value="{{searchText}}" class="search-input" />
<view wx:if="{{searchText}}" bindtap="clearSearch" class="clear-btn">
<image src="/pagesA/images/ch.png" class="clear-icon"></image>
</view>
</view>
</view>
<!-- 分类标签 -->
<scroll-view class="category-container" scroll-x="true">
<view class="category-list">
<view class="category-item {{activeCategory === '' ? 'active' : ''}}" bindtap="onCategoryTap" data-id="">
<text class="category-text">全部</text>
</view>
<view wx:for="{{categories}}" wx:key="id" class="category-item {{activeCategory === item.label ? 'active' : ''}}" bindtap="onCategoryTap" data-id="{{item.label}}">
<text class="category-text">{{item.label}}</text>
</view>
</view>
</scroll-view>
<!-- 经验分享列表 -->
<scroll-view class="experience-scroll" scroll-y="true" bindscrolltolower="onScrollToLower" style="height: 100vh;">
<view class="experience-list">
<view wx:for="{{experienceList}}" wx:key="id" class="experience-item" bindtap="onExperienceTap" data-id="{{item.id}}">
<!-- 分类标签 -->
<view class="tag">
<view class="item-category-tag">
<text class="tag-text">{{item.categoryName}}</text>
</view>
<!-- 发布时间 -->
<text class="publish-time">{{item.publishTime}}</text>
</view>
<!-- 标题 -->
<view class="item-title">{{item.title}}</view>
<!-- 摘要 -->
<view class="item-summary">{{item.summary}}</view>
<!-- 底部信息 -->
<view class="item-footer">
<!-- 作者信息 -->
<view class="author-info">
<image src="{{baseUrl+item.vetAvatar}}" class="author-avatar"></image>
<text class="author-name">{{item.vetName}}</text>
</view>
<!-- 浏览量 -->
<view class="view-info">
<image src="/pagesB/images/lll.png" class="view-icon"></image>
<text class="view-count">{{item.viewCount}}</text>
</view>
</view>
</view>
<!-- 加载更多 -->
<view wx:if="{{!loading && hasMore}}" class="load-more" bindtap="loadMoreData">
<text class="load-more-text">点击加载更多</text>
</view>
<view wx:if="{{loading}}" class="loading">
<text class="loading-text">加载中...</text>
</view>
<view wx:if="{{!hasMore && experienceList.length > 0}}" class="no-more">
<text class="no-more-text">没有更多了</text>
</view>
<!-- 空状态 -->
<view wx:if="{{experienceList.length === 0 && !loading}}" class="empty-state">
<text class="empty-text">暂无相关经验分享</text>
<text class="empty-hint">{{searchText || activeCategory ? '换个关键词试试吧' : '快去分享你的经验吧'}}</text>
</view>
</view>
</scroll-view>
</view>

332
pagesB/pages/experienceList/experienceList.wxss

@ -0,0 +1,332 @@
/* pages/experience/experience.wxss */
.page-container {
background-color: #f5f7fa;
min-height: 100vh;
}
/* 搜索区域 */
.search-container {
background: linear-gradient(135deg, #4A90E2 0%, #6AC5F8 100%);
padding: 20rpx 32rpx 32rpx;
}
.search-box {
background-color: white;
border-radius: 50rpx;
padding: 20rpx 32rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 16rpx rgba(74, 144, 226, 0.2);
}
.search-icon {
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
}
.search-input {
width: 95%;
font-size: 28rpx;
color: #333;
}
.placeholder {
color: #999;
font-size: 28rpx;
}
.clear-btn {
width: 32rpx;
height: 32rpx;
display: flex;
align-items: center;
justify-content: center;
}
.clear-icon {
width: 30rpx;
height: 30rpx;
filter: brightness(0) contrast(100%);
}
/* 分类区域 */
.category-container {
background-color: white;
padding: 20rpx 32rpx;
white-space: nowrap;
box-sizing: border-box;
}
.category-list {
display: inline-flex;
}
.category-item {
display: inline-flex;
align-items: center;
padding: 12rpx 28rpx;
margin-right: 20rpx;
border-radius: 40rpx;
background-color: #f5f7fa;
border: 2rpx solid #f5f7fa;
transition: all 0.3s ease;
}
.category-item.active {
background-color: #E8F3FF;
border-color: #4A90E2;
}
.category-text {
font-size: 26rpx;
color: #666;
font-weight: 400;
}
.category-item.active .category-text {
color: #4A90E2;
font-weight: 500;
}
.category-item.active .category-count {
background-color: rgba(74, 144, 226, 0.1);
color: #4A90E2;
}
/* 经验列表 */
.experience-list {
padding: 32rpx;
}
.experience-item {
background-color: white;
border-radius: 20rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
}
.experience-item:active {
transform: translateY(-2rpx);
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.08);
}
.tag{
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 20rpx;
}
.item-category-tag {
display: inline-block;
background-color: #E8F3FF;
padding: 6rpx 16rpx;
border-radius: 20rpx;
}
.tag-text {
font-size: 22rpx;
color: #4A90E2;
font-weight: 500;
}
.item-title {
font-size: 34rpx;
color: #1a1a1a;
font-weight: 600;
line-height: 1.4;
margin-bottom: 16rpx;
}
.item-summary {
font-size: 28rpx;
color: #666;
line-height: 1.5;
margin-bottom: 24rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.item-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 20rpx;
border-top: 1rpx solid #f0f0f0;
}
.author-info {
display: flex;
align-items: center;
flex: 1;
}
.author-avatar {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
margin-right: 12rpx;
}
.author-name {
font-size: 24rpx;
color: #999;
}
.view-info {
display: flex;
align-items: center;
margin-right: 32rpx;
}
.view-icon {
width: 28rpx;
height: 28rpx;
margin-right: 8rpx;
opacity: 0.6;
}
.view-count {
font-size: 24rpx;
color: #999;
}
.publish-time {
font-size: 24rpx;
color: #ccc;
flex-shrink: 0;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-bottom: 16rpx;
}
.empty-hint {
font-size: 26rpx;
color: #ccc;
}
/* 新增样式 */
.experience-scroll {
box-sizing: border-box;
}
/* 加载更多样式 */
.load-more {
text-align: center;
padding: 40rpx 0;
color: #4A90E2;
font-size: 28rpx;
}
.load-more-text {
padding: 16rpx 32rpx;
background-color: #E8F3FF;
border-radius: 24rpx;
display: inline-block;
}
.loading {
text-align: center;
padding: 40rpx 0;
color: #999;
font-size: 28rpx;
}
.loading-text {
display: inline-block;
padding: 16rpx 32rpx;
}
.no-more {
text-align: center;
padding: 40rpx 0;
color: #ccc;
font-size: 26rpx;
}
.no-more-text {
display: inline-block;
padding: 16rpx 32rpx;
}
/* 优化空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
text-align: center;
}
.empty-text {
font-size: 32rpx;
color: #999;
margin-bottom: 20rpx;
font-weight: 500;
}
.empty-hint {
font-size: 28rpx;
color: #ccc;
}
/* 优化列表项样式 */
.experience-item {
position: relative;
overflow: hidden;
}
.experience-item:last-child {
margin-bottom: 0;
}
/* 响应式调整 */
@media (max-width: 375px) {
.load-more,
.loading,
.no-more {
padding: 30rpx 0;
}
.empty-state {
padding: 80rpx 0;
}
}
/* 响应式调整 */
@media (max-width: 375px) {
.search-container {
padding: 16rpx 24rpx 24rpx;
}
.experience-list {
padding: 24rpx;
}
.experience-item {
padding: 24rpx;
}
}

587
pagesB/pages/forumlist/forumlist.js

@ -1,232 +1,159 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
// 帖子列表相关
posts: [],
baseUrl: baseUrl,
loading: false,
searchLoading: false,
initialLoading: true,
loadingMore: false,
refreshing: false,
hasMore: true,
page: 1,
pageSize: 10,
currentFilter: 'all',
searchKeyword: '',
currentUser: '当前用户'
lastSearchKeyword: '', // 新增:记录上次搜索关键词
scrollTop: 0,
showBackToTop: false,
scrollThreshold: 300,
// 发布帖子相关
showPostModal: false,
postTitle: '',
postContent: '',
postImages: [],
isSubmitting: false
},
onLoad: function() {
this.loadPosts();
// 监听页面显示,用于刷新数据
wx.onAppShow(() => {
this.refreshData();
});
onLoad: function () {
this.loadPosts(true);
},
onShow: function() {
onShow: function () {
// 每次显示页面时刷新数据
this.refreshData();
},
// 加载帖子列表
loadPosts: function(reset = false) {
loadPosts: function (reset = false) {
// 防止重复请求
if (reset) {
this.setData({
page: 1,
hasMore: true,
posts: [],
loading: true
loading: true,
searchLoading: !!this.data.searchKeyword
});
} else if (this.data.loadingMore) {
return;
}
this.setData({
loading: reset || this.data.page === 1,
loadingMore: !reset && this.data.page > 1
});
// 准备请求参数
const params = {
page: this.data.page,
pageSize: this.data.pageSize,
filter: this.data.currentFilter,
search: this.data.searchKeyword
pageSize: this.data.pageSize
};
// 如果有搜索关键词,添加搜索参数
const searchKeyword = this.data.searchKeyword.trim();
if (searchKeyword) {
params.searchKey = searchKeyword;
}
// 记录当前搜索关键词
this.setData({
loading: reset || this.data.page === 1,
loadingMore: !reset && this.data.page > 1
lastSearchKeyword: searchKeyword
});
// 模拟API请求
setTimeout(() => {
const mockPosts = this.generateMockPosts(params);
// 调用接口获取数据
http.forumList({
data: params,
success: (res) => {
if (res.code === 200) {
let postsData = res.rows || [];
// 处理图片字段(分割字符串为数组)
postsData = postsData.map(item => {
if (item.images && typeof item.images === 'string') {
item.images = item.images.split(',').filter(img => img.trim() !== '');
} else {
item.images = [];
}
return item;
});
if (reset) {
this.setData({
posts: mockPosts,
posts: postsData,
loading: false,
hasMore: mockPosts.length === params.pageSize
searchLoading: false,
initialLoading: false,
hasMore: postsData.length === this.data.pageSize
});
} else {
this.setData({
posts: [...this.data.posts, ...mockPosts],
posts: [...this.data.posts, ...postsData],
loading: false,
initialLoading: false,
loadingMore: false,
hasMore: mockPosts.length === params.pageSize
hasMore: postsData.length === this.data.pageSize
});
}
} else {
wx.showToast({
title: res.msg || '加载失败',
icon: 'none'
});
this.setData({
loading: false,
searchLoading: false,
initialLoading: false,
loadingMore: false
});
}
if (this.data.refreshing) {
wx.stopPullDownRefresh();
this.setData({ refreshing: false });
}
}, 800);
},
// 生成模拟数据
generateMockPosts: function(params) {
const posts = [];
const currentUser = this.data.currentUser;
const baseId = (params.page - 1) * params.pageSize;
for (let i = 0; i < params.pageSize; i++) {
const id = baseId + i + 1;
const solved = i % 4 === 0;
const hot = i % 3 === 0 && i % 2 === 0;
const isMine = i % 5 === 0;
// 根据筛选条件过滤
if (params.filter === 'solved' && !solved) continue;
if (params.filter === 'unsolved' && solved) continue;
if (params.filter === 'mine' && !isMine) continue;
const tags = this.getRandomTags();
const post = {
id: id,
title: this.getRandomTitle(id),
summary: this.getRandomSummary(id),
username: isMine ? currentUser : this.getRandomUsername(),
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
time: this.getRandomTime(),
likeCount: Math.floor(Math.random() * 50),
replyCount: Math.floor(Math.random() * 30),
viewCount: Math.floor(Math.random() * 300),
solved: solved,
hot: hot,
tags: tags,
lastReply: Math.random() > 0.3 ? {
username: this.getRandomUsername(),
time: this.getRandomTime('short')
} : null
};
// 搜索过滤
if (params.search) {
const keyword = params.search.toLowerCase();
const titleMatch = post.title.toLowerCase().includes(keyword);
const summaryMatch = post.summary.toLowerCase().includes(keyword);
const tagMatch = post.tags.some(tag => tag.toLowerCase().includes(keyword));
if (!titleMatch && !summaryMatch && !tagMatch) {
continue;
}
}
posts.push(post);
}
// 热门排序
if (params.filter === 'hot') {
posts.sort((a, b) => {
const aScore = a.likeCount * 2 + a.replyCount * 3 + a.viewCount;
const bScore = b.likeCount * 2 + b.replyCount * 3 + b.viewCount;
return bScore - aScore;
this.setData({
refreshing: false
});
}
return posts;
},
// 随机生成标题
getRandomTitle: function(id) {
const titles = [
'微信小程序如何实现图片上传和预览功能?',
'uni-app开发中如何处理不同平台的兼容性问题?',
'JavaScript闭包的使用场景有哪些?',
'Vue3组合式API和选项式API该如何选择?',
'React Hooks在项目中的最佳实践',
'Node.js高并发场景下的性能优化方案',
'TypeScript在大型项目中的类型设计经验分享',
'微信小程序云开发数据库查询性能优化',
'前端工程化建设:从零搭建Webpack配置',
'移动端H5页面适配的最佳方案是什么?',
'如何优雅地处理前端错误监控和上报?',
'微前端架构在实际项目中的应用经验',
'Webpack5 Module Federation实战分享',
'前端代码质量保证:ESLint + Prettier + Husky',
'跨端开发框架选型:Flutter vs React Native vs uni-app'
];
return titles[id % titles.length] || titles[0];
},
// 随机生成摘要
getRandomSummary: function(id) {
const summaries = [
'我正在开发一个微信小程序,需要实现图片上传功能,并且能够在上传前预览图片。请问有什么好的实现方案吗?上传的图片大小限制和格式有什么建议?',
'最近在做一个uni-app项目,需要同时兼容微信小程序和H5,遇到了一些样式和API兼容性问题,大家有什么好的解决方案吗?',
'在实际项目中经常使用闭包,但对其原理和应用场景理解还不够深入,想请教一下大家在项目中都是如何使用闭包的?',
'公司新项目准备使用Vue3,对于组合式API和选项式API的选择有些纠结,大家有什么建议吗?各自的使用场景是什么?',
'React Hooks确实很方便,但在大型项目中如何合理组织Hooks,避免过度使用导致代码难以维护?',
'我们的Node.js服务在高并发场景下性能表现不佳,有哪些常见的性能优化方案可以参考?',
'项目准备从JavaScript迁移到TypeScript,在类型设计方面有什么经验可以分享吗?如何设计合理的泛型和接口?'
];
return summaries[id % summaries.length] || summaries[0];
},
// 随机生成用户名
getRandomUsername: function() {
const usernames = [
'前端工程师', '技术爱好者', '小程序开发', '全栈程序员',
'架构师老王', '代码艺术家', '算法工程师', '产品经理',
'UI设计师', '测试工程师', '运维小哥', '数据分析师'
];
return usernames[Math.floor(Math.random() * usernames.length)];
},
// 随机生成时间
getRandomTime: function(type = 'normal') {
const times = type === 'short'
? ['5分钟前', '10分钟前', '半小时前', '1小时前']
: ['2小时前', '5小时前', '昨天', '2天前', '3天前', '一周前'];
return times[Math.floor(Math.random() * times.length)];
},
// 随机生成标签
getRandomTags: function() {
const allTags = [
'微信小程序', '前端开发', 'JavaScript', 'Vue.js', 'React',
'Node.js', 'TypeScript', 'uni-app', '性能优化', '工程化',
'移动端', 'H5', 'CSS', 'Webpack', 'Git'
];
const count = Math.floor(Math.random() * 3) + 1;
const tags = [];
const usedIndices = new Set();
for (let i = 0; i < count; i++) {
let index;
do {
index = Math.floor(Math.random() * allTags.length);
} while (usedIndices.has(index));
usedIndices.add(index);
tags.push(allTags[index]);
fail: (err) => {
wx.showToast({
title: '网络错误',
icon: 'none'
});
this.setData({
loading: false,
searchLoading: false,
initialLoading: false,
loadingMore: false,
refreshing: false
});
}
return tags;
});
},
// 下拉刷新
onRefresh: function() {
this.setData({ refreshing: true });
onRefresh: function () {
this.setData({
refreshing: true
});
this.loadPosts(true);
},
// 滚动到底部加载更多
loadMore: function() {
// 加载更多
loadMore: function () {
if (!this.data.hasMore || this.data.loadingMore) return;
this.setData({
@ -236,111 +163,315 @@ Page({
});
},
// 筛选切换
changeFilter: function(e) {
const filterType = e.currentTarget.dataset.type;
if (this.data.currentFilter === filterType) return;
// 搜索输入(防抖)
onSearchInput: function (e) {
const keyword = e.detail.value;
this.setData({
currentFilter: filterType,
searchKeyword: '' // 切换筛选时清空搜索
}, () => {
this.loadPosts(true);
searchKeyword: keyword
});
},
// 搜索输入
onSearchInput: function(e) {
this.setData({ searchKeyword: e.detail.value });
// 防抖搜索
clearTimeout(this.searchTimer);
// 如果输入框为空,立即重置搜索
if (!keyword.trim()) {
this.setData({
searchKeyword: ''
});
// 清空搜索时立即重新加载数据
this.loadPosts(true);
return;
}
this.searchTimer = setTimeout(() => {
if (e.detail.value.trim()) {
// 只有当有搜索词且与上次不同时才搜索
if (keyword.trim() && keyword.trim() !== this.data.lastSearchKeyword) {
this.loadPosts(true);
}
}, 300);
}, 500);
},
// 搜索确认
onSearchConfirm: function(e) {
onSearchConfirm: function (e) {
const keyword = e.detail.value.trim();
if (keyword) {
this.setData({ searchKeyword: keyword });
this.setData({
searchKeyword: keyword
});
// 如果搜索词为空,加载所有帖子
if (!keyword) {
this.loadPosts(true);
} else {
// 只有当搜索词与上次不同时才搜索
if (keyword !== this.data.lastSearchKeyword) {
this.loadPosts(true);
}
}
},
// 清空搜索
clearSearch: function() {
// 清空搜索 - 优化版
clearSearch: function () {
// 如果当前已经有搜索词,才执行清空操作
if (this.data.searchKeyword) {
this.setData({
searchKeyword: '',
currentFilter: 'all'
searchKeyword: ''
}, () => {
// 清空后立即加载所有帖子
this.loadPosts(true);
});
}
},
// 跳转到详情页
goToDetail: function(e) {
goToDetail: function (e) {
const postId = e.currentTarget.dataset.id;
wx.navigateTo({
url: `/pages/forum/detail/detail?id=${postId}`,
success: () => {
// 记录浏览历史
this.recordViewHistory(postId);
url: `/pagesB/pages/onlineAsk/onlineAsk?id=${postId}`
});
},
// 图片预览功能
previewImage: function (e) {
const postIndex = e.currentTarget.dataset.postindex;
const imageIndex = e.currentTarget.dataset.imageindex;
const post = this.data.posts[postIndex];
if (!post || !post.images || post.images.length === 0) return;
// 构建完整的图片URL数组
const urls = post.images.map(img => this.data.baseUrl + img);
wx.previewImage({
current: urls[imageIndex], // 当前显示图片的链接
urls: urls // 需要预览的图片链接列表
});
},
// 显示发布模态框
createPost: function () {
// 检查登录状态(如果需要)
// 这里可以添加登录检查逻辑
this.setData({
showPostModal: true
});
},
// 隐藏发布模态框
hidePostModal: function () {
if (this.data.isSubmitting) return;
this.setData({
showPostModal: false,
postTitle: '',
postContent: '',
postImages: []
});
},
// 阻止事件冒泡
stopPropagation: function () {},
// 标题输入
onPostTitleInput: function (e) {
this.setData({
postTitle: e.detail.value
});
},
// 内容输入
onPostContentInput: function (e) {
this.setData({
postContent: e.detail.value
});
},
// 选择图片
chooseImage: function () {
const remaining = 3 - this.data.postImages.length;
if (remaining <= 0) {
wx.showToast({
title: '最多上传3张图片',
icon: 'none'
});
return;
}
wx.chooseMedia({
count: remaining,
mediaType: ['image'],
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFiles = res.tempFiles;
const newImages = tempFiles.map(file => file.tempFilePath);
const postImages = [...this.data.postImages, ...newImages];
this.setData({
postImages: postImages.slice(0, 3) // 确保不超过3张
});
},
fail: (err) => {
console.error('选择图片失败:', err);
}
});
},
// 创建新帖子
createPost: function() {
wx.navigateTo({
url: '/pages/forum/create/create'
// 移除图片
removeImage: function (e) {
const index = e.currentTarget.dataset.index;
const postImages = [...this.data.postImages];
postImages.splice(index, 1);
this.setData({
postImages
});
},
// 记录浏览历史
recordViewHistory: function(postId) {
try {
const history = wx.getStorageSync('forumViewHistory') || [];
const index = history.findIndex(item => item.id === postId);
// 提交帖子
submitPost: function () {
const { postTitle, postContent, postImages } = this.data;
// 验证输入
if (!postTitle.trim()) {
wx.showToast({
title: '请输入标题',
icon: 'none'
});
return;
}
if (!postContent.trim()) {
wx.showToast({
title: '请输入内容',
icon: 'none'
});
return;
}
this.setData({
isSubmitting: true
});
if (index !== -1) {
history.splice(index, 1);
// 如果有图片,先上传图片
const uploadPromises = postImages.map(imagePath => {
return new Promise((resolve, reject) => {
wx.uploadFile({
url: baseUrl+'/common/upload',
header: {
'Authorization': 'Bearer ' + wx.getStorageSync('token')
},
filePath: imagePath,
name: 'file',
success: (res) => {
const data = JSON.parse(res.data);
console.log(data);
if (data.code === 200) {
resolve(data.fileName); // 假设返回的图片路径在data.url中
} else {
reject(new Error('图片上传失败'));
}
},
fail: (err) => {
reject(err);
}
});
});
});
// 处理图片上传
Promise.all(uploadPromises)
.then((imageUrls) => {
// 所有图片上传成功,提交帖子数据
const postData = {
title: postTitle,
content: postContent,
images: imageUrls.join(',') // 将图片URL用逗号拼接
};
history.unshift({
id: postId,
timestamp: Date.now()
return http.forumAdd({
data: postData,
success:res=>{
console.log(1111,res);
if (res.code === 200) {
// 发布成功
this.setData({
showPostModal: false,
postTitle: '',
postContent: '',
postImages: [],
isSubmitting: false
});
wx.showToast({
title: '发布成功',
icon: 'success',
duration: 2000
});
// 只保留最近50条记录
if (history.length > 50) {
history.pop();
// 刷新帖子列表
setTimeout(() => {
this.loadPosts(true);
}, 500);
} else {
throw new Error(res.msg || '发布失败');
}
}
});
})
},
// 滚动事件监听
onScroll: function (e) {
const scrollTop = e.detail.scrollTop;
const showBackToTop = scrollTop > this.data.scrollThreshold;
wx.setStorageSync('forumViewHistory', history);
} catch (error) {
console.error('记录浏览历史失败:', error);
if (showBackToTop !== this.data.showBackToTop) {
this.setData({
scrollTop: scrollTop,
showBackToTop: showBackToTop
});
}
},
// 返回顶部
backToTop: function () {
this.setData({
showBackToTop: false
});
wx.pageScrollTo({
scrollTop: 0,
duration: 400,
success: () => {
this.setData({
scrollTop: 0
});
},
fail: (err) => {
console.log('滚动失败:', err);
this.setData({
scrollTop: 0
});
}
});
},
// 刷新数据
refreshData: function() {
// 这里可以检查是否有新数据需要刷新
// 例如:从详情页返回时刷新点赞状态等
refreshData: function () {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
if (currentPage.data && currentPage.data.refresh) {
this.loadPosts(true);
currentPage.setData({
refresh: false
});
}
},
onPullDownRefresh: function() {
onPullDownRefresh: function () {
this.onRefresh();
},
onReachBottom: function() {
onReachBottom: function () {
this.loadMore();
},
onPageScroll: function(e) {
// 可以在这里处理页面滚动时的效果
}
});

1
pagesB/pages/forumlist/forumlist.json

@ -1,3 +1,4 @@
{
"navigationBarTitleText": "问答论坛",
"usingComponents": {}
}

288
pagesB/pages/forumlist/forumlist.wxml

@ -1,202 +1,208 @@
<view class="forum-list-page">
<!-- 顶部栏 -->
<view class="header">
<view class="title">问答论坛</view>
<button class="add-btn" bindtap="createPost">提问</button>
</view>
<!-- 筛选栏 -->
<view class="filter-bar">
<scroll-view class="filter-scroll" scroll-x>
<view class="filter-list">
<view
class="filter-item {{currentFilter === 'all' ? 'active' : ''}}"
bindtap="changeFilter"
data-type="all"
>
<text>全部</text>
</view>
<view
class="filter-item {{currentFilter === 'unsolved' ? 'active' : ''}}"
bindtap="changeFilter"
data-type="unsolved"
>
<text>待解决</text>
</view>
<view
class="filter-item {{currentFilter === 'solved' ? 'active' : ''}}"
bindtap="changeFilter"
data-type="solved"
>
<text>已解决</text>
</view>
<view
class="filter-item {{currentFilter === 'hot' ? 'active' : ''}}"
bindtap="changeFilter"
data-type="hot"
>
<text>热门</text>
</view>
<view
class="filter-item {{currentFilter === 'mine' ? 'active' : ''}}"
bindtap="changeFilter"
data-type="mine"
>
<text>我的帖子</text>
</view>
<view class="forum-page">
<!-- 顶部栏 -->
<view class="header">
<view class="header-content">
<view class="header-main">
<text class="title-text">问答社区</text>
<text class="title-sub">互帮互助,共同成长</text>
</view>
</scroll-view>
</view>
</view>
<!-- 主内容区 -->
<view class="main-content">
<!-- 搜索框 -->
<view class="search-container">
<view class="search-input-wrapper">
<image class="search-icon" src="/images/search.png" mode="aspectFit"></image>
<input
class="search-input"
placeholder="搜索问题或关键词..."
value="{{searchKeyword}}"
bindinput="onSearchInput"
bindconfirm="onSearchConfirm"
confirm-type="search"
/>
<view class="search-section">
<view class="search-box">
<image class="search-icon" src="/pagesB/images/sou.png" mode="aspectFit"></image>
<input class="search-input" placeholder="搜索问题或关键词..." value="{{searchKeyword}}" bindinput="onSearchInput" bindconfirm="onSearchConfirm" confirm-type="search" />
<view class="search-clear" wx:if="{{searchKeyword}}" bindtap="clearSearch">
×
<text class="clear-text">×</text>
</view>
</view>
</view>
<!-- 帖子列表 -->
<scroll-view
class="post-list-container"
scroll-y
enable-back-to-top
bindscrolltolower="loadMore"
refresher-enabled="{{true}}"
refresher-triggered="{{refreshing}}"
bindrefresherrefresh="onRefresh"
>
<scroll-view class="post-list-section" scroll-y enable-back-to-top scroll-top="{{scrollTop}}" bindscrolltolower="loadMore" bindscroll="onScroll" refresher-enabled="{{true}}" refresher-triggered="{{refreshing}}" bindrefresherrefresh="onRefresh">
<!-- 搜索加载提示 -->
<view class="search-loading" wx:if="{{searchLoading && posts.length === 0}}">
<view class="search-spinner"></view>
<text class="search-loading-text">搜索中...</text>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{!loading && posts.length === 0}}">
<image class="empty-image" src="/images/empty-forum.png" mode="aspectFit"></image>
<view class="empty-state" wx:if="{{!loading && !searchLoading && posts.length === 0}}">
<view class="empty-text" wx:if="{{searchKeyword}}">
没有找到"{{searchKeyword}}"相关的问题
</view>
<view class="empty-text" wx:else>
暂无帖子,快来发布第一个问题吧!
这里还没有问题,快来发布第一个吧!
</view>
<button class="empty-btn" bindtap="createPost" wx:if="{{!searchKeyword}}">发布问题</button>
<button class="empty-btn" bindtap="clearSearch" wx:else>清空搜索</button>
<button class="empty-btn" bindtap="createPost" wx:if="{{!searchKeyword}}">
发布问题
</button>
</view>
<!-- 帖子列表 -->
<view class="post-list" wx:if="{{posts.length > 0}}">
<block wx:for="{{posts}}" wx:key="id">
<view class="post-item" data-id="{{item.id}}" bindtap="goToDetail">
<!-- 左侧状态栏 -->
<view class="post-status-side">
<view class="vote-count">
<view class="vote-number">{{item.likeCount}}</view>
<view class="vote-label">点赞</view>
<view class="post-card" data-id="{{item.id}}" bindtap="goToDetail">
<view class="post-content">
<view class="post-type">
<!-- 头像 -->
<view class="user-info">
<image class="user-avatar" src="{{baseUrl+item.avatar}}" mode="aspectFill"></image>
<text class="username">{{item.nickName}}</text>
</view>
<view class="reply-count">
<view class="reply-number">{{item.replyCount}}</view>
<view class="reply-label">回答</view>
<!-- 时间 -->
<text class="post-time">{{item.createdAt}}</text>
</view>
<view class="view-count">
<view class="view-number">{{item.viewCount}}</view>
<view class="view-label">浏览</view>
<!-- 标题 -->
<view class="post-title-wrapper">
<text class="post-title">{{item.title}}</text>
</view>
<!-- 内容摘要 -->
<view class="post-summary">
{{item.content}}
</view>
<!-- 右侧内容区 -->
<view class="post-content-main">
<!-- 图片预览 -->
<view class="post-images" wx:if="{{item.images && item.images.length>0}}">
<view class="images-grid">
<block wx:for="{{item.images}}" wx:key="index" wx:for-index="imgIndex">
<image class="post-image" src="{{baseUrl+item}}" mode="aspectFill" data-postindex="{{index}}" data-imageindex="{{imgIndex}}" bindtap="previewImage"></image>
</block>
</view>
</view>
<!-- 帖子标题和状态 -->
<view class="post-header">
<view class="post-title">{{item.title}}</view>
<view class="status-badge" wx:if="{{item.solved}}">
<text class="solved-badge">已解决</text>
<!-- 底部信息 -->
<view class="post-footer">
<view class="post-meta">
<view class="meta-item">
<image class="meta-icon" src="/pagesB/images/hf.png" mode="aspectFit"></image>
<text class="meta-count">{{item.answerCount || 0}}</text>
</view>
<view class="meta-item">
<image class="meta-icon" src="/pagesB/images/lll.png" mode="aspectFit"></image>
<text class="meta-count">{{item.viewCount || 0}}</text>
</view>
<view class="status-badge" wx:if="{{item.hot}}">
<text class="hot-badge">热门</text>
</view>
</view>
<!-- 帖子内容摘要 -->
<view class="post-summary">{{item.summary}}</view>
</view>
</view>
</block>
<!-- 帖子元信息 -->
<view class="post-meta">
<!-- 加载更多 -->
<view class="load-more" wx:if="{{hasMore && posts.length > 0}}">
<view class="loading-spinner" wx:if="{{!loadingMore}}">
<text class="loading-text">上拉加载更多</text>
</view>
<view class="loading-spinner" wx:else>
<view class="spinner"></view>
<text class="loading-text">加载中...</text>
</view>
</view>
<!-- 用户信息 -->
<view class="user-info">
<image class="user-avatar" src="{{item.avatar}}" mode="aspectFill"></image>
<text class="username">{{item.username}}</text>
<text class="separator">·</text>
<text class="post-time">{{item.time}}</text>
<!-- 没有更多了 -->
<view class="no-more" wx:if="{{!hasMore && posts.length > 0}}">
<view class="no-more-line"></view>
<text class="no-more-text">已经到底了</text>
<view class="no-more-line"></view>
</view>
<!-- 标签 -->
<view class="post-tags" wx:if="{{item.tags && item.tags.length > 0}}">
<block wx:for="{{item.tags.slice(0, 2)}}" wx:key="index">
<text class="tag">{{item}}</text>
</block>
<text class="more-tags" wx:if="{{item.tags.length > 2}}">+{{item.tags.length - 2}}</text>
</view>
</scroll-view>
</view>
<!-- 固定发布按钮(左下角) -->
<view class="floating-create-btn" bindtap="createPost">
<image class="create-icon" src="/pagesA/images/jh.png" mode="aspectFit"></image>
</view>
<!-- 返回顶部按钮(右下角) -->
<view class="back-to-top-btn {{showBackToTop ? 'show' : ''}}" bindtap="backToTop">
<view class="back-top-icon">↑</view>
</view>
<!-- 发布模态框 -->
<view class="post-modal-overlay" wx:if="{{showPostModal}}" bindtap="hidePostModal">
<view class="post-modal-content" catchtap="stopPropagation">
<view class="modal-header">
<text class="modal-title">发布问题</text>
<view class="modal-close" bindtap="hidePostModal">
<text class="close-icon">×</text>
</view>
</view>
<!-- 最后回复信息 -->
<view class="last-reply" wx:if="{{item.lastReply}}">
<text class="last-reply-label">最后回复:</text>
<text class="last-reply-user">{{item.lastReply.username}}</text>
<text class="separator">·</text>
<text class="last-reply-time">{{item.lastReply.time}}</text>
<view class="modal-body">
<view class="form-field">
<view class="field-header">
<text class="field-label">问题标题</text>
<text class="field-counter">{{postTitle.length}}/50</text>
</view>
<input class="title-input" placeholder="请输入问题标题" value="{{postTitle}}" bindinput="onPostTitleInput" maxlength="50" />
</view>
<view class="form-field">
<view class="field-header">
<text class="field-label">详细描述</text>
<text class="field-counter">{{postContent.length}}/500</text>
</view>
<textarea class="content-input" placeholder="请详细描述您的问题..." value="{{postContent}}" bindinput="onPostContentInput" maxlength="500" auto-height />
</view>
<view class="form-field">
<view class="field-header">
<text class="field-label">添加图片</text>
<text class="field-hint">最多3张</text>
</view>
</block>
<view class="image-upload-area">
<!-- 加载更多 -->
<view class="load-more" wx:if="{{hasMore && posts.length > 0}}">
<view class="loading-text" wx:if="{{!loadingMore}}">
上拉加载更多
<view class="uploaded-images" wx:if="{{postImages.length > 0}}">
<block wx:for="{{postImages}}" wx:key="index">
<view class="image-item">
<image class="preview-image" src="{{item}}" mode="aspectFill"></image>
<view class="image-remove" bindtap="removeImage" data-index="{{index}}">
<text class="remove-icon">×</text>
</view>
<view class="loading-more" wx:else>
<image class="loading-icon" src="/images/loading.png" mode="aspectFit"></image>
加载中...
</view>
</block>
</view>
<!-- 没有更多了 -->
<view class="no-more" wx:if="{{!hasMore && posts.length > 0}}">
<text>没有更多了</text>
<view class="upload-btn" wx:if="{{postImages.length < 3}}" bindtap="chooseImage">
<image class="camera-icon" src="/pagesA/images/jh.png" mode="aspectFit"></image>
<text class="upload-text">添加图片</text>
</view>
</view>
</view>
<!-- 底部占位 -->
<view class="bottom-placeholder"></view>
</scroll-view>
</view>
<!-- 加载提示 -->
<view class="loading" wx:if="{{loading && posts.length === 0}}">
<image class="loading-icon" src="/images/loading.png" mode="aspectFit"></image>
加载中...
<view class="modal-footer">
<button class="cancel-btn" bindtap="hidePostModal">取消</button>
<button class="submit-btn" bindtap="submitPost" disabled="{{!postTitle || !postContent || isSubmitting}}">
{{isSubmitting ? '发布中...' : '发布'}}
</button>
</view>
<!-- 创建帖子浮动按钮 -->
<view class="fab-container" wx:if="{{!searchKeyword}}">
<view class="fab" bindtap="createPost">
<image class="fab-icon" src="/images/add.png" mode="aspectFit"></image>
</view>
</view>
<!-- 首次加载遮罩 -->
<view class="loading-overlay" wx:if="{{initialLoading && posts.length === 0}}">
<view class="loading-content">
<view class="spinner-large"></view>
<text class="loading-tip">加载中...</text>
</view>
</view>
</view>

998
pagesB/pages/forumlist/forumlist.wxss
File diff suppressed because it is too large
View File

421
pagesB/pages/onlineAsk/onlineAsk.js

@ -1,14 +1,20 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
postId: null, // 存储帖子ID
post: null,
postHf: [], // 帖子回复列表
replyContent: '',
baseUrl: baseUrl,
replyTarget: {
type: '',
username: '',
replyId: '',
type: '', // 'post'或'reply'或'comment'
id: '', // 回复或评论的ID
nickName: '',
replyIndex: null,
commentId: '',
commentIndex: null
commentIndex: null,
parentId: null // 父级ID(用于二级评论)
},
replyPlaceholder: '输入您的回复...',
isInputFocused: false,
@ -19,96 +25,89 @@ Page({
previewIndex: 0,
loading: false,
scrollToId: '',
currentUser: '当前用户',
keyboardHeight: 0
},
onLoad: function(options) {
const postId = options.id || '1';
onLoad: function (options) {
const postId = options.id
this.setData({
postId: postId
})
this.loadPostDetail(postId);
this.getforumReply(postId)
// 监听键盘高度变化
wx.onKeyboardHeightChange(res => {
if (res.height > 0) {
this.setData({ keyboardHeight: res.height });
this.setData({
keyboardHeight: res.height
});
}
});
},
// 加载帖子详情
loadPostDetail: function(postId) {
this.setData({ loading: true });
loadPostDetail: function (postId) {
this.setData({
loading: true
});
// 模拟API请求
setTimeout(() => {
const mockPost = {
id: 1,
username: '技术爱好者',
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
time: '2小时前',
title: '微信小程序如何实现图片上传和预览功能?',
content: '我正在开发一个微信小程序,需要实现图片上传功能,并且能够在上传前预览图片。请问有什么好的实现方案吗?上传的图片大小限制和格式有什么建议?',
images: [
'https://img.yzcdn.cn/vant/cat.jpeg',
'https://img.yzcdn.cn/vant/cat.jpeg'
],
tags: ['微信小程序', '图片上传', '前端开发'],
likeCount: 12,
replyCount: 5,
viewCount: 156,
liked: false,
solved: false,
replies: [
{
replyId: 'r1_1',
username: '前端开发工程师',
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
time: '1小时前',
content: '可以使用wx.chooseImage选择图片,然后使用wx.uploadFile上传到服务器。预览功能可以使用wx.previewImage实现。',
likeCount: 3,
liked: false,
comments: [
{
commentId: 'c1_1',
username: '学习者',
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
toUsername: '前端开发工程师',
time: '30分钟前',
content: '感谢分享,请问有具体的代码示例吗?'
}
]
http.forumDetails({
data: {
id: postId
},
{
replyId: 'r1_2',
username: '小程序开发者',
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
time: '45分钟前',
content: '建议将图片大小限制在2MB以内,支持JPG、PNG格式。可以使用云开发存储功能简化上传流程。',
likeCount: 2,
liked: true,
comments: []
}
]
};
success: res => {
console.log('帖子详情:', res);
const postData = res.data
const images = postData.images ? postData.images.split(',') : []
this.setData({
post: mockPost,
post: postData,
images: images,
loading: false
});
}, 500);
},
fail: err => {
console.error('加载帖子详情失败:', err);
wx.showToast({
title: '加载失败',
icon: 'none'
});
this.setData({
loading: false
});
}
})
},
// 帖子回复列表
getforumReply(postId) {
http.forumReply({
data: {
questionId: postId
},
success: res => {
console.log('回复列表:', res);
this.setData({
postHf: res.rows || []
})
},
fail: err => {
console.error('加载回复列表失败:', err);
this.setData({
postHf: []
})
}
})
},
// 滚动监听
onScroll: function(e) {
onScroll: function (e) {
// 可以在这里实现滚动相关逻辑
},
// 输入框获取焦点
onInputFocus: function(e) {
onInputFocus: function (e) {
this.setData({
isInputFocused: true,
inputTransformY: `-${e.detail.height}px`
@ -116,7 +115,7 @@ Page({
},
// 输入框失去焦点
onInputBlur: function() {
onInputBlur: function () {
this.setData({
isInputFocused: false,
inputTransformY: '0'
@ -124,69 +123,55 @@ Page({
},
// 回复输入
onReplyInput: function(e) {
onReplyInput: function (e) {
this.setData({
replyContent: e.detail.value
});
},
// 聚焦到输入框
focusReplyInput: function() {
this.setData({
replyTarget: {
type: 'post',
username: this.data.post.username
},
replyPlaceholder: `回复 ${this.data.post.username}...`,
replyContent: '',
isInputFocused: true
});
},
// 回复用户
replyToUser: function(e) {
const { type, index, replyIndex, commentIndex, username } = e.currentTarget.dataset;
const replyTarget = {
type: type,
username: username
};
// 回复一级评论
replyToUser: function (e) {
console.log(567,e);
const {
type,
index,
username
} = e.currentTarget.dataset;
if (type === 'reply') {
replyTarget.replyIndex = parseInt(index);
replyTarget.replyId = this.data.post.replies[index].replyId;
} else if (type === 'comment') {
replyTarget.replyIndex = parseInt(replyIndex);
replyTarget.commentIndex = parseInt(commentIndex);
replyTarget.commentId = this.data.post.replies[replyIndex].comments[commentIndex].commentId;
replyTarget.replyId = this.data.post.replies[replyIndex].replyId;
}
const replyItem = this.data.postHf[index];
this.setData({
replyTarget: replyTarget,
replyTarget: {
type: 'reply', // 回复一级评论
id: replyItem.id,
nickName: username,
replyIndex: parseInt(index),
parentId: null // 一级评论没有父级ID
},
replyPlaceholder: `回复 @${username}...`,
replyContent: '',
isInputFocused: true
});
// 滚动到输入框位置
// 滚动到对应回复位置
setTimeout(() => {
this.setData({
scrollToId: type === 'reply' ? `reply-${replyTarget.replyId}` : ''
scrollToId: `reply-${replyItem.id}`
});
}, 100);
},
// 清除回复目标
clearReplyTarget: function() {
clearReplyTarget: function () {
this.setData({
replyTarget: {
type: '',
username: '',
replyId: '',
id: '',
nickName: '',
replyIndex: null,
commentId: '',
commentIndex: null
commentIndex: null,
parentId: null
},
replyPlaceholder: '输入您的回复...',
replyContent: ''
@ -194,177 +179,110 @@ Page({
},
// 提交回复
submitReply: function() {
const { replyContent, replyTarget, post } = this.data;
submitReply: function () {
const {
replyContent,
replyTarget,
postId
} = this.data;
const content = replyContent.trim();
if (!content) {
wx.showToast({ title: '请输入内容', icon: 'none' });
wx.showToast({
title: '请输入内容',
icon: 'none'
});
return;
}
if (content.length > 500) {
wx.showToast({ title: '回复内容不能超过500字', icon: 'none' });
wx.showToast({
title: '回复内容不能超过500字',
icon: 'none'
});
return;
}
this.setData({ isSubmitting: true });
this.setData({
isSubmitting: true
});
// 模拟网络请求
setTimeout(() => {
if (replyTarget.type === 'post') {
// 回复帖子
this.replyToPost(content);
} else if (replyTarget.type === 'reply') {
// 回复评论
this.replyToComment(content, replyTarget);
} else if (replyTarget.type === 'comment') {
// 回复评论的回复
this.replyToCommentReply(content, replyTarget);
} else {
// 普通回复(直接回复帖子)
this.replyToPost(content);
}
// 准备提交数据
const submitData = {
questionId: postId, // 帖子ID
content: content // 回复内容
};
this.setData({ isSubmitting: false });
}, 500);
},
// 如果有回复目标,添加父级ID
if (replyTarget.type === 'reply' && replyTarget.id) {
submitData.parentId = replyTarget.id; // 回复一级评论
} else if (replyTarget.type === 'comment' && replyTarget.id) {
submitData.parentId = replyTarget.id; // 回复二级评论
}
// 如果type为'post'或为空,则表示直接回复帖子,parentId为空
// 回复帖子
replyToPost: function(content) {
const post = this.data.post;
const replyId = `r${post.id}_${Date.now()}`;
const newReply = {
replyId: replyId,
username: this.data.currentUser,
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
time: '刚刚',
content: content,
likeCount: 0,
liked: false,
comments: []
};
console.log('提交数据:', submitData);
post.replies.push(newReply);
post.replyCount += 1;
// 调用提交接口
http.commentReply({
data: submitData,
success: res => {
console.log('回复成功:', res);
// 提交成功后的处理
this.handleReplySuccess(content, replyTarget);
this.setData({
post: post,
replyContent: '',
replyTarget: {
type: '',
username: '',
replyId: '',
replyIndex: null,
commentId: '',
commentIndex: null
// 刷新回复列表
setTimeout(() => {
this.getforumReply(postId);
}, 500);
},
replyPlaceholder: '输入您的回复...',
isInputFocused: false
});
fail: err => {
console.error('回复失败:', err);
wx.showToast({
title: '回复成功',
icon: 'success',
duration: 1500
title: '回复失败,请重试',
icon: 'none',
duration: 2000
});
// 滚动到最新回复
setTimeout(() => {
this.setData({
scrollToId: `reply-${replyId}`
isSubmitting: false
});
}, 800);
},
// 回复评论
replyToComment: function(content, target) {
const post = this.data.post;
const replyIndex = target.replyIndex;
const reply = post.replies[replyIndex];
const commentId = `c${reply.replyId}_${Date.now()}`;
const newComment = {
commentId: commentId,
username: this.data.currentUser,
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
toUsername: target.username,
time: '刚刚',
content: content
};
if (!reply.comments) {
reply.comments = [];
}
reply.comments.push(newComment);
this.setData({
post: post,
replyContent: '',
replyTarget: {
type: '',
username: '',
replyId: '',
replyIndex: null,
commentId: '',
commentIndex: null
},
replyPlaceholder: '输入您的回复...',
isInputFocused: false
});
wx.showToast({
title: '回复成功',
icon: 'success',
duration: 1500
});
},
// 回复评论的回复
replyToCommentReply: function(content, target) {
const post = this.data.post;
const reply = post.replies[target.replyIndex];
const originalComment = reply.comments[target.commentIndex];
const commentId = `cc${originalComment.commentId}_${Date.now()}`;
const newComment = {
commentId: commentId,
username: this.data.currentUser,
avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
toUsername: target.username,
time: '刚刚',
content: content
};
reply.comments.push(newComment);
// 处理回复成功后的UI更新
handleReplySuccess: function (content, replyTarget) {
// 清空输入框和回复目标
this.setData({
post: post,
replyContent: '',
replyTarget: {
type: '',
username: '',
replyId: '',
id: '',
nickName: '',
replyIndex: null,
commentId: '',
commentIndex: null
commentIndex: null,
parentId: null
},
replyPlaceholder: '输入您的回复...',
isInputFocused: false
isInputFocused: false,
isSubmitting: false
});
wx.showToast({
title: '回复成功',
icon: 'success',
duration: 1500
// 如果是直接回复帖子,滚动到底部
if (!replyTarget.type || replyTarget.type === 'post') {
setTimeout(() => {
wx.pageScrollTo({
scrollTop: 9999,
duration: 300
});
}, 300);
}
},
// 图片预览
previewImage: function(e) {
previewImage: function (e) {
const imgIndex = e.currentTarget.dataset.imgIndex;
const images = this.data.post.images;
const images = this.data.images;
this.setData({
showPreview: true,
@ -374,33 +292,36 @@ Page({
},
// 图片预览滑动
onSwiperChange: function(e) {
onSwiperChange: function (e) {
this.setData({
previewIndex: e.detail.current
});
},
// 隐藏预览
hidePreview: function() {
this.setData({ showPreview: false });
hidePreview: function () {
this.setData({
showPreview: false
});
},
// 下拉刷新
onPullDownRefresh: function() {
if (this.data.post) {
this.loadPostDetail(this.data.post.id);
onPullDownRefresh: function () {
if (this.data.postId) {
this.loadPostDetail(this.data.postId);
this.getforumReply(this.data.postId);
}
wx.stopPullDownRefresh();
},
// 页面上拉触底
onReachBottom: function() {
onReachBottom: function () {
// 这里可以实现加载更多回复的逻辑
console.log('加载更多回复');
},
// 页面卸载
onUnload: function() {
onUnload: function () {
// 移除键盘高度监听
wx.offKeyboardHeightChange();
}

66
pagesB/pages/onlineAsk/onlineAsk.wxml

@ -1,5 +1,4 @@
<view class="forum-page">
<!-- 帖子详情 -->
<scroll-view
class="post-detail-container"
@ -14,14 +13,11 @@
<!-- 帖子头部 -->
<view class="post-header">
<view class="user-info">
<image class="avatar" src="{{post.avatar}}" mode="aspectFill"></image>
<image class="avatar" src="{{baseUrl+post.avatar}}" mode="aspectFill"></image>
<view class="user-detail">
<view class="username">{{post.username}}</view>
<view class="post-time">{{post.time}}</view>
</view>
<view class="username">{{post.nickName}}</view>
<view class="post-time">{{post.createdAt}}</view>
</view>
<view class="post-status" wx:if="{{post.solved}}">
<text class="solved-badge">已解决</text>
</view>
</view>
@ -33,10 +29,10 @@
<!-- 帖子图片 -->
<view class="post-images" wx:if="{{post.images && post.images.length > 0}}">
<view class="images-container">
<block wx:for="{{post.images}}" wx:for-item="image" wx:for-index="imgIndex" wx:key="index">
<block wx:for="{{images}}" wx:for-item="image" wx:for-index="imgIndex" wx:key="index">
<image
class="post-image"
src="{{image}}"
src="{{baseUrl+image}}"
mode="aspectFill"
data-img-index="{{imgIndex}}"
bindtap="previewImage"
@ -44,8 +40,6 @@
</block>
</view>
</view>
</view>
</view>
@ -54,56 +48,43 @@
<view class="replies-section" id="replies-section">
<view class="section-title">
<text class="title-text">全部回复</text>
<text class="reply-count">{{post.replyCount}}条</text>
<text class="reply-count">{{postHf.length}}条</text>
</view>
<view class="reply-list" wx:if="{{post.replies && post.replies.length > 0}}">
<block wx:for="{{post.replies}}" wx:key="replyId" wx:for-index="replyIndex">
<view class="reply-item" id="reply-{{item.replyId}}">
<view class="reply-list" wx:if="{{postHf.length > 0}}">
<block wx:for="{{postHf}}" wx:key="id" wx:for-index="replyIndex">
<view class="reply-item" id="reply-{{item.id}}">
<view class="reply-user">
<image class="reply-avatar" src="{{item.avatar}}" mode="aspectFill"></image>
<image class="reply-avatar" src="{{baseUrl+item.avatar}}" mode="aspectFill"></image>
<view class="reply-user-info">
<view class="reply-username">{{item.username}}</view>
<view class="reply-time">{{item.time}}</view>
<view class="reply-username">{{item.nickName}}</view>
<view class="reply-time">{{item.createdAt}}</view>
</view>
</view>
<view class="reply-content">{{item.content}}</view>
<!-- 回复操作 -->
<view class="reply-actions">
<view class="reply-action" bindtap="replyToUser" data-type="reply" data-index="{{replyIndex}}" data-username="{{item.username}}">
<view class="reply-action" bindtap="replyToUser" data-type="reply" data-index="{{replyIndex}}" data-username="{{item.nickName}}">
<image class="reply-action-icon" src="/pagesB/images/hf.png" mode="aspectFit"></image>
<text class="reply-action-text">回复</text>
</view>
</view>
<!-- 评论列表 -->
<view class="comment-list" wx:if="{{item.comments && item.comments.length > 0}}">
<block wx:for="{{item.comments}}" wx:key="commentId">
<!-- 二级评论列表 -->
<view class="comment-list" wx:if="{{item.children.length > 0}}">
<block wx:for="{{item.children}}" wx:key="id" wx:for-index="commentIndex">
<view class="comment-item">
<view class="comment-user">
<image class="comment-avatar" src="{{item.avatar}}" mode="aspectFill"></image>
<image class="comment-avatar" src="{{baseUrl+item.avatar}}" mode="aspectFill"></image>
<view class="comment-user-info">
<view class="comment-username">{{item.username}}</view>
<view class="comment-time">{{item.time}}</view>
<view class="comment-username">{{item.nickName}}</view>
<view class="comment-time">{{item.createdAt}}</view>
</view>
</view>
<view class="comment-content">
<text class="comment-to" wx:if="{{item.toUsername}}">@{{item.toUsername}} </text>
{{item.content}}
</view>
<!-- 评论操作 -->
<view class="comment-actions">
<view class="comment-action" bindtap="replyToUser"
data-type="comment"
data-reply-index="{{replyIndex}}"
data-comment-index="{{index}}"
data-username="{{item.username}}">
<text>回复</text>
</view>
</view>
</view>
</block>
</view>
@ -141,13 +122,13 @@
bindtap="submitReply"
disabled="{{!replyContent}}"
>
{{isSubmitting ? '发送中' : '发送'}}
{{isSubmitting ? '发送中...' : '发送'}}
</button>
</view>
<!-- 回复对象显示 -->
<view class="reply-target" wx:if="{{replyTarget.username}}">
<text class="target-text">回复 {{replyTarget.username}}</text>
<view class="reply-target" wx:if="{{replyTarget.nickName}}">
<text class="target-text">回复 {{replyTarget.nickName}}</text>
<text class="clear-target" bindtap="clearReplyTarget">×</text>
</view>
</view>
@ -157,7 +138,7 @@
<swiper class="preview-swiper" current="{{previewIndex}}" bindchange="onSwiperChange">
<block wx:for="{{previewImages}}" wx:key="index">
<swiper-item>
<image class="preview-image" src="{{item}}" mode="aspectFit"></image>
<image class="preview-image" src="{{baseUrl+item}}" mode="aspectFit"></image>
</swiper-item>
</block>
</swiper>
@ -166,7 +147,6 @@
<!-- 加载提示 -->
<view class="loading" wx:if="{{loading}}">
<image class="loading-icon" src="/images/loading.png" mode="aspectFit"></image>
加载中...
</view>
</view>

30
pagesB/pages/onlineAsk/onlineAsk.wxss

@ -54,14 +54,6 @@
color: #999;
}
.post-status .solved-badge {
background-color: #07c160;
color: white;
font-size: 24rpx;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
/* 帖子内容 */
.post-content {
margin-bottom: 30rpx;
@ -88,14 +80,14 @@
}
.images-container {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
width: 100%;
display: grid;
grid-template-columns: repeat(3,1fr);
}
.post-image {
width: 220rpx;
height: 220rpx;
width: 200rpx;
height: 200rpx;
border-radius: 12rpx;
flex-shrink: 0;
}
@ -429,18 +421,6 @@
font-size: 28rpx;
}
.loading-icon {
width: 60rpx;
height: 60rpx;
margin-bottom: 20rpx;
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 移除按钮边框 */
button::after {
border: none;

44
utils/api.js

@ -156,6 +156,47 @@ function videoZd(params) {
http('/system/dict/data/list', 'get', params)
}
//在线问答列表
function forumList(params) {
http('/system/questions/list', 'get', params)
}
//在线问答详情
function forumDetails(params) {
http('/system/questions/'+params.data.id, 'get', params)
}
//在线问答新增帖子
function forumAdd(params) {
http('/system/questions', 'post', params)
}
//在线问答详情回复
function forumReply(params) {
http('/system/answers/list', 'get', params)
}
//新增回复
function commentReply(params) {
http('/system/answers', 'post', params)
}
// 经验分享列表
function experience(params) {
http('/vet/article/list', 'get', params)
}
// 经验分享详情
function experienceDetails(params) {
http('/vet/article/' + params.data.id, 'get', params)
}
// 经验分享分类字典
function experiencezd(params) {
http('/vet/article/options', 'get', params)
}
@ -163,5 +204,6 @@ export default { // 暴露接口
login,carousel,disaster,pharmacy,guidance,getPhoneNumber,inquiry,policyeDetails,
search,trend,feed,sales,wzd,wzdxq,wzdAdd,expertsList,recommendationList,policyeZd,
recommendationXq,queryList,tipList,article,articleDetails,articleZd,policyelucidation,
areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails
areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails,forumList,forumAdd,forumDetails,
forumReply,commentReply,experience,experiencezd,experienceDetails
}

3
utils/baseUrl.js

@ -1,4 +1,5 @@
// var baseUrl = 'https://wx.chenhaitech.com/ymtx-prod-api'
var baseUrl = 'http://192.168.101.109:8080'
// var baseUrl = 'http://192.168.101.109:8080'
var baseUrl = 'http://192.168.101.105:8082'
// var baseUrl = 'http://192.168.101.111:8081'
module.exports = baseUrl
Loading…
Cancel
Save