mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 02:47:29 +08:00
直播功能完善提交
This commit is contained in:
@@ -3,10 +3,10 @@ var BASE = {
|
|||||||
* @description api请求基础路径
|
* @description api请求基础路径
|
||||||
*/
|
*/
|
||||||
API_DEV: {
|
API_DEV: {
|
||||||
common: "http://127.0.0.1:8890",
|
common: "https://common-api.pickmall.cn",
|
||||||
buyer: "http://127.0.0.1:8888",
|
buyer: "https://buyer-api.pickmall.cn",
|
||||||
seller: "http://127.0.0.1:8889",
|
seller: "https://store-api.pickmall.cn",
|
||||||
manager: "http://127.0.0.1:8887",
|
manager: "https://admin-api.pickmall.cn"
|
||||||
},
|
},
|
||||||
API_PROD: {
|
API_PROD: {
|
||||||
common: "https://common-api.pickmall.cn",
|
common: "https://common-api.pickmall.cn",
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ export interface LiveRoomForm {
|
|||||||
endTime?: string
|
endTime?: string
|
||||||
pushStreamServer?: string
|
pushStreamServer?: string
|
||||||
pushStreamCode?: string
|
pushStreamCode?: string
|
||||||
|
imSdkAppid?: string | number
|
||||||
|
imSdkAppId?: string | number
|
||||||
|
sdkAppId?: string | number
|
||||||
|
imSdkSecretKey?: string
|
||||||
|
sdkSecretKey?: string
|
||||||
|
secretKey?: string
|
||||||
|
userSig?: string
|
||||||
|
imUserSig?: string
|
||||||
|
adminUserSig?: string
|
||||||
|
imGroupId?: string
|
||||||
|
groupId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LiveCoupon {
|
export interface LiveCoupon {
|
||||||
|
|||||||
@@ -38,9 +38,13 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
<template v-if="canPassAuth(row)">
|
||||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||||
|
</template>
|
||||||
|
<template v-if="canPassAuth(row) && canRejectAuth(row)">
|
||||||
<span class="op-split">|</span>
|
<span class="op-split">|</span>
|
||||||
<a class="link-text" @click="handleAuth(row, 'REJECT')">拒绝</a>
|
</template>
|
||||||
|
<a v-if="canRejectAuth(row)" class="link-text" @click="handleAuth(row, 'REFUSE')">拒绝</a>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -82,9 +86,13 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
<template v-if="canPassAuth(row)">
|
||||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||||
|
</template>
|
||||||
|
<template v-if="canPassAuth(row) && canRejectAuth(row)">
|
||||||
<span class="op-split">|</span>
|
<span class="op-split">|</span>
|
||||||
<a class="link-text" @click="handleAuth(row, 'REJECT')">拒绝</a>
|
</template>
|
||||||
|
<a v-if="canRejectAuth(row)" class="link-text" @click="handleAuth(row, 'REFUSE')">拒绝</a>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -262,6 +270,14 @@ export default {
|
|||||||
const map = { PASS: "success", REFUSE: "danger", TOBEAUDITED: "warning" };
|
const map = { PASS: "success", REFUSE: "danger", TOBEAUDITED: "warning" };
|
||||||
return map[status] || "info";
|
return map[status] || "info";
|
||||||
},
|
},
|
||||||
|
canPassAuth(row) {
|
||||||
|
const status = row?.authStatus;
|
||||||
|
return status === "TOBEAUDITED" || status === "REFUSE" || !status;
|
||||||
|
},
|
||||||
|
canRejectAuth(row) {
|
||||||
|
const status = row?.authStatus;
|
||||||
|
return status === "TOBEAUDITED" || status === "PASS" || !status;
|
||||||
|
},
|
||||||
parsePageResult(res) {
|
parsePageResult(res) {
|
||||||
if (!res) return { records: [], total: 0 };
|
if (!res) return { records: [], total: 0 };
|
||||||
if (res.records) {
|
if (res.records) {
|
||||||
@@ -342,7 +358,10 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleAuth(record, authStatus) {
|
handleAuth(record, authStatus) {
|
||||||
authLiveMessage({ id: record.id, authStatus }).then((res) => {
|
authLiveMessage({
|
||||||
|
...record,
|
||||||
|
authStatus,
|
||||||
|
}).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.$Message.success("操作成功");
|
this.$Message.success("操作成功");
|
||||||
this.loadMessages();
|
this.loadMessages();
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { toRef } from "vue";
|
import { toRef } from "vue";
|
||||||
import { useChat } from "../composables/useChat";
|
import { useChat } from "../composables/useChat";
|
||||||
|
import { resolveImConfigFromDetail } from "../composables/useLiveSetting";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "LiveChatPanel",
|
name: "LiveChatPanel",
|
||||||
@@ -71,7 +72,7 @@ export default {
|
|||||||
userInfo = {};
|
userInfo = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return useChat(toRef(props, "liveId"), userInfo);
|
return useChat(toRef(props, "liveId"), userInfo, toRef(props, "liveDetail"));
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -84,30 +85,60 @@ export default {
|
|||||||
imGroupId() {
|
imGroupId() {
|
||||||
return this.liveDetail?.imGroupId || this.liveDetail?.groupId || this.liveId || "";
|
return this.liveDetail?.imGroupId || this.liveDetail?.groupId || this.liveId || "";
|
||||||
},
|
},
|
||||||
|
imSdkAppId() {
|
||||||
|
return resolveImConfigFromDetail(this.liveDetail).sdkAppId;
|
||||||
|
},
|
||||||
|
canInitChat() {
|
||||||
|
const { sdkAppId, secretKey, userSig } = resolveImConfigFromDetail(this.liveDetail);
|
||||||
|
return !!(this.imGroupId && sdkAppId && (userSig || secretKey));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
imGroupId: {
|
canInitChat: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(id) {
|
handler(ready) {
|
||||||
if (!id) return;
|
if (!ready) return;
|
||||||
this.setGroupID(id);
|
this.setGroupID(this.imGroupId);
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
this.bootstrapChat();
|
this.bootstrapChat();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
imGroupId(id) {
|
||||||
|
if (!id) return;
|
||||||
|
this.setGroupID(id);
|
||||||
|
},
|
||||||
active(val) {
|
active(val) {
|
||||||
if (val && this.imGroupId && !this.chatInited) {
|
if (val && this.canInitChat && !this.chatInited) {
|
||||||
this.bootstrapChat();
|
this.bootstrapChat();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
liveId() {
|
liveId() {
|
||||||
this.chatInited = false;
|
this.chatInited = false;
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
if (this.active && this.imGroupId) {
|
if (this.active && this.canInitChat) {
|
||||||
this.bootstrapChat();
|
this.bootstrapChat();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
liveDetail: {
|
||||||
|
deep: true,
|
||||||
|
handler(detail, oldDetail) {
|
||||||
|
const nextConfig = resolveImConfigFromDetail(detail);
|
||||||
|
const prevConfig = resolveImConfigFromDetail(oldDetail);
|
||||||
|
if (
|
||||||
|
nextConfig.sdkAppId &&
|
||||||
|
(nextConfig.sdkAppId !== prevConfig.sdkAppId ||
|
||||||
|
nextConfig.secretKey !== prevConfig.secretKey ||
|
||||||
|
nextConfig.userSig !== prevConfig.userSig)
|
||||||
|
) {
|
||||||
|
this.chatInited = false;
|
||||||
|
this.cleanup();
|
||||||
|
if (this.active && this.canInitChat) {
|
||||||
|
this.bootstrapChat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
@@ -117,7 +148,7 @@ export default {
|
|||||||
this.createTextMessageByInput();
|
this.createTextMessageByInput();
|
||||||
},
|
},
|
||||||
async bootstrapChat() {
|
async bootstrapChat() {
|
||||||
if (!this.liveId || this.chatInited || this.initializing) {
|
if (!this.liveId || this.chatInited || this.initializing || !this.canInitChat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { nextTick, ref, unref, watch } from "vue";
|
|||||||
import { postSendMessage } from "@/api/live";
|
import { postSendMessage } from "@/api/live";
|
||||||
import { Message } from "@/utils/message";
|
import { Message } from "@/utils/message";
|
||||||
import TencentCloudChat from "@tencentcloud/chat";
|
import TencentCloudChat from "@tencentcloud/chat";
|
||||||
import { fetchLiveSetting } from "./useLiveSetting";
|
import { resolveImConfigFromDetail } from "./useLiveSetting";
|
||||||
import { genTestUserSig } from "../utils/GenerateTestUserSig";
|
import { genTestUserSig } from "../utils/GenerateTestUserSig";
|
||||||
|
|
||||||
const MAX_MESSAGE_COUNT = 100;
|
const MAX_MESSAGE_COUNT = 100;
|
||||||
const ADMIN_IM_USER_ID = "admin";
|
const ADMIN_IM_USER_ID = "admin";
|
||||||
|
|
||||||
export function useChat(liveId, userInfo) {
|
export function useChat(liveId, userInfo, liveDetail) {
|
||||||
const chat = ref(null);
|
const chat = ref(null);
|
||||||
const groupID = ref("");
|
const groupID = ref("");
|
||||||
const messageList = ref([]);
|
const messageList = ref([]);
|
||||||
@@ -67,22 +67,25 @@ export function useChat(liveId, userInfo) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setting = await fetchLiveSetting();
|
const detail = unref(liveDetail) || {};
|
||||||
if (!setting?.imSdkAppid) {
|
const { sdkAppId, secretKey, userSig: detailUserSig } = resolveImConfigFromDetail(detail);
|
||||||
initError.value = "请先在系统设置中配置直播 IM SDK APPID";
|
if (!sdkAppId) {
|
||||||
return;
|
initError.value = "直播间详情缺少 IM SDK APPID";
|
||||||
}
|
|
||||||
if (!setting?.imSdkSecretKey) {
|
|
||||||
initError.value = "请先在系统设置中配置直播 IM SDK 密钥";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sdkAppId = Number(setting.imSdkAppid);
|
let userSig = detailUserSig;
|
||||||
const { userSig } = genTestUserSig({
|
if (!userSig) {
|
||||||
|
if (!secretKey) {
|
||||||
|
initError.value = "直播间详情缺少 IM 登录凭证";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
userSig = genTestUserSig({
|
||||||
SDKAppID: sdkAppId,
|
SDKAppID: sdkAppId,
|
||||||
secretKey: setting.imSdkSecretKey,
|
secretKey,
|
||||||
userID: ADMIN_IM_USER_ID,
|
userID: ADMIN_IM_USER_ID,
|
||||||
});
|
}).userSig;
|
||||||
|
}
|
||||||
|
|
||||||
if (chat.value) {
|
if (chat.value) {
|
||||||
detachChatEvents(chat.value);
|
detachChatEvents(chat.value);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export async function fetchLiveSetting(force = false) {
|
|||||||
return fetchingPromise;
|
return fetchingPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 解析 IM SDK AppID */
|
/** 解析 IM SDK AppID(系统设置,兼容旧逻辑) */
|
||||||
export function resolveSdkAppId(setting) {
|
export function resolveSdkAppId(setting) {
|
||||||
if (!setting?.imSdkAppid) {
|
if (!setting?.imSdkAppid) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -42,3 +42,30 @@ export function resolveSdkAppId(setting) {
|
|||||||
const id = Number(setting.imSdkAppid);
|
const id = Number(setting.imSdkAppid);
|
||||||
return Number.isNaN(id) ? 0 : id;
|
return Number.isNaN(id) ? 0 : id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 从直播间详情解析 IM SDK AppID */
|
||||||
|
export function resolveSdkAppIdFromDetail(detail) {
|
||||||
|
return resolveImConfigFromDetail(detail).sdkAppId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从直播间详情解析 IM 配置 */
|
||||||
|
export function resolveImConfigFromDetail(detail) {
|
||||||
|
if (!detail) {
|
||||||
|
return { sdkAppId: 0, secretKey: "", userSig: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const sdkRaw = detail.sdkAppId ?? detail.imSdkAppId ?? detail.imSdkAppid;
|
||||||
|
const sdkAppId =
|
||||||
|
sdkRaw == null || sdkRaw === "" ? 0 : Number(sdkRaw);
|
||||||
|
|
||||||
|
const secretKey =
|
||||||
|
detail.imSdkSecretKey ?? detail.sdkSecretKey ?? detail.secretKey ?? "";
|
||||||
|
const userSig =
|
||||||
|
detail.userSig ?? detail.imUserSig ?? detail.adminUserSig ?? "";
|
||||||
|
|
||||||
|
return {
|
||||||
|
sdkAppId: Number.isNaN(sdkAppId) ? 0 : sdkAppId,
|
||||||
|
secretKey: String(secretKey || ""),
|
||||||
|
userSig: String(userSig || ""),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -239,7 +239,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getSetting } from "@/api/index";
|
|
||||||
import {
|
import {
|
||||||
endLive,
|
endLive,
|
||||||
getLiveInfo,
|
getLiveInfo,
|
||||||
@@ -363,7 +362,6 @@ export default {
|
|||||||
this.$Message.error("缺少直播ID");
|
this.$Message.error("缺少直播ID");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.loadWapSetting();
|
|
||||||
this.refreshAll();
|
this.refreshAll();
|
||||||
this.startDurationTimer();
|
this.startDurationTimer();
|
||||||
},
|
},
|
||||||
@@ -692,15 +690,6 @@ export default {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
loadWapSetting() {
|
|
||||||
getSetting("BASE_SETTING")
|
|
||||||
.then((res) => {
|
|
||||||
if (res.success && res.result?.buyerDomain) {
|
|
||||||
this.wapUrl = res.result.buyerDomain;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user