同步列表
Some checks failed
CI / build (18.x) (push) Failing after 33m30s
CI / build (20.x) (push) Failing after 1m35s
CI / deploy-preview (push) Has been skipped
CI / lint (push) Failing after 34s
CI / test (push) Failing after 15s
CI / security (push) Failing after 34s

This commit is contained in:
97694731 2026-06-29 14:52:02 +08:00
parent 62e3781ecf
commit fac91a81e2
19 changed files with 359 additions and 54 deletions

View File

@ -1,71 +1,71 @@
{
"hash": "780fd6b7",
"browserHash": "11a50aed",
"hash": "7466b81f",
"browserHash": "72dd502f",
"optimized": {
"@element-plus/icons-vue": {
"src": "../../@element-plus/icons-vue/dist/index.js",
"file": "@element-plus_icons-vue.js",
"fileHash": "e73a6617",
"fileHash": "a827a77d",
"needsInterop": false
},
"axios": {
"src": "../../axios/index.js",
"file": "axios.js",
"fileHash": "9ada0434",
"fileHash": "563efb6a",
"needsInterop": false
},
"crypto-js": {
"src": "../../crypto-js/index.js",
"file": "crypto-js.js",
"fileHash": "35b4399e",
"fileHash": "70871dfd",
"needsInterop": true
},
"dayjs": {
"src": "../../dayjs/dayjs.min.js",
"file": "dayjs.js",
"fileHash": "3c458ca9",
"fileHash": "330e0aa9",
"needsInterop": true
},
"element-plus": {
"src": "../../element-plus/es/index.mjs",
"file": "element-plus.js",
"fileHash": "65c76065",
"fileHash": "c8723d93",
"needsInterop": false
},
"element-plus/es/locale/lang/zh-cn": {
"src": "../../element-plus/es/locale/lang/zh-cn.mjs",
"file": "element-plus_es_locale_lang_zh-cn.js",
"fileHash": "05b5b909",
"fileHash": "5d10d7a9",
"needsInterop": false
},
"jsbarcode": {
"src": "../../jsbarcode/bin/JsBarcode.js",
"file": "jsbarcode.js",
"fileHash": "d60441c9",
"fileHash": "5b45d96a",
"needsInterop": true
},
"json-bigint": {
"src": "../../json-bigint/index.js",
"file": "json-bigint.js",
"fileHash": "4eb91e5f",
"fileHash": "43b512d4",
"needsInterop": true
},
"pinia": {
"src": "../../pinia/dist/pinia.mjs",
"file": "pinia.js",
"fileHash": "461b0d9b",
"fileHash": "9078f52d",
"needsInterop": false
},
"vue": {
"src": "../../vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "aa9868f1",
"fileHash": "bd6fb29e",
"needsInterop": false
},
"vue-router": {
"src": "../../vue-router/dist/vue-router.mjs",
"file": "vue-router.js",
"fileHash": "010be937",
"fileHash": "d015433f",
"needsInterop": false
}
},

View File

@ -15,10 +15,12 @@ export const fetchTodayStats = async () => {
total_receiving_count: data?.total_receiving_count ?? 0,
total_outbound_count: data?.total_outbound_count ?? 0,
total_sale_count: data?.total_sale_count ?? 0,
today_sale_amount: data?.today_sale_amount ?? 0,
yesterday_order_count: data?.yesterday_order_count ?? 0,
yesterday_receiving_count: data?.yesterday_receiving_count ?? 0,
yesterday_outbound_count: data?.yesterday_outbound_count ?? 0,
yesterday_sale_count: data?.yesterday_sale_count ?? 0
yesterday_sale_count: data?.yesterday_sale_count ?? 0,
yesterday_sale_amount: data?.yesterday_sale_amount ?? 0
}
}
@ -41,7 +43,7 @@ export const fetchEmployeeStats = async () => {
/**
* 获取店铺信息列表
* @param {Object} params - { time_range?: string, store_name?: string }
* @returns {Promise<Array<{store_name: string, store_type: string, sale_count: number, outbound_count: number, receiving_count: number, order_count: number}>>}
* @returns {Promise<Array<{store_name: string, store_type: string, sale_amount: number, outbound_count: number, receiving_count: number, order_count: number}>>}
*/
export const fetchStoreInfo = async (params = {}) => {
const response = await request.get(`${ADMIN_BASE}/store-info`, { params })
@ -51,7 +53,7 @@ export const fetchStoreInfo = async (params = {}) => {
return (data?.data ?? []).map(item => ({
store_name: item.store_name ?? '-',
store_type: item.store_type ?? '-',
sale_count: item.sale_count ?? 0,
sale_amount: item.sale_amount ?? 0,
outbound_count: item.outbound_count ?? 0,
receiving_count: item.receiving_count ?? 0,
order_count: item.order_count ?? 0,

View File

@ -386,4 +386,15 @@ export const fetchDestroyLog = async ({ keyword, page, pageSize }) => {
export const restoreProduct = async ({ destroy_log_id }) => {
const response = await request.post(`${API_BASE}/restore`, { destroy_log_id })
return response.data
}
/**
* 从旺店通同步商品
* @param {Object} params
* @param {string} params.start_time - 开始时间 yyyy-MM-dd HH:mm:ss
* @param {string} params.end_time - 结束时间 yyyy-MM-dd HH:mm:ss
* @returns {Promise}
*/
export const syncGoodsFromWdt = async ({ start_time, end_time }) => {
return request.get('/wangdian/query-goods', { params: { start_time, end_time } })
}

View File

@ -122,3 +122,12 @@ export const releaseWave = async (data) => {
export const exportPurchaseOrderToWdt = async (params) => {
return request.get('/purchase-order/export-to-wdt', { params, responseType: 'blob' })
}
/**
* 创建采购单推送到旺店通
* @param {number} purchase_order_id - 采购单ID
* @returns {Promise} 接口返回的 Promise 对象
*/
export const pushPurchaseOrderToWdt = async (purchase_order_id) => {
return request.post('/wangdian/purchase-order-push', { purchase_order_id })
}

View File

@ -224,16 +224,27 @@ export const fetchExpressInfo = async (waybillNo) => {
}
/**
* 回收快递单号
* 回收快递单号旧接口 /logistics/cancel
* @param {Object} params
* @param {string|number} params.user_id - 用户ID
* @param {string} params.logistics_no - 物流单号
* @returns {Promise<Object>}
*/
export const recycleWaybillNo = async ({ user_id, logistics_no }) => {
const formData = new FormData()
formData.append('user_id', String(user_id))
formData.append('logistics_no', logistics_no)
const res = await request.post(`/logistics/cancel`, formData)
// export const recycleWaybillNo = async ({ user_id, logistics_no }) => {
// const formData = new FormData()
// formData.append('user_id', String(user_id))
// formData.append('logistics_no', logistics_no)
// const res = await request.post(`/logistics/cancel`, formData)
// return res.data
// }
/**
* 回收快递单号新接口 /print/cancelBmOrderApi
* @param {Object} params
* @param {string} params.mailNo - 快递单号
* @returns {Promise<Object>}
*/
export const recycleWaybillNo = async ({ mailNo }) => {
const res = await axios.post(`${PRINT_API_BASE}/api/print/cancelBmOrderApi`, { mailNo })
return res.data
}

View File

@ -83,4 +83,12 @@ export const updateSupplier = async (supplier) => {
*/
export const deleteSupplier = async (supplier) => {
return request.post(`${API_BASE}/delete`, supplier)
}
/**
* 同步供应商从旺店通拉取
* @returns {Promise} 接口返回的 Promise 对象
*/
export const syncSupplierFromWdt = async () => {
return request.get('/wangdian/query-provider')
}

28
src/api/wangdian.js Normal file
View File

@ -0,0 +1,28 @@
import request from '@/utils/request'
/**
* 标准化列表接口返回的数据格式
*/
const normalizeListResponse = (payload) => {
const data = payload?.data
if (!data) return { list: [], total: 0 }
if (Array.isArray(data)) return { list: data, total: data.length }
return {
list: Array.isArray(data.list) ? data.list : [],
total: typeof data.total === 'number' ? data.total : 0
}
}
/**
* 获取旺店通同步任务列表
* @param {Object} params
* @param {number} params.page - 当前页码
* @param {number} params.pageSize - 每页条数
* @returns {Promise<{list: Array, total: number}>}
*/
export const fetchSyncTaskList = async ({ page, pageSize }) => {
const response = await request.get('/wangdian/sync-task-list', {
params: { page, page_size: pageSize }
})
return normalizeListResponse(response)
}

View File

@ -107,4 +107,12 @@ export const updateWarehouse = async (warehouse) => {
*/
export const deleteWarehouse = async (warehouse) => {
return request.post(`${API_BASE}/delete`, warehouse)
}
/**
* 同步仓库从旺店通拉取
* @returns {Promise} 接口返回的 Promise 对象
*/
export const syncWarehouseFromWdt = async () => {
return request.get('/wangdian/query-warehouse')
}

View File

@ -29,6 +29,15 @@
<el-menu-item index="/admin/employee-type" @click="goTo('/admin/employee-type')">账户类型</el-menu-item>
</el-sub-menu>
<!-- 旺店通 -->
<el-sub-menu index="wangdian" v-if="userStore.adminUserInfo">
<template #title>
<el-icon><Connection /></el-icon>
<span>旺店通</span>
</template>
<el-menu-item index="/wangdian/sync-task" @click="goTo('/wangdian/sync-task')">同步列表</el-menu-item>
</el-sub-menu>
<!-- 分账管理 - 仅管理员可见 -->
<el-sub-menu index="splitAccount" v-if="userStore.userInfo.username == '18904056800'">
<template #title>
@ -297,7 +306,7 @@
<script setup>import { ref, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Monitor, Tickets, User, DataLine, List, Fold, Expand, ArrowDown, SwitchButton, Wallet, Money, Avatar, Tools, Upload, Box, Document, Setting, Van, Finished, Shop, Printer, Edit } from '@element-plus/icons-vue'
import { Monitor, Tickets, User, DataLine, List, Fold, Expand, ArrowDown, SwitchButton, Wallet, Money, Avatar, Tools, Upload, Box, Document, Setting, Van, Finished, Shop, Printer, Edit, Connection } from '@element-plus/icons-vue'
import { removeAdminToken, removeAdminUserInfo } from '@/utils/auth'
import { useUserStore } from '@/store/user'

View File

@ -197,7 +197,7 @@
<el-table-column prop="updated_at" label="更新时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.updated_at) }}</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" fixed="right">
<el-table-column label="操作" width="250" align="center" fixed="right">
<template #default="{ row }">
<el-button type="primary" link :icon="Edit" size="small" @click="handleEdit(row)">修改</el-button>
<el-tooltip v-if="row.warehouse_name" content="已落位商品不可删除" placement="top" :disabled="false">
@ -205,6 +205,7 @@
</el-tooltip>
<el-button v-else type="danger" link :icon="Delete" size="small" @click="handleDelete(row)">删除</el-button>
<el-button type="danger" link :icon="Delete" size="small" @click="handleDestroy(row)">销毁</el-button>
<el-button type="primary" link size="small" @click="handleSyncGoods(row)">同步商品</el-button>
</template>
</el-table-column>
</el-table>
@ -252,7 +253,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Refresh, MoreFilled, Upload, Edit, Delete } from '@element-plus/icons-vue'
import GoodsPop from '@/components/goodsPop/index.vue'
import dayjs from 'dayjs'
import { fetchProductList, retryProductPublish, importProductsByExcel, deleteProduct, destroyProduct } from '@/api/product'
import { fetchProductList, retryProductPublish, importProductsByExcel, deleteProduct, destroyProduct, syncGoodsFromWdt } from '@/api/product'
import { fetchWarehouseList } from '@/api/warehouse'
interface ShopListItem {
@ -481,6 +482,17 @@ export default defineComponent({
}).catch(() => { })
}
const handleSyncGoods = async (row: ProductItem): Promise<void> => {
const start_time = formatTimestamp(row.created_at)
const end_time = formatTimestamp(row.updated_at)
try {
await syncGoodsFromWdt({ start_time, end_time })
ElMessage.success({ message: '已同步,在任务管理里查看进度', customClass: 'scan-success-message' })
} catch {
ElMessage.error({ message: '同步失败', customClass: 'scan-error-message' })
}
}
const handleSelectionChange = (rows: ProductItem[]): void => {
selectedRows.value = rows
}
@ -567,7 +579,7 @@ export default defineComponent({
stats,
formatTimestamp, formatAppearance, getFirstImage, getImageList, showAllShopMsg,
handleSearch, resetSearch, handleCurrentChange, handleSizeChange,
handleEdit, handleDelete, reTryGoosTask, handleDestroy,
handleEdit, handleDelete, reTryGoosTask, handleDestroy, handleSyncGoods,
refreshList, selectedRows, handleSelectionChange,
//
importDialogVisible, importWarehouseId, importFile, importLoading, uploadRef, warehouseOptions,

View File

@ -22,6 +22,7 @@
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
<el-button :icon="Refresh" @click="resetSearch">重置</el-button>
<el-button type="success" :icon="Plus" @click="handleAdd">新增仓库</el-button>
<el-button type="warning" @click="handleSyncFromWdt">同步仓库</el-button>
</div>
<!-- 仓库列表表格支持单选行高亮占位行保持表格高度一致 -->
@ -316,7 +317,8 @@ import {
fetchWarehouseDetail,
createWarehouse,
updateWarehouse,
deleteWarehouse
deleteWarehouse,
syncWarehouseFromWdt
} from '@/api/warehouse'
import { fetchLogisticsList } from '@/api/logistics'
import { regionData } from './regionData'
@ -855,6 +857,17 @@ export default defineComponent({
Object.assign(formData, createDefaultFormData())
}
//
const handleSyncFromWdt = async (): Promise<void> => {
try {
await syncWarehouseFromWdt()
ElMessage.success({ message: '已同步,在任务管理里查看进度' })
refreshList()
} catch (error) {
ElMessage.error({ message: '同步失败', customClass: 'scan-error-message' })
}
}
//
const fetchLogisticsTemplates = async (): Promise<void> => {
logisticsLoading.value = true
@ -918,6 +931,7 @@ export default defineComponent({
handleDelete,
submitForm,
resetForm,
handleSyncFromWdt,
//
detailDialogVisible,
detailLoading,

View File

@ -109,6 +109,15 @@ const routes = [
// 普通用户也可访问
}
},
{
path: 'wangdian/sync-task',
name: 'wangdian-sync-task',
component: () => import('@/views/wangdian/syncTaskList.vue'),
meta: {
title: '同步列表',
requiresAuth: true
}
},
{
path: 'location',
name: 'location',

View File

@ -14,8 +14,8 @@ const USE_MOCK = false // 设置为true使用模拟数据
// 创建axios实例
const request = axios.create({
// baseURL: import.meta.env.DEV ? '/api' : (import.meta.env.VITE_API_BASE || 'http://127.0.0.1:9090/api'),
baseURL: import.meta.env.DEV ? '/api' : (import.meta.env.VITE_API_BASE || 'http://192.168.101.213:9090/api'),
// baseURL: import.meta.env.DEV ? '/api' : (import.meta.env.VITE_API_BASE || 'https://psi.api.buzhiyushu.cn/api'),
// baseURL: import.meta.env.DEV ? '/api' : (import.meta.env.VITE_API_BASE || 'http://192.168.101.213:9090/api'),
baseURL: import.meta.env.DEV ? '/api' : (import.meta.env.VITE_API_BASE || 'https://psi.api.buzhiyushu.cn/api'),
timeout: 10000,
// 用 JSONbig 替代默认 JSON.parse保留大整数精度
transformResponse: [

View File

@ -91,16 +91,16 @@
</div>
<div class="stat-info">
<div class="stat-title">今日销售</div>
<div class="stat-value">{{ todayStats.total_sale_count }}</div>
<div class="stat-desc">销售数量</div>
<div class="stat-value">{{ (todayStats.today_sale_amount / 100).toFixed(2) }}</div>
<div class="stat-desc">销售金额</div>
</div>
</div>
<div class="stat-divider"></div>
<div class="stat-sub">
<div class="stat-info">
<div class="stat-title">昨日销售</div>
<div class="stat-value">{{ yesterdayStats.yesterday_sale_count }}</div>
<div class="stat-desc">销售数量</div>
<div class="stat-value">{{ (yesterdayStats.yesterday_sale_amount / 100).toFixed(2) }}</div>
<div class="stat-desc">销售金额</div>
</div>
</div>
</div>
@ -209,9 +209,9 @@
<el-table-column prop="store_type" label="店铺类型" min-width="120" align="center">
<template #default="{ row }">{{ row.store_type || '-' }}</template>
</el-table-column>
<el-table-column prop="sale_count" label="销售数量" min-width="100" align="center">
<el-table-column prop="sale_amount" label="销售金额" min-width="110" align="center">
<template #default="{ row }">
<el-tag type="warning" size="small">{{ row.sale_count ?? 0 }}</el-tag>
<el-tag type="warning" size="small">¥{{ ((row.sale_amount ?? 0) / 100).toFixed(2) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="outbound_count" label="出库数量" min-width="100" align="center">
@ -255,7 +255,8 @@ const todayStats = ref({
total_order_count: 0,
total_receiving_count: 0,
total_outbound_count: 0,
total_sale_count: 0
total_sale_count: 0,
today_sale_amount: 0
})
//
@ -263,7 +264,8 @@ const yesterdayStats = ref({
yesterday_order_count: 0,
yesterday_receiving_count: 0,
yesterday_outbound_count: 0,
yesterday_sale_count: 0
yesterday_sale_count: 0,
yesterday_sale_amount: 0
})
//
@ -295,13 +297,15 @@ const loadTodayStats = async () => {
total_order_count: data.total_order_count,
total_receiving_count: data.total_receiving_count,
total_outbound_count: data.total_outbound_count,
total_sale_count: data.total_sale_count
total_sale_count: data.total_sale_count,
today_sale_amount: data.today_sale_amount
}
yesterdayStats.value = {
yesterday_order_count: data.yesterday_order_count,
yesterday_receiving_count: data.yesterday_receiving_count,
yesterday_outbound_count: data.yesterday_outbound_count,
yesterday_sale_count: data.yesterday_sale_count
yesterday_sale_count: data.yesterday_sale_count,
yesterday_sale_amount: data.yesterday_sale_amount
}
} catch (error) {
console.error('加载今日统计失败:', error)
@ -309,13 +313,15 @@ const loadTodayStats = async () => {
total_order_count: 0,
total_receiving_count: 0,
total_outbound_count: 0,
total_sale_count: 0
total_sale_count: 0,
today_sale_amount: 0
}
yesterdayStats.value = {
yesterday_order_count: 0,
yesterday_receiving_count: 0,
yesterday_outbound_count: 0,
yesterday_sale_count: 0
yesterday_sale_count: 0,
yesterday_sale_amount: 0
}
}
}

View File

@ -104,8 +104,9 @@
<el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip align="center">
<template #default="{ row }" >{{ row.remark || '-' }}</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right" align="center">
<el-table-column label="操作" width="200" fixed="right" align="center">
<template #default="{ row }">
<el-button type="primary" link @click="handlePushToWdt(row)">创建采购单</el-button>
<!-- <el-button type="primary" link :icon="Edit" @click="handleEdit(row)" :disabled="Number(row.status) >= 3">编辑</el-button> -->
<el-button type="danger" link :icon="Delete" @click="handleDelete(row)" :disabled="Number(row.status) >= 2">删除</el-button>
</template>
@ -131,7 +132,7 @@ import { defineComponent, ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Refresh, Plus, Edit, Delete, View, Loading } from '@element-plus/icons-vue'
import dayjs from 'dayjs'
import { fetchPurchaseOrderList, fetchPurchaseOrderDetail, createPurchaseOrder, updatePurchaseOrder, deletePurchaseOrder, exportPurchaseOrderToWdt } from '@/api/purchaseOrder'
import { fetchPurchaseOrderList, fetchPurchaseOrderDetail, createPurchaseOrder, updatePurchaseOrder, deletePurchaseOrder, exportPurchaseOrderToWdt, pushPurchaseOrderToWdt } from '@/api/purchaseOrder'
import { fetchSupplierList } from '@/api/supplier'
import { fetchWarehouseList } from '@/api/warehouse'
@ -335,6 +336,15 @@ export default defineComponent({
}).catch(() => {})
}
const handlePushToWdt = async (row: any): Promise<void> => {
try {
await pushPurchaseOrderToWdt(row.id)
ElMessage.success({ message: '已创建,在任务管理里查看进度', customClass: 'scan-success-message' })
} catch (error) {
ElMessage.error({ message: '创建采购单失败', customClass: 'scan-error-message' })
}
}
const handleExport = async (): Promise<void> => {
try {
const res = await exportPurchaseOrderToWdt({
@ -394,7 +404,7 @@ export default defineComponent({
statusLabel, statusTagType,
formatTimestamp, formatAmount,
handleSearch, resetSearch, handleCurrentChange, handleSizeChange,
handleExpandChange, handleView, handleDelete, handleExport, resetForm
handleExpandChange, handleView, handleDelete, handlePushToWdt, handleExport, resetForm
}
}
})

View File

@ -1031,14 +1031,8 @@ export default defineComponent({
/** 回收快递单号 */
const handleRecycleWaybill = async (item: any) => {
if (!item?.logistics_no) return
const userInfo = JSON.parse(localStorage.getItem('admin_userInfo') || '{}')
const userId = userInfo?.about_id
if (!userId) {
ElMessage.error({ message: '未获取到用户信息', customClass: 'scan-error-message' })
return
}
try {
await recycleWaybillNo({ user_id: userId, logistics_no: item.logistics_no })
await recycleWaybillNo({ mailNo: item.logistics_no })
ElMessage.success({ message: `快递单 ${item.logistics_no} 已回收`, customClass: 'scan-success-message' })
//
detailCache.value = {}

View File

@ -19,6 +19,7 @@
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
<el-button :icon="Refresh" @click="resetSearch">重置</el-button>
<el-button type="success" :icon="Plus" @click="handleAdd">新增供应商</el-button>
<el-button type="warning" @click="handleSyncFromWdt">同步供应商</el-button>
</div>
<el-table :data="tableData" v-loading="loading" border stripe style="width: 100%">
@ -129,7 +130,8 @@ import {
fetchSupplierDetail,
createSupplier,
updateSupplier,
deleteSupplier
deleteSupplier,
syncSupplierFromWdt
} from '@/api/supplier'
interface SupplierItem {
@ -380,6 +382,15 @@ export default defineComponent({
}).catch(() => {})
}
const handleSyncFromWdt = async (): Promise<void> => {
try {
await syncSupplierFromWdt()
ElMessage.success({ message: '已同步,在任务管理里查看进度', customClass: 'scan-success-message' })
} catch (error) {
ElMessage.error({ message: '同步供应商失败', customClass: 'scan-error-message' })
}
}
const submitForm = async (): Promise<void> => {
try {
await formRef.value?.validate()
@ -453,6 +464,7 @@ export default defineComponent({
handleDetail,
handleEdit,
handleDelete,
handleSyncFromWdt,
submitForm,
resetForm
}

View File

@ -0,0 +1,162 @@
<template>
<el-card class="sync-task-manager">
<template #header>
<div class="card-header">旺店通同步列表</div>
</template>
<el-table :data="tableData" v-loading="loading" border stripe style="width: 100%">
<el-table-column prop="task_type" label="任务类型" width="140" align="center">
<template #default="{ row }">
<el-tag size="small">{{ taskTypeLabel(row.task_type) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="statusTagType(row.status)" size="small">
{{ statusLabel(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="progress" label="已处理" width="100" align="center" />
<el-table-column prop="total" label="总数" width="100" align="center" />
<el-table-column prop="error_msg" label="错误信息" min-width="200" show-overflow-tooltip align="center">
<template #default="{ row }">{{ row.error_msg || '-' }}</template>
</el-table-column>
<el-table-column label="开始时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.started_at) }}</template>
</el-table-column>
<el-table-column label="完成时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.finished_at) }}</template>
</el-table-column>
<el-table-column label="创建时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.created_at) }}</template>
</el-table-column>
<el-table-column label="更新时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.updated_at) }}</template>
</el-table-column>
</el-table>
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-card>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, onMounted } from 'vue'
import dayjs from 'dayjs'
import { fetchSyncTaskList } from '@/api/wangdian'
const TASK_TYPE_MAP: Record<string, string> = {
purchase_push: '采购单推送',
sync_provider: '同步供应商',
sync_warehouse: '同步仓库',
sync_goods: '同步商品'
}
const STATUS_MAP: Record<string, { label: string; type: string }> = {
running: { label: '运行中', type: 'warning' },
completed: { label: '已完成', type: 'success' },
cancelled: { label: '已取消', type: 'info' },
failed: { label: '失败', type: 'danger' }
}
export default defineComponent({
name: 'SyncTaskList',
setup() {
const loading = ref<boolean>(false)
const tableData = ref<any[]>([])
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0
})
const taskTypeLabel = (type: string): string => TASK_TYPE_MAP[type] || type
const statusLabel = (status: string): string => STATUS_MAP[status]?.label || status
const statusTagType = (status: string): string => STATUS_MAP[status]?.type || 'info'
const formatTimestamp = (timestamp?: number | string | null): string => {
if (!timestamp && timestamp !== 0) return '-'
const num = Number(timestamp)
if (num === 0) return '-'
return dayjs.unix(num).format('YYYY-MM-DD HH:mm:ss')
}
const loadList = async (): Promise<void> => {
loading.value = true
try {
const res = await fetchSyncTaskList({
page: pagination.current,
pageSize: pagination.pageSize
})
tableData.value = res.list || []
pagination.total = res.total || 0
} catch {
tableData.value = []
pagination.total = 0
} finally {
loading.value = false
}
}
const handleCurrentChange = (page: number): void => {
pagination.current = page
void loadList()
}
const handleSizeChange = (size: number): void => {
pagination.pageSize = size
pagination.current = 1
void loadList()
}
onMounted(() => {
void loadList()
})
return {
loading, tableData, pagination,
taskTypeLabel, statusLabel, statusTagType,
formatTimestamp,
handleCurrentChange, handleSizeChange
}
}
})
</script>
<style scoped>
.sync-task-manager {
width: 100%;
}
.card-header {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.pagination-wrapper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
background: white;
padding: 14px 20px;
border-radius: 8px;
}
:deep(.el-table) {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
}
</style>

View File

@ -246,9 +246,9 @@ module.exports = defineConfig({
proxy: {
'/api': {
// target: 'http://127.0.0.1:9090',
target: 'http://192.168.101.213:9090',
// target: 'https://psi.api.buzhiyushu.cn',
// target: 'http://192.168.101.213:9090',
// target: 'https://psi.api.buzhiyushu.cn',
target: 'http://127.0.0.1:9090',
changeOrigin: true
},
'/api/print': {