From bf467fbc58d608f6f8ebe57244f79ced76678889 Mon Sep 17 00:00:00 2001 From: menxipeng Date: Sun, 3 Aug 2025 21:52:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=9A=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/back/ShopUserController.java | 76 ++++++++- .../core/domain/entity/ActivityInfo.java | 118 +------------ .../ruoyi/system/mapper/ShopUserMapper.java | 8 + .../system/service/IShopUserService.java | 8 + .../service/impl/ShopUserServiceImpl.java | 64 ++++++- .../mapper/system/ActivityInfoMapper.xml | 4 +- .../mapper/system/ShopUserMapper.xml | 10 ++ ruoyi-ui/src/api/activity/activity.js | 8 +- ruoyi-ui/src/views/activity/index.vue | 161 +++++++++++++----- ruoyi-ui/src/views/user/manage/index.vue | 26 +-- 10 files changed, 313 insertions(+), 170 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/ShopUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/ShopUserController.java index fbf7b1d..028f361 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/ShopUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/back/ShopUserController.java @@ -4,13 +4,17 @@ import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.ShopUser; +import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.service.IShopUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletResponse; import java.util.List; @@ -25,13 +29,15 @@ import java.util.List; @RequestMapping("/back/user") public class ShopUserController extends BaseController { + private static final Logger log = LoggerFactory.getLogger(ShopUserController.class); + @Autowired private IShopUserService shopUserService; /** * 查询用户管理列表 */ - @PreAuthorize("@ss.hasPermi('system:user:list')") + // @PreAuthorize("@ss.hasPermi('system:user:list')") @GetMapping("/list") public TableDataInfo list(ShopUser shopUser) { @@ -95,4 +101,72 @@ public class ShopUserController extends BaseController { return toAjax(shopUserService.deleteShopUserByIds(ids)); } + + /** + * 更新用户在线时长 + * 客户端每5分钟调用一次,更新数据库在线时长字段online + */ + @GetMapping("/updateOnlineTime/{online}") + public AjaxResult updateOnlineTime(@PathVariable("online") String online) + { + try { + // 获取当前登录用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + if (loginUser == null || loginUser.getUserId() == null) { + return AjaxResult.error("用户未登录或用户ID为空"); + } + ShopUser shopUser = loginUser.getShopUser(); + + // 设置在线时长 + shopUser.setOnline(online); + + // 记录用户在线时长更新日志 + log.info("更新用户[{}]在线时长: {}", shopUser.getUserId(), online); + + // 调用服务更新用户在线时长 + int rows = shopUserService.updateUserOnlineTime(shopUser); + + if (rows > 0) { + return AjaxResult.success("更新在线时长成功"); + } else { + return AjaxResult.error("更新在线时长失败,用户可能不存在"); + } + } catch (Exception e) { + log.error("更新用户在线时长异常", e); + return AjaxResult.error("更新在线时长异常: " + e.getMessage()); + } + } + + /** + * 更新指定用户的在线时长(管理员使用) + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @PostMapping("/updateUserOnlineTime") + public AjaxResult updateUserOnlineTime(@RequestBody ShopUser shopUser) + { + if (shopUser == null || shopUser.getUserId() == null) { + return AjaxResult.error("用户ID不能为空"); + } + + if (shopUser.getOnline() == null) { + return AjaxResult.error("在线时长不能为空"); + } + + try { + // 记录用户在线时长更新日志 + log.info("管理员更新用户[{}]在线时长: {}", shopUser.getUserId(), shopUser.getOnline()); + + // 调用服务更新用户在线时长 + int rows = shopUserService.updateUserOnlineTime(shopUser); + + if (rows > 0) { + return AjaxResult.success("更新在线时长成功"); + } else { + return AjaxResult.error("更新在线时长失败,用户可能不存在"); + } + } catch (Exception e) { + log.error("更新用户[{}]在线时长异常", shopUser.getUserId(), e); + return AjaxResult.error("更新在线时长异常: " + e.getMessage()); + } + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/ActivityInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/ActivityInfo.java index 220d66a..4542cf1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/ActivityInfo.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/ActivityInfo.java @@ -2,6 +2,7 @@ package com.ruoyi.common.core.domain.entity; import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.annotation.Excel; @@ -13,6 +14,7 @@ import com.ruoyi.common.core.domain.BaseEntity; * @author ruoyi * @date 2025-07-20 */ +@Data public class ActivityInfo extends BaseEntity { private static final long serialVersionUID = 1L; @@ -58,119 +60,11 @@ public class ActivityInfo extends BaseEntity @Excel(name = "活动图片") private String img; - public void setId(String id) - { - this.id = id; - } + @JsonFormat(pattern = "yyyy-MM-dd") + private Date createTIme; - public String getId() - { - return id; - } + @JsonFormat(pattern = "yyyy-MM-dd") + private Date updateTime; - public void setName(String name) - { - this.name = name; - } - public String getName() - { - return name; - } - - public void setContent(String content) - { - this.content = content; - } - - public String getContent() - { - return content; - } - - public void setStartTime(Date startTime) - { - this.startTime = startTime; - } - - public Date getStartTime() - { - return startTime; - } - - public void setEndTime(Date endTime) - { - this.endTime = endTime; - } - - public Date getEndTime() - { - return endTime; - } - - public void setCreator(String creator) - { - this.creator = creator; - } - - public String getCreator() - { - return creator; - } - - public void setModify(String modify) - { - this.modify = modify; - } - - public String getModify() - { - return modify; - } - - public void setShelf(Long shelf) - { - this.shelf = shelf; - } - - public Long getShelf() - { - return shelf; - } - - public void setIsDel(Long isDel) - { - this.isDel = isDel; - } - - public Long getIsDel() - { - return isDel; - } - - public void setImg(String img) - { - this.img = img; - } - - public String getImg() - { - return img; - } - - @Override - public String toString() { - return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) - .append("id", getId()) - .append("name", getName()) - .append("content", getContent()) - .append("startTime", getStartTime()) - .append("endTime", getEndTime()) - .append("creator", getCreator()) - .append("modify", getModify()) - .append("shelf", getShelf()) - .append("isDel", getIsDel()) - .append("img", getImg()) - .toString(); - } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java index 6a100c0..f84211f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/ShopUserMapper.java @@ -69,5 +69,13 @@ public interface ShopUserMapper { * @return 结果 */ public int deleteShopUserByIds(String[] ids); + + /** + * 更新用户在线时长 + * + * @param shopUser 用户信息(包含userId和online字段) + * @return 结果 + */ + public int updateUserOnlineTime(ShopUser shopUser); } \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IShopUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IShopUserService.java index 552083d..601074d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IShopUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IShopUserService.java @@ -61,4 +61,12 @@ public interface IShopUserService * @return 结果 */ public int deleteShopUserById(String id); + + /** + * 更新用户在线时长 + * + * @param shopUser 用户信息(包含userId和online字段) + * @return 结果 + */ + public int updateUserOnlineTime(ShopUser shopUser); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ShopUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ShopUserServiceImpl.java index 53eb22f..871696c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ShopUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ShopUserServiceImpl.java @@ -1,9 +1,13 @@ package com.ruoyi.system.service.impl; +import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.entity.ShopUser; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.system.config.AliConfig; import com.ruoyi.system.mapper.ShopUserMapper; import com.ruoyi.system.service.IShopUserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,8 +20,9 @@ import java.util.List; * @date 2025-07-15 */ @Service -public class ShopUserServiceImpl implements IShopUserService +public class ShopUserServiceImpl implements IShopUserService { + private static final Logger log = LoggerFactory.getLogger(ShopUserServiceImpl.class); @Autowired private ShopUserMapper shopUserMapper; @@ -94,4 +99,61 @@ public class ShopUserServiceImpl implements IShopUserService { return shopUserMapper.deleteShopUserById(id); } + + /** + * 更新用户在线时长 + * + * @param shopUser 用户信息(包含userId和online字段) + * @return 结果 + */ + @Override + public int updateUserOnlineTime(ShopUser shopUser) + { + if (shopUser == null || shopUser.getUserId() == null) { + return 0; + } + + // 先查询用户当前的在线时长 + ShopUser currentUser = shopUserMapper.selectShopUserByUserId(shopUser.getUserId()); + if (currentUser == null) { + return 0; + } + + // 在原有时长基础上累加新的时长 + String currentOnline = currentUser.getOnline(); + String newOnline = shopUser.getOnline(); + + // 计算累加后的在线时长 + double currentOnlineValue = 0; + double newOnlineValue = 0; + + try { + if (currentOnline != null && !currentOnline.isEmpty()) { + currentOnlineValue = Double.parseDouble(currentOnline); + } + + if (newOnline != null && !newOnline.isEmpty()) { + // 接口传入的是分钟,需要转换为小时 + newOnlineValue = Double.parseDouble(newOnline) / 60.0; + // 保留两位小数 + newOnlineValue = Math.round(newOnlineValue * 100) / 100.0; + } + } catch (NumberFormatException e) { + // 如果解析失败,使用默认值 + log.error("解析在线时长失败", e); + } + + // 累加时长(数据库中存储的是小时) + double totalOnline = currentOnlineValue + newOnlineValue; + // 保留两位小数 + totalOnline = Math.round(totalOnline * 100) / 100.0; + + // 更新用户在线时长 + ShopUser updateUser = new ShopUser(); + updateUser.setUserId(shopUser.getUserId()); + updateUser.setOnline(String.valueOf(totalOnline)); + updateUser.setUpdateTime(DateUtils.getNowDate()); + + return shopUserMapper.updateUserOnlineTime(updateUser); + } } diff --git a/ruoyi-system/src/main/resources/mapper/system/ActivityInfoMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ActivityInfoMapper.xml index f9a4203..21bb922 100644 --- a/ruoyi-system/src/main/resources/mapper/system/ActivityInfoMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/ActivityInfoMapper.xml @@ -15,10 +15,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + - select id, name, content, start_time, end_time, creator, modify, shelf, is_del, img from activity_info + select id, name, content, start_time, end_time, creator, modify, shelf, is_del, img,update_time,create_time from activity_info + + + + update shop_user + + online = #{online}, + update_time = #{updateTime}, + + where user_id = #{userId} + \ No newline at end of file diff --git a/ruoyi-ui/src/api/activity/activity.js b/ruoyi-ui/src/api/activity/activity.js index d96bc3c..abc09fb 100644 --- a/ruoyi-ui/src/api/activity/activity.js +++ b/ruoyi-ui/src/api/activity/activity.js @@ -20,7 +20,7 @@ export function getActivity(id) { // 新增活动 export function addActivity(data) { return request({ - url: '/back/activity/add', + url: '/back/activity/addActivity', method: 'post', data: data }) @@ -29,8 +29,8 @@ export function addActivity(data) { // 修改活动 export function updateActivity(data) { return request({ - url: '/back/activity/update', - method: 'post', + url: '/back/activity', + method: 'put', data: data }) } @@ -41,4 +41,4 @@ export function delActivity(id) { url: '/back/activity/' + id, method: 'delete' }) -} \ No newline at end of file +} diff --git a/ruoyi-ui/src/views/activity/index.vue b/ruoyi-ui/src/views/activity/index.vue index 50e046d..443287f 100644 --- a/ruoyi-ui/src/views/activity/index.vue +++ b/ruoyi-ui/src/views/activity/index.vue @@ -9,11 +9,17 @@ @keyup.enter.native="handleQuery" /> - - - - - + + + + + + + + + + + @@ -26,27 +32,36 @@ - - + + - + + + + + + + + @@ -83,21 +98,24 @@ - + - - + +
+ 图片将保存到服务器,请确保上传的图片符合要求 +
- - - 已结束 - 进行中 - 未开始 + + + 上架 + 下架 @@ -140,10 +157,26 @@ import { listActivity, getActivity, delActivity, addActivity, updateActivity } from "@/api/activity/activity"; import { getImageUrl } from "@/utils/image"; +// 获取服务器基础URL +const baseUrl = process.env.VUE_APP_BASE_API || ''; + export default { name: "Activity", data() { + // 验证结束时间必须大于开始时间 + const validateEndTime = (rule, value, callback) => { + if (value && this.form.startTime) { + if (new Date(value) <= new Date(this.form.startTime)) { + callback(new Error('结束时间必须大于开始时间')); + } else { + callback(); + } + } else { + callback(); + } + }; return { + baseUrl: process.env.VUE_APP_BASE_API, // 遮罩层 loading: true, // 选中数组 @@ -167,26 +200,42 @@ export default { pageNum: 1, pageSize: 10, name: null, - status: null + status: null, + shelf: null }, // 表单参数 - form: {}, + form: { + id: null, + name: null, + content: null, + img: null, + startTime: null, + endTime: null, + status: "1", + shelf: "1", + activityUrl: null + }, // 表单校验 rules: { name: [ { required: true, message: "活动名称不能为空", trigger: "blur" } ], - description: [ - { required: true, message: "活动描述不能为空", trigger: "blur" } + content: [ + { required: true, message: "活动内容不能为空", trigger: "blur" }, + { pattern: /^\d+$/, message: "活动内容只能填数字", trigger: "blur" } + ], + img: [ + { required: true, message: "活动图片不能为空", trigger: "change" } ], startTime: [ { required: true, message: "开始时间不能为空", trigger: "change" } ], endTime: [ - { required: true, message: "结束时间不能为空", trigger: "change" } + { required: true, message: "结束时间不能为空", trigger: "change" }, + { validator: validateEndTime, trigger: "change" } ], - status: [ - { required: true, message: "活动状态不能为空", trigger: "change" } + shelf: [ + { required: true, message: "商家状态不能为空", trigger: "change" } ] } }; @@ -214,11 +263,12 @@ export default { this.form = { id: null, name: null, - description: null, - imageUrl: null, + content: null, + img: null, startTime: null, endTime: null, status: "1", + shelf: "1", activityUrl: null }; this.resetForm("form"); @@ -251,6 +301,22 @@ export default { const id = row.id || this.ids getActivity(id).then(response => { this.form = response.data; + // 确保图片URL正确处理,用于回显 + if (this.form.img) { + // 如果img不是完整URL,则处理为相对路径 + if (this.form.img.startsWith('http://') || this.form.img.startsWith('https://')) { + // 完整URL保持不变 + } else { + // 确保路径格式正确,移除baseUrl前缀(如果有) + if (this.form.img.startsWith(baseUrl)) { + this.form.img = this.form.img.substring(baseUrl.length); + } + // 确保路径不以/开头(因为上传组件期望的是相对路径) + if (this.form.img.startsWith('/')) { + this.form.img = this.form.img.substring(1); + } + } + } this.open = true; this.title = "修改活动"; }); @@ -287,8 +353,27 @@ export default { }, // 获取图片完整URL的方法 getImageUrlMethod(imagePath) { - return getImageUrl(imagePath); + if (!imagePath) { + return ''; + } + + // 如果已经是完整URL,直接返回 + if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) { + return imagePath; + } + + // 确保路径以/开头 + if (!imagePath.startsWith('/')) { + imagePath = '/' + imagePath; + } + + // 返回完整URL + return baseUrl + imagePath; + }, + // 验证活动内容只能输入数字 + validateNumberInput() { + this.form.content = this.form.content.replace(/[^\d]/g, ''); } } }; - \ No newline at end of file + diff --git a/ruoyi-ui/src/views/user/manage/index.vue b/ruoyi-ui/src/views/user/manage/index.vue index ebcd621..126a307 100644 --- a/ruoyi-ui/src/views/user/manage/index.vue +++ b/ruoyi-ui/src/views/user/manage/index.vue @@ -26,7 +26,7 @@ @@ -42,14 +42,14 @@ @@ -57,9 +57,9 @@ {{ scope.row.playTag }} - + @@ -67,15 +67,15 @@ - {{ scope.row.status === 1 ? '加入黑名单' : '取消加入黑名单' }} + {{ scope.row.status === '1' ? '加入黑名单' : '取消加入黑名单' }}
- + { @@ -152,4 +152,4 @@ export default { .el-tag { border-radius: 12px; } - \ No newline at end of file +