1
This commit is contained in:
@@ -6,7 +6,10 @@
|
|||||||
},
|
},
|
||||||
"compression": "maximum",
|
"compression": "maximum",
|
||||||
"asarUnpack": [
|
"asarUnpack": [
|
||||||
"public/**/*"
|
"public/jre/**/*",
|
||||||
|
"public/icon/**/*",
|
||||||
|
"public/image/**/*",
|
||||||
|
"public/splash.html"
|
||||||
],
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"output": "dist"
|
"output": "dist"
|
||||||
@@ -40,15 +43,28 @@
|
|||||||
"filter": ["**/*"]
|
"filter": ["**/*"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
||||||
"from": "src/main/static",
|
"from": "src/main/static",
|
||||||
"to": "static",
|
"to": "static",
|
||||||
"filter": ["**/*"]
|
"filter": ["**/*"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"from": "public",
|
||||||
|
"to": "assets",
|
||||||
|
"filter": [
|
||||||
|
"erp_client_sb-*.jar"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"from": "public",
|
"from": "public",
|
||||||
"to": "public",
|
"to": "public",
|
||||||
"filter": [
|
"filter": [
|
||||||
"**/*",
|
"jre/**/*",
|
||||||
|
"icon/**/*",
|
||||||
|
"image/**/*",
|
||||||
|
"splash.html",
|
||||||
|
"!erp_client_sb-*.jar",
|
||||||
|
"!data/**/*",
|
||||||
"!jre/bin/jabswitch.exe",
|
"!jre/bin/jabswitch.exe",
|
||||||
"!jre/bin/jaccessinspector.exe",
|
"!jre/bin/jaccessinspector.exe",
|
||||||
"!jre/bin/jaccesswalker.exe",
|
"!jre/bin/jaccesswalker.exe",
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
import {app, BrowserWindow, ipcMain, Menu, screen, dialog} from 'electron';
|
import {app, BrowserWindow, ipcMain, Menu, screen, dialog} from 'electron';
|
||||||
import {existsSync, createWriteStream, promises as fs} from 'fs';
|
import {existsSync, createWriteStream, promises as fs, mkdirSync, copyFileSync} from 'fs';
|
||||||
import {join, dirname} from 'path';
|
import {join, dirname} from 'path';
|
||||||
import {spawn, ChildProcess} from 'child_process';
|
import {spawn, ChildProcess} from 'child_process';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
|
|
||||||
let springProcess: ChildProcess | null = null;
|
let springProcess: ChildProcess | null = null;
|
||||||
let mainWindow: BrowserWindow | null = null;
|
let mainWindow: BrowserWindow | null = null;
|
||||||
let splashWindow: BrowserWindow | null = null;
|
let splashWindow: BrowserWindow | null = null;
|
||||||
let appOpened = false;
|
let appOpened = false;
|
||||||
|
|
||||||
let downloadProgress = {percentage: 0, current: '0 MB', total: '0 MB', speed: ''};
|
let downloadProgress = {percentage: 0, current: '0 MB', total: '0 MB', speed: ''};
|
||||||
let isDownloading = false;
|
let isDownloading = false;
|
||||||
let downloadedFilePath: string | null = null;
|
let downloadedFilePath: string | null = null;
|
||||||
|
|
||||||
function openAppIfNotOpened() {
|
function openAppIfNotOpened() {
|
||||||
if (appOpened) return;
|
if (appOpened) return;
|
||||||
appOpened = true;
|
appOpened = true;
|
||||||
if (mainWindow) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.once('did-finish-load', () => {
|
mainWindow.webContents.once('did-finish-load', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mainWindow?.show();
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow?.focus();
|
mainWindow.show();
|
||||||
if (splashWindow) {
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安全关闭启动画面
|
||||||
|
if (splashWindow && !splashWindow.isDestroyed()) {
|
||||||
splashWindow.close();
|
splashWindow.close();
|
||||||
splashWindow = null;
|
splashWindow = null;
|
||||||
}
|
}
|
||||||
@@ -61,12 +62,24 @@ function getJarFilePath(): string {
|
|||||||
return join(__dirname, '../../public/erp_client_sb-2.4.7.jar');
|
return join(__dirname, '../../public/erp_client_sb-2.4.7.jar');
|
||||||
}
|
}
|
||||||
|
|
||||||
const bundledJarPath = join(process.resourcesPath, 'app.asar.unpacked/public/erp_client_sb-2.4.7.jar');
|
// 生产环境:需要将JAR包从asar提取到临时位置
|
||||||
if (existsSync(bundledJarPath)) {
|
const tempDir = join(app.getPath('temp'), 'erp-client');
|
||||||
return bundledJarPath;
|
const tempJarPath = join(tempDir, 'erp_client_sb-2.4.7.jar');
|
||||||
|
|
||||||
|
// 确保临时目录存在
|
||||||
|
if (!existsSync(tempDir)) {
|
||||||
|
mkdirSync(tempDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return join(__dirname, '../../public/erp_client_sb-2.4.7.jar');
|
// 如果临时JAR不存在,从asar中复制
|
||||||
|
if (!existsSync(tempJarPath)) {
|
||||||
|
const asarJarPath = join(__dirname, '../assets/erp_client_sb-2.4.7.jar');
|
||||||
|
if (existsSync(asarJarPath)) {
|
||||||
|
copyFileSync(asarJarPath, tempJarPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempJarPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSplashPath(): string {
|
function getSplashPath(): string {
|
||||||
@@ -95,9 +108,48 @@ function getIconPath(): string {
|
|||||||
return join(__dirname, '../renderer/icon/icon.png');
|
return join(__dirname, '../renderer/icon/icon.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDataDirectoryPath(): string {
|
||||||
|
// 将用户数据目录放在可写的应用数据目录下
|
||||||
|
const userDataPath = app.getPath('userData');
|
||||||
|
const dataDir = join(userDataPath, 'data');
|
||||||
|
|
||||||
|
// 确保数据目录存在
|
||||||
|
if (!existsSync(dataDir)) {
|
||||||
|
mkdirSync(dataDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateDataFromPublic(): void {
|
||||||
|
// 如果是首次运行,尝试从public/data迁移数据
|
||||||
|
const oldDataPath = join(__dirname, '../../public/data');
|
||||||
|
const newDataPath = getDataDirectoryPath();
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development' && existsSync(oldDataPath)) {
|
||||||
|
try {
|
||||||
|
const files = require('fs').readdirSync(oldDataPath);
|
||||||
|
for (const file of files) {
|
||||||
|
const srcFile = join(oldDataPath, file);
|
||||||
|
const destFile = join(newDataPath, file);
|
||||||
|
|
||||||
|
if (!existsSync(destFile)) {
|
||||||
|
require('fs').copyFileSync(srcFile, destFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('数据迁移失败,使用默认配置');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function startSpringBoot() {
|
function startSpringBoot() {
|
||||||
|
// 首先迁移数据(如果需要)
|
||||||
|
migrateDataFromPublic();
|
||||||
|
|
||||||
const jarPath = getJarFilePath();
|
const jarPath = getJarFilePath();
|
||||||
const javaPath = getJavaExecutablePath();
|
const javaPath = getJavaExecutablePath();
|
||||||
|
const dataDir = getDataDirectoryPath();
|
||||||
|
|
||||||
if (!existsSync(jarPath)) {
|
if (!existsSync(jarPath)) {
|
||||||
dialog.showErrorBox('启动失败', `JAR 文件不存在:\n${jarPath}`);
|
dialog.showErrorBox('启动失败', `JAR 文件不存在:\n${jarPath}`);
|
||||||
@@ -106,15 +158,31 @@ function startSpringBoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
springProcess = spawn(javaPath, ['-jar', jarPath], {
|
// Spring Boot启动参数配置
|
||||||
cwd: dirname(jarPath),
|
const springArgs = [
|
||||||
detached: false
|
'-jar', jarPath,
|
||||||
|
`--spring.datasource.url=jdbc:sqlite:${dataDir}/erp-cache.db`,
|
||||||
|
`--logging.file.path=${dataDir}`,
|
||||||
|
`--server.port=8081`
|
||||||
|
];
|
||||||
|
|
||||||
|
// 工作目录设为数据目录,这样Spring Boot会在数据目录下创建临时文件
|
||||||
|
springProcess = spawn(javaPath, springArgs, {
|
||||||
|
cwd: dataDir,
|
||||||
|
detached: false,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
'ERP_DATA_DIR': dataDir,
|
||||||
|
'USER_DATA_DIR': dataDir
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let startupCompleted = false;
|
let startupCompleted = false;
|
||||||
|
|
||||||
springProcess.stdout?.on('data', (data) => {
|
springProcess.stdout?.on('data', (data) => {
|
||||||
const output = data.toString();
|
const output = data.toString();
|
||||||
|
console.log('[Spring Boot]', output.trim());
|
||||||
|
|
||||||
if (!startupCompleted && (output.includes('Started Success') || output.includes('Started ErpClientSbApplication'))) {
|
if (!startupCompleted && (output.includes('Started Success') || output.includes('Started ErpClientSbApplication'))) {
|
||||||
startupCompleted = true;
|
startupCompleted = true;
|
||||||
openAppIfNotOpened();
|
openAppIfNotOpened();
|
||||||
@@ -185,6 +253,16 @@ function createWindow() {
|
|||||||
Menu.setApplicationMenu(null);
|
Menu.setApplicationMenu(null);
|
||||||
mainWindow.setMenuBarVisibility(false);
|
mainWindow.setMenuBarVisibility(false);
|
||||||
|
|
||||||
|
// 打开开发者工具
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听窗口关闭事件,确保正确清理引用
|
||||||
|
mainWindow.on('closed', () => {
|
||||||
|
mainWindow = null;
|
||||||
|
});
|
||||||
|
|
||||||
mainWindow.webContents.once('did-finish-load', () => {
|
mainWindow.webContents.once('did-finish-load', () => {
|
||||||
setTimeout(() => checkPendingUpdate(), 500);
|
setTimeout(() => checkPendingUpdate(), 500);
|
||||||
});
|
});
|
||||||
@@ -212,6 +290,11 @@ app.whenReady().then(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听启动窗口关闭事件
|
||||||
|
splashWindow.on('closed', () => {
|
||||||
|
splashWindow = null;
|
||||||
|
});
|
||||||
|
|
||||||
const splashPath = getSplashPath();
|
const splashPath = getSplashPath();
|
||||||
if (existsSync(splashPath)) {
|
if (existsSync(splashPath)) {
|
||||||
splashWindow.loadFile(splashPath);
|
splashWindow.loadFile(splashPath);
|
||||||
@@ -278,31 +361,6 @@ ipcMain.handle('download-update', async (event, downloadUrl: string) => {
|
|||||||
isDownloading = true;
|
isDownloading = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const isRealDev = process.env.NODE_ENV === 'development' && !app.isPackaged;
|
|
||||||
|
|
||||||
if (isRealDev) {
|
|
||||||
for (let i = 0; i <= 100; i += 10) {
|
|
||||||
setTimeout(() => {
|
|
||||||
downloadProgress = {
|
|
||||||
percentage: i,
|
|
||||||
current: (i * 0.5).toFixed(1) + ' MB',
|
|
||||||
total: '50.0 MB',
|
|
||||||
speed: '2.5 MB/s'
|
|
||||||
};
|
|
||||||
if (mainWindow) {
|
|
||||||
mainWindow.webContents.send('download-progress', downloadProgress);
|
|
||||||
}
|
|
||||||
}, i * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
downloadedFilePath = 'completed';
|
|
||||||
isDownloading = false;
|
|
||||||
}, 1100);
|
|
||||||
|
|
||||||
return {success: true, filePath: 'dev-mode-simulated', dev: true};
|
|
||||||
}
|
|
||||||
|
|
||||||
const tempPath = join(app.getPath('temp'), 'app.asar.new');
|
const tempPath = join(app.getPath('temp'), 'app.asar.new');
|
||||||
|
|
||||||
await downloadFile(downloadUrl, tempPath, (progress) => {
|
await downloadFile(downloadUrl, tempPath, (progress) => {
|
||||||
@@ -353,13 +411,6 @@ ipcMain.handle('get-download-progress', () => {
|
|||||||
|
|
||||||
ipcMain.handle('install-update', async () => {
|
ipcMain.handle('install-update', async () => {
|
||||||
try {
|
try {
|
||||||
const isRealDev = process.env.NODE_ENV === 'development' && !app.isPackaged;
|
|
||||||
|
|
||||||
if (isRealDev) {
|
|
||||||
downloadedFilePath = null;
|
|
||||||
return {success: true, message: '开发环境模拟重启'};
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateFilePath = join(process.resourcesPath, 'app.asar.update');
|
const updateFilePath = join(process.resourcesPath, 'app.asar.update');
|
||||||
const hasUpdateFile = existsSync(updateFilePath);
|
const hasUpdateFile = existsSync(updateFilePath);
|
||||||
|
|
||||||
@@ -406,38 +457,23 @@ ipcMain.handle('cancel-download', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-update-status', () => {
|
ipcMain.handle('get-update-status', () => {
|
||||||
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged || process.defaultApp;
|
return {downloadedFilePath, isDownloading, downloadProgress, isPackaged: app.isPackaged};
|
||||||
return {downloadedFilePath, isDownloading, downloadProgress, isPackaged: app.isPackaged, isDev};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加文件保存对话框处理器
|
// 添加文件保存对话框处理器
|
||||||
ipcMain.handle('show-save-dialog', async (event, options) => {
|
ipcMain.handle('show-save-dialog', async (event, options) => {
|
||||||
if (!mainWindow) {
|
return await dialog.showSaveDialog(mainWindow!, options);
|
||||||
return {canceled: true};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await dialog.showSaveDialog(mainWindow, options);
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('文件保存对话框错误:', error);
|
|
||||||
return {canceled: true, error: error instanceof Error ? error.message : '对话框打开失败'};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加文件夹选择对话框处理器
|
// 添加文件夹选择对话框处理器
|
||||||
ipcMain.handle('show-open-dialog', async (event, options) => {
|
ipcMain.handle('show-open-dialog', async (event, options) => {
|
||||||
if (!mainWindow) {
|
return await dialog.showOpenDialog(mainWindow!, options);
|
||||||
return {canceled: true};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
// 添加文件写入处理器
|
||||||
const result = await dialog.showOpenDialog(mainWindow, options);
|
ipcMain.handle('write-file', async (event, filePath: string, data: Uint8Array) => {
|
||||||
return result;
|
await fs.writeFile(filePath, Buffer.from(data));
|
||||||
} catch (error) {
|
return { success: true };
|
||||||
console.error('文件夹选择对话框错误:', error);
|
|
||||||
return {canceled: true, error: error instanceof Error ? error.message : '对话框打开失败'};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const electronAPI = {
|
|||||||
showSaveDialog: (options: any) => ipcRenderer.invoke('show-save-dialog', options),
|
showSaveDialog: (options: any) => ipcRenderer.invoke('show-save-dialog', options),
|
||||||
// 添加文件夹选择对话框 API
|
// 添加文件夹选择对话框 API
|
||||||
showOpenDialog: (options: any) => ipcRenderer.invoke('show-open-dialog', options),
|
showOpenDialog: (options: any) => ipcRenderer.invoke('show-open-dialog', options),
|
||||||
|
// 添加文件写入 API
|
||||||
|
writeFile: (filePath: string, data: Uint8Array) => ipcRenderer.invoke('write-file', filePath, data),
|
||||||
|
|
||||||
onDownloadProgress: (callback: (progress: any) => void) => {
|
onDownloadProgress: (callback: (progress: any) => void) => {
|
||||||
ipcRenderer.on('download-progress', (event, progress) => callback(progress))
|
ipcRenderer.on('download-progress', (event, progress) => callback(progress))
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const RakutenDashboard = defineAsyncComponent(() => import('./components/rakuten
|
|||||||
const AmazonDashboard = defineAsyncComponent(() => import('./components/amazon/AmazonDashboard.vue'))
|
const AmazonDashboard = defineAsyncComponent(() => import('./components/amazon/AmazonDashboard.vue'))
|
||||||
const ZebraDashboard = defineAsyncComponent(() => import('./components/zebra/ZebraDashboard.vue'))
|
const ZebraDashboard = defineAsyncComponent(() => import('./components/zebra/ZebraDashboard.vue'))
|
||||||
const UpdateDialog = defineAsyncComponent(() => import('./components/common/UpdateDialog.vue'))
|
const UpdateDialog = defineAsyncComponent(() => import('./components/common/UpdateDialog.vue'))
|
||||||
|
const SettingsDialog = defineAsyncComponent(() => import('./components/common/SettingsDialog.vue'))
|
||||||
|
|
||||||
const dashboardsMap: Record<string, Component> = {
|
const dashboardsMap: Record<string, Component> = {
|
||||||
rakuten: RakutenDashboard,
|
rakuten: RakutenDashboard,
|
||||||
@@ -48,6 +49,9 @@ const userPermissions = ref<string>('')
|
|||||||
// 更新对话框状态
|
// 更新对话框状态
|
||||||
const showUpdateDialog = ref(false)
|
const showUpdateDialog = ref(false)
|
||||||
|
|
||||||
|
// 设置对话框状态
|
||||||
|
const showSettingsDialog = ref(false)
|
||||||
|
|
||||||
// 菜单配置 - 复刻ERP客户端格式
|
// 菜单配置 - 复刻ERP客户端格式
|
||||||
const menuConfig = [
|
const menuConfig = [
|
||||||
{key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'},
|
{key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'},
|
||||||
@@ -69,8 +73,6 @@ function hasPermission(module: string) {
|
|||||||
if (!permissions) {
|
if (!permissions) {
|
||||||
return defaultModules.includes(module) // 没有权限信息时显示默认菜单
|
return defaultModules.includes(module) // 没有权限信息时显示默认菜单
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简化权限检查:直接检查模块名是否在权限字符串中
|
|
||||||
return permissions.includes(module)
|
return permissions.includes(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +134,7 @@ function handleMenuSelect(key: string) {
|
|||||||
async function handleLoginSuccess(data: { token: string; permissions?: string }) {
|
async function handleLoginSuccess(data: { token: string; permissions?: string }) {
|
||||||
isAuthenticated.value = true
|
isAuthenticated.value = true
|
||||||
showAuthDialog.value = false
|
showAuthDialog.value = false
|
||||||
|
showRegDialog.value = false // 确保注册对话框也关闭
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 保存token到本地数据库
|
// 保存token到本地数据库
|
||||||
@@ -209,11 +212,6 @@ function showRegisterDialog() {
|
|||||||
showRegDialog.value = true
|
showRegDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRegisterSuccess() {
|
|
||||||
showRegDialog.value = false
|
|
||||||
showAuthDialog.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function backToLogin() {
|
function backToLogin() {
|
||||||
showRegDialog.value = false
|
showRegDialog.value = false
|
||||||
showAuthDialog.value = true
|
showAuthDialog.value = true
|
||||||
@@ -362,6 +360,10 @@ async function openDeviceManager() {
|
|||||||
await fetchDeviceData()
|
await fetchDeviceData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openSettings() {
|
||||||
|
showSettingsDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchDeviceData() {
|
async function fetchDeviceData() {
|
||||||
if (!currentUsername.value) {
|
if (!currentUsername.value) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
@@ -472,7 +474,8 @@ onUnmounted(() => {
|
|||||||
@go-forward="goForward"
|
@go-forward="goForward"
|
||||||
@reload="reloadPage"
|
@reload="reloadPage"
|
||||||
@user-click="handleUserClick"
|
@user-click="handleUserClick"
|
||||||
@open-device="openDeviceManager"/>
|
@open-device="openDeviceManager"
|
||||||
|
@open-settings="openSettings"/>
|
||||||
<div class="content-body">
|
<div class="content-body">
|
||||||
<div
|
<div
|
||||||
class="dashboard-home"
|
class="dashboard-home"
|
||||||
@@ -500,12 +503,15 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<RegisterDialog
|
<RegisterDialog
|
||||||
v-model="showRegDialog"
|
v-model="showRegDialog"
|
||||||
@register-success="handleRegisterSuccess"
|
@login-success="handleLoginSuccess"
|
||||||
@back-to-login="backToLogin"/>
|
@back-to-login="backToLogin"/>
|
||||||
|
|
||||||
<!-- 更新对话框 -->
|
<!-- 更新对话框 -->
|
||||||
<UpdateDialog v-model="showUpdateDialog" />
|
<UpdateDialog v-model="showUpdateDialog" />
|
||||||
|
|
||||||
|
<!-- 设置对话框 -->
|
||||||
|
<SettingsDialog v-model="showSettingsDialog" />
|
||||||
|
|
||||||
<!-- 设备管理弹框 -->
|
<!-- 设备管理弹框 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="showDeviceDialog"
|
v-model="showDeviceDialog"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
export type HttpMethod = 'GET' | 'POST';
|
export type HttpMethod = 'GET' | 'POST';
|
||||||
|
|
||||||
const BASE_CLIENT = 'http://localhost:8081'; // erp_client_sb
|
const BASE_CLIENT = 'http://localhost:8081'; // erp_client_sb
|
||||||
const BASE_RUOYI = 'http://localhost:8080';
|
const BASE_RUOYI = 'http://192.168.1.89:8080';
|
||||||
|
|
||||||
function resolveBase(path: string): string {
|
function resolveBase(path: string): string {
|
||||||
// 走 ruoyi-admin 的路径:鉴权与版本、平台工具路由
|
// 走 ruoyi-admin 的路径:鉴权与版本、平台工具路由
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const zebraApi = {
|
|||||||
return http.delete<void>(`/tool/banma/accounts/${id}`);
|
return http.delete<void>(`/tool/banma/accounts/${id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 业务采集(仍走客户端微服务 8081)
|
// 业务采集
|
||||||
getShops(params?: { accountId?: number }) {
|
getShops(params?: { accountId?: number }) {
|
||||||
return http.get<{ data?: { list?: Array<{ id: string; shopName: string }> } }>(
|
return http.get<{ data?: { list?: Array<{ id: string; shopName: string }> } }>(
|
||||||
'/api/banma/shops', params as unknown as Record<string, unknown>
|
'/api/banma/shops', params as unknown as Record<string, unknown>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { amazonApi } from '../../api/amazon'
|
import { amazonApi } from '../../api/amazon'
|
||||||
|
import { handlePlatformFileExport } from '../../utils/settings'
|
||||||
|
|
||||||
// 响应式状态
|
// 响应式状态
|
||||||
const loading = ref(false) // 主加载状态
|
const loading = ref(false) // 主加载状态
|
||||||
@@ -196,11 +197,9 @@ async function exportToExcel() {
|
|||||||
html += '</table>'
|
html += '</table>'
|
||||||
|
|
||||||
const blob = new Blob([html], { type: 'application/vnd.ms-excel' })
|
const blob = new Blob([html], { type: 'application/vnd.ms-excel' })
|
||||||
const link = document.createElement('a')
|
const fileName = `Amazon产品数据_${new Date().toISOString().slice(0, 10)}.xls`
|
||||||
link.href = URL.createObjectURL(blob)
|
|
||||||
link.download = `Amazon产品数据_${new Date().toISOString().slice(0, 10)}.xls`
|
await handlePlatformFileExport('amazon', blob, fileName)
|
||||||
link.click()
|
|
||||||
URL.revokeObjectURL(link.href)
|
|
||||||
|
|
||||||
clearInterval(progressInterval)
|
clearInterval(progressInterval)
|
||||||
exportProgress.value = 100
|
exportProgress.value = 100
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface Props {
|
|||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'update:modelValue', value: boolean): void
|
(e: 'update:modelValue', value: boolean): void
|
||||||
(e: 'registerSuccess'): void
|
(e: 'loginSuccess', data: { token: string; user: any }): void
|
||||||
(e: 'backToLogin'): void
|
(e: 'backToLogin'): void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,12 +53,25 @@ async function handleRegister() {
|
|||||||
|
|
||||||
registerLoading.value = true
|
registerLoading.value = true
|
||||||
try {
|
try {
|
||||||
const result = await authApi.register({
|
// 1. 注册
|
||||||
|
await authApi.register({
|
||||||
username: registerForm.value.username,
|
username: registerForm.value.username,
|
||||||
password: registerForm.value.password
|
password: registerForm.value.password
|
||||||
})
|
})
|
||||||
ElMessage.success(result.message || '注册成功,请登录')
|
|
||||||
emit('registerSuccess')
|
// 2. 注册成功后直接登录
|
||||||
|
const loginData = await authApi.login({
|
||||||
|
username: registerForm.value.username,
|
||||||
|
password: registerForm.value.password
|
||||||
|
})
|
||||||
|
|
||||||
|
emit('loginSuccess', {
|
||||||
|
token: loginData.token,
|
||||||
|
user: {
|
||||||
|
username: loginData.username,
|
||||||
|
permissions: loginData.permissions
|
||||||
|
}
|
||||||
|
})
|
||||||
resetForm()
|
resetForm()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ElMessage.error((err as Error).message)
|
ElMessage.error((err as Error).message)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ElMessageBox, ElMessage } from 'element-plus'
|
|||||||
type PlatformKey = 'zebra' | 'shopee' | 'rakuten' | 'amazon'
|
type PlatformKey = 'zebra' | 'shopee' | 'rakuten' | 'amazon'
|
||||||
|
|
||||||
const props = defineProps<{ modelValue: boolean; platform?: PlatformKey }>()
|
const props = defineProps<{ modelValue: boolean; platform?: PlatformKey }>()
|
||||||
const emit = defineEmits(['update:modelValue', 'add'])
|
const emit = defineEmits(['update:modelValue', 'add', 'refresh'])
|
||||||
const visible = computed({ get: () => props.modelValue, set: v => emit('update:modelValue', v) })
|
const visible = computed({ get: () => props.modelValue, set: v => emit('update:modelValue', v) })
|
||||||
const curPlatform = ref<PlatformKey>(props.platform || 'zebra')
|
const curPlatform = ref<PlatformKey>(props.platform || 'zebra')
|
||||||
const PLATFORM_LABEL: Record<PlatformKey, string> = {
|
const PLATFORM_LABEL: Record<PlatformKey, string> = {
|
||||||
@@ -23,6 +23,9 @@ async function load() {
|
|||||||
const list = (res as any)?.data ?? res
|
const list = (res as any)?.data ?? res
|
||||||
accounts.value = Array.isArray(list) ? list : []
|
accounts.value = Array.isArray(list) ? list : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 暴露方法供父组件调用
|
||||||
|
defineExpose({ load })
|
||||||
onMounted(load)
|
onMounted(load)
|
||||||
|
|
||||||
function switchPlatform(p: PlatformKey) {
|
function switchPlatform(p: PlatformKey) {
|
||||||
@@ -38,11 +41,12 @@ function formatDate(a: any) {
|
|||||||
async function onDelete(a: any) {
|
async function onDelete(a: any) {
|
||||||
const id = a?.id
|
const id = a?.id
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(`确定删除账号 “${a?.name || a?.username || id}” 吗?`, '提示', { type: 'warning' })
|
await ElMessageBox.confirm(`确定删除账号 "${a?.name || a?.username || id}" 吗?`, '提示', { type: 'warning' })
|
||||||
} catch { return }
|
} catch { return }
|
||||||
await zebraApi.removeAccount(id)
|
await zebraApi.removeAccount(id)
|
||||||
ElMessage({ message: '删除成功', type: 'success' })
|
ElMessage({ message: '删除成功', type: 'success' })
|
||||||
await load()
|
await load()
|
||||||
|
emit('refresh') // 通知外层组件刷新账号列表
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -106,11 +106,13 @@ type Stage = 'check' | 'downloading' | 'completed'
|
|||||||
const stage = ref<Stage>('check')
|
const stage = ref<Stage>('check')
|
||||||
const appName = ref('我了个电商')
|
const appName = ref('我了个电商')
|
||||||
const version = ref('2.0.0')
|
const version = ref('2.0.0')
|
||||||
const prog = ref({ percentage: 0, current: '0 MB', total: '0 MB', speed: '' as string | undefined })
|
const prog = ref({ percentage: 0, current: '0 MB', total: '0 MB', speed: '' })
|
||||||
const info = ref({
|
const info = ref({
|
||||||
latestVersion: '2.4.8',
|
latestVersion: '2.4.8',
|
||||||
downloadUrl: '',
|
downloadUrl: '',
|
||||||
updateNotes: '• 优化了用户界面体验\n• 修复了已知问题\n• 提升了系统稳定性\n• 增加了新的功能模块\n• 优化了数据处理性能'
|
updateNotes: '• 优化了用户界面体验\n• 修复了已知问题\n• 提升了系统稳定性\n• 增加了新的功能模块\n• 优化了数据处理性能',
|
||||||
|
currentVersion: '',
|
||||||
|
hasUpdate: false
|
||||||
})
|
})
|
||||||
|
|
||||||
async function autoCheck() {
|
async function autoCheck() {
|
||||||
@@ -143,26 +145,24 @@ async function autoCheck() {
|
|||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
if (!info.value.downloadUrl) {
|
if (!info.value.downloadUrl) {
|
||||||
ElMessage({ message: '下载链接不可用', type: 'error' })
|
ElMessage({ message: '下载链接不可用', type: 'error' });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stage.value = 'downloading'
|
stage.value = 'downloading';
|
||||||
prog.value = { percentage: 0, current: '0 MB', total: '0 MB', speed: '' }
|
prog.value = { percentage: 0, current: '0 MB', total: '0 MB', speed: '' };
|
||||||
|
|
||||||
|
(window as any).electronAPI.onDownloadProgress((progress: any) => {
|
||||||
|
|
||||||
window.electronAPI.onDownloadProgress((progress) => {
|
|
||||||
prog.value = {
|
prog.value = {
|
||||||
percentage: progress.percentage || 0,
|
percentage: progress.percentage || 0,
|
||||||
current: progress.current || '0 MB',
|
current: progress.current || '0 MB',
|
||||||
total: progress.total || '0 MB',
|
total: progress.total || '0 MB',
|
||||||
speed: progress.speed || ''
|
speed: progress.speed || ''
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await window.electronAPI.downloadUpdate(info.value.downloadUrl)
|
const response = await (window as any).electronAPI.downloadUpdate(info.value.downloadUrl)
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
stage.value = 'completed'
|
stage.value = 'completed'
|
||||||
@@ -181,10 +181,8 @@ async function start() {
|
|||||||
|
|
||||||
async function cancelDownload() {
|
async function cancelDownload() {
|
||||||
try {
|
try {
|
||||||
if (window.electronAPI) {
|
(window as any).electronAPI.removeDownloadProgressListener()
|
||||||
window.electronAPI.removeDownloadProgressListener()
|
await (window as any).electronAPI.cancelDownload()
|
||||||
await window.electronAPI.cancelDownload()
|
|
||||||
}
|
|
||||||
show.value = false
|
show.value = false
|
||||||
stage.value = 'check'
|
stage.value = 'check'
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -205,7 +203,7 @@ async function installUpdate() {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const response = await window.electronAPI.installUpdate()
|
const response = await (window as any).electronAPI.installUpdate()
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
ElMessage({ message: '应用即将重启', type: 'success' })
|
ElMessage({ message: '应用即将重启', type: 'success' })
|
||||||
@@ -231,9 +229,7 @@ onMounted(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (window.electronAPI) {
|
(window as any).electronAPI.removeDownloadProgressListener()
|
||||||
window.electronAPI.removeDownloadProgressListener()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ interface Emits {
|
|||||||
(e: 'reload'): void
|
(e: 'reload'): void
|
||||||
(e: 'user-click'): void
|
(e: 'user-click'): void
|
||||||
(e: 'open-device'): void
|
(e: 'open-device'): void
|
||||||
|
(e: 'open-settings'): void
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
@@ -45,7 +46,7 @@ defineEmits<Emits>()
|
|||||||
<button class="nav-btn-round" title="设备管理" @click="$emit('open-device')">
|
<button class="nav-btn-round" title="设备管理" @click="$emit('open-device')">
|
||||||
<el-icon><Monitor /></el-icon>
|
<el-icon><Monitor /></el-icon>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn-round" title="设置">
|
<button class="nav-btn-round" title="设置" @click="$emit('open-settings')">
|
||||||
<el-icon><Setting /></el-icon>
|
<el-icon><Setting /></el-icon>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn-round" title="用户" @click="$emit('user-click')">
|
<button class="nav-btn-round" title="用户" @click="$emit('user-click')">
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {ref, computed, onMounted} from 'vue'
|
|||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import {rakutenApi} from '../../api/rakuten'
|
import {rakutenApi} from '../../api/rakuten'
|
||||||
import { batchConvertImages } from '../../utils/imageProxy'
|
import { batchConvertImages } from '../../utils/imageProxy'
|
||||||
|
import { handlePlatformFileExport } from '../../utils/settings'
|
||||||
|
|
||||||
// UI 与加载状态
|
// UI 与加载状态
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -202,6 +203,11 @@ async function handleStartSearch() {
|
|||||||
processedProducts.value = 0
|
processedProducts.value = 0
|
||||||
const resp = await rakutenApi.getProducts({file: pendingFile.value, batchId: currentBatchId.value})
|
const resp = await rakutenApi.getProducts({file: pendingFile.value, batchId: currentBatchId.value})
|
||||||
const products = (resp.products || []).map(p => ({...p, skuPrices: parseSkuPrices(p)}))
|
const products = (resp.products || []).map(p => ({...p, skuPrices: parseSkuPrices(p)}))
|
||||||
|
|
||||||
|
if (products.length === 0) {
|
||||||
|
showMessage('未采集到数据,请检查代理或店铺是否存在', 'warning')
|
||||||
|
}
|
||||||
|
|
||||||
allProducts.value = products
|
allProducts.value = products
|
||||||
pendingFile.value = null
|
pendingFile.value = null
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -367,12 +373,9 @@ async function exportToExcel() {
|
|||||||
const blob = new Blob([buffer], {
|
const blob = new Blob([buffer], {
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
})
|
})
|
||||||
|
const fileName = `乐天商品数据_${new Date().toISOString().slice(0, 10)}.xlsx`
|
||||||
|
|
||||||
const link = document.createElement('a')
|
await handlePlatformFileExport('rakuten', blob, fileName)
|
||||||
link.href = URL.createObjectURL(blob)
|
|
||||||
link.download = `乐天商品数据_${new Date().toISOString().slice(0, 10)}.xlsx`
|
|
||||||
link.click()
|
|
||||||
URL.revokeObjectURL(link.href)
|
|
||||||
|
|
||||||
showMessage('Excel文件导出成功!', 'success')
|
showMessage('Excel文件导出成功!', 'success')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -412,8 +415,7 @@ onMounted(loadLatest)
|
|||||||
<div class="dropzone" @dragover.prevent="onDragOver" @dragleave="onDragLeave" @drop="onDrop" @click="openRakutenUpload" :class="{ disabled: loading }">
|
<div class="dropzone" @dragover.prevent="onDragOver" @dragleave="onDragLeave" @drop="onDrop" @click="openRakutenUpload" :class="{ disabled: loading }">
|
||||||
<div class="dz-el-icon">📤</div>
|
<div class="dz-el-icon">📤</div>
|
||||||
<div class="dz-text">点击或将文件拖拽到这里上传</div>
|
<div class="dz-text">点击或将文件拖拽到这里上传</div>
|
||||||
<div class="dz-sub">支持扩展名:.xls .xlsx</div>
|
<div class="dz-sub">支持 .xls .xlsx</div>
|
||||||
<div class="dz-sub">文件单列:1/1</div>
|
|
||||||
</div>
|
</div>
|
||||||
<input ref="uploadInputRef" style="display:none" type="file" accept=".xls,.xlsx" @change="handleExcelUpload" :disabled="loading"/>
|
<input ref="uploadInputRef" style="display:none" type="file" accept=".xls,.xlsx" @change="handleExcelUpload" :disabled="loading"/>
|
||||||
<div v-if="selectedFileName" class="file-chip">
|
<div v-if="selectedFileName" class="file-chip">
|
||||||
@@ -621,10 +623,10 @@ onMounted(loadLatest)
|
|||||||
.content-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
.content-panel { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||||
|
|
||||||
.left-controls { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
|
.left-controls { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
|
||||||
.dropzone { border: 1px dashed #c0c4cc; border-radius: 6px; padding: 16px; text-align: center; cursor: pointer; background: #fafafa; }
|
.dropzone { border: 1px dashed #c0c4cc; border-radius: 6px; padding: 12px; text-align: center; cursor: pointer; background: #fafafa; }
|
||||||
.dropzone:hover { background: #f6fbff; border-color: #409EFF; }
|
.dropzone:hover { background: #f6fbff; border-color: #409EFF; }
|
||||||
.dropzone.disabled { opacity: .6; cursor: not-allowed; }
|
.dropzone.disabled { opacity: .6; cursor: not-allowed; }
|
||||||
.dz-el-icon { font-size: 20px; margin-bottom: 6px; color: #909399; }
|
.dz-el-icon { font-size: 18px; margin-bottom: 4px; color: #909399; }
|
||||||
.dz-text { color: #303133; font-size: 13px; }
|
.dz-text { color: #303133; font-size: 13px; }
|
||||||
.dz-sub { color: #909399; font-size: 12px; }
|
.dz-sub { color: #909399; font-size: 12px; }
|
||||||
.single-input.left { display: flex; gap: 8px; }
|
.single-input.left { display: flex; gap: 8px; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
|||||||
import { zebraApi, type ZebraOrder, type BanmaAccount } from '../../api/zebra'
|
import { zebraApi, type ZebraOrder, type BanmaAccount } from '../../api/zebra'
|
||||||
import AccountManager from '../common/AccountManager.vue'
|
import AccountManager from '../common/AccountManager.vue'
|
||||||
import { batchConvertImages } from '../../utils/imageProxy'
|
import { batchConvertImages } from '../../utils/imageProxy'
|
||||||
|
import { handlePlatformFileExport } from '../../utils/settings'
|
||||||
|
|
||||||
type Shop = { id: string; shopName: string }
|
type Shop = { id: string; shopName: string }
|
||||||
|
|
||||||
@@ -234,12 +235,9 @@ async function exportToExcel() {
|
|||||||
const blob = new Blob([buffer], {
|
const blob = new Blob([buffer], {
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
})
|
})
|
||||||
|
const fileName = `斑马订单数据_${new Date().toISOString().slice(0, 10)}.xlsx`
|
||||||
|
|
||||||
const link = document.createElement('a')
|
await handlePlatformFileExport('zebra', blob, fileName)
|
||||||
link.href = URL.createObjectURL(blob)
|
|
||||||
link.download = `斑马订单数据_${new Date().toISOString().slice(0, 10)}.xlsx`
|
|
||||||
link.click()
|
|
||||||
URL.revokeObjectURL(link.href)
|
|
||||||
|
|
||||||
showMessage('Excel文件导出成功!', 'success')
|
showMessage('Excel文件导出成功!', 'success')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -266,6 +264,7 @@ const formUsername = ref('')
|
|||||||
const formPassword = ref('')
|
const formPassword = ref('')
|
||||||
const rememberPwd = ref(true)
|
const rememberPwd = ref(true)
|
||||||
const managerVisible = ref(false)
|
const managerVisible = ref(false)
|
||||||
|
const accountManagerRef = ref()
|
||||||
|
|
||||||
function openAddAccount() {
|
function openAddAccount() {
|
||||||
isEditMode.value = false
|
isEditMode.value = false
|
||||||
@@ -302,6 +301,9 @@ async function submitAccount() {
|
|||||||
accountDialogVisible.value = false
|
accountDialogVisible.value = false
|
||||||
await loadAccounts()
|
await loadAccounts()
|
||||||
if (id) accountId.value = id
|
if (id) accountId.value = id
|
||||||
|
if (managerVisible.value && accountManagerRef.value?.load) {
|
||||||
|
accountManagerRef.value.load()
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
ElMessage({ message: e?.message || '账号或密码错误,无法获取Token', type: 'error' })
|
ElMessage({ message: e?.message || '账号或密码错误,无法获取Token', type: 'error' })
|
||||||
}
|
}
|
||||||
@@ -519,7 +521,7 @@ async function removeCurrentAccount() {
|
|||||||
<el-button type="primary" class="btn-blue" style="width: 100%" @click="submitAccount">登录</el-button>
|
<el-button type="primary" class="btn-blue" style="width: 100%" @click="submitAccount">登录</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<AccountManager v-model="managerVisible" platform="zebra" @add="openAddAccount" />
|
<AccountManager ref="accountManagerRef" v-model="managerVisible" platform="zebra" @add="openAddAccount" @refresh="loadAccounts" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,8 @@ public class AmazonScrapingServiceImpl implements IAmazonScrapingService, PagePr
|
|||||||
if (asin == null || asin.trim().isEmpty()) continue;
|
if (asin == null || asin.trim().isEmpty()) continue;
|
||||||
String cleanAsin = asin.replaceAll("[^a-zA-Z0-9]", "");
|
String cleanAsin = asin.replaceAll("[^a-zA-Z0-9]", "");
|
||||||
|
|
||||||
// 查找缓存,有缓存就用缓存,没缓存就爬取
|
|
||||||
Optional<AmazonProductEntity> cached = amazonProductRepository.findByAsin(cleanAsin);
|
Optional<AmazonProductEntity> cached = amazonProductRepository.findByAsin(cleanAsin);
|
||||||
if (cached.isPresent()) {
|
if (cached.isPresent() && !isEmpty(cached.get().getPrice()) && !isEmpty(cached.get().getSeller())) {
|
||||||
AmazonProductEntity entity = cached.get();
|
AmazonProductEntity entity = cached.get();
|
||||||
entity.setSessionId(sessionId);
|
entity.setSessionId(sessionId);
|
||||||
entity.setUpdatedAt(LocalDateTime.now());
|
entity.setUpdatedAt(LocalDateTime.now());
|
||||||
|
|||||||
@@ -36,10 +36,17 @@ public class BanmaOrderController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/accounts")
|
@PostMapping("/accounts")
|
||||||
public R<?> saveAccount(@RequestBody BanmaAccount body) {
|
public R<?> saveAccount(@RequestBody BanmaAccount body) {
|
||||||
|
// 先验证Token
|
||||||
|
String token = ((com.ruoyi.system.service.impl.BanmaAccountServiceImpl) accountService)
|
||||||
|
.validateAndGetToken(body.getUsername(), body.getPassword());
|
||||||
|
if (token == null) {
|
||||||
|
return R.fail("账号或密码错误,无法获取Token");
|
||||||
|
}
|
||||||
|
// 验证成功后保存账号
|
||||||
Long id = accountService.saveOrUpdate(body);
|
Long id = accountService.saveOrUpdate(body);
|
||||||
boolean ok = false;
|
// 刷新Token到数据库
|
||||||
try { ok = accountService.refreshToken(id); } catch (Exception ignore) {}
|
accountService.refreshToken(id);
|
||||||
return ok ? R.ok(Map.of("id", id)) : R.fail("账号或密码错误,无法获取Token");
|
return R.ok(Map.of("id", id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user