展品维保小程序前端代码接口
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.5 KiB

  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. address: ''
  215. })
  216. // 这里可以调用API保存用户信息
  217. uni.showToast({
  218. title: '信息保存成功',
  219. icon: 'success'
  220. });
  221. // 跳转到首页或其他页面
  222. setTimeout(() => {
  223. uni.switchTab({
  224. url: '/pages/index/index'
  225. });
  226. }, 1000);
  227. }
  228. }
  229. }
  230. </script>
  231. <style lang="scss" scoped>
  232. .user-info-container {
  233. min-height: 100vh;
  234. background-color: #f5f5f5;
  235. }
  236. .custom-navbar {
  237. position: fixed;
  238. top: 0;
  239. left: 0;
  240. right: 0;
  241. z-index: 1000;
  242. background-color: #1488DB;
  243. .navbar-content {
  244. height: 88rpx;
  245. display: flex;
  246. align-items: center;
  247. justify-content: center;
  248. padding-top: var(--status-bar-height, 44rpx);
  249. .navbar-title {
  250. font-size: 36rpx;
  251. font-weight: 500;
  252. color: #ffffff;
  253. }
  254. }
  255. }
  256. .content {
  257. padding-top: calc(88rpx + var(--status-bar-height, 44rpx));
  258. padding: calc(88rpx + var(--status-bar-height, 44rpx)) 40rpx 40rpx;
  259. }
  260. .avatar-section {
  261. display: flex;
  262. justify-content: center;
  263. margin-bottom: 80rpx;
  264. .app-info {
  265. display: flex;
  266. flex-direction: column;
  267. align-items: center;
  268. .app-logo {
  269. width: 160rpx;
  270. height: 160rpx;
  271. border-radius: 20rpx;
  272. border: 4rpx dashed #cccccc;
  273. margin-bottom: 20rpx;
  274. }
  275. .app-name {
  276. font-size: 32rpx;
  277. font-weight: 500;
  278. color: #333333;
  279. }
  280. }
  281. }
  282. .form-section {
  283. background-color: #ffffff;
  284. border-radius: 20rpx;
  285. padding: 40rpx;
  286. margin-bottom: 60rpx;
  287. }
  288. .form-item {
  289. display: flex;
  290. align-items: center;
  291. margin-bottom: 40rpx;
  292. &:last-child {
  293. margin-bottom: 0;
  294. }
  295. .form-label {
  296. width: 120rpx;
  297. font-size: 32rpx;
  298. color: #333333;
  299. font-weight: 500;
  300. }
  301. .form-input {
  302. flex: 3;
  303. height: 80rpx;
  304. padding: 0 20rpx;
  305. // border: 2rpx solid #e0e0e0;
  306. border-radius: 10rpx;
  307. font-size: 30rpx;
  308. color: #333333;
  309. &.phone-input {
  310. margin-right: 20rpx;
  311. }
  312. }
  313. .avatar-upload {
  314. .avatar-image {
  315. width: 120rpx;
  316. height: 120rpx;
  317. border-radius: 10rpx;
  318. border: 2rpx dashed #cccccc;
  319. }
  320. }
  321. .phone-input-container {
  322. flex: 1;
  323. display: flex;
  324. align-items: center;
  325. .get-phone-btn {
  326. flex: 2;
  327. // padding: 0rpx 0rpx;
  328. background-color: #1488DB;
  329. border-radius: 40rpx;
  330. border: none;
  331. outline: none;
  332. &::after {
  333. border: none;
  334. }
  335. .btn-text {
  336. font-size: 26rpx;
  337. color: #ffffff;
  338. }
  339. }
  340. }
  341. }
  342. .submit-section {
  343. padding: 0 40rpx;
  344. .submit-btn {
  345. width: 100%;
  346. height: 88rpx;
  347. background-color: #1488DB;
  348. border-radius: 44rpx;
  349. display: flex;
  350. align-items: center;
  351. justify-content: center;
  352. .submit-text {
  353. font-size: 32rpx;
  354. font-weight: 500;
  355. color: #ffffff;
  356. }
  357. }
  358. }
  359. // 添加按钮样式
  360. .avatar-button {
  361. padding: 0;
  362. margin: 0;
  363. background: transparent;
  364. border: none;
  365. outline: none;
  366. &::after {
  367. border: none;
  368. }
  369. }
  370. </style>