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

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