首页 文章 精选 留言 我的

精选列表

搜索[uniapp],共459篇文章
优秀的个人博客,低调大师

ShopWind 多商户商城 v4.6 更新,Vue3+uniapp 前后端分离

ShopWind多商户商城系统 v4.6发布更新,采用全新技术构架,实现前后端分离。使用 vue3/vite、Element Plus UI、 axios 数据请求、页面异步加载。PC 前端的页面全新改版,更新优化了页面 DIY 可视化装修、IM 客服系统等内容。V4.6版本页面预览: 开源版体验 前台体验:https://test.sho‍pw‍ind.net买家测试账号:buyer 密码:123456 支付密码:123456 后台体验:https://test.s‍hopwind.net/admin平台管理员账号:admin 密码:123456 商家体验:https://test.shopwin‍d.net/seller/login.html商家测试账号:seller 密码:123456 多商户旗舰版体验 后台体验:https://v4.shopwind‍.net/admin平台管理员账号:admin 密码:111111 前台体验:https://v4.shopwi‍n‍d.net自行微信登录、QQ、支付宝登录 商家体验:https://v4.shopwind.n‍et/seller/login商家测试账号:18978189171 密码:111111 移动端体验 H5 端体验:‍https://v4.shopwind.net/h5 更新内容如下: 新增商品采集插件 新增移动端发布商品增加商品类型(实物商品,服务商品,虚拟商品)字段 新增服务端访问的域名与安装时的域名如果不一致给出提示 新增服务端管理后台 DIY 装修选择商品组件增加分类和关键词搜索条件 新增服务端管理后台 DIY 装修选择秒杀商品组件增加分类和关键词搜索条件 新增电脑端配送时效功能模块(可设置店铺承诺发货送到时效) 新增移动端商品详情页显示物流配送时效 新增电脑端店铺商品分类设置 新增电脑端发布商品时增加本店分类 新增 API 接口【获取商品详情接口】增加返回字段本店分类(scategory)数组 新增 API 接口【获取商品列表】增加入参店铺商品分类(scate_id)筛选条件 新增移动端店铺底部主导航模块(首页 - 商品 - 分类 - 客服) 新增移动端店铺商品分类页 优化数据采集插件,在采集商品时可以选择不同的插件(已安装配置好)来采集商品 优化采集插件【99api】通过链接自动识别采集的平台 优化移动端发布 / 编辑商品,品牌项增加 “请选择” 优化移动端商品详情页批发价格增加 1 件的价格显示 优化服务端管理后台 DIY 装修输入链接的操作(增加选择链接的快捷方式) 修复移动端商品列表中显示已关闭的店铺的商品数据 修复电脑端购买商品后支付成功返回页面空白的问题 修复移动端 DIY 组件【优惠券】页面效果错位的问题 修复电脑端卖家中心限时秒杀商品编辑无法加载商品的问题 修复电脑端商家中心搭配购商品编辑无法加载商品的问题 修复电脑端商家中心搭配购商品列表活动状态显示不正确的问题 修复电脑端商品中心批发价商品列表活动状态显示不正确的问题 修复电脑端商品中心三级分销商品列表活动状态显示不正确的问题 修复服务端配置 EMail 组件(未配置可使用)的情况下,提交订单报错的问题 修复商品详情页配送地址(省市区)显示有误的问题 修复电脑端我是商家 - 上传店铺 LOGO 不成功的问题 修复移动端我的 - 设置生日是无法弹出选择日期组件

优秀的个人博客,低调大师

从零用 Java 实现小红书 SpringBoot Vue UniApp(19)分享卡片、体验时长与上线清单

