27 changed files with 3672 additions and 1222 deletions
-
7app.json
-
55pages/home/home.js
-
66pages/home/home.wxml
-
83pages/home/home.wxss
-
7pages/personal/personal.js
-
2pages/personal/personal.wxml
-
317pagesA/pages/attestation/attestation.js
-
4pagesA/pages/attestation/attestation.json
-
185pagesA/pages/attestation/attestation.wxml
-
546pagesA/pages/attestation/attestation.wxss
-
34pagesB/pages/experienceDetails/experienceDetails.js
-
4pagesB/pages/experienceDetails/experienceDetails.json
-
46pagesB/pages/experienceDetails/experienceDetails.wxml
-
146pagesB/pages/experienceDetails/experienceDetails.wxss
-
206pagesB/pages/experienceList/experienceList.js
-
4pagesB/pages/experienceList/experienceList.json
-
80pagesB/pages/experienceList/experienceList.wxml
-
332pagesB/pages/experienceList/experienceList.wxss
-
641pagesB/pages/forumlist/forumlist.js
-
1pagesB/pages/forumlist/forumlist.json
-
330pagesB/pages/forumlist/forumlist.wxml
-
1200pagesB/pages/forumlist/forumlist.wxss
-
455pagesB/pages/onlineAsk/onlineAsk.js
-
66pagesB/pages/onlineAsk/onlineAsk.wxml
-
30pagesB/pages/onlineAsk/onlineAsk.wxss
-
44utils/api.js
-
3utils/baseUrl.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' |
|||
}); |
|||
} |
|||
}); |
|||
@ -0,0 +1,4 @@ |
|||
{ |
|||
"navigationBarTitleText":"实名认证", |
|||
"usingComponents": {} |
|||
} |
|||
@ -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> |
|||
@ -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%; |
|||
} |
|||
} |
|||
@ -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 |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
|
|||
}) |
|||
@ -0,0 +1,4 @@ |
|||
{ |
|||
"navigationBarTitleText": "分享详情", |
|||
"usingComponents": {} |
|||
} |
|||
@ -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> |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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) |
|||
} |
|||
} |
|||
}) |
|||
@ -0,0 +1,4 @@ |
|||
{ |
|||
"navigationBarTitleText": "经验分享", |
|||
"usingComponents": {} |
|||
} |
|||
@ -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> |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -1,3 +1,4 @@ |
|||
{ |
|||
"navigationBarTitleText": "问答论坛", |
|||
"usingComponents": {} |
|||
} |
|||
@ -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> |
|||
</scroll-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> |
|||
</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> |
|||
<view class="reply-count"> |
|||
<view class="reply-number">{{item.replyCount}}</view> |
|||
<view class="reply-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> |
|||
<!-- 时间 --> |
|||
<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> |
|||
|
|||
<!-- 右侧内容区 --> |
|||
<view class="post-content-main"> |
|||
|
|||
<!-- 帖子标题和状态 --> |
|||
<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> |
|||
<view class="status-badge" wx:if="{{item.hot}}"> |
|||
<text class="hot-badge">热门</text> |
|||
</view> |
|||
|
|||
<!-- 内容摘要 --> |
|||
<view class="post-summary"> |
|||
{{item.content}} |
|||
</view> |
|||
|
|||
<!-- 帖子内容摘要 --> |
|||
<view class="post-summary">{{item.summary}}</view> |
|||
|
|||
<!-- 帖子元信息 --> |
|||
<view class="post-meta"> |
|||
|
|||
<!-- 用户信息 --> |
|||
<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> |
|||
|
|||
<!-- 标签 --> |
|||
<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> |
|||
|
|||
<!-- 图片预览 --> |
|||
<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> |
|||
<text class="more-tags" wx:if="{{item.tags.length > 2}}">+{{item.tags.length - 2}}</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="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> |
|||
</block> |
|||
|
|||
|
|||
<!-- 加载更多 --> |
|||
<view class="load-more" wx:if="{{hasMore && posts.length > 0}}"> |
|||
<view class="loading-text" wx:if="{{!loadingMore}}"> |
|||
上拉加载更多 |
|||
<view class="loading-spinner" wx:if="{{!loadingMore}}"> |
|||
<text class="loading-text">上拉加载更多</text> |
|||
</view> |
|||
<view class="loading-more" wx:else> |
|||
<image class="loading-icon" src="/images/loading.png" mode="aspectFit"></image> |
|||
加载中... |
|||
<view class="loading-spinner" wx:else> |
|||
<view class="spinner"></view> |
|||
<text class="loading-text">加载中...</text> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
<!-- 没有更多了 --> |
|||
<view class="no-more" wx:if="{{!hasMore && posts.length > 0}}"> |
|||
<text>没有更多了</text> |
|||
<view class="no-more-line"></view> |
|||
<text class="no-more-text">已经到底了</text> |
|||
<view class="no-more-line"></view> |
|||
</view> |
|||
|
|||
|
|||
</view> |
|||
|
|||
<!-- 底部占位 --> |
|||
<view class="bottom-placeholder"></view> |
|||
|
|||
|
|||
</scroll-view> |
|||
|
|||
<!-- 加载提示 --> |
|||
<view class="loading" wx:if="{{loading && posts.length === 0}}"> |
|||
<image class="loading-icon" src="/images/loading.png" mode="aspectFit"></image> |
|||
加载中... |
|||
</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 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="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> |
|||
<view class="image-upload-area"> |
|||
|
|||
<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> |
|||
</block> |
|||
</view> |
|||
|
|||
<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> |
|||
|
|||
<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> |
|||
</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> |
|||
1200
pagesB/pages/forumlist/forumlist.wxss
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue