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

403 lines
8.4 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
1 month ago
2 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.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. if (!userInfo.area) {
  198. userInfo.area = ''
  199. }
  200. }
  201. },
  202. onLoad() {
  203. if (uni.getStorageSync('token')) {
  204. this.getUserInfo();
  205. }else {
  206. uni.redirectTo({
  207. url: '/subPages/login/login'
  208. })
  209. }
  210. }
  211. }
  212. </script>
  213. <style lang="scss" scoped>
  214. .profile-container {
  215. min-height: 100vh;
  216. background-color: #f5f5f5;
  217. }
  218. .vertical-line {
  219. width: 9rpx;
  220. height: 33rpx;
  221. background-color: #1488DB;
  222. margin-right: 20rpx;
  223. }
  224. // 自定义导航栏
  225. .custom-navbar {
  226. background: linear-gradient(90deg, #1488db 0%, #1488db 100%);
  227. padding-top: var(--status-bar-height, 44rpx);
  228. .navbar-content {
  229. height: 88rpx;
  230. display: flex;
  231. align-items: center;
  232. justify-content: space-between;
  233. padding: 0 30rpx;
  234. .navbar-left {
  235. .back-icon {
  236. font-size: 40rpx;
  237. color: #ffffff;
  238. font-weight: bold;
  239. }
  240. }
  241. .navbar-title {
  242. font-size: 36rpx;
  243. color: #ffffff;
  244. font-weight: 500;
  245. }
  246. .navbar-right {
  247. display: flex;
  248. gap: 20rpx;
  249. .more-icon,
  250. .settings-icon {
  251. font-size: 32rpx;
  252. color: #ffffff;
  253. }
  254. }
  255. }
  256. }
  257. .section {
  258. margin: 20rpx;
  259. background-color: #ffffff;
  260. border-radius: 20rpx;
  261. overflow: hidden;
  262. .section-title {
  263. display: flex;
  264. align-items: center;
  265. padding: 30rpx;
  266. border-bottom: 1rpx solid #f0f0f0;
  267. .title-text {
  268. font-size: 32rpx;
  269. font-weight: 500;
  270. color: #333333;
  271. }
  272. }
  273. }
  274. .avatar-section {
  275. display: flex;
  276. flex-direction: column;
  277. align-items: center;
  278. padding: 40rpx 30rpx;
  279. border-bottom: 1rpx solid #f0f0f0;
  280. .avatar-button {
  281. padding: 0;
  282. margin: 0;
  283. background: transparent;
  284. border: none;
  285. outline: none;
  286. margin-bottom: 20rpx;
  287. &::after {
  288. border: none;
  289. }
  290. .avatar {
  291. width: 160rpx;
  292. height: 160rpx;
  293. border-radius: 80rpx;
  294. border: 4rpx dashed #cccccc;
  295. }
  296. }
  297. .avatar-tip {
  298. font-size: 26rpx;
  299. color: #999999;
  300. }
  301. }
  302. .info-item {
  303. display: flex;
  304. align-items: center;
  305. justify-content: space-between;
  306. padding: 30rpx;
  307. border-bottom: 1rpx solid #f0f0f0;
  308. &:last-child {
  309. border-bottom: none;
  310. }
  311. .label {
  312. font-size: 30rpx;
  313. color: #333333;
  314. font-weight: 500;
  315. width: 120rpx;
  316. }
  317. .value-container {
  318. flex: 1;
  319. display: flex;
  320. align-items: center;
  321. justify-content: flex-end;
  322. .nickname-input,
  323. .phone-input,
  324. .address-input {
  325. width: 100%;
  326. text-align: right;
  327. font-size: 30rpx;
  328. color: #666666;
  329. border: none;
  330. outline: none;
  331. background: transparent;
  332. &::placeholder {
  333. color: #cccccc;
  334. }
  335. }
  336. }
  337. }
  338. .save-section {
  339. padding: 40rpx 20rpx;
  340. .save-button {
  341. width: 100%;
  342. height: 88rpx;
  343. background-color: #1488db;
  344. border-radius: 44rpx;
  345. border: none;
  346. outline: none;
  347. font-size: 32rpx;
  348. font-weight: 500;
  349. color: #ffffff;
  350. display: flex;
  351. align-items: center;
  352. justify-content: center;
  353. &::after {
  354. border: none;
  355. }
  356. }
  357. }
  358. </style>