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

View File

@ -15,10 +15,12 @@ export const fetchTodayStats = async () => {
total_receiving_count: data?.total_receiving_count ?? 0, total_receiving_count: data?.total_receiving_count ?? 0,
total_outbound_count: data?.total_outbound_count ?? 0, total_outbound_count: data?.total_outbound_count ?? 0,
total_sale_count: data?.total_sale_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_order_count: data?.yesterday_order_count ?? 0,
yesterday_receiving_count: data?.yesterday_receiving_count ?? 0, yesterday_receiving_count: data?.yesterday_receiving_count ?? 0,
yesterday_outbound_count: data?.yesterday_outbound_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 } * @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 = {}) => { export const fetchStoreInfo = async (params = {}) => {
const response = await request.get(`${ADMIN_BASE}/store-info`, { 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 => ({ return (data?.data ?? []).map(item => ({
store_name: item.store_name ?? '-', store_name: item.store_name ?? '-',
store_type: item.store_type ?? '-', store_type: item.store_type ?? '-',
sale_count: item.sale_count ?? 0, sale_amount: item.sale_amount ?? 0,
outbound_count: item.outbound_count ?? 0, outbound_count: item.outbound_count ?? 0,
receiving_count: item.receiving_count ?? 0, receiving_count: item.receiving_count ?? 0,
order_count: item.order_count ?? 0, order_count: item.order_count ?? 0,

View File

@ -387,3 +387,14 @@ export const restoreProduct = async ({ destroy_log_id }) => {
const response = await request.post(`${API_BASE}/restore`, { destroy_log_id }) const response = await request.post(`${API_BASE}/restore`, { destroy_log_id })
return response.data 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) => { export const exportPurchaseOrderToWdt = async (params) => {
return request.get('/purchase-order/export-to-wdt', { params, responseType: 'blob' }) 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 {Object} params
* @param {string|number} params.user_id - 用户ID * @param {string|number} params.user_id - 用户ID
* @param {string} params.logistics_no - 物流单号 * @param {string} params.logistics_no - 物流单号
* @returns {Promise<Object>} * @returns {Promise<Object>}
*/ */
export const recycleWaybillNo = async ({ user_id, logistics_no }) => { // export const recycleWaybillNo = async ({ user_id, logistics_no }) => {
const formData = new FormData() // const formData = new FormData()
formData.append('user_id', String(user_id)) // formData.append('user_id', String(user_id))
formData.append('logistics_no', logistics_no) // formData.append('logistics_no', logistics_no)
const res = await request.post(`/logistics/cancel`, formData) // 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 return res.data
} }

View File

@ -84,3 +84,11 @@ export const updateSupplier = async (supplier) => {
export const deleteSupplier = async (supplier) => { export const deleteSupplier = async (supplier) => {
return request.post(`${API_BASE}/delete`, 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

@ -108,3 +108,11 @@ export const updateWarehouse = async (warehouse) => {
export const deleteWarehouse = async (warehouse) => { export const deleteWarehouse = async (warehouse) => {
return request.post(`${API_BASE}/delete`, 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-menu-item index="/admin/employee-type" @click="goTo('/admin/employee-type')">账户类型</el-menu-item>
</el-sub-menu> </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'"> <el-sub-menu index="splitAccount" v-if="userStore.userInfo.username == '18904056800'">
<template #title> <template #title>
@ -297,7 +306,7 @@
<script setup>import { ref, computed } from 'vue' <script setup>import { ref, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus' 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 { removeAdminToken, removeAdminUserInfo } from '@/utils/auth'
import { useUserStore } from '@/store/user' import { useUserStore } from '@/store/user'

View File

@ -197,7 +197,7 @@
<el-table-column prop="updated_at" label="更新时间" width="170" align="center"> <el-table-column prop="updated_at" label="更新时间" width="170" align="center">
<template #default="{ row }">{{ formatTimestamp(row.updated_at) }}</template> <template #default="{ row }">{{ formatTimestamp(row.updated_at) }}</template>
</el-table-column> </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 }"> <template #default="{ row }">
<el-button type="primary" link :icon="Edit" size="small" @click="handleEdit(row)">修改</el-button> <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"> <el-tooltip v-if="row.warehouse_name" content="已落位商品不可删除" placement="top" :disabled="false">
@ -205,6 +205,7 @@
</el-tooltip> </el-tooltip>
<el-button v-else type="danger" link :icon="Delete" size="small" @click="handleDelete(row)">删除</el-button> <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="danger" link :icon="Delete" size="small" @click="handleDestroy(row)">销毁</el-button>
<el-button type="primary" link size="small" @click="handleSyncGoods(row)">同步商品</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </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 { Search, Refresh, MoreFilled, Upload, Edit, Delete } from '@element-plus/icons-vue'
import GoodsPop from '@/components/goodsPop/index.vue' import GoodsPop from '@/components/goodsPop/index.vue'
import dayjs from 'dayjs' 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' import { fetchWarehouseList } from '@/api/warehouse'
interface ShopListItem { interface ShopListItem {
@ -481,6 +482,17 @@ export default defineComponent({
}).catch(() => { }) }).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 => { const handleSelectionChange = (rows: ProductItem[]): void => {
selectedRows.value = rows selectedRows.value = rows
} }
@ -567,7 +579,7 @@ export default defineComponent({
stats, stats,
formatTimestamp, formatAppearance, getFirstImage, getImageList, showAllShopMsg, formatTimestamp, formatAppearance, getFirstImage, getImageList, showAllShopMsg,
handleSearch, resetSearch, handleCurrentChange, handleSizeChange, handleSearch, resetSearch, handleCurrentChange, handleSizeChange,
handleEdit, handleDelete, reTryGoosTask, handleDestroy, handleEdit, handleDelete, reTryGoosTask, handleDestroy, handleSyncGoods,
refreshList, selectedRows, handleSelectionChange, refreshList, selectedRows, handleSelectionChange,
// //
importDialogVisible, importWarehouseId, importFile, importLoading, uploadRef, warehouseOptions, importDialogVisible, importWarehouseId, importFile, importLoading, uploadRef, warehouseOptions,

View File

@ -22,6 +22,7 @@
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button> <el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
<el-button :icon="Refresh" @click="resetSearch">重置</el-button> <el-button :icon="Refresh" @click="resetSearch">重置</el-button>
<el-button type="success" :icon="Plus" @click="handleAdd">新增仓库</el-button> <el-button type="success" :icon="Plus" @click="handleAdd">新增仓库</el-button>
<el-button type="warning" @click="handleSyncFromWdt">同步仓库</el-button>
</div> </div>
<!-- 仓库列表表格支持单选行高亮占位行保持表格高度一致 --> <!-- 仓库列表表格支持单选行高亮占位行保持表格高度一致 -->
@ -316,7 +317,8 @@ import {
fetchWarehouseDetail, fetchWarehouseDetail,
createWarehouse, createWarehouse,
updateWarehouse, updateWarehouse,
deleteWarehouse deleteWarehouse,
syncWarehouseFromWdt
} from '@/api/warehouse' } from '@/api/warehouse'
import { fetchLogisticsList } from '@/api/logistics' import { fetchLogisticsList } from '@/api/logistics'
import { regionData } from './regionData' import { regionData } from './regionData'
@ -855,6 +857,17 @@ export default defineComponent({
Object.assign(formData, createDefaultFormData()) 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> => { const fetchLogisticsTemplates = async (): Promise<void> => {
logisticsLoading.value = true logisticsLoading.value = true
@ -918,6 +931,7 @@ export default defineComponent({
handleDelete, handleDelete,
submitForm, submitForm,
resetForm, resetForm,
handleSyncFromWdt,
// //
detailDialogVisible, detailDialogVisible,
detailLoading, 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', path: 'location',
name: 'location', name: 'location',

View File

@ -14,8 +14,8 @@ const USE_MOCK = false // 设置为true使用模拟数据
// 创建axios实例 // 创建axios实例
const request = axios.create({ 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://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 || '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 || 'https://psi.api.buzhiyushu.cn/api'),
timeout: 10000, timeout: 10000,
// 用 JSONbig 替代默认 JSON.parse保留大整数精度 // 用 JSONbig 替代默认 JSON.parse保留大整数精度
transformResponse: [ transformResponse: [

View File

@ -91,16 +91,16 @@
</div> </div>
<div class="stat-info"> <div class="stat-info">
<div class="stat-title">今日销售</div> <div class="stat-title">今日销售</div>
<div class="stat-value">{{ todayStats.total_sale_count }}</div> <div class="stat-value">{{ (todayStats.today_sale_amount / 100).toFixed(2) }}</div>
<div class="stat-desc">销售数量</div> <div class="stat-desc">销售金额</div>
</div> </div>
</div> </div>
<div class="stat-divider"></div> <div class="stat-divider"></div>
<div class="stat-sub"> <div class="stat-sub">
<div class="stat-info"> <div class="stat-info">
<div class="stat-title">昨日销售</div> <div class="stat-title">昨日销售</div>
<div class="stat-value">{{ yesterdayStats.yesterday_sale_count }}</div> <div class="stat-value">{{ (yesterdayStats.yesterday_sale_amount / 100).toFixed(2) }}</div>
<div class="stat-desc">销售数量</div> <div class="stat-desc">销售金额</div>
</div> </div>
</div> </div>
</div> </div>
@ -209,9 +209,9 @@
<el-table-column prop="store_type" label="店铺类型" min-width="120" align="center"> <el-table-column prop="store_type" label="店铺类型" min-width="120" align="center">
<template #default="{ row }">{{ row.store_type || '-' }}</template> <template #default="{ row }">{{ row.store_type || '-' }}</template>
</el-table-column> </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 }"> <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> </template>
</el-table-column> </el-table-column>
<el-table-column prop="outbound_count" label="出库数量" min-width="100" align="center"> <el-table-column prop="outbound_count" label="出库数量" min-width="100" align="center">
@ -255,7 +255,8 @@ const todayStats = ref({
total_order_count: 0, total_order_count: 0,
total_receiving_count: 0, total_receiving_count: 0,
total_outbound_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_order_count: 0,
yesterday_receiving_count: 0, yesterday_receiving_count: 0,
yesterday_outbound_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_order_count: data.total_order_count,
total_receiving_count: data.total_receiving_count, total_receiving_count: data.total_receiving_count,
total_outbound_count: data.total_outbound_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 = { yesterdayStats.value = {
yesterday_order_count: data.yesterday_order_count, yesterday_order_count: data.yesterday_order_count,
yesterday_receiving_count: data.yesterday_receiving_count, yesterday_receiving_count: data.yesterday_receiving_count,
yesterday_outbound_count: data.yesterday_outbound_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) { } catch (error) {
console.error('加载今日统计失败:', error) console.error('加载今日统计失败:', error)
@ -309,13 +313,15 @@ const loadTodayStats = async () => {
total_order_count: 0, total_order_count: 0,
total_receiving_count: 0, total_receiving_count: 0,
total_outbound_count: 0, total_outbound_count: 0,
total_sale_count: 0 total_sale_count: 0,
today_sale_amount: 0
} }
yesterdayStats.value = { yesterdayStats.value = {
yesterday_order_count: 0, yesterday_order_count: 0,
yesterday_receiving_count: 0, yesterday_receiving_count: 0,
yesterday_outbound_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"> <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip align="center">
<template #default="{ row }" >{{ row.remark || '-' }}</template> <template #default="{ row }" >{{ row.remark || '-' }}</template>
</el-table-column> </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 }"> <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="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> <el-button type="danger" link :icon="Delete" @click="handleDelete(row)" :disabled="Number(row.status) >= 2">删除</el-button>
</template> </template>
@ -131,7 +132,7 @@ import { defineComponent, ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Refresh, Plus, Edit, Delete, View, Loading } from '@element-plus/icons-vue' import { Search, Refresh, Plus, Edit, Delete, View, Loading } from '@element-plus/icons-vue'
import dayjs from 'dayjs' 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 { fetchSupplierList } from '@/api/supplier'
import { fetchWarehouseList } from '@/api/warehouse' import { fetchWarehouseList } from '@/api/warehouse'
@ -335,6 +336,15 @@ export default defineComponent({
}).catch(() => {}) }).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> => { const handleExport = async (): Promise<void> => {
try { try {
const res = await exportPurchaseOrderToWdt({ const res = await exportPurchaseOrderToWdt({
@ -394,7 +404,7 @@ export default defineComponent({
statusLabel, statusTagType, statusLabel, statusTagType,
formatTimestamp, formatAmount, formatTimestamp, formatAmount,
handleSearch, resetSearch, handleCurrentChange, handleSizeChange, 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) => { const handleRecycleWaybill = async (item: any) => {
if (!item?.logistics_no) return 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 { 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' }) ElMessage.success({ message: `快递单 ${item.logistics_no} 已回收`, customClass: 'scan-success-message' })
// //
detailCache.value = {} detailCache.value = {}

View File

@ -19,6 +19,7 @@
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button> <el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
<el-button :icon="Refresh" @click="resetSearch">重置</el-button> <el-button :icon="Refresh" @click="resetSearch">重置</el-button>
<el-button type="success" :icon="Plus" @click="handleAdd">新增供应商</el-button> <el-button type="success" :icon="Plus" @click="handleAdd">新增供应商</el-button>
<el-button type="warning" @click="handleSyncFromWdt">同步供应商</el-button>
</div> </div>
<el-table :data="tableData" v-loading="loading" border stripe style="width: 100%"> <el-table :data="tableData" v-loading="loading" border stripe style="width: 100%">
@ -129,7 +130,8 @@ import {
fetchSupplierDetail, fetchSupplierDetail,
createSupplier, createSupplier,
updateSupplier, updateSupplier,
deleteSupplier deleteSupplier,
syncSupplierFromWdt
} from '@/api/supplier' } from '@/api/supplier'
interface SupplierItem { interface SupplierItem {
@ -380,6 +382,15 @@ export default defineComponent({
}).catch(() => {}) }).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> => { const submitForm = async (): Promise<void> => {
try { try {
await formRef.value?.validate() await formRef.value?.validate()
@ -453,6 +464,7 @@ export default defineComponent({
handleDetail, handleDetail,
handleEdit, handleEdit,
handleDelete, handleDelete,
handleSyncFromWdt,
submitForm, submitForm,
resetForm 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: { proxy: {
'/api': { '/api': {
// target: 'http://127.0.0.1:9090', // target: 'http://127.0.0.1:9090',
target: 'http://192.168.101.213:9090', // target: 'http://192.168.101.213:9090',
// target: 'https://psi.api.buzhiyushu.cn',
// target: 'https://psi.api.buzhiyushu.cn', // target: 'https://psi.api.buzhiyushu.cn',
target: 'http://127.0.0.1:9090',
changeOrigin: true changeOrigin: true
}, },
'/api/print': { '/api/print': {