优化输入框和表单样式,确保在小程序和管理端开发中使用容器包裹输入框以避免布局问题。更新个人资料页,增加VIP用户的字段展示与编辑逻辑,确保用户体验一致性。调整相关文档以反映最新开发进展,提升功能可用性与用户体验。
This commit is contained in:
@@ -63,7 +63,7 @@ description: Soul 创业派对管理端开发规范。在 soul-admin/ 下编辑
|
||||
|
||||
### 4.1 输入框 padding(前端通用)
|
||||
|
||||
设置 input 的 padding、背景、边框时,用 div 包裹 input;padding 写在容器上,input 仅做文字样式。可避免光标截断、布局异常。React:`<div className="form-input"><input ... /></div>`。
|
||||
**口诀**:外边包 div/view,内部 input width 100%。设置 input 的 padding、背景、边框时,用 div 包裹 input;padding 写在容器上,input 仅做文字样式(`width: 100%`)。禁止在 input 自身上设 padding,可避免光标截断、布局异常。React:`<div className="form-input"><input className="form-input-inner" ... /></div>`。
|
||||
|
||||
### 4.2 表单弹窗与「可选择+可手动填写」(吸收 SetVipModal 经验)
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@ description: Soul 创业派对小程序开发规范。在 miniprogram/ 下编辑
|
||||
|
||||
## 6. 表单与输入框
|
||||
|
||||
- **input / textarea padding**:给 `<input>` 或 `<textarea>` 设置 padding 时,**必须**用 `<view>` 包裹,padding 写在 view 上;不在 input/textarea 自身上设 padding。可避免光标截断、布局异常等原生组件表现问题。
|
||||
- **input / textarea 边距**:**必须**用 `<view>` 包裹,padding/边距一律写在 view 上;内部 `<input>` 仅设 `width: 100%` 和字体样式。禁止在 input/textarea 自身上设 padding,否则会光标截断、布局异常。
|
||||
- **口诀**:外边包 view,内部 input width 100%。
|
||||
- **正确写法**:
|
||||
- input:`<view class="form-input"><input class="form-input-inner" ... /></view>`,`.form-input { padding: 16rpx 24rpx; background: #1F2937; }`,`.form-input-inner { width: 100%; font-size: 28rpx; background: transparent; }`
|
||||
- textarea:`<view class="form-textarea-wrap"><textarea class="form-textarea-inner" ... /></view>`,`.form-textarea-wrap { padding: 16rpx 24rpx; background: #1F2937; }`,`.form-textarea-inner { width: 100%; font-size: 28rpx; background: transparent; min-height: 160rpx; }`
|
||||
|
||||
@@ -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 §6:view 包裹、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>
|
||||
|
||||
@@ -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 §6:view 包裹、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 §6:view 包裹、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 */
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -24,12 +24,19 @@
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "个人资料",
|
||||
"pathName": "pages/profile-show/profile-show",
|
||||
"name": "pages/profile-edit/profile-edit",
|
||||
"pathName": "pages/profile-edit/profile-edit",
|
||||
"query": "",
|
||||
"scene": null,
|
||||
"launchMode": "default"
|
||||
},
|
||||
{
|
||||
"name": "个人资料",
|
||||
"pathName": "pages/profile-show/profile-show",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "pages/mentors/mentors",
|
||||
"pathName": "pages/mentors/mentors",
|
||||
|
||||
@@ -13,6 +13,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"soul-api/internal/database"
|
||||
"soul-api/internal/model"
|
||||
)
|
||||
|
||||
const ckbAPIKey = "fyngh-ecy9h-qkdae-epwd5-rz6kd"
|
||||
@@ -140,6 +143,25 @@ func CKBJoin(c *gin.Context) {
|
||||
}
|
||||
_ = json.Unmarshal(b, &result)
|
||||
if result.Code == 200 {
|
||||
// 资源对接:同步更新用户资料中的 help_offer、help_need、phone、wechat_id
|
||||
if body.Type == "investor" && body.UserID != "" {
|
||||
updates := map[string]interface{}{}
|
||||
if body.CanHelp != "" {
|
||||
updates["help_offer"] = body.CanHelp
|
||||
}
|
||||
if body.NeedHelp != "" {
|
||||
updates["help_need"] = body.NeedHelp
|
||||
}
|
||||
if body.Phone != "" {
|
||||
updates["phone"] = body.Phone
|
||||
}
|
||||
if body.Wechat != "" {
|
||||
updates["wechat_id"] = body.Wechat
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
database.DB().Model(&model.User{}).Where("id = ?", body.UserID).Updates(updates)
|
||||
}
|
||||
}
|
||||
msg := "成功加入" + ckbSourceMap[body.Type]
|
||||
if result.Message == "已存在" {
|
||||
msg = "您已加入,我们会尽快联系您"
|
||||
|
||||
@@ -196,37 +196,35 @@ func UserProfileGet(c *gin.Context) {
|
||||
}
|
||||
db := database.DB()
|
||||
var user model.User
|
||||
q := db.Select("id", "open_id", "nickname", "avatar", "phone", "wechat_id", "referral_code",
|
||||
"has_full_book", "earnings", "pending_earnings", "referral_count", "created_at",
|
||||
"mbti", "region", "industry", "position", "business_scale", "skills",
|
||||
"story_best_month", "story_achievement", "story_turning", "help_offer", "help_need", "project_intro")
|
||||
if userId != "" {
|
||||
db = db.Where("id = ?", userId)
|
||||
q = q.Where("id = ?", userId)
|
||||
} else {
|
||||
db = db.Where("open_id = ?", openId)
|
||||
q = q.Where("open_id = ?", openId)
|
||||
}
|
||||
if err := db.First(&user).Error; err != nil {
|
||||
if err := q.First(&user).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "用户不存在"})
|
||||
return
|
||||
}
|
||||
profileComplete := (user.Phone != nil && *user.Phone != "") || (user.WechatID != nil && *user.WechatID != "")
|
||||
hasAvatar := user.Avatar != nil && *user.Avatar != "" && len(*user.Avatar) > 0
|
||||
str := func(p *string) interface{} { if p != nil { return *p }; return "" }
|
||||
resp := gin.H{
|
||||
"id": user.ID, "openId": user.OpenID, "nickname": user.Nickname, "avatar": user.Avatar,
|
||||
"phone": user.Phone, "wechatId": user.WechatID, "referralCode": user.ReferralCode,
|
||||
"id": user.ID, "openId": user.OpenID, "nickname": str(user.Nickname), "avatar": str(user.Avatar),
|
||||
"phone": str(user.Phone), "wechatId": str(user.WechatID), "referralCode": user.ReferralCode,
|
||||
"hasFullBook": user.HasFullBook, "earnings": user.Earnings, "pendingEarnings": user.PendingEarnings,
|
||||
"referralCount": user.ReferralCount, "profileComplete": profileComplete, "hasAvatar": hasAvatar,
|
||||
"createdAt": user.CreatedAt,
|
||||
// P3 资料扩展:统一返回所有表单字段,空值用 "" 便于前端回显
|
||||
"mbti": str(user.Mbti), "region": str(user.Region), "industry": str(user.Industry),
|
||||
"position": str(user.Position), "businessScale": str(user.BusinessScale), "skills": str(user.Skills),
|
||||
"storyBestMonth": str(user.StoryBestMonth), "storyAchievement": str(user.StoryAchievement),
|
||||
"storyTurning": str(user.StoryTurning), "helpOffer": str(user.HelpOffer), "helpNeed": str(user.HelpNeed),
|
||||
"projectIntro": str(user.ProjectIntro),
|
||||
}
|
||||
// P3 资料扩展
|
||||
if user.Mbti != nil { resp["mbti"] = user.Mbti }
|
||||
if user.Region != nil { resp["region"] = user.Region }
|
||||
if user.Industry != nil { resp["industry"] = user.Industry }
|
||||
if user.Position != nil { resp["position"] = user.Position }
|
||||
if user.BusinessScale != nil { resp["businessScale"] = user.BusinessScale }
|
||||
if user.Skills != nil { resp["skills"] = user.Skills }
|
||||
if user.StoryBestMonth != nil { resp["storyBestMonth"] = user.StoryBestMonth }
|
||||
if user.StoryAchievement != nil { resp["storyAchievement"] = user.StoryAchievement }
|
||||
if user.StoryTurning != nil { resp["storyTurning"] = user.StoryTurning }
|
||||
if user.HelpOffer != nil { resp["helpOffer"] = user.HelpOffer }
|
||||
if user.HelpNeed != nil { resp["helpNeed"] = user.HelpNeed }
|
||||
if user.ProjectIntro != nil { resp["projectIntro"] = user.ProjectIntro }
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": resp})
|
||||
}
|
||||
|
||||
@@ -308,9 +306,28 @@ func UserProfilePost(c *gin.Context) {
|
||||
}
|
||||
updates["updated_at"] = time.Now()
|
||||
db.Model(&user).Updates(updates)
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "资料更新成功", "data": gin.H{
|
||||
"id": user.ID, "nickname": body.Nickname, "avatar": body.Avatar, "phone": body.Phone, "wechatId": body.WechatID, "referralCode": user.ReferralCode,
|
||||
}})
|
||||
// 重新查询并返回与 GET 一致的完整资料结构,空值统一为 ""
|
||||
profileCols := []string{"id", "open_id", "nickname", "avatar", "phone", "wechat_id", "referral_code", "created_at",
|
||||
"mbti", "region", "industry", "position", "business_scale", "skills",
|
||||
"story_best_month", "story_achievement", "story_turning", "help_offer", "help_need", "project_intro"}
|
||||
if err := database.DB().Select(profileCols).Where("id = ?", user.ID).First(&user).Error; err == nil {
|
||||
str := func(p *string) interface{} { if p != nil { return *p }; return "" }
|
||||
resp := gin.H{
|
||||
"id": user.ID, "openId": user.OpenID, "nickname": str(user.Nickname), "avatar": str(user.Avatar),
|
||||
"phone": str(user.Phone), "wechatId": str(user.WechatID), "referralCode": user.ReferralCode,
|
||||
"createdAt": user.CreatedAt,
|
||||
"mbti": str(user.Mbti), "region": str(user.Region), "industry": str(user.Industry),
|
||||
"position": str(user.Position), "businessScale": str(user.BusinessScale), "skills": str(user.Skills),
|
||||
"storyBestMonth": str(user.StoryBestMonth), "storyAchievement": str(user.StoryAchievement),
|
||||
"storyTurning": str(user.StoryTurning), "helpOffer": str(user.HelpOffer), "helpNeed": str(user.HelpNeed),
|
||||
"projectIntro": str(user.ProjectIntro),
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "资料更新成功", "data": resp})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "message": "资料更新成功", "data": gin.H{
|
||||
"id": user.ID, "nickname": body.Nickname, "avatar": body.Avatar, "phone": body.Phone, "wechatId": body.WechatID, "referralCode": user.ReferralCode,
|
||||
}})
|
||||
}
|
||||
}
|
||||
|
||||
// UserPurchaseStatus GET /api/user/purchase-status?userId=
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user