优化输入框和表单样式,确保在小程序和管理端开发中使用容器包裹输入框以避免布局问题。更新个人资料页,增加VIP用户的字段展示与编辑逻辑,确保用户体验一致性。调整相关文档以反映最新开发进展,提升功能可用性与用户体验。

This commit is contained in:
Alex-larget
2026-02-28 17:26:03 +08:00
parent 41e5b1258b
commit 8e2ea9b7c1
14 changed files with 195 additions and 114 deletions

View File

@@ -212,42 +212,48 @@
<view class="resource-form">
<view class="form-item">
<text class="form-label">我能帮到你什么 <text class="required">*</text></text>
<input class="form-input-new" placeholder="例如:私域运营、品牌策划、流量资源..." value="{{canHelp}}" bindinput="onCanHelpInput" maxlength="100"/>
<view class="form-input-wrap">
<input class="form-input-inner" type="text" placeholder="例如:私域运营、品牌策划、流量资源..." value="{{canHelp}}" bindinput="onCanHelpInput" maxlength="100"/>
</view>
</view>
<view class="form-item">
<text class="form-label">我需要什么帮助 <text class="required">*</text></text>
<input class="form-input-new" placeholder="例如:技术支持、资金、人脉..." value="{{needHelp}}" bindinput="onNeedHelpInput" maxlength="100"/>
<view class="form-input-wrap">
<input class="form-input-inner" placeholder="例如:技术支持、资金、人脉..." value="{{needHelp}}" bindinput="onNeedHelpInput" maxlength="100"/>
</view>
</view>
</view>
</block>
<!-- 联系方式输入区域 -->
<!-- 联系方式输入区域Skill §6view 包裹、padding 写 view、input width 100% -->
<view class="input-area">
<view class="input-wrapper">
<text class="input-prefix">{{contactType === 'phone' ? '+86' : '@'}}</text>
<input
wx:if="{{contactType === 'phone'}}"
type="number"
class="input-field"
placeholder="请输入11位手机号"
placeholder-class="input-placeholder-new"
value="{{phoneNumber}}"
bindinput="onPhoneInput"
maxlength="11"
disabled="{{isJoining}}"
focus="{{contactType === 'phone'}}"
/>
<input
wx:else
type="text"
class="input-field"
placeholder="请输入微信号"
placeholder-class="input-placeholder-new"
value="{{wechatId}}"
bindinput="onWechatInput"
disabled="{{isJoining}}"
focus="{{contactType === 'wechat'}}"
/>
<view class="input-field-wrap">
<input
wx:if="{{contactType === 'phone'}}"
type="number"
class="input-field-inner"
placeholder="请输入11位手机号"
placeholder-class="input-placeholder-new"
value="{{phoneNumber}}"
bindinput="onPhoneInput"
maxlength="11"
disabled="{{isJoining}}"
focus="{{contactType === 'phone'}}"
/>
<input
wx:else
type="text"
class="input-field-inner"
placeholder="请输入微信号"
placeholder-class="input-placeholder-new"
value="{{wechatId}}"
bindinput="onWechatInput"
disabled="{{isJoining}}"
focus="{{contactType === 'wechat'}}"
/>
</view>
</view>
<text class="error-msg" wx:if="{{joinError}}">{{joinError}}</text>
</view>

View File

