This commit is contained in:
pikachu1995@126.com
2026-07-08 09:59:08 +08:00
50 changed files with 1414 additions and 1438 deletions

View File

@@ -16,10 +16,12 @@
"@amap/amap-jsapi-loader": "0.0.7", "@amap/amap-jsapi-loader": "0.0.7",
"@antv/g2": "^4.1.12", "@antv/g2": "^4.1.12",
"@element-plus/icons-vue": "^2.3.2", "@element-plus/icons-vue": "^2.3.2",
"@tencentcloud/chat": "^3.6.6",
"axios": "^1.7.9", "axios": "^1.7.9",
"core-js": "^3.49.0", "core-js": "^3.49.0",
"dplayer": "^1.26.0", "dplayer": "^1.26.0",
"element-plus": "^2.14.1", "element-plus": "^2.14.1",
"hls.js": "^1.6.16",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"price-color": "1.0.2", "price-color": "1.0.2",
@@ -39,7 +41,6 @@
"xss": "^1.0.7" "xss": "^1.0.7"
}, },
"devDependencies": { "devDependencies": {
"webpack": "^5.95.0",
"@vue/cli-plugin-babel": "^5.0.9", "@vue/cli-plugin-babel": "^5.0.9",
"@vue/cli-plugin-router": "^5.0.9", "@vue/cli-plugin-router": "^5.0.9",
"@vue/cli-plugin-vuex": "^5.0.9", "@vue/cli-plugin-vuex": "^5.0.9",
@@ -51,7 +52,8 @@
"less-loader": "^11.1.4", "less-loader": "^11.1.4",
"style-loader": "^3.3.4", "style-loader": "^3.3.4",
"style-resources-loader": "^1.5.0", "style-resources-loader": "^1.5.0",
"vue-cli-plugin-style-resources-loader": "^0.1.5" "vue-cli-plugin-style-resources-loader": "^0.1.5",
"webpack": "^5.95.0"
}, },
"resolutions": { "resolutions": {
"minimatch": "^3.1.2", "minimatch": "^3.1.2",

22
manager/pnpm-lock.yaml generated
View File

@@ -21,6 +21,9 @@ importers:
'@element-plus/icons-vue': '@element-plus/icons-vue':
specifier: ^2.3.2 specifier: ^2.3.2
version: 2.3.2(vue@3.5.39) version: 2.3.2(vue@3.5.39)
'@tencentcloud/chat':
specifier: ^3.6.6
version: 3.6.6
axios: axios:
specifier: ^1.7.9 specifier: ^1.7.9
version: 1.18.1 version: 1.18.1
@@ -33,6 +36,9 @@ importers:
element-plus: element-plus:
specifier: ^2.14.1 specifier: ^2.14.1
version: 2.14.2(vue@3.5.39) version: 2.14.2(vue@3.5.39)
hls.js:
specifier: ^1.6.16
version: 1.6.16
js-cookie: js-cookie:
specifier: ^2.2.1 specifier: ^2.2.1
version: 2.2.1 version: 2.2.1
@@ -829,36 +835,42 @@ packages:
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.6': '@parcel/watcher-linux-arm-musl@2.5.6':
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.6': '@parcel/watcher-linux-arm64-glibc@2.5.6':
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.6': '@parcel/watcher-linux-arm64-musl@2.5.6':
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.6': '@parcel/watcher-linux-x64-glibc@2.5.6':
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.6': '@parcel/watcher-linux-x64-musl@2.5.6':
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.6': '@parcel/watcher-win32-arm64@2.5.6':
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
@@ -906,6 +918,9 @@ packages:
'@sxzz/popperjs-es@2.11.8': '@sxzz/popperjs-es@2.11.8':
resolution: {integrity: sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==} resolution: {integrity: sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==}
'@tencentcloud/chat@3.6.6':
resolution: {integrity: sha512-PYPGUoZHw3GjDgM0N72qr0K/Wjp28HAoGaND077sbUQEwYFaMjZ1tuBQZugFG6v8OS8Ihx71yqNshR3xDHvYaA==}
'@types/body-parser@1.19.6': '@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
@@ -2353,6 +2368,9 @@ packages:
highlight.js@10.7.3: highlight.js@10.7.3:
resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
hls.js@1.6.16:
resolution: {integrity: sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==}
hosted-git-info@2.8.9: hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -5147,6 +5165,8 @@ snapshots:
'@sxzz/popperjs-es@2.11.8': {} '@sxzz/popperjs-es@2.11.8': {}
'@tencentcloud/chat@3.6.6': {}
'@types/body-parser@1.19.6': '@types/body-parser@1.19.6':
dependencies: dependencies:
'@types/connect': 3.4.38 '@types/connect': 3.4.38
@@ -6833,6 +6853,8 @@ snapshots:
highlight.js@10.7.3: {} highlight.js@10.7.3: {}
hls.js@1.6.16: {}
hosted-git-info@2.8.9: {} hosted-git-info@2.8.9: {}
hpack.js@2.1.6: hpack.js@2.1.6:

View File

@@ -78,6 +78,9 @@ export const queryLiveMessagePage = params => getRequest('/live/message/page', p
export const authLiveMessage = params => export const authLiveMessage = params =>
putRequest('/live/message/auth', params, { 'Content-type': 'application/json' }) putRequest('/live/message/auth', params, { 'Content-type': 'application/json' })
export const postSendMessage = params =>
postRequest('/live/message/send', params, { 'Content-type': 'application/json' })
// ========== 直播用户 / 拉黑 ========== // ========== 直播用户 / 拉黑 ==========
export const liveUserList = params => getRequest('/live/user/page', params) export const liveUserList = params => getRequest('/live/user/page', params)

View File

@@ -0,0 +1,251 @@
<template>
<div class="live-chat-panel">
<div v-if="initError" class="chat-error">
<el-alert :title="initError" type="warning" :closable="false" show-icon />
</div>
<div ref="chatListRef" class="chat-list" @scroll="onScroll">
<div v-if="isLoadingHistory" class="chat-loading">加载历史消息...</div>
<div
v-for="msg in messageList"
:key="msg.messageId"
class="chat-item"
:class="{ 'is-system': msg.isSystem }"
>
<el-avatar v-if="!msg.isSystem" :src="msg.avatar" :size="28">
{{ (msg.username || "").charAt(0) }}
</el-avatar>
<div class="chat-bubble">
<div v-if="!msg.isSystem" class="chat-user">{{ msg.username }}</div>
<div class="chat-text">{{ msg.message }}</div>
</div>
</div>
<el-empty v-if="!messageList.length && !initError && !initializing" :image-size="64" description="暂无聊天消息" />
<div ref="bottomAnchorRef" class="chat-bottom-anchor" />
</div>
<div v-if="unreadCount > 0" class="chat-unread" @click="scrollToBottomAndClearUnread">
{{ unreadCount }} 条新消息
</div>
<div class="chat-input-bar">
<el-input
v-model="messageContent"
placeholder="发送消息到直播间..."
maxlength="200"
@keyup.enter="createTextMessageByInput"
/>
<el-button type="primary" :disabled="!messageContent.trim()" @click="handleSend">
发送
</el-button>
</div>
</div>
</template>
<script>
import Cookies from "js-cookie";
import { toRef } from "vue";
import { useChat } from "../composables/useChat";
export default {
name: "LiveChatPanel",
props: {
liveId: {
type: String,
required: true,
},
liveDetail: {
type: Object,
default: () => ({}),
},
active: {
type: Boolean,
default: true,
},
},
setup(props) {
let userInfo = {};
try {
userInfo = JSON.parse(Cookies.get("userInfoManager") || "{}");
} catch {
userInfo = {};
}
return useChat(toRef(props, "liveId"), userInfo);
},
data() {
return {
initializing: false,
chatInited: false,
};
},
computed: {
/** 腾讯云 IM 群组:优先后端字段,否则用直播间 ID与旧版中控台一致 */
imGroupId() {
return this.liveDetail?.imGroupId || this.liveDetail?.groupId || this.liveId || "";
},
},
watch: {
imGroupId: {
immediate: true,
handler(id) {
if (!id) return;
this.setGroupID(id);
if (this.active) {
this.bootstrapChat();
}
},
},
active(val) {
if (val && this.imGroupId && !this.chatInited) {
this.bootstrapChat();
}
},
liveId() {
this.chatInited = false;
this.cleanup();
if (this.active && this.imGroupId) {
this.bootstrapChat();
}
},
},
beforeUnmount() {
this.cleanup();
},
methods: {
handleSend() {
this.createTextMessageByInput();
},
async bootstrapChat() {
if (!this.liveId || this.chatInited || this.initializing) {
return;
}
const groupId = this.imGroupId;
if (!groupId) {
this.initError = "缺少直播间 ID无法初始化聊天";
return;
}
this.setGroupID(groupId);
this.initializing = true;
try {
await this.initTencentIm();
if (!this.initError) {
this.chatInited = true;
}
} catch (error) {
console.error("初始化直播聊天失败:", error);
this.initError = "聊天初始化失败,请刷新重试";
this.chatInited = false;
} finally {
this.initializing = false;
}
},
},
};
</script>
<style lang="scss" scoped>
.live-chat-panel {
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
min-height: 0;
max-height: 100%;
overflow: hidden;
position: relative;
}
.chat-error {
flex-shrink: 0;
margin-bottom: 8px;
}
.chat-list {
flex: 1 1 0;
height: 0;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
padding: 4px 0;
overscroll-behavior: contain;
}
.chat-bottom-anchor {
height: 1px;
flex-shrink: 0;
}
.chat-loading {
text-align: center;
color: #909399;
font-size: 12px;
padding: 8px 0;
}
.chat-item {
display: flex;
align-items: flex-start;
gap: 8px;
margin-bottom: 12px;
&.is-system {
justify-content: center;
.chat-bubble {
background: #f4f4f5;
border-radius: 12px;
padding: 4px 12px;
}
.chat-text {
color: #909399;
font-size: 12px;
}
}
}
.chat-bubble {
min-width: 0;
flex: 1;
}
.chat-user {
font-size: 12px;
color: #909399;
margin-bottom: 4px;
}
.chat-text {
font-size: 14px;
color: #303133;
line-height: 1.5;
word-break: break-all;
}
.chat-unread {
position: absolute;
left: 50%;
bottom: 56px;
transform: translateX(-50%);
padding: 4px 12px;
background: $theme_color;
color: #fff;
font-size: 12px;
border-radius: 12px;
cursor: pointer;
z-index: 2;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}
.chat-input-bar {
flex-shrink: 0;
display: flex;
gap: 8px;
padding-top: 12px;
border-top: 1px solid #ebeef5;
background: #fff;
}
</style>

View File

@@ -0,0 +1,475 @@
/* eslint-disable no-console */
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 { genTestUserSig } from "../utils/GenerateTestUserSig";
const MAX_MESSAGE_COUNT = 100;
const ADMIN_IM_USER_ID = "admin";
export function useChat(liveId, userInfo) {
const chat = ref(null);
const groupID = ref("");
const messageList = ref([]);
const messageContent = ref("");
const chatListRef = ref(null);
const bottomAnchorRef = ref(null);
const isAtBottom = ref(true);
const unreadCount = ref(0);
const isLoadingHistory = ref(false);
const hasMoreHistory = ref(true);
const nextReqMessageID = ref("");
const imReady = ref(false);
const initError = ref("");
let loginPromise = null;
let historyLoaded = false;
function resetSessionState() {
imReady.value = false;
loginPromise = null;
historyLoaded = false;
hasMoreHistory.value = true;
nextReqMessageID.value = "";
isLoadingHistory.value = false;
}
function detachChatEvents(instance) {
if (!instance) return;
instance.off(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived);
instance.off(TencentCloudChat.EVENT.SDK_READY, onSdkReady);
instance.off(TencentCloudChat.EVENT.SDK_NOT_READY, onSdkNotReady);
instance.off(TencentCloudChat.EVENT.KICKED_OUT, onKickedOut);
}
function attachChatEvents(instance) {
instance.on(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived);
instance.on(TencentCloudChat.EVENT.SDK_READY, onSdkReady);
instance.on(TencentCloudChat.EVENT.SDK_NOT_READY, onSdkNotReady);
instance.on(TencentCloudChat.EVENT.KICKED_OUT, onKickedOut);
}
async function initTencentIm() {
initError.value = "";
resetSessionState();
if (!groupID.value) {
const fallbackGroupId = unref(liveId);
if (fallbackGroupId) {
groupID.value = `${fallbackGroupId}`;
}
}
if (!groupID.value) {
initError.value = "直播间群组 ID 不存在";
console.warn("groupID 不存在,跳过 IM 初始化");
return;
}
const setting = await fetchLiveSetting();
if (!setting?.imSdkAppid) {
initError.value = "请先在系统设置中配置直播 IM SDK APPID";
return;
}
if (!setting?.imSdkSecretKey) {
initError.value = "请先在系统设置中配置直播 IM SDK 密钥";
return;
}
const sdkAppId = Number(setting.imSdkAppid);
const { userSig } = genTestUserSig({
SDKAppID: sdkAppId,
secretKey: setting.imSdkSecretKey,
userID: ADMIN_IM_USER_ID,
});
if (chat.value) {
detachChatEvents(chat.value);
try {
await chat.value.logout?.();
} catch (error) {
console.warn("IM logout error:", error);
}
chat.value = null;
}
const chatInstance = TencentCloudChat.create({ SDKAppID: sdkAppId });
chat.value = chatInstance;
chatInstance.setLogLevel(1);
attachChatEvents(chatInstance);
try {
await loginChat(userSig);
await waitForSdkReady();
await joinGroupAndLoadHistory();
} catch (error) {
initError.value = error?.message || "IM 初始化失败";
console.warn("initTencentIm error:", error);
}
}
function waitForSdkReady(timeoutMs = 15000) {
if (imReady.value) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error("IM SDK 就绪超时"));
}, timeoutMs);
const onReady = () => {
clearTimeout(timer);
chat.value?.off(TencentCloudChat.EVENT.SDK_READY, onReady);
resolve();
};
chat.value?.on(TencentCloudChat.EVENT.SDK_READY, onReady);
});
}
function loginChat(userSig) {
if (!chat.value) {
return Promise.reject(new Error("IM 实例不存在"));
}
if (loginPromise) {
return loginPromise;
}
loginPromise = chat.value
.login({
userID: ADMIN_IM_USER_ID,
userSig,
})
.then((imResponse) => {
if (imResponse.data.repeatLogin === true) {
imReady.value = true;
}
return imResponse;
})
.catch((imError) => {
const message = imError?.message || "IM 登录失败";
initError.value = message;
throw imError;
})
.finally(() => {
loginPromise = null;
});
return loginPromise;
}
function onSdkNotReady() {
console.log("[SDK Not Ready]");
imReady.value = false;
}
function onSdkReady() {
console.log("[SDK Ready]");
imReady.value = true;
updateUserInfo();
}
function onKickedOut() {
console.log("[用户被踢下线]");
imReady.value = false;
initError.value = "IM 已下线,请刷新页面";
}
async function joinGroupAndLoadHistory() {
if (!chat.value || !imReady.value || !groupID.value) {
return;
}
await joinGroup();
await getHistoryMessageList("");
}
function updateUserInfo() {
if (!chat.value || !userInfo) {
return;
}
chat.value.updateMyProfile({
nick: userInfo.nickName || userInfo.username || "管理员",
avatar: userInfo.face || "",
gender: TencentCloudChat.TYPES.GENDER_UNKNOWN,
allowType: TencentCloudChat.TYPES.ALLOW_TYPE_ALLOW_ANY,
});
}
async function joinGroup() {
if (!chat.value || !imReady.value || !groupID.value) {
return;
}
try {
const imResponse = await chat.value.joinGroup({
groupID: groupID.value,
type: TencentCloudChat.TYPES.GRP_AVCHATROOM,
});
console.log("[加群成功]", imResponse);
} catch (imError) {
console.warn("joinGroup error:", imError);
throw imError;
}
}
async function getHistoryMessageList(nextReqId) {
if (!chat.value || !imReady.value || !groupID.value) {
return;
}
if (isLoadingHistory.value || !hasMoreHistory.value) {
return;
}
if (!nextReqId && historyLoaded) {
return;
}
isLoadingHistory.value = true;
const requestParams = {
conversationID: `GROUP${groupID.value}`,
direction: 0,
};
if (nextReqId) {
requestParams.nextReqMessageID = nextReqId;
}
try {
const imResponse = await chat.value.getMessageList(requestParams);
const msgList = imResponse.data.messageList;
const nextId = imResponse.data.nextReqMessageID;
const isCompleted = imResponse.data.isCompleted;
const formattedMessages = msgList.map((msg) => formatReceivedMessage(msg));
formattedMessages.forEach((msg) => {
addMessageToList(msg, "append");
});
scrollToBottom(true);
nextReqMessageID.value = nextId;
hasMoreHistory.value = !isCompleted;
historyLoaded = true;
} catch (imError) {
console.warn("getMessageList error:", imError);
throw imError;
} finally {
isLoadingHistory.value = false;
}
}
function formatReceivedMessage(message) {
let messageText = "";
let username = "";
let isSystem = false;
if (message.from === "@TIM#SYSTEM") {
username = "系统消息";
isSystem = true;
} else {
username = message.nick || message.from || "用户";
}
const avatar = message.avatar || null;
const textType = TencentCloudChat.TYPES.MSG_TEXT;
const customType = TencentCloudChat.TYPES.MSG_CUSTOM;
if (message.type === textType || message.type === "TIMTextElem") {
messageText = message.payload?.text || "";
} else if (message.type === customType || message.type === "TIMCustomElem") {
try {
const customData = JSON.parse(message.payload.data);
messageText = customData.content || "系统消息";
username = "系统消息";
isSystem = true;
} catch {
messageText = "系统消息";
username = "系统消息";
isSystem = true;
}
} else {
messageText = "欢迎加入直播间";
}
return {
username,
message: messageText,
avatar: isSystem ? null : avatar,
messageId: message.ID,
time: message.time,
type: message.type,
isSystem,
};
}
function onMessageReceived(event) {
const msgList = event.data;
msgList.forEach((message) => {
const formattedMessage = formatReceivedMessage(message);
if (!formattedMessage.message?.trim() && !formattedMessage.isSystem) {
return;
}
addMessageToList(formattedMessage, "append");
isAtBottom.value = true;
unreadCount.value = 0;
scrollToBottom(true);
});
}
function addMessageToList(message, mode = "append") {
const exists = messageList.value.some((item) => item.messageId === message.messageId);
if (exists) {
return;
}
if (mode === "append") {
messageList.value.push(message);
if (messageList.value.length > MAX_MESSAGE_COUNT) {
const removeCount = messageList.value.length - MAX_MESSAGE_COUNT;
messageList.value.splice(0, removeCount);
}
} else {
messageList.value.unshift(message);
if (messageList.value.length > MAX_MESSAGE_COUNT) {
const removeCount = messageList.value.length - MAX_MESSAGE_COUNT;
messageList.value.splice(-removeCount, removeCount);
}
}
messageList.value.sort((a, b) => a.time - b.time);
}
async function createTextMessageByInput() {
const content = messageContent.value.trim();
if (!content) {
return;
}
if (!imReady.value) {
Message.error("IM 未就绪,请稍后再试");
return;
}
try {
const res = await postSendMessage({
liveRoomId: unref(liveId),
message: content,
});
if (res?.success) {
messageContent.value = "";
isAtBottom.value = true;
unreadCount.value = 0;
scrollToBottom(true);
}
} catch {
Message.error("发送失败");
}
}
function scrollToBottom(force = false) {
if (!force && !isAtBottom.value) {
return;
}
nextTick(() => {
const run = () => {
const anchor = bottomAnchorRef.value;
if (anchor?.scrollIntoView) {
anchor.scrollIntoView({ block: "end" });
}
const el = chatListRef.value;
if (el) {
el.scrollTop = el.scrollHeight;
}
};
run();
requestAnimationFrame(run);
setTimeout(run, 50);
setTimeout(run, 150);
});
}
watch(
() => messageList.value.length,
() => {
if (isAtBottom.value) {
scrollToBottom(true);
}
}
);
function checkIfAtBottom(scrollDetail) {
const { scrollTop, scrollHeight, clientHeight } = scrollDetail;
const isNearBottom = scrollTop + clientHeight >= scrollHeight - 10;
if (isNearBottom && !isAtBottom.value) {
isAtBottom.value = true;
unreadCount.value = 0;
} else if (!isNearBottom && isAtBottom.value) {
isAtBottom.value = false;
}
}
function onScroll() {
const el = chatListRef.value;
if (!el) {
return;
}
checkIfAtBottom({
scrollTop: el.scrollTop,
scrollHeight: el.scrollHeight,
clientHeight: el.clientHeight,
});
}
function scrollToBottomAndClearUnread() {
unreadCount.value = 0;
isAtBottom.value = true;
scrollToBottom(true);
}
function setGroupID(id) {
groupID.value = id;
}
function cleanup() {
resetSessionState();
if (chat.value) {
detachChatEvents(chat.value);
try {
chat.value.logout?.();
} catch (error) {
console.error("清理腾讯云 IM 失败:", error);
}
chat.value = null;
}
}
return {
chat,
groupID,
messageList,
messageContent,
chatListRef,
bottomAnchorRef,
isAtBottom,
unreadCount,
isLoadingHistory,
hasMoreHistory,
imReady,
initError,
initTencentIm,
createTextMessageByInput,
scrollToBottom,
scrollToBottomAndClearUnread,
onScroll,
setGroupID,
cleanup,
};
}

