注释搜索:主播发送消息

观看列表只能主播跟管理员查看
This commit is contained in:
cbb
2026-02-10 17:49:33 +08:00
parent 2cc252dce0
commit 20ccbf1f14
19 changed files with 190 additions and 67 deletions

2
.env
View File

@@ -1,5 +1,5 @@
# API
# VITE_SYSTEM_URL = "http://h69b336a.natappfree.cc"
# VITE_SYSTEM_URL = "http://s8e84fdb.natappfree.cc"
VITE_SYSTEM_URL = "https://dev.cqjcteach.cn/prod-api"
# 第三方客户 channelId

View File

@@ -851,6 +851,7 @@
userIDList
}
try {
// await updateProfile({ key: 'inviteOption', value: TUIChatEngine.TYPES.INVITE_OPTIONS_FREE_ACCESS })
await TUIGroupService.addGroupMember(options)
} catch (error) {
console.log(error)

View File

@@ -53,6 +53,15 @@ export const addOrder = data => {
})
}
/** 加入订单 */
export const addOrderItem = data => {
return http({
url: '/api/service/order/join',
method: 'post',
data
})
}
/** 创建普通订单接口 */
export const createOrder = data => {
return http({

View File

@@ -164,10 +164,11 @@ export const getUserWithdrawConfig = id => {
}
/** 获取用户积分详细信息 */
export const getUserIntegral = () => {
export const getUserIntegral = (loading = true) => {
return http({
url: `/api/system/userPoints/details`,
method: 'get'
method: 'get',
loading
})
}
@@ -308,3 +309,12 @@ export const getUserBuyRecordDetail = id => {
method: 'get'
})
}
/** 修改订单 */
export const updateUserBuyRecord = data => {
return http({
url: `/api/service/order`,
method: 'put',
data
})
}

View File

@@ -1,7 +1,9 @@
/** 直播间 businessID 唯一值 */
export const LIVE_BUSINESS = {
// 管理员
// 系统管理员发送
ADMIN: 'admin',
// 签到
SIGN: 'sign',
/** 房间管理员 */
ANCHOR: 'anchor',
}

View File

@@ -355,12 +355,6 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/shop-together/user",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/discover/ranking-list",
"style": {
@@ -404,6 +398,12 @@
}
},
// #ifdef APP-PLUS
{
"path": "pages/shop-together/user",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/discover/livelist/index",
"style": {

View File

@@ -1,4 +1,5 @@
<template>
<!-- 开始直播页面 -->
<view
class="live-container"
@click="handleHideInput"
@@ -193,12 +194,15 @@
:groupID="groupId"
:creatorType="creatorType"
></Activity>
<LiveAudienceList v-model="isShowAudienceList"></LiveAudienceList>
<LiveAudienceList v-model="isShowAudienceList" @adminBack="handleAdminBack"></LiveAudienceList>
<AudienceActionPanel
v-if="liveID"
v-if="liveID && isShowAudienceActionPanel"
v-model="isShowAudienceActionPanel"
:userInfo="selectedAudience"
:liveID="liveID"
@adminBack="handleAdminBack"
></AudienceActionPanel>
<CoGuestPanel
@@ -476,6 +480,19 @@
templateLayout.value = data
}
/** 设置管理员回调(发送自定义消息) */
const handleAdminBack = (e) => {
const data = {
liveID: liveID.value,
businessID: LIVE_BUSINESS.ANCHOR,
data: JSON.stringify({
...e,
count: `${e.userName}${e.show ? '成为' : '撤销'}管理员`
})
}
sendCustomMessage(data)
}
// 自定义Modal相关方法
const showCustomModalDialog = userInfo => {
currentModalUserInfo.value = userInfo

View File

@@ -1,4 +1,5 @@
<template>
<!-- 观众端页面 -->
<view
class="live-container"
@click="handleHideInput"

View File

@@ -240,7 +240,9 @@
</span>
</div>
<div class="top-right">
<div class="audience-list-header" @click="showAudienceList">
<!-- 不能点击查看观众列表 -->
<!-- @click="showAudienceList" -->
<div class="audience-list-header">
<Avatar
v-for="item in audienceList.slice(0, 3)"
:key="item.userId"

View File

@@ -97,8 +97,6 @@
}
}
// 订单列表
.order-list {
padding: 24rpx 0;
@@ -111,7 +109,9 @@
margin-bottom: 24rpx;
padding: 32rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.03);
transition: transform 0.2s ease, box-shadow 0.2s ease;
transition:
transform 0.2s ease,
box-shadow 0.2s ease;
&:active {
transform: translateY(-2rpx);
@@ -314,4 +314,24 @@
}
}
// 底部按钮
.bottom-btn {
margin-top: 16rpx;
display: flex;
justify-content: end;
button {
margin: 0;
border-radius: 80rpx;
width: 180rpx;
height: 60rpx;
line-height: 60rpx;
font-size: 26rpx;
color: #333333;
background: #fff;
border: 2rpx solid #d4dae0;
box-sizing: border-box;
&:after {
display: none;
}
}
}

