|
@@ -23,17 +23,27 @@
|
|
|
<!-- 头像 -->
|
|
<!-- 头像 -->
|
|
|
<view class="info-item avatar-item">
|
|
<view class="info-item avatar-item">
|
|
|
<text class="item-label">{{ t('pagesContent.my.info.avatar') }}</text>
|
|
<text class="item-label">{{ t('pagesContent.my.info.avatar') }}</text>
|
|
|
- <image
|
|
|
|
|
- class="avatar-image"
|
|
|
|
|
- :src="basicInfo.avatar || '/static/default-avatar.svg'"
|
|
|
|
|
- mode="aspectFill"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <view class="avatar-wrapper">
|
|
|
|
|
+ <image
|
|
|
|
|
+ class="avatar-image"
|
|
|
|
|
+ :src="basicInfo.avatar || '/static/default-avatar.svg'"
|
|
|
|
|
+ mode="aspectFill"
|
|
|
|
|
+ />
|
|
|
|
|
+ <view class="edit-btn" @click="handleEditAvatar">
|
|
|
|
|
+ <text class="edit-btn-text">修改</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 昵称 -->
|
|
<!-- 昵称 -->
|
|
|
<view class="info-item">
|
|
<view class="info-item">
|
|
|
<text class="item-label">{{ t('pagesContent.my.info.nickname') }}</text>
|
|
<text class="item-label">{{ t('pagesContent.my.info.nickname') }}</text>
|
|
|
- <text class="item-value">{{ basicInfo.nickname || '-' }}</text>
|
|
|
|
|
|
|
+ <view class="value-wrapper">
|
|
|
|
|
+ <text class="item-value">{{ basicInfo.nickname || '-' }}</text>
|
|
|
|
|
+ <view class="edit-btn" @click="handleEditNickname">
|
|
|
|
|
+ <text class="edit-btn-text">修改</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 手机号 -->
|
|
<!-- 手机号 -->
|
|
@@ -45,8 +55,108 @@
|
|
|
<!-- 性别 -->
|
|
<!-- 性别 -->
|
|
|
<view class="info-item">
|
|
<view class="info-item">
|
|
|
<text class="item-label">{{ t('pagesContent.my.info.gender') }}</text>
|
|
<text class="item-label">{{ t('pagesContent.my.info.gender') }}</text>
|
|
|
- <view class="gender-value">
|
|
|
|
|
- <text class="item-value" :class="genderClass">{{ genderDisplay }}</text>
|
|
|
|
|
|
|
+ <view class="value-wrapper">
|
|
|
|
|
+ <view class="gender-value">
|
|
|
|
|
+ <text class="item-value" :class="genderClass">{{ genderDisplay }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="edit-btn" @click="handleEditGender">
|
|
|
|
|
+ <text class="edit-btn-text">修改</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 修改头像弹窗 -->
|
|
|
|
|
+ <view v-if="showAvatarModal" class="modal-overlay" @click="closeAvatarModal">
|
|
|
|
|
+ <view class="modal-content" @click.stop>
|
|
|
|
|
+ <view class="modal-header">
|
|
|
|
|
+ <text class="modal-title">修改头像</text>
|
|
|
|
|
+ <view class="modal-close" @click="closeAvatarModal">
|
|
|
|
|
+ <text class="close-icon">×</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="modal-body">
|
|
|
|
|
+ <view class="upload-area" @click="handleSelectImage">
|
|
|
|
|
+ <image
|
|
|
|
|
+ v-if="tempAvatar"
|
|
|
|
|
+ class="preview-image"
|
|
|
|
|
+ :src="tempAvatar"
|
|
|
|
|
+ mode="aspectFill"
|
|
|
|
|
+ />
|
|
|
|
|
+ <view v-else class="upload-placeholder">
|
|
|
|
|
+ <text class="placeholder-text">点击选择图片</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="modal-actions">
|
|
|
|
|
+ <view class="action-btn cancel-btn" @click="closeAvatarModal">
|
|
|
|
|
+ <text class="btn-text">取消</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="action-btn confirm-btn" @click="confirmUpdateAvatar">
|
|
|
|
|
+ <text class="btn-text">确认</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 修改昵称弹窗 -->
|
|
|
|
|
+ <view v-if="showNicknameModal" class="modal-overlay" @click="closeNicknameModal">
|
|
|
|
|
+ <view class="modal-content" @click.stop>
|
|
|
|
|
+ <view class="modal-header">
|
|
|
|
|
+ <text class="modal-title">修改昵称</text>
|
|
|
|
|
+ <view class="modal-close" @click="closeNicknameModal">
|
|
|
|
|
+ <text class="close-icon">×</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="modal-body">
|
|
|
|
|
+ <input
|
|
|
|
|
+ class="modal-input"
|
|
|
|
|
+ v-model="tempNickname"
|
|
|
|
|
+ placeholder="请输入昵称"
|
|
|
|
|
+ maxlength="20"
|
|
|
|
|
+ />
|
|
|
|
|
+ <view class="modal-actions">
|
|
|
|
|
+ <view class="action-btn cancel-btn" @click="closeNicknameModal">
|
|
|
|
|
+ <text class="btn-text">取消</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="action-btn confirm-btn" @click="confirmUpdateNickname">
|
|
|
|
|
+ <text class="btn-text">确认</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 修改性别弹窗 -->
|
|
|
|
|
+ <view v-if="showGenderModal" class="modal-overlay" @click="closeGenderModal">
|
|
|
|
|
+ <view class="modal-content" @click.stop>
|
|
|
|
|
+ <view class="modal-header">
|
|
|
|
|
+ <text class="modal-title">修改性别</text>
|
|
|
|
|
+ <view class="modal-close" @click="closeGenderModal">
|
|
|
|
|
+ <text class="close-icon">×</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="modal-body">
|
|
|
|
|
+ <picker
|
|
|
|
|
+ mode="selector"
|
|
|
|
|
+ :range="genderDictListWithLabel"
|
|
|
|
|
+ range-key="displayLabel"
|
|
|
|
|
+ :value="selectedGenderIndex"
|
|
|
|
|
+ @change="handleGenderChange"
|
|
|
|
|
+ >
|
|
|
|
|
+ <view class="picker-value">
|
|
|
|
|
+ <text class="value-text">{{ selectedGenderLabel || '请选择性别' }}</text>
|
|
|
|
|
+ <text class="arrow-icon">▼</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </picker>
|
|
|
|
|
+ <view class="modal-actions">
|
|
|
|
|
+ <view class="action-btn cancel-btn" @click="closeGenderModal">
|
|
|
|
|
+ <text class="btn-text">取消</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="action-btn confirm-btn" @click="confirmUpdateGender">
|
|
|
|
|
+ <text class="btn-text">确认</text>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -57,7 +167,7 @@
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { ref, computed, onMounted } from 'vue'
|
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
-import { getBasicInfo } from '@/apis/auth'
|
|
|
|
|
|
|
+import { getBasicInfo, updateAvatar, updateNickname, updateGender, uploadToOss } from '@/apis/auth'
|
|
|
import { getDictDataByType } from '@/apis/dict'
|
|
import { getDictDataByType } from '@/apis/dict'
|
|
|
|
|
|
|
|
const { t, locale } = useI18n()
|
|
const { t, locale } = useI18n()
|
|
@@ -82,6 +192,53 @@ const loading = ref(false)
|
|
|
// 性别字典数据
|
|
// 性别字典数据
|
|
|
const genderDictList = ref([])
|
|
const genderDictList = ref([])
|
|
|
|
|
|
|
|
|
|
+// 弹窗状态
|
|
|
|
|
+const showAvatarModal = ref(false)
|
|
|
|
|
+const showNicknameModal = ref(false)
|
|
|
|
|
+const showGenderModal = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+// 临时数据
|
|
|
|
|
+const tempAvatar = ref('')
|
|
|
|
|
+const tempAvatarOssId = ref('')
|
|
|
|
|
+const tempNickname = ref('')
|
|
|
|
|
+const tempGender = ref('')
|
|
|
|
|
+
|
|
|
|
|
+// 性别显示(为字典项添加displayLabel属性)
|
|
|
|
|
+const genderDictListWithLabel = computed(() => {
|
|
|
|
|
+ return genderDictList.value.map(item => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const labelObj = JSON.parse(item.dictLabel)
|
|
|
|
|
+ const localeKey = locale.value.replace('-', '_')
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ displayLabel: labelObj[localeKey] || labelObj['zh_CN'] || item.dictLabel
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ displayLabel: item.dictLabel
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 选中的性别索引
|
|
|
|
|
+const selectedGenderIndex = computed(() => {
|
|
|
|
|
+ if (!tempGender.value) return 0
|
|
|
|
|
+ return genderDictListWithLabel.value.findIndex(item =>
|
|
|
|
|
+ String(item.dictValue) === String(tempGender.value)
|
|
|
|
|
+ )
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 选中的性别标签
|
|
|
|
|
+const selectedGenderLabel = computed(() => {
|
|
|
|
|
+ if (!tempGender.value) return ''
|
|
|
|
|
+ const item = genderDictListWithLabel.value.find(item =>
|
|
|
|
|
+ String(item.dictValue) === String(tempGender.value)
|
|
|
|
|
+ )
|
|
|
|
|
+ return item?.displayLabel || ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
// 性别显示
|
|
// 性别显示
|
|
|
const genderDisplay = computed(() => {
|
|
const genderDisplay = computed(() => {
|
|
|
if (basicInfo.value.gender === null || basicInfo.value.gender === undefined || basicInfo.value.gender === '') return '-'
|
|
if (basicInfo.value.gender === null || basicInfo.value.gender === undefined || basicInfo.value.gender === '') return '-'
|
|
@@ -142,6 +299,215 @@ const fetchGenderDict = async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 打开修改头像弹窗
|
|
|
|
|
+const handleEditAvatar = () => {
|
|
|
|
|
+ tempAvatar.value = basicInfo.value.avatar || ''
|
|
|
|
|
+ tempAvatarOssId.value = ''
|
|
|
|
|
+ showAvatarModal.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭修改头像弹窗
|
|
|
|
|
+const closeAvatarModal = () => {
|
|
|
|
|
+ showAvatarModal.value = false
|
|
|
|
|
+ tempAvatar.value = ''
|
|
|
|
|
+ tempAvatarOssId.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 选择图片
|
|
|
|
|
+const handleSelectImage = () => {
|
|
|
|
|
+ uni.chooseImage({
|
|
|
|
|
+ count: 1,
|
|
|
|
|
+ sizeType: ['compressed'],
|
|
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
|
|
+ success: async (res) => {
|
|
|
|
|
+ tempAvatar.value = res.tempFilePaths[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 确认修改头像
|
|
|
|
|
+const confirmUpdateAvatar = async () => {
|
|
|
|
|
+ if (!tempAvatar.value) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '请选择图片',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ uni.showLoading({
|
|
|
|
|
+ title: '上传中...',
|
|
|
|
|
+ mask: true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 先上传图片到OSS
|
|
|
|
|
+ const uploadResponse = await uploadToOss(tempAvatar.value)
|
|
|
|
|
+
|
|
|
|
|
+ if (uploadResponse && uploadResponse.code === 200 && uploadResponse.data) {
|
|
|
|
|
+ // 使用返回的ossId更新头像
|
|
|
|
|
+ const updateResponse = await updateAvatar({
|
|
|
|
|
+ avatar: uploadResponse.data.ossId
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+
|
|
|
|
|
+ if (updateResponse && updateResponse.code === 200) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改成功',
|
|
|
|
|
+ icon: 'success'
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ closeAvatarModal()
|
|
|
|
|
+ // 重新获取基本信息
|
|
|
|
|
+ fetchBasicInfo()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: updateResponse.msg || '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: uploadResponse.msg || '上传失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ console.error('修改头像失败:', error)
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 打开修改昵称弹窗
|
|
|
|
|
+const handleEditNickname = () => {
|
|
|
|
|
+ tempNickname.value = basicInfo.value.nickname || ''
|
|
|
|
|
+ showNicknameModal.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭修改昵称弹窗
|
|
|
|
|
+const closeNicknameModal = () => {
|
|
|
|
|
+ showNicknameModal.value = false
|
|
|
|
|
+ tempNickname.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 确认修改昵称
|
|
|
|
|
+const confirmUpdateNickname = async () => {
|
|
|
|
|
+ if (!tempNickname.value || !tempNickname.value.trim()) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '请输入昵称',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ uni.showLoading({
|
|
|
|
|
+ title: '修改中...',
|
|
|
|
|
+ mask: true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const response = await updateNickname({
|
|
|
|
|
+ nickname: tempNickname.value.trim()
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+
|
|
|
|
|
+ if (response && response.code === 200) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改成功',
|
|
|
|
|
+ icon: 'success'
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ closeNicknameModal()
|
|
|
|
|
+ // 重新获取基本信息
|
|
|
|
|
+ fetchBasicInfo()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: response.msg || '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ console.error('修改昵称失败:', error)
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 打开修改性别弹窗
|
|
|
|
|
+const handleEditGender = () => {
|
|
|
|
|
+ tempGender.value = basicInfo.value.gender || ''
|
|
|
|
|
+ showGenderModal.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭修改性别弹窗
|
|
|
|
|
+const closeGenderModal = () => {
|
|
|
|
|
+ showGenderModal.value = false
|
|
|
|
|
+ tempGender.value = ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 性别选择变化
|
|
|
|
|
+const handleGenderChange = (e) => {
|
|
|
|
|
+ const index = e.detail.value
|
|
|
|
|
+ tempGender.value = genderDictListWithLabel.value[index].dictValue
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 确认修改性别
|
|
|
|
|
+const confirmUpdateGender = async () => {
|
|
|
|
|
+ if (!tempGender.value && tempGender.value !== 0) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '请选择性别',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ uni.showLoading({
|
|
|
|
|
+ title: '修改中...',
|
|
|
|
|
+ mask: true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const response = await updateGender({
|
|
|
|
|
+ gender: tempGender.value
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+
|
|
|
|
|
+ if (response && response.code === 200) {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改成功',
|
|
|
|
|
+ icon: 'success'
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ closeGenderModal()
|
|
|
|
|
+ // 重新获取基本信息
|
|
|
|
|
+ fetchBasicInfo()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: response.msg || '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ console.error('修改性别失败:', error)
|
|
|
|
|
+ uni.showToast({
|
|
|
|
|
+ title: '修改失败',
|
|
|
|
|
+ icon: 'none'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 获取基本信息
|
|
// 获取基本信息
|
|
|
const fetchBasicInfo = async () => {
|
|
const fetchBasicInfo = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -270,11 +636,40 @@ const handleBack = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
&.avatar-item {
|
|
&.avatar-item {
|
|
|
- .avatar-image {
|
|
|
|
|
- width: 100rpx;
|
|
|
|
|
- height: 100rpx;
|
|
|
|
|
- border-radius: 50rpx;
|
|
|
|
|
- border: 4rpx solid #6ec7f5;
|
|
|
|
|
|
|
+ .avatar-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 24rpx;
|
|
|
|
|
+
|
|
|
|
|
+ .avatar-image {
|
|
|
|
|
+ width: 100rpx;
|
|
|
|
|
+ height: 100rpx;
|
|
|
|
|
+ border-radius: 50rpx;
|
|
|
|
|
+ border: 4rpx solid #6ec7f5;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .value-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 16rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .edit-btn {
|
|
|
|
|
+ padding: 10rpx 24rpx;
|
|
|
|
|
+ background: linear-gradient(135deg, #1ec9c9 0%, #17b3b3 100%);
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ opacity: 0.8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .edit-btn-text {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -322,5 +717,240 @@ const handleBack = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 弹窗样式
|
|
|
|
|
+ .modal-overlay {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.6);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ z-index: 1000;
|
|
|
|
|
+ backdrop-filter: blur(4rpx);
|
|
|
|
|
+
|
|
|
|
|
+ .modal-content {
|
|
|
|
|
+ width: 620rpx;
|
|
|
|
|
+ max-width: 90%;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ border-radius: 24rpx;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
|
|
|
|
+ animation: modalSlideIn 0.3s ease-out;
|
|
|
|
|
+
|
|
|
|
|
+ @keyframes modalSlideIn {
|
|
|
|
|
+ from {
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ transform: translateY(-40rpx) scale(0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ to {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ transform: translateY(0) scale(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-header {
|
|
|
|
|
+ padding: 40rpx 32rpx 24rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ background: linear-gradient(135deg, #f8fcff 0%, #ffffff 100%);
|
|
|
|
|
+
|
|
|
|
|
+ .modal-title {
|
|
|
|
|
+ font-size: 34rpx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #1a1a1a;
|
|
|
|
|
+ letter-spacing: 1rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-close {
|
|
|
|
|
+ width: 56rpx;
|
|
|
|
|
+ height: 56rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.04);
|
|
|
|
|
+ transition: all 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.08);
|
|
|
|
|
+ transform: scale(0.9);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .close-icon {
|
|
|
|
|
+ font-size: 44rpx;
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ font-weight: 300;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-body {
|
|
|
|
|
+ padding: 32rpx;
|
|
|
|
|
+
|
|
|
|
|
+ .upload-area {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 420rpx;
|
|
|
|
|
+ border: 3rpx dashed #d9d9d9;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ margin-bottom: 32rpx;
|
|
|
|
|
+ background: #fafafa;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ border-color: #1ec9c9;
|
|
|
|
|
+ background: #f0fffe;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .preview-image {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ object-fit: cover;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .upload-placeholder {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ gap: 16rpx;
|
|
|
|
|
+
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ content: '+';
|
|
|
|
|
+ font-size: 80rpx;
|
|
|
|
|
+ color: #1ec9c9;
|
|
|
|
|
+ font-weight: 300;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .placeholder-text {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-input {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 28rpx 24rpx;
|
|
|
|
|
+ border: 2rpx solid #e8e8e8;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ margin-bottom: 32rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ background: #fafafa;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+ min-height: 88rpx;
|
|
|
|
|
+
|
|
|
|
|
+ &:focus {
|
|
|
|
|
+ border-color: #1ec9c9;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ box-shadow: 0 0 0 4rpx rgba(30, 201, 201, 0.1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .picker-value {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ padding: 28rpx 24rpx;
|
|
|
|
|
+ border: 2rpx solid #e8e8e8;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 32rpx;
|
|
|
|
|
+ background: #fafafa;
|
|
|
|
|
+ transition: all 0.2s;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ min-height: 88rpx;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ background: #f0f0f0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .value-text {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ color: #333333;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .arrow-icon {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #999999;
|
|
|
|
|
+ transition: transform 0.3s;
|
|
|
|
|
+ margin-left: 16rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .modal-actions {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20rpx;
|
|
|
|
|
+ margin-top: 8rpx;
|
|
|
|
|
+
|
|
|
|
|
+ .action-btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ padding: 28rpx;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ transition: all 0.2s;
|
|
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ transform: scale(0.98);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .btn-text {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ letter-spacing: 1rpx;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.cancel-btn {
|
|
|
|
|
+ background: #f5f5f5;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ background: #e8e8e8;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .btn-text {
|
|
|
|
|
+ color: #666666;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.confirm-btn {
|
|
|
|
|
+ background: linear-gradient(135deg, #1ec9c9 0%, #17b3b3 100%);
|
|
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(30, 201, 201, 0.3);
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(30, 201, 201, 0.3);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .btn-text {
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|