20260325稳定版

This commit is contained in:
2026-03-25 15:59:24 +08:00
commit 0decd78604
470 changed files with 53100 additions and 0 deletions
+679
View File
@@ -0,0 +1,679 @@
<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>