设置全局通知及音效

This commit is contained in:
peak 2025-06-16 09:22:39 +08:00
parent 8114f48e70
commit 91af29f200
9 changed files with 164 additions and 27 deletions

View File

@ -4,9 +4,9 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='https://zysc.fjptzykj.com'
# VITE_BASE_URL='https://zysc.fjptzykj.com'
# VITE_BASE_URL='http://192.168.10.75:6127'
# VITE_BASE_URL='http://127.0.0.1:6127'
VITE_BASE_URL='http://127.0.0.1:6127'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

View File

@ -6,7 +6,11 @@ import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import routerSearch from '@/components/RouterSearch/index.vue'
import EventBus from '@/utils/eventBus'
import { debounce } from 'lodash'
import { getRefreshToken, getAccessToken } from '@/utils/auth'
import { useWebSocket } from '@vueuse/core'
import { ElNotification } from 'element-plus'
import bgm from './xm3463.mp3'
const audio = new Audio(bgm)
defineOptions({ name: 'APP' })
const { getPrefixCls } = useDesign()
@ -26,15 +30,76 @@ const setDefaultTheme = () => {
}
setDefaultTheme()
const debounceNotify = debounce((msg) => {
alert(msg)
ElNotification.info({
title: "新消息",
message: msg,
duration: 3000,
})
}, 600);
//alert(msg)
ElNotification.info({
title: "新消息",
message: msg,
duration: 3000,
})
}, 600);
const server = ref('')
const wsInstance = ref<any>(null)
// WebSocket
const createWebSocket = () => {
if (!getAccessToken()) return
server.value = (import.meta.env.VITE_BASE_URL + '/infra/ws?token=').replace('http', 'ws') + getAccessToken()
wsInstance.value = useWebSocket(server.value, {
onConnected: (ws) => {
// if (typeof shangxian === 'function') {
// shangxian()
// }
console.log('websocket 连接成功!', ws)
},
onDisconnected: (ws, event) => {
// if (typeof xiaxian === 'function') {
// xiaxian()
// }
console.log('WebSocket 连接断开', event)
},
onMessage: (ws, event) => {
if (event.data === 'pong') {
return
}
const jsonMessage = JSON.parse(event.data)
if( jsonMessage.type === 'kefu_message_type'){
console.log('来自用户发送的消息:', JSON.parse(jsonMessage.content))
const message = JSON.parse(jsonMessage.content)
if (message.senderType == 1) {
audio.play()
debounceNotify(message.content)
}
}
},
autoReconnect: true,
heartbeat: true
})
}
// token
// watch(() => getAccessToken(), (newToken) => {
// if (wsInstance.value?.close) {
// wsInstance.value.close()
// }
// if (newToken) {
// createWebSocket()
// }
// })
onMounted(() => {
EventBus.on('show-notification', debounceNotify);
//
EventBus.on('show-notification', debounceNotify)
// token
EventBus.on('update-token', () => {
if (wsInstance.value?.close) {
wsInstance.value.close()
}
createWebSocket()
})
if (wsInstance.value?.close) {
wsInstance.value.close()
}
//
createWebSocket()
})
</script>
<template>
@ -69,6 +134,6 @@ body {
}
.scrollbar__view {
height: 99%!important;
height: 99% !important;
}
</style>

View File

