index.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <template>
  2. <view class="user-detail-page">
  3. <NavBar title="用户详情" bgColor="#ffd53f" color="#5c4314"></NavBar>
  4. <view class="user-hero">
  5. <image :src="user.avatarUrl || 'https://img.icons8.com/?size=256&id=23235&format=png'" class="avatar" mode="aspectFill"></image>
  6. <view class="hero-info">
  7. <text class="user-name">{{ user.name || '-' }}</text>
  8. <text class="gender-text" v-if="user.gender !== undefined">({{ user.gender === 1 ? '女' : '男' }})</text>
  9. </view>
  10. <text class="user-phone">{{ user.phone || '-' }}</text>
  11. <view class="tag-list" v-if="user.tags && user.tags.length > 0">
  12. <text class="tag-item" v-for="tag in user.tags" :key="tag.id">{{ tag.name }}</text>
  13. </view>
  14. </view>
  15. <view class="info-card">
  16. <view class="section-title">基本信息</view>
  17. <view class="info-row"><text class="label">状态</text><text class="value" :class="{ 'orange': user.status === 0 }">{{ user.status === 0 ? '正常' : '禁用' }}</text></view>
  18. <view class="info-row"><text class="label">所属区域</text><text class="value">{{ user.areaName || '-' }}</text></view>
  19. <view class="info-row"><text class="label">所属站点</text><text class="value">{{ user.stationName || '-' }}</text></view>
  20. <view class="info-row"><text class="label">所属品牌</text><text class="value">{{ user.tenantName || '-' }}</text></view>
  21. <view class="info-row"><text class="label">录入时间</text><text class="value">{{ user.createTime || '-' }}</text></view>
  22. <view class="section-title">居住信息</view>
  23. <view class="info-row"><text class="label">详细住址</text><text class="value">{{ user.address || '-' }}</text></view>
  24. <view class="info-row"><text class="label">房屋类型</text><text class="value">{{ getHouseTypeLabel(user.houseType) }}</text></view>
  25. <view class="info-row"><text class="label">入门方式</text><text class="value">{{ user.entryMethod === 'password' ? '密码' : (user.entryMethod === 'key' ? '钥匙' : user.entryMethod || '-') }}</text></view>
  26. <view class="info-row"><text class="label">开门详情</text><text class="value">{{ user.entryMethod === 'password' ? (user.entryPassword || '-') : (user.keyLocation || '-') }}</text></view>
  27. <view class="info-row" v-if="user.remark" style="margin-top:20rpx;"><text class="label">备注</text><text class="value">{{ user.remark }}</text></view>
  28. </view>
  29. <button class="edit-btn" @click="goToEdit">编辑用户资料</button>
  30. </view>
  31. </template>
  32. <script setup>
  33. import { ref } from 'vue'
  34. import { onLoad } from '@dcloudio/uni-app'
  35. import NavBar from '@/components/nav-bar/index.vue'
  36. import { getCustomer } from '@/api/archieves/customer'
  37. import { listAreaStation } from '@/api/system/areaStation'
  38. import customerEnums from '@/json/customer.json'
  39. const { houseTypeOptions } = customerEnums
  40. // 将房屋类型 value 转换为中文标签
  41. const getHouseTypeLabel = (val) => {
  42. const item = houseTypeOptions.find(o => o.value === val)
  43. return item ? item.label : (val || '-')
  44. }
  45. const user = ref({})
  46. onLoad((options) => {
  47. if (options.id) {
  48. loadDetail(options.id)
  49. }
  50. })
  51. const loadDetail = async (id) => {
  52. try {
  53. uni.showLoading({ title: '加载中...' })
  54. const [stationRes, userRes] = await Promise.all([
  55. listAreaStation().catch(() => []),
  56. getCustomer(id)
  57. ])
  58. const data = userRes || {}
  59. const allNodes = Array.isArray(stationRes) ? stationRes : (stationRes?.data || [])
  60. if (data.areaId) {
  61. const area = allNodes.find(n => String(n.id) === String(data.areaId))
  62. data.areaName = area ? area.name : '-'
  63. }
  64. if (data.stationId) {
  65. const station = allNodes.find(n => String(n.id) === String(data.stationId))
  66. data.stationName = station ? station.name : '-'
  67. }
  68. user.value = data
  69. } catch(err) {
  70. console.error(err)
  71. } finally {
  72. uni.hideLoading()
  73. }
  74. }
  75. const goToEdit = () => {
  76. if (!user.value.id) return
  77. uni.navigateTo({ url: `/pages/my/user/edit/index?id=${user.value.id}` })
  78. }
  79. </script>
  80. <style lang="scss" scoped>
  81. .user-detail-page { min-height: 100vh; background: #f7f8fa; padding-bottom: 160rpx; }
  82. .user-hero { background: linear-gradient(150deg, #ffd53f, #ff9500); padding: 40rpx 40rpx 60rpx; display: flex; flex-direction: column; align-items: center; }
  83. .avatar { width: 160rpx; height: 160rpx; border-radius: 50%; border: 8rpx solid #fff; margin-bottom: 20rpx; background:#fff; }
  84. .hero-info { display: flex; align-items: center; margin-bottom: 8rpx; }
  85. .user-name { font-size: 40rpx; font-weight: 800; color: #5c4314; }
  86. .gender-text { font-size: 30rpx; color: #5c4314; margin-left: 8rpx; opacity: 0.8; }
  87. .user-phone { font-size: 28rpx; color: #5c4314; opacity: 0.8; }
  88. .tag-list { display: flex; flex-wrap: wrap; gap: 12rpx; justify-content: center; margin-top: 16rpx; }
  89. .tag-item { background: rgba(255,255,255,0.3); color: #5c4314; font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 16rpx; }
  90. .info-card { background: #fff; border-radius: 32rpx 32rpx 0 0; margin-top: -40rpx; padding: 40rpx 32rpx; position: relative; z-index: 3; }
  91. .section-title { font-size: 32rpx; font-weight: bold; color: #333; margin: 32rpx 0 16rpx; display: flex; align-items: center; }
  92. .section-title::before { content: ''; display: inline-block; width: 6rpx; height: 28rpx; background: #ffd53f; margin-right: 12rpx; border-radius: 4rpx; }
  93. .section-title:first-child { margin-top: 0; }
  94. .info-row { display: flex; justify-content: space-between; padding: 24rpx 0; border-bottom: 2rpx solid #EEEEEE; }
  95. .info-row:last-child { border-bottom: none; }
  96. .label { font-size: 28rpx; color: #999; flex-shrink: 0; margin-right: 20rpx; }
  97. .value { font-size: 28rpx; color: #333; font-weight: 500; text-align: right; word-break: break-all; }
  98. .value.orange { color: #ff9800; }
  99. .edit-btn { margin: 40rpx 32rpx; width: calc(100% - 64rpx); height: 96rpx; background: linear-gradient(90deg, #ffd53f, #ff9500); color: #fff; border: none; border-radius: 48rpx; font-size: 32rpx; font-weight: bold; line-height: 96rpx; }
  100. </style>