>## [**移动端演示 http://8.146.211.120:8081/#/**](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8081%2F%23%2F) ## [**管理端演示 http://8.146.211.120:8088/#/**](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8088%2F%23%2F) ## [**项目整体介绍及演示**](https://gitee.com/link?target=https%3A%2F%2Fblog.csdn.net%2Fqq_35238367%2Farticle%2Fdetails%2F145126222) **前言** (16)~(18)分别做了 IM、直播、聊天室。把用户真正「拉进来」,还差最后一公里:**分享**与**可控的试用时长**。 本章聚焦两件运营向能力: 1. 直播 / 聊天室邀请以**卡片消息**发到私信或群聊,点击直达房间 2. `max-minutes` 体验限制:配置、倒计时、到期关房、一键 SQL ---- ![IM 架构:卡片消息走统一协议](https://developer.qcloudimg.com/http-save/yehe-12101878/04bc4457806b7d1a66ec617a0543f174.png) ![消息中的直播 / 聊天室邀请卡片](https://developer.qcloudimg.com/http-save/yehe-12101878/953b8b5d07c8bc3753a354e4c606d76e.png) ![线上演示:消息 Tab 会话列表](https://developer.qcloudimg.com/http-save/yehe-12101878/e1bfc2452659ce1148957ea2f8bd400c.png) ![线上演示:私信聊天页](https://developer.qcloudimg.com/http-save/yehe-12101878/905fbdc6e09e8cbb356b02979cfd9cdb.png) ![直播倒计时示意](https://developer.qcloudimg.com/http-save/yehe-12101878/1f41eabad5117b0ae83220c7dae3a065.png) ![聊天室倒计时示意](https://developer.qcloudimg.com/http-save/yehe-12101878/35952566f3618adba262e29d25e2e937.png) ![开播页](https://developer.qcloudimg.com/http-save/yehe-12101878/b2977e3a0ae47120a9aecccafad13891.png) ![聊天室入口](https://developer.qcloudimg.com/http-save/yehe-12101878/f483d9ee5fa9b4d7eda17dfc92bcd679.png) ![管理端仪表盘(线上截图)](https://developer.qcloudimg.com/http-save/yehe-12101878/62d6c56986ff1e8930800477d8bae40a.png) ### 一、分享卡片:为什么不用纯文本链接 纯文本链接有两个问题:聊天里不好识别;无法带封面、标题、主播信息。 因此扩展私信/群聊 `contentType`: |类型值|含义|会话摘要| |:-:|:-:|:-:| |`7` LIVE|直播邀请卡|`[直播]标题`| |`8` VOICE_ROOM|聊天室邀请卡|`[聊天室]标题`| 后端摘要(16 已埋点): ``` if (contentType == TYPE_LIVE) { return "[直播]" + extractNoteTitle(content); } if (contentType == TYPE_VOICE_ROOM) { return "[聊天室]" + extractNoteTitle(content); } ``` #### 发送链路 ``` 直播间/聊天室点击分享 → 选择「发给好友」 → share-invite 页选互关好友(或进群) → 组装卡片 payload 调用私信/群发接口 → 对端气泡渲染卡片 → 点击跳转 live?id= / voice-room/room?roomNo= ``` #### 邀请链接(站外私域) ``` export function buildLiveInviteLink(noteId) { // #ifdef H5 if (typeof location !== 'undefined') { const base = `${location.origin}${location.pathname || '/'}`; return `${base}#/pages/note/live?id=${encodeURIComponent(noteId)}`; } // #endif return `/pages/note/live?id=${noteId}`; } export function buildVoiceRoomInviteLink(roomNo) { // #ifdef H5 if (typeof location !== 'undefined') { const base = `${location.origin}${location.pathname || '/'}`; return `${base}#/pages/voice-room/room?roomNo=${encodeURIComponent(roomNo)}`; } // #endif return `/pages/voice-room/room?roomNo=${roomNo}`; } ``` #### 卡片 payload 组装思路 与笔记分享同一套路(`buildNotePayload` 模式):JSON 字符串写入 `content`,`contentType` 标 7 或 8。 ``` // 直播卡示意 function buildLiveSharePayload(note) { return JSON.stringify({ noteId: note.id, title: note.title || '直播中', coverUrl: note.coverUrl || '', nickname: note.anchorNickname || '', avatar: note.anchorAvatar || '', liveMode: note.liveMode, // 0 语音 / 1 视频 }); } // 聊天室卡示意 function buildVoiceRoomSharePayload(room) { return JSON.stringify({ roomNo: room.roomNo, title: room.title || '聊天室', coverUrl: room.ownerAvatar || '', nickname: room.ownerNickname || '', mediaMode: room.mediaMode, }); } // 发送 await DmApi.sendMessage({ peerId, contentType: 7, // 或 8 content: buildLiveSharePayload(note), }); ``` 后端只需放宽 `contentType` 白名单并写好会话摘要,**不必为卡片单独建表**。 前端协议与页面: - `sheep/helper/dmContent.js` - `pages/message/share-invite.vue` - `pages/message/chat.vue` / `group-chat.vue` 渲染与点击跳转 ---- ### 二、体验时长:配置驱动 |config_key|默认|说明| |:-:|:-:|:-:| |`member.live.max-minutes`|30|直播单场最长分钟,`0`=不限制| |`member.voice-room.max-minutes`|30|聊天室单场最长分钟,`0`=不限制| #### 三端协同 1. **后端**:credentials / 进房接口返回 `maxMinutes` + 到期时间;定时任务扫到期房间 2. **Vue 页**:`experienceCountdown.js` 中部倒计时;到期弹窗 3. **Hybrid TRTC 页**:URL 带 `expireAt`,App WebView 内同样倒计时兜底 ``` export function createExperienceCountdown(options) { const expireAtMs = Number(options?.expireAtMs) || 0; const onTick = options?.onTick; const onExpire = options?.onExpire; let timer = null; const tick = () => { const remain = Math.max(0, Math.ceil((expireAtMs - Date.now()) / 1000)); if (typeof onTick === 'function') onTick(remain, formatRemain(remain)); if (remain **演示地址** 移动端:[http://8.146.211.120:8081/#/](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8081%2F%23%2F) 管理端:[http://8.146.211.120:8088/#/](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8088%2F%23%2F) **代码地址** https://gitee.com/ddeatrr/springboot_vue_xhs

