feat(user-tag): 后台用户列表展示标签 + 小程序用户中心会员等级下方展示标签
后台 msh_single_admin user/list/index.vue: - 在「分组」「推荐人」之间新增「用户标签」列,用 el-tag 渲染(多标签 ',' 切分) - 加入默认显示项 checkedCities / columnData 后端 UserCenterResponse + UserServiceImpl: - UserCenterResponse 新增 tagName 字段 - getUserCenter 在已注入的 userTagService 基础上回填标签名(已存在 getGroupNameInId) 小程序 pages/user/index.vue: - 用户名 + VIP 行下方新增 .user-tags 容器,按 ',' 切分多标签 - 半透明白底胶囊,与顶部渐变橙色背景协调 附带修复: - pages/tool/calculator-history.vue formatTime 兼容 ISO/数组/数字/旧字符串四种来源 - 解决「NaN-NaN-NaN NaN:NaN」问题(ISO 字符串里的 'T' 被替换 / 后变非法日期) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,4 +85,7 @@ public class UserCenterResponse implements Serializable {
|
|||||||
|
|
||||||
@ApiModelProperty(value = "用户收藏数量")
|
@ApiModelProperty(value = "用户收藏数量")
|
||||||
private Integer collectCount;
|
private Integer collectCount;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户标签名(逗号分隔,多标签)")
|
||||||
|
private String tagName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -564,6 +564,10 @@ public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserS
|
|||||||
userCenterResponse.setVipName(systemUserLevel.getName());
|
userCenterResponse.setVipName(systemUserLevel.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 用户标签:在会员等级下方展示
|
||||||
|
if (StrUtil.isNotBlank(currentUser.getTagId())) {
|
||||||
|
userCenterResponse.setTagName(userTagService.getGroupNameInId(currentUser.getTagId()));
|
||||||
|
}
|
||||||
// 充值开关
|
// 充值开关
|
||||||
String rechargeSwitch = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_KEY_RECHARGE_SWITCH);
|
String rechargeSwitch = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_KEY_RECHARGE_SWITCH);
|
||||||
if (StrUtil.isNotBlank(rechargeSwitch)) {
|
if (StrUtil.isNotBlank(rechargeSwitch)) {
|
||||||
|
|||||||
@@ -209,6 +209,20 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="groupName" label="分组" min-width="100" v-if="checkedCities.includes('分组')" />
|
<el-table-column prop="groupName" label="分组" min-width="100" v-if="checkedCities.includes('分组')" />
|
||||||
|
<el-table-column label="用户标签" min-width="160" v-if="checkedCities.includes('用户标签')">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<template v-if="scope.row.tagName">
|
||||||
|
<el-tag
|
||||||
|
v-for="(tag, idx) in String(scope.row.tagName).split(',').filter(Boolean)"
|
||||||
|
:key="idx"
|
||||||
|
size="mini"
|
||||||
|
effect="plain"
|
||||||
|
style="margin-right: 4px; margin-bottom: 2px;"
|
||||||
|
>{{ tag }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="spreadNickname" label="推荐人" min-width="130" v-if="checkedCities.includes('推荐人')" />
|
<el-table-column prop="spreadNickname" label="推荐人" min-width="130" v-if="checkedCities.includes('推荐人')" />
|
||||||
<el-table-column label="手机号" min-width="100" v-if="checkedCities.includes('手机号')">
|
<el-table-column label="手机号" min-width="100" v-if="checkedCities.includes('手机号')">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
@@ -500,8 +514,8 @@ export default {
|
|||||||
idKey: 'uid',
|
idKey: 'uid',
|
||||||
card_select_show: false,
|
card_select_show: false,
|
||||||
checkAll: false,
|
checkAll: false,
|
||||||
checkedCities: ['ID', '头像', '姓名', '用户等级', '分组', '推荐人', '手机号', '余额', '积分'],
|
checkedCities: ['ID', '头像', '姓名', '用户等级', '分组', '用户标签', '推荐人', '手机号', '余额', '积分'],
|
||||||
columnData: ['ID', '头像', '姓名', '用户等级', '分组', '推荐人', '手机号', '余额', '积分'],
|
columnData: ['ID', '头像', '姓名', '用户等级', '分组', '用户标签', '推荐人', '手机号', '余额', '积分'],
|
||||||
isIndeterminate: true,
|
isIndeterminate: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -105,14 +105,25 @@ export default {
|
|||||||
uni.navigateTo({ url: '/pages/tool/calculator' })
|
uni.navigateTo({ url: '/pages/tool/calculator' })
|
||||||
},
|
},
|
||||||
formatTime(s) {
|
formatTime(s) {
|
||||||
if (!s) return ''
|
if (s == null || s === '') return ''
|
||||||
try {
|
// 兼容 4 种来源:
|
||||||
const d = new Date(typeof s === 'string' ? s.replace(/-/g, '/') : s)
|
// ① 数字时间戳;② Java LocalDateTime 序列化为数组 [y,m,d,h,m,s,nano];
|
||||||
const pad = (n) => (n < 10 ? '0' + n : '' + n)
|
// ③ ISO 字符串 "2026-05-03T01:21:18"(含 T,旧版 replace 后变 "2026/05/03T01:21:18" 解析为 Invalid Date → NaN);
|
||||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes())
|
// ④ 旧式 "2026-05-03 01:21:18"(iOS 需把 - 替换成 /)
|
||||||
} catch (e) {
|
let d
|
||||||
return String(s)
|
if (typeof s === 'number') {
|
||||||
|
d = new Date(s)
|
||||||
|
} else if (Array.isArray(s) && s.length >= 3) {
|
||||||
|
d = new Date(s[0], (s[1] || 1) - 1, s[2] || 1, s[3] || 0, s[4] || 0, s[5] || 0)
|
||||||
|
} else if (typeof s === 'string') {
|
||||||
|
d = /T/.test(s) ? new Date(s) : new Date(s.replace(/-/g, '/'))
|
||||||
|
} else {
|
||||||
|
d = new Date(s)
|
||||||
}
|
}
|
||||||
|
if (!d || isNaN(d.getTime())) return String(s)
|
||||||
|
const pad = (n) => (n < 10 ? '0' + n : '' + n)
|
||||||
|
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
||||||
|
+ ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes())
|
||||||
},
|
},
|
||||||
formatBmi(b) {
|
formatBmi(b) {
|
||||||
if (b == null) return '—'
|
if (b == null) return '—'
|
||||||
|
|||||||
@@ -21,6 +21,14 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 用户标签:在会员等级下方展示 -->
|
||||||
|
<view class="user-tags" v-if="userInfo && uid && userInfo.tagName">
|
||||||
|
<text
|
||||||
|
class="user-tag"
|
||||||
|
v-for="(tag, idx) in String(userInfo.tagName).split(',').filter(Boolean)"
|
||||||
|
:key="idx"
|
||||||
|
>{{ tag }}</text>
|
||||||
|
</view>
|
||||||
<view class="num" v-if="userInfo && userInfo.phone && uid">
|
<view class="num" v-if="userInfo && userInfo.phone && uid">
|
||||||
<view class="num-txt">{{userInfo.phone}}</view>
|
<view class="num-txt">{{userInfo.phone}}</view>
|
||||||
<view class="icon">
|
<view class="icon">
|
||||||
@@ -598,6 +606,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* 用户标签(test-0415 后续:会员等级下方展示) */
|
||||||
|
.user-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8rpx;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
|
||||||
|
.user-tag {
|
||||||
|
padding: 2rpx 16rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
background: rgba(255, 255, 255, 0.18);
|
||||||
|
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 18px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
.app_set{
|
.app_set{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
|
|||||||
Reference in New Issue
Block a user