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

391 lines
8.1 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months 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 class="info-item">
  54. <text class="label">地址</text>
  55. <view class="value-container">
  56. <input
  57. class="address-input"
  58. v-model="userInfo.address"
  59. :placeholder="configParamText('config_rubric')"
  60. type="text"
  61. maxlength="11"
  62. />
  63. </view>
  64. </view>
  65. <!-- 地址 -->
  66. <!-- <view class="info-item">
  67. <text class="label">地址</text>
  68. <view class="value-container" @click="openMap">
  69. <text class="address-input">
  70. {{ userInfo.address || '请选择地址' }}
  71. </text>
  72. <text class="address-input" v-else>
  73. 请选择地址
  74. </text>
  75. </view>
  76. </view> -->
  77. </view>
  78. <!-- 保存按钮 -->
  79. <view class="save-section">
  80. <button class="save-button" @click="saveProfile">
  81. 保存
  82. </button>
  83. </view>
  84. </view>
  85. </template>
  86. <script>
  87. export default {
  88. name: 'MyProfile',
  89. data() {
  90. return {
  91. userInfo: {
  92. headImage: '',
  93. nickName: '',
  94. phone: '',
  95. address: ''
  96. }
  97. }
  98. },
  99. methods: {
  100. // 返回上一页
  101. goBack() {
  102. uni.navigateBack();
  103. },
  104. // 选择微信头像
  105. async onChooseAvatar(e) {
  106. console.log('选择头像回调', e);
  107. if (e.detail.avatarUrl) {
  108. const file = {
  109. path: e.detail.avatarUrl
  110. }
  111. const res = await this.$utils.uploadImage(file)
  112. this.userInfo.headImage = res.url
  113. uni.showToast({
  114. title: '头像更新成功',
  115. icon: 'success'
  116. });
  117. } else {
  118. uni.showToast({
  119. title: '头像选择失败',
  120. icon: 'none'
  121. });
  122. }
  123. },
  124. // 昵称输入失焦验证
  125. onNicknameBlur() {
  126. if (!this.userInfo.nickName.trim()) {
  127. uni.showToast({
  128. title: '请输入昵称',
  129. icon: 'none'
  130. });
  131. }
  132. },
  133. // 保存资料
  134. async saveProfile() {
  135. // 验证昵称
  136. if (!this.userInfo.nickName.trim()) {
  137. uni.showToast({
  138. title: '请输入昵称',
  139. icon: 'none'
  140. });
  141. return;
  142. }
  143. // 验证手机号(如果填写了)
  144. if (this.userInfo.phone && !/^1[3-9]\d{9}$/.test(this.userInfo.phone)) {
  145. uni.showToast({
  146. title: '请输入正确的手机号',
  147. icon: 'none'
  148. });
  149. return;
  150. }
  151. const res = await this.$api.user.updateUser({
  152. nickName: this.userInfo.nickName,
  153. phone: this.userInfo.phone,
  154. headImage: this.userInfo.headImage,
  155. address: this.userInfo.address
  156. })
  157. if (res.code === 200) {
  158. uni.showToast({
  159. title: `${res.message}`,
  160. icon: 'success'
  161. });
  162. setTimeout(() => {
  163. uni.navigateBack()
  164. }, 1000);
  165. }
  166. },
  167. // 获取个人信息
  168. async getUserInfo() {
  169. const res = await this.$api.user.queryUser()
  170. this.userInfo = {...this.userInfo, ...res.result}
  171. // this.userInfo = res.result
  172. },
  173. // 打开地图
  174. // openMap() {
  175. // uni.chooseLocation({
  176. // success: (res) => {
  177. // console.log('位置名称:' + res.name)
  178. // console.log('详细地址:' + res.address)
  179. // console.log('纬度:' + res.latitude)
  180. // console.log('经度:' + res.longitude)
  181. // this.userInfo.address = res.address || res.name
  182. // uni.showToast({
  183. // title: '地址更新成功',
  184. // icon: 'success'
  185. // });
  186. // },
  187. // fail: (err) => {
  188. // console.log(err);
  189. // uni.showToast({
  190. // title: `获取位置失败`,
  191. // icon: 'none'
  192. // })
  193. // }
  194. // })
  195. // }
  196. },
  197. onLoad() {
  198. this.getUserInfo();
  199. }
  200. }
  201. </script>
  202. <style lang="scss" scoped>
  203. .profile-container {
  204. min-height: 100vh;
  205. background-color: #f5f5f5;
  206. }
  207. .vertical-line {
  208. width: 9rpx;
  209. height: 33rpx;
  210. background-color: #1488DB;
  211. margin-right: 20rpx;
  212. }
  213. // 自定义导航栏
  214. .custom-navbar {
  215. background: linear-gradient(90deg, #1488db 0%, #1488db 100%);
  216. padding-top: var(--status-bar-height, 44rpx);
  217. .navbar-content {
  218. height: 88rpx;
  219. display: flex;
  220. align-items: center;
  221. justify-content: space-between;
  222. padding: 0 30rpx;
  223. .navbar-left {
  224. .back-icon {
  225. font-size: 40rpx;
  226. color: #ffffff;
  227. font-weight: bold;
  228. }
  229. }
  230. .navbar-title {
  231. font-size: 36rpx;
  232. color: #ffffff;
  233. font-weight: 500;
  234. }
  235. .navbar-right {
  236. display: flex;
  237. gap: 20rpx;
  238. .more-icon,
  239. .settings-icon {
  240. font-size: 32rpx;
  241. color: #ffffff;
  242. }
  243. }
  244. }
  245. }
  246. .section {
  247. margin: 20rpx;
  248. background-color: #ffffff;
  249. border-radius: 20rpx;
  250. overflow: hidden;
  251. .section-title {
  252. display: flex;
  253. align-items: center;
  254. padding: 30rpx;
  255. border-bottom: 1rpx solid #f0f0f0;
  256. .title-text {
  257. font-size: 32rpx;
  258. font-weight: 500;
  259. color: #333333;
  260. }
  261. }
  262. }
  263. .avatar-section {
  264. display: flex;
  265. flex-direction: column;
  266. align-items: center;
  267. padding: 40rpx 30rpx;
  268. border-bottom: 1rpx solid #f0f0f0;
  269. .avatar-button {
  270. padding: 0;
  271. margin: 0;
  272. background: transparent;
  273. border: none;
  274. outline: none;
  275. margin-bottom: 20rpx;
  276. &::after {
  277. border: none;
  278. }
  279. .avatar {
  280. width: 160rpx;
  281. height: 160rpx;
  282. border-radius: 80rpx;
  283. border: 4rpx dashed #cccccc;
  284. }
  285. }
  286. .avatar-tip {
  287. font-size: 26rpx;
  288. color: #999999;
  289. }
  290. }
  291. .info-item {
  292. display: flex;
  293. align-items: center;
  294. justify-content: space-between;
  295. padding: 30rpx;
  296. border-bottom: 1rpx solid #f0f0f0;
  297. &:last-child {
  298. border-bottom: none;
  299. }
  300. .label {
  301. font-size: 30rpx;
  302. color: #333333;
  303. font-weight: 500;
  304. width: 120rpx;
  305. }
  306. .value-container {
  307. flex: 1;
  308. display: flex;
  309. align-items: center;
  310. justify-content: flex-end;
  311. .nickname-input,
  312. .phone-input,
  313. .address-input {
  314. width: 100%;
  315. text-align: right;
  316. font-size: 30rpx;
  317. color: #666666;
  318. border: none;
  319. outline: none;
  320. background: transparent;
  321. &::placeholder {
  322. color: #cccccc;
  323. }
  324. }
  325. }
  326. }
  327. .save-section {
  328. padding: 40rpx 20rpx;
  329. .save-button {
  330. width: 100%;
  331. height: 88rpx;
  332. background-color: #1488db;
  333. border-radius: 44rpx;
  334. border: none;
  335. outline: none;
  336. font-size: 32rpx;
  337. font-weight: 500;
  338. color: #ffffff;
  339. display: flex;
  340. align-items: center;
  341. justify-content: center;
  342. &::after {
  343. border: none;
  344. }
  345. }
  346. }
  347. </style>