You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
373 lines
16 KiB
373 lines
16 KiB
<template>
|
|
<view class="setup-page">
|
|
<view class="top-safe" :style="{ height: menuButtonInfo.top + 'px' }"></view>
|
|
<view class="nav">
|
|
<view class="back" @tap="back">‹</view>
|
|
<view class="title">{{ isEdit ? '编辑 i/e 资料' : '先认识一下你' }}</view>
|
|
<view class="step">{{ step }}/5</view>
|
|
</view>
|
|
|
|
<view class="progress"><view :style="{ width: step * 20 + '%' }"></view></view>
|
|
|
|
<view class="card" v-if="step === 1">
|
|
<view class="eyebrow">Your Energy</view>
|
|
<view class="headline">今天更像 i 还是 e?</view>
|
|
<view class="mode-card i" :class="{ active: form.currentMode === 'i' }" @tap="form.currentMode = 'i'">
|
|
<view class="mark">i</view>
|
|
<view><view class="mode-title">安静陪伴</view><view class="mode-desc">慢回复、允许沉默、低压力靠近。</view></view>
|
|
</view>
|
|
<view class="mode-card e" :class="{ active: form.currentMode === 'e' }" @tap="form.currentMode = 'e'">
|
|
<view class="mark">e</view>
|
|
<view><view class="mode-title">轻轻热闹</view><view class="mode-desc">有人开场,聊点废话,把情绪拉亮。</view></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card" v-if="step === 2">
|
|
<view class="eyebrow">Light Profile</view>
|
|
<view class="headline">设置一个轻社交资料</view>
|
|
<view class="avatar-wrap" @tap="chooseAvatar">
|
|
<image class="avatar-img" v-if="form.avatarUrl" :src="form.avatarUrl" mode="aspectFill"></image>
|
|
<view class="avatar-text" v-else>{{ avatarPreview }}</view>
|
|
<view class="avatar-tip">点一下换头像</view>
|
|
</view>
|
|
<view class="random-name" @tap="randomName">随机一个昵称</view>
|
|
<input class="input" v-model="form.anonymousName" maxlength="16" placeholder="昵称,例如:南门慢跑员" />
|
|
<view class="mini-title">性别</view>
|
|
<view class="gender-row">
|
|
<view class="gender-chip" v-for="item in genderOptions" :key="item.key" :class="{ active: form.gender === item.key }" @tap="form.gender = item.key">
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
<textarea class="textarea" v-model="form.intro" maxlength="80" placeholder="一句轻介绍:我通常慢热,但会认真听。" />
|
|
</view>
|
|
|
|
<view class="card" v-if="step === 3">
|
|
<view class="eyebrow">Tags</view>
|
|
<view class="headline">选择几个此刻标签</view>
|
|
<view class="tag-grid">
|
|
<view class="tag" v-for="item in tagOptions" :key="item" :class="{ active: form.interestTags.includes(item) }" @tap="toggleTag(item)">
|
|
{{ item }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card" v-if="step === 4">
|
|
<view class="eyebrow">Persona Cards</view>
|
|
<view class="headline">上传你的人格卡片</view>
|
|
<view class="card-desc">最多 5 张,像个人主页的形象展示。别人点击头像时可以看到。</view>
|
|
<view class="persona-grid">
|
|
<view class="persona-item" v-for="(img, index) in form.personaImages" :key="img">
|
|
<image :src="img" mode="aspectFill" @tap="previewPersona(index)"></image>
|
|
<view class="persona-delete" @tap.stop="removePersonaImage(index)">×</view>
|
|
</view>
|
|
<view class="persona-add" v-if="form.personaImages.length < 5" @tap="choosePersonaImages">
|
|
<view class="plus">+</view>
|
|
<view>添加图片</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card" v-if="step === 5">
|
|
<view class="eyebrow">Match Target</view>
|
|
<view class="headline">你现在想遇见哪类人?</view>
|
|
<view class="target-card" v-for="item in targetOptions" :key="item.key" :class="{ active: form.targetModePreference === item.key }" @tap="form.targetModePreference = item.key">
|
|
<view class="target-title">{{ item.title }}</view>
|
|
<view class="target-desc">{{ item.desc }}</view>
|
|
</view>
|
|
<view class="mini-title target-gender-title">想匹配的性别</view>
|
|
<view class="gender-row">
|
|
<view class="gender-chip" v-for="item in targetGenderOptions" :key="item.key" :class="{ active: form.targetGenderPreference === item.key }" @tap="form.targetGenderPreference = item.key">
|
|
{{ item.label }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="actions">
|
|
<view class="ghost" @tap="prev" v-if="step > 1">上一步</view>
|
|
<view class="solid" @tap="next">{{ step === 5 ? '进入 i/e 此刻' : '继续' }}</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { getIeProfile, saveIeProfile } from '@/common/ieApi.js'
|
|
import tui from '@/common/httpRequest.js'
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
menuButtonInfo: { top: 44 },
|
|
step: 1,
|
|
isEdit: false,
|
|
submitting: false,
|
|
profileCompleted: 0,
|
|
form: {
|
|
currentMode: 'i',
|
|
targetModePreference: 'any',
|
|
targetGenderPreference: 'any',
|
|
anonymousName: '',
|
|
avatarText: '我',
|
|
avatarUrl: '',
|
|
gender: 'unknown',
|
|
intro: '',
|
|
interestTags: [],
|
|
personaImages: []
|
|
},
|
|
tagOptions: ['慢热', '爱听歌', '夜跑', '自习', '想聊天', '想安静', '情绪低电量', '散步', '电影', '游戏', '摄影', '干饭'],
|
|
targetOptions: [
|
|
{ key: 'i', title: '想遇见 i 人', desc: '安静、慢一点、允许沉默。' },
|
|
{ key: 'e', title: '想遇见 e 人', desc: '轻松开场,聊一点不重要的小事。' },
|
|
{ key: 'any', title: '都可以', desc: '交给此刻的随机同频。' }
|
|
],
|
|
genderOptions: [{ key: 'male', label: '男生' }, { key: 'female', label: '女生' }, { key: 'unknown', label: '不想说' }],
|
|
targetGenderOptions: [{ key: 'male', label: '男生' }, { key: 'female', label: '女生' }, { key: 'any', label: '不限' }],
|
|
nameSeeds: ['南门慢跑员', '图书馆三楼', '便利店灯光', '耳机里的云', '操场晚风', '自习逃跑员', '月台旁的影子']
|
|
}
|
|
},
|
|
computed: {
|
|
avatarPreview() {
|
|
return (this.form.anonymousName || this.form.avatarText || '我').slice(0, 1)
|
|
}
|
|
},
|
|
onLoad(options) {
|
|
if (uni.getMenuButtonBoundingClientRect) this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
|
this.isEdit = options && options.edit === '1'
|
|
this.loadProfile()
|
|
},
|
|
onShow(){
|
|
uni.authorize({
|
|
scope: 'scope.writePhotosAlbum',
|
|
success() {
|
|
|
|
},
|
|
fail() {
|
|
this.tui.toast("您未授权,图片上传功能可能会出现错误")
|
|
}
|
|
})
|
|
},
|
|
methods: {
|
|
async loadProfile() {
|
|
const profile = await getIeProfile()
|
|
if (!profile) return
|
|
this.profileCompleted = profile.profileCompleted || 0
|
|
this.form.currentMode = profile.currentMode || 'i'
|
|
this.form.targetModePreference = profile.targetModePreference || 'any'
|
|
this.form.targetGenderPreference = profile.targetGenderPreference || 'any'
|
|
this.form.anonymousName = this.isEdit || profile.profileCompleted === 1 ? (profile.anonymousName || '') : ''
|
|
this.form.avatarText = profile.avatarText || '我'
|
|
this.form.avatarUrl = profile.avatarUrl || ''
|
|
this.form.gender = profile.gender || 'unknown'
|
|
this.form.intro = profile.intro || ''
|
|
this.form.interestTags = profile.interestTags || []
|
|
this.form.personaImages = profile.personaImages || []
|
|
},
|
|
toggleTag(tag) {
|
|
const index = this.form.interestTags.indexOf(tag)
|
|
if (index > -1) {
|
|
this.form.interestTags.splice(index, 1)
|
|
return
|
|
}
|
|
if (this.form.interestTags.length >= 6) {
|
|
uni.showToast({ title: '最多选择 6 个标签', icon: 'none' })
|
|
return
|
|
}
|
|
this.form.interestTags.push(tag)
|
|
},
|
|
randomName() {
|
|
this.form.anonymousName = this.nameSeeds[Math.floor(Math.random() * this.nameSeeds.length)]
|
|
},
|
|
chooseAvatar() {
|
|
let that = this;
|
|
uni.chooseMedia({
|
|
count: 1,
|
|
mediaType: ['image'],
|
|
sourceType: ['camera', 'album'],
|
|
camera: 'back',
|
|
success(res) {
|
|
that.upLoadFile(res.tempFiles[0].tempFilePath)
|
|
},
|
|
fail() {
|
|
uni.hideLoading();
|
|
}
|
|
})
|
|
},
|
|
async upLoadFile(path) {
|
|
let that = this;
|
|
uni.showLoading({
|
|
title: '加载中...',
|
|
mask: true
|
|
})
|
|
let hiver_token = uni.getStorageSync("hiver_token")
|
|
await uni.uploadFile({
|
|
url: that.tui.interfaceUrl() + '/upload/file',
|
|
filePath: path,
|
|
name: 'file',
|
|
header: {
|
|
"content-type": "multipart/form-data",
|
|
'accessToken': hiver_token
|
|
},
|
|
formData: {},
|
|
success: (uploadFileRes) => {
|
|
|
|
let path = JSON.parse(uploadFileRes.data)
|
|
|
|
this.form.avatarUrl = path.result
|
|
},
|
|
fail: (err) => {
|
|
uni.hideLoading();
|
|
uni.showToast({
|
|
title: JSON.stringify(err),
|
|
icon: 'none'
|
|
})
|
|
}
|
|
});
|
|
await setTimeout(res => {
|
|
that.parentId = ''
|
|
// uni.hideLoading();
|
|
}, 1000)
|
|
},
|
|
choosePersonaImages() {
|
|
const remain = 5 - this.form.personaImages.length
|
|
if (remain <= 0) {
|
|
uni.showToast({ title: '最多上传 5 张', icon: 'none' })
|
|
return
|
|
}
|
|
uni.chooseMedia({
|
|
count: remain,
|
|
mediaType: ['image'],
|
|
sourceType: ['camera', 'album'],
|
|
camera: 'back',
|
|
success: async (res) => {
|
|
const files = res.tempFiles || []
|
|
for (const file of files) {
|
|
if (this.form.personaImages.length >= 5) break
|
|
const url = await this.uploadPersonaFile(file.tempFilePath)
|
|
if (url) this.form.personaImages.push(url)
|
|
}
|
|
}
|
|
})
|
|
},
|
|
uploadPersonaFile(path) {
|
|
if (!path) return Promise.resolve('')
|
|
const hiverToken = uni.getStorageSync('hiver_token')
|
|
uni.showLoading({ title: '上传中...', mask: true })
|
|
return new Promise((resolve) => {
|
|
uni.uploadFile({
|
|
url: this.tui.interfaceUrl() + '/upload/file',
|
|
filePath: path,
|
|
name: 'file',
|
|
header: {
|
|
'content-type': 'multipart/form-data',
|
|
'accessToken': hiverToken
|
|
},
|
|
success: (uploadFileRes) => {
|
|
try {
|
|
const data = JSON.parse(uploadFileRes.data)
|
|
resolve(data.result || '')
|
|
} catch (e) {
|
|
resolve('')
|
|
}
|
|
},
|
|
fail: () => resolve(''),
|
|
complete: () => uni.hideLoading()
|
|
})
|
|
})
|
|
},
|
|
removePersonaImage(index) {
|
|
this.form.personaImages.splice(index, 1)
|
|
},
|
|
previewPersona(index) {
|
|
uni.previewImage({ urls: this.form.personaImages, current: this.form.personaImages[index] })
|
|
},
|
|
validateStep() {
|
|
if (this.step === 2 && !this.form.anonymousName.trim()) {
|
|
uni.showToast({ title: '先起一个昵称吧', icon: 'none' })
|
|
return false
|
|
}
|
|
if (this.step === 3 && !this.form.interestTags.length) {
|
|
uni.showToast({ title: '至少选一个标签', icon: 'none' })
|
|
return false
|
|
}
|
|
return true
|
|
},
|
|
prev() { this.step = Math.max(1, this.step - 1) },
|
|
async next() {
|
|
if (this.submitting) return
|
|
if (!this.validateStep()) return
|
|
if (this.step < 5) {
|
|
this.step += 1
|
|
return
|
|
}
|
|
this.submitting = true
|
|
uni.showLoading({ title: '正在进入 i/e', mask: true })
|
|
try {
|
|
const profile = await saveIeProfile({
|
|
...this.form,
|
|
avatarText: this.avatarPreview
|
|
})
|
|
if (!profile) return
|
|
uni.redirectTo({ url: this.isEdit ? '/package1/ieBrowser/universe' : '/package1/ieBrowser/index' })
|
|
} finally {
|
|
this.submitting = false
|
|
uni.hideLoading()
|
|
}
|
|
},
|
|
back() {
|
|
if (this.isEdit) {
|
|
uni.redirectTo({ url: '/package1/ieBrowser/universe' })
|
|
return
|
|
}
|
|
uni.redirectTo({ url: '/pages/index/index' })
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
page { background: #f7f9ff; }
|
|
.setup-page { min-height: 100vh; padding: 0 32rpx 168rpx; box-sizing: border-box; color: #151a2d; background: radial-gradient(circle at 82% 10%, rgba(169,255,231,.42), transparent 320rpx), radial-gradient(circle at 16% 70%, rgba(255,184,209,.24), transparent 340rpx), linear-gradient(180deg, #fbfdff, #eef4ff 64%, #fff4e8); }
|
|
.nav { height: 92rpx; display: flex; align-items: center; }
|
|
.back { width: 70rpx; color: rgba(21,26,45,.56); font-size: 56rpx; }
|
|
.title { flex: 1; font-size: 32rpx; font-weight: 800; }
|
|
.step { color: #6c69d8; font-size: 24rpx; font-weight: 800; }
|
|
.progress { height: 10rpx; border-radius: 999rpx; background: rgba(21,26,45,.06); overflow: hidden; }
|
|
.progress view { height: 100%; border-radius: 999rpx; background: #a9ffe7; transition: width .25s ease; }
|
|
.card { margin-top: 36rpx; padding: 38rpx 32rpx; border-radius: 46rpx; border: 1rpx solid rgba(255,255,255,.82); background: rgba(255,255,255,.64); box-shadow: 0 26rpx 80rpx rgba(96,112,160,.14); backdrop-filter: blur(26rpx); }
|
|
.eyebrow { color: rgba(21,26,45,.42); font-size: 22rpx; letter-spacing: 5rpx; text-transform: uppercase; }
|
|
.headline { margin-top: 16rpx; margin-bottom: 28rpx; font-size: 46rpx; line-height: 60rpx; font-weight: 800; }
|
|
.card-desc { margin: -10rpx 0 24rpx; color: rgba(21,26,45,.52); font-size: 24rpx; line-height: 38rpx; }
|
|
.mode-card, .target-card { display: flex; align-items: center; margin-top: 22rpx; padding: 28rpx; border-radius: 34rpx; background: rgba(238,244,255,.68); border: 2rpx solid transparent; }
|
|
.mode-card.active, .target-card.active { border-color: #a9ffe7; background: rgba(223,254,244,.7); transform: scale(1.01); }
|
|
.mark { width: 82rpx; height: 82rpx; margin-right: 22rpx; border-radius: 28rpx; text-align: center; line-height: 82rpx; font-size: 46rpx; font-weight: 800; }
|
|
.i .mark { color: #fff; background: #7771d8; }
|
|
.e .mark { color: #11162a; background: #a9ffe7; }
|
|
.mode-title, .target-title { font-size: 30rpx; font-weight: 800; }
|
|
.mode-desc, .target-desc { margin-top: 8rpx; color: rgba(21,26,45,.54); font-size: 23rpx; line-height: 36rpx; }
|
|
.mini-title { margin: 24rpx 0 16rpx; color: rgba(21,26,45,.5); font-size: 23rpx; font-weight: 800; }
|
|
.target-gender-title { margin-top: 30rpx; }
|
|
.gender-row { display: flex; flex-wrap: wrap; }
|
|
.gender-chip { height: 58rpx; line-height: 58rpx; margin: 0 14rpx 14rpx 0; padding: 0 24rpx; border-radius: 999rpx; color: rgba(21,26,45,.58); background: rgba(238,244,255,.82); font-size: 23rpx; }
|
|
.gender-chip.active { color: #11162a; background: #a9ffe7; font-weight: 800; }
|
|
.avatar-wrap { width: 184rpx; margin: 0 auto 30rpx; text-align: center; }
|
|
.avatar-img, .avatar-text { width: 154rpx; height: 154rpx; margin: 0 auto; border-radius: 50%; }
|
|
.avatar-img { display: block; }
|
|
.avatar-text { text-align: center; line-height: 154rpx; color: #11162a; background: linear-gradient(145deg, #effffb, #a9ffe7); font-size: 58rpx; font-weight: 800; }
|
|
.avatar-tip { margin-top: 14rpx; color: rgba(21,26,45,.42); font-size: 22rpx; }
|
|
.random-name { width: 220rpx; height: 58rpx; margin: 0 auto 22rpx; border-radius: 999rpx; text-align: center; line-height: 58rpx; color: #6c69d8; background: rgba(139,124,255,.1); font-size: 23rpx; font-weight: 800; }
|
|
.input, .textarea { width: 100%; box-sizing: border-box; border-radius: 28rpx; background: rgba(238,244,255,.78); color: #151a2d; font-size: 27rpx; }
|
|
.input { height: 88rpx; padding: 0 26rpx; }
|
|
.textarea { height: 180rpx; margin-top: 22rpx; padding: 24rpx 26rpx; line-height: 40rpx; }
|
|
.tag-grid { display: flex; flex-wrap: wrap; }
|
|
.tag { margin: 0 14rpx 18rpx 0; padding: 16rpx 24rpx; border-radius: 999rpx; color: rgba(21,26,45,.62); background: rgba(238,244,255,.82); font-size: 24rpx; }
|
|
.tag.active { color: #11162a; background: #a9ffe7; font-weight: 800; }
|
|
.persona-grid { display: flex; flex-wrap: wrap; gap: 18rpx; }
|
|
.persona-item, .persona-add { position: relative; width: 184rpx; height: 224rpx; border-radius: 30rpx; overflow: hidden; background: rgba(238,244,255,.82); }
|
|
.persona-item image { width: 100%; height: 100%; display: block; }
|
|
.persona-delete { position: absolute; right: 12rpx; top: 12rpx; width: 42rpx; height: 42rpx; border-radius: 50%; text-align: center; line-height: 38rpx; color: #fff; background: rgba(21,26,45,.56); font-size: 34rpx; }
|
|
.persona-add { display: flex; flex-direction: column; align-items: center; justify-content: center; color: rgba(21,26,45,.46); border: 2rpx dashed rgba(108,105,216,.22); box-sizing: border-box; font-size: 23rpx; }
|
|
.persona-add .plus { margin-bottom: 10rpx; color: #6c69d8; font-size: 44rpx; font-weight: 800; }
|
|
.actions { position: fixed; left: 32rpx; right: 32rpx; bottom: 42rpx; display: flex; gap: 18rpx; }
|
|
.ghost, .solid { flex: 1; height: 96rpx; border-radius: 999rpx; text-align: center; line-height: 96rpx; font-size: 28rpx; font-weight: 800; }
|
|
.ghost { color: rgba(21,26,45,.58); background: rgba(255,255,255,.68); }
|
|
.solid { color: #11162a; background: linear-gradient(135deg, #effffb, #a9ffe7); box-shadow: 0 22rpx 58rpx rgba(169,255,231,.28); }
|
|
</style>
|
|
|