This commit is contained in:
ZiJIe 2025-06-24 18:27:57 +08:00
parent a61e54cea2
commit 0a2e896962
8 changed files with 131 additions and 130 deletions

View File

@ -1,30 +1,30 @@
package com.ruoyi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}
package com.ruoyi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -97,7 +97,7 @@ public class WebMagicController extends BaseController implements PageProcessor
@SuppressWarnings("unchecked")
private void loadProxyConfig() {
try {
// File configFile = ResourceUtils.getFile("classpath:test_proxy.yml");
//File configFile = ResourceUtils.getFile("classpath:test_proxy.yml");
File configFile = new File("/www/java_mall/erp/config/test_proxy.yml");
if (configFile.exists()) {
Yaml yaml = new Yaml();
@ -168,6 +168,7 @@ public class WebMagicController extends BaseController implements PageProcessor
@Override
public void process(Page page) {
try {
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
Html html = page.getHtml();
String priceSymbol = html.xpath("//span[@class='a-price-symbol']/text()").toString();
String priceWhole = html.xpath("//span[@class='a-price-whole']/text()").toString();

View File

@ -1,11 +1,11 @@
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE =ERP管理系统
# 开发环境配置
ENV = 'development'
# 若依管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'
# ERP管理系统/开发环境
VUE_APP_BASE_API = 'http://192.168.1.89:8080'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

@ -1,8 +1,8 @@
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE = ERP管理系统
# 生产环境配置
ENV = 'production'
# 若依管理系统/生产环境
# ERP管理系统/生产环境
VUE_APP_BASE_API = 'https://erp.tashowz.com'

View File

@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = 若依管理系统
VUE_APP_TITLE = ERP管理系统
BABEL_ENV = production
@ -8,5 +8,5 @@ NODE_ENV = production
# 测试环境配置
ENV = 'staging'
# 若依管理系统/测试环境
# ERP管理系统/测试环境
VUE_APP_BASE_API = '/stage-api'

View File

@ -1,7 +1,7 @@
{
"name": "ruoyi",
"version": "3.9.0",
"description": "若依管理系统",
"description": "ERP管理系统",
"author": "若依",
"license": "MIT",
"scripts": {

View File

@ -40,7 +40,7 @@
class="action-button"
>开始爬取</el-button>
</el-col>
<el-col :span="3">
<!-- <el-col :span="3">
<el-button
type="info"
plain
@ -49,7 +49,7 @@
@click="openProxyDialog"
class="action-button"
>选择代理</el-button>
</el-col>
</el-col>-->
<el-col :span="15">
<div class="notice-box" v-if="asinList.length > 0">
已导入 <span class="count-number">{{asinList.length}}</span> 个ASIN
@ -59,13 +59,13 @@
</div>
</el-col>
</el-row>
<!-- 爬取进度条 -->
<el-row v-if="crawling">
<el-col :span="24">
<div class="progress-container">
<el-progress
:percentage="crawlProgress.percentage"
<el-progress
:percentage="crawlProgress.percentage"
:format="progressFormat"
:stroke-width="12"
class="crawl-progress"
@ -121,12 +121,12 @@
</template>
</el-dialog>
<!-- 代理选择对话框 -->
<el-dialog
title="选择代理节点"
:visible="proxyDialog.open"
@close="proxyDialog.open = false"
<el-dialog
title="选择代理节点"
:visible="proxyDialog.open"
@close="proxyDialog.open = false"
width="1300px"
append-to-body
append-to-body
custom-class="proxy-dialog"
:close-on-click-modal="false"
>
@ -142,11 +142,11 @@
></el-input>
</el-col>
<el-col :span="7">
<el-button
type="primary"
icon="el-icon-connection"
size="small"
@click="testProxyDelay"
<el-button
type="primary"
icon="el-icon-connection"
size="small"
@click="testProxyDelay"
:loading="testingDelay"
:disabled="filteredProxyNodes.length === 0"
style="width: 100%;"
@ -157,16 +157,16 @@
<div class="proxy-content" v-if="proxyNodes.length > 0">
<el-row :gutter="10">
<el-col :xs="8" :sm="8" :md="6" :lg="6" :xl="6" v-for="(item, index) in filteredProxyNodes" :key="item.name">
<div
class="proxy-item"
<div
class="proxy-item"
:class="{ 'is-selected': selectedProxy === item.name }"
@click="selectProxy(item.name)"
>
<div class="proxy-item-left">
<span class="proxy-flag">{{ getCountryFlag(item.name) }}</span>
<el-radio
v-model="selectedProxy"
:label="item.name"
<el-radio
v-model="selectedProxy"
:label="item.name"
:disabled="loadingProxy"
class="proxy-radio"
>
@ -269,8 +269,8 @@ export default {
return this.proxyNodes;
}
const keyword = this.proxySearchKeyword.toLowerCase();
return this.proxyNodes.filter(proxy =>
proxy.name.toLowerCase().includes(keyword) ||
return this.proxyNodes.filter(proxy =>
proxy.name.toLowerCase().includes(keyword) ||
proxy.server.toLowerCase().includes(keyword)
);
}
@ -291,7 +291,7 @@ export default {
{ key: 'amazon_products_proxy', target: 'currentProxy' },
{ key: 'amazon_products_proxy_delays', target: 'cachedDelays' }
];
items.forEach(item => {
const data = localStorage.getItem(item.key);
if (data) {
@ -307,7 +307,7 @@ export default {
this.clearCache();
}
},
/** 保存数据到本地缓存 */
saveToCache() {
try {
@ -324,7 +324,7 @@ export default {
console.error('保存数据到缓存失败:', error);
}
},
/** 保存代理延迟数据到本地缓存 */
saveProxyDelaysToCache() {
try {
@ -338,7 +338,7 @@ export default {
status: node.status,
timestamp: new Date().getTime()
}));
if (delayData.length) {
const testJson = JSON.stringify(delayData);
@ -349,10 +349,10 @@ export default {
console.error('保存代理延迟数据到缓存失败:', error);
}
},
/** 清空缓存数据 */
clearCache() {
['amazon_products_data', 'amazon_products_asin_list',
['amazon_products_data', 'amazon_products_asin_list',
'amazon_products_proxy', 'amazon_products_proxy_delays'].forEach(key => {
localStorage.removeItem(key);
});
@ -370,19 +370,19 @@ export default {
};
return styles[type.toLowerCase()] || '';
},
/** 获取代理颜色 */
getProxyColor(index) {
return ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399'][index % 5];
},
/** 选择代理 */
selectProxy(name) {
if (!this.loadingProxy && name) {
this.selectedProxy = name;
}
},
/** 加载代理节点列表 */
loadProxyNodes() {
this.loading = true;
@ -393,12 +393,12 @@ export default {
this.loading = false;
if (response.code === 200) {
this.proxyNodes = response.data || [];
if (this.proxyNodes.length) {
if (this.currentProxy) {
this.selectedProxy = this.currentProxy;
}
this.restoreCachedDelays();
}
} else {
@ -408,13 +408,13 @@ export default {
this.loading = false;
});
},
restoreCachedDelays() {
if (!this.cachedDelays?.length || !this.proxyNodes?.length) return;
const now = new Date().getTime();
const oneDay = 24 * 60 * 60 * 1000;
this.cachedDelays.forEach(cachedItem => {
if (cachedItem?.timestamp && (now - cachedItem.timestamp) < oneDay) {
const proxyNode = this.proxyNodes.find(p => p.name === cachedItem.name);
@ -425,7 +425,7 @@ export default {
}
});
},
/** 打开代理选择对话框 */
openProxyDialog() {
this.tempSelectedProxy = this.selectedProxy;
@ -440,11 +440,11 @@ export default {
this.proxyDialog.open = false;
}
},
/** 切换代理节点 */
handleProxyChange(proxyName) {
if (!proxyName) return;
this.loadingProxy = true;
request({
url: '/tool/webmagic/proxy/set',
@ -453,7 +453,7 @@ export default {
}).then(response => {
this.loadingProxy = false;
this.proxyDialog.open = false;
if (response.code === 200) {
this.currentProxy = proxyName;
this.saveToCache();
@ -467,11 +467,11 @@ export default {
this.selectedProxy = this.currentProxy;
});
},
/** 获取国家/地区旗帜emoji */
getCountryFlag(proxyName) {
if (!proxyName) return '🌍';
const lowerName = proxyName.toLowerCase();
const flags = {
'hong kong': '🇭🇰', 'hk': '🇭🇰', '🇭🇰': '🇭🇰',
@ -492,7 +492,7 @@ export default {
'canada': '🇨🇦', 'ca': '🇨🇦', '🇨🇦': '🇨🇦',
'malaysia': '🇲🇾', 'my': '🇲🇾', '🇲🇾': '🇲🇾'
};
const matchedKey = Object.keys(flags).find(key => lowerName.includes(key));
return matchedKey ? flags[matchedKey] : '🌍';
},
@ -503,25 +503,25 @@ export default {
return proxyName.replace(/^[\uD800-\uDBFF][\uDC00-\uDFFF]\s*/, '')
.replace(/^\s*(vn|jp|hk|tw|sg|us|kr|in|ph|id|th|de|fr|gb|ca|my)\s+/i, '');
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "导入ASIN";
this.upload.open = true;
},
/** 进度条格式化 */
progressFormat(percentage) {
return `${this.crawlProgress.current}/${this.crawlProgress.total}`;
},
/** 获取进度条状态 */
getProgressStatus() {
if (this.crawlProgress.percentage >= 100) return 'success';
if (this.crawlProgress.percentage < 0) return 'exception';
return '';
return '';
},
/** 下载模板操作 */
importTemplate() {
//
@ -533,7 +533,7 @@ export default {
];
exportExcel(data, '亚马逊产品信息模板', '.et');
},
//
handleFileChange(file) {
//
@ -544,11 +544,11 @@ export default {
this.$refs.upload.clearFiles();
return false;
}
//
this.selectedFile = file.raw;
},
//
submitFileForm() {
if (!this.selectedFile) {
@ -563,23 +563,23 @@ export default {
this.$message.error('导入数据为空');
return;
}
//
const asinList = data.slice(1)
.map(row => row[0])
.filter(asin => asin && typeof asin === 'string' && asin.trim() !== '');
if (asinList.length === 0) {
this.$message.error('未找到有效的ASIN数据');
return;
}
this.asinList = asinList;
this.$message.success(`成功解析到${this.asinList.length}个ASIN`);
// ASIN
this.saveToCache();
//
this.upload.open = false;
this.$refs.upload && this.$refs.upload.clearFiles();
@ -593,44 +593,44 @@ export default {
this.$message.error('处理文件失败: ' + (error.message || error));
}
},
//
handleCrawl() {
if (!this.asinList.length) {
this.$message.warning("请先导入ASIN列表");
return;
}
if (!this.currentProxy) {
this.startCrawl(); //
} else {
this.startCrawl();
}
},
//
startCrawl() {
this.crawling = true;
this.loading = true;
//
this.crawlProgress = {
total: this.asinList.length,
current: 0,
percentage: 0
};
// 2ASIN
const batchSize = 2;
this.productData = []; //
//
localStorage.removeItem('amazon_products_data');
//
this.batchCrawl(this.asinList, 0, batchSize);
},
//
batchCrawl(asinList, startIndex, batchSize) {
if (startIndex >= asinList.length) {
@ -641,26 +641,26 @@ export default {
this.saveToCache();
return;
}
//
const endIndex = Math.min(startIndex + batchSize, asinList.length);
// ASIN
const currentBatch = asinList.slice(startIndex, endIndex);
//
this.crawlProgress.current = startIndex;
this.crawlProgress.percentage = Math.floor((startIndex / this.crawlProgress.total) * 100);
//
request({
url: '/tool/webmagic/batch',
method: 'post',
data: currentBatch,
timeout: 9000000
timeout: 9000000
}).then(response => {
if (response.code === 200) {
this.productData = [...this.productData, ...response.data];
this.crawlProgress.current = endIndex;
this.crawlProgress.percentage = Math.floor((endIndex / this.crawlProgress.total) * 100);
this.batchCrawl(asinList, endIndex, batchSize);
@ -672,7 +672,7 @@ export default {
}).catch(error => {
console.error("爬取失败:", error);
this.$message.error("爬取失败: " + (error.message || error));
if (error.message && error.message.includes('timeout')) {
this.$message.warning("当前批次请求超时,将尝试继续下一批");
@ -690,33 +690,33 @@ export default {
}
});
},
// Excel
handleExport() {
if (!this.productData.length) {
this.$message.warning("没有数据可导出");
return;
}
const data = [
['ASIN', '卖家/配送方', '当前售价']
];
this.productData.forEach(item => {
const seller = item.seller || '';
const shipper = item.shipper ? (item.shipper !== item.seller ? `配送方: ${item.shipper}` : '') : '';
const sellerInfo = shipper ? `${seller} (${shipper})` : seller;
data.push([
item.asin || '',
sellerInfo,
item.price || ''
]);
});
exportExcel(data, '亚马逊产品信息', '.et');
},
/** 测试代理延迟 */
testProxyDelay() {
if (!this.filteredProxyNodes?.length) {
@ -726,29 +726,29 @@ export default {
this.startProxyTest(); //
},
/** 开始测试代理节点 */
startProxyTest() {
this.testingDelay = true;
const proxyNames = this.filteredProxyNodes.map(item => item.name);
this.proxyNodes.forEach(proxy => {
if (proxyNames.includes(proxy.name)) {
proxy.delay = undefined;
proxy.testing = true;
}
});
const batches = [];
const batchSize = 10;
for (let i = 0; i < proxyNames.length; i += batchSize) {
batches.push(proxyNames.slice(i, i + batchSize));
}
this.testNextBatch(batches, 0);
},
/** 测试下一批代理节点 */
testNextBatch(batches, batchIndex) {
if (batchIndex >= batches.length) {
@ -757,7 +757,7 @@ export default {
this.saveProxyDelaysToCache();
return;
}
request({
url: '/tool/webmagic/proxy/test',
method: 'post',
@ -776,10 +776,10 @@ export default {
this.handleTestError(error.message || '网络错误', batches, batchIndex);
});
},
updateProxyDelays(results) {
if (!results?.length) return;
results.forEach(result => {
const proxyNode = this.proxyNodes.find(p => p.name === result.name);
if (proxyNode) {
@ -789,11 +789,11 @@ export default {
}
});
},
/** 处理测试错误 */
handleTestError(errorMsg, batches, batchIndex) {
console.error('测试代理延迟失败:', errorMsg);
batches[batchIndex].forEach(proxyName => {
const proxyNode = this.proxyNodes.find(p => p.name === proxyName);
if (proxyNode?.testing) {
@ -802,13 +802,13 @@ export default {
proxyNode.testing = false;
}
});
this.$message.warning('部分代理测试失败,继续测试下一批');
setTimeout(() => {
this.testNextBatch(batches, batchIndex + 1);
}, 500);
},
/** 获取延迟样式类 */
getDelayClass(delay) {
if (delay === undefined || delay < 0) return 'delay-error';
@ -818,7 +818,7 @@ export default {
if (delay < 1000) return 'delay-slow';
return 'delay-very-slow';
},
/** 格式化延迟显示 */
formatDelay(delay) {
if (delay === undefined) return '';

View File

@ -7,7 +7,7 @@ function resolve(dir) {
const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
const name = 'ERP管理系统' // 网页标题
const baseUrl = 'https://erp.tashowz.com' // 后端接口
//const baseUrl = 'http://43.136.31.205:8080'