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

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