mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 10:57:26 +08:00
解决 Profile.vue 合并冲突,同步master代码
This commit is contained in:
@@ -38,9 +38,13 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleAuth(row, 'REJECT')">拒绝</a>
|
||||
<template v-if="canPassAuth(row)">
|
||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||
</template>
|
||||
<template v-if="canPassAuth(row) && canRejectAuth(row)">
|
||||
<span class="op-split">|</span>
|
||||
</template>
|
||||
<a v-if="canRejectAuth(row)" class="link-text" @click="handleAuth(row, 'REFUSE')">拒绝</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -82,9 +86,13 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="handleAuth(row, 'REJECT')">拒绝</a>
|
||||
<template v-if="canPassAuth(row)">
|
||||
<a class="link-text" @click="handleAuth(row, 'PASS')">通过</a>
|
||||
</template>
|
||||
<template v-if="canPassAuth(row) && canRejectAuth(row)">
|
||||
<span class="op-split">|</span>
|
||||
</template>
|
||||
<a v-if="canRejectAuth(row)" class="link-text" @click="handleAuth(row, 'REFUSE')">拒绝</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -262,6 +270,14 @@ export default {
|
||||
const map = { PASS: "success", REFUSE: "danger", TOBEAUDITED: "warning" };
|
||||
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) {
|
||||
if (!res) return { records: [], total: 0 };
|
||||
if (res.records) {
|
||||
@@ -342,7 +358,10 @@ export default {
|
||||
});
|
||||
},
|
||||
handleAuth(record, authStatus) {
|
||||
authLiveMessage({ id: record.id, authStatus }).then((res) => {
|
||||
authLiveMessage({
|
||||
...record,
|
||||
authStatus,
|
||||
}).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("操作成功");
|
||||
this.loadMessages();
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
import Cookies from "js-cookie";
|
||||
import { toRef } from "vue";
|
||||
import { useChat } from "../composables/useChat";
|
||||
import { resolveImConfigFromDetail } from "../composables/useLiveSetting";
|
||||
|
||||
export default {
|
||||
name: "LiveChatPanel",
|
||||
@@ -71,7 +72,7 @@ export default {
|
||||
userInfo = {};
|
||||
}
|
||||
|
||||
return useChat(toRef(props, "liveId"), userInfo);
|
||||
return useChat(toRef(props, "liveId"), userInfo, toRef(props, "liveDetail"));
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -84,30 +85,60 @@ export default {
|
||||
imGroupId() {
|
||||
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: {
|
||||
imGroupId: {
|
||||
canInitChat: {
|
||||
immediate: true,
|
||||
handler(id) {
|
||||
if (!id) return;
|
||||
this.setGroupID(id);
|
||||
handler(ready) {
|
||||
if (!ready) return;
|
||||
this.setGroupID(this.imGroupId);
|
||||
if (this.active) {
|
||||
this.bootstrapChat();
|
||||
}
|
||||
},
|
||||
},
|
||||
imGroupId(id) {
|
||||
if (!id) return;
|
||||
this.setGroupID(id);
|
||||
},
|
||||
active(val) {
|
||||
if (val && this.imGroupId && !this.chatInited) {
|
||||
if (val && this.canInitChat && !this.chatInited) {
|
||||
this.bootstrapChat();
|
||||
}
|
||||
},
|
||||
liveId() {
|
||||
this.chatInited = false;
|
||||
this.cleanup();
|
||||
if (this.active && this.imGroupId) {
|
||||
if (this.active && this.canInitChat) {
|
||||
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() {
|
||||
this.cleanup();
|
||||
@@ -117,7 +148,7 @@ export default {
|
||||
this.createTextMessageByInput();
|
||||
},
|
||||
async bootstrapChat() {
|
||||
if (!this.liveId || this.chatInited || this.initializing) {
|
||||
if (!this.liveId || this.chatInited || this.initializing || !this.canInitChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ import { nextTick, ref, unref, watch } from "vue";
|
||||
import { postSendMessage } from "@/api/live";
|
||||
import { Message } from "@/utils/message";
|
||||
import TencentCloudChat from "@tencentcloud/chat";
|
||||
import { fetchLiveSetting } from "./useLiveSetting";
|
||||
import { resolveImConfigFromDetail } from "./useLiveSetting";
|
||||
import { genTestUserSig } from "../utils/GenerateTestUserSig";
|
||||
|
||||
const MAX_MESSAGE_COUNT = 100;
|
||||
const ADMIN_IM_USER_ID = "admin";
|
||||
|
||||
export function useChat(liveId, userInfo) {
|
||||
export function useChat(liveId, userInfo, liveDetail) {
|
||||
const chat = ref(null);
|
||||
const groupID = ref("");
|
||||
const messageList = ref([]);
|
||||
@@ -67,22 +67,25 @@ export function useChat(liveId, userInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const setting = await fetchLiveSetting();
|
||||
if (!setting?.imSdkAppid) {
|
||||
initError.value = "请先在系统设置中配置直播 IM SDK APPID";
|
||||
return;
|
||||
}
|
||||
if (!setting?.imSdkSecretKey) {
|
||||
initError.value = "请先在系统设置中配置直播 IM SDK 密钥";
|
||||
const detail = unref(liveDetail) || {};
|
||||
const { sdkAppId, secretKey, userSig: detailUserSig } = resolveImConfigFromDetail(detail);
|
||||
if (!sdkAppId) {
|
||||
initError.value = "直播间详情缺少 IM SDK APPID";
|
||||
return;
|
||||
}
|
||||
|
||||
const sdkAppId = Number(setting.imSdkAppid);
|
||||
const { userSig } = genTestUserSig({
|
||||
SDKAppID: sdkAppId,
|
||||
secretKey: setting.imSdkSecretKey,
|
||||
userID: ADMIN_IM_USER_ID,
|
||||
});
|
||||
let userSig = detailUserSig;
|
||||
if (!userSig) {
|
||||
if (!secretKey) {
|
||||
initError.value = "直播间详情缺少 IM 登录凭证";
|
||||
return;
|
||||
}
|
||||
userSig = genTestUserSig({
|
||||
SDKAppID: sdkAppId,
|
||||
secretKey,
|
||||
userID: ADMIN_IM_USER_ID,
|
||||
}).userSig;
|
||||
}
|
||||
|
||||
if (chat.value) {
|
||||
detachChatEvents(chat.value);
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function fetchLiveSetting(force = false) {
|
||||
return fetchingPromise;
|
||||
}
|
||||
|
||||
/** 解析 IM SDK AppID */
|
||||
/** 解析 IM SDK AppID(系统设置,兼容旧逻辑) */
|
||||
export function resolveSdkAppId(setting) {
|
||||
if (!setting?.imSdkAppid) {
|
||||
return 0;
|
||||
@@ -42,3 +42,30 @@ export function resolveSdkAppId(setting) {
|
||||
const id = Number(setting.imSdkAppid);
|
||||
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 || ""),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="panel-head">
|
||||
<span class="panel-title">直播预览</span>
|
||||
<div class="ratio-switch">
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="player-box" :class="aspectRatio === '16:9' ? 'ratio-169' : 'ratio-43'">
|
||||
@@ -239,7 +239,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSetting } from "@/api/index";
|
||||
import {
|
||||
endLive,
|
||||
getLiveInfo,
|
||||
@@ -363,7 +362,6 @@ export default {
|
||||
this.$Message.error("缺少直播ID");
|
||||
return;
|
||||
}
|
||||
this.loadWapSetting();
|
||||
this.refreshAll();
|
||||
this.startDurationTimer();
|
||||
},
|
||||
@@ -644,7 +642,7 @@ export default {
|
||||
},
|
||||
buildShareUrl() {
|
||||
const base = (this.wapUrl || BASE?.WAP_URL || config.website || "").replace(/\/?$/, "/");
|
||||
return `${base}pages/promotions/live/detail?id=${this.liveId}`;
|
||||
return `${base}pages/promotion/live/room?id=${this.liveId}`;
|
||||
},
|
||||
handleShare() {
|
||||
const url = this.buildShareUrl();
|
||||
@@ -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>
|
||||
|
||||
@@ -237,7 +237,7 @@ export default {
|
||||
},
|
||||
buildH5ShareUrl(liveId) {
|
||||
const base = (this.wapUrl || BASE?.WAP_URL || config.website || "").replace(/\/?$/, "/");
|
||||
return `${base}pages/promotions/live/detail?id=${liveId}`;
|
||||
return `${base}pages/promotion/live/room?id=${liveId}`;
|
||||
},
|
||||
handleShare(row) {
|
||||
this.shareTitle = row.title || "";
|
||||
@@ -246,8 +246,40 @@ export default {
|
||||
},
|
||||
copyShareUrl() {
|
||||
if (!this.shareH5Url) return;
|
||||
navigator.clipboard.writeText(this.shareH5Url);
|
||||
this.$Message.success("链接已复制");
|
||||
this.copyText(this.shareH5Url);
|
||||
},
|
||||
copyText(text) {
|
||||
const onSuccess = () => this.$Message.success("链接已复制");
|
||||
const onFail = () => this.$Message.error("复制失败,请手动复制");
|
||||
|
||||
if (navigator.clipboard?.writeText) {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.then(onSuccess)
|
||||
.catch(() => {
|
||||
this.copyTextFallback(text) ? onSuccess() : onFail();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.copyTextFallback(text) ? onSuccess() : onFail();
|
||||
},
|
||||
copyTextFallback(text) {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
textArea.style.position = "fixed";
|
||||
textArea.style.left = "-9999px";
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
let ok = false;
|
||||
try {
|
||||
ok = document.execCommand("copy");
|
||||
} catch (e) {
|
||||
ok = false;
|
||||
}
|
||||
document.body.removeChild(textArea);
|
||||
return ok;
|
||||
},
|
||||
handleStart(row) {
|
||||
if (row.liveStatus === "LIVING") {
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
<el-upload
|
||||
v-if="canUploadImages"
|
||||
ref="up"
|
||||
:action="commonUrl + '/common/common/upload/file'"
|
||||
:action="managerApiUrl + '/manager/common/upload/file'"
|
||||
:data="uploadData"
|
||||
:headers="accessToken"
|
||||
:before-upload="beforeUpload"
|
||||
@@ -385,7 +385,7 @@ import {
|
||||
updateFileDirectory,
|
||||
} from "@/api/index";
|
||||
import DPlayer from "dplayer";
|
||||
import {commonUrl} from "@/libs/axios";
|
||||
import {managerApiUrl} from "@/libs/axios";
|
||||
import config from "@/config/index";
|
||||
import playIcon from "@/assets/play.png";
|
||||
|
||||
@@ -417,7 +417,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
commonUrl, // 上传文件路径
|
||||
managerApiUrl, // 上传文件路径
|
||||
config, // api地址
|
||||
fileDirectoryId: "",
|
||||
groupFormValidate: {
|
||||
|
||||
@@ -51,15 +51,6 @@
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="label-btns goods-setting-btns">
|
||||
<div class="goods-setting-action-row">
|
||||
<el-button type="success" @click="createIndex()">重新生成所有商品索引</el-button>
|
||||
<el-button type="info" @click="deleteDownGoods()">删除ES中下架的商品</el-button>
|
||||
<el-button type="warning" @click="generateCache()">生成所有商品的缓存</el-button>
|
||||
<el-button type="danger" @click="deleteNotExistIndex()">删除不存在的索引</el-button>
|
||||
<div class="progress-item" v-if="showProgress">
|
||||
<el-progress :percentage="progressVal" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="goods-setting-save-row">
|
||||
<el-button type="primary" @click="submit('formValidate')">保存</el-button>
|
||||
</div>
|
||||
@@ -69,7 +60,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import { ElMessage } from "element-plus";
|
||||
import { setSetting, createIndex, getProgress, deleteGoodsDown, generateGoodsCache, delSkuIndex } from "@/api/index";
|
||||
import { setSetting } from "@/api/index";
|
||||
export default {
|
||||
props: ["res", "type"],
|
||||
data() {
|
||||
@@ -83,9 +74,6 @@ export default {
|
||||
originalPictureWidth: "0",
|
||||
originalPictureHeight: "0",
|
||||
},
|
||||
progressVal: 0,
|
||||
showProgress: false,
|
||||
intervalProgress: null,
|
||||
ruleValidate: {},
|
||||
result: "",
|
||||
};
|
||||
@@ -103,69 +91,6 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
createIndex() {
|
||||
createIndex().then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("开始生成!");
|
||||
this.showProgress = true;
|
||||
setTimeout(() => {
|
||||
this.intervalProgress = setInterval(() => {
|
||||
getProgress().then((resp) => {
|
||||
const progressResult = resp.result;
|
||||
if (progressResult != null && progressResult.flag === 0) {
|
||||
clearInterval(this.intervalProgress);
|
||||
this.showProgress = false;
|
||||
ElMessage.success("生成成功!");
|
||||
} else {
|
||||
this.progressVal = Math.floor((progressResult.processed / progressResult.total) * 100);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}, 10000);
|
||||
} else if (res.code === 100000) {
|
||||
this.showProgress = true;
|
||||
this.intervalProgress = setInterval(() => {
|
||||
getProgress().then((resp) => {
|
||||
const progressResult = resp.result;
|
||||
if (progressResult != null && progressResult.flag === 0) {
|
||||
clearInterval(this.intervalProgress);
|
||||
this.showProgress = false;
|
||||
ElMessage.success("生成成功!");
|
||||
} else {
|
||||
this.progressVal = Math.floor((progressResult.processed / progressResult.total) * 100);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteDownGoods() {
|
||||
deleteGoodsDown().then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("删除成功!");
|
||||
} else {
|
||||
ElMessage.error("删除失败!");
|
||||
}
|
||||
});
|
||||
},
|
||||
generateCache() {
|
||||
generateGoodsCache().then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("生成成功!");
|
||||
} else {
|
||||
ElMessage.error("生成失败!");
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteNotExistIndex() {
|
||||
delSkuIndex().then((res) => {
|
||||
if (res.success) {
|
||||
ElMessage.success("删除成功!");
|
||||
} else {
|
||||
ElMessage.error("删除失败!");
|
||||
}
|
||||
});
|
||||
},
|
||||
setupSetting() {
|
||||
setSetting(this.type, this.formValidate).then((res) => {
|
||||
if (res.success) {
|
||||
@@ -217,19 +142,6 @@ export default {
|
||||
gap: 10px;
|
||||
margin-left: 150px;
|
||||
}
|
||||
.goods-setting-action-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.goods-setting-action-row .progress-item {
|
||||
flex: 0 0 240px;
|
||||
min-width: 200px;
|
||||
}
|
||||
.goods-setting-action-row .progress-item :deep(.el-progress) {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.el-input){
|
||||
width: 180px !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user