View File

@@ -1,8 +1,13 @@
<script setup>
import { ref, computed, onMounted, reactive } from 'vue'
import { navigateTo } from '@/utils/router'
import { getUserBuyRecordList } from '../../../api/my-index'
import {
getUserBuyRecordList,
updateUserBuyRecord
} from '../../../api/my-index'
import { useUI } from '../../../utils/use-ui'
const { showDialog, showToast } = useUI()
// 响应式数据
const paging = ref(null)
const activeFilter = ref('') // -1表示全部
@@ -36,6 +41,7 @@
const getList = async () => {
try {
const res = await getUserBuyRecordList({
// orderType: 1,
orderStatus: activeFilter.value,
pageNum: formData.pageNum,
pageSize: formData.pageSize
@@ -74,6 +80,19 @@
const getStatusClass = status => {
return statusMap[status]?.color || 'status-default'
}
/** 确认收货按钮回调 */
const confirmReceipt = async item => {
const show = await showDialog('提示', '确认已收到商品吗?')
if (!show) return
const data = {
orderStatus: 8,
id: item.id
}
await updateUserBuyRecord(data)
item.orderStatus = 8
showToast('收货成功', 'success')
}
</script>
<template>
@@ -187,7 +206,6 @@
<view class="goods-info">
<text class="goods-name">{{ item.userName }}</text>
<text class="goods-spec">
<!-- {{ item.orderType == 1 ? '普通订单' : '拼单订单' }} -->
{{ item.specText }}
</text>
<view class="goods-price-info">
@@ -206,6 +224,11 @@
</view>
</view>
<!-- 底部按钮 -->
<view v-if="item.orderStatus == 7" class="bottom-btn">
<button @click.stop="confirmReceipt(item)">确认收货</button>
</view>
<!-- 底部装饰线 -->
<view class="card-footer">
<view class="decorative-line"></view>

View File

@@ -1,6 +1,11 @@
<script setup>
import { onLoad, onShow } from '@dcloudio/uni-app'
import { getProductDetail, addOrder, createOrder } from '@/api/mall'
import {
getProductDetail,
addOrder,
addOrderItem,
createOrder
} from '@/api/mall'
import { reactive, ref } from 'vue'
import { formatRMB } from '@/utils'
import { getUserAddress } from '@/api'
@@ -86,13 +91,13 @@
const getData = async productId => {
const res = await getProductDetail(productId)
viewData.value = res.data
const {
id,
price,
stockQuantity,
originalPrice: nub
} = res.data.skuList[0]
originalPrice.value = nub
formData.maxNum = stockQuantity
formData.spec = id
@@ -142,15 +147,19 @@
skuId: formData.spec
}
tixian.value.close()
if (formData.startGroup) {
const res = await addOrder(data)
await refreshUserInfo()
await showToast('订单提交成功', 'success')
const isApiShow = formData.startGroup
let api = null
if (isApiShow) {
api = data.groupId ? addOrderItem : addOrder
} else {
api = createOrder
}
const res = await api(data)
await refreshUserInfo()
await showToast('订单提交成功', 'success')
if (isApiShow) {
navigateTo('/pages/shop-together/detail', { id: res.data.groupId })
} else {
const res = await createOrder(data)
await refreshUserInfo()
await showToast('订单提交成功', 'success')
navigateBack()
}
}
@@ -163,7 +172,6 @@
// groupId
groupId.value = e?.groupId || ''
console.log(e?.groupId, '===')
formData.startGroup = !!e?.groupId
await getData(e.productId)
})
</script>
@@ -268,9 +276,10 @@
></image>
</view>
</view>
<!--
v-if="groupId" -->
<view
v-if="groupId"
v-if="!groupId"
class="pay-way-item"
@click="formData.startGroup = !formData.startGroup"
>

View File

@@ -1,10 +1,11 @@
<script setup>
import { useAuthUser } from '@/composables/useAuthUser'
import { onLoad } from '@dcloudio/uni-app'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { navigateTo } from '@/utils/router'
import { useUI } from '@/utils/use-ui'
import { formatNumberWithWan } from '../../utils'
import { getUserPayPwd } from '@/api/my-index'
import { useUserStore } from '../../stores/user'
const bottomList = [
{
@@ -17,7 +18,11 @@
icon: 'user-code',
url: '/pages/my-index/wallet/invite'
},
{ name: '我的拼团伙伴', icon: 'team', url: '/pages/my-index/my-team' },
{
name: '我的拼团伙伴',
icon: 'team',
url: '/pages/my-index/my-team'
},
// { name: '群创建直播', icon: 'videocam', url: '' },
{
name: '直播记录',
@@ -46,6 +51,7 @@
}
]
const { getIntegral } = useUserStore()
const { showDialog } = useUI()
const { userInfo, integralData } = useAuthUser()
@@ -70,6 +76,9 @@
// 获取用户信息
console.log(userInfo.value, '===获取用户信息')
})
onShow(() => {
getIntegral(false)
})
</script>
<template>
@@ -179,7 +188,9 @@
display: flex;
flex-direction: column;
.name {
font-family: PingFang SC, PingFang SC;
font-family:
PingFang SC,
PingFang SC;
font-weight: bold;
font-size: 32rpx;
color: #333333;
@@ -227,7 +238,9 @@
display: flex;
flex-direction: column;
text {
font-family: PingFang SC, PingFang SC;
font-family:
PingFang SC,
PingFang SC;
font-weight: 500;
font-size: 28rpx;
color: #ffffff;
@@ -248,7 +261,9 @@
height: 64rpx;
line-height: 64rpx;
border-radius: 100rpx 100rpx 100rpx 100rpx;
font-family: PingFang SC, PingFang SC;
font-family:
PingFang SC,
PingFang SC;
font-weight: 500;
font-size: 28rpx;
color: #ffffff;
@@ -283,7 +298,9 @@
}
.text-box {
margin-left: 16rpx;
font-family: PingFang SC, PingFang SC;
font-family:
PingFang SC,
PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #333333;

View File

@@ -103,10 +103,16 @@
>
<view class="left-name">
<image
src="https://wx1.sinaimg.cn/mw690/92eeb099gy1i29hl0ne80j21jk2bcash.jpg"
v-if="item.avatar"
:src="item.avatar"
mode="scaleToFill"
class="avatar"
></image>
<uni-icons
v-else
type="contact-filled"
size="120rpx"
></uni-icons>
<text>{{ item.userName }}</text>
</view>
<text class="date">加入时间{{ item.paidTime }}</text>

View File

@@ -1,22 +0,0 @@
module.exports = {
printWidth: 74,
tabWidth: 2,
semi: false,
arrowParens: 'avoid',
singleQuote: true,
trailingComma: 'none',
bracketSpacing: true,
htmlWhitespaceSensitivity: 'ignore',
endOfLine: 'auto',
insertPragma: false,
proseWrap: 'preserve',
'objectCurly-newline': [
'error',
{
multiline: true
}
],
'array-bracket-newline': ['error', 'consistent'],
vueIndentScriptAndStyle: true
}

View File

@@ -126,8 +126,8 @@ export const useUserStore = defineStore('user', () => {
}
/** 获取用户积分 */
const getIntegral = async () => {
const res = await getUserIntegral()
const getIntegral = async (loading = true) => {
const res = await getUserIntegral(loading)
integralData.value = res.data.availablePoints
}

View File

@@ -23,7 +23,13 @@
<view class="nickname-content-wrapper">
<text class="chat-nickname"
numberOfLines="1">{{ message?.sender?.userName || message?.sender?.userID }}</text>
<text class="chat-content">{{ message?.textContent || '' }}</text>
<!-- 主播发送消息
<text v-if="message?.businessID == 'anchor'" class="chat-content">
{{ getAnchorMessageText(message) }}
</text> -->
<text class="chat-content">
{{ message?.textContent || '' }}
</text>
</view>
</view>
</view>
@@ -177,9 +183,16 @@
emit('itemTap', message);
};
/** 主播发送自定义消息显示文本 */
const getAnchorMessageText = (message: any) => {
const data = JSON.parse(message.data)
return data.count
}
const handleReceiveGift = {
callback: (event) => {
const res = JSON.parse(event)
console.log('===消息接收===', res)
const value = {
...res,
textContent: `${res.gift?.name || ''}`,

View File

@@ -1,5 +1,5 @@
<template>
<view class="bottom-drawer-container" v-if="modelValue">
<view class="bottom-drawer-container" v-if="!loading && modelValue">
<view class="drawer-overlay" @tap="close"></view>
<view class="bottom-drawer" :class="{ 'drawer-open': modelValue }">
<view class="drawer-header">
@@ -126,7 +126,10 @@
}
})
const emit = defineEmits(['update:modelValue', 'update:userInfo'])
const emit = defineEmits(['update:modelValue', 'update:userInfo', 'adminBack'])
/** 加载状态 */
const loading = ref(true)
/** 禁言,管理员列表 */
const listData = reactive({
@@ -168,12 +171,16 @@
Promise.all(apiList).then((res) => {
listData.tabooList = res[0].data.Response?.MutedAccountList || []
listData.adminList = res[1].data.Response?.Admin_Account || []
console.log('===请求接口了!!!')
if (state === 1) {
showToast(`${isMessageDisabled.value ? '禁止' : '恢复'}成功`, 'success')
}
if (state === 2) {
showToast(`${isAdminShow.value ? '设置' : '撤销'}成功`, 'success')
}
}).finally(() => {
loading.value = false
})
}
@@ -200,6 +207,10 @@
userID: userData.value.userID,
success: () =>{
getListData(2)
emit('adminBack', {
...userData.value,
show: !isAdminShow.value
})
close()
}
})

View File

@@ -40,7 +40,7 @@
</view>
</view>
<AudienceActionPanel v-model="isShowAudienceActionPanel" :userInfo="selectedAudience" :liveID="liveID" :adminType="isAdminState">
<AudienceActionPanel v-model="isShowAudienceActionPanel" :userInfo="selectedAudience" :liveID="liveID" :adminType="isAdminState" @adminBack="onAdminBack">
</AudienceActionPanel>
</view>
@@ -108,7 +108,7 @@ import { useAuthUser } from '../../../../composables/useAuthUser';
}
});
const emit = defineEmits(['update:modelValue']);
const emit = defineEmits(['update:modelValue', 'adminBack']);
const close = () => {
emit('update:modelValue', false);
};
@@ -124,6 +124,10 @@ import { useAuthUser } from '../../../../composables/useAuthUser';
}
})
const onAdminBack = (e) => {
emit('adminBack', e)
}
// 初始化加载
onMounted(() => {
uni.getSystemInfo({