@ -1,6 +1,7 @@
import { useCache, CACHE_KEY } from '@/hooks/web/useCache'
import { TokenType } from '@/api/login/types'
import { decrypt, encrypt } from '@/utils/jsencrypt'
import EventBus from '@/utils/eventBus'
const { wsCache } = useCache()
@ -23,6 +24,7 @@ export const getRefreshToken = () => {
export const setToken = (token: TokenType) => {
wsCache.set(RefreshTokenKey, token.refreshToken)
wsCache.set(AccessTokenKey, token.accessToken)
EventBus.emit("update-token")
}
// 删除token

View File

@ -164,11 +164,11 @@ import * as UserApi from '@/api/member/user'
import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff'
import { string } from 'vue-types'
import EventBus from '@/utils/eventBus';
import bgm from './xm3463.mp3'
// import bgm from './xm3463.mp3'
import type { TabsPaneContext } from 'element-plus'
import { ElNotification } from 'element-plus'
const findName = ref('')
const audio = new Audio(bgm)
// const audio = new Audio(bgm)
defineOptions({ name: 'KeFu' })
const lineStatus = ref(true)
@ -284,8 +284,8 @@ watchEffect(() => {
console.log('来自用户发送的消息:', JSON.parse(jsonMessage.content))
const message = JSON.parse(jsonMessage.content)
if (message.senderType == 1) {
audio.play()
EventBus.emit('notification', message.content)
// audio.play()
// EventBus.emit('notification', message.content)
// Notification.requestPermission().then(permission => {
// if (permission === 'granted') {
// console.log('');

Binary file not shown.

View File

@ -70,4 +70,7 @@ public class ActivityInfoRespVO {
@ExcelProperty("记录创建时间")
private LocalDateTime createTime;
@Schema(description = "活动图片")
@ExcelProperty("活动图片")
private String image;
}

View File

@ -2,9 +2,18 @@ package cn.iocoder.yudao.module.promotion.controller.app.activity;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.promotion.controller.admin.activityinfo.vo.ActivityInfoPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.activityinfo.vo.ActivityInfoRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.activityinfo.vo.ActivityInfoSaveReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.activityinfo.ActivityInfoDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
@ -13,6 +22,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.promotion.service.activityinfo.ActivityInfoService;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
@ -21,17 +31,19 @@ import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@ -51,6 +63,56 @@ public class AppActivityController {
private DiscountActivityService discountActivityService;
@Resource
private RewardActivityService rewardActivityService;
@Resource
private ActivityInfoService activityInfoService;
@PostMapping("/create")
@Operation(summary = "创建活动信息")
public CommonResult<Long> createActivityInfo(@Valid @RequestBody ActivityInfoSaveReqVO createReqVO) {
return success(activityInfoService.createActivityInfo(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新活动信息")
public CommonResult<Boolean> updateActivityInfo(@Valid @RequestBody ActivityInfoSaveReqVO updateReqVO) {
activityInfoService.updateActivityInfo(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除活动信息")
@Parameter(name = "id", description = "编号", required = true)
public CommonResult<Boolean> deleteActivityInfo(@RequestParam("id") Long id) {
activityInfoService.deleteActivityInfo(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得活动信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<ActivityInfoRespVO> getActivityInfo(@RequestParam("id") Long id) {
ActivityInfoDO activityInfo = activityInfoService.getActivityInfo(id);
return success(BeanUtils.toBean(activityInfo, ActivityInfoRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得活动信息分页")
public CommonResult<PageResult<ActivityInfoRespVO>> getActivityInfoPage(@Valid ActivityInfoPageReqVO pageReqVO) {
PageResult<ActivityInfoDO> pageResult = activityInfoService.getActivityInfoPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ActivityInfoRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出活动信息 Excel")
@ApiAccessLog(operateType = EXPORT)
public void exportActivityInfoExcel(@Valid ActivityInfoPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ActivityInfoDO> list = activityInfoService.getActivityInfoPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "活动信息.xls", "数据", ActivityInfoRespVO.class,
BeanUtils.toBean(list, ActivityInfoRespVO.class));
}
@GetMapping("/list-by-spu-id")
@Operation(summary = "获得单个商品,正在参与的所有活动")

View File

@ -80,5 +80,9 @@ public class ActivityInfoDO extends BaseDO {
* 枚举 {@link TODO promotion_activity_info_topic_type 对应的类}
*/
private String topicType;
/**
* 活动图片
*/
private String image;
}

View File

@ -47,8 +47,8 @@ spring:
datasource:
master:
name: ruoyi-vue-pro
url: jdbc:mysql://1.14.205.126:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://1.14.205.126:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
@ -58,7 +58,7 @@ spring:
# url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
username: root
# password: 123456
password: xpower1234
password: root
# username: sa # SQL Server 连接的示例
# password: Yudao@2024 # SQL Server 连接的示例
# username: SYSDBA # DM 连接的示例
@ -73,13 +73,14 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 1.14.205.126 # 地址
# host: 1.14.205.126 # 地址
# host: 120.46.37.243 # 地址
# host: 124.70.1.134 # 地址
# host: 127.0.0.1 # 地址
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引
password: Zykj9480a. # 密码,建议生产环境开启
# password: Zykj9480a. # 密码,建议生产环境开启
password: 111111
--- #################### 定时任务相关配置 ####################