@@ -798,17 +798,24 @@
}
.input-prefix {
padding: 0 24rpx;
padding: 0 28rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
border-right: 1rpx solid rgba(255, 255, 255, 0.1);
}
.input-field {
/* Skill §6view 包裹、padding 写 view、input width 100% */
.input-field-wrap {
flex: 1;
padding: 28rpx 24rpx;
padding: 28rpx 32rpx;
box-sizing: border-box;
}
.input-field-inner {
width: 100%;
font-size: 32rpx;
color: #ffffff;
background: transparent;
box-sizing: border-box;
}
.input-placeholder-new {
@@ -1176,12 +1183,13 @@
border: 1rpx solid rgba(255, 255, 255, 0.2);
}
/* 资源对接表单 */
/* 资源对接表单Skill §6view 包裹、padding 写 view、input width 100% */
.resource-form {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-bottom: 24rpx;
padding: 0 40rpx;
}
.resource-form .form-item {
display: flex;
@@ -1192,13 +1200,18 @@
font-size: 26rpx;
color: rgba(255,255,255,0.6);
}
.resource-form .form-input-new {
.resource-form .form-input-wrap {
background: #1c1c1e;
border: 2rpx solid rgba(0,206,209,0.3);
border-radius: 16rpx;
padding: 20rpx;
padding: 24rpx 32rpx;
}
.resource-form .form-input-inner {
width: 100%;
font-size: 28rpx;
color: #fff;
background: transparent;
box-sizing: border-box;
}
/* 手机/微信号弹窗 - comprehensive_profile_editor_v1_2 */

View File

@@ -89,13 +89,13 @@
/* 阅读统计 */
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24rpx; }
.stat-box {
background: #252525; border-radius: 20rpx; padding: 32rpx;
background: #252525; border-radius: 20rpx; padding: 20rpx;
display: flex; flex-direction: column; align-items: center; justify-content: center;
aspect-ratio: 4/3;
aspect-ratio: 2/1;
}
.stat-icon { font-size: 48rpx; margin-bottom: 16rpx; color: #4FD1C5; }
.stat-num { font-size: 40rpx; font-weight: bold; color: #fff; }
.stat-label { font-size: 20rpx; color: #6B7280; margin-top: 8rpx; }
.stat-icon { font-size: 40rpx; margin-bottom: 8rpx; color: #4FD1C5; }
.stat-num { font-size: 36rpx; font-weight: bold; color: #fff; }
.stat-label { font-size: 20rpx; color: #6B7280; margin-top: 4rpx; }
/* 最近阅读 */
.recent-list { display: flex; flex-direction: column; gap: 24rpx; }

View File

@@ -1,6 +1,12 @@
/**
* Soul创业派对 - 资料编辑完整版comprehensive_profile_editor_v1_1
* 温馨提示、头像、基本信息、核心联系方式、个人故事、互助需求、项目介绍
*
* 接口约定(/api/miniprogram/user/profile
* - GET ?userId= 返回 data: { avatar, nickname, mbti, region, industry, businessScale, position, skills, phone, wechatId, ... },空值统一为 ""
* - POST body普通用户提交基础字段VIP 提交全部字段(含 skills、个人故事、互助需求、项目介绍
*
* 表单展示:普通用户仅展示 温馨提示、头像、昵称、MBTI、地区、行业、业务体量、职位、核心联系方式VIP 展示全部
*/
const app = getApp()
@@ -9,6 +15,7 @@ const MBTI_OPTIONS = ['INTJ', 'INFP', 'INTP', 'ENTP', 'ENFP', 'ENTJ', 'ENFJ', 'I
Page({
data: {
statusBarHeight: 44,
isVip: false,
avatar: '',
nickname: '',
mbti: '',
@@ -46,28 +53,35 @@ Page({
return
}
try {
const res = await app.request({ url: `/api/miniprogram/user/profile?userId=${userInfo.id}`, silent: true })
const userId = userInfo.id
const [profileRes, vipRes] = await Promise.all([
app.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true }),
app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true }),
])
this.setData({ isVip: vipRes?.data?.isVip || false })
const res = profileRes
if (res?.success && res.data) {
const d = res.data
const mbtiIndex = MBTI_OPTIONS.indexOf(d.mbti || '') >= 0 ? MBTI_OPTIONS.indexOf(d.mbti) : 0
const v = (k) => (d[k] != null && d[k] !== '') ? String(d[k]) : ''
const mbtiIndex = MBTI_OPTIONS.indexOf(v('mbti')) >= 0 ? MBTI_OPTIONS.indexOf(v('mbti')) : 0
this.setData({
avatar: d.avatar || '',
nickname: d.nickname || '',
mbti: d.mbti || '',
avatar: v('avatar'),
nickname: v('nickname'),
mbti: v('mbti'),
mbtiIndex,
region: d.region || '',
industry: d.industry || '',
businessScale: d.businessScale || '',
position: d.position || '',
skills: d.skills || '',
phone: d.phone || '',
wechatId: d.wechatId || wx.getStorageSync('user_wechat') || '',
storyBestMonth: d.storyBestMonth || '',
storyAchievement: d.storyAchievement || '',
storyTurning: d.storyTurning || '',
helpOffer: d.helpOffer || '',
helpNeed: d.helpNeed || '',
projectIntro: d.projectIntro || '',
region: v('region'),
industry: v('industry'),
businessScale: v('businessScale'),
position: v('position'),
skills: v('skills'),
phone: v('phone'),
wechatId: v('wechatId') || wx.getStorageSync('user_wechat') || '',
storyBestMonth: v('storyBestMonth'),
storyAchievement: v('storyAchievement'),
storyTurning: v('storyTurning'),
helpOffer: v('helpOffer'),
helpNeed: v('helpNeed'),
projectIntro: v('projectIntro'),
loading: false,
})
} else {
@@ -154,27 +168,35 @@ Page({
}
this.setData({ saving: true })
try {
const s = (v) => (v || '').toString().trim()
const isVip = this.data.isVip
const payload = {
userId,
nickname: this.data.nickname.trim() || undefined,
mbti: this.data.mbti || undefined,
region: this.data.region.trim() || undefined,
industry: this.data.industry.trim() || undefined,
businessScale: this.data.businessScale.trim() || undefined,
position: this.data.position.trim() || undefined,
skills: this.data.skills.trim() || undefined,
phone: this.data.phone.trim() || undefined,
wechatId: this.data.wechatId.trim() || undefined,
storyBestMonth: this.data.storyBestMonth.trim() || undefined,
storyAchievement: this.data.storyAchievement.trim() || undefined,
storyTurning: this.data.storyTurning.trim() || undefined,
helpOffer: this.data.helpOffer.trim() || undefined,
helpNeed: this.data.helpNeed.trim() || undefined,
projectIntro: this.data.projectIntro.trim() || undefined,
avatar: s(this.data.avatar),
nickname: s(this.data.nickname),
mbti: s(this.data.mbti),
region: s(this.data.region),
industry: s(this.data.industry),
businessScale: s(this.data.businessScale),
position: s(this.data.position),
phone: s(this.data.phone),
wechatId: s(this.data.wechatId),
}
const showHelp = isVip || this.data.helpOffer || this.data.helpNeed
if (isVip) {
payload.skills = s(this.data.skills)
payload.storyBestMonth = s(this.data.storyBestMonth)
payload.storyAchievement = s(this.data.storyAchievement)
payload.storyTurning = s(this.data.storyTurning)
payload.projectIntro = s(this.data.projectIntro)
}
if (showHelp) {
payload.helpOffer = s(this.data.helpOffer)
payload.helpNeed = s(this.data.helpNeed)
}
if (payload.wechatId) wx.setStorageSync('user_wechat', payload.wechatId)
if (payload.phone) wx.setStorageSync('user_phone', payload.phone)
const hasUpdate = Object.keys(payload).some(k => k !== 'userId' && payload[k] != null)
const hasUpdate = Object.keys(payload).some(k => k !== 'userId' && payload[k] !== '')
if (!hasUpdate) {
wx.showToast({ title: '无变更', icon: 'none' })
this.setData({ saving: false })
@@ -186,8 +208,9 @@ Page({
data: payload,
})
wx.showToast({ title: '保存成功', icon: 'success' })
if (app.globalData.userInfo && payload.nickname) {
app.globalData.userInfo.nickname = payload.nickname
if (app.globalData.userInfo) {
if (payload.nickname) app.globalData.userInfo.nickname = payload.nickname
if (payload.avatar) app.globalData.userInfo.avatar = payload.avatar
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
setTimeout(() => wx.navigateBack(), 800)

View File

@@ -58,7 +58,7 @@
<text class="form-label">职位</text>
<view class="form-input-wrap"><input class="form-input-inner" placeholder="例如:创始人/联合创始人" value="{{position}}" bindinput="onPositionInput"/></view>
</view>
<view class="form-row">
<view class="form-row" wx:if="{{isVip}}">
<text class="form-label">我擅长</text>
<view class="form-input-wrap"><input class="form-input-inner" placeholder="例如短视频制作、IP打造、私域运营" value="{{skills}}" bindinput="onSkillsInput"/></view>
</view>
@@ -80,8 +80,8 @@
</view>
</view>
<!-- 个人故事 -->
<view class="section">
<!-- 个人故事(仅 VIP 展示) -->
<view class="section" wx:if="{{isVip}}">
<view class="section-title">
<text class="section-icon">💡</text>
<text>个人故事</text>
@@ -100,8 +100,8 @@
</view>
</view>
<!-- 互助需求 -->
<view class="section">
<!-- 互助需求VIP 或 资源对接已填写时展示) -->
<view class="section" wx:if="{{isVip || helpOffer || helpNeed}}">
<view class="section-title">
<text class="section-icon">🤝</text>
<text>互助需求</text>
@@ -116,8 +116,8 @@
</view>
</view>
<!-- 项目介绍 -->
<view class="section">
<!-- 项目介绍(仅 VIP 展示) -->
<view class="section" wx:if="{{isVip}}">
<view class="section-title">
<text class="section-icon">🚀</text>
<text>项目介绍</text>

View File

@@ -61,13 +61,6 @@ Page({
}
},
goToRead(e) {
const id = e.currentTarget.dataset.id
const mid = e.currentTarget.dataset.mid || app.getSectionMid(id)
const q = mid ? `mid=${mid}` : `id=${id}`
wx.navigateTo({ url: `/pages/read/read?${q}` })
},
goBack() { wx.navigateBack() },
onShareAppMessage() {

View File

@@ -15,7 +15,7 @@
</view>
<view class="orders-list" wx:elif="{{orders.length > 0}}">
<view class="order-item" wx:for="{{orders}}" wx:key="id" bindtap="goToRead" data-id="{{item.sectionId}}" data-mid="{{item.sectionMid}}">
<view class="order-item" wx:for="{{orders}}" wx:key="id">
<view class="order-info">
<text class="order-title">{{item.title}}</text>
<text class="order-time">{{item.createTime}}</text>

View File

@@ -9,7 +9,6 @@
@keyframes skeleton { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.orders-list { display: flex; flex-direction: column; gap: 16rpx; }
.order-item { display: flex; align-items: center; justify-content: space-between; padding: 24rpx; background: #1c1c1e; border-radius: 24rpx; }
.order-item:active { background: #2c2c2e; }
.order-info { flex: 1; }
.order-title { font-size: 28rpx; color: #fff; display: block; margin-bottom: 8rpx; }
.order-time { font-size: 22rpx; color: rgba(255,255,255,0.4); }