daShangDao_miniProgram/pkgManage/clone-tool/index.vue
2026-06-15 16:37:57 +08:00

1328 lines
38 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="clone-tool-container">
<!-- 上方日志展示区域 -->
<view class="log-section">
<view class="log-header">
<text class="log-title">日志输出</text>
<view class="log-actions">
<button class="btn-small" @click="clearLog">清空</button>
<button class="btn-small" @click="exportLog">导出</button>
</view>
</view>
<scroll-view class="log-content" scroll-y scroll-with-animation :scroll-top="scrollTop">
<view v-for="(log, index) in logs" :key="index" class="log-item">
<text>{{ log }}</text>
</view>
<view v-if="logs.length === 0" class="empty-log">
<text>暂无日志信息</text>
</view>
</scroll-view>
</view>
<!-- 下方控制按钮区域 -->
<view class="control-section">
<!-- 状态显示 -->
<view class="status-bar">
<text class="status-text">{{ status }}</text>
</view>
<!-- 主要功能按钮 -->
<view class="main-buttons">
<button class="function-btn account-btn" @click="showAccountModal = true">
<text class="btn-label">账号配置</text>
</button>
<button class="function-btn fetch-btn" @click="showFetchModal = true">
<text class="btn-label">拉取商品</text>
</button>
<button class="function-btn price-btn" @click="showPriceModal = true">
<text class="btn-label">价格配置</text>
</button>
<button class="function-btn process-btn" @click="showProcessModal = true">
<text class="btn-label">处理控制</text>
</button>
</view>
</view>
<!-- 底部状态栏 -->
<view class="status-bar">
<text>{{ progressText }}</text>
<text>{{ currentItemText }}</text>
</view>
<!-- 账号配置模态框 -->
<view v-if="showAccountModal" class="modal-overlay" @click="showAccountModal = false">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">账号配置</text>
<text class="modal-close" @click="showAccountModal = false">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="label">用户名:</text>
<input class="input" v-model="config.username" placeholder="请输入用户名" />
</view>
<view class="form-item">
<text class="label">密码:</text>
<input class="input" v-model="config.password" type="password" placeholder="请输入密码" />
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="showAccountModal = false">取消</button>
<!-- <button class="btn-primary" @click="saveConfig">保存配置</button> -->
<button class="btn-primary" @click="login">登录</button>
</view>
</view>
</view>
<!-- 拉取商品模态框 -->
<view v-if="showFetchModal" class="modal-overlay" @click="showFetchModal = false">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">拉取商品设置</text>
<text class="modal-close" @click="showFetchModal = false">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="label">货号:</text>
<input class="input" v-model="fetchParams.itemSn" placeholder="请输入货号" />
</view>
<view class="form-item">
<text class="label">价格范围:</text>
<view class="price-range-container">
<input class="input price-range-input" v-model="fetchParams.priceMin" placeholder="最低价格"
type="digit" inputmode="decimal" />
<text class="price-separator">-</text>
<input class="input price-range-input" v-model="fetchParams.priceMax" placeholder="最高价格"
type="digit" inputmode="decimal" />
</view>
</view>
<view class="form-item">
<text class="label">开始日期:</text>
<view class="date-input-container">
<picker mode="date" :value="startDateFormatted" @change="onStartDateChange"
class="date-picker">
<view class="picker-text">{{ fetchParams.startDate || '请选择开始日期' }}</view>
</picker>
<button v-if="fetchParams.startDate" class="clear-btn" @click="clearStartDate">×</button>
</view>
</view>
<view class="form-item">
<text class="label">结束日期:</text>
<view class="date-input-container">
<picker mode="date" :value="endDateFormatted" @change="onEndDateChange" class="date-picker">
<view class="picker-text">{{ fetchParams.endDate || '请选择结束日期' }}</view>
</picker>
<button v-if="fetchParams.endDate" class="clear-btn" @click="clearEndDate">×</button>
</view>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="showFetchModal = false">取消</button>
<button class="btn-primary" @click="confirmFetchItems" :disabled="fetching">
{{ fetching ? '拉取中...' : '开始拉取' }}
</button>
</view>
</view>
</view>
<!-- 价格配置模态框 -->
<view v-if="showPriceModal" class="modal-overlay" @click="showPriceModal = false">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">价格配置设置</text>
<text class="modal-close" @click="showPriceModal = false">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="label">调整类型:</text>
<radio-group @change="onPriceTypeChange" class="radio-group">
<label class="radio-item">
<radio value="1" :checked="priceConfig.configType === 1" />折扣
</label>
<label class="radio-item">
<radio value="2" :checked="priceConfig.configType === 2" />加减值
</label>
<label class="radio-item">
<radio value="3" :checked="priceConfig.configType === 3" />指定金额
</label>
</radio-group>
</view>
<view class="form-item">
<text class="label">调整值:</text>
<view class="price-input-container">
<!-- 加减值类型显示正负号选择 -->
<picker v-if="priceConfig.configType === 2" mode="selector" :range="signOptions"
:value="signIndex" @change="onSignChange" class="sign-picker">
<view class="sign-text">{{ signOptions[signIndex] }}</view>
</picker>
<input class="input price-input" v-model="priceConfig.value"
:placeholder="getPlaceholderText()" type="digit" @input="onPriceValueInput"
@keypress="onKeyPress" inputmode="decimal" />
</view>
<!-- 根据配置类型显示不同的提示文字 -->
<text class="price-hint-text">
<text v-if="priceConfig.configType === 1">请输入0-100内的折扣数字</text>
<text v-else-if="priceConfig.configType === 2">选择加减符号并输入相应的数字进行调整值</text>
<text v-else-if="priceConfig.configType === 3">请输入纯数字</text>
</text>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="showPriceModal = false">取消</button>
<button class="btn-primary" @click="confirmSavePriceConfig">保存配置</button>
</view>
</view>
</view>
<!-- 处理控制模态框 -->
<view v-if="showProcessModal" class="modal-overlay" @click="showProcessModal = false">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">处理控制</text>
<text class="modal-close" @click="showProcessModal = false">×</text>
</view>
<view class="modal-body">
<view class="process-controls">
<button class="control-btn start-btn" @click="startProcessing" :disabled="processing">
<text class="btn-icon"></text>
<text class="btn-text">开始处理</text>
</button>
<button class="control-btn pause-btn" @click="togglePause" :disabled="!processing">
<text class="btn-icon">{{ paused ? '▶️' : '⏸️' }}</text>
<text class="btn-text">{{ paused ? '继续' : '暂停' }}</text>
</button>
<button class="control-btn stop-btn" @click="stopProcessing" :disabled="!processing">
<text class="btn-icon"></text>
<text class="btn-text">停止</text>
</button>
</view>
<view class="process-info">
<text class="info-text">当前状态: {{ status }}</text>
<text class="info-text">处理进度: {{ progressText }}</text>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="showProcessModal = false">关闭</button>
</view>
</view>
</view>
</view>
</template>
<script>
import request from '@/utils/request.js';
import {
generateDeviceId,
validateDate,
dateToTimestamp,
adjustPrice,
formatLogMessage,
saveToStorage,
loadFromStorage,
getNewItemIds,
clearNewItemIds
} from '@/utils/clone-tool.js';
import {
login as kongfzLogin,
fetchItems as kongfzFetchItems,
getItemTplFields as kongfzGetItemTplFields,
submitItemForm as kongfzSubmitItemForm,
deleteItem as kongfzDeleteItem,
batchUpdatePddPlatformId
} from '@/api/kongfz.js';
export default {
data() {
return {
// 配置信息
config: {
username: '',
password: '',
token: ''
},
// 价格配置
priceConfig: {
configType: 1, // 1: 折扣, 2: 加减值, 3: 指定金额
value: 1.0
},
// 正负号选择
signOptions: ['+', '-'],
signIndex: 0,
// 拉取参数
fetchParams: {
itemSn: '',
priceMin: '',
priceMax: '',
startDate: '',
endDate: ''
},
// 处理状态
processing: false,
paused: false,
fetching: false,
status: '就绪',
// 日志
logs: [],
scrollTop: 0,
// 进度
progressText: '0/0',
currentItemText: '当前商品: 无',
// 商品列表
itemList: [],
currentItemIndex: -1,
// 设备ID
deviceId: '',
// 模态框控制
showAccountModal: false,
showFetchModal: false,
showPriceModal: false,
showProcessModal: false
};
},
onLoad() {
// 生成设备ID
this.deviceId = generateDeviceId();
this.log(`设备ID: ${this.deviceId}`);
// 加载配置
this.config = loadFromStorage('kongfz_config', this.config);
const savedPriceConfig = loadFromStorage('kongfz_price_config', this.priceConfig);
this.priceConfig = savedPriceConfig;
// 加载正负号信息
if (savedPriceConfig && savedPriceConfig.signIndex !== undefined) {
this.signIndex = savedPriceConfig.signIndex;
}
// 加载商品列表
const itemList = loadFromStorage('kongfz_item_list');
if (itemList) {
this.itemList = itemList;
}
// 加载新商品ID列表
this.newItemIds = getNewItemIds();
this.log('配置已加载');
if (this.newItemIds.length > 0) {
this.log(`已加载 ${this.newItemIds.length} 个新商品ID`);
}
},
computed: {
// 开始日期格式化为YYYY-MM-DD格式供picker使用
startDateFormatted() {
if (!this.fetchParams.startDate) return '';
const date = this.fetchParams.startDate;
if (date.length === 8) {
return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`;
}
return date;
},
// 结束日期格式化为YYYY-MM-DD格式供picker使用
endDateFormatted() {
if (!this.fetchParams.endDate) return '';
const date = this.fetchParams.endDate;
if (date.length === 8) {
return `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}`;
}
return date;
}
},
methods: {
// 开始日期选择处理
onStartDateChange(e) {
const selectedDate = e.detail.value;
this.fetchParams.startDate = selectedDate.replace(/-/g, '');
},
// 结束日期选择处理
onEndDateChange(e) {
const selectedDate = e.detail.value;
this.fetchParams.endDate = selectedDate.replace(/-/g, '');
},
// 清空开始日期
clearStartDate() {
this.fetchParams.startDate = '';
},
// 清空结束日期
clearEndDate() {
this.fetchParams.endDate = '';
},
// 价格类型选择处理
onPriceTypeChange(e) {
this.priceConfig.configType = parseInt(e.detail.value);
// 重置调整值
this.priceConfig.value = this.priceConfig.configType === 1 ? 1.0 : 0;
// 重置正负号为正号
this.signIndex = 0;
},
// 正负号选择处理
onSignChange(e) {
this.signIndex = e.detail.value;
},
// 获取输入框提示文本
getPlaceholderText() {
switch (this.priceConfig.configType) {
case 1:
return '请输入0-100的折扣值';
case 2:
return '请输入数字';
case 3:
return '请输入指定金额';
default:
return '请输入调整值';
}
},
// 键盘按键事件处理(阻止非数字字符输入)
onKeyPress(e) {
const char = String.fromCharCode(e.which || e.keyCode);
const currentValue = this.priceConfig.value || '';
// 只允许数字和小数点
if (!/[\d.]/.test(char)) {
e.preventDefault();
return false;
}
// 如果是小数点,检查是否已经有小数点
if (char === '.' && currentValue.includes('.')) {
e.preventDefault();
return false;
}
return true;
},
// 价格值输入处理
onPriceValueInput(e) {
let value = e.detail.value;
// 严格过滤:只允许数字和小数点,移除所有非数字字符(包括汉字)
value = value.replace(/[^\d.]/g, '');
// 防止多个小数点
const dotCount = (value.match(/\./g) || []).length;
if (dotCount > 1) {
const firstDotIndex = value.indexOf('.');
value = value.substring(0, firstDotIndex + 1) + value.substring(firstDotIndex + 1).replace(/\./g, '');
}
// 防止以小数点开头
if (value.startsWith('.')) {
value = '0' + value;
}
// 折扣类型限制0-100
if (this.priceConfig.configType === 1) {
const numValue = parseFloat(value);
if (numValue > 100) {
value = '100';
uni.showToast({
title: '折扣值不能超过100',
icon: 'none'
});
}
}
// 更新值
this.priceConfig.value = value;
// 强制更新输入框显示(防止输入汉字后显示异常)
this.$nextTick(() => {
this.priceConfig.value = value;
});
},
// 保存配置
saveConfig() {
if (saveToStorage('kongfz_config', this.config)) {
this.log('配置已保存');
this.showAccountModal = false; // 关闭弹框
} else {
this.log('保存配置失败');
}
},
// 加载价格配置
loadPriceConfig() {
const savedPriceConfig = loadFromStorage('kongfz_price_config', this.priceConfig);
this.priceConfig = savedPriceConfig;
// 加载正负号信息
if (savedPriceConfig && savedPriceConfig.signIndex !== undefined) {
this.signIndex = savedPriceConfig.signIndex;
}
console.log('已加载价格配置:', this.priceConfig);
},
// 保存价格配置
savePriceConfig() {
// 验证价格值是否为数字
let value = parseFloat(this.priceConfig.value);
if (isNaN(value)) {
uni.showToast({
title: '请输入有效的数值',
icon: 'none'
});
return;
}
// 折扣类型验证范围
if (this.priceConfig.configType === 1 && (value < 0 || value > 100)) {
uni.showToast({
title: '折扣值必须在0-100之间',
icon: 'none'
});
return;
}
// 加减值类型处理正负号
if (this.priceConfig.configType === 2 && parseInt(this.signIndex) === 1) {
value = -Math.abs(value); // 确保是负数
}
// 保存配置时包含正负号信息
const configToSave = {
...this.priceConfig,
value: value,
signIndex: this.signIndex
};
console.log("价格配置", configToSave)
if (saveToStorage('kongfz_price_config', configToSave)) {
this.log('价格配置已保存');
} else {
this.log('保存价格配置失败');
}
},
// 登录
async login() {
const {
username,
password
} = this.config;
if (!username || !password) {
uni.showToast({
title: '请输入用户名和密码',
icon: 'none'
});
return;
}
this.log('正在登录...');
this.status = '登录中...';
try {
// 调用登录API
const result = await kongfzLogin(username, password);
if (result.success) {
console.log("token", result);
this.config.token = result.token;
this.saveConfig();
this.log(`登录成功! Token: ${result.token}`);
this.status = '登录成功';
// 关闭账号配置模态框
this.showAccountModal = false;
// 显示成功提示
uni.showToast({
title: '登录成功',
icon: 'success',
duration: 2000
});
} else {
// 处理登录失败情况
this.handleLoginError(result);
}
} catch (err) {
console.error('登录出错:', err);
this.log(`登录失败: ${err.message}`);
this.status = '登录失败';
// 显示网络错误提示
uni.showModal({
title: '登录失败',
content: '网络异常或服务器错误,请检查网络连接后重试',
showCancel: false
});
}
},
// 处理登录错误
handleLoginError(result) {
this.log(result.message || '登录失败');
this.status = '登录失败';
// 根据错误码显示不同的错误信息
let errorTitle = '登录失败';
let errorContent = result.message || '未知错误';
// 检查是否有具体的错误码
if (result.responseData) {
const errCode = result.responseData.errCode;
const errInfo = result.responseData.errInfo;
switch (errCode) {
case 102:
errorContent = '用户名不能为空';
break;
case 1000:
errorContent = '授权码错误或已过期';
break;
case 1001:
errorContent = '用户不存在,请检查用户名是否正确';
break;
case 1005:
errorContent = '密码错误,请检查密码是否正确';
break;
case 1009:
errorContent = '调用次数已达上限,请稍后再试';
break;
default:
if (errInfo) {
errorContent = errInfo;
}
break;
}
// 检查是否需要手机验证
if (result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect" &&
result.responseData.extInfo.uri &&
result.responseData.extInfo.uri.includes("请使用手机号验证登录")) {
errorTitle = '需要手机验证';
errorContent = '该账号需要手机验证登录,请使用其他账号或到网页端完成验证';
}
}
// 显示错误弹框
uni.showModal({
title: errorTitle,
content: errorContent,
showCancel: false,
confirmText: '确定'
});
},
// 确认拉取商品
confirmFetchItems() {
this.showFetchModal = false;
this.startFetchItems();
},
// 确认保存价格配置
confirmSavePriceConfig() {
this.showPriceModal = false;
this.savePriceConfig();
// 更新当前的价格配置
this.loadPriceConfig();
},
// 开始拉取商品
startFetchItems() {
if (this.fetching) {
return;
}
// 获取输入参数
const {
itemSn,
priceMin,
priceMax,
startDate,
endDate
} = this.fetchParams;
// 验证日期格式
if (startDate && !validateDate(startDate)) {
uni.showToast({
title: '开始日期格式错误请输入YYYYMMDD格式的日期',
icon: 'none'
});
return;
}
if (endDate && !validateDate(endDate)) {
uni.showToast({
title: '结束日期格式错误请输入YYYYMMDD格式的日期',
icon: 'none'
});
return;
}
// 验证时间范围
if (startDate && endDate) {
try {
const startTs = dateToTimestamp(startDate, false);
const endTs = dateToTimestamp(endDate, true);
if (endTs <= startTs) {
uni.showToast({
title: '结束日期必须大于开始日期',
icon: 'none'
});
return;
}
} catch (e) {
this.log(`日期转换错误: ${e.message}`);
return;
}
}
// 准备参数
const params = {};
if (itemSn) {
params.itemSn = itemSn;
}
if (priceMin) {
try {
parseFloat(priceMin); // 验证是否为数字
params.priceMin = priceMin;
} catch (e) {
uni.showToast({
title: '最低价格格式错误,请输入有效数字',
icon: 'none'
});
return;
}
}
if (priceMax) {
try {
parseFloat(priceMax); // 验证是否为数字
params.priceMax = priceMax;
} catch (e) {
uni.showToast({
title: '最高价格格式错误,请输入有效数字',
icon: 'none'
});
return;
}
}
if (startDate) {
try {
const startTs = dateToTimestamp(startDate, false);
params.startCreateTime = startTs.toString();
} catch (e) {
this.log(`开始日期转换错误: ${e.message}`);
return;
}
}
if (endDate) {
try {
const endTs = dateToTimestamp(endDate, true);
params.endCreateTime = endTs.toString();
} catch (e) {
this.log(`结束日期转换错误: ${e.message}`);
return;
}
}
this.log('开始拉取商品...');
this.status = '拉取商品中...';
this.fetching = true;
// 执行拉取
this.fetchItems(params);
},
// 拉取商品
fetchItems(params) {
const token = this.config.token;
if (!token) {
this.log('请先登录获取Token');
this.fetching = false;
this.status = '就绪';
return;
}
// 调用API获取商品列表
console.log(`开始拉取商品...`);
this.log(`请求参数:${JSON.stringify(params)}`);
this.log(`使用Token${token.substring(0, 4)}...${token.substring(token.length - 4)}`);
kongfzFetchItems(token, params, (progressMessage) => {
// 进度回调
this.log(progressMessage);
})
.then(allItemIds => {
if (allItemIds.length > 0) {
this.itemList = allItemIds;
this.log(`✅ 成功拉取 ${allItemIds.length} 个商品`);
this.log(
`📋 商品ID列表: ${allItemIds.slice(0, 5).map(item => item.id).join(', ')}${allItemIds.length > 5 ? '...' : ''}`
);
// 统计商品状态
const statusCounts = allItemIds.reduce((acc, item) => {
acc[item.status] = (acc[item.status] || 0) + 1;
return acc;
}, {});
this.log(
`📊 商品状态统计: ${Object.entries(statusCounts).map(([status, count]) => `${status}=${count}`).join(', ')}`
);
console.log("保存数据", allItemIds)
// 保存到本地存储
saveToStorage('kongfz_item_list', allItemIds);
this.log('💾 商品列表已保存到本地存储');
} else {
this.log('⚠️ 没有找到符合条件的商品');
this.log('请检查以下可能的原因:');
this.log('1. 筛选条件是否过于严格');
this.log('2. 账号中是否有在售商品');
this.log('3. 日期范围是否正确');
}
this.fetching = false;
this.status = '就绪';
this.log('拉取商品完成');
})
.catch(err => {
this.log(`❌ 拉取商品失败: ${err.message}`);
this.log('🔍 请检查以下可能的问题:');
this.log('1. 网络连接是否正常');
this.log('2. 登录状态是否有效 (Token可能已过期)');
this.log('3. 孔夫子网站是否可访问');
this.log('4. 请求参数是否正确');
// 建议用户重新登录
this.log('建议尝试重新登录后再次拉取');
this.fetching = false;
this.status = '拉取失败';
// 3秒后恢复状态
setTimeout(() => {
if (this.status === '拉取失败') {
this.status = '就绪';
}
}, 3000);
});
},
// 开始处理商品
startProcessing() {
if (this.processing) {
return;
}
// 检查是否有商品列表
if (!this.itemList || this.itemList.length === 0) {
try {
const itemListStr = uni.getStorageSync('kongfz_item_list');
if (itemListStr) {
this.itemList = JSON.parse(itemListStr);
}
} catch (e) {
this.log('读取商品列表失败: ' + e.message);
}
if (!this.itemList || this.itemList.length === 0) {
uni.showToast({
title: '没有可处理的商品,请先拉取商品',
icon: 'none'
});
return;
}
}
// 检查是否已登录
if (!this.config.token) {
this.log('请先登录获取Token');
uni.showToast({
title: '请先登录',
icon: 'none'
});
return;
}
this.processing = true;
this.paused = false;
this.status = '处理中...';
this.log('开始处理商品...');
// 清除之前的新商品ID存储数据
try {
uni.removeStorageSync('kongfz_new_ids');
this.log('已清除之前的新商品ID记录');
} catch (e) {
this.log('清除新商品ID记录失败: ' + e.message);
}
// 重置进度
this.currentItemIndex = -1;
const waitingItems = this.itemList.filter(item => item.status === 'wait');
this.progressText = `0/${waitingItems.length}`;
// 保存当前商品列表到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 开始处理
this.processNextItem();
},
// 处理下一个商品
processNextItem() {
if (!this.processing || this.paused) {
return;
}
// 查找下一个待处理的商品
let nextItemIndex = -1;
for (let i = 0; i < this.itemList.length; i++) {
if (this.itemList[i].status === 'wait') {
nextItemIndex = i;
break;
}
}
if (nextItemIndex === -1) {
// 所有商品已处理完成
this.log('所有商品处理完成!');
this.stopProcessing();
return;
}
this.currentItemIndex = nextItemIndex;
const currentItem = this.itemList[nextItemIndex];
const itemId = currentItem.id;
this.currentItemText = `当前商品: ${itemId}`;
this.log(`处理商品: ${itemId}`);
// 获取商品模板字段
this.log(`获取商品 ${itemId} 的模板字段...`);
console.log("通过itemId获取模板", itemId)
this.getItemTplFields(itemId).then(itemData => {
console.log("itemData", itemData)
if (itemData) {
// 保存商品数据
this.log(`保存商品 ${itemId} 数据...`);
this.saveItemData(itemId, itemData);
// 更新状态为geted
this.updateItemStatus(nextItemIndex, 'geted');
// 更新进度
const waitingItems = this.itemList.filter(item => item.status === 'wait');
const processedItems = this.itemList.filter(item => item.status !== 'wait').length;
this.progressText = `${processedItems}/${processedItems + waitingItems.length}`;
// 保存当前状态到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 提交商品表单
this.log(`提交商品 ${itemId}...`);
console.log("itemData", itemData)
this.submitItemForm(itemData).then(success => {
if (success) {
this.log(`商品 ${itemId} 提交成功`);
// 刷新新商品ID列表
// this.refreshNewItemIds();
// 删除原商品
this.deleteItem(itemId).then(deleteSuccess => {
if (deleteSuccess) {
this.updateItemStatus(nextItemIndex, 'delete');
this.log(`原商品 ${itemId} 已删除`);
} else {
this.updateItemStatus(nextItemIndex, 'delete_error');
this.log(`警告: 原商品 ${itemId} 删除失败`);
}
console.log("保存数据1", this.itemList)
// 保存当前状态到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 立即处理当前商品的孔更新
this.log(`开始处理商品 ${itemId} 的平台ID更新...`);
this.processSinglePddItem(itemId).then(() => {
this.log(`孔商品 ${itemId} 处理完成`);
// 延迟5秒后处理下一个
this.log('等待5秒...');
setTimeout(() => this.processNextItem(), 5000);
}).catch(err => {
this.log(`商品 ${itemId} 孔处理失败: ${err.message}`);
// 延迟5秒后处理下一个
this.log('等待5秒...');
setTimeout(() => this.processNextItem(), 5000);
});
});
} else {
this.log(`商品 ${itemId} 提交失败`);
this.updateItemStatus(nextItemIndex, 'clone_error');
// 保存当前状态到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 延迟5秒后处理下一个
this.log('等待5秒...');
setTimeout(() => this.processNextItem(), 5000);
}
});
} else {
// 更新状态为error
this.updateItemStatus(nextItemIndex, 'error');
this.log(`商品 ${itemId} 处理失败`);
// 保存当前状态到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 延迟5秒后处理下一个
this.log('等待5秒...');
setTimeout(() => this.processNextItem(), 5000);
}
}).catch(err => {
this.log(`处理商品 ${itemId} 时出错: ${err.message}`);
this.updateItemStatus(nextItemIndex, 'error');
// 保存当前状态到本地存储
saveToStorage('kongfz_item_list', this.itemList);
// 延迟5秒后处理下一个
this.log('等待5秒...');
setTimeout(() => this.processNextItem(), 5000);
});
},
// 暂停/继续处理
togglePause() {
this.paused = !this.paused;
if (this.paused) {
this.log('处理已暂停...');
this.status = '已暂停';
} else {
this.log('继续处理...');
this.status = '处理中...';
this.processNextItem();
}
},
// 停止处理
stopProcessing() {
this.processing = false;
this.paused = false;
this.log('处理已停止');
this.status = '已停止';
this.currentItemText = '当前商品: 无';
},
// 获取商品模板字段
getItemTplFields(itemId) {
return kongfzGetItemTplFields(this.config.token, itemId);
},
// 保存商品数据
saveItemData(itemId, data) {
try {
// 保存到本地存储
const key = `kongfz_item_${itemId}`;
saveToStorage(key, data);
return true;
} catch (e) {
this.log(`保存商品数据失败: ${e.message}`);
return false;
}
},
// 更新商品状态
updateItemStatus(index, newStatus) {
if (index >= 0 && index < this.itemList.length) {
this.itemList[index].status = newStatus;
// 不在每次状态更新时都保存而是在processNextItem方法的关键点保存
}
},
// 提交商品表单
submitItemForm(itemData) {
return kongfzSubmitItemForm(this.config.token, itemData, this.priceConfig);
},
// 删除原商品
deleteItem(itemId) {
return kongfzDeleteItem(this.config.token, itemId);
},
// 添加日志
log(message) {
const logMessage = formatLogMessage(message);
this.logs.push(logMessage);
// 同时输出到控制台
console.log(logMessage);
// 保持日志不超过1000条
if (this.logs.length > 1000) {
this.logs.shift();
}
// 自动滚动到底部
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.log-content').fields({
scrollOffset: true,
size: true
}, (data) => {
if (data && data.scrollHeight > data.height) {
// 计算需要滚动的距离
const maxScrollTop = data.scrollHeight - data.height;
this.scrollTop = maxScrollTop;
}
}).exec();
});
},
// 清空日志
clearLog() {
this.logs = [];
this.log('日志已清空');
},
// 导出日志
exportLog() {
if (this.logs.length === 0) {
uni.showToast({
title: '暂无日志可导出',
icon: 'none'
});
return;
}
const logContent = this.logs.join('\n');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `clone-tool-log-${timestamp}.txt`;
// 在小程序环境中,可以使用分享功能
uni.showActionSheet({
itemList: ['复制到剪贴板', '分享日志'],
success: (res) => {
if (res.tapIndex === 0) {
uni.setClipboardData({
data: logContent,
success: () => {
uni.showToast({
title: '日志已复制到剪贴板',
icon: 'success'
});
}
});
} else if (res.tapIndex === 1) {
// 分享功能
uni.share({
provider: 'weixin',
type: 0,
title: '克隆工具日志',
summary: `日志内容,共${this.logs.length}条记录`,
success: () => {
this.log('日志分享成功');
},
fail: (err) => {
this.log(`日志分享失败: ${err.errMsg}`);
}
});
}
}
});
},
// 开始孔商品处理
startPddProcessing() {
if (this.pddProcessing) {
return;
}
// 获取新商品ID列表
const newItemIds = getNewItemIds();
if (!newItemIds || newItemIds.length === 0) {
uni.showToast({
title: '没有找到新商品ID请先完成商品处理',
icon: 'none'
});
this.log('孔处理失败: 没有找到新商品ID');
return;
}
// 检查是否有对应的旧商品ID
if (!this.itemList || this.itemList.length === 0) {
uni.showToast({
title: '没有找到原始商品列表,请先拉取商品',
icon: 'none'
});
this.log('孔处理失败: 没有找到原始商品列表');
return;
}
this.pddProcessing = true;
this.pddStatus = '处理中...';
this.pddProcessedItems = [];
this.log('开始孔商品处理...');
this.log(`找到 ${newItemIds.length} 个新商品ID`);
this.log(`原始商品列表包含 ${this.itemList.length} 个商品`);
// 构建ID对应关系 - 使用存储的映射关系而不是索引匹配
const idMappings = [];
// 遍历新商品ID列表每个项目现在包含oldId和newId的映射
for (const item of newItemIds) {
// 严格校验oldId和newId都不为空
if (item.oldId && item.newId &&
String(item.oldId).trim() !== '' &&
String(item.newId).trim() !== '') {
idMappings.push({
oldPlatformId: String(item.oldId),
newPlatformId: String(item.newId)
});
} else {
// 记录跳过的无效数据
this.log(`跳过无效数据: oldId=${item.oldId || '空'}, newId=${item.newId || '空'}`);
}
}
if (idMappings.length === 0) {
this.pddProcessing = false;
this.pddStatus = '处理失败';
uni.showToast({
title: '没有找到有效的ID对应关系',
icon: 'none'
});
this.log('孔处理失败: 没有找到有效的ID对应关系');
return;
}
this.pddProgressText = `0/${idMappings.length}`;
this.log(`准备处理 ${idMappings.length} 个商品ID对应关系`);
// 调用批量更新接口
this.processPddBatch(idMappings);
},
// 处理单个商品的孔平台ID更新
processSinglePddItem(oldItemId) {
return new Promise((resolve, reject) => {
// 获取新商品ID列表
const newItemIds = getNewItemIds();
if (!newItemIds || newItemIds.length === 0) {
reject(new Error('没有找到新商品ID记录'));
return;
}
// 查找对应的新商品ID
const matchedItem = newItemIds.find(item =>
item.oldId && String(item.oldId).trim() === String(oldItemId).trim()
);
if (!matchedItem || !matchedItem.newId || String(matchedItem.newId).trim() === '') {
reject(new Error(`未找到商品 ${oldItemId} 对应的新商品ID`));
return;
}
// 构建单个商品的ID映射
const idMapping = [{
oldPlatformId: String(matchedItem.oldId),
newPlatformId: String(matchedItem.newId)
}];
this.log(`找到商品 ${oldItemId} 对应的新ID: ${matchedItem.newId}`);
// 调用批量更新接口(虽然只有一个商品)
batchUpdatePddPlatformId(idMapping)
.then(result => {
if (result.success) {
this.log(`商品 ${oldItemId} 孔平台ID更新成功`);
resolve(result);
} else {
reject(new Error(result.message || '更新失败'));
}
})
.catch(err => {
reject(err);
});
});
},
// 处理孔批量更新
processPddBatch(idMappings) {
this.pddCurrentItemText = `正在批量更新 ${idMappings.length} 个商品...`;
batchUpdatePddPlatformId(idMappings)
.then(result => {
if (result.success) {
this.pddStatus = '处理完成';
this.pddProgressText = `${idMappings.length}/${idMappings.length}`;
this.pddCurrentItemText = '批量更新完成';
this.log(`孔商品处理成功: ${result.message}`);
this.log(`成功更新 ${idMappings.length} 个商品的平台ID`);
// 显示处理结果
uni.showToast({
title: '孔商品处理完成',
icon: 'success'
});
// 保存处理记录
this.pddProcessedItems = idMappings;
} else {
this.pddStatus = '处理失败';
this.pddCurrentItemText = '批量更新失败';
this.log(`孔商品处理失败: ${result.message}`);
uni.showToast({
title: `处理失败: ${result.message}`,
icon: 'none'
});
}
})
.catch(err => {
this.pddStatus = '处理失败';
this.pddCurrentItemText = '批量更新出错';
this.log(`孔商品处理出错: ${err.message}`);
uni.showToast({
title: `处理出错: ${err.message}`,
icon: 'none'
});
})
.finally(() => {
this.pddProcessing = false;
});
},
// 格式化时间
formatTime(timeStr) {
try {
const date = new Date(timeStr);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
} catch (e) {
return timeStr;
}
}
}
};
</script>
<style lang="scss">
@import "./index.scss";
</style>