订单,视频通话需要开发

This commit is contained in:
cbb
2026-02-07 17:44:59 +08:00
parent 101ddcb0c1
commit 20b6be5dfb
13 changed files with 259 additions and 120 deletions

View File

@@ -291,3 +291,20 @@ export const endUserService = id => {
method: 'get' method: 'get'
}) })
} }
/** 购买记录 */
export const getUserBuyRecordList = data => {
return http({
url: '/api/service/order/list',
method: 'get',
data
})
}
/** 购买记录详情 */
export const getUserBuyRecordDetail = id => {
return http({
url: `/api/service/order/${id}`,
method: 'get'
})
}

View File

@@ -31,12 +31,31 @@
<text class="action-btn-content">镜像</text> <text class="action-btn-content">镜像</text>
</view> </view>
<view class="action-btn" @tap="openNetworkQualityPanel"> <!-- <view class="action-btn" @tap="openNetworkQualityPanel">
<view class="action-btn-image-container"> <view class="action-btn-image-container">
<image class="action-btn-image" src="/static/images/live-dashboard.png" mode="aspectFit" /> <image class="action-btn-image" src="/static/images/live-dashboard.png" mode="aspectFit" />
</view> </view>
<text class="action-btn-content">仪表盘</text> <text class="action-btn-content">仪表盘</text>
</view> </view> -->
<view class="action-btn" @tap="muteSpeak">
<view class="action-btn-image-container">
<image
v-if="isMessageDisabled"
class="action-btn-image"
src="/static/images/jinzhifayan.png"
mode="aspectFit"
/>
<image
v-else
class="action-btn-image"
src="/static/images/yunxufayan.png"
mode="aspectFit"
/>
</view>
<text v-if="isMessageDisabled" class="action-btn-content">禁止发言</text>
<text v-else class="action-btn-content">恢复发言</text>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -50,7 +69,8 @@
<script setup> <script setup>
import { import {
ref, ref,
onMounted onMounted,
watch
} from 'vue'; } from 'vue';
import NetworkQualityPanel from '@/uni_modules/tuikit-atomic-x/components/NetworkQualityPanel.nvue'; import NetworkQualityPanel from '@/uni_modules/tuikit-atomic-x/components/NetworkQualityPanel.nvue';
import BeautyPanel from '@/uni_modules/tuikit-atomic-x/components/BeautyPanel.nvue'; import BeautyPanel from '@/uni_modules/tuikit-atomic-x/components/BeautyPanel.nvue';
@@ -58,6 +78,8 @@
import { import {
useDeviceState useDeviceState
} from "@/uni_modules/tuikit-atomic-x/state/DeviceState"; } from "@/uni_modules/tuikit-atomic-x/state/DeviceState";
import { useUI } from '../utils/use-ui';
import useLiveListState from '@/uni_modules/tuikit-atomic-x/state/LiveListState';
const { const {
isFrontCamera, isFrontCamera,
@@ -66,6 +88,10 @@
localMirrorType localMirrorType
} = useDeviceState(uni?.$liveID); } = useDeviceState(uni?.$liveID);
const { updateLiveInfo } = useLiveListState()
const { showLoading, hideLoading, showDialog, showToast } = useUI()
const defaultavatarURL = 'https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_01.png'; const defaultavatarURL = 'https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_01.png';
const props = defineProps({ const props = defineProps({
@@ -79,15 +105,30 @@
userName: '', userName: '',
userID: '', userID: '',
avatarURL: '', avatarURL: '',
isMessageDisabled: false,
userRole: 1 userRole: 1
}) })
}, },
currentLive: {
type: Object,
default: () => ({})
}
}); });
const emit = defineEmits(['update:modelValue', 'update:currentLive']);
// 监听当前直播信息变化
watch(() => props?.currentLive, (newLive) => {
if (newLive) {
console.log('当前直播信息更新:', newLive);
isMessageDisabled.value = !newLive.isMessageDisable
}
});
const isShowNetworkQualityPanel = ref(false); const isShowNetworkQualityPanel = ref(false);
const isShowBeautyPanel = ref(false); const isShowBeautyPanel = ref(false);
const isShowAudioEffect = ref(false); const isShowAudioEffect = ref(false);
/** 禁止发言状态 */
const isMessageDisabled = ref(true)
const handleBeauty = () => { const handleBeauty = () => {
isShowBeautyPanel.value = true; isShowBeautyPanel.value = true;
@@ -126,10 +167,37 @@
} }
} }
const emit = defineEmits(['update:modelValue']);
const close = () => { const close = () => {
emit('update:modelValue', false); emit('update:modelValue', false);
}; };
const muteSpeak = async () => {
// showDialog
const show = await showDialog('提示', `确认${isMessageDisabled.value ? '禁止' : '恢复'}全部观众发言?`)
if (show) {
showLoading()
const liveInfo = {
liveID: uni?.$liveID,
isMessageDisable: isMessageDisabled.value
}
updateLiveInfo({
liveInfo,
modifyFlagList: ['IS_MESSAGE_DISABLE'],
success: () => {
hideLoading()
showToast(`操作成功`, 'success')
isMessageDisabled.value = false
},
fail: (err) => {
hideLoading()
showToast(`操作失败`, 'error')
console.log('=====修改失败=====', err)
}
})
}
}
</script> </script>
<style> <style>