优秀的个人博客,低调大师

从零用 Java 实现小红书 SpringBoot Vue UniApp(16)消息体系:私信、群聊与视频通话

>## [**移动端演示 http://8.146.211.120:8081/#/**](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8081%2F%23%2F) ## [**管理端演示 http://8.146.211.120:8088/#/**](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8088%2F%23%2F) ## [**项目整体介绍及演示**](https://gitee.com/link?target=https%3A%2F%2Fblog.csdn.net%2Fqq_35238367%2Farticle%2Fdetails%2F145126222) **前言** 前十五章已经走通内容、商城,以及评论 / IM 基础图文能力。但真正让用户愿意留下来的,往往不是商品页,而是**人与人之间更完整的连接**。 本章在此基础上补齐完整消息体系: - 私信多媒体(文字 / 图片 / 语音 / 视频 / 笔记卡片) - 群聊(创建、广场、禁言、撤回、在线人数) - 会话聚合 Inbox(置顶、未读) - 社交互动通知(赞藏、关注、评论@) - 1v1 音视频通话(腾讯云 TRTC) 形成「内容社区 + IM」双引擎。 ---- ![消息体系架构示意](https://developer.qcloudimg.com/http-save/yehe-12101878/9df1bd8e063a67302fed23fb16fb9c20.png) ![IM 能力总览](https://developer.qcloudimg.com/http-save/yehe-12101878/e708a91d1b19b87b08833f88d967889f.png) ![线上演示:消息 Tab 会话列表](https://developer.qcloudimg.com/http-save/yehe-12101878/8dcb406bfad68829f014722e6568d3a0.png) ![线上演示:私信聊天页](https://developer.qcloudimg.com/http-save/yehe-12101878/5dbcbdb33221838116cea1ce52546c39.png) ![消息里的邀请卡片与多媒体气泡](https://developer.qcloudimg.com/http-save/yehe-12101878/f920d5d7db453b46ef0ef52774bc0824.png) ![管理端仪表盘(线上截图)](https://developer.qcloudimg.com/http-save/yehe-12101878/2a37d9244956adf03987fa73be82d5ea.png) ### 相对原教程,本章新增了什么 |能力|早期教程|当前工程| |:-:|:-:|:-:| |私信|文本为主|文本/图/语音/视频/笔记/通话记录/直播邀请卡| |群聊|无|完整群生命周期 + 广场发现| |会话列表|简单列表|Inbox 聚合、置顶、未读角标| |实时通道|有限|全局 WebSocket 单连接多业务复用| |音视频通话|无|TRTC 发起/接听/拒绝/挂断全流程| ---- ### 一、整体架构 消息体系拆成四条线: 1. **会话线**:Inbox 汇总私信会话 + 群会话,负责未读与置顶 2. **内容线**:统一 `contentType + content`,多媒体用 JSON 存 payload 3. **实时线**:WebSocket 推送新消息、已读、在线人数、来电 4. **通话线**:RTC 信令走业务接口,媒体走 TRTC ``` 消息 Tab ├─ 赞藏 / 关注 / 评论@ 通知入口 └─ Inbox 会话列表(私信 + 群) ↓ 点进会话 chat.vue / group-chat.vue ↓ 发送 POST /member/dm/message/send ↓ 落库 + WebSocket 推对端 ``` ---- ### 二、消息类型协议(核心) 后端在 `MemberDmServiceImpl` 中定义类型常量,前后端约定同一套数字: ``` private static final int TYPE_TEXT = 1; private static final int TYPE_IMAGE = 2; private static final int TYPE_VOICE = 3; private static final int TYPE_NOTE = 4; private static final int TYPE_VIDEO = 5; /** 语音/视频通话记录 */ private static final int TYPE_CALL = 6; /** 直播分享卡片 */ private static final int TYPE_LIVE = 7; /** 音视频聊天室分享卡片 */ private static final int TYPE_VOICE_ROOM = 8; ``` 发送时做白名单校验,非法类型回落为文本: ``` int contentType = reqVO.getContentType() == null ? TYPE_TEXT : reqVO.getContentType(); if (contentType != TYPE_TEXT && contentType != TYPE_IMAGE && contentType != TYPE_VOICE && contentType != TYPE_NOTE && contentType != TYPE_VIDEO && contentType != TYPE_LIVE && contentType != TYPE_VOICE_ROOM) { contentType = TYPE_TEXT; } ``` 会话列表摘要按类型简化展示(和早期「评论/IM 加图片」同一思路): ``` private String buildSummary(int contentType, String content) { if (contentType == TYPE_IMAGE) { return "[图片]"; } if (contentType == TYPE_VOICE) { return "[语音]"; } if (contentType == TYPE_VIDEO) { return "[视频]"; } if (contentType == TYPE_NOTE) { return "[笔记]" + extractNoteTitle(content); } if (contentType == TYPE_LIVE) { return "[直播]" + extractNoteTitle(content); } if (contentType == TYPE_VOICE_ROOM) { return "[聊天室]" + extractNoteTitle(content); } // ... return StrUtil.maxLength(content, 80); } ``` 前端类型常量与组装工具(`sheep/helper/dmContent.js`): ``` export const DM_TYPE = { TEXT: 1, IMAGE: 2, VOICE: 3, NOTE: 4, VIDEO: 5, }; export function buildVoicePayload(url, durationSec) { return JSON.stringify({ url, duration: Math.max(1, Math.round(durationSec || 1)), }); } export function buildNotePayload(note) { const cover = note.coverUrl || (note.picUrls && note.picUrls.length ? note.picUrls[0] : '') || ''; const summary = (note.content || note.title || '').replace(/\s+/g, ' ').trim().slice(0, 80); return JSON.stringify({ noteId: note.id, title: note.title || summary || '笔记', coverUrl: cover, nickname: note.nickname || '', avatar: note.avatar || '', summary, noteType: Number(note.noteType || 0), likeCount: Number(note.likeCount || 0), }); } ``` 发送接口: ``` // sheep/api/member/dm.js sendMessage: (data) => { return request({ url: '/member/dm/message/send', method: 'POST', data, custom: { auth: true, showLoading: false }, }); }, ``` ---- ### 三、私信气泡:按 contentType 条件渲染 `pages/message/chat.vue` 里根据类型切换 UI(笔记卡 / 语音条 / 视频封面 / 图片 / 文本): ``` {{ notePayload(item)?.title || '笔记' }} {{ voiceDuration(item) }}" {{ videoDurationText(item) }} {{ item.content }} ``` 发送封装: ``` async function sendContent(content, contentType = DM_TYPE.TEXT) { const payload = contentType === DM_TYPE.TEXT ? (content || '').trim() : content || ''; const { code, data } = await DmApi.sendMessage({ peerId: state.peerId, contentType, content: payload, }); // 成功后 push 到本地 messageList,并滚到底部 } ``` ---- ### 四、WebSocket:一条连接多业务复用 类型常量集中在 `WebSocketMessageTypeConstants`: ``` /** 私信新消息 */ String MEMBER_DM_MESSAGE = "member_dm_message_type"; /** 群聊新消息 */ String MEMBER_GROUP_CHAT_MESSAGE = "member_group_chat_message_type"; /** 消息未读总数变更 */ String MEMBER_UNREAD_COUNT = "member_unread_count_type"; /** 视频通话邀请 / 接听 / 拒绝 / 取消 / 挂断 */ String MEMBER_RTC_CALL_INVITE = "member_rtc_call_invite_type"; String MEMBER_RTC_CALL_ACCEPTED = "member_rtc_call_accepted_type"; String MEMBER_RTC_CALL_REJECTED = "member_rtc_call_rejected_type"; String MEMBER_RTC_CALL_CANCELLED = "member_rtc_call_cancelled_type"; String MEMBER_RTC_CALL_HANGUP = "member_rtc_call_hangup_type"; ``` 前端 `sheep/helper/wsGlobal.js` 订阅未读与来电;进聊天页再处理具体消息推送。这样消息 Tab 角标、聊天页气泡、来电弹窗共用同一条长连接。 ---- ### 五、群聊要点 群聊覆盖运营侧常见能力: - 创建群、群广场发现、申请加入 - 群公告、成员列表、邀请入群 - 群主禁言、踢人、消息撤回 - 群在线人数实时订阅(`MEMBER_GROUP_CHAT_ONLINE_*`) 消息体同样走 `contentType`,与私信协议对齐,前端 `group-chat.vue` 复用气泡渲染思路。 ---- ### 六、1v1 音视频通话 通话信令接口(`AppMemberRtcController`): ``` @PostMapping("/call/create") @Operation(summary = "发起 1v1 视频通话") public CommonResult create(@Valid @RequestBody AppMemberRtcCallCreateReqVO reqVO) { return success(rtcService.createCall(getLoginUserId(), reqVO)); } @PostMapping("/call/accept") public CommonResult accept(@RequestParam("roomId") String roomId) { return success(rtcService.acceptCall(getLoginUserId(), roomId)); } @PostMapping("/call/reject") public CommonResult reject(@RequestParam("roomId") String roomId) { rtcService.rejectCall(getLoginUserId(), roomId); return success(true); } ``` 创建通话后通过 WebSocket 推送来电;接听返回 TRTC 凭证,媒体进独立通话页。结束后写一条 `TYPE_CALL` 气泡到私信会话。 流程: ``` 发起方 createCall → 对端 WS 收到 INVITE → accept / reject / timeout → TRTC 进房通话 → hangup → 私信写入通话记录气泡 ``` ---- ### 关键代码位置 **后端** - 私信:`yudao-module-member/.../service/dm/MemberDmServiceImpl.java` - 群聊:`.../controller/app/groupchat/` - 会话 Inbox:`.../controller/app/inbox/` - 通话:`.../controller/app/rtc/AppMemberRtcController.java` - WS 常量:`.../enums/WebSocketMessageTypeConstants.java` **移动端** - 消息 Tab:`pages/index/message.vue` - 私信:`pages/message/chat.vue` - 内容协议:`sheep/helper/dmContent.js` - 全局 WS:`sheep/helper/wsGlobal.js` ---- ### 总结 1. 用统一 `contentType` 扩展多媒体,避免每种消息各建一套表 2. Inbox + WebSocket 解决多入口未读不一致 3. 信令与媒体分离:业务状态走后端,音视频走 TRTC #### 下一章预告 有了 IM 通道之后,下一章接入 **TRTC 直播**:笔记开播、公屏弹幕、心跳关播、体验时长倒计时。 ---- >**演示地址** 移动端:[http://8.146.211.120:8081/#/](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8081%2F%23%2F) 管理端:[http://8.146.211.120:8088/#/](https://gitee.com/link?target=http%3A%2F%2F8.146.211.120%3A8088%2F%23%2F) **代码地址** https://gitee.com/ddeatrr/springboot_vue_xhs

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册