newadmin
This commit is contained in:
parent
263a27c6a4
commit
188dbedbe6
86
src/api/modules/audit.js
Normal file
86
src/api/modules/audit.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import request from '@/utils/axios'
|
||||||
|
|
||||||
|
// 查询审核列表
|
||||||
|
export const getAuditList = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出审核列表
|
||||||
|
export const exportAudit = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit/export',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取审核详细信息
|
||||||
|
export const getAuditById = (id) => {
|
||||||
|
return request({
|
||||||
|
url: `/zhishu/audit/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增审核
|
||||||
|
export const addAudit = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改审核
|
||||||
|
export const updateAudit = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除审核
|
||||||
|
export const deleteAudit = (ids) => {
|
||||||
|
return request({
|
||||||
|
url: `/zhishu/audit/${ids}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改审核通过状态
|
||||||
|
export const updateAuditStatus = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit/updateStatus',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改审核未通过状态
|
||||||
|
export const failSendAudit = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/audit/failSend',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审核API对象
|
||||||
|
export const auditApi = {
|
||||||
|
getAuditList,
|
||||||
|
exportAudit,
|
||||||
|
getAuditById,
|
||||||
|
addAudit,
|
||||||
|
updateAudit,
|
||||||
|
deleteAudit,
|
||||||
|
updateAuditStatus,
|
||||||
|
failSendAudit
|
||||||
|
}
|
||||||
|
|
||||||
|
export default auditApi
|
||||||
36
src/api/modules/bookAudit.js
Normal file
36
src/api/modules/bookAudit.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import instance from '../../utils/axios.js'
|
||||||
|
|
||||||
|
// 图书审核相关API
|
||||||
|
const bookAuditApi = {
|
||||||
|
// 获取图书审核列表
|
||||||
|
getBookAuditList: (params) => instance.get('/zhishu/bookAudit/list', { params }),
|
||||||
|
|
||||||
|
// 获取图书审核详细信息
|
||||||
|
getBookAuditById: (id) => instance.get(`/zhishu/bookAudit/${id}`),
|
||||||
|
|
||||||
|
// 新增图书审核
|
||||||
|
addBookAudit: (data) => instance.post('/zhishu/bookAudit', data),
|
||||||
|
|
||||||
|
// 修改图书审核
|
||||||
|
updateBookAudit: (data) => instance.put('/zhishu/bookAudit', data),
|
||||||
|
|
||||||
|
// 删除图书审核(支持批量删除)
|
||||||
|
deleteBookAudit: (ids) => {
|
||||||
|
const idStr = Array.isArray(ids) ? ids.join(',') : ids;
|
||||||
|
return instance.delete(`/zhishu/bookAudit/${idStr}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出图书审核列表
|
||||||
|
exportBookAudit: (data) => instance.post('/zhishu/bookAudit/export', data, {
|
||||||
|
responseType: 'blob'
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 修改审核状态(通过/未通过)
|
||||||
|
updateBookAuditStatus: (data) => instance.put('/zhishu/bookAudit/updateStatus', data),
|
||||||
|
|
||||||
|
// 审核未通过并记录日志
|
||||||
|
failSendBookAudit: (data) => instance.post('/zhishu/bookAudit/failSend', data)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导出模块
|
||||||
|
export { bookAuditApi };
|
||||||
107
src/api/modules/excelTask.js
Normal file
107
src/api/modules/excelTask.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import instance from '../../utils/axios.js'
|
||||||
|
|
||||||
|
// 查询任务列表
|
||||||
|
export const getExcelTaskList = (params = {}) => {
|
||||||
|
return instance.get('/zhishu/excelTask/list', { params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取任务详细信息
|
||||||
|
export const getExcelTaskDetail = (id) => {
|
||||||
|
return instance.get(`/zhishu/excelTask/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增任务
|
||||||
|
export const addExcelTask = (data) => {
|
||||||
|
return instance.post('/zhishu/excelTask', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改任务
|
||||||
|
export const updateExcelTask = (data) => {
|
||||||
|
return instance.put('/zhishu/excelTask', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除任务
|
||||||
|
export const deleteExcelTask = (ids) => {
|
||||||
|
return instance.delete(`/zhishu/excelTask/${ids}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出任务列表
|
||||||
|
export const exportExcelTask = (params) => {
|
||||||
|
return instance.post('/zhishu/excelTask/export', params, {
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导入模板
|
||||||
|
export const getImportTemplate = () => {
|
||||||
|
return instance.post('/zhishu/excelTask/importTemplate', {}, {
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件上传
|
||||||
|
export const uploadExcelFile = (file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
return instance.post('/zhishu/excelTask/upload', formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志列表
|
||||||
|
export const getLogsList = (id) => {
|
||||||
|
return instance.get('/zhishu/excelTask/logsList', {
|
||||||
|
params: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志消息
|
||||||
|
export const getLogsMsg = (id) => {
|
||||||
|
return instance.get('/zhishu/excelTask/logsMsg', {
|
||||||
|
params: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取详细日志列表
|
||||||
|
export const getLogsDetailList = (taskId, shopId) => {
|
||||||
|
return instance.get(`/zhishu/excelTask/logsDetailList/${taskId}/${shopId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载日志
|
||||||
|
export const downloadLogs = (fileName) => {
|
||||||
|
return instance.get(`/zhishu/excelTask/downloadLogs/${fileName}`, {
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停线程
|
||||||
|
export const pauseThread = (threadId, taskId) => {
|
||||||
|
return instance.get(`/zhishu/excelTask/pauseThread/${threadId}/${taskId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续执行线程
|
||||||
|
export const continueThread = (threadId, taskId) => {
|
||||||
|
return instance.get(`/zhishu/excelTask/continueThread/${threadId}/${taskId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为了向后兼容,也导出整个对象
|
||||||
|
export const excelTaskApi = {
|
||||||
|
getExcelTaskList,
|
||||||
|
getExcelTaskDetail,
|
||||||
|
addExcelTask,
|
||||||
|
updateExcelTask,
|
||||||
|
deleteExcelTask,
|
||||||
|
exportExcelTask,
|
||||||
|
getImportTemplate,
|
||||||
|
uploadExcelFile,
|
||||||
|
getLogsList,
|
||||||
|
getLogsMsg,
|
||||||
|
getLogsDetailList,
|
||||||
|
downloadLogs,
|
||||||
|
pauseThread,
|
||||||
|
continueThread
|
||||||
|
}
|
||||||
|
|
||||||
|
export default excelTaskApi
|
||||||
58
src/api/modules/pddGoods.js
Normal file
58
src/api/modules/pddGoods.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import instance from '../../utils/axios.js'
|
||||||
|
|
||||||
|
// 拼多多商品相关API
|
||||||
|
const pddGoodsApi = {
|
||||||
|
// 获取授权回调代码
|
||||||
|
getCode: (params) => instance.get('/pddGoods', { params }),
|
||||||
|
|
||||||
|
// 获取店铺商品总数
|
||||||
|
getShopGoodsTotalNum: (shopId) => instance.get(`/pddGoods/getShopGoodsTotalNum?shopId=${shopId}`),
|
||||||
|
|
||||||
|
// 创建店铺商品列表同步任务
|
||||||
|
createShopGoodsList: (shopId, sycFlag) => instance.get(`/pddGoods/createShopGoodsList?shopId=${shopId}&sycFlag=${sycFlag}`),
|
||||||
|
|
||||||
|
// 创建店铺商品详细信息同步任务
|
||||||
|
createShopGoodsDetailList: (shopId) => instance.get(`/pddGoods/createShopGoodsDetailList?shopId=${shopId}`),
|
||||||
|
|
||||||
|
// 获取店铺商品列表
|
||||||
|
getShopGoodsList: (shopId, isOnsale, pageNum, pageSize) => instance.get(`/pddGoods/getShopGoodsList?shopId=${shopId}&isOnsale=${isOnsale}&pageNum=${pageNum}&pageSize=${pageSize}`),
|
||||||
|
|
||||||
|
// 导出店铺商品数据
|
||||||
|
emportShopGoods: (data) => instance.post('/pddGoods/emportShopGoods', data, { responseType: 'blob' }),
|
||||||
|
|
||||||
|
// 检查CSV文件是否存在
|
||||||
|
checkFile: (shopId) => instance.get(`/pddGoods/checkFile?shopId=${shopId}`),
|
||||||
|
|
||||||
|
// 批量修改所有商品上架状态
|
||||||
|
editShopGoodsAllByIsOnSale: (shopId, isOnSale) => instance.post('/pddGoods/editShopGoodsAllByIsOnSale', `shopId=${shopId}&isOnSale=${isOnSale}`, {
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 获取商品价格验证文件下载链接
|
||||||
|
getVerifyPriceUrl: (shopId) => instance.get(`/pddGoods/getVerifyPriceUrl?shopId=${shopId}`),
|
||||||
|
|
||||||
|
// 通过CSV修改商品价格数据
|
||||||
|
updateShopGoodsDataPriceCSV: (data) => instance.post('/pddGoods/updateShopGoodsDataPriceCSV', data),
|
||||||
|
|
||||||
|
// 批量设置商品为售罄状态
|
||||||
|
batchSetSoldOut: (shopId) => instance.post('/pddGoods/batchSetSoldOut', `shopId=${shopId}`, {
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 通过CSV批量翻新上架商品
|
||||||
|
batchRenovateOnSaleByCsv: (file, shopId) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
formData.append('shopId', shopId)
|
||||||
|
return instance.post('/pddGoods/batchRenovateOnSaleByCsv', formData, {
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 翻新单个商品上架状态
|
||||||
|
renovateOnSale: (data) => instance.post('/pddGoods/renovateOnSale', data)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导出模块
|
||||||
|
export { pddGoodsApi };
|
||||||
166
src/api/modules/shopOrder.js
Normal file
166
src/api/modules/shopOrder.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
import request from '@/utils/axios'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 店铺订单相关接口
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 查询订单列表
|
||||||
|
export function getShopOrderList(params) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询订单列表(分页)
|
||||||
|
export function getShopOrderPage(params) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出订单列表
|
||||||
|
export function exportShopOrder(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/export',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取订单详细信息
|
||||||
|
export function getShopOrderInfo(id) {
|
||||||
|
return request({
|
||||||
|
url: `/zhishu/shopOrder/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增订单
|
||||||
|
export function addShopOrder(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改订单
|
||||||
|
export function updateShopOrder(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除订单
|
||||||
|
export function deleteShopOrder(ids) {
|
||||||
|
return request({
|
||||||
|
url: `/zhishu/shopOrder/${ids}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单列表查询接口(根据成交时间)
|
||||||
|
export function getInterShopOrder(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/getInterShopOrder',
|
||||||
|
method: 'get',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据订单编码查询订单信息
|
||||||
|
export function getOrderByOrderSn(orderSn) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/listByOrderSn',
|
||||||
|
method: 'get',
|
||||||
|
params: { orderSn }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据店铺id查询订单信息
|
||||||
|
export function getOrderByShopId(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/listByShopId',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量插入/更新订单信息
|
||||||
|
export function insertOrUpdateOrderBatch(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/insertOrUpdateOrderBatch',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定时同步孔网订单
|
||||||
|
export function syncKfzOrderTask() {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/syncKfzOrderTask',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取配送方式列表
|
||||||
|
export function getDeliveryMethodList(params) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/delivery/methodList',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单发货
|
||||||
|
export function orderDelivery(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/delivery',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查订单信息
|
||||||
|
export function checkOrderInfo(orderId) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/checkInfo',
|
||||||
|
method: 'post',
|
||||||
|
params: { orderId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新同步订单(已扣减库存订单不会再次扣减)
|
||||||
|
export function syncKfzHistoryOrder(params, data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/syncKfzHistoryOrder',
|
||||||
|
method: 'post',
|
||||||
|
params,
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新同步订单完成回调
|
||||||
|
export function syncKfzHistoryOrderCallBack(params) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/syncKfzHistoryOrderCallBack',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改订单同步状态
|
||||||
|
export function updateIsSynOrder(data) {
|
||||||
|
return request({
|
||||||
|
url: '/zhishu/shopOrder/updateIsSynOrder',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
66
src/components/Pagination.vue
Normal file
66
src/components/Pagination.vue
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div class="pagination-container">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:total="total"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'Pagination'
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
total: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
|
||||||
|
|
||||||
|
const currentPage = computed({
|
||||||
|
get: () => props.page,
|
||||||
|
set: (val) => emit('update:page', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
const pageSize = computed({
|
||||||
|
get: () => props.limit,
|
||||||
|
set: (val) => emit('update:limit', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSizeChange = (size) => {
|
||||||
|
emit('update:limit', size)
|
||||||
|
emit('pagination', { page: currentPage.value, limit: size })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (page) => {
|
||||||
|
emit('update:page', page)
|
||||||
|
emit('pagination', { page, limit: pageSize.value })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
54
src/components/RightToolbar.vue
Normal file
54
src/components/RightToolbar.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div class="right-toolbar">
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<el-button @click="toggleSearch" circle>
|
||||||
|
<el-icon>
|
||||||
|
<Search />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="handleRefresh" circle>
|
||||||
|
<el-icon>
|
||||||
|
<Refresh />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Search, Refresh } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'RightToolbar'
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
showSearch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:showSearch', 'queryTable'])
|
||||||
|
|
||||||
|
const toggleSearch = () => {
|
||||||
|
emit('update:showSearch', !props.showSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
emit('queryTable')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.right-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
635
src/views/Audit/index.vue
Normal file
635
src/views/Audit/index.vue
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition enter-active-class="animate__animated animate__fadeInDown"
|
||||||
|
leave-active-class="animate__animated animate__fadeOutUp">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="search-form">
|
||||||
|
<div class="search-left">
|
||||||
|
<el-form-item label="企业名称" prop="companyName" label-width="100px">
|
||||||
|
<el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系方式" prop="contactPhone">
|
||||||
|
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系方式" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div class="search-right">
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="auditList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="ID" align="center" prop="id" :show-overflow-tooltip="true">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="truncate-cell">
|
||||||
|
{{ row.id }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="用户昵称" align="center" prop="userName" width="140" :show-overflow-tooltip="true">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="truncate-cell">
|
||||||
|
<el-button link @click="handleQueryInfo(scope.row)" class="apply-btn" title="点击显示用户详细信息">{{
|
||||||
|
scope.row.userName }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="企业名称" align="center" prop="companyName" />
|
||||||
|
<el-table-column label="企业类型" align="center" prop="companyType">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.companyType === '1' ? '有限责任公司' :
|
||||||
|
row.companyType === '2' ? '股份有限公司' :
|
||||||
|
row.companyType === '3' ? '个人独资企业' :
|
||||||
|
'合伙企业' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="联系人名" align="center" prop="contactPerson" />
|
||||||
|
<el-table-column label="联系方式" align="center" prop="contactPhone" />
|
||||||
|
<el-table-column label="邮箱" align="center" prop="email" />
|
||||||
|
<el-table-column label="备注" align="center" prop="remark" width="120" :show-overflow-tooltip="true">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="truncate-cell">
|
||||||
|
{{ row.remark }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审核状态" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.status === '0' ? 'success' : row.status === '1' ? 'danger' : 'info'"
|
||||||
|
:effect="row.status === '0' ? 'dark' : 'light'" size="large">
|
||||||
|
{{ row.status === '0' ? '通过' : row.status === '1' ? '未通过' : '待审核' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="通过" placement="top">
|
||||||
|
<el-button link type="success" @click="handleUpdateStatus(scope.row.id, '0')">
|
||||||
|
<el-icon><Check /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="未通过" placement="top">
|
||||||
|
<el-button link type="danger" circle @click="handleOpenDialog(scope.row.id)">X</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 添加或修改审核对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="auditFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="管理员ID" prop="adminId">
|
||||||
|
<el-input v-model="form.adminId" placeholder="请输入管理员ID" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="企业名称" prop="companyName">
|
||||||
|
<el-input v-model="form.companyName" placeholder="请输入企业名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="企业类型" prop="companyType">
|
||||||
|
<el-input v-model="form.companyType" placeholder="请输入企业类型" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系人名" prop="contactPerson">
|
||||||
|
<el-input v-model="form.contactPerson" placeholder="请输入联系人名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系方式" prop="contactPhone">
|
||||||
|
<el-input v-model="form.contactPhone" placeholder="请输入联系方式" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="邮箱" prop="email">
|
||||||
|
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="营业执照" prop="license">
|
||||||
|
<el-input v-model="form.license" placeholder="请输入营业执照" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="审核状态" prop="status">
|
||||||
|
<el-radio-group v-model="form.status">
|
||||||
|
<el-radio :label="0" border size="large" value="0">通过</el-radio>
|
||||||
|
<el-radio :label="1" border size="large" value="1">未通过</el-radio>
|
||||||
|
<el-radio :label="2" border size="large" value="2">待审核</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 未通过信息对话框 -->
|
||||||
|
<el-dialog title="填写未通过信息" center v-model="dialog1.visible" width="50%" :close-on-click-modal="false">
|
||||||
|
<el-form ref="formRef" :model="form" label-width="120px" :rules="rules">
|
||||||
|
<el-form-item label="驳回理由" prop="remark" :rules="[
|
||||||
|
{ required: true, message: '必须填写驳回理由', trigger: 'blur' },
|
||||||
|
{ min: 10, message: '至少输入10个字符', trigger: 'blur' }
|
||||||
|
]">
|
||||||
|
<el-input type="textarea" :rows="3" v-model="form.remark" placeholder="请输入具体驳回原因,例如:1.材料不完整;2.信息有误..."
|
||||||
|
show-word-limit :maxlength="500" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialog1.visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="hitbackButton(form.remark)">
|
||||||
|
确认打回
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 申请入驻对话框 -->
|
||||||
|
<el-dialog title="申请入驻" v-model="dialogVisible" width="50%" :before-close="handleClose">
|
||||||
|
<el-form ref="settleFormRef" :model="form" :rules="rules" label-width="120px" disabled>
|
||||||
|
<el-form-item label="身份证正反面" prop="cardIdentity">
|
||||||
|
<el-image v-if="cardFronUrl" :src="cardFronUrl" class="avatar" :preview-src-list="[cardFronUrl]"
|
||||||
|
style="width: 200px;height: 200px;margin-right: 30px">
|
||||||
|
</el-image>
|
||||||
|
<el-image v-if="cartSideUrl" :src="cartSideUrl" class="avatar" :preview-src-list="[cartSideUrl]"
|
||||||
|
style="width: 200px;height: 200px">
|
||||||
|
</el-image>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="联系人" prop="contactPerson">
|
||||||
|
<el-input v-model="form.contactPerson" disabled="true" placeholder="联系人姓名"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系电话" prop="contactPhone">
|
||||||
|
<el-input v-model="form.contactPhone" placeholder="请输入联系电话"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="电子邮箱" prop="email">
|
||||||
|
<el-input v-model="form.email" placeholder="请输入电子邮箱"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="营业执照" prop="license">
|
||||||
|
<el-image v-if="imageUrl" :src="imageUrl" class="avatar" :preview-src-list="[imageUrl]"
|
||||||
|
style="width: 200px;height: 200px">
|
||||||
|
<template #tip>
|
||||||
|
<div class="upload-tip">请上传经营许可证</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item style="display: none" label="营业执照名称:" prop="licenseName">
|
||||||
|
<el-input v-model="form.licenseName" placeholder="请输入营业执照名称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="注册号:" prop="licenseNumber">
|
||||||
|
<el-input v-model="form.licenseNumber" disabled="true" placeholder="营业执照注册号"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="企业名称" prop="companyName">
|
||||||
|
<el-input v-model="form.companyName" disabled="true" placeholder="企业全称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="店铺地址" prop="adress">
|
||||||
|
<el-input v-model="form.adress" disabled="true" placeholder="店铺地址"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="企业类型" prop="companyType">
|
||||||
|
<el-select v-model="form.companyType" placeholder="请选择企业类型">
|
||||||
|
<el-option label="有限责任公司" value="1"></el-option>
|
||||||
|
<el-option label="股份有限公司" value="2"></el-option>
|
||||||
|
<el-option label="个人独资企业" value="3"></el-option>
|
||||||
|
<el-option label="合伙企业" value="4"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="营业执照过期时间" prop="licenseTime">
|
||||||
|
<el-date-picker v-model="form.licenseTime" date-format="YYYY/MM/DD" value-format="YYYY/MM/DD" type="date"
|
||||||
|
placeholder="date" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="经营许可证" prop="businessLicense">
|
||||||
|
<el-image v-if="Imagelicense" :src="Imagelicense" class="avatar" :preview-src-list="[Imagelicense]"
|
||||||
|
style="width: 200px;height: 200px">
|
||||||
|
<template #tip>
|
||||||
|
<div class="upload-tip">请上传经营许可证</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="经营许可证过期时间" prop="businessLicenseTime">
|
||||||
|
<el-date-picker v-model="form.businessLicenseTime" date-format="YYYY/MM/DD" value-format="YYYY/MM/DD"
|
||||||
|
type="date" placeholder="date" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="出版物许可证证照核实方式" prop="remark">
|
||||||
|
<el-input type="textarea" :rows="3" v-model="form.remark" placeholder="请输入其他需要说明的信息"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineOptions({
|
||||||
|
name: 'Audit'
|
||||||
|
})
|
||||||
|
import { ref, reactive, toRefs, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { Check } from '@element-plus/icons-vue'
|
||||||
|
import { getAuditList, getAuditById, addAudit, updateAudit, deleteAudit, updateAuditStatus, failSendAudit, exportAudit } from '@/api/modules/audit'
|
||||||
|
import { ImageApi } from '@/api/modules/Image'
|
||||||
|
|
||||||
|
const auditList = ref([])
|
||||||
|
const buttonLoading = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const showSearch = ref(true)
|
||||||
|
const ids = ref([])
|
||||||
|
const single = ref(true)
|
||||||
|
const multiple = ref(true)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
|
const queryFormRef = ref()
|
||||||
|
const auditFormRef = ref()
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
|
||||||
|
const dialog1 = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 身份证正面
|
||||||
|
const cardFronUrl = ref('')
|
||||||
|
// 身份证反面
|
||||||
|
const cartSideUrl = ref('')
|
||||||
|
// 营业执照图片
|
||||||
|
const imageUrl = ref('')
|
||||||
|
const Imagelicense = ref('')
|
||||||
|
|
||||||
|
const initFormData = {
|
||||||
|
userId: undefined,
|
||||||
|
userName: undefined,
|
||||||
|
adminId: undefined,
|
||||||
|
status: undefined,
|
||||||
|
companyName: undefined,
|
||||||
|
companyType: undefined,
|
||||||
|
contactPerson: undefined,
|
||||||
|
contactPhone: undefined,
|
||||||
|
email: undefined,
|
||||||
|
license: undefined,
|
||||||
|
remark: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
userId: undefined,
|
||||||
|
userName: undefined,
|
||||||
|
adminId: undefined,
|
||||||
|
companyName: undefined,
|
||||||
|
companyType: undefined,
|
||||||
|
contactPerson: undefined,
|
||||||
|
contactPhone: undefined,
|
||||||
|
email: undefined,
|
||||||
|
license: undefined,
|
||||||
|
remark: undefined,
|
||||||
|
status: undefined
|
||||||
|
},
|
||||||
|
rules: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 组合式API存储当前操作上下文
|
||||||
|
const operationContext = reactive({
|
||||||
|
currentId: '',
|
||||||
|
currentData: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data)
|
||||||
|
|
||||||
|
// 打开弹窗方法
|
||||||
|
const handleOpenDialog = (id) => {
|
||||||
|
operationContext.currentId = id
|
||||||
|
console.log(operationContext.currentId)
|
||||||
|
dialog1.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭对话框
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询审核列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getAuditList(queryParams.value)
|
||||||
|
auditList.value = res.data?.list || res.data || []
|
||||||
|
total.value = res.data?.total || res.total || 0
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取审核列表失败:', error)
|
||||||
|
ElMessage.error('获取审核列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset()
|
||||||
|
dialog.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData }
|
||||||
|
auditFormRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection) => {
|
||||||
|
ids.value = selection.map(item => item.id)
|
||||||
|
single.value = selection.length !== 1
|
||||||
|
multiple.value = !selection.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset()
|
||||||
|
dialog.visible = true
|
||||||
|
dialog.title = '添加审核'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQueryInfo = async (row) => {
|
||||||
|
reset()
|
||||||
|
const _id = row?.id || ids.value[0]
|
||||||
|
try {
|
||||||
|
const res = await getAuditById(_id)
|
||||||
|
console.log(res)
|
||||||
|
|
||||||
|
console.log("res.data.license", res.data.license)
|
||||||
|
|
||||||
|
// 处理营业执照图片
|
||||||
|
try {
|
||||||
|
const imageResponse = await ImageApi.getImage({ fileName: res.data.license })
|
||||||
|
imageUrl.value = imageResponse // 现在直接返回字符串
|
||||||
|
console.log("imageUrl.value", imageUrl.value)
|
||||||
|
} catch (imageError) {
|
||||||
|
console.error('获取营业执照图片失败:', imageError)
|
||||||
|
imageUrl.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
Imagelicense.value = res.data.businessLicense
|
||||||
|
console.log("Imagelicense.value", Imagelicense.value)
|
||||||
|
|
||||||
|
// 处理身份证图片
|
||||||
|
try {
|
||||||
|
const urlArray = JSON.parse(res.data.cardIdentity)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cardFrontResponse = await ImageApi.getImage({ fileName: urlArray[0] })
|
||||||
|
cardFronUrl.value = cardFrontResponse // 现在直接返回字符串
|
||||||
|
console.log("cardFronUrl.value", cardFronUrl.value)
|
||||||
|
} catch (imageError) {
|
||||||
|
console.error('获取身份证正面图片失败:', imageError)
|
||||||
|
cardFronUrl.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cartSideResponse = await ImageApi.getImage({ fileName: urlArray[1] })
|
||||||
|
cartSideUrl.value = cartSideResponse // 现在直接返回字符串
|
||||||
|
console.log("cartSideUrl.value", cartSideUrl.value)
|
||||||
|
} catch (imageError) {
|
||||||
|
console.error('获取身份证反面图片失败:', imageError)
|
||||||
|
cartSideUrl.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析身份证图片失败:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(form.value, res.data)
|
||||||
|
dialogVisible.value = true
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取审核详情失败:', error)
|
||||||
|
ElMessage.error('获取审核详情失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row) => {
|
||||||
|
reset()
|
||||||
|
const _id = row?.id || ids.value[0]
|
||||||
|
try {
|
||||||
|
const res = await getAuditById(_id)
|
||||||
|
Object.assign(form.value, res.data)
|
||||||
|
dialog.visible = true
|
||||||
|
dialog.title = '修改审核'
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取审核详情失败:', error)
|
||||||
|
ElMessage.error('获取审核详情失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 审核通过按钮操作 */
|
||||||
|
const handleUpdateStatus = async (id, status) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否审核编号为"${id}"的数据项?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
id: id,
|
||||||
|
status: status
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateAuditStatus(params)
|
||||||
|
ElMessage.success('审核通过')
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('审核状态更新失败:', error)
|
||||||
|
ElMessage.error('审核状态更新失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打回按钮
|
||||||
|
*/
|
||||||
|
const hitbackButton = async (remark) => {
|
||||||
|
const payload = {
|
||||||
|
id: operationContext.currentId,
|
||||||
|
status: '1',
|
||||||
|
remark
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await failSendAudit(payload)
|
||||||
|
ElMessage.success('审核未通过操作成功')
|
||||||
|
dialog1.visible = false
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('审核未通过操作失败:', error)
|
||||||
|
ElMessage.error('审核未通过操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
auditFormRef.value?.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true
|
||||||
|
try {
|
||||||
|
if (form.value.id) {
|
||||||
|
await updateAudit(form.value)
|
||||||
|
} else {
|
||||||
|
await addAudit(form.value)
|
||||||
|
}
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
dialog.visible = false
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('操作失败')
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row) => {
|
||||||
|
const _ids = row?.id || ids.value
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否确认删除审核编号为"${_ids}"的数据项?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
await deleteAudit(_ids)
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
ElMessage.error('删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
const res = await exportAudit(queryParams.value)
|
||||||
|
// 处理文件下载
|
||||||
|
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||||
|
const url = window.URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = `audit_${new Date().getTime()}.xlsx`
|
||||||
|
link.click()
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
ElMessage.success('导出成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导出失败:', error)
|
||||||
|
ElMessage.error('导出失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 文本溢出处理 */
|
||||||
|
.truncate-cell {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: var(--el-transition-duration-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #8c939d;
|
||||||
|
width: 140px;
|
||||||
|
height: 120px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-tip {
|
||||||
|
margin-top: 8px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-left {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.avatar-uploader .avatar {
|
||||||
|
width: 178px;
|
||||||
|
height: 178px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
408
src/views/bookAudit/index.vue
Normal file
408
src/views/bookAudit/index.vue
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<div v-if="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="商品编号" prop="itemNumber">
|
||||||
|
<el-input v-model="queryParams.itemNumber" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="品相" prop="conditionCode">
|
||||||
|
<el-input v-model="queryParams.conditionCode" placeholder="请输入品相" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="isbn" prop="isbn">
|
||||||
|
<el-input v-model="queryParams.isbn" placeholder="请输入isbn" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain @click="handleAdd">新增</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="success" plain :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="danger" plain :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="warning" plain @click="handleExport">导出</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button @click="showSearch = !showSearch">{{ showSearch ? '隐藏搜索' : '显示搜索' }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="bookAuditList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="expand">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-form label-position="left" inline class="demo-table-expand">
|
||||||
|
<el-form-item>
|
||||||
|
<el-image style="width: 100px; height: 120px" :src="row.bookPic" fit="cover"
|
||||||
|
:preview-src-list="[row.bookPic]" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="审核图书id" align="center" prop="id" />
|
||||||
|
<el-table-column label="产品编码" align="center" prop="productId" />
|
||||||
|
<el-table-column label="商品名称" align="center" prop="goodsName" :show-overflow-tooltip="true">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="truncate-cell">
|
||||||
|
{{ row.goodsName }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="isbn" align="center" prop="isbn" />
|
||||||
|
<el-table-column label="标准售价" align="center" prop="price">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ (row.price / 100).toFixed(2) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审核状态" align="center" prop="status">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.status === '0' ? 'success' : row.status === '1' ? 'danger' : 'info'"
|
||||||
|
:effect="row.status === '0' ? 'dark' : 'light'" size="large">
|
||||||
|
{{ row.status === '0' ? '通过' : row.status === '1' ? '未通过' : '待审核' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="通过" placement="top">
|
||||||
|
<el-button link type="success" icon="Check" @click="handleUpdateStatus(scope.row.id, '0')">
|
||||||
|
<el-icon>
|
||||||
|
<Check />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="未通过" placement="top">
|
||||||
|
<el-button link type="danger" circle @click="handleUpdateStatus(scope.row.id, '1')">X</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-pagination v-if="total > 0" :total="total" v-model:current-page="queryParams.pageNum"
|
||||||
|
v-model:page-size="queryParams.pageSize" @current-change="getList" @size-change="getList"
|
||||||
|
:page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" />
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 添加或修改图书审核管理对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="bookAuditFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="用户id" prop="userId">
|
||||||
|
<el-input v-model="form.userId" placeholder="请输入用户id" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="产品编码" prop="productId">
|
||||||
|
<el-input v-model="form.productId" placeholder="请输入产品编码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品名称" prop="goodsName">
|
||||||
|
<el-input v-model="form.goodsName" placeholder="请输入商品名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="isbn" prop="isbn">
|
||||||
|
<el-input v-model="form.isbn" placeholder="请输入isbn" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="货号" prop="artNo">
|
||||||
|
<el-input v-model="form.artNo" placeholder="请输入货号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="品相" prop="conditionCode">
|
||||||
|
<el-input v-model="form.conditionCode" placeholder="请输入品相" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品编号" prop="itemNumber">
|
||||||
|
<el-input v-model="form.itemNumber" placeholder="请输入商品编号" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { bookAuditApi } from '@/api/modules/bookAudit'
|
||||||
|
import { Check } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const bookAuditList = ref([])
|
||||||
|
const buttonLoading = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const showSearch = ref(true)
|
||||||
|
const ids = ref([])
|
||||||
|
const single = ref(true)
|
||||||
|
const multiple = ref(true)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
|
// 表单引用
|
||||||
|
const queryFormRef = ref()
|
||||||
|
const bookAuditFormRef = ref()
|
||||||
|
|
||||||
|
// 对话框状态
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始表单数据
|
||||||
|
const initFormData = {
|
||||||
|
userId: '',
|
||||||
|
productId: '',
|
||||||
|
goodsName: '',
|
||||||
|
isbn: '',
|
||||||
|
artNo: '',
|
||||||
|
conditionCode: '',
|
||||||
|
itemNumber: '',
|
||||||
|
status: '',
|
||||||
|
inventory: '',
|
||||||
|
bookPic: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询参数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
userId: '',
|
||||||
|
productId: '',
|
||||||
|
goodsName: '',
|
||||||
|
isbn: '',
|
||||||
|
artNo: '',
|
||||||
|
conditionCode: '',
|
||||||
|
itemNumber: '',
|
||||||
|
status: '',
|
||||||
|
inventory: '',
|
||||||
|
bookPic: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form = reactive({ ...initFormData })
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = reactive({
|
||||||
|
conditionCode: [
|
||||||
|
{ required: true, message: "品相不能为空", trigger: "blur" }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 审核状态更新
|
||||||
|
const handleUpdateStatus = async (id, status) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否审核编号为"${id}"的数据项?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
id: id,
|
||||||
|
status: status
|
||||||
|
}
|
||||||
|
|
||||||
|
await bookAuditApi.updateBookAuditStatus(params)
|
||||||
|
ElMessage.success(status === '0' ? '审核通过' : '审核未通过')
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('审核状态更新失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询图书审核管理列表
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const filteredParams = Object.entries(queryParams)
|
||||||
|
.filter(([_, v]) => v !== '' && v !== null && v !== undefined)
|
||||||
|
.reduce((acc, [k, v]) => {
|
||||||
|
acc[k] = v
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
const res = await bookAuditApi.getBookAuditList(filteredParams)
|
||||||
|
bookAuditList.value = res.data.list || res.data.rows || []
|
||||||
|
total.value = res.data.total || 0
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
ElMessage.error('获取列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消按钮
|
||||||
|
const cancel = () => {
|
||||||
|
reset()
|
||||||
|
dialog.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单重置
|
||||||
|
const reset = () => {
|
||||||
|
Object.assign(form, initFormData)
|
||||||
|
bookAuditFormRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索按钮操作
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNum = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置按钮操作
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
Object.assign(queryParams, {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
userId: '',
|
||||||
|
productId: '',
|
||||||
|
goodsName: '',
|
||||||
|
isbn: '',
|
||||||
|
artNo: '',
|
||||||
|
conditionCode: '',
|
||||||
|
itemNumber: '',
|
||||||
|
status: '',
|
||||||
|
inventory: '',
|
||||||
|
bookPic: ''
|
||||||
|
})
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多选框选中数据
|
||||||
|
const handleSelectionChange = (selection) => {
|
||||||
|
ids.value = selection.map(item => item.id)
|
||||||
|
single.value = selection.length !== 1
|
||||||
|
multiple.value = !selection.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增按钮操作
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset()
|
||||||
|
dialog.visible = true
|
||||||
|
dialog.title = "添加图书审核管理"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改按钮操作
|
||||||
|
const handleUpdate = async (row) => {
|
||||||
|
reset()
|
||||||
|
const _id = row?.id || ids.value[0]
|
||||||
|
try {
|
||||||
|
const res = await bookAuditApi.getBookAuditById(_id)
|
||||||
|
Object.assign(form, res.data)
|
||||||
|
dialog.visible = true
|
||||||
|
dialog.title = "修改图书审核管理"
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取详情失败:', error)
|
||||||
|
ElMessage.error('获取详情失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交按钮
|
||||||
|
const submitForm = () => {
|
||||||
|
bookAuditFormRef.value?.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true
|
||||||
|
try {
|
||||||
|
if (form.id) {
|
||||||
|
await bookAuditApi.updateBookAudit(form)
|
||||||
|
} else {
|
||||||
|
await bookAuditApi.addBookAudit(form)
|
||||||
|
}
|
||||||
|
ElMessage.success("操作成功")
|
||||||
|
dialog.visible = false
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('操作失败')
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除按钮操作
|
||||||
|
const handleDelete = async (row) => {
|
||||||
|
const _ids = row?.id || ids.value
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否确认删除图书审核管理编号为"${_ids}"的数据项?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
await bookAuditApi.deleteBookAudit(_ids)
|
||||||
|
ElMessage.success("删除成功")
|
||||||
|
await getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出按钮操作
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
const res = await bookAuditApi.exportBookAudit(queryParams)
|
||||||
|
// 创建下载链接
|
||||||
|
const url = window.URL.createObjectURL(new Blob([res.data]))
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.setAttribute('download', `bookAudit_${new Date().getTime()}.xlsx`)
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导出失败:', error)
|
||||||
|
ElMessage.error('导出失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时获取列表
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 文本溢出处理 */
|
||||||
|
.truncate-cell {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 增强悬浮提示样式 */
|
||||||
|
.el-tooltip__popper {
|
||||||
|
max-width: 400px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-table-expand {
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-table-expand label {
|
||||||
|
width: 90px;
|
||||||
|
color: #99a9bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-table-expand .el-form-item {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
601
src/views/excelTask/index.vue
Normal file
601
src/views/excelTask/index.vue
Normal file
@ -0,0 +1,601 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="animate.searchAnimate.enter" :leave-active-class="animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="任务类型" prop="taskType">
|
||||||
|
<el-select v-model="queryParams.taskType" placeholder="请选择任务类型" clearable>
|
||||||
|
<el-option label="发布任务" value="1" />
|
||||||
|
<el-option label="更新任务" value="2" />
|
||||||
|
<el-option label="下架任务" value="3" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件名称" prop="fileName">
|
||||||
|
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable
|
||||||
|
@keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务状态" prop="taskStatus">
|
||||||
|
<el-select v-model="queryParams.taskStatus" placeholder="请选择任务状态" clearable>
|
||||||
|
<el-option label="执行中" value="1" />
|
||||||
|
<el-option label="已暂停" value="2" />
|
||||||
|
<el-option label="已完成" value="3" />
|
||||||
|
<el-option label="已失败" value="4" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>书品导入任务列表</span>
|
||||||
|
<el-button type="primary" icon="Plus" @click="handleAdd">新增任务</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="任务编码" align="center" prop="id" :show-overflow-tooltip="true">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="truncate-cell">
|
||||||
|
{{ row.id }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="任务类型" align="center" prop="taskType">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="scope.row.taskType === '1'" type="success">发布任务</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.taskType === '2'" type="warning">更新任务</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.taskType === '3'" type="danger">下架任务</el-tag>
|
||||||
|
<el-tag v-else>未知</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="货区名称" align="center" prop="depotIds" />
|
||||||
|
<el-table-column label="文件名称" align="center" prop="fileName" width="250" />
|
||||||
|
<el-table-column label="执行数据条数" align="center" prop="dataNum" />
|
||||||
|
<el-table-column label="任务状态" align="center" prop="taskStatus">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="scope.row.taskStatus === '1'" type="success">执行中</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.taskStatus === '2'" type="warning">已暂停</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.taskStatus === '3'" type="info">已完成</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.taskStatus === '4'" type="danger">已失败</el-tag>
|
||||||
|
<el-tag v-else>未知</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ formatTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="查看日志" placement="top">
|
||||||
|
<el-button link type="primary" @click="showLogs(scope.row)">
|
||||||
|
日志
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip content="暂停任务" placement="top">
|
||||||
|
<el-button v-if="scope.row.taskStatus === '1'" link type="warning"
|
||||||
|
@click="pauseTask(scope.row)">
|
||||||
|
暂停
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip content="恢复任务" placement="top">
|
||||||
|
<el-button v-if="scope.row.taskStatus === '2'" link type="success"
|
||||||
|
@click="resumeTask(scope.row)">
|
||||||
|
恢复
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip content="删除任务" placement="top">
|
||||||
|
<el-button link type="danger" @click="handleDelete(scope.row)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-pagination v-show="total > 0" :total="total" v-model:current-page="queryParams.pageNum"
|
||||||
|
v-model:page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper" @size-change="getList" @current-change="getList" />
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 添加任务对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
|
||||||
|
<el-form ref="taskFormRef" :model="form" :rules="rules" label-width="100px" style="height:600px">
|
||||||
|
<el-form-item label="任务类型" prop="taskType">
|
||||||
|
<el-select v-model="form.taskType" placeholder="请选择任务类型">
|
||||||
|
<el-option label="发布任务" value="1"></el-option>
|
||||||
|
<el-option label="更新任务" value="2"></el-option>
|
||||||
|
<el-option label="下架任务" value="3"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="仓库选择" prop="depotIds" style="width: 100%">
|
||||||
|
<el-checkbox-group v-model="form.depotIds">
|
||||||
|
<el-checkbox v-for="item in depotList" :key="item.value" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="文件选择" prop="fileUrl" style="width: 100%">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="14">
|
||||||
|
<el-upload ref="uploadRef" class="upload-demo" :action="uploadUrl" :limit="1"
|
||||||
|
:headers="uploadHeaders" :on-success="handleUploadSuccess" :on-exceed="handleExceed"
|
||||||
|
:before-upload="beforeUpload">
|
||||||
|
<template #trigger>
|
||||||
|
<el-button type="primary">上传文件</el-button>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-button @click="downloadTemplate">下载模板</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 日志对话框 -->
|
||||||
|
<el-dialog :title="dialog.logsTitle" v-model="dialog.logsVisible" width="800px" append-to-body>
|
||||||
|
<div class="logs-message">
|
||||||
|
{{ logsMessage }}
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="loading" :data="taskLogsList" height="400px">
|
||||||
|
<el-table-column label="仓库名称" align="center" prop="depotName" />
|
||||||
|
<el-table-column label="进度" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.progress }}%
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间/修改时间" align="center" prop="createTime" width="300">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.createTime }} / {{ scope.row.updateTime }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="查看" placement="top">
|
||||||
|
<el-button link type="primary" icon="Memo" @click="showLogsDetail(scope.row)">查看</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="下载" placement="top">
|
||||||
|
<el-button link type="primary" icon="Download"
|
||||||
|
@click="downloadTaskLogs(scope.row.taskId + scope.row.shopId)">下载</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="closeLogsDialog">关 闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 详细日志对话框 -->
|
||||||
|
<el-dialog :title="dialog.detailTitle" v-model="dialog.detailVisible" width="700px" append-to-body>
|
||||||
|
<el-table v-loading="loading" :data="taskLogsDetailList" height="700px">
|
||||||
|
<el-table-column label="日志名称" align="center" prop="logName" />
|
||||||
|
<el-table-column label="数量" align="center" prop="num" width="100px" />
|
||||||
|
<el-table-column label="占比" align="center" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.progress }}%
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="下载日志" placement="top">
|
||||||
|
<el-button link type="primary" icon="Download"
|
||||||
|
@click="downloadTaskLogs(scope.row.mark)">下载日志</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="closeDetailDialog">关 闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getExcelTaskList,
|
||||||
|
addExcelTask,
|
||||||
|
deleteExcelTask,
|
||||||
|
getLogsList,
|
||||||
|
getLogsMsg,
|
||||||
|
getLogsDetailList,
|
||||||
|
downloadLogs,
|
||||||
|
pauseThread,
|
||||||
|
continueThread,
|
||||||
|
getImportTemplate,
|
||||||
|
uploadExcelFile
|
||||||
|
} from '@/api/modules/excelTask'
|
||||||
|
import { depotApi } from '@/api/modules/depot'
|
||||||
|
|
||||||
|
const { appContext } = getCurrentInstance()
|
||||||
|
const animate = appContext.config.globalProperties.$animate || {
|
||||||
|
searchAnimate: {
|
||||||
|
enter: 'animate__animated animate__fadeInDown',
|
||||||
|
leave: 'animate__animated animate__fadeOutUp'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const taskList = ref([])
|
||||||
|
const taskLogsList = ref([])
|
||||||
|
const taskLogsDetailList = ref([])
|
||||||
|
const depotList = ref([])
|
||||||
|
const buttonLoading = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const showSearch = ref(true)
|
||||||
|
const ids = ref([])
|
||||||
|
const total = ref(0)
|
||||||
|
const logsMessage = ref('')
|
||||||
|
|
||||||
|
// 表单引用
|
||||||
|
const queryFormRef = ref()
|
||||||
|
const taskFormRef = ref()
|
||||||
|
const uploadRef = ref()
|
||||||
|
|
||||||
|
// 查询参数
|
||||||
|
const queryParams = ref({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
taskType: undefined,
|
||||||
|
fileName: undefined,
|
||||||
|
taskStatus: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form = ref({
|
||||||
|
taskType: undefined,
|
||||||
|
depotIds: [],
|
||||||
|
fileUrl: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = {
|
||||||
|
taskType: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
|
||||||
|
depotIds: [{ required: true, message: '仓库不能为空', trigger: 'blur' }],
|
||||||
|
fileUrl: [{ required: true, message: '文件不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对话框状态
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '',
|
||||||
|
logsVisible: false,
|
||||||
|
logsTitle: '',
|
||||||
|
detailVisible: false,
|
||||||
|
detailTitle: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 上传配置
|
||||||
|
const baseUrl = import.meta.env.VITE_APP_BASE_API
|
||||||
|
const uploadUrl = ref(baseUrl + '/zhishu/excelTask/upload')
|
||||||
|
const uploadHeaders = ref({
|
||||||
|
'Authorization': `Bearer ${localStorage.getItem('accessToken') || ''}`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化时间
|
||||||
|
const formatTime = (time) => {
|
||||||
|
if (!time) return ''
|
||||||
|
const date = new Date(time)
|
||||||
|
return date.toLocaleString('zh-CN')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取任务列表
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getExcelTaskList(queryParams.value)
|
||||||
|
taskList.value = res.data?.list || []
|
||||||
|
total.value = res.data?.total || 0
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取任务列表失败:', error)
|
||||||
|
ElMessage.error('获取任务列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取仓库列表
|
||||||
|
const getDepotList = async () => {
|
||||||
|
try {
|
||||||
|
const res = await depotApi.getDepotNameList()
|
||||||
|
const resList = res.data?.rows || []
|
||||||
|
depotList.value = resList.map(item => ({
|
||||||
|
value: item.id,
|
||||||
|
label: item.name
|
||||||
|
}))
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取仓库列表失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置搜索
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多选
|
||||||
|
const handleSelectionChange = (selection) => {
|
||||||
|
ids.value = selection.map(item => item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增任务
|
||||||
|
const handleAdd = () => {
|
||||||
|
resetForm()
|
||||||
|
dialog.visible = true
|
||||||
|
dialog.title = '添加任务'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停任务
|
||||||
|
const pauseTask = async (row) => {
|
||||||
|
try {
|
||||||
|
await pauseThread(row.threadId, row.id)
|
||||||
|
ElMessage.success('任务已暂停')
|
||||||
|
getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('暂停任务失败:', error)
|
||||||
|
ElMessage.error('暂停任务失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复任务
|
||||||
|
const resumeTask = async (row) => {
|
||||||
|
try {
|
||||||
|
await continueThread(row.threadId, row.id)
|
||||||
|
ElMessage.success('任务已恢复')
|
||||||
|
getList()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('恢复任务失败:', error)
|
||||||
|
ElMessage.error('恢复任务失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除任务
|
||||||
|
const handleDelete = async (row) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`是否确认删除任务编号为"${row.id}"的数据项?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
await deleteExcelTask(row.id)
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
getList()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('删除任务失败:', error)
|
||||||
|
ElMessage.error('删除任务失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示日志
|
||||||
|
const showLogs = async (row) => {
|
||||||
|
try {
|
||||||
|
const [logsRes, msgRes] = await Promise.all([
|
||||||
|
getLogsList(row.id),
|
||||||
|
getLogsMsg(row.id)
|
||||||
|
])
|
||||||
|
taskLogsList.value = logsRes.data || []
|
||||||
|
logsMessage.value = msgRes.data || ''
|
||||||
|
dialog.logsVisible = true
|
||||||
|
dialog.logsTitle = '任务日志'
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取日志失败:', error)
|
||||||
|
ElMessage.error('获取日志失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示详细日志
|
||||||
|
const showLogsDetail = async (row) => {
|
||||||
|
try {
|
||||||
|
const res = await getLogsDetailList(row.taskId, row.shopId)
|
||||||
|
taskLogsDetailList.value = res.data || []
|
||||||
|
dialog.detailVisible = true
|
||||||
|
dialog.detailTitle = `详细日志信息:${taskLogsDetailList.value[0]?.depotName || ''}`
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取详细日志失败:', error)
|
||||||
|
ElMessage.error('获取详细日志失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载日志
|
||||||
|
const downloadTaskLogs = async (fileName) => {
|
||||||
|
try {
|
||||||
|
const fullFileName = fileName + '.xlsx'
|
||||||
|
const url = `${baseUrl}/zhishu/excelTask/downloadLogs/${fullFileName}`
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = fullFileName
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载日志失败:', error)
|
||||||
|
ElMessage.error('下载日志失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载模板
|
||||||
|
const downloadTemplate = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getImportTemplate()
|
||||||
|
const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||||
|
const url = window.URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = `task_template_${new Date().getTime()}.xlsx`
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载模板失败:', error)
|
||||||
|
ElMessage.error('下载模板失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件上传前检查
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
const isExcel = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
|
||||||
|
file.type === 'application/vnd.ms-excel'
|
||||||
|
if (!isExcel) {
|
||||||
|
ElMessage.error('只能上传Excel文件!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10
|
||||||
|
if (!isLt10M) {
|
||||||
|
ElMessage.error('上传文件大小不能超过 10MB!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件上传成功
|
||||||
|
const handleUploadSuccess = (response) => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
form.value.fileUrl = response.data?.url || ''
|
||||||
|
ElMessage.success('文件上传成功')
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message || '文件上传失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件超出限制
|
||||||
|
const handleExceed = () => {
|
||||||
|
ElMessage.warning('只能上传一个文件')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const submitForm = async () => {
|
||||||
|
if (!taskFormRef.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await taskFormRef.value.validate()
|
||||||
|
buttonLoading.value = true
|
||||||
|
|
||||||
|
const submitData = {
|
||||||
|
...form.value,
|
||||||
|
depotIds: form.value.depotIds.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
await addExcelTask(submitData)
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
dialog.visible = false
|
||||||
|
getList()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== false) { // 表单验证失败时error为false
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('操作失败')
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const resetForm = () => {
|
||||||
|
form.value = {
|
||||||
|
taskType: undefined,
|
||||||
|
depotIds: [],
|
||||||
|
fileUrl: undefined
|
||||||
|
}
|
||||||
|
taskFormRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消
|
||||||
|
const cancel = () => {
|
||||||
|
resetForm()
|
||||||
|
dialog.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭日志对话框
|
||||||
|
const closeLogsDialog = () => {
|
||||||
|
dialog.logsVisible = false
|
||||||
|
taskLogsList.value = []
|
||||||
|
logsMessage.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭详细日志对话框
|
||||||
|
const closeDetailDialog = () => {
|
||||||
|
dialog.detailVisible = false
|
||||||
|
taskLogsDetailList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时执行
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
getDepotList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.truncate-cell {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-message {
|
||||||
|
width: 100%;
|
||||||
|
height: 162px;
|
||||||
|
background: #f2f2f2;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
padding: 13px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tooltip__popper {
|
||||||
|
max-width: 400px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
879
src/views/pddGoods/index.vue
Normal file
879
src/views/pddGoods/index.vue
Normal file
@ -0,0 +1,879 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition enter-active-class="animate__animated animate__fadeInDown"
|
||||||
|
leave-active-class="animate__animated animate__fadeOutUp">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-position="left" label-width="80px">
|
||||||
|
<el-form-item label="店铺名称" prop="shopId">
|
||||||
|
<el-select v-model="shopId" placeholder="请选择店铺" clearable @change="handleQuery">
|
||||||
|
<el-option v-for="dict in shopList" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="状态" prop="is_onsale">
|
||||||
|
<el-select v-model="queryParams.is_onsale" placeholder="请选择状态" clearable @change="handleQuery">
|
||||||
|
<el-option key="0" label="下架" value="0" />
|
||||||
|
<el-option key="1" label="上架" value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button type="primary" @click="exportData">导出</el-button>
|
||||||
|
<el-button type="primary" @click="confirmTongBu">删除后拉取</el-button>
|
||||||
|
<el-button type="primary" @click="tongBu1">拉取</el-button>
|
||||||
|
<el-button type="danger" @click="handleAdd" v-hasPermi="['zhishu:pddGoods:tongbu']">
|
||||||
|
拼多多专属详情同步 </el-button>
|
||||||
|
<el-button type="primary" @click="editIsOnSale('1')">整店上架</el-button>
|
||||||
|
<el-button type="primary" @click="editIsOnSale('0')">整店下架</el-button>
|
||||||
|
<el-button type="danger" @click="repeatData">下架重复</el-button>
|
||||||
|
<el-button type="success" @click="showRenovateDialog">翻新上架</el-button>
|
||||||
|
<el-button type="primary" @click="createVerifyPriceUrl">生成核价链接</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
<el-dialog v-model="verifyPriceDialog" title="核价链接" width="700px" @close="closeData">
|
||||||
|
<div class="verify-price-dialog">
|
||||||
|
<el-form :model="encrypForm" :rules="encrypRules" ref="encrypFormRef">
|
||||||
|
<el-form-item label="店铺优惠" prop="shopPrice" v-if="!pricingLink">
|
||||||
|
<el-input v-model="encrypForm.shopPrice" placeholder="请输入店铺优惠、在0-20之间整数" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="利润区间" prop="profitRange" v-if="!pricingLink">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="10">
|
||||||
|
<el-form-item prop="minPrice">
|
||||||
|
<el-input v-model="encrypForm.minPrice" type="number" placeholder="利润最小值(整数)">
|
||||||
|
<template #append>元</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4" style="text-align: center; line-height: 32px"> 至</el-col>
|
||||||
|
<el-col :span="10">
|
||||||
|
<el-form-item prop="maxPrice">
|
||||||
|
<el-input v-model="encrypForm.maxPrice" type="number" placeholder="利润最大值(整数)">
|
||||||
|
<template #append>元</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="价格模版名称" prop="shopPrice" v-if="pricingLink">
|
||||||
|
<el-input v-model="priceName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div style="height: 110px; padding: 10px">
|
||||||
|
<span>{{ pricingLink }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button v-if="pricingLink" @click="copyLink" type="primary" style="margin-left: 10px"> 一键复制 </el-button>
|
||||||
|
<el-button type="primary" @click="encrypMethod" v-if="!pricingLink">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<!-- 翻新上架弹窗 -->
|
||||||
|
<el-dialog v-model="renovateDialogVisible" title="批量翻新上架" width="500px">
|
||||||
|
<el-upload ref="upload" class="upload-demo" :auto-upload="false" :on-change="handleFileChange"
|
||||||
|
:before-upload="beforeUpload" :limit="1" :file-list="fileList" accept=".csv">
|
||||||
|
<template #trigger>
|
||||||
|
<el-button type="primary">选择CSV文件</el-button>
|
||||||
|
</template>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">请上传包含商品信息的CSV文件</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="renovateDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="uploading" @click="handleUpload">开始上传</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="pddGoodsList" :element-loading-text="loadingText"
|
||||||
|
element-loading-svg-view-box="-10, -10, 50, 50" element-loading-background="rgba(122, 122, 122, 0.8)"
|
||||||
|
@selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="缩略图" align="left" prop="thumb_url" width="70" :show-overflow-tooltip="true">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-image style="width: 30px; height: 30px" :src="row.Img" fit="scale-down"
|
||||||
|
:preview-src-list="[currentPreviewImg]" preview-teleported @click="handlePreview(row.Img)">
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot">暂无</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="商品id" align="center" prop="TrilateralId" width="150" />
|
||||||
|
<el-table-column label="商品编码" align="center" prop="ISBN" width="150" />
|
||||||
|
<el-table-column label="商品名称" align="center" prop="Title" />
|
||||||
|
<el-table-column label="库存数量" align="center" prop="Stock" width="100" />
|
||||||
|
<el-table-column label="是否在架上" align="center" prop="IsOnSale" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.IsOnSale == '1' ? '是' : '否' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="价格" align="center" prop="TotalPrice" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.TotalPrice ? row.TotalPrice / 100 : '' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="规格编码/货号(孔网)" align="center" prop="SkuCode" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="FinishTime" width="200" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
||||||
|
v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加这个新的弹窗用于展示重复商品数据 -->
|
||||||
|
<el-dialog v-model="repeatDataDialog" title="重复商品列表" width="80%">
|
||||||
|
<el-table :data="repeatDataList" v-loading="repeatLoading" border style="width: 100%">
|
||||||
|
<el-table-column prop="trilateralId" label="商品ID" width="180" />
|
||||||
|
<el-table-column label="商品图片" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-image style="width: 50px; height: 50px" :src="row.img" fit="cover" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="title" label="商品名称" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="isbn" label="商品编码" width="150" />
|
||||||
|
<el-table-column prop="stock" label="库存" width="80" />
|
||||||
|
<el-table-column prop="isOnSale" label="是否在售" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.isOnSale === '1' ? '是' : '否' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="finishTime" label="创建时间" width="180" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-pagination v-model:current-page="repeatQuery.pageNum" v-model:page-size="repeatQuery.pageSize"
|
||||||
|
:total="repeatTotal" layout="total, sizes, prev, pager, next, jumper" @size-change="handleRepeatSizeChange"
|
||||||
|
@current-change="handleRepeatCurrentChange" />
|
||||||
|
<el-button type="danger" :loading="buttonLoading" @click="batchOffShelf">批量下架</el-button>
|
||||||
|
<el-button @click="repeatDataDialog = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 添加或修改充值对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="userRechargeFormRef" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="支付方式" prop="rechargType">
|
||||||
|
<el-select v-model="rechargType" placeholder="请选择支付方式">
|
||||||
|
<el-option v-for="dict in t_recharge_way" :key="dict.value" :label="dict.label"
|
||||||
|
:value="dict.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<span style="color: red; font-size: 14px; margin-left: 12px">{{ rechargText }}</span>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="tongBuDetail">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="dialog.titlePrcode" v-model="dialog.visiblePrcode" width="360px" append-to-body>
|
||||||
|
<div>
|
||||||
|
<img :src="qrCodeText" alt="Base64 图片" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Notice">
|
||||||
|
import { ref, reactive, onMounted, toRefs } from 'vue';
|
||||||
|
import { pddGoodsApi } from '@/api/modules/pddGoods';
|
||||||
|
import { taskApi } from '@/api/modules/task';
|
||||||
|
const { getShopGoodsTask, getRepeatData, selectTaskStatusByTaskType, getShopTaskAllNum } = taskApi;
|
||||||
|
import { userRechargeApi } from '@/api/modules/userRecharge';
|
||||||
|
const {
|
||||||
|
listUserRecharge,
|
||||||
|
getUserRecharge,
|
||||||
|
delUserRecharge,
|
||||||
|
addUserRecharge,
|
||||||
|
updateUserRecharge,
|
||||||
|
userRecharge,
|
||||||
|
checkTask,
|
||||||
|
editRechargeToError,
|
||||||
|
getConfigKey
|
||||||
|
} = userRechargeApi;
|
||||||
|
import { shopApi } from '@/api/modules/shop';
|
||||||
|
const { encrypUrlMenthod, getListShop, getVerifyPriceUrl } = shopApi;
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
|
|
||||||
|
// 添加响应式数据
|
||||||
|
const verifyPriceDialog = ref(false);
|
||||||
|
const verifyPriceUrl = ref('');
|
||||||
|
const shopTotalCount = ref('');
|
||||||
|
const loadingVerifyUrl = ref(false);
|
||||||
|
const rechargType = ref('');
|
||||||
|
const qrCodeText = ref('');
|
||||||
|
const rechargText = ref('');
|
||||||
|
|
||||||
|
// 移除proxy相关代码,直接使用响应式数据
|
||||||
|
const t_notice_status = ref([]);
|
||||||
|
const t_recharge_way = ref([]);
|
||||||
|
|
||||||
|
const pddGoodsList = ref([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const shopId = ref('');
|
||||||
|
const loadingText = ref('正在加载数据');
|
||||||
|
|
||||||
|
const queryFormRef = ref();
|
||||||
|
const noticeFormRef = ref();
|
||||||
|
const userRechargeFormRef = ref();
|
||||||
|
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const repeatDataDialog = ref(false);
|
||||||
|
const repeatLoading = ref(false);
|
||||||
|
const repeatDataList = ref([]);
|
||||||
|
const repeatTotal = ref(0);
|
||||||
|
const repeatQuery = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10
|
||||||
|
});
|
||||||
|
const selectedRepeatItems = ref([]);
|
||||||
|
|
||||||
|
const initFormData = {
|
||||||
|
created_at: undefined,
|
||||||
|
goods_id: undefined,
|
||||||
|
goods_name: undefined,
|
||||||
|
goods_quantity: undefined,
|
||||||
|
goods_reserve_quantity: undefined,
|
||||||
|
image_url: undefined,
|
||||||
|
is_more_sku: undefined,
|
||||||
|
is_onsale: undefined,
|
||||||
|
sku_list: undefined,
|
||||||
|
thumb_url: undefined,
|
||||||
|
price: undefined,
|
||||||
|
skuCode: undefined
|
||||||
|
};
|
||||||
|
const data = reactive({
|
||||||
|
form: { ...initFormData },
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
created_at: undefined,
|
||||||
|
goods_id: undefined,
|
||||||
|
goods_name: undefined,
|
||||||
|
goods_quantity: undefined,
|
||||||
|
goods_reserve_quantity: undefined,
|
||||||
|
image_url: undefined,
|
||||||
|
is_more_sku: undefined,
|
||||||
|
is_onsale: undefined,
|
||||||
|
sku_list: undefined,
|
||||||
|
thumb_url: undefined,
|
||||||
|
price: undefined,
|
||||||
|
skuCode: undefined,
|
||||||
|
params: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//加密需要的数据
|
||||||
|
const encrypForm = reactive({
|
||||||
|
dataUrl: undefined,
|
||||||
|
shopPrice: undefined,
|
||||||
|
maxPrice: undefined,
|
||||||
|
minPrice: undefined,
|
||||||
|
shopId: undefined,
|
||||||
|
shopType: undefined,
|
||||||
|
totalCount: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const pricingLink = ref('');
|
||||||
|
|
||||||
|
const priceName = ref('');
|
||||||
|
|
||||||
|
const { queryParams, form } = toRefs(data);
|
||||||
|
|
||||||
|
//表单校验
|
||||||
|
const encrypFormRef = ref(); // 表单引用
|
||||||
|
const encrypRules = {
|
||||||
|
shopPrice: [
|
||||||
|
{ required: true, message: '请输入店铺优惠', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const num = Number(value);
|
||||||
|
if (!Number.isInteger(num)) {
|
||||||
|
callback(new Error('必须输入整数'));
|
||||||
|
} else if (num < 0 || num > 20) {
|
||||||
|
callback(new Error('请输入0-20之间的整数'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
minPrice: [
|
||||||
|
{ required: true, message: '请输入利润最小值', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (!Number.isInteger(Number(value))) {
|
||||||
|
callback(new Error('必须输入整数'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
maxPrice: [
|
||||||
|
{ required: true, message: '请输入利润最大值', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
validator: function (rule, value, callback) {
|
||||||
|
const min = Number(encrypForm.minPrice);
|
||||||
|
const max = Number(value);
|
||||||
|
if (!Number.isInteger(max)) {
|
||||||
|
callback(new Error('必须输入整数'));
|
||||||
|
} else if (max <= min) {
|
||||||
|
callback(new Error('最大值必须大于最小值'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}.bind(this),
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 查询消息通知列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const isOnsale = queryParams.value.is_onsale ? queryParams.value.is_onsale : '';
|
||||||
|
const res = await pddGoodsApi.getShopGoodsList(shopId.value, isOnsale, queryParams.value.pageNum, queryParams.value.pageSize);
|
||||||
|
|
||||||
|
// 调试信息:打印API返回的原始数据
|
||||||
|
console.log('API返回的原始数据:', res);
|
||||||
|
|
||||||
|
// 处理后端返回的数据结构
|
||||||
|
if (res.data) {
|
||||||
|
pddGoodsList.value = res.data.records || [];
|
||||||
|
total.value = res.data.total || 0;
|
||||||
|
console.log('使用res.data结构,records数量:', pddGoodsList.value.length, '总数:', total.value);
|
||||||
|
} else {
|
||||||
|
// 如果直接返回分页数据结构
|
||||||
|
pddGoodsList.value = res.records || [];
|
||||||
|
total.value = res.total || 0;
|
||||||
|
console.log('使用直接结构,records数量:', pddGoodsList.value.length, '总数:', total.value);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = { ...initFormData };
|
||||||
|
noticeFormRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = async () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出
|
||||||
|
*/
|
||||||
|
const exportData = async () => {
|
||||||
|
const isOnsale = queryParams.value.is_onsale ? queryParams.value.is_onsale : '';
|
||||||
|
|
||||||
|
proxy?.download(
|
||||||
|
'huidiao/pdd/emportShopGoods',
|
||||||
|
{
|
||||||
|
'shopId': shopId.value,
|
||||||
|
'isOnsale': isOnsale
|
||||||
|
},
|
||||||
|
`baseInfo_${new Date().getTime()}.xlsx`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createVerifyPriceUrl = async () => {
|
||||||
|
if (!shopId.value) {
|
||||||
|
ElMessage.error('请先选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pddGoodsList.value.length === 0) {
|
||||||
|
proxy?.$modal.msgError('当前店铺没有商品数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
loadingVerifyUrl.value = true;
|
||||||
|
const allNum = await getShopTaskAllNum(shopId.value, '1');
|
||||||
|
console.log("res1",allNum)
|
||||||
|
if (allNum.data > 0) {
|
||||||
|
verifyPriceUrl.value = shopId.value;
|
||||||
|
shopTotalCount.value = allNum.data;
|
||||||
|
verifyPriceDialog.value = true;
|
||||||
|
} else {
|
||||||
|
ElMessage.error('请先同步店铺数据');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('生成核价链接出错:', error);
|
||||||
|
ElMessage.error('生成核价链接出错');
|
||||||
|
} finally {
|
||||||
|
loadingVerifyUrl.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟API调用,替换成你实际的API
|
||||||
|
const createVerifyPriceUrlApi = async (shopId) => {
|
||||||
|
// 这里应该是你的实际API调用,例如:
|
||||||
|
return await getVerifyPriceUrl(shopId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyVerifyUrl = () => {
|
||||||
|
if (!verifyPriceUrl.value) return;
|
||||||
|
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(verifyPriceUrl.value)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('链接已复制到剪贴板');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('复制失败:', err);
|
||||||
|
ElMessage.error('复制链接失败');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详细商品支付选择
|
||||||
|
*/
|
||||||
|
const handleAdd = async () => {
|
||||||
|
const checkRes = await getShopGoodsTask(shopId.value);
|
||||||
|
if (checkRes.code == 200) {
|
||||||
|
//获取总数
|
||||||
|
const totalData = await pddGoodsApi.getShopGoodsTotalNum(shopId.value);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '充值';
|
||||||
|
rechargText.value = '查询店铺总数据条数:' + totalData.data + '; 充值金额为:' + (Math.ceil((totalData.data / 10000) * 100) / 100).toFixed(2);
|
||||||
|
buttonLoading.value = false;
|
||||||
|
} else {
|
||||||
|
ElMessage.error(checkRes.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmTongBu = () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessageBox.confirm('本操作将删除选择店铺的所有商品再从孔网拉取,请谨慎操作,点击确定将执行该操作。', '提示', { type: 'warning' }).then(() => {
|
||||||
|
tongBu();
|
||||||
|
}).catch(() => { });
|
||||||
|
};
|
||||||
|
|
||||||
|
const tongBu = async () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sycFlag = 1;
|
||||||
|
const checkRes = await getShopGoodsTask(shopId.value);
|
||||||
|
|
||||||
|
if (checkRes.code == 200) {
|
||||||
|
const res = await pddGoodsApi.createShopGoodsList(shopId.value, sycFlag);
|
||||||
|
ElMessage.success(res.msg);
|
||||||
|
} else {
|
||||||
|
ElMessage.error(checkRes.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const tongBu1 = async () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sycFlag = 2;
|
||||||
|
const checkRes = await getShopGoodsTask(shopId.value);
|
||||||
|
|
||||||
|
if (checkRes.code == 200) {
|
||||||
|
const res = await pddGoodsApi.createShopGoodsList(shopId.value, sycFlag);
|
||||||
|
ElMessage.success(res.msg);
|
||||||
|
} else {
|
||||||
|
ElMessage.error(checkRes.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tongBuDetail = async () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rechargType.value == null || rechargType.value == undefined || rechargType.value == '') {
|
||||||
|
ElMessage.error('请选择支付方式');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonLoading.value = true;
|
||||||
|
//获取总数,生成二维码
|
||||||
|
const totalData = await pddGoodsApi.getShopGoodsTotalNum(shopId.value);
|
||||||
|
|
||||||
|
if (totalData.code == 200 && totalData.data > 0) {
|
||||||
|
//数量除以10000向上取
|
||||||
|
const price = (Math.ceil((totalData.data / 10000) * 100) / 100).toFixed(2);
|
||||||
|
const data = {
|
||||||
|
'rechargType': '1',
|
||||||
|
'rechargPrice': price
|
||||||
|
};
|
||||||
|
const res = await userRecharge(data);
|
||||||
|
|
||||||
|
if (res.code == 200) {
|
||||||
|
qrCodeText.value = 'data:image/png;base64,' + res.data.img;
|
||||||
|
dialog.visiblePrcode = true;
|
||||||
|
dialog.titlePrcode = '支付';
|
||||||
|
//定时器 2分钟持续获取 支付单据状态
|
||||||
|
let count = 0;
|
||||||
|
const maxCount = 40; // 两分钟内,每隔三秒打印一次,总共打印40次
|
||||||
|
let intervalId = setInterval(async () => {
|
||||||
|
if (count < maxCount) {
|
||||||
|
const status = await checkTask(res.data.id);
|
||||||
|
if (status == '1') {
|
||||||
|
count = 80;
|
||||||
|
const res = await pddGoodsApi.createShopGoodsDetailList(shopId.value);
|
||||||
|
ElMessage.success(res.msg);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
if (count == 40) {
|
||||||
|
editRechargeToError(res.data.id);
|
||||||
|
}
|
||||||
|
dialog.visible = false;
|
||||||
|
dialog.visiblePrcode = false;
|
||||||
|
qrCodeText.value = undefined;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
getList();
|
||||||
|
clearInterval(intervalId); // 停止定时器
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error('未获取到店铺商品数量信息');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentPreviewImg = ref(''); // 仅存储当前点击的图片
|
||||||
|
// 点击事件处理
|
||||||
|
const handlePreview = (imgUrl) => {
|
||||||
|
currentPreviewImg.value = imgUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection) => {
|
||||||
|
ids.value = selection.map((item) => item.id);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
const shopList = ref([]);
|
||||||
|
const getShopList = async () => {
|
||||||
|
const res = await getListShop();
|
||||||
|
console.log("res",res)
|
||||||
|
if (res.code === 200 && Array.isArray(res.data)) {
|
||||||
|
shopList.value = res.data.map(item => ({
|
||||||
|
value: item.id,
|
||||||
|
label: item.shopName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatTimestamp = (row, column, timestamp) => {
|
||||||
|
if (!timestamp) return '';
|
||||||
|
|
||||||
|
// 将10位时间戳转为毫秒(JS的Date需要毫秒)
|
||||||
|
const date = new Date(timestamp * 1000);
|
||||||
|
|
||||||
|
// 格式化为 YYYY-MM-DD hh:mm:ss
|
||||||
|
const padZero = (num) => num.toString().padStart(2, '0');
|
||||||
|
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = padZero(date.getMonth() + 1);
|
||||||
|
const day = padZero(date.getDate());
|
||||||
|
const hours = padZero(date.getHours());
|
||||||
|
const minutes = padZero(date.getMinutes());
|
||||||
|
const seconds = padZero(date.getSeconds());
|
||||||
|
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
};
|
||||||
|
//加密链接生成
|
||||||
|
const encrypMethod = async () => {
|
||||||
|
try {
|
||||||
|
// 1. 执行表单验证
|
||||||
|
await encrypFormRef.value?.validate();
|
||||||
|
|
||||||
|
// 2. 验证通过后,设置加载状态
|
||||||
|
loadingVerifyUrl.value = true;
|
||||||
|
|
||||||
|
// 3. 准备请求数据 - 将元转换为分
|
||||||
|
const requestData = {
|
||||||
|
...encrypForm,
|
||||||
|
shopPrice: Math.round(Number(encrypForm.shopPrice) * 100), // 元转分
|
||||||
|
minPrice: Math.round(Number(encrypForm.minPrice) * 100), // 元转分
|
||||||
|
maxPrice: Math.round(Number(encrypForm.maxPrice) * 100), // 元转分
|
||||||
|
dataUrl: verifyPriceUrl.value,
|
||||||
|
shopId: shopId.value,
|
||||||
|
totalCount: shopTotalCount.value,
|
||||||
|
shopType: '1' // 假设这是拼多多店铺类型
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4. 调用加密接口
|
||||||
|
const res = await encrypUrlMenthod(requestData);
|
||||||
|
|
||||||
|
// 5. 处理结果
|
||||||
|
if (res) {
|
||||||
|
pricingLink.value = res.url;
|
||||||
|
if (res.url != null) {
|
||||||
|
priceName.value = res.name;
|
||||||
|
}
|
||||||
|
ElMessage.success('核价链接生成成功');
|
||||||
|
} else {
|
||||||
|
ElMessage.warning('拼多多以外店铺正在开发中,请重新选择');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 验证失败会直接进入catch,不需要额外处理
|
||||||
|
console.error('表单验证失败:', error);
|
||||||
|
} finally {
|
||||||
|
loadingVerifyUrl.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//一键复制核价链接
|
||||||
|
const copyLink = async () => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(pricingLink.value);
|
||||||
|
ElMessage.success('复制成功');
|
||||||
|
} catch (err) {
|
||||||
|
ElMessage.error('复制失败,请手动复制');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const closeData = async () => {
|
||||||
|
pricingLink.value = null;
|
||||||
|
encrypForm.dataUrl = null;
|
||||||
|
encrypForm.shopId = null;
|
||||||
|
encrypForm.shopPrice = null;
|
||||||
|
encrypForm.maxPrice = null;
|
||||||
|
encrypForm.minPrice = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去重
|
||||||
|
*/
|
||||||
|
|
||||||
|
const repeatData = async () => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repeatQuery.pageNum = 1;
|
||||||
|
repeatQuery.pageSize = 10;
|
||||||
|
repeatTotal.value = 0;
|
||||||
|
repeatDataList.value = [];
|
||||||
|
buttonLoading.value = false;
|
||||||
|
|
||||||
|
repeatDataDialog.value = true;
|
||||||
|
try {
|
||||||
|
getRepeatDataList();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取重复数据失败:', error);
|
||||||
|
ElMessage.error('获取重复数据失败');
|
||||||
|
repeatLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRepeatDataList = async () => {
|
||||||
|
repeatLoading.value = true;
|
||||||
|
const res = await getRepeatData(shopId.value, repeatQuery.pageNum, repeatQuery.pageSize);
|
||||||
|
// 处理后端返回的数据结构
|
||||||
|
if (res.data) {
|
||||||
|
repeatDataList.value = res.data.records || [];
|
||||||
|
repeatTotal.value = res.data.total || 0;
|
||||||
|
} else {
|
||||||
|
// 如果直接返回分页数据结构
|
||||||
|
repeatDataList.value = res.records || [];
|
||||||
|
repeatTotal.value = res.total || 0;
|
||||||
|
}
|
||||||
|
repeatLoading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加分页相关方法
|
||||||
|
const handleRepeatSizeChange = (val) => {
|
||||||
|
repeatQuery.pageSize = val;
|
||||||
|
getRepeatDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRepeatCurrentChange = (val) => {
|
||||||
|
repeatQuery.pageNum = val;
|
||||||
|
getRepeatDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整店上/下架
|
||||||
|
*/
|
||||||
|
const editIsOnSale = async (isOnSale) => {
|
||||||
|
if (shopId.value == null || shopId.value == undefined || shopId.value == '') {
|
||||||
|
ElMessage.error('请选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await pddGoodsApi.editShopGoodsAllByIsOnSale(shopId.value, isOnSale);
|
||||||
|
|
||||||
|
if (res.code == 200) {
|
||||||
|
ElMessage.success(res.msg);
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量下架任务
|
||||||
|
*/
|
||||||
|
const batchOffShelf = async () => {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
const check = await selectTaskStatusByTaskType(shopId.value, 'BATCH_SET_SOLD_OUT');
|
||||||
|
if (check.code == 200) {
|
||||||
|
const res = await pddGoodsApi.batchSetSoldOut(shopId.value);
|
||||||
|
repeatDataDialog.value = false;
|
||||||
|
buttonLoading.value = false;
|
||||||
|
ElMessage.success(res.msg);
|
||||||
|
} else {
|
||||||
|
ElMessage.error(check.msg);
|
||||||
|
buttonLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getShopList();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 翻新上架相关变量
|
||||||
|
const renovateDialogVisible = ref(false); // 弹窗显示控制
|
||||||
|
const uploadFile = ref(); // 上传文件引用
|
||||||
|
const fileList = ref([]); // 文件列表
|
||||||
|
const uploading = ref(false); // 上传状态
|
||||||
|
|
||||||
|
// 显示翻新上架弹窗
|
||||||
|
const showRenovateDialog = () => {
|
||||||
|
if (!shopId.value) {
|
||||||
|
proxy?.$modal.msgError('请先选择店铺');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renovateDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理文件上传
|
||||||
|
const handleUpload = async () => {
|
||||||
|
if (fileList.value.length === 0) {
|
||||||
|
ElMessage.error('请先选择CSV文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uploading.value = true;
|
||||||
|
const file = fileList.value[0].raw;
|
||||||
|
const res = await batchRenovateOnSaleByCsv(file, shopId.value);
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success(res.msg || '已受理翻新上架请求');
|
||||||
|
renovateDialogVisible.value = false;
|
||||||
|
fileList.value = []; // 清空文件列表
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '翻新上架失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('翻新上架出错:', error);
|
||||||
|
ElMessage.error('翻新上架出错');
|
||||||
|
} finally {
|
||||||
|
uploading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 文件上传前校验
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
const isCSV = file.type === 'text/csv' || file.name.endsWith('.csv');
|
||||||
|
if (!isCSV) {
|
||||||
|
ElMessage.error('只能上传CSV格式文件');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 文件变化处理
|
||||||
|
const handleFileChange = (file, fileList) => {
|
||||||
|
uploadFile.value = file;
|
||||||
|
fileList.value = fileList.slice(-1); // 只保留最新上传的文件
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 文本溢出处理 */
|
||||||
|
.truncate-cell {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-price-dialog {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.url-display {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips p {
|
||||||
|
margin: 5px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-demo {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1442
src/views/shopOrder/index.vue
Normal file
1442
src/views/shopOrder/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user