View File

@@ -492,6 +492,13 @@
"navigationStyle": "custom", "navigationStyle": "custom",
"navigationBarTitleText": "红包详情" "navigationBarTitleText": "红包详情"
} }
},
{
"path": "pages/discover/order/index",
"style": {
"navigationBarTitleText": "购买记录",
"navigationBarBackgroundColor": "#ffffff"
}
} }
], ],
"globalStyle": { "globalStyle": {
@@ -533,4 +540,4 @@
} }
] ]
} }
} }

View File

@@ -213,6 +213,7 @@
<LiveMoreActionsPanel <LiveMoreActionsPanel
v-if="liveID" v-if="liveID"
v-model="isShowLiveMoreActionsPanel" v-model="isShowLiveMoreActionsPanel"
:currentLive="currentLive"
></LiveMoreActionsPanel> ></LiveMoreActionsPanel>
<UserInfoPanel <UserInfoPanel
v-if="liveID" v-if="liveID"

View File

@@ -66,7 +66,7 @@
</text> </text>
</view> </view>
</view> </view>
<view class="control-icons" @click.stop="navigateBack()"> <view class="control-icons" @click.stop="topBack()">
<!-- <image class="control-icon" src="/static/images/live-share.png" /> --> <!-- <image class="control-icon" src="/static/images/live-share.png" /> -->
<image class="control-icon" src="/static/images/close.png" /> <image class="control-icon" src="/static/images/close.png" />
</view> </view>
@@ -211,7 +211,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { navigateTo } from '@/utils/router' import { navigateBack, navigateTo } from '@/utils/router'
import { import {
imDataEndLive, imDataEndLive,
getLiveActivityDetail, getLiveActivityDetail,
@@ -586,29 +586,14 @@
'onLocalMicrophoneClosedByAdmin', 'onLocalMicrophoneClosedByAdmin',
handleLocalMicrophoneClosedByAdmin handleLocalMicrophoneClosedByAdmin
) )
uni.$liveID = ''
isShowExitSheet.value = true
uni.showModal({ uni.showModal({
title: `提示`, title: `提示`,
content: `直播已结束`, content: `直播已结束`,
showCancel: false, showCancel: false
success: c => {
if (c.confirm) {
uni.$liveID = ''
uni.navigateBack({
delta: 1
});
// uni.redirectTo({
// url: `/pages/livelist/index`,
// delta: 1,
// success: () => {
// console.log('返回成功')
// },
// fail: err => {
// console.error('返回失败', err)
// }
// })
}
}
}) })
navigateBack()
} }
} }
const handleKickedOutOfLive = { const handleKickedOutOfLive = {
@@ -712,7 +697,7 @@
uni.hideKeyboard() uni.hideKeyboard()
} }
const navigateBack = () => { const topBack = () => {
if (uni.$localGuestStatus === 'CONNECTED') { if (uni.$localGuestStatus === 'CONNECTED') {
exitSheetItems.value = ['断开连麦', '退出直播间'] exitSheetItems.value = ['断开连麦', '退出直播间']
exitSheetTitle.value = exitSheetTitle.value =

View File

@@ -18,6 +18,10 @@
] ]
const onGo = item => { const onGo = item => {
if (item === 'shopping') {
navigateTo('/pages/discover/order/index')
return
}
if (item === 'project') { if (item === 'project') {
showDialog('提示', '外部链接暂未提供', false) showDialog('提示', '外部链接暂未提供', false)
return return

View File

@@ -58,7 +58,8 @@
const res = await getUserMomentsList({ const res = await getUserMomentsList({
pageNum, pageNum,
pageSize, pageSize,
targetUserId: isType.value == 1 ? userInfo.value.userId : targetUserId.value targetUserId:
isType.value == 1 ? userInfo.value.userId : targetUserId.value
}) })
const list = res.rows.map(item => { const list = res.rows.map(item => {
return { return {
@@ -93,8 +94,8 @@
/** 关闭评论框 */ /** 关闭评论框 */
const closeComment = () => { const closeComment = () => {
contentData.value = '' // contentData.value = ''
inputId.value = '' // inputId.value = ''
} }
/** 发布评论 */ /** 发布评论 */
@@ -108,6 +109,8 @@
const res = await addUserMomentsComment(data) const res = await addUserMomentsComment(data)
item.commentList.push(res.data) item.commentList.push(res.data)
closeComment() closeComment()
contentData.value = ''
inputId.value = ''
} }
/** 删除动态 */ /** 删除动态 */
@@ -191,7 +194,7 @@
<!-- 动态列表 --> <!-- 动态列表 -->
<view v-if="!listLoading" class="dynamic-list" @click="closeComment"> <view v-if="!listLoading" class="dynamic-list" @click="closeComment">
<view v-for="item in dataList" :key="item.id" class="list"> <view v-for="(item, i) in dataList" :key="i" class="list">
<image <image
v-if="item.avatar" v-if="item.avatar"
:src="item.avatar" :src="item.avatar"
@@ -258,15 +261,30 @@
></uni-icons> ></uni-icons>
</view> </view>
<view v-if="inputId === item.id" class="input-box"> <view v-if="inputId === item.id" class="input-box">
<input <uni-easyinput
v-model="contentData" v-model="contentData"
trim
:inputBorder="false"
:clearable="false"
:placeholder-style="placeholderStyle"
confirmType="done"
placeholder="评论"
@confirm.stop="onComment(item)"
>
<template #right>
<button @click.stop="onComment(item)">发布</button>
</template>
</uni-easyinput>
<!-- <input
v-model="contentData"
:key="i"
focus focus
confirm-type="done" confirm-type="done"
placeholder="评论" placeholder="评论"
:placeholder-style="placeholderStyle" :placeholder-style="placeholderStyle"
@confirm.stop="onComment(item)" @confirm.stop="onComment(item)"
/> />
<button @click.stop="onComment(item)">发布</button> <button @click.stop="onComment(item)">发布</button> -->
</view> </view>
<!-- 评论内容 --> <!-- 评论内容 -->
<view v-if="item.commentList.length > 0" class="comment"> <view v-if="item.commentList.length > 0" class="comment">

View File

@@ -0,0 +1,11 @@
<script setup></script>
<template>
<view>购买记录pages\discover\order\index.vue</view>
</template>
<style lang="scss" scoped>
page {
background: #f9f9f9;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -33,7 +33,7 @@
<view class="action-btn-image-container"> <view class="action-btn-image-container">
<image <image
class="action-btn-image" class="action-btn-image"
v-if="userInfo?.isMessageDisabled" v-if="isMessageDisabled"
src="/static/images/unmute-speak.png" src="/static/images/unmute-speak.png"
mode="aspectFit" mode="aspectFit"
/> />
@@ -46,12 +46,32 @@
</view> </view>
<text <text
class="action-btn-content" class="action-btn-content"
v-if="userInfo?.isMessageDisabled" v-if="isMessageDisabled"
> >
解除禁言 解除禁言
</text> </text>
<text class="action-btn-content" v-else>禁言</text> <text class="action-btn-content" v-else>禁言</text>
</view> </view>
<view v-if="!adminType" class="action-btn" @tap="onDdmini">
<view class="action-btn-image-container">
<image
v-if="isAdminShow"
class="action-btn-image"
src="/static/images/no-administrator.png"
mode="aspectFit"
/>
<image
v-else
class="action-btn-image"
src="/static/images/administrator.png"
mode="aspectFit"
/>
</view>
<text v-if="isAdminShow" class="action-btn-content">撤销管理员</text>
<text v-else class="action-btn-content">设置管理员</text>
</view>
<view class="action-btn" @tap="kickOut"> <view class="action-btn" @tap="kickOut">
<view class="action-btn-image-container"> <view class="action-btn-image-container">
<image <image
@@ -62,17 +82,6 @@
</view> </view>
<text class="action-btn-content">踢出房间</text> <text class="action-btn-content">踢出房间</text>
</view> </view>
<view class="action-btn" @tap="onDdmini">
<view class="action-btn-image-container">
<image
class="action-btn-image"
src="/static/images/administrator.png"
mode="aspectFit"
/>
</view>
<text class="action-btn-content">设置管理员</text>
</view>
</view> </view>
<!-- <view class="divider-line-container"> <!-- <view class="divider-line-container">
<view class="divider-line"></view> <view class="divider-line"></view>
@@ -83,13 +92,13 @@
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref, computed, onMounted, reactive } from 'vue'
import { useLiveListState } from '@/uni_modules/tuikit-atomic-x/state/LiveListState' import { useLiveListState } from '@/uni_modules/tuikit-atomic-x/state/LiveListState'
import { useLiveAudienceState } from '@/uni_modules/tuikit-atomic-x/state/LiveAudienceState' import { useLiveAudienceState } from '@/uni_modules/tuikit-atomic-x/state/LiveAudienceState'
import { useUI } from '../../../../utils/use-ui' import { useUI } from '../../../../utils/use-ui'
import { getUserBanList, getUserAdminList } from '../../../../api' import { getUserBanList, getUserAdminList } from '../../../../api'
const { showLoading, hideLoading } = useUI() const { showLoading, hideLoading, showToast, showDialog } = useUI()
const { currentLive } = useLiveListState() const { currentLive } = useLiveListState()
const { const {
setAdministrator, setAdministrator,
@@ -108,12 +117,24 @@
userInfo: { userInfo: {
type: Object type: Object
}, },
adminType: {
type: Boolean,
default: false
},
liveID: { liveID: {
type: String type: String
} }
}) })
const emit = defineEmits(['update:modelValue', 'update:userInfo']) const emit = defineEmits(['update:modelValue', 'update:userInfo'])
/** 禁言,管理员列表 */
const listData = reactive({
/** 禁言列表 */
tabooList: [],
/** 管理员列表 */
adminList: []
})
const userData = computed({ const userData = computed({
get() { get() {
@@ -123,21 +144,37 @@
emit('update:userInfo', value) emit('update:userInfo', value)
} }
}) })
/** 是否禁止发言状态 */
const isMessageDisabled = computed(() => {
return listData.tabooList?.some(v => v?.Member_Account === userData.value.userID)
})
/** 是否管理员状态 */
const isAdminShow = computed(() => {
return listData.adminList?.some(v => v === userData.value.userID)
})
const close = () => { const close = () => {
emit('update:modelValue', false) emit('update:modelValue', false)
} }
/** 获取禁言列表 */ /** 获取对应列表state1 显示禁止提示框 2 管理员显示提示框 */
const getBanList = async () => { const getListData = async (state) => {
try { const apiList = [
showLoading() getUserBanList(uni?.$liveID),
const res = await getUserBanList(uni?.$liveID) getUserAdminList(uni?.$liveID)
console.log('禁言列表=====', res) ]
hideLoading() Promise.all(apiList).then((res) => {
} catch (err) { listData.tabooList = res[0].data.Response?.MutedAccountList || []
hideLoading() listData.adminList = res[1].data.Response?.Admin_Account || []
} if (state === 1) {
showToast(`${isMessageDisabled.value ? '禁止' : '恢复'}成功`, 'success')
}
if (state === 2) {
showToast(`${isAdminShow.value ? '设置' : '撤销'}成功`, 'success')
}
})
} }
/** 获取管理员列表 */ /** 获取管理员列表 */
@@ -153,65 +190,37 @@
} }
/** 设置为管理员 */ /** 设置为管理员 */
const onDdmini = () => { const onDdmini = async () => {
console.log('====', userData.value) const show = await showDialog('提示', `确认${isAdminShow.value ? '撤销' : '设置'}管理员?`)
uni.showModal({ if (show) {
title: `提示`, showLoading()
content: `确认设置该用户为管理员?`, const api = isAdminShow.value ? revokeAdministrator : setAdministrator
success: c => { api({
if (c.confirm) { liveID: uni?.$liveID,
uni.showLoading({ userID: userData.value.userID,
title: '加载中...', success: () =>{
mask: true // 防止穿透点击 getListData(2)
})
setAdministrator({
liveID: uni?.$liveID,
userID: props?.userInfo?.userID,
success: () => {
uni.hideLoading()
uni.showToast({
title: '设置成功',
icon: 'success',
mask: true
})
close()
},
fail: () => {
uni.hideLoading()
}
})
}
}
})
}
const muteSpeak = () => {
console.log(
`${uni?.$liveID} === mute or unMute speak, liveID: ${props.liveID}, isMessageDisabled: ${props?.userInfo?.isMessageDisabled}`
)
getBanList()
const isShow = props?.userInfo?.isMessageDisabled
uni.showModal({
title: `提示`,
content: isShow ? `确认禁止用户发言?` : `确认恢复用户发言?`,
success: c => {
if (c.confirm) {
const params = {
liveID: uni?.$liveID,
userID: props?.userInfo?.userID,
isDisable: !props?.userInfo?.isMessageDisabled
}
if (isShow) {
disableSendMessage(params)
} else {
disableSendMessage(params)
}
close() close()
} }
})
}
}
const muteSpeak = async () => {
const show = await showDialog('提示', `确认${isMessageDisabled.value ? '恢复' : '禁止'}用户发言?`)
if (show) {
showLoading()
disableSendMessage({
liveID: uni?.$liveID,
userID: userData.value.userID,
isDisable: !isMessageDisabled.value,
success: () => {
getListData(1)
close()
}
})
} }
})
} }
const kickOut = () => { const kickOut = () => {
@@ -250,6 +259,9 @@
}) })
} }
onMounted(() => {
getListData()
})
</script> </script>
<style> <style>

View File

@@ -21,7 +21,7 @@
<text class="tag-text">{{ audience.tag }}</text> <text class="tag-text">{{ audience.tag }}</text>
</view> </view>
</view> </view>
<view class="audience-more" v-if="loginUserInfo?.userID === currentLive.liveOwner.userID" <view class="audience-more" v-if="loginUserInfo?.userID === currentLive.liveOwner.userID || isAdminState"
@tap="audienceOperator(audience)"> @tap="audienceOperator(audience)">
<text class="more-text">···</text> <text class="more-text">···</text>
</view> </view>
@@ -40,7 +40,7 @@
</view> </view>
</view> </view>
<AudienceActionPanel v-model="isShowAudienceActionPanel" :userInfo="selectedAudience" :liveID="liveID"> <AudienceActionPanel v-model="isShowAudienceActionPanel" :userInfo="selectedAudience" :liveID="liveID" :adminType="isAdminState">
</AudienceActionPanel> </AudienceActionPanel>
</view> </view>
@@ -49,10 +49,11 @@
<script setup> <script setup>
import { import {
ref, ref,
onMounted onMounted,
watch
} from 'vue'; } from 'vue';
import AudienceActionPanel from '@/uni_modules/tuikit-atomic-x/components/LiveAudienceList/AudienceActionPanel.nvue'; import AudienceActionPanel from '@/uni_modules/tuikit-atomic-x/components/LiveAudienceList/AudienceActionPanel.nvue';
import { getUserAdminList } from '../../../../api'
import { import {
useLiveAudienceState useLiveAudienceState
} from "@/uni_modules/tuikit-atomic-x/state/LiveAudienceState"; } from "@/uni_modules/tuikit-atomic-x/state/LiveAudienceState";
@@ -62,6 +63,7 @@
import { import {
useLiveListState useLiveListState
} from "@/uni_modules/tuikit-atomic-x/state/LiveListState"; } from "@/uni_modules/tuikit-atomic-x/state/LiveListState";
import { useAuthUser } from '../../../../composables/useAuthUser';
const { const {
currentLive currentLive
} = useLiveListState(); } = useLiveListState();
@@ -69,6 +71,7 @@
loginUserInfo loginUserInfo
} = useLoginState(); } = useLoginState();
const {tencentUserSig } = useAuthUser()
const { const {
audienceList, audienceList,
audienceListCursor audienceListCursor
@@ -80,6 +83,8 @@
const scrollTop = ref(0); const scrollTop = ref(0);
const isShowAudienceActionPanel = ref(false); const isShowAudienceActionPanel = ref(false);
const selectedAudience = ref(null); const selectedAudience = ref(null);
/** 是否管理员身份 */
const isAdminState = ref(false)
const safeArea = ref({ const safeArea = ref({
left: 0, left: 0,
right: 0, right: 0,
@@ -107,6 +112,17 @@
const close = () => { const close = () => {
emit('update:modelValue', false); emit('update:modelValue', false);
}; };
watch(() => props.modelValue, (v) => {
if (v) {
getUserAdminList(uni?.$liveID).then(res => {
const adminList = res.data.Response?.Admin_Account || []
console.log('===管理员列表', adminList)
isAdminState.value = adminList?.some(v => v === tencentUserSig.value.userId)
console.log('===状态', isAdminState.value)
})
}
})
// 初始化加载 // 初始化加载
onMounted(() => { onMounted(() => {