木邻有你前端代码仓库
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.

344 lines
6.9 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. <template>
  2. <view class="profile-container">
  3. <!-- 基本资料 -->
  4. <view class="section">
  5. <view class="section-title">
  6. <!-- 小竖线 -->
  7. <view class="vertical-line"></view>
  8. <view>
  9. <text class="title-text">基本资料</text>
  10. </view>
  11. </view>
  12. <!-- 头像 -->
  13. <view class="avatar-section">
  14. <button
  15. class="avatar-button"
  16. open-type="chooseAvatar"
  17. @chooseavatar="onChooseAvatar"
  18. >
  19. <image
  20. class="avatar"
  21. :src="userInfo.headImage || '/static/待上传头像.png'"
  22. mode="aspectFill"
  23. ></image>
  24. </button>
  25. <text class="avatar-tip">点击更换头像</text>
  26. </view>
  27. <!-- 昵称 -->
  28. <view class="info-item">
  29. <text class="label">昵称</text>
  30. <view class="value-container">
  31. <input
  32. class="nickname-input"
  33. v-model="userInfo.nickName"
  34. placeholder="请输入"
  35. type="nickname"
  36. @blur="onNicknameBlur"
  37. />
  38. </view>
  39. </view>
  40. <!-- 手机号 -->
  41. <view class="info-item">
  42. <text class="label">手机号</text>
  43. <view class="value-container">
  44. <input
  45. class="phone-input"
  46. v-model="userInfo.phone"
  47. placeholder="请输入"
  48. type="number"
  49. maxlength="11"
  50. />
  51. </view>
  52. </view>
  53. </view>
  54. <!-- 保存按钮 -->
  55. <view class="save-section">
  56. <button class="save-button" @click="saveProfile">
  57. 保存
  58. </button>
  59. </view>
  60. </view>
  61. </template>
  62. <script>
  63. export default {
  64. name: 'MyProfile',
  65. data() {
  66. return {
  67. userInfo: {
  68. headImage: '',
  69. nickName: '',
  70. phone: ''
  71. }
  72. }
  73. },
  74. methods: {
  75. // 返回上一页
  76. goBack() {
  77. uni.navigateBack();
  78. },
  79. // 加载用户资料
  80. // loadUserProfile() {
  81. // // 从本地存储获取用户资料
  82. // const storedUserInfo = uni.getStorageSync('userInfo');
  83. // if (storedUserInfo) {
  84. // this.userInfo = { ...this.userInfo, ...storedUserInfo };
  85. // }
  86. // },
  87. // 选择微信头像
  88. async onChooseAvatar(e) {
  89. console.log('选择头像回调', e);
  90. if (e.detail.avatarUrl) {
  91. // this.userInfo.headImage = e.detail.avatarUrl;
  92. // console.log('头像设置成功', e.detail.avatarUrl);
  93. const file = {
  94. path: e.detail.avatarUrl
  95. }
  96. const res = await this.$utils.uploadImage(file)
  97. this.userInfo.headImage = res.url
  98. uni.showToast({
  99. title: '头像更新成功',
  100. icon: 'success'
  101. });
  102. } else {
  103. uni.showToast({
  104. title: '头像选择失败',
  105. icon: 'none'
  106. });
  107. }
  108. },
  109. // 昵称输入失焦验证
  110. onNicknameBlur() {
  111. if (!this.userInfo.nickName.trim()) {
  112. uni.showToast({
  113. title: '请输入昵称',
  114. icon: 'none'
  115. });
  116. }
  117. },
  118. // 保存资料
  119. async saveProfile() {
  120. // 验证昵称
  121. if (!this.userInfo.nickName.trim()) {
  122. uni.showToast({
  123. title: '请输入昵称',
  124. icon: 'none'
  125. });
  126. return;
  127. }
  128. // 验证手机号(如果填写了)
  129. if (this.userInfo.phone && !/^1[3-9]\d{9}$/.test(this.userInfo.phone)) {
  130. uni.showToast({
  131. title: '请输入正确的手机号',
  132. icon: 'none'
  133. });
  134. return;
  135. }
  136. const res = await this.$api.user.updateUser({
  137. nickName: this.userInfo.nickName,
  138. phone: this.userInfo.phone,
  139. headImage: this.userInfo.headImage
  140. })
  141. if (res.code === 200) {
  142. uni.showToast({
  143. title: `${res.message}`,
  144. icon: 'success'
  145. });
  146. setTimeout(() => {
  147. uni.navigateBack()
  148. }, 1000);
  149. }
  150. },
  151. // 获取个人信息
  152. async getUserInfo() {
  153. const res = await this.$api.user.queryUser()
  154. this.userInfo = res.result
  155. }
  156. },
  157. onShow() {
  158. this.getUserInfo();
  159. }
  160. }
  161. </script>
  162. <style lang="scss" scoped>
  163. .profile-container {
  164. min-height: 100vh;
  165. background-color: #f5f5f5;
  166. }
  167. .vertical-line {
  168. width: 9rpx;
  169. height: 33rpx;
  170. background-color: #1488DB;
  171. margin-right: 20rpx;
  172. }
  173. // 自定义导航栏
  174. .custom-navbar {
  175. background: linear-gradient(90deg, #1488db 0%, #1488db 100%);
  176. padding-top: var(--status-bar-height, 44rpx);
  177. .navbar-content {
  178. height: 88rpx;
  179. display: flex;
  180. align-items: center;
  181. justify-content: space-between;
  182. padding: 0 30rpx;
  183. .navbar-left {
  184. .back-icon {
  185. font-size: 40rpx;
  186. color: #ffffff;
  187. font-weight: bold;
  188. }
  189. }
  190. .navbar-title {
  191. font-size: 36rpx;
  192. color: #ffffff;
  193. font-weight: 500;
  194. }
  195. .navbar-right {
  196. display: flex;
  197. gap: 20rpx;
  198. .more-icon,
  199. .settings-icon {
  200. font-size: 32rpx;
  201. color: #ffffff;
  202. }
  203. }
  204. }
  205. }
  206. .section {
  207. margin: 20rpx;
  208. background-color: #ffffff;
  209. border-radius: 20rpx;
  210. overflow: hidden;
  211. .section-title {
  212. display: flex;
  213. align-items: center;
  214. padding: 30rpx;
  215. border-bottom: 1rpx solid #f0f0f0;
  216. .title-text {
  217. font-size: 32rpx;
  218. font-weight: 500;
  219. color: #333333;
  220. }
  221. }
  222. }
  223. .avatar-section {
  224. display: flex;
  225. flex-direction: column;
  226. align-items: center;
  227. padding: 40rpx 30rpx;
  228. border-bottom: 1rpx solid #f0f0f0;
  229. .avatar-button {
  230. padding: 0;
  231. margin: 0;
  232. background: transparent;
  233. border: none;
  234. outline: none;
  235. margin-bottom: 20rpx;
  236. &::after {
  237. border: none;
  238. }
  239. .avatar {
  240. width: 160rpx;
  241. height: 160rpx;
  242. border-radius: 80rpx;
  243. border: 4rpx dashed #cccccc;
  244. }
  245. }
  246. .avatar-tip {
  247. font-size: 26rpx;
  248. color: #999999;
  249. }
  250. }
  251. .info-item {
  252. display: flex;
  253. align-items: center;
  254. justify-content: space-between;
  255. padding: 30rpx;
  256. border-bottom: 1rpx solid #f0f0f0;
  257. &:last-child {
  258. border-bottom: none;
  259. }
  260. .label {
  261. font-size: 30rpx;
  262. color: #333333;
  263. font-weight: 500;
  264. width: 120rpx;
  265. }
  266. .value-container {
  267. flex: 1;
  268. display: flex;
  269. align-items: center;
  270. justify-content: flex-end;
  271. .nickname-input,
  272. .phone-input {
  273. width: 100%;
  274. text-align: right;
  275. font-size: 30rpx;
  276. color: #666666;
  277. border: none;
  278. outline: none;
  279. background: transparent;
  280. &::placeholder {
  281. color: #cccccc;
  282. }
  283. }
  284. }
  285. }
  286. .save-section {
  287. padding: 40rpx 20rpx;
  288. .save-button {
  289. width: 100%;
  290. height: 88rpx;
  291. background-color: #1488db;
  292. border-radius: 44rpx;
  293. border: none;
  294. outline: none;
  295. font-size: 32rpx;
  296. font-weight: 500;
  297. color: #ffffff;
  298. display: flex;
  299. align-items: center;
  300. justify-content: center;
  301. &::after {
  302. border: none;
  303. }
  304. }
  305. }
  306. </style>