会员分页列表
需求
后台
query
pojo
包下新建query
包
package com.indi.srb.core.pojo.query;
@Data
@ApiModel(description = "会员搜索对象")
public class UserInfoQuery {
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "1:出借人 2:借款人")
private Integer userType;
@ApiModelProperty(value = "用户状态")
private Integer status;
}
service
UserInfoService.java
IPage<UserInfo> listPage(Page<UserInfo> userInfoPage, UserInfoQuery userInfoQuery);
UserInfoServiceImpl.java
@Override
public IPage<UserInfo> listPage(Page<UserInfo> userInfoPage, UserInfoQuery userInfoQuery) {
// 查询条件为空,则直接查询
if (userInfoQuery == null) {
return baseMapper.selectPage(userInfoPage, null);
}
String mobile = userInfoQuery.getMobile();
Integer userType = userInfoQuery.getUserType();
Integer status = userInfoQuery.getStatus();
// 导入baomidou的StringUtils
// 手机号不为空| 用户类型不为空| 用户状态不为空
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq(StringUtils.isNotBlank(mobile), "mobile", mobile)
.eq(userType != null, "user_type", userType)
.eq(status != null, "status", status);
// 返回分页对象
return baseMapper.selectPage(userInfoPage, queryWrapper);
}
controller
controller.admin
包下
新建AdminUserInfoController.java
package com.indi.srb.core.controller.admin;
@Api(tags = "用户信息管理")
@CrossOrigin
@RestController
@RequestMapping("/admin/core/userInfo")
public class AdminUserInfoController {
@Resource
private UserInfoService userInfoService;
@ApiOperation("获取分页列表")
@GetMapping("/list/{page}/{limit}")
public R listPage(@ApiParam(value = "当前页码", required = true)
@PathVariable Long page,
@ApiParam(value = "每页记录数", required = true)
@PathVariable Long limit,
@ApiParam(value = "查询对象")
UserInfoQuery userInfoQuery) {
// 创建分页模型
Page<UserInfo> userInfoPage = new Page<>(page, limit);
IPage<UserInfo> pageModel = userInfoService.listPage(userInfoPage, userInfoQuery);
return R.ok().setData("pageModel", pageModel);
}
}
LocalDateTime的json格式化问题
srb-service
模块config
包下
创建LocalDateTimeSerializerConfig.java
json格式化配置文件
package com.indi.srb.base.config;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
public LocalDateTimeSerializer localDateTimeDeserializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer());
}
}
上面的方案是全局生效,当全局的格式化方式无法满足需求时
也可以单独对日期格式做处理:在类的属性上添加注解
@JsonFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "创建时间")
private LocalDateTime createTime;
前台
配置路由
src/router/index.js
{
path: '/core/user-info',
component: Layout,
redirect: '/core/user-info/list',
name: 'coreUserInfo',
meta: { title: '会员管理', icon: 'user' },
alwaysShow: true,
children: [
{
path: 'list',
name: 'coreUserInfoList',
component: () => import('@/views/core/user-info/list'),
meta: { title: '会员列表' }
}
]
},
创建api
src/api/core/user-info.js
import request from '@/utils/request'
export default {
getPageList(page, limit, searchObj) {
// get请求没办法传参,所以需要使用params
return request({
url: `/admin/core/userInfo/list/${page}/${limit}`,
method: 'get',
params: searchObj
})
},
}
创建vue组件
src/views/core/user-info/list.vue
<template>
<div class="app-container">
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="手机号">
<el-input v-model="searchObj.mobile" placeholder="手机号" />
</el-form-item>
<el-form-item label="用户类型">
<el-select v-model="searchObj.userType" placeholder="请选择" clearable>
<el-option label="投资人" value="1" />
<el-option label="借款人" value="2" />
</el-select>
</el-form-item>
<el-form-item label="用户状态">
<el-select v-model="searchObj.status" placeholder="请选择" clearable>
<el-option label="正常" value="1" />
<el-option label="锁定" value="0" />
</el-select>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">
查询
</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
<!-- 列表 -->
<el-table :data="list" border stripe>
<el-table-column label="#" width="50">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="用户类型" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.userType === 1" type="success" size="mini">
投资人
</el-tag>
<el-tag
v-else-if="scope.row.userType === 2"
type="warning"
size="mini"
>
借款人
</el-tag>
</template>
</el-table-column>
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="name" label="用户姓名" />
<el-table-column prop="idCard" label="身份证号" />
<el-table-column prop="integral" label="用户积分" />
<el-table-column prop="createTime" label="注册时间" width="100" />
<el-table-column label="绑定状态" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.bindStatus === 0" type="warning" size="mini">
未绑定
</el-tag>
<el-tag
v-else-if="scope.row.bindStatus === 1"
type="success"
size="mini"
>
已绑定
</el-tag>
<el-tag v-else type="danger" size="mini">绑定失败</el-tag>
</template>
</el-table-column>
<el-table-column label="用户状态" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 0" type="danger" size="mini">
锁定
</el-tag>
<el-tag v-else type="success" size="mini">
正常
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[10, 20]"
style="padding: 30px 0; "
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="changeCurrentPage"
/>
</div>
</template>
<script>
import userInfoApi from '@/api/core/user-info'
export default {
data() {
return {
list: null, // 数据列表
total: 0, // 数据库中的总记录数
page: 1, // 默认页码
limit: 10, // 每页记录数
searchObj: {}, // 查询条件
loginRecordList: [], //会员登录日志
dialogTableVisible: false //对话框是否显示
}
},
created() {
// 当页面加载时获取数据
this.fetchData()
},
methods: {
fetchData() {
userInfoApi
.getPageList(this.page, this.limit, this.searchObj)
.then(response => {
this.list = response.data.pageModel.records
this.total = response.data.pageModel.total
})
},
// 每页记录数改变,size:回调参数,表示当前选中的“每页条数”
changePageSize(size) {
this.limit = size
this.fetchData()
},
// 改变页码,page:回调参数,表示当前选中的“页码”
changeCurrentPage(page) {
this.page = page
this.fetchData()
},
// 重置表单
resetData() {
this.searchObj = {}
this.fetchData()
}
}
}
</script>
锁定和解锁
需求
后端
service
UserInfoService.java
void lock(Long id,Integer status);
UserInfoServiceImpl.java
@Override
public void lock(Long id, Integer status) {
UserInfo userInfo = new UserInfo();
userInfo.setId(id);
userInfo.setStatus(status);
baseMapper.updateById(userInfo);
}
controller
AdminUserInfoController.java
@ApiOperation("修改用户状态")
@PutMapping("lock/{id}/{status}")
public R lock(
@ApiParam(value = "id", required = true)
@PathVariable("id") Long id,
@ApiParam(value = "状态:0:锁定:1:解锁", required = true)
@PathVariable("status") Integer status) {
userInfoService.lock(id, status);
return R.ok().setMessage(status == 0 ? "锁定成功" : "解锁成功");
}
前端
api
src/api/core/user-info.js
lock(id, status) {
return request({
url: `/admin/core/userInfo/lock/${id}/${status}`,
method: 'put'
})
},
template
src/views/core/user-info/list.vue
<el-table-column label="操作" align="center" width="200">
<template slot-scope="scope">
<el-button
v-if="scope.row.status == 1"
type="primary"
size="mini"
@click="lock(scope.row.id, 0)"
>
锁定
</el-button>
<el-button
v-else
type="danger"
size="mini"
@click="lock(scope.row.id, 1)"
>
解锁
</el-button>
</el-table-column>
script
src/views/core/user-info/list.vue
// 锁定/解锁
lock(id, status) {
userInfoApi.lock(id, status).then(response => {
this.$message.success(response.message)
this.fetchData()
})
},
登录日志
需求
后端
servicce
UserLoginRecordService.java
List<UserLoginRecord> listTop50(Long userId);
UserLoginRecordServiceImpl.java
@Override
public List<UserLoginRecord> listTop50(Long userId) {
QueryWrapper<UserLoginRecord> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq("user_id", userId)
.orderByDesc("id")
.last("limit 50");
return baseMapper.selectList(queryWrapper);
}
controller
controller.admin
包下
创建AdminUserLoginRecordController.java
package com.indi.srb.core.controller.admin;
@Api(tags = "会员登录管理")
@CrossOrigin
@RestController
@RequestMapping("/admin/core/userLoginRecord")
public class AdminUserLoginRecordController {
@Resource
private UserLoginRecordService userLoginRecordService;
@ApiOperation("会员登录日志表")
@GetMapping("/listTop50/{userId}")
public R listTop50(
@ApiParam(value = "用户id", required = true)
@PathVariable Long userId) {
List<UserLoginRecord> list = userLoginRecordService.listTop50(userId);
return R.ok().setData("list", list);
}
}
前端
api
src/api/core/user-info.js
getLoginRecordList(userId) {
return request({
url: `/admin/core/userLoginRecord/listTop50/${userId}`,
method: 'get'
})
}
template
src/views/core/user-info/list.vue
<el-button
type="primary"
size="mini"
@click="showLoginRecord(scope.row.id)"
>
登录日志
</el-button>
<!-- 用户登录日志 -->
<el-dialog title="用户登录日志" :visible.sync="dialogTableVisible">
<el-table :data="loginRecordList" border stripe>
<el-table-column type="index" />
<el-table-column prop="ip" label="IP" />
<el-table-column prop="createTime" label="登录时间" />
</el-table>
</el-dialog>
script
src/views/core/user-info/list.vue
// 用户登录记录
showLoginRecord(userId) {
this.dialogTableVisible = true
userInfoApi.getLoginRecordList(userId).then(response => {
this.loginRecordList = response.data.list
})
}