This commit is contained in:
2025-09-30 09:42:43 +08:00
parent 9719228d6d
commit c5ac27cdec
15 changed files with 222 additions and 139 deletions

View File

@@ -2,6 +2,7 @@
import { ref, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { amazonApi } from '../../api/amazon'
import { handlePlatformFileExport } from '../../utils/settings'
// 响应式状态
const loading = ref(false) // 主加载状态
@@ -196,11 +197,9 @@ async function exportToExcel() {
html += '</table>'
const blob = new Blob([html], { type: 'application/vnd.ms-excel' })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = `Amazon产品数据_${new Date().toISOString().slice(0, 10)}.xls`
link.click()
URL.revokeObjectURL(link.href)
const fileName = `Amazon产品数据_${new Date().toISOString().slice(0, 10)}.xls`
await handlePlatformFileExport('amazon', blob, fileName)
clearInterval(progressInterval)
exportProgress.value = 100

View File

@@ -10,7 +10,7 @@ interface Props {
interface Emits {
(e: 'update:modelValue', value: boolean): void
(e: 'registerSuccess'): void
(e: 'loginSuccess', data: { token: string; user: any }): void
(e: 'backToLogin'): void
}
@@ -53,12 +53,25 @@ async function handleRegister() {
registerLoading.value = true
try {
const result = await authApi.register({
// 1. 注册
await authApi.register({
username: registerForm.value.username,
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()
} catch (err) {
ElMessage.error((err as Error).message)

View File

@@ -6,7 +6,7 @@ import { ElMessageBox, ElMessage } from 'element-plus'
type PlatformKey = 'zebra' | 'shopee' | 'rakuten' | 'amazon'
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 curPlatform = ref<PlatformKey>(props.platform || 'zebra')
const PLATFORM_LABEL: Record<PlatformKey, string> = {
@@ -23,6 +23,9 @@ async function load() {
const list = (res as any)?.data ?? res
accounts.value = Array.isArray(list) ? list : []
}
// 暴露方法供父组件调用
defineExpose({ load })
onMounted(load)
function switchPlatform(p: PlatformKey) {
@@ -38,11 +41,12 @@ function formatDate(a: any) {
async function onDelete(a: any) {
const id = a?.id
try {
await ElMessageBox.confirm(`确定删除账号 ${a?.name || a?.username || id} 吗?`, '提示', { type: 'warning' })
await ElMessageBox.confirm(`确定删除账号 "${a?.name || a?.username || id}" 吗?`, '提示', { type: 'warning' })
} catch { return }
await zebraApi.removeAccount(id)
ElMessage({ message: '删除成功', type: 'success' })
await load()
emit('refresh') // 通知外层组件刷新账号列表
}
</script>

View File

@@ -106,11 +106,13 @@ type Stage = 'check' | 'downloading' | 'completed'
const stage = ref<Stage>('check')
const appName = ref('我了个电商')
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({
latestVersion: '2.4.8',
downloadUrl: '',
updateNotes: '• 优化了用户界面体验\n• 修复了已知问题\n• 提升了系统稳定性\n• 增加了新的功能模块\n• 优化了数据处理性能'
updateNotes: '• 优化了用户界面体验\n• 修复了已知问题\n• 提升了系统稳定性\n• 增加了新的功能模块\n• 优化了数据处理性能',
currentVersion: '',
hasUpdate: false
})
async function autoCheck() {
@@ -143,26 +145,24 @@ async function autoCheck() {
async function start() {
if (!info.value.downloadUrl) {
ElMessage({ message: '下载链接不可用', type: 'error' })
return
ElMessage({ message: '下载链接不可用', type: 'error' });
return;
}
stage.value = 'downloading'
prog.value = { percentage: 0, current: '0 MB', total: '0 MB', speed: '' }
stage.value = 'downloading';
prog.value = { percentage: 0, current: '0 MB', total: '0 MB', speed: '' };
window.electronAPI.onDownloadProgress((progress) => {
(window as any).electronAPI.onDownloadProgress((progress: any) => {
prog.value = {
percentage: progress.percentage || 0,
current: progress.current || '0 MB',
total: progress.total || '0 MB',
speed: progress.speed || ''
}
})
};
});
try {
const response = await window.electronAPI.downloadUpdate(info.value.downloadUrl)
const response = await (window as any).electronAPI.downloadUpdate(info.value.downloadUrl)
if (response.success) {
stage.value = 'completed'
@@ -181,10 +181,8 @@ async function start() {
async function cancelDownload() {
try {
if (window.electronAPI) {
window.electronAPI.removeDownloadProgressListener()
await window.electronAPI.cancelDownload()
}
(window as any).electronAPI.removeDownloadProgressListener()
await (window as any).electronAPI.cancelDownload()
show.value = false
stage.value = 'check'
} catch (error) {
@@ -205,7 +203,7 @@ async function installUpdate() {
type: 'warning'
}
)
const response = await window.electronAPI.installUpdate()
const response = await (window as any).electronAPI.installUpdate()
if (response.success) {
ElMessage({ message: '应用即将重启', type: 'success' })
@@ -231,9 +229,7 @@ onMounted(async () => {
})
onUnmounted(() => {
if (window.electronAPI) {
window.electronAPI.removeDownloadProgressListener()
}
(window as any).electronAPI.removeDownloadProgressListener()
})
</script>

View File

@@ -13,6 +13,7 @@ interface Emits {
(e: 'reload'): void
(e: 'user-click'): void
(e: 'open-device'): void
(e: 'open-settings'): void
}
defineProps<Props>()
@@ -45,7 +46,7 @@ defineEmits<Emits>()
<button class="nav-btn-round" title="设备管理" @click="$emit('open-device')">
<el-icon><Monitor /></el-icon>
</button>
<button class="nav-btn-round" title="设置">
<button class="nav-btn-round" title="设置" @click="$emit('open-settings')">
<el-icon><Setting /></el-icon>
</button>
<button class="nav-btn-round" title="用户" @click="$emit('user-click')">

View File

@@ -3,6 +3,7 @@ import {ref, computed, onMounted} from 'vue'
import { ElMessage } from 'element-plus'
import {rakutenApi} from '../../api/rakuten'
import { batchConvertImages } from '../../utils/imageProxy'
import { handlePlatformFileExport } from '../../utils/settings'
// UI 与加载状态
const loading = ref(false)
@@ -200,10 +201,15 @@ async function handleStartSearch() {
progressPercentage.value = 0
totalProducts.value = 0
processedProducts.value = 0
const resp = await rakutenApi.getProducts({file: pendingFile.value, batchId: currentBatchId.value})
const products = (resp.products || []).map(p => ({...p, skuPrices: parseSkuPrices(p)}))
allProducts.value = products
pendingFile.value = null
const resp = await rakutenApi.getProducts({file: pendingFile.value, batchId: currentBatchId.value})
const products = (resp.products || []).map(p => ({...p, skuPrices: parseSkuPrices(p)}))
if (products.length === 0) {
showMessage('未采集到数据,请检查代理或店铺是否存在', 'warning')
}
allProducts.value = products
pendingFile.value = null
} catch (e) {
statusType.value = 'error'
statusMessage.value = '解析失败,请重试'
@@ -367,12 +373,9 @@ async function exportToExcel() {
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
const fileName = `乐天商品数据_${new Date().toISOString().slice(0, 10)}.xlsx`
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = `乐天商品数据_${new Date().toISOString().slice(0, 10)}.xlsx`
link.click()
URL.revokeObjectURL(link.href)
await handlePlatformFileExport('rakuten', blob, fileName)
showMessage('Excel文件导出成功', 'success')
} 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="dz-el-icon">📤</div>
<div class="dz-text">点击或将文件拖拽到这里上传</div>
<div class="dz-sub">支持扩展名.xls .xlsx</div>
<div class="dz-sub">文件单列1/1</div>
<div class="dz-sub">支持 .xls .xlsx</div>
</div>
<input ref="uploadInputRef" style="display:none" type="file" accept=".xls,.xlsx" @change="handleExcelUpload" :disabled="loading"/>
<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; }
.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.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-sub { color: #909399; font-size: 12px; }
.single-input.left { display: flex; gap: 8px; }

View File

@@ -4,6 +4,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { zebraApi, type ZebraOrder, type BanmaAccount } from '../../api/zebra'
import AccountManager from '../common/AccountManager.vue'
import { batchConvertImages } from '../../utils/imageProxy'
import { handlePlatformFileExport } from '../../utils/settings'
type Shop = { id: string; shopName: string }
@@ -234,12 +235,9 @@ async function exportToExcel() {
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
const fileName = `斑马订单数据_${new Date().toISOString().slice(0, 10)}.xlsx`
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = `斑马订单数据_${new Date().toISOString().slice(0, 10)}.xlsx`
link.click()
URL.revokeObjectURL(link.href)
await handlePlatformFileExport('zebra', blob, fileName)
showMessage('Excel文件导出成功', 'success')
} catch (error) {
@@ -266,6 +264,7 @@ const formUsername = ref('')
const formPassword = ref('')
const rememberPwd = ref(true)
const managerVisible = ref(false)
const accountManagerRef = ref()
function openAddAccount() {
isEditMode.value = false
@@ -302,6 +301,9 @@ async function submitAccount() {
accountDialogVisible.value = false
await loadAccounts()
if (id) accountId.value = id
if (managerVisible.value && accountManagerRef.value?.load) {
accountManagerRef.value.load()
}
} catch (e: any) {
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>
</template>
</el-dialog>
<AccountManager v-model="managerVisible" platform="zebra" @add="openAddAccount" />
<AccountManager ref="accountManagerRef" v-model="managerVisible" platform="zebra" @add="openAddAccount" @refresh="loadAccounts" />
</div>
</template>