将用户信息修改页面从 `novel/Modifyinformation.vue` 移动到 `auth/Modifyinformation.vue`,并优化了表单提交逻辑。新增了手机号绑定功能,提升了用户体验。同时,修复了页面样式和交互问题,确保功能更加完善。 - 移动并重构用户信息修改页面 - 新增手机号绑定功能 - 优化表单提交逻辑 - 修复页面样式和交互问题master
| @ -0,0 +1,248 @@ | |||
| <template> | |||
| <view class="modify-info-page"> | |||
| <navbar title="修改信息" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="header"> | |||
| <button open-type="chooseAvatar" | |||
| class="share" | |||
| @chooseavatar="onChooseAvatar"> | |||
| <view class="avatar-upload"> | |||
| <uv-avatar :src="userInfoForm.headImage" size="88" shape="circle" class="avatar-main" /> | |||
| <view class="avatar-upload-btn"> | |||
| <uv-icon name="camera-fill" size="28" color="#fff" /> | |||
| </view> | |||
| </view> | |||
| </button> | |||
| </view> | |||
| <view class="card"> | |||
| <view class="card-title">个人信息</view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 昵称</view> | |||
| <view class="form-value"> | |||
| <input type="nickname" placeholder="请输入昵称" id="nickName" | |||
| v-model="userInfoForm.nickName" /> | |||
| </view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 个性签名</view> | |||
| <view class="form-value"> | |||
| <input placeholder="请输入个性签名" v-model="userInfoForm.signature" /> | |||
| </view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| </view> | |||
| <button | |||
| class="share" | |||
| open-type="getPhoneNumber" @getphonenumber="getPhone"> | |||
| <view class="card"> | |||
| <view class="card-title">手机号</view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 手机号</view> | |||
| <view class="form-value">{{ userInfoForm.phone }}</view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| </view> | |||
| </button> | |||
| <view class="footer"> | |||
| <uv-button type="primary" text="确认" shape="circle" size="large" @click="submit" | |||
| customStyle="width:100%;height:44px;font-size:18px;background:#0a226b;" /> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| components: {}, | |||
| data() { | |||
| return { | |||
| avatarUrl: '', | |||
| fileList: [], | |||
| showUpload: false, | |||
| userInfoForm: { | |||
| headImage: '', | |||
| nickName: '', | |||
| phone: '', | |||
| }, | |||
| } | |||
| }, | |||
| onLoad() { | |||
| this.userInfoForm.phone = this.userInfo.phone || '' | |||
| this.userInfoForm.nickName = this.userInfo.nickName || '' | |||
| this.userInfoForm.headImage = this.userInfo.headImage || '' | |||
| }, | |||
| methods: { | |||
| onChooseAvatar(res) { | |||
| this.$Oss.ossUpload(res.target.avatarUrl) | |||
| .then(url => { | |||
| this.userInfoForm.headImage = url | |||
| }) | |||
| }, | |||
| getPhone(e) { | |||
| this.$api('bindPhone', { | |||
| phoneCode: e.detail.code | |||
| }, res => { | |||
| if (res.code == 200) { | |||
| let phoneObj = JSON.parse(res.result) | |||
| if (phoneObj.errmsg == 'ok') { | |||
| this.userInfoForm.phone = phoneObj.phone_info.phoneNumber | |||
| } else { | |||
| uni.showModal({ | |||
| title: phoneObj.errmsg | |||
| }) | |||
| } | |||
| } | |||
| }) | |||
| }, | |||
| submit() { | |||
| let self = this | |||
| uni.createSelectorQuery().in(this) | |||
| .select("#nickName") | |||
| .fields({ | |||
| properties: ["value"], | |||
| }) | |||
| .exec((res) => { | |||
| const nickName = res?.[0]?.value | |||
| self.userInfoForm.nickName = nickName | |||
| if (self.$utils.verificationAll(self.userInfoForm, { | |||
| headImage: '请选择头像', | |||
| nickName: '请填写昵称', | |||
| phone: '请填写手机号', | |||
| })) { | |||
| return | |||
| } | |||
| self.$api('updateInfo', { | |||
| avatarUrl: self.userInfoForm.headImage, | |||
| nickName: self.userInfoForm.nickName, | |||
| phone: self.userInfoForm.phone, | |||
| }, res => { | |||
| if (res.code == 200) { | |||
| uni.reLaunch({ | |||
| url: '/pages/index/index' | |||
| }) | |||
| } | |||
| }) | |||
| }) | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| .modify-info-page { | |||
| min-height: 100vh; | |||
| background: #f8f8f8; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .back-arrow-fix { | |||
| position: absolute; | |||
| top: 60rpx; | |||
| left: 32rpx; | |||
| z-index: 1000; | |||
| } | |||
| .header { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| margin-top: 120rpx; | |||
| margin-bottom: 24rpx; | |||
| position: relative; | |||
| } | |||
| .avatar-upload { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| position: relative; | |||
| width: 120rpx; | |||
| height: 120rpx; | |||
| } | |||
| .avatar-main { | |||
| box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08); | |||
| } | |||
| .avatar-upload-btn { | |||
| position: absolute; | |||
| bottom: 0; | |||
| right: 0; | |||
| width: 48rpx; | |||
| height: 48rpx; | |||
| background: #0a226b; | |||
| border-radius: 50%; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); | |||
| border: 2rpx solid #fff; | |||
| } | |||
| .card { | |||
| background: #fff; | |||
| border-radius: 24rpx; | |||
| margin: 0 24rpx 32rpx 24rpx; | |||
| padding: 32rpx 28rpx 8rpx 28rpx; | |||
| box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.02); | |||
| text-align: left; | |||
| } | |||
| .card-title { | |||
| font-size: 28rpx; | |||
| font-weight: bold; | |||
| color: #222; | |||
| margin-bottom: 18rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-item { | |||
| margin-bottom: 8rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-label { | |||
| font-size: 22rpx; | |||
| color: #888; | |||
| margin-bottom: 4rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| } | |||
| .star { | |||
| color: #f44; | |||
| font-size: 22rpx; | |||
| margin-right: 4rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-value { | |||
| font-size: 26rpx; | |||
| color: #222; | |||
| font-weight: 500; | |||
| margin-bottom: 2rpx; | |||
| } | |||
| .divider { | |||
| height: 1px; | |||
| background: #f0f0f0; | |||
| margin: 8rpx 0 8rpx 0; | |||
| } | |||
| .footer { | |||
| position: fixed; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 90rpx; | |||
| margin: 0 24rpx; | |||
| } | |||
| </style> | |||
| @ -1,166 +1,244 @@ | |||
| <template> | |||
| <!-- 礼物盒页面 --> | |||
| <view class="giftbox-container"> | |||
| <navbar title="礼物盒" leftClick @leftClick="$utils.navigateBack" /> | |||
| <!-- 礼物列表 --> | |||
| <view class="gift-list"> | |||
| <view | |||
| v-for="(gift, idx) in gifts" | |||
| :key="gift.id" | |||
| :class="['gift-item', { selected: idx === selectedIndex }]" | |||
| @click="selectGift(idx)" | |||
| > | |||
| <view class="gift-img"> | |||
| <text class="gift-emoji">{{ gift.emoji }}</text> | |||
| </view> | |||
| <view class="gift-name">{{ gift.name }}</view> | |||
| <view class="gift-info"> | |||
| <text class="gift-count">x{{ gift.count }}</text> | |||
| <text class="gift-bean">{{ gift.price }}豆豆</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 底部操作栏 --> | |||
| <view class="giftbox-bottom"> | |||
| <view class="giftbox-left">剩余:{{ gifts[selectedIndex].count }} 个</view> | |||
| <view class="giftbox-buy"> | |||
| <button class="buy-btn" @click="buyGift">购买</button> | |||
| <uv-number-box v-model="buyCount" :min="1" :max="gifts[selectedIndex].count" /> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 礼物盒页面 --> | |||
| <view class="giftbox-container"> | |||
| <navbar title="礼物盒" leftClick @leftClick="$utils.navigateBack" /> | |||
| <!-- 礼物列表 --> | |||
| <view class="gift-list"> | |||
| <view v-for="(gift, idx) in gifts" :key="gift.id" | |||
| :class="['gift-item', { selected: idx === selectedIndex }]" @click="selectGift(idx)"> | |||
| <view class="gift-img"> | |||
| <text class="gift-emoji">{{ gift.emoji }}</text> | |||
| </view> | |||
| <view class="gift-name">{{ gift.name }}</view> | |||
| <view class="gift-info"> | |||
| <text class="gift-count">x{{ gift.count }}</text> | |||
| <text class="gift-bean">{{ gift.price }}豆豆</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 底部操作栏 --> | |||
| <view class="giftbox-bottom"> | |||
| <view class="giftbox-left">剩余:{{ gifts[selectedIndex].count }} 个</view> | |||
| <view class="giftbox-buy"> | |||
| <button class="buy-btn" @click="buyGift">购买</button> | |||
| <uv-number-box v-model="buyCount" :min="1" :max="gifts[selectedIndex].count" /> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import BackArrow from './components/BackArrow.vue'; | |||
| export default { | |||
| components: { | |||
| 'uv-navbar': () => import('@/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue'), | |||
| 'uv-number-box': () => import('@/uni_modules/uv-number-box/components/uv-number-box/uv-number-box.vue'), | |||
| BackArrow | |||
| }, | |||
| data() { | |||
| return { | |||
| gifts: [ | |||
| { id: 1, name: '小星星', emoji: '🌟', count: 6, price: 1 }, | |||
| { id: 2, name: '爱你哟', emoji: '🧡', count: 5, price: 1 }, | |||
| { id: 3, name: '加油鸭', emoji: '🦆', count: 5, price: 1 }, | |||
| { id: 4, name: '蓝色烟花', emoji: '🎆', count: 5, price: 1 }, | |||
| { id: 5, name: '沙滩椅', emoji: '🏖️', count: 5, price: 1 }, | |||
| { id: 6, name: '菠萝', emoji: '🍍', count: 5, price: 1 }, | |||
| { id: 7, name: '咖啡', emoji: '☕', count: 5, price: 1 }, | |||
| { id: 8, name: '早餐', emoji: '🥐', count: 5, price: 1 }, | |||
| { id: 9, name: '花花', emoji: '🌷', count: 5, price: 1 }, | |||
| { id: 10, name: '玫瑰', emoji: '🌹', count: 5, price: 1 }, | |||
| { id: 11, name: '玫瑰花', emoji: '🥀', count: 5, price: 1 }, | |||
| { id: 12, name: '跑车', emoji: '🏎️', count: 5, price: 1 }, | |||
| ], | |||
| selectedIndex: 0, | |||
| buyCount: 1, | |||
| } | |||
| }, | |||
| methods: { | |||
| selectGift(idx) { | |||
| this.selectedIndex = idx | |||
| this.buyCount = 1 | |||
| }, | |||
| buyGift() { | |||
| // 跳转到礼物购买页面,并传递选中礼物信息 | |||
| const gift = this.gifts[this.selectedIndex] | |||
| uni.navigateTo({ | |||
| url: `/pages_order/novel/Giftpurchases?name=${encodeURIComponent(gift.name)}&price=${gift.price}&count=${this.buyCount}` | |||
| }) | |||
| }, | |||
| }, | |||
| } | |||
| import BackArrow from './components/BackArrow.vue'; | |||
| export default { | |||
| components: { | |||
| 'uv-navbar': () => import('@/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue'), | |||
| 'uv-number-box': () => import('@/uni_modules/uv-number-box/components/uv-number-box/uv-number-box.vue'), | |||
| BackArrow | |||
| }, | |||
| data() { | |||
| return { | |||
| gifts: [{ | |||
| id: 1, | |||
| name: '小星星', | |||
| emoji: '🌟', | |||
| count: 6, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 2, | |||
| name: '爱你哟', | |||
| emoji: '🧡', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 3, | |||
| name: '加油鸭', | |||
| emoji: '🦆', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 4, | |||
| name: '蓝色烟花', | |||
| emoji: '🎆', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 5, | |||
| name: '沙滩椅', | |||
| emoji: '🏖️', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 6, | |||
| name: '菠萝', | |||
| emoji: '🍍', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 7, | |||
| name: '咖啡', | |||
| emoji: '☕', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 8, | |||
| name: '早餐', | |||
| emoji: '🥐', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 9, | |||
| name: '花花', | |||
| emoji: '🌷', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 10, | |||
| name: '玫瑰', | |||
| emoji: '🌹', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 11, | |||
| name: '玫瑰花', | |||
| emoji: '🥀', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| { | |||
| id: 12, | |||
| name: '跑车', | |||
| emoji: '🏎️', | |||
| count: 5, | |||
| price: 1 | |||
| }, | |||
| ], | |||
| selectedIndex: 0, | |||
| buyCount: 1, | |||
| } | |||
| }, | |||
| methods: { | |||
| selectGift(idx) { | |||
| this.selectedIndex = idx | |||
| this.buyCount = 1 | |||
| }, | |||
| buyGift() { | |||
| // 跳转到礼物购买页面,并传递选中礼物信息 | |||
| const gift = this.gifts[this.selectedIndex] | |||
| uni.navigateTo({ | |||
| url: `/pages_order/novel/Giftpurchases?name=${encodeURIComponent(gift.name)}&price=${gift.price}&count=${this.buyCount}` | |||
| }) | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .giftbox-container { | |||
| min-height: 100vh; | |||
| background: #f8f8f8; | |||
| padding-bottom: 120rpx; | |||
| } | |||
| .gift-list { | |||
| display: flex; | |||
| flex-wrap: wrap; | |||
| gap: 24rpx; | |||
| padding: 32rpx 16rpx 0 16rpx; | |||
| } | |||
| .gift-item { | |||
| width: 30%; | |||
| background: #fff; | |||
| border-radius: 18rpx; | |||
| box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03); | |||
| margin-bottom: 24rpx; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| padding: 24rpx 0 16rpx 0; | |||
| border: 2rpx solid transparent; | |||
| transition: border 0.2s; | |||
| } | |||
| .gift-item.selected { | |||
| border: 2rpx solid #223a7a; | |||
| box-shadow: 0 4rpx 16rpx 0 rgba(34,58,122,0.08); | |||
| } | |||
| .gift-img { | |||
| width: 80rpx; | |||
| height: 80rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| margin-bottom: 8rpx; | |||
| } | |||
| .gift-emoji { | |||
| font-size: 56rpx; | |||
| } | |||
| .gift-name { | |||
| font-size: 28rpx; | |||
| color: #222; | |||
| margin-bottom: 4rpx; | |||
| } | |||
| .gift-info { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 8rpx; | |||
| font-size: 22rpx; | |||
| color: #888; | |||
| } | |||
| .giftbox-bottom { | |||
| position: fixed; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 90rpx; | |||
| background: #fff; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| height: 100rpx; | |||
| padding: 0 32rpx; | |||
| box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05); | |||
| z-index: 10; | |||
| } | |||
| .giftbox-left { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| } | |||
| .giftbox-buy { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 18rpx; | |||
| } | |||
| .buy-btn { | |||
| background: #223a7a; | |||
| color: #fff; | |||
| font-size: 28rpx; | |||
| border-radius: 32rpx; | |||
| padding: 0 36rpx; | |||
| height: 68rpx; | |||
| line-height: 68rpx; | |||
| border: none; | |||
| } | |||
| </style> | |||
| .giftbox-container { | |||
| min-height: 100vh; | |||
| background: #f8f8f8; | |||
| padding-bottom: 120rpx; | |||
| } | |||
| .gift-list { | |||
| display: flex; | |||
| flex-wrap: wrap; | |||
| gap: 24rpx; | |||
| padding: 32rpx 16rpx 0 16rpx; | |||
| } | |||
| .gift-item { | |||
| width: 30%; | |||
| background: #fff; | |||
| border-radius: 18rpx; | |||
| box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03); | |||
| margin-bottom: 24rpx; | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| padding: 24rpx 0 16rpx 0; | |||
| border: 2rpx solid transparent; | |||
| transition: border 0.2s; | |||
| } | |||
| .gift-item.selected { | |||
| border: 2rpx solid #223a7a; | |||
| box-shadow: 0 4rpx 16rpx 0 rgba(34, 58, 122, 0.08); | |||
| } | |||
| .gift-img { | |||
| width: 80rpx; | |||
| height: 80rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| margin-bottom: 8rpx; | |||
| } | |||
| .gift-emoji { | |||
| font-size: 56rpx; | |||
| } | |||
| .gift-name { | |||
| font-size: 28rpx; | |||
| color: #222; | |||
| margin-bottom: 4rpx; | |||
| } | |||
| .gift-info { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 8rpx; | |||
| font-size: 22rpx; | |||
| color: #888; | |||
| } | |||
| .giftbox-bottom { | |||
| position: fixed; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 90rpx; | |||
| background: #fff; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| height: 100rpx; | |||
| padding: 0 32rpx; | |||
| box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05); | |||
| z-index: 10; | |||
| } | |||
| .giftbox-left { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| } | |||
| .giftbox-buy { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 18rpx; | |||
| } | |||
| .buy-btn { | |||
| background: #223a7a; | |||
| color: #fff; | |||
| font-size: 28rpx; | |||
| border-radius: 32rpx; | |||
| padding: 0 36rpx; | |||
| height: 68rpx; | |||
| line-height: 68rpx; | |||
| border: none; | |||
| } | |||
| </style> | |||
| @ -1,185 +0,0 @@ | |||
| <template> | |||
| <view class="modify-info-page"> | |||
| <navbar title="修改信息" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="header"> | |||
| <view class="avatar-upload"> | |||
| <uv-avatar :src="avatarUrl" size="88" shape="circle" @click="showUpload = true" class="avatar-main" /> | |||
| <view class="avatar-upload-btn" @click="showUpload = true"> | |||
| <uv-icon name="camera-fill" size="28" color="#fff" /> | |||
| </view> | |||
| <uv-upload | |||
| v-if="showUpload" | |||
| :fileList="fileList" | |||
| :maxCount="1" | |||
| accept="image" | |||
| :previewImage="false" | |||
| :deletable="false" | |||
| :showUploadList="false" | |||
| @afterRead="onAvatarChange" | |||
| @delete="onAvatarDelete" | |||
| /> | |||
| </view> | |||
| </view> | |||
| <view class="card"> | |||
| <view class="card-title">个人信息</view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 昵称</view> | |||
| <view class="form-value">{{ form.nickname }}</view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 个性签名</view> | |||
| <view class="form-value">{{ form.signature }}</view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| </view> | |||
| <view class="card"> | |||
| <view class="card-title">手机号</view> | |||
| <view class="form-item"> | |||
| <view class="form-label"><text class="star">*</text> 手机号</view> | |||
| <view class="form-value">{{ form.phone }}</view> | |||
| </view> | |||
| <view class="divider"></view> | |||
| </view> | |||
| <view class="footer"> | |||
| <uv-button type="primary" text="确认" shape="circle" size="large" @click="onSubmit" customStyle="width:100%;height:44px;font-size:18px;background:#0a226b;" /> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import BackArrow from './components/BackArrow.vue' | |||
| export default { | |||
| components: { BackArrow }, | |||
| data() { | |||
| return { | |||
| avatarUrl: '', | |||
| fileList: [], | |||
| showUpload: false, | |||
| form: { | |||
| nickname: '战斗世界', | |||
| signature: '世界这么美,小说好精彩~', | |||
| phone: '19989674531' | |||
| } | |||
| } | |||
| }, | |||
| methods: { | |||
| goBack() { | |||
| uni.navigateBack() | |||
| }, | |||
| onAvatarChange(file) { | |||
| this.avatarUrl = file.file.url | |||
| this.fileList = [file.file] | |||
| this.showUpload = false | |||
| }, | |||
| onAvatarDelete() { | |||
| this.avatarUrl = '' | |||
| this.fileList = [] | |||
| }, | |||
| onSubmit() { | |||
| uni.showToast({ title: '提交成功', icon: 'success' }) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| .modify-info-page { | |||
| min-height: 100vh; | |||
| background: #f8f8f8; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .back-arrow-fix { | |||
| position: absolute; | |||
| top: 60rpx; | |||
| left: 32rpx; | |||
| z-index: 1000; | |||
| } | |||
| .header { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| margin-top: 120rpx; | |||
| margin-bottom: 24rpx; | |||
| position: relative; | |||
| } | |||
| .avatar-upload { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| position: relative; | |||
| width: 120rpx; | |||
| height: 120rpx; | |||
| } | |||
| .avatar-main { | |||
| box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08); | |||
| } | |||
| .avatar-upload-btn { | |||
| position: absolute; | |||
| bottom: 0; | |||
| right: 0; | |||
| width: 48rpx; | |||
| height: 48rpx; | |||
| background: #0a226b; | |||
| border-radius: 50%; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.08); | |||
| border: 2rpx solid #fff; | |||
| } | |||
| .card { | |||
| background: #fff; | |||
| border-radius: 24rpx; | |||
| margin: 0 24rpx 32rpx 24rpx; | |||
| padding: 32rpx 28rpx 8rpx 28rpx; | |||
| box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.02); | |||
| } | |||
| .card-title { | |||
| font-size: 28rpx; | |||
| font-weight: bold; | |||
| color: #222; | |||
| margin-bottom: 18rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-item { | |||
| margin-bottom: 8rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-label { | |||
| font-size: 22rpx; | |||
| color: #888; | |||
| margin-bottom: 4rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| } | |||
| .star { | |||
| color: #f44; | |||
| font-size: 22rpx; | |||
| margin-right: 4rpx; | |||
| margin-top: 18rpx; | |||
| } | |||
| .form-value { | |||
| font-size: 26rpx; | |||
| color: #222; | |||
| font-weight: 500; | |||
| margin-bottom: 2rpx; | |||
| } | |||
| .divider { | |||
| height: 1px; | |||
| background: #f0f0f0; | |||
| margin: 8rpx 0 8rpx 0; | |||
| } | |||
| .footer { | |||
| position: fixed; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 90rpx; | |||
| margin: 0 24rpx; | |||
| } | |||
| </style> | |||
| @ -1,356 +1,328 @@ | |||
| <template> | |||
| <!-- 新建作品页面 --> | |||
| <view class="create-novel"> | |||
| <navbar title="新建作品" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="form-container"> | |||
| <!-- 封面信息 --> | |||
| <view class="section"> | |||
| <view class="section-title">封面信息</view> | |||
| <view class="upload-cover"> | |||
| <view class="sub-title">上传封面</view> | |||
| <view class="cover-box" @click="chooseCover"> | |||
| <image v-if="formData.cover" :src="formData.cover" mode="aspectFill" class="cover-image"></image> | |||
| <view v-else class="upload-placeholder"> | |||
| <text class="plus">+</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 作品信息 --> | |||
| <view class="section"> | |||
| <view class="section-title">作品信息</view> | |||
| <view class="form-item"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品名称</text> | |||
| <input | |||
| type="text" | |||
| v-model="formData.title" | |||
| placeholder="请输入" | |||
| placeholder-class="input-placeholder" | |||
| /> | |||
| </view> | |||
| <view class="form-item"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品类型</text> | |||
| <input | |||
| type="text" | |||
| v-model="formData.type" | |||
| placeholder="请输入" | |||
| placeholder-class="input-placeholder" | |||
| /> | |||
| </view> | |||
| <view class="form-item"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品简介</text> | |||
| <textarea | |||
| v-model="formData.description" | |||
| placeholder="请输入" | |||
| placeholder-class="input-placeholder" | |||
| :maxlength="500" | |||
| ></textarea> | |||
| </view> | |||
| <view class="form-item"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品状态</text> | |||
| <view class="status-options"> | |||
| <view | |||
| class="status-item" | |||
| :class="{ active: formData.status === 'serial' }" | |||
| @click="formData.status = 'serial'" | |||
| > | |||
| <view class="radio-dot" :class="{ checked: formData.status === 'serial' }"></view> | |||
| <text>连载</text> | |||
| </view> | |||
| <view | |||
| class="status-item" | |||
| :class="{ active: formData.status === 'completed' }" | |||
| @click="formData.status = 'completed'" | |||
| > | |||
| <view class="radio-dot" :class="{ checked: formData.status === 'completed' }"></view> | |||
| <text>完结</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 书籍信息 --> | |||
| <view class="section"> | |||
| <view class="section-title">书籍信息</view> | |||
| <view class="form-item"> | |||
| <text class="label">书号</text> | |||
| <text class="value">9999993339393</text> | |||
| </view> | |||
| <view class="form-item"> | |||
| <text class="label">总字数</text> | |||
| <text class="value">99999999</text> | |||
| </view> | |||
| </view> | |||
| <!-- 提交按钮 --> | |||
| <view class="submit-btn" @click="submitForm">提交申请</view> | |||
| </view> | |||
| </view> | |||
| <!-- 新建作品页面 --> | |||
| <view class="create-novel"> | |||
| <navbar title="新建作品" leftClick @leftClick="$utils.navigateBack" /> | |||
| <view class="form-container"> | |||
| <!-- 封面信息 --> | |||
| <view class="section"> | |||
| <view class="section-title">封面信息</view> | |||
| <view class="upload-cover"> | |||
| <view class="sub-title">上传封面</view> | |||
| <view class="cover-box" @click="chooseCover"> | |||
| <image v-if="formData.Image" :src="formData.Image" mode="aspectFill" class="cover-image"> | |||
| </image> | |||
| <view v-else class="upload-placeholder"> | |||
| <text class="plus">+</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 作品信息 --> | |||
| <view class="section"> | |||
| <view class="section-title">作品信息</view> | |||
| <view class="form-item"> | |||
| <view style="display: flex;"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品名称</text> | |||
| </view> | |||
| <input type="text" v-model="formData.name" placeholder="请输入" | |||
| placeholder-class="input-placeholder" /> | |||
| </view> | |||
| <view class="form-item"> | |||
| <view style="display: flex;"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品类型</text> | |||
| </view> | |||
| <input type="text" | |||
| disabled | |||
| v-model="formData.type" placeholder="请输入" | |||
| placeholder-class="input-placeholder" /> | |||
| </view> | |||
| <view class="form-item"> | |||
| <view style="display: flex;"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品简介</text> | |||
| </view> | |||
| <textarea v-model="formData.details" placeholder="请输入" placeholder-class="input-placeholder" | |||
| :maxlength="500"></textarea> | |||
| </view> | |||
| <view class="form-item"> | |||
| <view style="display: flex;"> | |||
| <text class="required">*</text> | |||
| <text class="label">作品状态</text> | |||
| </view> | |||
| <view class="status-options"> | |||
| <view class="status-item" :class="{ active: formData.status == '0' }" | |||
| @click="formData.status = '0'"> | |||
| <view class="radio-dot" :class="{ checked: formData.status == '0' }"></view> | |||
| <text>连载</text> | |||
| </view> | |||
| <view class="status-item" :class="{ active: formData.status == '1' }" | |||
| @click="formData.status = '1'"> | |||
| <view class="radio-dot" :class="{ checked: formData.status == '1' }"></view> | |||
| <text>完结</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <!-- 书籍信息 --> | |||
| <view class="section" v-if="formData.id"> | |||
| <view class="section-title">书籍信息</view> | |||
| <view class="form-item"> | |||
| <text class="label">书号</text> | |||
| <text class="value">9999993339393</text> | |||
| </view> | |||
| <view class="form-item"> | |||
| <text class="label">总字数</text> | |||
| <text class="value">99999999</text> | |||
| </view> | |||
| </view> | |||
| <!-- 提交按钮 --> | |||
| <view class="submit-btn" @click="submitForm">提交申请</view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| components: { | |||
| 'uv-navbar': () => import('@/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue') | |||
| }, | |||
| data() { | |||
| return { | |||
| formData: { | |||
| cover: '', | |||
| title: '', | |||
| type: '', | |||
| description: '', | |||
| status: 'serial' // 默认连载 | |||
| } | |||
| } | |||
| }, | |||
| methods: { | |||
| // 选择封面 | |||
| chooseCover() { | |||
| uni.chooseImage({ | |||
| count: 1, | |||
| success: (res) => { | |||
| this.formData.cover = res.tempFilePaths[0] | |||
| } | |||
| }) | |||
| }, | |||
| // 提交表单 | |||
| submitForm() { | |||
| if (!this.formData.title) { | |||
| uni.showToast({ | |||
| title: '请输入作品名称', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (!this.formData.type) { | |||
| uni.showToast({ | |||
| title: '请输入作品类型', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (!this.formData.description) { | |||
| uni.showToast({ | |||
| title: '请输入作品简介', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 构建作品数据 | |||
| const workData = { | |||
| id: Date.now().toString(), | |||
| title: this.formData.title, | |||
| cover: this.formData.cover || 'https://bookcover.yuewen.com/qdbimg/349573/1033014772/150.webp', | |||
| type: this.formData.type, | |||
| description: this.formData.description, | |||
| status: this.formData.status, | |||
| readers: '0', | |||
| publishStatus: '发布审核中', | |||
| isOriginal: true, | |||
| chapters: [], | |||
| author: '当前用户', // 添加作者信息 | |||
| tags: [this.formData.type], // 添加标签 | |||
| updateTime: new Date().getTime() // 添加更新时间 | |||
| } | |||
| // 获取现有的作品列表 | |||
| let worksList = uni.getStorageSync('worksList') || [] | |||
| // 添加新作品 | |||
| worksList.unshift(workData) // 使用unshift确保新作品显示在最前面 | |||
| // 保存到本地存储 | |||
| uni.setStorageSync('worksList', worksList) | |||
| // 保存到全局状态 | |||
| getApp().globalData.submittedWork = workData | |||
| // 设置需要显示提交成功提示的标记 | |||
| getApp().globalData.showSubmitSuccess = true | |||
| // 显示成功提示 | |||
| uni.showToast({ | |||
| title: '创建成功', | |||
| icon: 'success' | |||
| }) | |||
| // 延迟返回上一页 | |||
| setTimeout(() => { | |||
| // 先保存当前要显示的标签 | |||
| uni.setStorageSync('activeBookshelfTab', 'work') | |||
| // 返回上一页 | |||
| uni.navigateBack({ | |||
| delta: 1 | |||
| }) | |||
| }, 500) | |||
| } | |||
| } | |||
| } | |||
| export default { | |||
| data() { | |||
| return { | |||
| formData: { | |||
| Image: '', | |||
| title: '', | |||
| type: '1', | |||
| details: '', | |||
| status: '0' // 默认连载 | |||
| } | |||
| } | |||
| }, | |||
| methods: { | |||
| // 选择封面 | |||
| chooseCover() { | |||
| uni.chooseImage({ | |||
| count: 1, | |||
| success: (res) => { | |||
| this.$Oss.ossUpload(res.tempFilePaths[0]) | |||
| .then(url => { | |||
| this.formData.Image = url | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| // 提交表单 | |||
| async submitForm() { | |||
| if (!this.formData.name) { | |||
| uni.showToast({ | |||
| title: '请输入作品名称', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (!this.formData.type) { | |||
| uni.showToast({ | |||
| title: '请输入作品类型', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| if (!this.formData.details) { | |||
| uni.showToast({ | |||
| title: '请输入作品简介', | |||
| icon: 'none' | |||
| }) | |||
| return | |||
| } | |||
| // 构建作品数据 | |||
| const workData = { | |||
| name: this.formData.name, | |||
| Image: this.formData.Image, | |||
| type: this.formData.type, | |||
| details: this.formData.details, | |||
| status: this.formData.status, | |||
| } | |||
| await this.$fetch('saveOrUpdateBook', workData) | |||
| // 延迟返回上一页 | |||
| setTimeout(() => { | |||
| // 先保存当前要显示的标签 | |||
| uni.setStorageSync('activeBookshelfTab', 'work') | |||
| // 返回上一页 | |||
| uni.navigateBack({ | |||
| delta: 1 | |||
| }) | |||
| }, 500) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss"> | |||
| .create-novel { | |||
| min-height: 100vh; | |||
| background-color: #F8F8F8; | |||
| .form-container { | |||
| padding: 20rpx; | |||
| .section { | |||
| background-color: #FFFFFF; | |||
| border-radius: 12rpx; | |||
| padding: 30rpx; | |||
| margin-bottom: 20rpx; | |||
| .section-title { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 30rpx; | |||
| } | |||
| .upload-cover { | |||
| .sub-title { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| margin-bottom: 20rpx; | |||
| } | |||
| .cover-box { | |||
| width: 200rpx; | |||
| height: 266rpx; | |||
| background-color: #F5F5F5; | |||
| border-radius: 8rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| overflow: hidden; | |||
| .cover-image { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .upload-placeholder { | |||
| .plus { | |||
| font-size: 60rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .form-item { | |||
| margin-bottom: 30rpx; | |||
| position: relative; | |||
| &:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| .required { | |||
| color: #FF0000; | |||
| margin-right: 4rpx; | |||
| } | |||
| .label { | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| margin-bottom: 16rpx; | |||
| display: block; | |||
| } | |||
| input, textarea { | |||
| width: 100%; | |||
| height: 80rpx; | |||
| background-color: #F5F5F5; | |||
| border-radius: 8rpx; | |||
| padding: 20rpx; | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| box-sizing: border-box; | |||
| position: relative; | |||
| z-index: 1; | |||
| } | |||
| textarea { | |||
| height: 200rpx; | |||
| } | |||
| .input-placeholder { | |||
| color: #999; | |||
| } | |||
| .status-options { | |||
| display: flex; | |||
| gap: 40rpx; | |||
| .status-item { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 10rpx; | |||
| .radio-dot { | |||
| width: 32rpx; | |||
| height: 32rpx; | |||
| border: 2rpx solid #999; | |||
| border-radius: 50%; | |||
| position: relative; | |||
| &.checked { | |||
| border-color: #001351; | |||
| &::after { | |||
| content: ''; | |||
| position: absolute; | |||
| width: 20rpx; | |||
| height: 20rpx; | |||
| background-color: #001351; | |||
| border-radius: 50%; | |||
| left: 50%; | |||
| top: 50%; | |||
| transform: translate(-50%, -50%); | |||
| } | |||
| } | |||
| } | |||
| text { | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| } | |||
| } | |||
| } | |||
| .value { | |||
| font-size: 28rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| .submit-btn { | |||
| background-color: #001351; | |||
| color: #FFFFFF; | |||
| font-size: 32rpx; | |||
| text-align: center; | |||
| padding: 24rpx 0; | |||
| border-radius: 12rpx; | |||
| margin-top: 40rpx; | |||
| &:active { | |||
| opacity: 0.9; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| .create-novel { | |||
| min-height: 100vh; | |||
| background-color: #F8F8F8; | |||
| .form-container { | |||
| padding: 20rpx; | |||
| .section { | |||
| background-color: #FFFFFF; | |||
| border-radius: 12rpx; | |||
| padding: 30rpx; | |||
| margin-bottom: 20rpx; | |||
| .section-title { | |||
| font-size: 32rpx; | |||
| font-weight: bold; | |||
| color: #333; | |||
| margin-bottom: 30rpx; | |||
| } | |||
| .upload-cover { | |||
| .sub-title { | |||
| font-size: 28rpx; | |||
| color: #666; | |||
| margin-bottom: 20rpx; | |||
| } | |||
| .cover-box { | |||
| width: 200rpx; | |||
| height: 266rpx; | |||
| background-color: #F5F5F5; | |||
| border-radius: 8rpx; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| overflow: hidden; | |||
| .cover-image { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .upload-placeholder { | |||
| .plus { | |||
| font-size: 60rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .form-item { | |||
| margin-bottom: 30rpx; | |||
| position: relative; | |||
| &:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| .required { | |||
| color: #FF0000; | |||
| margin-right: 4rpx; | |||
| } | |||
| .label { | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| margin-bottom: 16rpx; | |||
| display: block; | |||
| } | |||
| input, | |||
| textarea { | |||
| width: 100%; | |||
| height: 80rpx; | |||
| background-color: #F5F5F5; | |||
| border-radius: 8rpx; | |||
| padding: 20rpx; | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| box-sizing: border-box; | |||
| position: relative; | |||
| z-index: 1; | |||
| } | |||
| textarea { | |||
| height: 200rpx; | |||
| } | |||
| .input-placeholder { | |||
| color: #999; | |||
| } | |||
| .status-options { | |||
| display: flex; | |||
| gap: 40rpx; | |||
| .status-item { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 10rpx; | |||
| .radio-dot { | |||
| width: 32rpx; | |||
| height: 32rpx; | |||
| border: 2rpx solid #999; | |||
| border-radius: 50%; | |||
| position: relative; | |||
| &.checked { | |||
| border-color: #001351; | |||
| &::after { | |||
| content: ''; | |||
| position: absolute; | |||
| width: 20rpx; | |||
| height: 20rpx; | |||
| background-color: #001351; | |||
| border-radius: 50%; | |||
| left: 50%; | |||
| top: 50%; | |||
| transform: translate(-50%, -50%); | |||
| } | |||
| } | |||
| } | |||
| text { | |||
| font-size: 28rpx; | |||
| color: #333; | |||
| } | |||
| } | |||
| } | |||
| .value { | |||
| font-size: 28rpx; | |||
| color: #999; | |||
| } | |||
| } | |||
| } | |||
| .submit-btn { | |||
| background-color: #001351; | |||
| color: #FFFFFF; | |||
| font-size: 32rpx; | |||
| text-align: center; | |||
| padding: 24rpx 0; | |||
| border-radius: 12rpx; | |||
| margin-top: 40rpx; | |||
| &:active { | |||
| opacity: 0.9; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| </style> | |||