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

414 lines
9.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
1 month ago
  1. <template>
  2. <view class="user-info-container">
  3. <!-- 内容区域 -->
  4. <view class="content">
  5. <!-- 头像区域 -->
  6. <view class="avatar-section">
  7. <view class="app-info">
  8. <image
  9. class="app-logo"
  10. :src="configParamImage('config_logo')"
  11. mode="aspectFit"
  12. ></image>
  13. <text class="app-name">{{ configParamText('config_app_name') }}</text>
  14. </view>
  15. </view>
  16. <!-- 表单区域 -->
  17. <view class="form-section">
  18. <!-- 头像 -->
  19. <!-- 在模板中修改头像区域 -->
  20. <view class="form-item">
  21. <text class="form-label">头像</text>
  22. <view class="avatar-upload">
  23. <button
  24. class="avatar-button"
  25. open-type="chooseAvatar"
  26. @chooseavatar="onChooseAvatar"
  27. >
  28. <image
  29. class="avatar-image"
  30. :src="userInfo.headImage || '/static/待上传头像.png'"
  31. mode="aspectFill"
  32. ></image>
  33. </button>
  34. </view>
  35. </view>
  36. <!-- 昵称 -->
  37. <view class="form-item">
  38. <text class="form-label">昵称</text>
  39. <input
  40. class="form-input"
  41. v-model="userInfo.nickName"
  42. placeholder="请输入昵称"
  43. type="nickname"
  44. @blur="onNicknameBlur"
  45. />
  46. </view>
  47. <!-- 手机号 -->
  48. <view class="form-item">
  49. <text class="form-label">手机号</text>
  50. <view class="phone-input-container">
  51. <input
  52. class="form-input phone-input"
  53. v-model="userInfo.phone"
  54. placeholder="请输入手机号"
  55. type="number"
  56. maxlength="11"
  57. />
  58. <button
  59. class="get-phone-btn"
  60. open-type="getPhoneNumber"
  61. @getphonenumber="getPhoneNumber"
  62. >
  63. <text class="btn-text">获取手机号</text>
  64. </button>
  65. </view>
  66. </view>
  67. </view>
  68. <!-- 确定按钮 -->
  69. <view class="submit-section">
  70. <view class="submit-btn" @click="submitUserInfo">
  71. <text class="submit-text">确定</text>
  72. </view>
  73. </view>
  74. </view>
  75. </view>
  76. </template>
  77. <script>
  78. export default {
  79. name: 'UserInfo',
  80. data() {
  81. return {
  82. userInfo: {
  83. headImage: '',
  84. nickName: '',
  85. phone: ''
  86. }
  87. }
  88. },
  89. onLoad() {
  90. // 获取微信用户信息
  91. this.getWechatUserInfo();
  92. },
  93. methods: {
  94. // 获取微信用户信息
  95. async getWechatUserInfo() {
  96. const { result } = await this.$api.user.queryUser()
  97. this.userInfo.nickName = result.nickName
  98. this.userInfo.headImage = result.headImage
  99. this.userInfo.phone = result.phone
  100. },
  101. // 提交表单
  102. // 选择头像并上传到OSS
  103. async onChooseAvatar(e) {
  104. console.log('选择头像回调', e);
  105. if (e.detail.avatarUrl) {
  106. try {
  107. // 显示上传中提示
  108. uni.showLoading({ title: '上传头像中...' });
  109. // 构造文件对象
  110. const file = {
  111. path: e.detail.avatarUrl,
  112. tempFilePath: e.detail.avatarUrl
  113. };
  114. // 上传到OSS
  115. const uploadResult = await this.$utils.uploadImage(file);
  116. uni.hideLoading();
  117. if (uploadResult.success) {
  118. // 上传成功,更新头像URL
  119. this.userInfo.headImage = uploadResult.url;
  120. console.log('头像上传成功', uploadResult.url);
  121. uni.showToast({
  122. title: '头像上传成功',
  123. icon: 'success'
  124. });
  125. } else {
  126. // 上传失败,使用本地头像
  127. // this.userInfo.headImage = e.detail.avatarUrl;
  128. uni.showToast({
  129. title: '头像上传失败!请稍后重试!',
  130. icon: 'none'
  131. });
  132. }
  133. } catch (error) {
  134. uni.hideLoading();
  135. console.error('头像上传异常:', error);
  136. // 异常情况下使用本地头像
  137. this.userInfo.headImage = e.detail.avatarUrl;
  138. uni.showToast({
  139. title: '头像处理异常,使用本地头像',
  140. icon: 'none'
  141. });
  142. }
  143. } else {
  144. uni.showToast({
  145. title: '头像选择失败',
  146. icon: 'none'
  147. });
  148. }
  149. },
  150. // 昵称输入失焦
  151. onNicknameBlur() {
  152. if (!this.userInfo.nickname.trim()) {
  153. uni.showToast({
  154. title: '请输入昵称',
  155. icon: 'none'
  156. });
  157. }
  158. },
  159. // 获取手机号
  160. async getPhoneNumber(e) {
  161. console.log('获取手机号回调', e);
  162. if (e.detail.errMsg === 'getPhoneNumber:ok') {
  163. // 获取成功,可以通过e.detail.code发送到后端换取手机号
  164. console.log('获取手机号成功', e.detail);
  165. const res = await this.$api.login.bindPhone({
  166. phoneCode: e.detail.code
  167. })
  168. const str = JSON.parse(res.result);
  169. this.userInfo.phone = str.phone_info.phoneNumber
  170. uni.showToast({
  171. title: '手机号获取成功',
  172. icon: 'success'
  173. });
  174. // 这里需要将e.detail.code发送到后端解密获取真实手机号
  175. // 暂时模拟设置手机号
  176. // this.userInfo.phone = '138****8888';
  177. } else {
  178. // 如果失败了就申请开启权限
  179. uni.showToast({
  180. title: '手机号获取失败',
  181. icon: 'error'
  182. })
  183. }
  184. },
  185. // 提交用户信息
  186. async submitUserInfo() {
  187. if (!this.userInfo.nickName.trim()) {
  188. uni.showToast({
  189. title: '请输入昵称',
  190. icon: 'none'
  191. });
  192. return;
  193. }
  194. if (!this.userInfo.phone.trim()) {
  195. uni.showToast({
  196. title: '请输入手机号',
  197. icon: 'none'
  198. });
  199. return;
  200. }
  201. if (!/^1[3-9]\d{9}$/.test(this.userInfo.phone)) {
  202. uni.showToast({
  203. title: '请输入正确的手机号',
  204. icon: 'none'
  205. });
  206. return;
  207. }
  208. console.log('提交用户信息', this.userInfo);
  209. // 提交用户信息
  210. await this.$api.user.updateUser({
  211. nickName: this.userInfo.nickName,
  212. phone: this.userInfo.phone,
  213. headImage: this.userInfo.headImage
  214. })
  215. // 这里可以调用API保存用户信息
  216. uni.showToast({
  217. title: '信息保存成功',
  218. icon: 'success'
  219. });
  220. // 跳转到首页或其他页面
  221. setTimeout(() => {
  222. uni.switchTab({
  223. url: '/pages/index/index'
  224. });
  225. }, 1500);
  226. }
  227. }
  228. }
  229. </script>
  230. <style lang="scss" scoped>
  231. .user-info-container {
  232. min-height: 100vh;
  233. background-color: #f5f5f5;
  234. }
  235. .custom-navbar {
  236. position: fixed;
  237. top: 0;
  238. left: 0;
  239. right: 0;
  240. z-index: 1000;
  241. background-color: #1488DB;
  242. .navbar-content {
  243. height: 88rpx;
  244. display: flex;
  245. align-items: center;
  246. justify-content: center;
  247. padding-top: var(--status-bar-height, 44rpx);
  248. .navbar-title {
  249. font-size: 36rpx;
  250. font-weight: 500;
  251. color: #ffffff;
  252. }
  253. }
  254. }
  255. .content {
  256. padding-top: calc(88rpx + var(--status-bar-height, 44rpx));
  257. padding: calc(88rpx + var(--status-bar-height, 44rpx)) 40rpx 40rpx;
  258. }
  259. .avatar-section {
  260. display: flex;
  261. justify-content: center;
  262. margin-bottom: 80rpx;
  263. .app-info {
  264. display: flex;
  265. flex-direction: column;
  266. align-items: center;
  267. .app-logo {
  268. width: 160rpx;
  269. height: 160rpx;
  270. border-radius: 20rpx;
  271. border: 4rpx dashed #cccccc;
  272. margin-bottom: 20rpx;
  273. }
  274. .app-name {
  275. font-size: 32rpx;
  276. font-weight: 500;
  277. color: #333333;
  278. }
  279. }
  280. }
  281. .form-section {
  282. background-color: #ffffff;
  283. border-radius: 20rpx;
  284. padding: 40rpx;
  285. margin-bottom: 60rpx;
  286. }
  287. .form-item {
  288. display: flex;
  289. align-items: center;
  290. margin-bottom: 40rpx;
  291. &:last-child {
  292. margin-bottom: 0;
  293. }
  294. .form-label {
  295. width: 120rpx;
  296. font-size: 32rpx;
  297. color: #333333;
  298. font-weight: 500;
  299. }
  300. .form-input {
  301. flex: 3;
  302. height: 80rpx;
  303. padding: 0 20rpx;
  304. // border: 2rpx solid #e0e0e0;
  305. border-radius: 10rpx;
  306. font-size: 30rpx;
  307. color: #333333;
  308. &.phone-input {
  309. margin-right: 20rpx;
  310. }
  311. }
  312. .avatar-upload {
  313. .avatar-image {
  314. width: 120rpx;
  315. height: 120rpx;
  316. border-radius: 10rpx;
  317. border: 2rpx dashed #cccccc;
  318. }
  319. }
  320. .phone-input-container {
  321. flex: 1;
  322. display: flex;
  323. align-items: center;
  324. .get-phone-btn {
  325. flex: 2;
  326. // padding: 0rpx 0rpx;
  327. background-color: #1488DB;
  328. border-radius: 40rpx;
  329. border: none;
  330. outline: none;
  331. &::after {
  332. border: none;
  333. }
  334. .btn-text {
  335. font-size: 26rpx;
  336. color: #ffffff;
  337. }
  338. }
  339. }
  340. }
  341. .submit-section {
  342. padding: 0 40rpx;
  343. .submit-btn {
  344. width: 100%;
  345. height: 88rpx;
  346. background-color: #1488DB;
  347. border-radius: 44rpx;
  348. display: flex;
  349. align-items: center;
  350. justify-content: center;
  351. .submit-text {
  352. font-size: 32rpx;
  353. font-weight: 500;
  354. color: #ffffff;
  355. }
  356. }
  357. }
  358. // 添加按钮样式
  359. .avatar-button {
  360. padding: 0;
  361. margin: 0;
  362. background: transparent;
  363. border: none;
  364. outline: none;
  365. &::after {
  366. border: none;
  367. }
  368. }
  369. </style>