Files
guoxue-mp/pages/user/setting.vue
T
2026-03-25 15:59:24 +08:00

680 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="setting-page">
<view class="top-bar" :style="{ paddingTop: statusBarPadding }">
<u-icon name="arrow-left" size="32" color="#fff" @click="goBack"></u-icon>
</view>
<view class="form-section">
<text class="form-title">请完善您的信息</text>
<view class="form-item" v-for="item in formItems" :key="item.key">
<template v-if="item.key !== 'time' || (item.key === 'time' && !authing) ">
<text class="label">{{ item.label }}</text>
<view class="input" v-if="item.type === 'input'">
<input class="w-100p" :placeholder="item.placeholder" v-model="form[item.key]"/>
</view>
<view v-else class="picker" @click="openPicker(item)">
<text class="picker-value">{{ displayValue(item.key, item.placeholder) }}</text>
<u-icon class="picker-arrow" name="arrow-down" size="20" color="#777"></u-icon>
</view>
</template>
</view>
</view>
<u-picker
:show="pickerVisible.gender"
:columns="genderColumns"
@confirm="onGenderConfirm"
@cancel="closePicker('gender')"
@close="closePicker('gender')"
></u-picker>
<u-datetime-picker
ref="birthRef"
mode="date"
:show="pickerVisible.birth"
v-model="birthPickerValue"
:minDate="minDate"
:maxDate="maxDate"
@change="onBirthChange"
@confirm="onBirthConfirm"
@cancel="closePicker('birth')"
@close="closePicker('birth')"
></u-datetime-picker>
<u-picker
:show="pickerVisible.time"
:columns="timeColumns"
@confirm="onTimeConfirm"
@cancel="closePicker('time')"
@close="closePicker('time')"
></u-picker>
<u-picker
ref="birthplaceRef"
:show="pickerVisible.birthplace"
:columns="areaColumns"
:defaultIndex="areaDefaultIndex"
@change="onBirthplaceChange"
@confirm="onBirthplaceConfirm"
@cancel="closePicker('birthplace')"
@close="closePicker('birthplace')"
></u-picker>
<view class="tips">我们会根据你的选择,提供更精准的推荐</view>
<view class="tips">您还可以选择其他人物进行聊天</view>
<view class="mentor-section">
<view class="mentor-card" v-for="mentor in mentors" :key="mentor.id"
:class="{ active: currentMentor === mentor.roleName }" @click="selectMentor(mentor)">
<view class="mentor-name">{{ mentor.roleName }}</view>
<image class="mentor-avatar" :src="mentor.avatar" mode="aspectFit"></image>
</view>
</view>
<view class="intro-card" v-if="currentMentorItem">
<text class="intro-text">
简介:{{ currentMentorItem.roleDesc }}
</text>
</view>
<!-- <u-gap height="200rpx"/>-->
<!-- <view class="chat-input" :style="{bottom: `${inputBottom}px`}">-->
<!-- <view class="m-40 flex justify-between items-center w-100p">-->
<!-- <view class="input-wrap">-->
<!-- <textarea-->
<!-- class="textarea"-->
<!-- v-model="content"-->
<!-- placeholder="迷茫困惑的话和我聊聊吧"-->
<!-- maxlength="-1"-->
<!-- placeholder-style="text-align:center;"-->
<!-- auto-height-->
<!-- fixed-->
<!-- :show-confirm-bar="false"-->
<!-- />-->
<!-- </view>-->
<!-- <button class="send-btn" @click="save">发送</button>-->
<!-- </view>-->
<!-- </view>-->
<button class="primary-btn" @click="save">保存</button>
<!-- <text class="skip" @click="skip" v-if="!noChat">跳过设置</text>-->
<Login ref="Login" @done="getUserData"/>
</view>
</template>
<script>
import {addChatListReq, chatListReq, listChatRoleReq} from "@/api/chat";
import {updateUserReq, userInfoReq} from "@/api/user";
import {getUserInfo} from "@/util/user";
import {dayjs} from '@/uni_modules/iRainna-dayjs/js_sdk/dayjs.min.js'
import Login from "@/components/Login.vue";
import {dictDataReq, sysAreaListReq} from "@/api/common";
const TIME_OPTIONS = [
'子时23~1点',
'丑时1~3点',
'寅时3~5点',
'卯时5~7点',
'辰时7~9点',
'巳时9~11点',
'午时11~13点',
'未时13~15点',
'申时15~17点',
'酉时17~19点',
'戌时19~21点',
'亥时21~23点'
]
export default {
components: {Login},
data() {
return {
statusBarPadding: '40rpx',
form: {
name: '',
gender: '',
birth: '',
time: '子时23~1点',
birthplace: '',
},
pickerVisible: {
gender: false,
birth: false,
time: false,
birthplace: false
},
genderColumns: [['男', '女']],
timeColumns: [TIME_OPTIONS],
birthPickerValue: Date.now(),
chatId: null,
roleName: null,
roleDesc: null,
avatar: null,
word: null,
formItems: [
{key: 'name', label: '*姓名', type: 'input', placeholder: '请输入'},
{key: 'gender', label: '*性别', type: 'picker', placeholder: '请选择', mode: 'selector', range: ['男', '女']},
{key: 'birth', label: '*出生年月日(阳历)', type: 'picker', placeholder: '请选择', mode: 'date', range: []},
{key: 'time', label: '时辰', type: 'picker', placeholder: '请选择', mode: 'selector', range: TIME_OPTIONS},
{key: 'birthplace', label: '出生地', type: 'picker', placeholder: '请选择', mode: 'selector'}
],
mentors: [],
currentMentor: '五师妹',
currentMentorItem: null,
minDate: dayjs('1900-01-01').valueOf(),
maxDate: dayjs().valueOf(),
noChat: false,
messageList: [],
defaultIndex: [],
areaColumns: [[], []],
areaDefaultIndex: [0, 0],
provinceList: [],
cityList: [],
selectedProvinceIndex: 0,
selectedCityIndex: 0,
inputBottom: 0,
content: '',
authing: true
}
},
onLoad(option) {
this.getDictList()
const info = uni.getSystemInfoSync()
this.inputBottom = uni.getSystemInfoSync().safeAreaInsets.bottom
this.statusBarPadding = `${(info.statusBarHeight || 20) + 10}px`
if (option.chatId) this.chatId = option.chatId
if (option.roleName) this.roleName = option.roleName
if (option.roleDesc) this.roleDesc = option.roleDesc
if (option.avatar) this.avatar = option.avatar
if (option.word) {
this.word = option.word
this.content = option.word
}
if (option.noChat) this.noChat = true
if (!getUserInfo().token) this.$refs.Login.open()
else {
this.getUserData()
}
},
methods: {
async getMessageList() {
const res = await chatListReq()
this.messageList = res.data
this.getRoleList()
},
async getDictList() {
const {data} = await dictDataReq({dictId: '171'})
this.authing = parseInt(data[0].dictDataCode) === 1
},
async getRoleList() {
const {data} = await listChatRoleReq()
const roleIdList = this.messageList.map(item => item.roleId)
// this.mentors = data.filter(item => {
// return !roleIdList.includes(item.id)
// })
this.mentors = data.map(item => {
const hasChat = roleIdList.includes(item.id)
let chatId = null
if (hasChat) {
chatId = this.messageList.find(msg => msg.roleId === item.id).id
}
return {
...item,
hasChat,
chatId
}
})
console.log(this.mentors)
this.currentMentor = ''
this.currentMentorItem = null
if (this.mentors.length) {
this.currentMentor = this.mentors[0].roleName
this.currentMentorItem = this.mentors[0]
}
// this.currentMentor = data[0].roleName
// this.currentMentorItem = data[0]
},
goBack() {
uni.navigateBack().catch(() => {
uni.switchTab({url: '/pages/user/index'})
})
},
openPicker(item) {
if (item.key === 'gender') {
this.pickerVisible.gender = true
return
}
if (item.key === 'birth') {
this.syncBirthPickerValue()
this.pickerVisible.birth = true
return
}
if (item.key === 'time') {
this.pickerVisible.time = true
return
}
if (item.key === 'birthplace') {
this.openAreaPicker()
}
},
closePicker(type) {
if (Object.prototype.hasOwnProperty.call(this.pickerVisible, type)) {
this.pickerVisible[type] = false
}
},
async openAreaPicker() {
await this.loadProvinceList()
if (!this.provinceList.length) {
uni.showToast({title: '暂无地区数据', icon: 'none'})
return
}
this.syncProvinceFromForm()
await this.loadCityList(this.selectedProvinceIndex)
this.syncCityFromForm()
this.updateAreaColumns()
this.areaDefaultIndex = [this.selectedProvinceIndex, this.selectedCityIndex]
this.pickerVisible.birthplace = true
},
parseBirthplace() {
const birthplace = (this.form.birthplace || '').trim()
if (!birthplace) return {provinceName: '', cityName: ''}
const parts = birthplace.split(/\s+/).filter(Boolean)
return {
provinceName: parts[0] || '',
cityName: parts[1] || ''
}
},
syncProvinceFromForm() {
const {provinceName} = this.parseBirthplace()
if (!provinceName) return
const idx = this.provinceList.findIndex(item => this.getAreaName(item) === provinceName)
if (idx !== -1) {
this.selectedProvinceIndex = idx
}
},
syncCityFromForm() {
const {cityName} = this.parseBirthplace()
if (!cityName || !this.cityList.length) return
const idx = this.cityList.findIndex(item => this.getAreaName(item) === cityName)
if (idx !== -1) {
this.selectedCityIndex = idx
}
},
async loadProvinceList() {
if (this.provinceList.length) {
this.updateAreaColumns(-1)
return
}
try {
const {data} = await sysAreaListReq({fid: 0})
this.provinceList = data || []
this.updateAreaColumns(0)
} catch (e) {
uni.showToast({title: '获取省份失败', icon: 'none'})
}
},
async loadCityList(provinceIndex = 0) {
const province = this.provinceList[provinceIndex]
if (!province) {
this.cityList = []
this.updateAreaColumns(1)
return
}
const fid = province.id || province.fid || province.value
if (fid === undefined || fid === null) {
this.cityList = []
this.updateAreaColumns(2)
return
}
try {
const {data} = await sysAreaListReq({fid})
this.cityList = data || []
this.updateAreaColumns(3)
} catch (e) {
this.cityList = []
this.updateAreaColumns(4)
uni.showToast({title: '获取城市失败', icon: 'none'})
}
},
updateAreaColumns(flag = null) {
console.log('this.selectedCityIndex', this.selectedCityIndex, flag)
if (this.selectedProvinceIndex >= this.provinceList.length) {
this.selectedProvinceIndex = 0
}
const provinceNames = this.provinceList.map(item => this.getAreaName(item))
this.$set(this.areaColumns, 0, provinceNames)
if (this.cityList.length) {
if (this.selectedCityIndex >= this.cityList.length) {
this.selectedCityIndex = 0
}
} else {
this.selectedCityIndex = 0
}
const cityNames = (this.cityList.length ? this.cityList : []).map(item => this.getAreaName(item))
this.$set(this.areaColumns, 1, cityNames.length ? cityNames : [''])
this.areaDefaultIndex = [this.selectedProvinceIndex, this.selectedCityIndex]
console.log('this.areaDefaultIndex', this.areaDefaultIndex)
},
onBirthplaceChange({columnIndex, index}) {
if (columnIndex === 0) {
this.selectedProvinceIndex = index
this.selectedCityIndex = 0
this.loadCityList(index)
} else if (columnIndex === 1) {
this.selectedCityIndex = index
}
},
onBirthplaceConfirm({value, indexs}) {
const provinceIndex = indexs && indexs.length ? indexs[0] : this.selectedProvinceIndex
const cityIndex = indexs && indexs.length > 1 ? indexs[1] : this.selectedCityIndex
this.selectedProvinceIndex = provinceIndex
this.selectedCityIndex = cityIndex
this.areaDefaultIndex = [this.selectedProvinceIndex, this.selectedCityIndex]
const province = this.provinceList[provinceIndex]
const city = this.cityList[cityIndex]
const provinceName = this.getAreaName(province)
const cityName = this.getAreaName(city)
this.form.birthplace = cityName ? `${provinceName} ${cityName}` : provinceName
this.closePicker('birthplace')
},
getAreaName(area) {
if (!area) return ''
return area.areaName || area.name || area.label || area.title || ''
},
syncBirthPickerValue() {
if (this.form.birth) {
this.birthPickerValue = dayjs(this.form.birth).valueOf()
this.$refs.birthRef.innerValue = this.birthPickerValue
} else {
this.birthPickerValue = Date.now()
this.birthPickerValue = Number(this.birthPickerValue)
}
console.log('this.birthPickerValue', this.birthPickerValue)
},
onGenderConfirm({value}) {
this.form.gender = value && value.length ? value[0] : ''
this.closePicker('gender')
},
onBirthConfirm({value}) {
this.form.birth = this.formatDate(value)
this.birthPickerValue = value
this.closePicker('birth')
},
onBirthChange({value}) {
this.form.birth = this.formatDate(value)
this.birthPickerValue = value
},
onTimeConfirm({value}) {
this.form.time = value && value.length ? value[0] : ''
this.closePicker('time')
},
formatDate(timestamp) {
const date = new Date(timestamp)
const year = date.getFullYear()
const month = `${date.getMonth() + 1}`.padStart(2, '0')
const day = `${date.getDate()}`.padStart(2, '0')
return `${year}-${month}-${day}`
},
displayValue(key, placeholder) {
return this.form[key] || placeholder
},
selectMentor(item) {
this.currentMentor = item.roleName
this.currentMentorItem = item
},
async save() {
// if (!this.content) return uni.showToast({title: '请输入内容', icon: 'none'})
await updateUserReq({
userId: getUserInfo().uid,
birthday: this.form.birth,
sex: this.form.gender === '男' ? 0 : 1,
birthAddress: this.form.birthplace,
birthTime: this.form.time,
realName: this.form.name,
})
uni.showToast({title: '已保存', icon: 'success'})
await this.toChat()
},
skip() {
uni.showToast({title: '已跳过设置', icon: 'none'})
this.toChat()
},
async toChat() {
if (!this.currentMentor) return
let url = '/pages/chat/index'
const mentor = this.mentors.find(item => item.roleName === this.currentMentor)
url += `?roleName=${mentor.roleName}&roleDesc=${mentor.roleDesc}&avatar=${mentor.avatar}`
let chatId = null
// if (!mentor.hasChat) {
const {data} = await addChatListReq({
roleName: mentor.roleName,
roleDesc: mentor.roleDesc,
roleId: mentor.id
})
chatId = data.id
// } else {
// chatId = mentor.chatId
// }
url += `&chatId=${chatId}&roleId=${mentor.id}`
if (this.content) url += `&word=${this.content}`
uni.navigateTo({url})
},
async getUserData() {
const {data} = await userInfoReq()
if (data.birthday) {
this.form.birth = dayjs(data.birthday).format('YYYY-MM-DD')
this.birthPickerValue = dayjs(data.birthday).toDate()
}
if (data.sex !== null && data.sex !== undefined)
this.form.gender = parseInt(data.sex) === 0 ? '男' : '女'
if (data.birthTime)
this.form.time = data.birthTime
if (data.birthAddress)
this.form.birthplace = data.birthAddress
if (data.realName)
this.form.name = data.realName
console.log(data.gender)
console.log(this.form)
this.getMessageList()
}
}
}
</script>
<style lang="scss" scoped>
.setting-page {
min-height: 100vh;
padding: 40rpx 30rpx 60rpx;
background: linear-gradient(180deg, #8f99dd 0%, #e3e8ff 60%, #ffffff 100%);
color: #fff;
box-sizing: border-box;
}
.top-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 20rpx;
}
.top-title {
font-size: 32rpx;
}
.top-right .pill {
display: flex;
align-items: center;
gap: 14rpx;
background: rgba(255, 255, 255, 0.8);
padding: 12rpx 30rpx;
border-radius: 40rpx;
}
.form-section {
margin-top: 40rpx;
background: rgba(255, 255, 255, 0.15);
border-radius: 30rpx;
padding: 30rpx;
}
.form-title {
font-size: 30rpx;
font-weight: 600;
color: #f2f2ff;
}
.form-item {
margin-top: 30rpx;
}
.label {
font-size: 26rpx;
color: #f3f5ff;
margin-bottom: 12rpx;
display: block;
}
.input,
.picker {
width: 100%;
height: 76rpx;
border-radius: 40rpx;
background: rgba(255, 255, 255, 0.45);
color: #333;
padding: 0 30rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
.picker {
justify-content: space-between;
}
.picker-value {
color: #51526b;
font-size: 28rpx;
flex: 1;
}
.picker-arrow {
margin-left: 20rpx;
}
.tips {
margin: 30rpx 0;
text-align: center;
color: #5f5f81;
font-size: 24rpx;
}
.mentor-section {
display: flex;
justify-content: space-around;
margin-bottom: 30rpx;
}
.mentor-card {
width: 45%;
border-radius: 32rpx;
background: rgba(255, 255, 255, 0.6);
padding: 20rpx;
text-align: center;
color: #4d4f7f;
}
.mentor-card.active {
background: linear-gradient(160deg, #7f8aff, #b0bdff);
color: #fff;
}
.mentor-name {
font-size: 30rpx;
margin-bottom: 20rpx;
}
.mentor-avatar {
width: 140rpx;
height: 140rpx;
border-radius: 70rpx;
margin: 0 auto;
}
.intro-card {
background: rgba(255, 255, 255, 0.7);
border-radius: 30rpx;
padding: 30rpx;
color: #3a406d;
font-size: 26rpx;
line-height: 1.6;
margin-bottom: 30rpx;
}
.primary-btn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
border-radius: 48rpx;
background: linear-gradient(120deg, #1a2663, #293892);
color: #fff;
font-size: 30rpx;
letter-spacing: 4rpx;
}
.skip {
display: block;
margin-top: 20rpx;
text-align: center;
color: #454669;
}
.chat-input {
width: 100%;
padding: 40rpx 0;
//padding: 20rpx 30rpx 40rpx;
align-items: center;
gap: 20rpx;
//background: #f7f7fb;
display: flex;
justify-content: center;
position: fixed;
left: 0;
bottom: 0;
}
.chat-input .input-wrap {
flex: 1;
border-radius: 30rpx;
background: #21284f;
color: #fff;
padding: 20rpx 30rpx;
margin-left: 30rpx;
display: flex;
align-items: center;
justify-content: center;
//height: 100rpx;
min-height: 60rpx;
}
.chat-input .textarea {
width: 100%;
//height: 100%;
background: none !important;
color: #ffffff !important;
text-align: left;
line-height: 40rpx;
padding: 0;
min-height: 50rpx;
}
.send-btn {
width: 140rpx;
height: 100rpx;
border-radius: 999rpx;
background: linear-gradient(120deg, #fbc889, #f37a5b);
color: #000;
display: flex;
align-items: center;
justify-content: center;
margin: 0 30rpx;
}
</style>