feat(splash): 添加全局开屏图片功能并优化客户端启动流程
- 新增全局开屏图片上传、获取、删除接口 - 实现客户端全局开屏图片优先加载机制 - 集成七牛云存储配置从 pxdj 切换到 bydj - 优化 splash 窗口显示逻辑确保至少显示 2 秒 - 添加全局开屏图片管理界面组件 - 更新应用配置和构建设置 - 修复多处图片缓存和加载问题 - 调整服务端 API 地址配置 - 修改微信客服联系方式
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
<div align="center">
|
||||
|
||||
# Electron Vue Template
|
||||
|
||||
<img width="794" alt="image" src="https://user-images.githubusercontent.com/32544586/222748627-ee10c9a6-70d2-4e21-b23f-001dd8ec7238.png">
|
||||
|
||||
A simple starter template for a **Vue3** + **Electron** TypeScript based application, including **ViteJS** and **Electron Builder**.
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
This template utilizes [ViteJS](https://vitejs.dev) for building and serving your (Vue powered) front-end process, it provides Hot Reloads (HMR) to make development fast and easy ⚡
|
||||
|
||||
Building the Electron (main) process is done with [Electron Builder](https://www.electron.build/), which makes your application easily distributable and supports cross-platform compilation 😎
|
||||
|
||||
## Getting started
|
||||
|
||||
Click the green **Use this template** button on top of the repository, and clone your own newly created repository.
|
||||
|
||||
**Or..**
|
||||
|
||||
Clone this repository: `git clone git@github.com:Deluze/electron-vue-template.git`
|
||||
|
||||
|
||||
### Install dependencies ⏬
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Start developing ⚒️
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Additional Commands
|
||||
|
||||
```bash
|
||||
npm run dev # starts application with hot reload
|
||||
npm run build # builds application, distributable files can be found in "dist" folder
|
||||
|
||||
# OR
|
||||
|
||||
npm run build:win # uses windows as build target
|
||||
npm run build:mac # uses mac as build target
|
||||
npm run build:linux # uses linux as build target
|
||||
```
|
||||
|
||||
Optional configuration options can be found in the [Electron Builder CLI docs](https://www.electron.build/cli.html).
|
||||
## Project Structure
|
||||
|
||||
```bash
|
||||
- scripts/ # all the scripts used to build or serve your application, change as you like.
|
||||
- src/
|
||||
- main/ # Main thread (Electron application source)
|
||||
- renderer/ # Renderer thread (VueJS application source)
|
||||
```
|
||||
|
||||
## Using static files
|
||||
|
||||
If you have any files that you want to copy over to the app directory after installation, you will need to add those files in your `src/main/static` directory.
|
||||
|
||||
Files in said directory are only accessible to the `main` process, similar to `src/renderer/assets` only being accessible to the `renderer` process. Besides that, the concept is the same as to what you're used to in your other front-end projects.
|
||||
|
||||
#### Referencing static files from your main process
|
||||
|
||||
```ts
|
||||
/* Assumes src/main/static/myFile.txt exists */
|
||||
|
||||
import {app} from 'electron';
|
||||
import {join} from 'path';
|
||||
import {readFileSync} from 'fs';
|
||||
|
||||
const path = join(app.getAppPath(), 'static', 'myFile.txt');
|
||||
const buffer = readFileSync(path);
|
||||
```
|
||||
7281
electron-vue-template/package-lock.json
generated
Normal file
7281
electron-vue-template/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
"name": "erpClient",
|
||||
"version": "0.1.0",
|
||||
"description": "A minimal Electron + Vue application",
|
||||
"main": "main/main.js",
|
||||
"main": "build/main/main.js",
|
||||
"scripts": {
|
||||
"dev": "node scripts/dev-server.js",
|
||||
"build": "node scripts/build.js && electron-builder --dir",
|
||||
@@ -17,6 +17,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.4.1",
|
||||
"binary-extensions": "^3.1.0",
|
||||
"chalk": "^4.1.2",
|
||||
"chokidar": "^3.5.3",
|
||||
"electron": "^32.1.2",
|
||||
@@ -32,5 +33,26 @@
|
||||
"element-plus": "^2.11.3",
|
||||
"exceljs": "^4.4.0",
|
||||
"vue": "^3.3.8"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.tashow.erp",
|
||||
"productName": "天骄智能电商",
|
||||
"files": [
|
||||
"build/**/*",
|
||||
"node_modules/**/*",
|
||||
"package.json"
|
||||
],
|
||||
"directories": {
|
||||
"buildResources": "assets",
|
||||
"output": "dist"
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "dir",
|
||||
"arch": ["x64"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4417
electron-vue-template/pnpm-lock.yaml
generated
Normal file
4417
electron-vue-template/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ let springProcess: ChildProcess | null = null;
|
||||
let mainWindow: BrowserWindow | null = null;
|
||||
let splashWindow: BrowserWindow | null = null;
|
||||
let appOpened = false;
|
||||
let splashStartTime = 0; // 记录 splash 窗口显示时间
|
||||
let downloadProgress = {percentage: 0, current: '0 MB', total: '0 MB'};
|
||||
let isDownloading = false;
|
||||
let downloadedFilePath: string | null = null;
|
||||
@@ -24,8 +25,9 @@ function openAppIfNotOpened() {
|
||||
return;
|
||||
}
|
||||
appOpened = true;
|
||||
const url = `http://localhost:${process.argv[2] || 8083}`;
|
||||
isDev
|
||||
? mainWindow.loadURL(`http://localhost:${process.argv[2] || 8083}`)
|
||||
? mainWindow.loadURL(url)
|
||||
: mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
|
||||
|
||||
mainWindow.webContents.once('did-finish-load', () => {
|
||||
@@ -33,7 +35,11 @@ function openAppIfNotOpened() {
|
||||
splashWindow.webContents.send('splash-complete');
|
||||
}
|
||||
|
||||
// 先显示主窗口,再关闭splash,避免白屏
|
||||
// 计算 splash 已显示的时间,确保至少显示 2 秒
|
||||
const splashElapsed = Date.now() - splashStartTime;
|
||||
const minSplashTime = 2000;
|
||||
const remainingTime = Math.max(0, minSplashTime - splashElapsed);
|
||||
|
||||
setTimeout(() => {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
const shouldMinimize = loadConfig().launchMinimized || false;
|
||||
@@ -41,17 +47,16 @@ function openAppIfNotOpened() {
|
||||
mainWindow.show();
|
||||
mainWindow.focus();
|
||||
}
|
||||
if (isDev) mainWindow.webContents.openDevTools();
|
||||
}
|
||||
|
||||
// 延迟关闭splash,确保主窗口已显示
|
||||
// 延迟关闭 splash
|
||||
setTimeout(() => {
|
||||
if (splashWindow && !splashWindow.isDestroyed()) {
|
||||
splashWindow.close();
|
||||
splashWindow = null;
|
||||
}
|
||||
}, 100);
|
||||
}, 200);
|
||||
}, remainingTime + 200);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,31 +98,34 @@ const getImageCacheDir = () => {
|
||||
};
|
||||
|
||||
// 下载图片到本地
|
||||
async function downloadImageToLocal(imageUrl: string, username: string, type: 'splash' | 'logo'): Promise<void> {
|
||||
async function downloadImageToLocal(imageUrl: string, username: string, type: 'splash' | 'logo' | 'global_splash'): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const protocol = imageUrl.startsWith('https') ? https : http;
|
||||
protocol.get(imageUrl, (res) => {
|
||||
const handleResponse = (res: http.IncomingMessage) => {
|
||||
if (res.statusCode !== 200) return resolve();
|
||||
const chunks: Buffer[] = [];
|
||||
res.on('data', (chunk) => chunks.push(chunk));
|
||||
res.on('end', () => {
|
||||
const buffer = Buffer.concat(chunks);
|
||||
const ext = imageUrl.match(/\.(jpg|jpeg|png|gif|webp)$/i)?.[1] || 'png';
|
||||
const filepath = join(getImageCacheDir(), `${username}_${type}.${ext}`);
|
||||
const filename = type === 'global_splash' ? `global_splash.${ext}` : `${username}_${type}.${ext}`;
|
||||
const filepath = join(getImageCacheDir(), filename);
|
||||
writeFileSync(filepath, buffer);
|
||||
console.log(`[图片缓存] 已保存: ${username}_${type}.${ext}`);
|
||||
console.log(`[图片缓存] 已保存: ${filename}`);
|
||||
resolve();
|
||||
});
|
||||
res.on('error', () => resolve());
|
||||
}).on('error', () => resolve());
|
||||
};
|
||||
const req = imageUrl.startsWith('https') ? https.get(imageUrl, handleResponse) : http.get(imageUrl, handleResponse);
|
||||
req.on('error', () => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
// 加载本地缓存图片
|
||||
function loadCachedImage(username: string, type: 'splash' | 'logo'): string | null {
|
||||
function loadCachedImage(username: string, type: 'splash' | 'logo' | 'global_splash'): string | null {
|
||||
try {
|
||||
const files = readdirSync(getImageCacheDir());
|
||||
const file = files.find(f => f.startsWith(`${username}_${type}.`));
|
||||
const prefix = type === 'global_splash' ? 'global_splash.' : `${username}_${type}.`;
|
||||
const file = files.find(f => f.startsWith(prefix));
|
||||
if (file) {
|
||||
const buffer = readFileSync(join(getImageCacheDir(), file));
|
||||
const ext = extname(file).slice(1);
|
||||
@@ -129,10 +137,11 @@ function loadCachedImage(username: string, type: 'splash' | 'logo'): string | nu
|
||||
}
|
||||
|
||||
// 删除本地缓存图片
|
||||
function deleteCachedImage(username: string, type: 'splash' | 'logo'): void {
|
||||
function deleteCachedImage(username: string, type: 'splash' | 'logo' | 'global_splash'): void {
|
||||
try {
|
||||
const files = readdirSync(getImageCacheDir());
|
||||
const file = files.find(f => f.startsWith(`${username}_${type}.`));
|
||||
const prefix = type === 'global_splash' ? 'global_splash.' : `${username}_${type}.`;
|
||||
const file = files.find(f => f.startsWith(prefix));
|
||||
if (file) {
|
||||
const filepath = join(getImageCacheDir(), file);
|
||||
if (existsSync(filepath)) {
|
||||
@@ -143,6 +152,66 @@ function deleteCachedImage(username: string, type: 'splash' | 'logo'): void {
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
// 从服务器同步获取全局开屏图片URL(带超时)
|
||||
async function fetchGlobalSplashImageUrl(): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
const config = loadConfig();
|
||||
const serverUrl = config.serverUrl || 'http://8.138.23.49:8085';
|
||||
const url = `${serverUrl}/monitor/account/global-splash-image`;
|
||||
|
||||
const handleResponse = (res: http.IncomingMessage) => {
|
||||
if (res.statusCode !== 200) return resolve(null);
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
resolve(json.code === 200 && json.data?.url ? json.data.url : null);
|
||||
} catch {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
res.on('error', () => resolve(null));
|
||||
};
|
||||
|
||||
const req = url.startsWith('https') ? https.get(url, handleResponse) : http.get(url, handleResponse);
|
||||
req.on('error', () => resolve(null));
|
||||
req.setTimeout(3000, () => {
|
||||
req.destroy();
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 从远程URL下载图片并转为base64
|
||||
async function downloadImageAsBase64(imageUrl: string): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
const handleResponse = (res: http.IncomingMessage) => {
|
||||
if (res.statusCode !== 200) return resolve(null);
|
||||
const chunks: Buffer[] = [];
|
||||
res.on('data', (chunk) => chunks.push(chunk));
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const buffer = Buffer.concat(chunks);
|
||||
const ext = imageUrl.match(/\.(jpg|jpeg|png|gif|webp)$/i)?.[1] || 'png';
|
||||
const mime = { jpg: 'jpeg', jpeg: 'jpeg', png: 'png', gif: 'gif', webp: 'webp' }[ext] || 'png';
|
||||
resolve(`url('data:image/${mime};base64,${buffer.toString('base64')}')`);
|
||||
} catch {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
res.on('error', () => resolve(null));
|
||||
};
|
||||
|
||||
const req = imageUrl.startsWith('https') ? https.get(imageUrl, handleResponse) : http.get(imageUrl, handleResponse);
|
||||
req.on('error', () => resolve(null));
|
||||
req.setTimeout(5000, () => {
|
||||
req.destroy();
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取默认开屏图片
|
||||
function getDefaultSplashImage(): string {
|
||||
const path = getResourcePath('../../public/image/splash_screen.png', 'public/image/splash_screen.png');
|
||||
@@ -179,6 +248,7 @@ interface AppConfig {
|
||||
lastUsername?: string;
|
||||
splashImageUrl?: string;
|
||||
brandLogoUrl?: string;
|
||||
serverUrl?: string;
|
||||
}
|
||||
|
||||
function getConfigPath(): string {
|
||||
@@ -246,11 +316,10 @@ function startSpringBoot() {
|
||||
springProcess = spawn(javaPath, springArgs, {
|
||||
cwd: dataDir,
|
||||
detached: false,
|
||||
stdio: 'ignore'
|
||||
stdio: 'ignore',
|
||||
windowsHide: true
|
||||
});
|
||||
|
||||
let startupCompleted = false;
|
||||
|
||||
springProcess.on('close', () => mainWindow ? mainWindow.close() : app.quit());
|
||||
springProcess.on('error', (error) => {
|
||||
dialog.showErrorBox('启动失败', error.message.includes('ENOENT')
|
||||
@@ -388,7 +457,7 @@ if (!gotTheLock) {
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
app.whenReady().then(async () => {
|
||||
if (!isDev) {
|
||||
protocol.interceptFileProtocol('file', (request, callback) => {
|
||||
// 使用 fileURLToPath 正确解码 URL,处理空格和特殊字符
|
||||
@@ -436,17 +505,50 @@ app.whenReady().then(() => {
|
||||
if (!shouldMinimize) {
|
||||
const config = loadConfig();
|
||||
const username = config.lastUsername || '';
|
||||
const imageUrl = config.splashImageUrl || '';
|
||||
const userSplashUrl = config.splashImageUrl || '';
|
||||
|
||||
// 图片加载:本地缓存 > 默认图片
|
||||
let splashImage = (imageUrl && username && loadCachedImage(username, 'splash')) || getDefaultSplashImage();
|
||||
let splashImage: string | null = null;
|
||||
|
||||
// 如果有URL但缓存不存在,后台下载
|
||||
if (imageUrl && username && !loadCachedImage(username, 'splash')) {
|
||||
downloadImageToLocal(imageUrl, username, 'splash');
|
||||
// 开屏图片加载优先级:全局图片(实时) > 用户自定义图片 > 默认本地图片
|
||||
console.log('[开屏图片] 开始获取全局开屏图片...');
|
||||
|
||||
// 1. 获取全局开屏图片
|
||||
const globalUrl = await fetchGlobalSplashImageUrl();
|
||||
if (globalUrl) {
|
||||
console.log('[开屏图片] 获取到全局图片URL:', globalUrl);
|
||||
splashImage = await downloadImageAsBase64(globalUrl);
|
||||
if (splashImage) {
|
||||
console.log('[开屏图片] 使用实时全局图片');
|
||||
downloadImageToLocal(globalUrl, '', 'global_splash').catch(() => {});
|
||||
} else {
|
||||
splashImage = loadCachedImage('', 'global_splash');
|
||||
}
|
||||
} else {
|
||||
splashImage = loadCachedImage('', 'global_splash');
|
||||
}
|
||||
|
||||
// 2. 如果没有全局图片,尝试用户自定义图片
|
||||
if (!splashImage && userSplashUrl && username) {
|
||||
console.log('[开屏图片] 使用用户自定义图片');
|
||||
splashImage = loadCachedImage(username, 'splash');
|
||||
if (!splashImage) {
|
||||
downloadImageToLocal(userSplashUrl, username, 'splash').catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 使用默认本地图片
|
||||
if (!splashImage) {
|
||||
console.log('[开屏图片] 使用默认本地图片');
|
||||
splashImage = getDefaultSplashImage();
|
||||
}
|
||||
|
||||
// 将图片数据写入临时文件,避免 data URL 过长
|
||||
const tempSplashPath = join(app.getPath('temp'), 'splash-temp.html');
|
||||
const splashHtml = readFileSync(getSplashPath(), 'utf-8').replace('__SPLASH_IMAGE__', splashImage);
|
||||
writeFileSync(tempSplashPath, splashHtml);
|
||||
|
||||
// 记录 splash 显示时间
|
||||
splashStartTime = Date.now();
|
||||
|
||||
splashWindow = new BrowserWindow({
|
||||
width: 1200,
|
||||
@@ -454,8 +556,8 @@ app.whenReady().then(() => {
|
||||
frame: false,
|
||||
transparent: false,
|
||||
resizable: false,
|
||||
alwaysOnTop: false,
|
||||
show: false,
|
||||
alwaysOnTop: true, // 设置为置顶,确保在主窗口之上
|
||||
show: false, // 创建时不显示,等待内容加载完成
|
||||
center: true,
|
||||
icon: getIconPath(),
|
||||
backgroundColor: '#ffffff',
|
||||
@@ -466,15 +568,24 @@ app.whenReady().then(() => {
|
||||
});
|
||||
|
||||
splashWindow.on('closed', () => splashWindow = null);
|
||||
// 加载预注入的 HTML(图片已base64内联,无跨域问题)
|
||||
splashWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(splashHtml)}`);
|
||||
splashWindow.once('ready-to-show', () => splashWindow?.show());
|
||||
|
||||
// 监听页面加载完成后显示
|
||||
splashWindow.webContents.on('did-finish-load', () => {
|
||||
setTimeout(() => {
|
||||
if (splashWindow && !splashWindow.isDestroyed()) {
|
||||
splashWindow.show();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
|
||||
// 加载临时 HTML 文件
|
||||
splashWindow.loadFile(tempSplashPath);
|
||||
}
|
||||
|
||||
// 已手动启动后端
|
||||
// setTimeout(() => {
|
||||
// startSpringBoot();
|
||||
// }, 200);
|
||||
setTimeout(() => {
|
||||
startSpringBoot();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
openAppIfNotOpened();
|
||||
@@ -955,9 +1066,7 @@ ipcMain.handle('load-config', () => {
|
||||
|
||||
async function getFileSize(url: string): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
const protocol = url.startsWith('https') ? https : http;
|
||||
|
||||
const request = protocol.get(url, {method: 'HEAD'}, (response) => {
|
||||
const handleResponse = (response: http.IncomingMessage) => {
|
||||
if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 307) {
|
||||
const redirectUrl = response.headers.location;
|
||||
if (redirectUrl) {
|
||||
@@ -965,11 +1074,16 @@ async function getFileSize(url: string): Promise<number> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const size = parseInt(response.headers['content-length'] || '0', 10);
|
||||
resolve(size);
|
||||
}).on('error', () => resolve(0));
|
||||
|
||||
};
|
||||
|
||||
const request = url.startsWith('https')
|
||||
? https.get(url, {method: 'HEAD'}, handleResponse)
|
||||
: http.get(url, {method: 'HEAD'}, handleResponse);
|
||||
|
||||
request.on('error', () => resolve(0));
|
||||
request.setTimeout(10000, () => {
|
||||
request.destroy();
|
||||
resolve(0);
|
||||
@@ -979,9 +1093,9 @@ async function getFileSize(url: string): Promise<number> {
|
||||
|
||||
async function downloadFile(url: string, filePath: string, onProgress: (progress: {downloaded: number, total: number}) => void): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const protocol = url.startsWith('https') ? https : http;
|
||||
let request: http.ClientRequest;
|
||||
|
||||
const request = protocol.get(url, (response) => {
|
||||
const handleResponse = (response: http.IncomingMessage) => {
|
||||
if (response.statusCode === 301 || response.statusCode === 302 || response.statusCode === 307) {
|
||||
const redirectUrl = response.headers.location;
|
||||
if (redirectUrl) {
|
||||
@@ -989,7 +1103,7 @@ async function downloadFile(url: string, filePath: string, onProgress: (progress
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${response.statusCode}`));
|
||||
return;
|
||||
@@ -1024,7 +1138,12 @@ async function downloadFile(url: string, filePath: string, onProgress: (progress
|
||||
fs.unlink(filePath).catch(() => {});
|
||||
reject(error);
|
||||
});
|
||||
};
|
||||
|
||||
}).on('error', reject);
|
||||
request = url.startsWith('https')
|
||||
? https.get(url, handleResponse)
|
||||
: http.get(url, handleResponse);
|
||||
|
||||
request.on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -656,8 +656,8 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="brandLogoUrl" class="brand-logo-section">
|
||||
<img :src="brandLogoUrl" alt="品牌 Banner" class="brand-logo"/>
|
||||
<div class="brand-logo-section">
|
||||
<img src="https://qiniu.bydj.tashowz.com/brand-logo/2026/01/4bfd767a56a54351a6db284563b4f83d.png" alt="品牌 Banner" class="brand-logo"/>
|
||||
</div>
|
||||
|
||||
<div class="menu-group-title">电商平台</div>
|
||||
|
||||
@@ -45,6 +45,11 @@ export const splashApi = {
|
||||
// 删除品牌logo
|
||||
async deleteBrandLogo(username: string) {
|
||||
return http.post<{ data: string }>(`/monitor/account/brand-logo/delete?username=${username}`)
|
||||
},
|
||||
|
||||
// 获取全局开屏图片
|
||||
async getGlobalSplashImage() {
|
||||
return http.get<{ data: { url: string } }>('/monitor/account/global-splash-image')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -607,12 +607,14 @@ onMounted(() => {
|
||||
<span class="sidebar-text">启动</span>
|
||||
</div>
|
||||
<div
|
||||
v-show="false"
|
||||
:class="['sidebar-item', { active: activeTab === 'splash' }]"
|
||||
@click="scrollToSection('splash')">
|
||||
<span class="sidebar-icon">🖼️</span>
|
||||
<span class="sidebar-text">开屏图片</span>
|
||||
</div>
|
||||
<div
|
||||
v-show="false"
|
||||
:class="['sidebar-item', { active: activeTab === 'brand' }]"
|
||||
@click="scrollToSection('brand')">
|
||||
<span class="sidebar-icon">🏷️</span>
|
||||
@@ -754,8 +756,8 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 开屏图片设置 -->
|
||||
<div id="section-splash" class="setting-section" @mouseenter="activeTab = 'splash'">
|
||||
<!-- 开屏图片设置 (暂时隐藏) -->
|
||||
<div id="section-splash" class="setting-section" @mouseenter="activeTab = 'splash'" style="display: none;">
|
||||
<div class="section-title-row">
|
||||
<div class="section-title">开屏图片</div>
|
||||
<img src="/icon/vipExclusive.png" alt="VIP专享" class="vip-exclusive-logo" />
|
||||
@@ -785,8 +787,8 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 品牌logo页面 -->
|
||||
<div id="section-brand" class="setting-section" @mouseenter="activeTab = 'brand'">
|
||||
<!-- 品牌logo页面 (暂时隐藏) -->
|
||||
<div id="section-brand" class="setting-section" @mouseenter="activeTab = 'brand'" style="display: none;">
|
||||
<div class="section-title-row">
|
||||
<div class="section-title">品牌 Banner</div>
|
||||
<img src="/icon/vipExclusive.png" alt="VIP专享" class="vip-exclusive-logo" />
|
||||
|
||||
@@ -38,7 +38,7 @@ function handleConfirm() {
|
||||
}
|
||||
|
||||
function copyWechat() {
|
||||
navigator.clipboard.writeText('_linhong').then(() => {
|
||||
navigator.clipboard.writeText('butaihaoba001').then(() => {
|
||||
ElMessage.success('微信号已复制')
|
||||
}).catch(() => {
|
||||
ElMessage.error('复制失败,请手动复制')
|
||||
@@ -75,7 +75,7 @@ function copyWechat() {
|
||||
</div>
|
||||
<div class="wechat-info">
|
||||
<div class="wechat-label">客服微信</div>
|
||||
<div class="wechat-id">_linhong</div>
|
||||
<div class="wechat-id">butaihaoba001</div>
|
||||
</div>
|
||||
<div class="copy-icon">📋</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
export const AppConfig = {
|
||||
CLIENT_BASE: 'http://localhost:8081',
|
||||
RUOYI_BASE: 'http://192.168.1.89:8085',
|
||||
RUOYI_BASE: 'http://8.138.23.49:8085',
|
||||
get SSE_URL() {
|
||||
return `${this.RUOYI_BASE}/monitor/account/events`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user