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

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