View File

@@ -0,0 +1,44 @@
import { getSetting } from "@/api/index";
/** @type {Record<string, any> | null} */
let cachedSetting = null;
/** @type {Promise<Record<string, any> | null> | null} */
let fetchingPromise = null;
/** 获取直播配置(带缓存) */
export async function fetchLiveSetting(force = false) {
if (!force && cachedSetting) {
return cachedSetting;
}
if (!force && fetchingPromise) {
return fetchingPromise;
}
fetchingPromise = (async () => {
try {
const res = await getSetting("LIVE_SETTING");
if (res?.success && res?.result) {
cachedSetting = res.result;
return cachedSetting;
}
console.warn("获取直播配置失败", res);
return null;
} catch (error) {
console.error("获取直播配置异常:", error);
return null;
} finally {
fetchingPromise = null;
}
})();
return fetchingPromise;
}
/** 解析 IM SDK AppID */
export function resolveSdkAppId(setting) {
if (!setting?.imSdkAppid) {
return 0;
}
const id = Number(setting.imSdkAppid);
return Number.isNaN(id) ? 0 : id;
}

View File

@@ -27,31 +27,29 @@
<div class="panel-head"> <div class="panel-head">
<span class="panel-title">直播预览</span> <span class="panel-title">直播预览</span>
<div class="ratio-switch"> <div class="ratio-switch">
<button
type="button"
class="ratio-btn"
:class="{ active: aspectRatio === '16:9' }"
@click="aspectRatio = '16:9'"
>
16:9
</button>
<button
type="button"
class="ratio-btn"
:class="{ active: aspectRatio === '4:3' }"
@click="aspectRatio = '4:3'"
>
4:3
</button>
</div> </div>
</div> </div>
<div class="player-box" :class="aspectRatio === '16:9' ? 'ratio-169' : 'ratio-43'"> <div class="player-box" :class="aspectRatio === '16:9' ? 'ratio-169' : 'ratio-43'">
<div v-if="videoUrl" id="live-dplayer" class="player-inner" /> <div v-if="showPlayerCover" class="player-cover">
<div v-else class="player-empty"> <img
<el-icon class="is-loading" :size="32"><Loading /></el-icon> v-if="liveDetail.coverImg"
<span>暂无拉流地址</span> class="cover-img"
:src="liveDetail.coverImg"
alt="直播封面"
/>
<div class="cover-mask">
<el-tag :type="liveStatusTagType(liveStatus)" size="small">{{ liveStatusText(liveStatus) }}</el-tag>
<span v-if="liveStatus === 'NEW' && liveDetail.startTime" class="cover-tip">
开播{{ formatTime(liveDetail.startTime) }}
</span>
<span v-else-if="liveStatus === 'PAUSED'" class="cover-tip">主播暂时离开请稍候</span>
<span v-else-if="liveStatus === 'ENDED'" class="cover-tip">直播已结束</span>
<span v-else-if="liveStatus === 'LIVING' && !videoUrl" class="cover-tip">等待拉流地址...</span>
</div> </div>
</div> </div>
<div v-if="shouldPlayStream" ref="hlsContainer" class="player-inner" />
</div>
</div> </div>
<div class="area-basic panel-box"> <div class="area-basic panel-box">
@@ -112,8 +110,12 @@
<div class="area-chat panel-box"> <div class="area-chat panel-box">
<el-tabs v-model="chatTab" class="panel-tabs fill-tabs"> <el-tabs v-model="chatTab" class="panel-tabs fill-tabs">
<el-tab-pane label="互动聊天" name="chat"> <el-tab-pane label="互动聊天" name="chat">
<div class="tab-body chat-placeholder"> <div class="tab-body chat-tab-body">
<el-empty :image-size="64" description="暂无聊天消息" /> <LiveChatPanel
:live-id="liveId"
:live-detail="liveDetail"
:active="chatTab === 'chat'"
/>
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="在线用户" name="online"> <el-tab-pane label="在线用户" name="online">
@@ -237,8 +239,7 @@
</template> </template>
<script> <script>
import DPlayer from "dplayer"; import { getSetting } from "@/api/index";
import { DocumentCopy, Loading, Refresh } from "@element-plus/icons-vue";
import { import {
endLive, endLive,
getLiveInfo, getLiveInfo,
@@ -246,16 +247,17 @@ import {
liveUserList, liveUserList,
startLive, startLive,
} from "@/api/live"; } from "@/api/live";
import { getSetting } from "@/api/index";
import config from "@/config"; import config from "@/config";
import { DocumentCopy, Refresh } from "@element-plus/icons-vue";
import CommentReview from "./components/CommentReview.vue"; import CommentReview from "./components/CommentReview.vue";
import Coupon from "./components/Coupon.vue"; import Coupon from "./components/Coupon.vue";
import LiveChatPanel from "./components/LiveChatPanel.vue";
import LiveGoods from "./components/LiveGoods.vue"; import LiveGoods from "./components/LiveGoods.vue";
import LivePurchaseRecords from "./components/LivePurchaseRecords.vue"; import LivePurchaseRecords from "./components/LivePurchaseRecords.vue";
export default { export default {
name: "live-control-panel", name: "live-control-panel",
components: { CommentReview, Coupon, LiveGoods, LivePurchaseRecords, DocumentCopy, Loading, Refresh }, components: { CommentReview, Coupon, LiveChatPanel, LiveGoods, LivePurchaseRecords, DocumentCopy, Refresh },
data() { data() {
return { return {
loading: false, loading: false,
@@ -275,15 +277,31 @@ export default {
pageSize: 10, pageSize: 10,
total: 0, total: 0,
}, },
player: null,
nowTick: Date.now(), nowTick: Date.now(),
durationTimer: null, durationTimer: null,
pollTimer: null,
hlsHttpFallbackUsed: false,
lastHlsPullUrl: "",
}; };
}, },
created() {
this.hlsInstance = null;
this.hlsVideoElement = null;
this._hlsVideoClickHandler = null;
},
computed: { computed: {
liveStatus() { liveStatus() {
return this.liveDetail.liveStatus || this.liveDetail.status || ""; return this.liveDetail.liveStatus || this.liveDetail.status || "";
}, },
isLiving() {
return this.liveStatus === "LIVING";
},
shouldPlayStream() {
return this.isLiving && !!this.videoUrl;
},
showPlayerCover() {
return !this.shouldPlayStream;
},
cumulativeViewers() { cumulativeViewers() {
return Number(this.liveDetail.actualViewNumber ?? 0); return Number(this.liveDetail.actualViewNumber ?? 0);
}, },
@@ -318,10 +336,19 @@ export default {
}, },
watch: { watch: {
videoUrl() { videoUrl() {
this.initPlayer(); this.syncH5Player();
},
isLiving() {
this.syncH5Player();
if (this.isLiving) {
this.startPolling();
} else {
this.stopPolling();
}
}, },
aspectRatio() { aspectRatio() {
this.$nextTick(() => this.initPlayer()); this.lastHlsPullUrl = "";
this.$nextTick(() => this.syncH5Player());
}, },
chatTab(tab) { chatTab(tab) {
if (tab === "online") this.loadOnlineUsers(); if (tab === "online") this.loadOnlineUsers();
@@ -341,7 +368,8 @@ export default {
this.startDurationTimer(); this.startDurationTimer();
}, },
beforeUnmount() { beforeUnmount() {
this.destroyPlayer(); this.destroyH5HlsPlayer();
this.stopPolling();
this.stopDurationTimer(); this.stopDurationTimer();
}, },
methods: { methods: {
@@ -385,55 +413,208 @@ export default {
return Number(val || 0).toFixed(2); return Number(val || 0).toFixed(2);
}, },
liveStatusText(status) { liveStatusText(status) {
const map = { NEW: "未开始", LIVING: "直播中", ENDED: "已结束" }; const map = { NEW: "未开始", LIVING: "直播中", PAUSED: "已暂停", ENDED: "已结束" };
return map[status] || "未知"; return map[status] || "未知";
}, },
liveStatusTagType(status) { liveStatusTagType(status) {
const map = { NEW: "info", LIVING: "success", ENDED: "warning" }; const map = { NEW: "info", LIVING: "success", PAUSED: "warning", ENDED: "warning" };
return map[status] || "info"; return map[status] || "info";
}, },
startPolling() {
this.stopPolling();
if (!this.isLiving) return;
this.pollTimer = setInterval(() => {
this.loadDetail(false);
}, 5000);
},
stopPolling() {
if (this.pollTimer) {
clearInterval(this.pollTimer);
this.pollTimer = null;
}
},
refreshAll() { refreshAll() {
this.loadDetail(); this.loadDetail();
this.loadOrderStats(); this.loadOrderStats();
this.$refs.purchaseRecords?.refresh(); this.$refs.purchaseRecords?.refresh();
if (this.chatTab === "online") this.loadOnlineUsers(); if (this.chatTab === "online") this.loadOnlineUsers();
}, },
destroyPlayer() { buildHlsPlayUrl(url, useHttpFallback = false) {
if (this.player) { if (!url) return "";
this.player.destroy(); const httpUrl =
this.player = null; useHttpFallback && url.startsWith("https://")
? url.replace("https://", "http://")
: url;
return httpUrl.replace(".flv", ".m3u8");
},
syncH5Player(retry = 0) {
const shouldPlay = this.shouldPlayStream;
if (!shouldPlay) {
this.destroyH5HlsPlayer();
this.lastHlsPullUrl = "";
return;
}
if (
this.videoUrl === this.lastHlsPullUrl &&
this.hlsInstance &&
this.hlsVideoElement &&
!this.hlsVideoElement.paused
) {
return;
}
if (this.videoUrl === this.lastHlsPullUrl && this.hlsInstance) {
this.ensureH5VideoPlaying(this.hlsVideoElement);
return;
}
this.lastHlsPullUrl = this.videoUrl;
this.hlsHttpFallbackUsed = false;
this.$nextTick(() => {
const container = this.$refs.hlsContainer;
if (!container) {
if (retry < 8) {
setTimeout(() => this.syncH5Player(retry + 1), 80);
}
return;
}
this.initH5HlsPlayer();
});
},
ensureH5VideoPlaying(video) {
if (!video) return Promise.resolve();
const tryPlay = (muted) => {
video.muted = muted;
return video.play().catch(() => Promise.reject());
};
return tryPlay(false)
.catch(() => tryPlay(true))
.catch(() => {
console.warn("[HLS] 自动播放被阻止,请点击画面播放");
});
},
async initH5HlsPlayer(useHttpFallback = false) {
const originalUrl = this.videoUrl;
const container = this.$refs.hlsContainer;
if (!originalUrl || !container) return;
const url = this.buildHlsPlayUrl(originalUrl, useHttpFallback);
this.destroyH5HlsPlayer();
const video = document.createElement("video");
video.style.cssText = "width:100%;height:100%;object-fit:cover;background:#000;";
video.autoplay = true;
video.muted = true;
video.defaultMuted = true;
video.playsInline = true;
video.setAttribute("autoplay", "");
video.setAttribute("muted", "");
video.setAttribute("playsinline", "");
video.setAttribute("webkit-playsinline", "");
video.controls = false;
const onVideoClick = () => {
if (video.muted) {
video.muted = false;
}
video.play().catch(() => {});
};
video.addEventListener("click", onVideoClick);
container.appendChild(video);
this.hlsVideoElement = video;
this._hlsVideoClickHandler = onVideoClick;
const onReadyPlay = () => {
this.ensureH5VideoPlaying(video);
};
let Hls = null;
try {
const hlsModule = await import("hls.js");
Hls = hlsModule.default;
} catch (error) {
console.error("[HLS] 加载播放器失败:", error);
this.$Message.error("直播播放器加载失败,请刷新页面重试");
return;
}
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: true,
lowLatencyMode: true,
liveSyncDurationCount: 3,
liveMaxLatencyDurationCount: 6,
maxBufferLength: 10,
maxMaxBufferLength: 30,
});
this.hlsInstance = hls;
hls.on(Hls.Events.MEDIA_ATTACHED, onReadyPlay);
hls.on(Hls.Events.MANIFEST_PARSED, onReadyPlay);
hls.attachMedia(video);
hls.loadSource(url);
hls.on(Hls.Events.ERROR, (_event, data) => {
if (!data.fatal) return;
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
if (!this.hlsHttpFallbackUsed && originalUrl.startsWith("https://")) {
console.warn("[HLS] HTTPS 加载失败,尝试 HTTP 降级...");
this.hlsHttpFallbackUsed = true;
this.destroyH5HlsPlayer();
this.$nextTick(() => this.initH5HlsPlayer(true));
} else {
console.error("[HLS] 网络错误,尝试重连...");
hls.startLoad();
}
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error("[HLS] 媒体错误,尝试恢复...");
hls.recoverMediaError();
break;
default:
console.error("[HLS] 致命错误:", data);
this.destroyH5HlsPlayer();
this.$Message.error("直播加载失败");
break;
}
});
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = url;
video.addEventListener("loadedmetadata", onReadyPlay);
video.addEventListener("canplay", onReadyPlay);
} else {
this.$Message.error("当前浏览器不支持 HLS 播放");
} }
}, },
initPlayer() { destroyH5HlsPlayer() {
this.destroyPlayer(); if (this.hlsInstance) {
if (!this.videoUrl) return; this.hlsInstance.destroy();
this.$nextTick(() => { this.hlsInstance = null;
const container = document.getElementById("live-dplayer"); }
if (!container) return; if (this.hlsVideoElement) {
this.player = new DPlayer({ if (this._hlsVideoClickHandler) {
container, this.hlsVideoElement.removeEventListener("click", this._hlsVideoClickHandler);
live: this.liveStatus === "LIVING", this._hlsVideoClickHandler = null;
autoplay: true, }
video: { this.hlsVideoElement.remove();
url: this.videoUrl, this.hlsVideoElement = null;
type: "auto", }
const container = this.$refs.hlsContainer;
if (container) {
container.innerHTML = "";
}
}, },
}); loadDetail(showLoading = true) {
}); if (showLoading) this.loading = true;
},
loadDetail() {
this.loading = true;
getLiveInfo(this.liveId) getLiveInfo(this.liveId)
.then((res) => { .then((res) => {
this.loading = false; if (showLoading) this.loading = false;
if (res.success) { if (res.success) {
const data = res.result || {}; const data = res.result || {};
this.liveDetail = data; this.liveDetail = data;
this.videoUrl = data.pullStreamUrl || data.streamUrl || ""; this.videoUrl = data.pullStreamUrl || data.streamUrl || "";
this.syncH5Player();
} }
}) })
.catch(() => { .catch(() => {
this.loading = false; if (showLoading) this.loading = false;
}); });
}, },
loadOrderStats() { loadOrderStats() {
@@ -503,7 +684,8 @@ export default {
return endLive(this.liveId).then((res) => { return endLive(this.liveId).then((res) => {
if (res.success) { if (res.success) {
this.$Message.success("直播已结束"); this.$Message.success("直播已结束");
this.destroyPlayer(); this.destroyH5HlsPlayer();
this.stopPolling();
this.refreshAll(); this.refreshAll();
} }
}); });
@@ -611,6 +793,13 @@ export default {
.area-chat, .area-chat,
.area-stats { .area-stats {
min-height: 0; min-height: 0;
height: 100%;
overflow: hidden;
}
.area-chat {
display: flex;
flex-direction: column;
} }
.area-manage { .area-manage {
@@ -687,17 +876,37 @@ export default {
.player-inner { .player-inner {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative;
z-index: 1;
} }
.player-empty { .player-cover {
position: absolute;
inset: 0;
z-index: 2;
background: #000;
.cover-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
.cover-mask {
position: absolute; position: absolute;
inset: 0; inset: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px; gap: 10px;
color: #909399; background: rgba(0, 0, 0, 0.45);
}
.cover-tip {
color: #fff;
font-size: 13px; font-size: 13px;
} }
@@ -874,12 +1083,14 @@ export default {
min-height: 100%; min-height: 100%;
} }
.chat-placeholder { .chat-tab-body {
display: flex;
flex-direction: column;
min-height: 0; min-height: 0;
height: 100%; height: 100%;
display: flex; overflow: hidden;
align-items: center; padding: 12px 16px 12px;
justify-content: center; box-sizing: border-box;
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {

View File

@@ -0,0 +1,38 @@
import LibGenerateTestUserSig from './lib-generate-test-usersig-es.min.js';
/**
* Signature expiration time, which should not be too short
* Time unit: second
* Default time: 7 * 24 * 60 * 60 = 604800 = 7days
*/
const EXPIRETIME = 604800;
/**
* Module: GenerateTestUserSig
*
* Description: Generates UserSig for testing. UserSig is a security signature designed by Tencent Cloud for its cloud services.
* It is calculated based on `SDKAppID`, `UserID`, and `EXPIRETIME` using the HMAC-SHA256 encryption algorithm.
*
* Attention: For the following reasons, do not use the code below in your commercial application.
*
* The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDKs basic features, not for commercial applications.
* `SECRETKEY` in client code can be easily decompiled and reversed, especially on web.
* Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic.
*
* The correct method is to deploy the `UserSig` calculation code and encryption key on your project server so that your application can request from your server a `UserSig` that is calculated whenever one is needed.
* Given that it is more difficult to hack a server than a client application, server-end calculation can better protect your key.
*
* Reference: https://cloud.tencent.com/document/product/647/17275#Server
*/
function genTestUserSig(options) {
const { SDKAppID, secretKey, userID } = options;
const sdkAppId = Number(SDKAppID);
const generator = new LibGenerateTestUserSig(sdkAppId, secretKey, EXPIRETIME);
const userSig = generator.genTestUserSig(userID);
return {
SDKAppID: sdkAppId,
userSig,
};
}
export { genTestUserSig, EXPIRETIME };

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,7 @@
<script> <script>
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import util from "@/libs/util"; import util from "@/libs/util";
import { getCategoryTree } from "@/api/goods.js";
export default { export default {
name: "App", name: "App",
@@ -18,6 +19,13 @@ export default {
util.initRouter(this); util.initRouter(this);
this.$store.commit("setOpenedList"); this.$store.commit("setOpenedList");
this.$store.commit("initCachepage"); this.$store.commit("initCachepage");
if (!localStorage.getItem("category")) {
getCategoryTree().then((res) => {
if (res.success && Array.isArray(res.result)) {
localStorage.setItem("category", JSON.stringify(res.result));
}
});
}
} }
}, },
}; };

View File

@@ -2,8 +2,7 @@ import { getCurrentPermissionList } from "@/api/index";
import lazyLoading from "./lazyLoading.js"; import lazyLoading from "./lazyLoading.js";
import { router } from "@/router/index"; import { router } from "@/router/index";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import config from "@/config/index";
const config = require("@/config/index");
let util = {}; let util = {};

View File

@@ -22,8 +22,11 @@ import { setStore, getStore, removeStore } from "@/libs/storage";
import util from "@/libs/util"; import util from "@/libs/util";
import { md5 } from "@/utils/md5.js"; import { md5 } from "@/utils/md5.js";
import * as filters from "@/utils/filters"; import * as filters from "@/utils/filters";
import config from "@/config/index";
import imgError from "./assets/img-error.png";
import loadingGif from "./assets/loading2.gif";
const { aMapSecurityJsCode, mainColor } = require("@/config"); const { aMapSecurityJsCode, mainColor } = config;
if (aMapSecurityJsCode) { if (aMapSecurityJsCode) {
window._AMapSecurityConfig = { window._AMapSecurityConfig = {
@@ -43,8 +46,8 @@ setupLegacyMessage(app);
installVueQr(app); installVueQr(app);
app.use(VueLazyload, { app.use(VueLazyload, {
error: require("./assets/img-error.png"), error: imgError,
loading: require("./assets/loading2.gif"), loading: loadingGif,
}); });
app.use(router); app.use(router);

View File

@@ -1,6 +1,5 @@
import Main from "@/views/Main.vue"; import Main from "@/views/Main.vue";
import config from "@/config/index";
const config = require('@/config/index')
// 不作为Main组件的子页面展示的页面单独写如下 // 不作为Main组件的子页面展示的页面单独写如下
export const loginRouter = { export const loginRouter = {
path: "/login", path: "/login",

View File

@@ -1,4 +1,6 @@
const { setting } = require("@/config"); import config from "@/config/index";
const { setting } = config;
const localSetting = window.localStorage.getItem('setting') const localSetting = window.localStorage.getItem('setting')
const settingData = { const settingData = {

View File

@@ -19,7 +19,6 @@
border-radius: 0.4em; border-radius: 0.4em;
flex-wrap: wrap; flex-wrap: wrap;
> .ivu-form-item,
> .el-form-item { > .el-form-item {
margin: 8px 10px !important; margin: 8px 10px !important;
} }
@@ -44,8 +43,3 @@
.search > .el-card + .el-card { .search > .el-card + .el-card {
margin-top: 10px; margin-top: 10px;
} }
// 兼容遗留 iView
.ivu-card + .ivu-card {
margin-top: 10px;
}

View File

@@ -120,6 +120,7 @@ import { Iphone, Message, Lock } from "@element-plus/icons-vue";
import * as RegExp from "@/utils/regular.js"; import * as RegExp from "@/utils/regular.js";
import * as apiLogin from "@/api/index.js"; import * as apiLogin from "@/api/index.js";
import { sendSms } from "@/api/common.js"; import { sendSms } from "@/api/common.js";
import config from "@/config/index";
import verify from "@/views/my-components/verify"; import verify from "@/views/my-components/verify";
export default { export default {
@@ -127,7 +128,7 @@ export default {
components: { verify, Iphone, Message, Lock }, components: { verify, Iphone, Message, Lock },
data() { data() {
return { return {
config: require("@/config"), config,
loading: false, loading: false,
loading1: false, loading1: false,
formFirst: { formFirst: {
@@ -207,7 +208,7 @@ export default {
} }
}) })
.catch(() => { .catch(() => {
this.loading = false; this.loading1 = false;
}); });
} }
}); });

View File

@@ -16,7 +16,6 @@
<div></div> <div></div>
<div class="user-dropdown-menu-con"> <div class="user-dropdown-menu-con">
<el-row <el-row
type="flex"
justify="end" justify="end"
align="middle" align="middle"
class="user-dropdown-innercon" class="user-dropdown-innercon"
@@ -90,8 +89,7 @@ import util from "@/libs/util.js";
import { logout } from "@/api/index"; import { logout } from "@/api/index";
import { getIMDetail } from "@/api/common"; import { getIMDetail } from "@/api/common";
import { userMsg } from "@/api/index"; import { userMsg } from "@/api/index";
import config from "@/config/index.js";
const config = require("@/config/index.js");
export default { export default {
components: { components: {

View File

@@ -1,19 +0,0 @@
.change-pass {
&-btn-box {
margin-bottom: 10px;
button {
padding-left: 0;
span {
color: #2D8CF0;
transition: all .2s;
}
span:hover {
color: #0C25F1;
transition: all .2s;
}
}
}
}

View File

@@ -93,18 +93,20 @@ export default {
this.$refs.editPasswordForm.validate((valid) => { this.$refs.editPasswordForm.validate((valid) => {
if (!valid) return; if (!valid) return;
this.savePassLoading = true; this.savePassLoading = true;
changePass(params).then((res) => { changePass(params)
this.savePassLoading = false; .then((res) => {
if (res.success) { if (res?.success) {
ElMessageBox.alert("修改密码成功,需重新登录", "修改密码成功", { ElMessageBox.alert("修改密码成功,需重新登录", "修改密码成功", {
confirmButtonText: "确定", confirmButtonText: "确定",
callback: () => { }).then(() => {
this.$store.commit("logout", this); this.$store.commit("logout", this);
this.$store.commit("clearOpenedSubmenu"); this.$store.commit("clearOpenedSubmenu");
this.$router.push({ name: "login" }); this.$router.push({ name: "login" });
},
}); });
} }
})
.finally(() => {
this.savePassLoading = false;
}); });
}); });
}, },
@@ -120,25 +122,3 @@ export default {
}, },
}; };
</script> </script>
<style lang="scss" scoped>
.change-pass {
&-btn-box {
margin-bottom: 10px;
button {
padding-left: 0;
span {
color: #2d8cf0;
transition: all 0.2s;
}
span:hover {
color: #0c25f1;
transition: all 0.2s;
}
}
}
}
</style>

View File

@@ -94,7 +94,7 @@
width: 100%; width: 100%;
} }
>.ivu-form { >.el-form {
flex-wrap: wrap !important; flex-wrap: wrap !important;
} }
@@ -175,11 +175,11 @@ div.base-info-item {
justify-content: flex-start; justify-content: flex-start;
width: 100%; width: 100%;
>.ivu-card-body { >.el-card__body {
width: 100%; width: 100%;
} }
.ivu-card-body { .el-card__body {
width: 100%; width: 100%;
justify-content: center; justify-content: center;
align-items: flex-start; align-items: flex-start;
@@ -344,7 +344,7 @@ div.base-info-item {
text-align: center; text-align: center;
z-index: 999; z-index: 999;
>.ivu-btn { >.el-button {
margin: 0 10px; margin: 0 10px;
} }
} }

View File

@@ -78,6 +78,8 @@
</template> </template>
<script> <script>
import * as API_GOODS from "@/api/goods"; import * as API_GOODS from "@/api/goods";
import goodsType1Img from "@/assets/goodsType1.png";
import goodsType2Img from "@/assets/goodsType2.png";
export default { export default {
data() { data() {
return { return {
@@ -85,14 +87,14 @@ export default {
goodsTypeWay: [ goodsTypeWay: [
{ {
title: "实物商品", title: "实物商品",
img: require("@/assets/goodsType1.png"), img: goodsType1Img,
desc: "零售批发,物流配送", desc: "零售批发,物流配送",
type: "PHYSICAL_GOODS", type: "PHYSICAL_GOODS",
check: false, check: false,
}, },
{ {
title: "虚拟商品", title: "虚拟商品",
img: require("@/assets/goodsType2.png"), img: goodsType2Img,
desc: "虚拟核验,无需物流", desc: "虚拟核验,无需物流",
type: "VIRTUAL_GOODS", type: "VIRTUAL_GOODS",
check: false, check: false,

View File

@@ -10,10 +10,10 @@
<div class="form-item-view"> <div class="form-item-view">
<el-form-item label="商品分类"> <el-form-item label="商品分类">
<span class="goods-category-name">{{ <span class="goods-category-name">{{
this.baseInfoForm.categoryName[0] baseInfoForm.categoryName[0]
}}</span> }}</span>
<span> &gt; {{ this.baseInfoForm.categoryName[1] }}</span> <span> &gt; {{ baseInfoForm.categoryName[1] }}</span>
<span> &gt; {{ this.baseInfoForm.categoryName[2] }}</span> <span> &gt; {{ baseInfoForm.categoryName[2] }}</span>
</el-form-item> </el-form-item>
<el-form-item label="商品名称" prop="goodsName"> <el-form-item label="商品名称" prop="goodsName">
<el-input v-model="baseInfoForm.goodsName" clearable placeholder="商品名称" style="width: 260px" type="text" /> <el-input v-model="baseInfoForm.goodsName" clearable placeholder="商品名称" style="width: 260px" type="text" />
@@ -190,7 +190,7 @@
<el-collapse-item title="自定义规格项" name="1"> <el-collapse-item title="自定义规格项" name="1">
<div> <div>
<div v-for="(item, $index) in skuInfo" :key="$index" class="sku-item-content"> <div v-for="(item, $index) in skuInfo" :key="$index" class="sku-item-content">
<el-card class="ivu-card-body"> <el-card>
<template #header> <template #header>
<el-button link type="danger" @click="handleCloseSkuItem($index, item)">删除规格项</el-button> <el-button link type="danger" @click="handleCloseSkuItem($index, item)">删除规格项</el-button>
</template> </template>
@@ -478,7 +478,7 @@
<div class="footer-btns"> <div class="footer-btns">
<el-button type="primary" @click="pre">上一步</el-button> <el-button type="primary" @click="pre">上一步</el-button>
<el-button :loading="submitLoading" type="primary" @click="save"> <el-button :loading="submitLoading" type="primary" @click="save">
{{ this.$route.query.id ? "保存" : "保存商品" }} {{ $route.query.id ? "保存" : "保存商品" }}
</el-button> </el-button>
</div> </div>
</div> </div>
@@ -1310,7 +1310,12 @@ export default {
this.params_panel = []; this.params_panel = [];
API_GOODS.getCategoryParamsListDataSeller(this.categoryId).then( API_GOODS.getCategoryParamsListDataSeller(this.categoryId).then(
(response) => { (response) => {
if (!response || response.length <= 0) { const list = Array.isArray(response)
? response
: Array.isArray(response?.result)
? response.result
: [];
if (!list.length) {
return; return;
} }
@@ -1355,15 +1360,15 @@ export default {
return undefined; return undefined;
}; };
const isGrouped = response[0] && Array.isArray(response[0].params); const isGrouped = list[0] && Array.isArray(list[0].params);
const flatParams = isGrouped const flatParams = isGrouped
? response.reduce((acc, g) => { ? list.reduce((acc, g) => {
if (g && Array.isArray(g.params)) { if (g && Array.isArray(g.params)) {
acc.push(...g.params); acc.push(...g.params);
} }
return acc; return acc;
}, []) }, [])
: response; : list;
this.goodsParams = flatParams this.goodsParams = flatParams
.map((p) => { .map((p) => {
@@ -1547,7 +1552,7 @@ export default {
} }
} else if (val._error) { } else if (val._error) {
// 清除错误 // 清除错误
this.$delete(val, '_error'); delete val._error;
if (this.skuInfo[groupIndex]) { if (this.skuInfo[groupIndex]) {
this.skuInfo[groupIndex].spec_values = this.skuInfo[groupIndex].spec_values.filter((i) => i.value !== ""); this.skuInfo[groupIndex].spec_values = this.skuInfo[groupIndex].spec_values.filter((i) => i.value !== "");
} }
@@ -2316,7 +2321,7 @@ export default {
</style> </style>
<style scoped> <style scoped>
.ivu-select .ivu-select-dropdown { .el-select .el-select-dropdown {
overflow: hidden !important; overflow: hidden !important;
} }

View File

@@ -10,7 +10,7 @@
<h4>Hi,<span style="margin-left: 5px">{{ userData.nickName }}</span></h4> <h4>Hi,<span style="margin-left: 5px">{{ userData.nickName }}</span></h4>
<img <img
class="shop-logo" class="shop-logo"
:src="userData.storeLogo || require('@/assets/logo1.png')" :src="userData.storeLogo || defaultLogo"
alt="" alt=""
/> />
</div> </div>
@@ -199,6 +199,7 @@
</template> </template>
<script> <script>
import defaultLogo from "@/assets/logo1.png";
import { Picture, CreditCard, List, User } from "@element-plus/icons-vue"; import { Picture, CreditCard, List, User } from "@element-plus/icons-vue";
import { getSellerHomeData, getHomeNotice } from "@/api/index"; import { getSellerHomeData, getHomeNotice } from "@/api/index";
import { getIMDetail } from "@/api/common"; import { getIMDetail } from "@/api/common";
@@ -216,6 +217,7 @@ export default {
}, },
data() { data() {
return { return {
defaultLogo,
noticeFlage: false, noticeFlage: false,
homeData: {}, homeData: {},
userData: "", userData: "",

View File

@@ -1,4 +1,4 @@
const plugins = [ const plugins = [
'advlist', 'anchor', 'autolink', 'autosave', 'code', 'codesample', 'directionality', 'emoticons', 'fullscreen', 'image', 'importcss', 'insertdatetime', 'link', 'lists', 'media', 'nonbreaking', 'pagebreak', 'preview', 'save', 'searchreplace', 'table', 'template', 'visualblocks', 'visualchars', 'wordcount' 'advlist', 'anchor', 'autolink', 'autosave', 'charmap', 'code', 'codesample', 'directionality', 'emoticons', 'fullscreen', 'image', 'importcss', 'insertdatetime', 'link', 'lists', 'media', 'nonbreaking', 'pagebreak', 'preview', 'save', 'searchreplace', 'table', 'template', 'visualblocks', 'visualchars', 'wordcount'
] ]
export default plugins export default plugins

View File

@@ -23,6 +23,7 @@
</template> </template>
<script> <script>
import { getCategoryTree } from "@/api/goods.js";
export default { export default {
data() { data() {
@@ -40,10 +41,32 @@ export default {
this.init(); this.init();
}, },
methods: { methods: {
loadCategoryFromCache() {
try {
const raw = localStorage.getItem("category");
if (!raw) {
return null;
}
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : null;
} catch {
return null;
}
},
applyCategoryList(category) {
if (!Array.isArray(category)) {
this.categoryList = [];
return;
}
category.forEach((item) => {
item.___type = "category";
});
this.categoryList = category;
},
// 点击一级 // 点击一级
handleClickChild(item, index) { handleClickChild(item, index) {
this.parentIndex = index; this.parentIndex = index;
this.secondLevel = item.children; this.secondLevel = item.children || [];
item.___type = "category"; item.___type = "category";
item.allId = item.id; item.allId = item.id;
@@ -51,8 +74,6 @@ export default {
this.thirdIndex = ''; this.thirdIndex = '';
this.thirdLevel = [] this.thirdLevel = []
this.$emit("selected", [item]); this.$emit("selected", [item]);
// 点击第一级的时候默认显示第二级第一个
// this.handleClickSecondChild(item.children, 0);
}, },
// 点击二级 // 点击二级
handleClickSecondChild(second, index) { handleClickSecondChild(second, index) {
@@ -60,10 +81,9 @@ export default {
second.allId = `${second.parentId},${second.id}` second.allId = `${second.parentId},${second.id}`
this.secondIndex = index; this.secondIndex = index;
this.thirdLevel = second.children; this.thirdLevel = second.children || [];
this.thirdIndex = ''; this.thirdIndex = '';
this.$emit("selected", [second]); this.$emit("selected", [second]);
// this.handleClickthirdChild(second.children[0], 0);
}, },
// 点击三级 // 点击三级
handleClickthirdChild(item, index) { handleClickthirdChild(item, index) {
@@ -73,21 +93,17 @@ export default {
this.thirdIndex = index; this.thirdIndex = index;
}, },
init() { init() {
const loadCategory = () => { const cached = this.loadCategoryFromCache();
const category = JSON.parse(localStorage.getItem("category")); if (cached) {
if (!Array.isArray(category)) { this.applyCategoryList(cached);
return; return;
} }
category.forEach((item) => { getCategoryTree().then((res) => {
item.___type = "category"; if (res.success && Array.isArray(res.result)) {
}); localStorage.setItem("category", JSON.stringify(res.result));
this.categoryList = category; this.applyCategoryList(res.result);
};
loadCategory();
if (!this.categoryList.length) {
setTimeout(loadCategory, 3000);
} }
});
}, },
}, },
}; };

View File

@@ -3,10 +3,12 @@ import category from "./category.vue";
import pages from "./pages.vue"; import pages from "./pages.vue";
import goods from "../goods-dialog.vue"; import goods from "../goods-dialog.vue";
import other from "./other.vue"; import other from "./other.vue";
import shops from "./shops.vue";
export default { export default {
category: markRaw(category), category: markRaw(category),
goods: markRaw(goods), goods: markRaw(goods),
other: markRaw(other), other: markRaw(other),
pages: markRaw(pages), pages: markRaw(pages),
shops: markRaw(shops),
}; };

View File

@@ -44,12 +44,12 @@
</div> </div>
</div> </div>
<el-pagination <el-pagination
v-model:current-page="params.pageNumber"
class="pageration" class="pageration"
size="small" size="small"
layout="total, prev, pager, next, jumper" layout="total, prev, pager, next, jumper"
:total="total" :total="total"
:page-size="params.pageSize" :page-size="params.pageSize"
:current-page="params.pageNumber"
@current-change="changePageSize" @current-change="changePageSize"
/> />
</div> </div>

View File

@@ -7,6 +7,7 @@
</template> </template>
<script> <script>
import defaultLogo from "@/assets/logo.png";
import { getBaseSite } from "@/api/common.js"; import { getBaseSite } from "@/api/common.js";
export default { export default {

View File

@@ -157,17 +157,6 @@
height: 100%; height: 100%;
.options {
.ivu-select-dropdown {
transform-origin: center top 0px;
position: absolute;
top: 45px !important;
left: -2px;
will-change: top, left;
}
}
.message-con { .message-con {
display: inline-block; display: inline-block;

View File

@@ -20,8 +20,7 @@
<script> <script>
import AMapLoader from "@amap/amap-jsapi-loader"; import AMapLoader from "@amap/amap-jsapi-loader";
import { getRegion } from "@/api/common.js"; import { getRegion } from "@/api/common.js";
import config from "@/config/index";
const config = require("@/config/index");
export default { export default {
name: "map", name: "map",
data() { data() {

View File

@@ -214,11 +214,8 @@ export default {
default: () => [] default: () => []
}, },
size: { size: {
default() { type: String,
return !this.$IVIEW || this.$IVIEW.size === "" default: "default",
? "default"
: this.$IVIEW.size;
}
}, },
loading: { loading: {
type: Boolean, type: Boolean,

View File

@@ -350,12 +350,8 @@
<script> <script>
import * as API_Order from "@/api/order"; import * as API_Order from "@/api/order";
import vueQr from "vue-qr";
export default { export default {
components: { name: "returnGoodsOrderDetail",
"vue-qr": vueQr,
},
name: "orderDetail",
data() { data() {
return { return {
sn: "", // 订单号 sn: "", // 订单号
@@ -624,9 +620,6 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.ivu-col {
width: 100% !important;
}
.main-content { .main-content {
min-height: 600px; min-height: 600px;
padding: 10px; padding: 10px;

View File

@@ -49,6 +49,9 @@
import { UploadFilled } from "@element-plus/icons-vue"; import { UploadFilled } from "@element-plus/icons-vue";
import { downLoadDeliverExcel, uploadDeliverExcel } from "@/api/order.js"; import { downLoadDeliverExcel, uploadDeliverExcel } from "@/api/order.js";
import { baseUrl } from "@/libs/axios.js"; import { baseUrl } from "@/libs/axios.js";
import downloadImg from "@/assets/download.png";
import uploadImg from "@/assets/upload.png";
import successImg from "@/assets/success.png";
export default { export default {
components: { UploadFilled }, components: { UploadFilled },
@@ -59,17 +62,17 @@ export default {
accessToken: {}, accessToken: {},
stepList: [ stepList: [
{ {
img: require("@/assets/download.png"), img: downloadImg,
title: "1.下载批量发货导入模板", title: "1.下载批量发货导入模板",
checked: true, checked: true,
}, },
{ {
img: require("@/assets/upload.png"), img: uploadImg,
title: "2.上传数据", title: "2.上传数据",
checked: false, checked: false,
}, },
{ {
img: require("@/assets/success.png"), img: successImg,
title: "3.完成", title: "3.完成",
checked: false, checked: false,
}, },

View File

@@ -578,7 +578,7 @@ export default {
}; };
</script> </script>
<style lang="scss" scpoed> <style lang="scss" scoped>
h4 { h4 {
margin-bottom: 10px; margin-bottom: 10px;
padding: 0 10px; padding: 0 10px;

View File

@@ -116,7 +116,7 @@
<img v-if="imageVisible" :src="imageSrc" style="width: 100%" alt="" /> <img v-if="imageVisible" :src="imageSrc" style="width: 100%" alt="" />
</el-dialog> </el-dialog>
<el-dialog v-model="liveGoodsVisible" width="800px" :show-footer="false"> <el-dialog v-model="liveGoodsVisible" width="800px">
<liveGoods reviewed @selectedGoods="callBackData" /> <liveGoods reviewed @selectedGoods="callBackData" />
</el-dialog> </el-dialog>
</div> </div>

View File

@@ -83,7 +83,7 @@
<!-- 选择商品链接 --> <!-- 选择商品链接 -->
<liliDialog ref="liliDialog" @selectedLink="selectedLink"></liliDialog> <liliDialog ref="liliDialog" @selectedLink="selectedLink"></liliDialog>
<!-- 选择图片 --> <!-- 选择图片 -->
<el-dialog width="1200px" v-model="picModelFlag" :show-footer="false"> <el-dialog width="1200px" v-model="picModelFlag">
<ossManage @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" ref="ossManage"/> <ossManage @callback="callbackSelected" :isComponent="true" :initialize="picModelFlag" ref="ossManage"/>
</el-dialog> </el-dialog>
</li> </li>

View File

@@ -1,7 +1 @@
import hotzone from './index.vue' export { default } from "./index.vue";
hotzone.install = (Vue) => {
Vue.component(hotzone.name, hotzone)
}
export default hotzone

View File

@@ -1,3 +1,20 @@
import nav1 from '@/assets/nav/1.jpg';
import nav2 from '@/assets/nav/2.jpg';
import nav3 from '@/assets/nav/3.jpg';
import nav4 from '@/assets/nav/4.jpg';
import nav5 from '@/assets/nav/5.jpg';
import navDecorate from '@/assets/nav/decorate.png';
import navDecorate1 from '@/assets/nav/decorate1.png';
import navDecorate2 from '@/assets/nav/decorate2.jpeg';
import navDecorate3 from '@/assets/nav/decorate3.jpeg';
import navDecorate4 from '@/assets/nav/decorate4.jpeg';
import navDecorate5 from '@/assets/nav/decorate5.jpeg';
import navDecorate6 from '@/assets/nav/decorate6.jpeg';
import navDecorate7 from '@/assets/nav/decorate7.jpeg';
import navDecorate8 from '@/assets/nav/decorate8.png';
import navDecorate9 from '@/assets/nav/decorate9.png';
import navDecorate10 from '@/assets/nav/decorate10.jpeg';
import navDecorate11 from '@/assets/nav/decorate11.jpeg';
export const modelData = [ export const modelData = [
{ {
@@ -7,32 +24,32 @@ export const modelData = [
showName: '', showName: '',
options: { options: {
list: [{ list: [{
img: require('@/assets/nav/decorate1.png'), img: navDecorate1,
url: '', url: '',
size: '1200*自定义' size: '1200*自定义'
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '', url: '',
size: '230*190' size: '230*190'
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '', url: '',
size: '230*190' size: '230*190'
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '', url: '',
size: '230*190' size: '230*190'
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '', url: '',
size: '230*190' size: '230*190'
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '', url: '',
size: '230*190' size: '230*190'
} }
@@ -48,70 +65,70 @@ export const modelData = [
list: [{ list: [{
time: 6, time: 6,
goodsList: [{ goodsList: [{
img: require('@/assets/nav/1.jpg'), img: nav1,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafads123213a', name: '阿迪达斯三叶草asdasdafads123213a',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/2.jpg'), img: nav2,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/3.jpg'), img: nav3,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/4.jpg'), img: nav4,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/5.jpg'), img: nav5,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/1.jpg'), img: nav1,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/2.jpg'), img: nav2,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/3.jpg'), img: nav3,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/4.jpg'), img: nav4,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/5.jpg'), img: nav5,
price: 20, price: 20,
originalPrice: 30, originalPrice: 30,
name: '阿迪达斯三叶草asdasdafadsa', name: '阿迪达斯三叶草asdasdafadsa',
@@ -122,23 +139,23 @@ export const modelData = [
{ {
time: 8, time: 8,
goodsList: [{ goodsList: [{
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/2.jpg'), img: nav2,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/3.jpg'), img: nav3,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/4.jpg'), img: nav4,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/5.jpg'), img: nav5,
url: '' url: ''
}, },
] ]
@@ -146,23 +163,23 @@ export const modelData = [
{ {
time: 10, time: 10,
goodsList: [{ goodsList: [{
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/2.jpg'), img: nav2,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/3.jpg'), img: nav3,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/4.jpg'), img: nav4,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/5.jpg'), img: nav5,
url: '' url: ''
}, },
] ]
@@ -170,23 +187,23 @@ export const modelData = [
{ {
time: 12, time: 12,
goodsList: [{ goodsList: [{
img: require('@/assets/nav/1.jpg'), img: nav1,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/2.jpg'), img: nav2,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/3.jpg'), img: nav3,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/4.jpg'), img: nav4,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/5.jpg'), img: nav5,
url: '' url: ''
}, },
] ]
@@ -213,65 +230,65 @@ export const modelData = [
icon: 'md-image', icon: 'md-image',
options: { options: {
bgImg: { bgImg: {
img: require('@/assets/nav/decorate.png'), img: navDecorate,
url: '', url: '',
size: "1300*585" size: "1300*585"
}, },
classification: [{ classification: [{
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, { }, {
img: require('@/assets/nav/decorate2.jpeg'), img: navDecorate2,
url: '', url: '',
size: '190*210' size: '190*210'
}, ], }, ],
brandList: [{ brandList: [{
img: require('@/assets/nav/decorate11.jpeg'), img: navDecorate11,
url: '', url: '',
size: '240*105' size: '240*105'
}, { }, {
img: require('@/assets/nav/decorate11.jpeg'), img: navDecorate11,
url: '', url: '',
size: '240*105' size: '240*105'
}, { }, {
img: require('@/assets/nav/decorate11.jpeg'), img: navDecorate11,
url: '', url: '',
size: '240*105' size: '240*105'
}, { }, {
img: require('@/assets/nav/decorate11.jpeg'), img: navDecorate11,
url: '', url: '',
size: '240*105' size: '240*105'
}, ] }, ]
@@ -288,49 +305,49 @@ export const modelData = [
bgColor: '#449dae', bgColor: '#449dae',
url: '', url: '',
list: [{ list: [{
img: require('@/assets/nav/decorate3.jpeg'), img: navDecorate3,
name: '阿迪达斯三叶草', name: '阿迪达斯三叶草',
describe: '也许是每一款经典系列都应该有一个独特的故事吧', describe: '也许是每一款经典系列都应该有一个独特的故事吧',
url: '', url: '',
size: '160*160' size: '160*160'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
size: '80*80' size: '80*80'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
size: '80*80' size: '80*80'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
size: '80*80' size: '80*80'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
size: '80*80' size: '80*80'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
size: '80*80' size: '80*80'
}, },
{ {
img: require('@/assets/nav/decorate4.jpeg'), img: navDecorate4,
name: '360行车记录', name: '360行车记录',
describe: '夜行 监控 电子狗 蓝牙', describe: '夜行 监控 电子狗 蓝牙',
url: '', url: '',
@@ -344,28 +361,28 @@ export const modelData = [
bgColor: '#a25684', bgColor: '#a25684',
url: '', url: '',
list: [{ list: [{
img: require('@/assets/nav/decorate5.jpeg'), img: navDecorate5,
name: '好心情喝出来', name: '好心情喝出来',
describe: '遇见懂你的饮品', describe: '遇见懂你的饮品',
url: '', url: '',
size: '100*100' size: '100*100'
}, },
{ {
img: require('@/assets/nav/decorate5.jpeg'), img: navDecorate5,
name: '好心情喝出来', name: '好心情喝出来',
describe: '遇见懂你的饮品', describe: '遇见懂你的饮品',
url: '', url: '',
size: '100*100' size: '100*100'
}, },
{ {
img: require('@/assets/nav/decorate5.jpeg'), img: navDecorate5,
name: '好心情喝出来', name: '好心情喝出来',
describe: '遇见懂你的饮品', describe: '遇见懂你的饮品',
url: '', url: '',
size: '100*100' size: '100*100'
}, },
{ {
img: require('@/assets/nav/decorate5.jpeg'), img: navDecorate5,
name: '好心情喝出来', name: '好心情喝出来',
describe: '遇见懂你的饮品', describe: '遇见懂你的饮品',
url: '', url: '',
@@ -388,35 +405,35 @@ export const modelData = [
list: [{ list: [{
name: '新年心愿单', name: '新年心愿单',
describe: '满269减50,满999减100', describe: '满269减50,满999减100',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "160*160" size: "160*160"
}, },
{ {
name: 'Ms.Maggie 冬季时尚', name: 'Ms.Maggie 冬季时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: 'Ms.Maggie 冬季时尚', name: 'Ms.Maggie 冬季时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: 'Ms.Maggie 冬季时尚', name: 'Ms.Maggie 冬季时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
@@ -430,42 +447,42 @@ export const modelData = [
list: [{ list: [{
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
{ {
name: '阿迪达斯 领跑时尚', name: '阿迪达斯 领跑时尚',
describe: '满269减50', describe: '满269减50',
img: require('@/assets/nav/decorate6.jpeg'), img: navDecorate6,
url: '', url: '',
size: "90*90" size: "90*90"
}, },
@@ -479,37 +496,37 @@ export const modelData = [
list: [{ list: [{
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
{ {
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
{ {
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
{ {
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
{ {
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
{ {
name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包', name: '小米红米3s手机壳保护套红米3高配版指纹男女款潮版磨砂硬壳防摔 收藏截图 送大礼包',
price: 14.9, price: 14.9,
img: require('@/assets/nav/decorate7.jpeg'), img: navDecorate7,
url: '' url: ''
}, },
] ]
@@ -524,7 +541,7 @@ export const modelData = [
list: [{ list: [{
name: '生鲜', name: '生鲜',
describe: "年货带回家 满199减60", describe: "年货带回家 满199减60",
img: require('@/assets/nav/decorate8.png'), img: navDecorate8,
url: '', url: '',
fromColor: '#e89621', fromColor: '#e89621',
toColor: "#f5c568", toColor: "#f5c568",
@@ -533,7 +550,7 @@ export const modelData = [
{ {
name: '众筹', name: '众筹',
describe: "年货带回家", describe: "年货带回家",
img: require('@/assets/nav/decorate9.png'), img: navDecorate9,
url: '', url: '',
fromColor: "#325bb4", fromColor: "#325bb4",
toColor: '#4c9afe', toColor: '#4c9afe',
@@ -542,7 +559,7 @@ export const modelData = [
{ {
name: '生鲜', name: '生鲜',
describe: "年货带回家 满199减60", describe: "年货带回家 满199减60",
img: require('@/assets/nav/decorate8.png'), img: navDecorate8,
url: '', url: '',
fromColor: "#1c9daf", fromColor: "#1c9daf",
toColor: '#40cda7', toColor: '#40cda7',
@@ -551,7 +568,7 @@ export const modelData = [
{ {
name: '众筹', name: '众筹',
describe: "备孕有孕检测仪", describe: "备孕有孕检测仪",
img: require('@/assets/nav/decorate9.png'), img: navDecorate9,
url: '', url: '',
fromColor: "#d13837", fromColor: "#d13837",
toColor: '#df6d4f', toColor: '#df6d4f',
@@ -560,7 +577,7 @@ export const modelData = [
{ {
name: '生鲜', name: '生鲜',
describe: "年货带回家 满199减60", describe: "年货带回家 满199减60",
img: require('@/assets/nav/decorate8.png'), img: navDecorate8,
url: '', url: '',
fromColor: "#ca4283", fromColor: "#ca4283",
toColor: '#eb75cf', toColor: '#eb75cf',
@@ -569,7 +586,7 @@ export const modelData = [
{ {
name: '众筹', name: '众筹',
describe: "备孕有孕检测仪", describe: "备孕有孕检测仪",
img: require('@/assets/nav/decorate9.png'), img: navDecorate9,
url: '', url: '',
fromColor: "#5d40c1", fromColor: "#5d40c1",
toColor: '#8c5fdb', toColor: '#8c5fdb',
@@ -595,244 +612,244 @@ export const modelData = [
options: { options: {
list: [ list: [
[{ [{
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
], ],
[{ [{
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
], ],
[{ [{
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
], ],
[{ [{
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''
}, },
{ {
img: require('@/assets/nav/decorate10.jpeg'), img: navDecorate10,
name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量', name: 'Apple/苹果 13 英寸MacBook Pro Multi-Touch Bar 和 Touch ID 2.9GHz 处理器 512GB 存储容量',
price: 6666, price: 6666,
url: '' url: ''

View File

@@ -25,7 +25,7 @@
</ul> </ul>
</div> </div>
<div class="search-con"> <div class="search-con">
<img :src="require('@/assets/logo.png')" class="logo" alt="" /> <img :src="logoImg" class="logo" alt="" />
<div class="search"> <div class="search">
<el-input size="large" placeholder="输入你想查找的商品"> <el-input size="large" placeholder="输入你想查找的商品">
<template #append> <template #append>
@@ -144,6 +144,7 @@
</template> </template>
<script> <script>
import { ShoppingCart } from "@element-plus/icons-vue"; import { ShoppingCart } from "@element-plus/icons-vue";
import logoImg from "@/assets/logo.png";
import Draggable from "vuedraggable"; import Draggable from "vuedraggable";
import ModelFormItem from "./modelFormItem.vue"; import ModelFormItem from "./modelFormItem.vue";
import ossManage from "@/views/sys/oss-manage/ossManage"; import ossManage from "@/views/sys/oss-manage/ossManage";
@@ -158,6 +159,7 @@ export default {
props: ["data"], props: ["data"],
data() { data() {
return { return {
logoImg,
picModelFlag: false, picModelFlag: false,
showModal: false, showModal: false,
showModalNav: false, showModalNav: false,

View File

@@ -67,7 +67,7 @@
class="discountAdvert" class="discountAdvert"
:style="{ :style="{
'background-image': 'background-image':
'url(' + require('@/assets/nav/decorate.png') + ')', 'url(' + decorateImg + ')',
}" }"
> >
<div> <div>
@@ -280,6 +280,7 @@ import onlyGoodsModel from "./modelList/onlyGoodsModel.vue";
import oneRowThreeColumns from "./modelList/oneRowThreeColumns.vue"; import oneRowThreeColumns from "./modelList/oneRowThreeColumns.vue";
import seckillOnlyAlbum from "./modelList/seckill-only-album.vue"; import seckillOnlyAlbum from "./modelList/seckill-only-album.vue";
import decorateImg from "@/assets/nav/decorate.png";
export default { export default {
name: "modelFormItem", name: "modelFormItem",
props: ["element", "select", "index", "data"], props: ["element", "select", "index", "data"],
@@ -302,6 +303,7 @@ export default {
}, },
data() { data() {
return { return {
decorateImg,
showModal: false, // modal显隐 showModal: false, // modal显隐
selected: {}, // 弹窗编辑草稿 selected: {}, // 弹窗编辑草稿
editTarget: null, // 确定后写回的原数据 editTarget: null, // 确定后写回的原数据

View File

@@ -36,7 +36,6 @@ export default {
default: {} default: {}
} }
}, },
components: {},
mounted() { mounted() {
}, },

View File

@@ -16,7 +16,6 @@
z-index: 99; z-index: 99;
width: 100%; width: 100%;
height: 100%; height: 100%;
.ivu-btn,
.el-button{ .el-button{
float: right; float: right;
margin-right: 5px; margin-right: 5px;

View File

@@ -35,7 +35,7 @@
cursor: pointer; cursor: pointer;
.ivu-card-body { .el-card__body {
padding: 0; padding: 0;
} }
@@ -243,7 +243,7 @@
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.demo-tree-render .ivu-tree-title{ .demo-tree-render .el-tree-node__content{
width: 94%; width: 94%;
} }
} }

View File

@@ -222,166 +222,8 @@
</el-col> </el-col>
</el-row> </el-row>
<!--<div class="oss-operation padding-row">-->
<!--<div>-->
<!--<Upload-->
<!--ref="up"-->
<!--:action="commonUrl + '/common/common/upload/file'"-->
<!--:data="{-->
<!--directoryPath: searchForm.fileDirectoryId,-->
<!--}"-->
<!--:headers="accessToken"-->
<!--:max-size="20480"-->
<!--:on-error="handleError"-->
<!--:on-exceeded-size="handleMaxSize"-->
<!--:on-success="handleSuccess"-->
<!--:show-upload-list="false"-->
<!--multiple-->
<!--style="display: inline-block"-->
<!--&gt;-->
<!--<Button>上传图片</Button>-->
<!--</Upload>-->
<!--<Dropdown @on-click="handleDropdown" v-if="!isComponent">-->
<!--<Button>-->
<!--更多操作-->
<!--<Icon type="md-arrow-dropdown"/>-->
<!--</Button>-->
<!--<DropdownMenu slot="list">-->
<!--<DropdownItem name="refresh">刷新</DropdownItem>-->
<!--<DropdownItem v-show="showType == 'list'" name="removeAll"-->
<!--&gt;批量删除-->
<!--</DropdownItem>-->
<!--</DropdownMenu>-->
<!--</Dropdown>-->
<!--</div>-->
<!--</div>-->
</div> </div>
<!--<Alert show-icon v-if="!isComponent">-->
<!--已选择-->
<!--<span>{{ selectCount }}</span> -->
<!--<a class="select-clear" @click="clearSelectAll">清空</a>-->
<!--<span v-if="selectCount > 0" style="margin-left: 15px"-->
<!--&gt;共计 {{ totalSize }} 存储量</span-->
<!--&gt;-->
<!--</Alert>-->
<!--<div v-show="showType === 'list'" >-->
<!--<div class="flex">-->
<!--<div class="article-category mr_10">-->
<!--<Tree-->
<!--:data="treeData"-->
<!--@on-contextmenu="handleContextMenu"-->
<!--@on-select-change="handleCateChange"-->
<!--&gt;-->
<!--<template slot="contextMenu" v-if="!isComponent">-->
<!--<DropdownItem @click.native="handleContextMenuEdit"-->
<!--&gt;编辑-->
<!--</DropdownItem-->
<!--&gt;-->
<!--<DropdownItem-->
<!--style="color: #ed4014"-->
<!--@click.native="handleContextMenuDelete"-->
<!--&gt;删除-->
<!--</DropdownItem-->
<!--&gt;-->
<!--</template>-->
<!--</Tree>-->
<!--<Alert v-if="!isComponent">鼠标右键编辑/删除分组</Alert>-->
<!--<div class="group-row flex" v-if="!isComponent">-->
<!--<Button @click="handleClickAddGroup">添加分组</Button>-->
<!--</div>-->
<!--</div>-->
<!--<Table-->
<!--ref="table"-->
<!--:columns="isComponent ? viewColumns : columns"-->
<!--:data="data"-->
<!--:loading="loading"-->
<!--border-->
<!--class="table"-->
<!--sortable="custom"-->
<!--@on-sort-change="changeSort"-->
<!--@on-selection-change="changeSelect"-->
<!--&gt;-->
<!--<template slot="fileKey" slot-scope="{ row }">-->
<!--<a @click="copyFileUrl(row)">{{ row.fileKey }}</a>-->
<!--</template>-->
<!--</Table>-->
<!--</div>-->
<!--</div>-->
<!--<div v-show="showType === 'thumb'">-->
<!--<div class="oss-wrapper">-->
<!--<Card v-for="(item, i) in data" :key="i" class="oss-card">-->
<!--<div class="content">-->
<!--<img-->
<!--v-if="item.fileType.indexOf('image') >= 0"-->
<!--:src="item.url"-->
<!--class="img"-->
<!--@click="showPic(item)"-->
<!--/>-->
<!--<div-->
<!--v-else-if="item.fileType.indexOf('video') >= 0"-->
<!--class="video"-->
<!--@click="showVideo(item)"-->
<!--&gt;-->
<!--&lt;!&ndash; 文件小于5MB显示video &ndash;&gt;-->
<!--<video v-if="item.fileSize < 1024 * 1024 * 5" class="cover">-->
<!--<source :src="item.url"/>-->
<!--</video>-->
<!--<img class="play" src="@/assets/play.png"/>-->
<!--</div>-->
<!--<div v-else class="other">-->
<!--<div class="name">{{ item.name }}</div>-->
<!--<div class="key">{{ item.fileKey }}</div>-->
<!--<div class="info">-->
<!--文件类型{{ item.fileType }} 文件大小{{-->
<!--((item.fileSize * 1.0) / (1024 * 1024)).toFixed(2)-->
<!--}}-->
<!--MB 创建时间{{ item.createTime }}-->
<!--</div>-->
<!--</div>-->
<!--<div class="actions">-->
<!--<div class="btn">-->
<!--<Tooltip content="下载" placement="top">-->
<!--<Icon-->
<!--size="16"-->
<!--type="md-download"-->
<!--@click="download(item)"-->
<!--/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--<div class="btn">-->
<!--<Tooltip content="重命名" placement="top">-->
<!--<Icon size="16" type="md-create" @click="rename(item)"/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--<div class="btn-no">-->
<!--<Tooltip content="删除" placement="top">-->
<!--<Icon size="16" type="md-trash" @click="remove(item)"/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</Card>-->
<!--</div>-->
<!--</div>-->
<!--<Row class="mt_10" justify="end" type="flex">-->
<!--<Page-->
<!--:current="searchForm.pageNumber"-->
<!--:page-size="searchForm.pageSize"-->
<!--:page-size-opts="pageSizeOpts"-->
<!--:total="total"-->
<!--show-elevator-->
<!--show-sizer-->
<!--show-total-->
<!--size="small"-->
<!--@on-change="changePage"-->
<!--@on-page-size-change="changePageSize"-->
<!--&gt;</Page>-->
<!--</Row>-->
</el-card> </el-card>
</el-row> </el-row>
<el-dialog <el-dialog
@@ -477,7 +319,8 @@ import {
import DPlayer from "dplayer"; import DPlayer from "dplayer";
import {commonUrl} from "@/libs/axios"; import {commonUrl} from "@/libs/axios";
const config = require("@/config/index"); import config from "@/config/index";
import playImg from "@/assets/play.png";
let dp; let dp;
export default { export default {
@@ -631,7 +474,7 @@ export default {
} else { } else {
return h("img", { return h("img", {
attrs: { attrs: {
src: require("@/assets/play.png"), src: playImg,
}, },
style: { style: {
cursor: "pointer", cursor: "pointer",
@@ -832,7 +675,7 @@ export default {
} else { } else {
return h("img", { return h("img", {
attrs: { attrs: {
src: require("@/assets/play.png"), src: playImg,
}, },
style: { style: {
cursor: "pointer", cursor: "pointer",
@@ -917,41 +760,6 @@ export default {
groupLoading: false, groupLoading: false,
// 图片列表 // 图片列表
selectedOss: [], selectedOss: [],
myData: [
{
title: 'parent 1',
expand: true,
render: (h, {root, node, data}) => {
return h('span', {style: {display: 'inline-block', width: '100%'}}, [
h('span', [h("Icon", {type: 'ios-folder-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '32px'}},
[h("Button", {
...this.buttonProps,
icon: 'ios-add',
type: 'primary',
style: {width: '64px'},
onClick: () => {
this.append(data)
}
})
])
]);
},
children: [
{
title: 'child 1-1',
expand: true,
children: [{title: 'leaf 1-1-1', expand: true}, {title: 'leaf 1-1-2', expand: true}]
},
{
title: 'child 1-2',
expand: true,
children: [{title: 'leaf 1-2-1', expand: true}, {title: 'leaf 1-2-1', expand: true}]
}
]
}
],
buttonProps: {type: 'default', size: 'small',},
}; };
}, },
watch: { watch: {
@@ -1099,57 +907,6 @@ export default {
this.searchForm.pageNumber = value; this.searchForm.pageNumber = value;
this.getDataList(); this.getDataList();
}, },
// 自定义tree节点显示内容和交互
renderContent(h, {root, node, data}) {
if (data.value === '0') {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}}, [])
]
);
} else {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}},
[
h("Dropdown", {style: {marginLeft: "4px"}},
[
h("Icon", {
props: {type: 'ios-more', size: "20",},
style: {display: 'inline-block'},
on: {
click: () => {
}
}
}),
h("DropdownMenu", {
slot: "list"
}, [
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuEdit(root, node, data)
}
}
}, "编辑"),
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuDelete()
}
}
}, "删除"),
])
]),
])
]
);
}
},
handleContextMenu(val) { handleContextMenu(val) {
console.log('handleContextMenu', val); console.log('handleContextMenu', val);

View File

@@ -218,166 +218,8 @@
</el-col> </el-col>
</el-row> </el-row>
<!--<div class="oss-operation padding-row">-->
<!--<div>-->
<!--<Upload-->
<!--ref="up"-->
<!--:action="commonUrl + '/common/common/upload/file'"-->
<!--:data="{-->
<!--directoryPath: searchForm.fileDirectoryId,-->
<!--}"-->
<!--:headers="accessToken"-->
<!--:max-size="20480"-->
<!--:on-error="handleError"-->
<!--:on-exceeded-size="handleMaxSize"-->
<!--:on-success="handleSuccess"-->
<!--:show-upload-list="false"-->
<!--multiple-->
<!--style="display: inline-block"-->
<!--&gt;-->
<!--<el-button>上传图片</el-button>-->
<!--</Upload>-->
<!--<Dropdown @click="handleDropdown" v-if="!isComponent">-->
<!--<el-button>-->
<!--更多操作-->
<!--<Icon type="md-arrow-dropdown"/>-->
<!--</el-button>-->
<!--<DropdownMenu #list>-->
<!--<DropdownItem name="refresh">刷新</DropdownItem>-->
<!--<DropdownItem v-show="showType == 'list'" name="removeAll"-->
<!--&gt;批量删除-->
<!--</DropdownItem>-->
<!--</DropdownMenu>-->
<!--</Dropdown>-->
<!--</div>-->
<!--</div>-->
</div> </div>
<!--<Alert show-icon v-if="!isComponent">-->
<!--已选择-->
<!--<span>{{ selectCount }}</span> -->
<!--<a class="select-clear" @click="clearSelectAll">清空</a>-->
<!--<span v-if="selectCount > 0" style="margin-left: 15px"-->
<!--&gt;共计 {{ totalSize }} 存储量</span-->
<!--&gt;-->
<!--</Alert>-->
<!--<div v-show="showType === 'list'" >-->
<!--<div class="flex">-->
<!--<div class="article-category mr_10">-->
<!--<Tree-->
<!--:data="treeData"-->
<!--@on-contextmenu="handleContextMenu"-->
<!--@on-select-change="handleCateChange"-->
<!--&gt;-->
<!--<template #contextMenu v-if="!isComponent">-->
<!--<DropdownItem @click.native="handleContextMenuEdit"-->
<!--&gt;编辑-->
<!--</DropdownItem-->
<!--&gt;-->
<!--<DropdownItem-->
<!--style="color: #ed4014"-->
<!--@click.native="handleContextMenuDelete"-->
<!--&gt;删除-->
<!--</DropdownItem-->
<!--&gt;-->
<!--</template>-->
<!--</Tree>-->
<!--<Alert v-if="!isComponent">鼠标右键编辑/删除分组</Alert>-->
<!--<div class="group-row flex" v-if="!isComponent">-->
<!--<el-button @click="handleClickAddGroup">添加分组</el-button>-->
<!--</div>-->
<!--</div>-->
<!--<Table-->
<!--ref="table"-->
<!--:columns="isComponent ? viewColumns : columns"-->
<!--:data="data"-->
<!--:loading="loading"-->
<!--border-->
<!--class="table"-->
<!--sortable="custom"-->
<!--@on-sort-change="changeSort"-->
<!--@on-selection-change="changeSelect"-->
<!--&gt;-->
<!--<template #fileKey #default="{ row }">-->
<!--<a @click="copyFileUrl(row)">{{ row.fileKey }}</a>-->
<!--</template>-->
<!--</Table>-->
<!--</div>-->
<!--</div>-->
<!--<div v-show="showType === 'thumb'">-->
<!--<div class="oss-wrapper">-->
<!--<Card v-for="(item, i) in data" :key="i" class="oss-card">-->
<!--<div class="content">-->
<!--<img-->
<!--v-if="item.fileType.indexOf('image') >= 0"-->
<!--:src="item.url"-->
<!--class="img"-->
<!--@click="showPic(item)"-->
<!--/>-->
<!--<div-->
<!--v-else-if="item.fileType.indexOf('video') >= 0"-->
<!--class="video"-->
<!--@click="showVideo(item)"-->
<!--&gt;-->
<!--&lt;!&ndash; 文件小于5MB显示video &ndash;&gt;-->
<!--<video v-if="item.fileSize < 1024 * 1024 * 5" class="cover">-->
<!--<source :src="item.url"/>-->
<!--</video>-->
<!--<img class="play" src="@/assets/play.png"/>-->
<!--</div>-->
<!--<div v-else class="other">-->
<!--<div class="name">{{ item.name }}</div>-->
<!--<div class="key">{{ item.fileKey }}</div>-->
<!--<div class="info">-->
<!--文件类型{{ item.fileType }} 文件大小{{-->
<!--((item.fileSize * 1.0) / (1024 * 1024)).toFixed(2)-->
<!--}}-->
<!--MB 创建时间{{ item.createTime }}-->
<!--</div>-->
<!--</div>-->
<!--<div class="actions">-->
<!--<div class="btn">-->
<!--<el-tooltip content="下载" placement="top">-->
<!--<Icon-->
<!--size="16"-->
<!--type="md-download"-->
<!--@click="download(item)"-->
<!--/>-->
<!--</el-tooltip>-->
<!--</div>-->
<!--<div class="btn">-->
<!--<el-tooltip content="重命名" placement="top">-->
<!--<Icon size="16" type="md-create" @click="rename(item)"/>-->
<!--</el-tooltip>-->
<!--</div>-->
<!--<div class="btn-no">-->
<!--<el-tooltip content="删除" placement="top">-->
<!--<Icon size="16" type="md-trash" @click="remove(item)"/>-->
<!--</el-tooltip>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</el-card>-->
<!--</div>-->
<!--</div>-->
<!--<div class="mt_10" justify="end" type="flex">-->
<!--<Page-->
<!--:current="searchForm.pageNumber"-->
<!--:page-size="searchForm.pageSize"-->
<!--:page-size-opts="pageSizeOpts"-->
<!--:total="total"-->
<!--show-elevator-->
<!--show-sizer-->
<!--show-total-->
<!--size="small"-->
<!--@change="changePage"-->
<!--@size-change="changePageSize"-->
<!--&gt;</el-pagination>-->
<!--</div>-->
</el-card> </el-card>
</el-row> </el-row>
<el-dialog <el-dialog
@@ -473,7 +315,8 @@ import {
import DPlayer from "dplayer"; import DPlayer from "dplayer";
import {commonUrl} from "@/libs/axios"; import {commonUrl} from "@/libs/axios";
const config = require("@/config/index"); import config from "@/config/index";
import playImg from "@/assets/play.png";
let dp; let dp;
export default { export default {
@@ -632,7 +475,7 @@ export default {
} else { } else {
return h("img", { return h("img", {
attrs: { attrs: {
src: require("@/assets/play.png"), src: playImg,
}, },
style: { style: {
cursor: "pointer", cursor: "pointer",
@@ -833,7 +676,7 @@ export default {
} else { } else {
return h("img", { return h("img", {
attrs: { attrs: {
src: require("@/assets/play.png"), src: playImg,
}, },
style: { style: {
cursor: "pointer", cursor: "pointer",
@@ -918,41 +761,6 @@ export default {
groupLoading: false, groupLoading: false,
// 图片列表 // 图片列表
selectedOss: [], selectedOss: [],
myData: [
{
title: 'parent 1',
expand: true,
render: (h, {root, node, data}) => {
return h('span', {style: {display: 'inline-block', width: '100%'}}, [
h('span', [h("Icon", {type: 'ios-folder-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '32px'}},
[h("Button", {
...this.buttonProps,
icon: 'ios-add',
type: 'primary',
style: {width: '64px'},
onClick: () => {
this.append(data)
}
})
])
]);
},
children: [
{
title: 'child 1-1',
expand: true,
children: [{title: 'leaf 1-1-1', expand: true}, {title: 'leaf 1-1-2', expand: true}]
},
{
title: 'child 1-2',
expand: true,
children: [{title: 'leaf 1-2-1', expand: true}, {title: 'leaf 1-2-1', expand: true}]
}
]
}
],
buttonProps: {type: 'default', size: 'small',},
}; };
}, },
watch: { watch: {
@@ -1104,57 +912,6 @@ export default {
this.searchForm.pageNumber = value; this.searchForm.pageNumber = value;
this.getDataList(); this.getDataList();
}, },
// 自定义tree节点显示内容和交互
renderContent(h, {root, node, data}) {
if (data.value === '0') {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}}, [])
]
);
} else {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}},
[
h("Dropdown", {style: {marginLeft: "4px"}},
[
h("Icon", {
props: {type: 'ios-more', size: "20",},
style: {display: 'inline-block'},
on: {
click: () => {
}
}
}),
h("DropdownMenu", {
slot: "list"
}, [
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuEdit(root, node, data)
}
}
}, "编辑"),
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuDelete()
}
}
}, "删除"),
])
]),
])
]
);
}
},
handleContextMenu(val) { handleContextMenu(val) {
console.log('handleContextMenu', val); console.log('handleContextMenu', val);

View File

@@ -247,7 +247,7 @@
@click="changeTextAlign('left')" @click="changeTextAlign('left')"
> >
<img <img
:src="require('@/assets/align-text-left.png')" :src="alignTextLeftImg"
class="align-text" class="align-text"
alt="" alt=""
/> />
@@ -258,7 +258,7 @@
@click="changeTextAlign('center')" @click="changeTextAlign('center')"
> >
<img <img
:src="require('@/assets/align-text-center.png')" :src="alignTextCenterImg"
class="align-text" class="align-text"
alt="" alt=""
/> />
@@ -269,7 +269,7 @@
@click="changeTextAlign('right')" @click="changeTextAlign('right')"
> >
<img <img
:src="require('@/assets/align-text-right.png')" :src="alignTextRightImg"
class="align-text" class="align-text"
alt="" alt=""
/> />
@@ -526,6 +526,9 @@
</template> </template>
<script> <script>
import { CircleClose } from "@element-plus/icons-vue"; import { CircleClose } from "@element-plus/icons-vue";
import alignTextLeftImg from "@/assets/align-text-left.png";
import alignTextCenterImg from "@/assets/align-text-center.png";
import alignTextRightImg from "@/assets/align-text-right.png";
import ossManage from "@/views/sys/oss-manage/ossManage"; import ossManage from "@/views/sys/oss-manage/ossManage";
import { modelData } from "./config"; import { modelData } from "./config";
import hotzone from "@/views/shop/hotzone"; import hotzone from "@/views/shop/hotzone";
@@ -540,6 +543,9 @@ export default {
}, },
data() { data() {
return { return {
alignTextLeftImg,
alignTextCenterImg,
alignTextRightImg,
ways, // 选择链接的类型 ways, // 选择链接的类型
picModelFlag: false, //图片选择器 picModelFlag: false, //图片选择器
linkType: "goods", // dialog弹窗口类型 linkType: "goods", // dialog弹窗口类型

View File

@@ -99,10 +99,14 @@ export default {
}, },
props: ["res"], props: ["res"],
methods: { methods: {
handleClickGoods(id) { handleClickGoods(goodsId) {
this.$router.push({ if (!goodsId) {
query: { id }, this.$Message.warning("商品信息不存在");
path: "/goods/goods-info/goodsDetail", return;
}
this.$filters.customRouterPush({
name: "goods-operation-edit",
query: { id: goodsId },
}); });
}, },
}, },

View File

@@ -112,10 +112,14 @@ export default {
}, },
props: ["res"], props: ["res"],
methods: { methods: {
handleClickGoods(id) { handleClickGoods(goodsId) {
this.$router.push({ if (!goodsId) {
query: { id }, this.$Message.warning("商品信息不存在");
path: "/goods/goods-info/goodsDetail", return;
}
this.$filters.customRouterPush({
name: "goods-operation-edit",
query: { id: goodsId },
}); });
}, },
} }

View File

@@ -35,7 +35,7 @@
cursor: pointer; cursor: pointer;
.ivu-card-body { .el-card__body {
padding: 0; padding: 0;
} }
@@ -240,7 +240,7 @@
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.demo-tree-render .ivu-tree-title{ .demo-tree-render .el-tree-node__content {
width: 94%; width: 94%;
} }
} }

View File

@@ -73,10 +73,7 @@
<div class="search"> <div class="search">
<el-card class="tabs-card"> <el-card class="tabs-card">
<el-tabs v-model="activeRoleTab" @tab-change="handleRoleTabChange"> <el-tabs v-model="activeRoleTab" @tab-change="handleRoleTabChange">
<el-tab-pane label="管理员" name="MANAGER" />
<el-tab-pane label="商家" name="STORE" /> <el-tab-pane label="商家" name="STORE" />
<el-tab-pane label="用户" name="MEMBER" />
<el-tab-pane label="客服" name="CUSTOMER" />
</el-tabs> </el-tabs>
</el-card> </el-card>
<el-row> <el-row>
@@ -232,167 +229,7 @@
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<!--<div class="oss-operation padding-row">-->
<!--<div>-->
<!--<Upload-->
<!--ref="up"-->
<!--:action="commonUrl + '/common/common/upload/file'"-->
<!--:data="{-->
<!--directoryPath: searchForm.fileDirectoryId,-->
<!--}"-->
<!--:headers="accessToken"-->
<!--:max-size="20480"-->
<!--:on-error="handleError"-->
<!--:on-exceeded-size="handleMaxSize"-->
<!--:on-success="handleSuccess"-->
<!--:show-upload-list="false"-->
<!--multiple-->
<!--style="display: inline-block"-->
<!--&gt;-->
<!--<Button>上传图片</Button>-->
<!--</Upload>-->
<!--<Dropdown @on-click="handleDropdown" v-if="!isComponent">-->
<!--<Button>-->
<!--更多操作-->
<!--<Icon type="md-arrow-dropdown"/>-->
<!--</Button>-->
<!--<DropdownMenu slot="list">-->
<!--<DropdownItem name="refresh">刷新</DropdownItem>-->
<!--<DropdownItem v-show="showType == 'list'" name="removeAll"-->
<!--&gt;批量删除-->
<!--</DropdownItem>-->
<!--</DropdownMenu>-->
<!--</Dropdown>-->
<!--</div>-->
<!--</div>-->
</div> </div>
<!--<Alert show-icon v-if="!isComponent">-->
<!--已选择-->
<!--<span>{{ selectCount }}</span> -->
<!--<a class="select-clear" @click="clearSelectAll">清空</a>-->
<!--<span v-if="selectCount > 0" style="margin-left: 15px"-->
<!--&gt;共计 {{ totalSize }} 存储量</span-->
<!--&gt;-->
<!--</Alert>-->
<!--<div v-show="showType === 'list'" >-->
<!--<div class="flex">-->
<!--<div class="article-category mr_10">-->
<!--<Tree-->
<!--:data="treeData"-->
<!--@on-contextmenu="handleContextMenu"-->
<!--@on-select-change="handleCateChange"-->
<!--&gt;-->
<!--<template slot="contextMenu" v-if="!isComponent">-->
<!--<DropdownItem @click.native="handleContextMenuEdit"-->
<!--&gt;编辑-->
<!--</DropdownItem-->
<!--&gt;-->
<!--<DropdownItem-->
<!--style="color: #ed4014"-->
<!--@click.native="handleContextMenuDelete"-->
<!--&gt;删除-->
<!--</DropdownItem-->
<!--&gt;-->
<!--</template>-->
<!--</Tree>-->
<!--<Alert v-if="!isComponent">鼠标右键编辑/删除分组</Alert>-->
<!--<div class="group-row flex" v-if="!isComponent">-->
<!--<Button @click="handleClickAddGroup">添加分组</Button>-->
<!--</div>-->
<!--</div>-->
<!--<Table-->
<!--ref="table"-->
<!--:columns="isComponent ? viewColumns : columns"-->
<!--:data="data"-->
<!--:loading="loading"-->
<!--border-->
<!--class="table"-->
<!--sortable="custom"-->
<!--@on-sort-change="changeSort"-->
<!--@on-selection-change="changeSelect"-->
<!--&gt;-->
<!--<template slot="fileKey" slot-scope="{ row }">-->
<!--<a @click="copyFileUrl(row)">{{ row.fileKey }}</a>-->
<!--</template>-->
<!--</Table>-->
<!--</div>-->
<!--</div>-->
<!--<div v-show="showType === 'thumb'">-->
<!--<div class="oss-wrapper">-->
<!--<Card v-for="(item, i) in data" :key="i" class="oss-card">-->
<!--<div class="content">-->
<!--<img-->
<!--v-if="item.fileType.indexOf('image') >= 0"-->
<!--:src="item.url"-->
<!--class="img"-->
<!--@click="showPic(item)"-->
<!--/>-->
<!--<div-->
<!--v-else-if="item.fileType.indexOf('video') >= 0"-->
<!--class="video"-->
<!--@click="showVideo(item)"-->
<!--&gt;-->
<!--&lt;!&ndash; 文件小于5MB显示video &ndash;&gt;-->
<!--<video v-if="item.fileSize < 1024 * 1024 * 5" class="cover">-->
<!--<source :src="item.url"/>-->
<!--</video>-->
<!--<img class="play" src="@/assets/play.png"/>-->
<!--</div>-->
<!--<div v-else class="other">-->
<!--<div class="name">{{ item.name }}</div>-->
<!--<div class="key">{{ item.fileKey }}</div>-->
<!--<div class="info">-->
<!--文件类型{{ item.fileType }} 文件大小{{-->
<!--((item.fileSize * 1.0) / (1024 * 1024)).toFixed(2)-->
<!--}}-->
<!--MB 创建时间{{ item.createTime }}-->
<!--</div>-->
<!--</div>-->
<!--<div class="actions">-->
<!--<div class="btn">-->
<!--<Tooltip content="下载" placement="top">-->
<!--<Icon-->
<!--size="16"-->
<!--type="md-download"-->
<!--@click="download(item)"-->
<!--/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--<div class="btn">-->
<!--<Tooltip content="重命名" placement="top">-->
<!--<Icon size="16" type="md-create" @click="rename(item)"/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--<div class="btn-no">-->
<!--<Tooltip content="删除" placement="top">-->
<!--<Icon size="16" type="md-trash" @click="remove(item)"/>-->
<!--</Tooltip>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--</Card>-->
<!--</div>-->
<!--</div>-->
<!--<Row class="mt_10" justify="end" type="flex">-->
<!--<Page-->
<!--:current="searchForm.pageNumber"-->
<!--:page-size="searchForm.pageSize"-->
<!--:page-size-opts="pageSizeOpts"-->
<!--:total="total"-->
<!--show-elevator-->
<!--show-sizer-->
<!--show-total-->
<!--size="small"-->
<!--@on-change="changePage"-->
<!--@on-page-size-change="changePageSize"-->
<!--&gt;</Page>-->
<!--</Row>-->
</el-card> </el-card>
</el-row> </el-row>
<el-dialog <el-dialog
@@ -488,7 +325,7 @@ import {
import DPlayer from "dplayer"; import DPlayer from "dplayer";
import {commonUrl} from "@/libs/axios"; import {commonUrl} from "@/libs/axios";
const config = require("@/config/index"); import config from "@/config/index";
let dp; let dp;
export default { export default {
@@ -553,14 +390,14 @@ export default {
picTitle: "", // 图片title picTitle: "", // 图片title
videoTitle: "", // 视频title videoTitle: "", // 视频title
modalTitle: "", // 添加或编辑标题 modalTitle: "", // 添加或编辑标题
activeRoleTab: "MANAGER", activeRoleTab: "STORE",
searchForm: { searchForm: {
// 搜索框对应data对象 // 搜索框对应data对象
name: "", name: "",
fileKey: "", fileKey: "",
fileType: "", fileType: "",
fileCategory: "", fileCategory: "",
userEnums: "MANAGER", userEnums: "STORE",
pageNumber: 1, // 当前页数 pageNumber: 1, // 当前页数
pageSize: 20, // 页面大小 pageSize: 20, // 页面大小
sort: "createTime", // 默认排序字段 sort: "createTime", // 默认排序字段
@@ -585,342 +422,6 @@ export default {
selectList: [], // 多选数据 selectList: [], // 多选数据
selectCount: 0, // 多选计数 selectCount: 0, // 多选计数
totalSize: "", // 文件大小统计 totalSize: "", // 文件大小统计
columns: [
// 表头
{
type: "selection",
width: 60,
align: "center",
},
{
title: "缩略图(点击预览)",
key: "url",
width: 300,
align: "center",
render: (h, params) => {
if (this.isImageFile(params.row)) {
return h("img", {
attrs: {
src: params.row.url || "",
alt: "加载图片失败",
},
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showPic(params.row);
},
},
});
} else if (this.isVideoFile(params.row)) {
// 如果视频文件大小超过5MB不予加载video
if (params.row.fileSize < 1024 * 1024 * 5) {
return h(
"video",
{
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showVideo(params.row);
},
},
},
[
h("source", {
attrs: {
src: params.row.url,
},
}),
]
);
} else {
return h("img", {
attrs: {
src: require("@/assets/play.png"),
},
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showVideo(params.row);
},
},
});
}
} else {
return h("span", "非多媒体类型");
}
},
},
{
title: "文件类型",
key: "fileType",
width: 115,
className: this.selectImage == true ? "none" : "",
},
{
title: "文件大小",
key: "fileSize",
width: 115,
sortable: true,
className: this.selectImage == true ? "none" : "",
render: (h, params) => {
let m =
((params.row.fileSize * 1.0) / (1024 * 1024)).toFixed(2) + " MB";
return h("span", m);
},
},
{
title: "上传者",
key: "createBy",
width: 200,
render: (h, params) => {
let m = "";
if (params.row.userEnums == "MANAGER") {
m = "[管理员]";
} else if (params.row.userEnums == "STORE") {
m = "[商家]";
} else if (params.row.userEnums == "CUSTOMER") {
m = "[客服]";
} else {
m = "[用户]";
}
m += params.row.createBy;
return h("span", m);
},
},
{
title: "操作",
key: "action",
align: "center",
fixed: "right",
// width: 300,
render: (h, params) => {
return h("div", [
h(
"a",
{
style: {
color: "#2d8cf0",
cursor: "pointer",
textDecoration: "none",
marginRight: "5px",
display: this.selectImage === true ? "inline-block" : "none",
},
on: {
click: () => {
this.selectedParams(params.row);
},
},
},
"选择"
),
h(
"span",
{
style: {
margin: "0 8px",
color: "#dcdee2",
display: this.selectImage === true ? "inline-block" : "none",
},
},
"|"
),
h(
"a",
{
style: {
color: "#2d8cf0",
cursor: "pointer",
textDecoration: "none",
marginRight: "5px",
display: this.selectImage == true ? "none" : "inline-block",
},
on: {
click: () => {
this.download(params.row);
},
},
},
"下载"
),
h(
"span",
{
style: {
margin: "0 8px",
color: "#dcdee2",
display: this.selectImage == true ? "none" : "inline-block",
},
},
"|"
),
h(
"a",
{
style: {
color: "#2d8cf0",
cursor: "pointer",
textDecoration: "none",
display: this.selectImage == true ? "none" : "inline-block",
},
on: {
click: () => {
this.remove(params.row);
},
},
},
"删除"
),
]);
},
},
],
viewColumns: [
{
title: "缩略图(点击预览)",
key: "url",
// width: 150,
align: "center",
render: (h, params) => {
if (this.isImageFile(params.row)) {
return h("img", {
attrs: {
src: params.row.url || "",
alt: "加载图片失败",
},
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showPic(params.row);
},
},
});
} else if (this.isVideoFile(params.row)) {
// 如果视频文件大小超过5MB不予加载video
if (params.row.fileSize < 1024 * 1024 * 5) {
return h(
"video",
{
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showVideo(params.row);
},
},
},
[
h("source", {
attrs: {
src: params.row.url,
},
}),
]
);
} else {
return h("img", {
attrs: {
src: require("@/assets/play.png"),
},
style: {
cursor: "pointer",
width: "80px",
height: "60px",
margin: "10px 0",
"object-fit": "contain",
},
on: {
click: () => {
this.showVideo(params.row);
},
},
});
}
} else {
return h("span", "非多媒体类型");
}
},
},
{
title: "上传者",
key: "createBy",
width: 120,
sortable: true,
render: (h, params) => {
let m = "";
if (params.row.userEnums == "MANAGER") {
m = "[管理员]";
} else if (params.row.userEnums == "STORE") {
m = "[商家]";
} else if (params.row.userEnums == "CUSTOMER") {
m = "[客服]";
} else {
m = "[用户]";
}
m += params.row.createBy;
return h("span", m);
},
},
{
title: "操作",
key: "action",
align: "center",
fixed: "right",
width: 300,
render: (h, params) => {
return h("div", [
h(
"Button",
{
props: {
type: "default",
size: "small",
},
style: {
marginRight: "5px",
display:
this.selectImage === true ? "inline-block" : "none",
},
on: {
click: () => {
this.selectedParams(params.row);
},
},
},
"选择"
)
]);
},
},
],
data: [], // 表单数据 data: [], // 表单数据
total: 0, // 表单数据总数 total: 0, // 表单数据总数
pageSizeOpts: [5, 10, 20], // 页码展示项 pageSizeOpts: [5, 10, 20], // 页码展示项
@@ -933,41 +434,6 @@ export default {
groupLoading: false, groupLoading: false,
// 图片列表 // 图片列表
selectedOss: [], selectedOss: [],
myData: [
{
title: 'parent 1',
expand: true,
render: (h, {root, node, data}) => {
return h('span', {style: {display: 'inline-block', width: '100%'}}, [
h('span', [h("Icon", {type: 'ios-folder-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '32px'}},
[h("Button", {
...this.buttonProps,
icon: 'ios-add',
type: 'primary',
style: {width: '64px'},
onClick: () => {
this.append(data)
}
})
])
]);
},
children: [
{
title: 'child 1-1',
expand: true,
children: [{title: 'leaf 1-1-1', expand: true}, {title: 'leaf 1-1-2', expand: true}]
},
{
title: 'child 1-2',
expand: true,
children: [{title: 'leaf 1-2-1', expand: true}, {title: 'leaf 1-2-1', expand: true}]
}
]
}
],
buttonProps: {type: 'default', size: 'small',},
}; };
}, },
watch: { watch: {
@@ -999,7 +465,7 @@ export default {
return this.activeRoleTab === "MANAGER"; return this.activeRoleTab === "MANAGER";
}, },
canUploadImages() { canUploadImages() {
return this.activeRoleTab === "MANAGER"; return this.activeRoleTab === "MANAGER" || this.activeRoleTab === "STORE";
}, },
uploadData() { uploadData() {
return { return {
@@ -1125,61 +591,8 @@ export default {
this.searchForm.pageNumber = value; this.searchForm.pageNumber = value;
this.getDataList(); this.getDataList();
}, },
// 自定义tree节点显示内容和交互
renderContent(h, {root, node, data}) {
if (data.value === '0') {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}}, [])
]
);
} else {
return h('span', {style: {display: 'inline-block', width: '100%'}},
[
h('span', [h("Icon", {type: 'ios-paper-outline', style: {marginRight: '8px'}}), h('span', data.title)]),
h('span', {style: {display: 'inline-block', float: 'right', marginRight: '10px'}},
[
h("Dropdown", {style: {marginLeft: "4px"}},
[
h("Icon", {
props: {type: 'ios-more', size: "20",},
style: {display: 'inline-block'},
on: {
click: () => {
}
}
}),
h("DropdownMenu", {
slot: "list"
}, [
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuEdit(root, node, data)
}
}
}, "编辑"),
h("DropdownItem", {
nativeOn: {
click: () => {
this.handleContextMenuDelete()
}
}
}, "删除"),
])
]),
])
]
);
}
},
handleContextMenu(val) { handleContextMenu(val) {
console.log('handleContextMenu', val); this.selectedGroupData = val;
this.selectedGroupData = val;
}, },
// 编辑分组 // 编辑分组
handleContextMenuEdit(root, node, data) { handleContextMenuEdit(root, node, data) {