Commit 10c1edcf by linjinhong

Merge remote-tracking branch 'origin/master' into linjinhong

parents e22d350f 84ed5778
......@@ -6,6 +6,7 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const ElInput: typeof import('element-plus/es')['ElInput']
const ElLoading: typeof import('element-plus/es')['ElLoading']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
......
......@@ -7,10 +7,10 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AmountInput: typeof import('./src/components/Form.vue/AmountInput.vue')['default']
AmountInput: typeof import('./src/components/Form/AmountInput.vue')['default']
CommonCard: typeof import('./src/components/CommonCard.vue')['default']
DatePicker: typeof import('./src/components/Form.vue/DatePicker.vue')['default']
DateRangePicker: typeof import('./src/components/Form.vue/DateRangePicker.vue')['default']
DatePicker: typeof import('./src/components/Form/DatePicker.vue')['default']
DateRangePicker: typeof import('./src/components/Form/DateRangePicker.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
......@@ -49,6 +49,8 @@ declare module 'vue' {
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload']
......@@ -59,11 +61,11 @@ declare module 'vue' {
RenderColumn: typeof import('./src/components/RenderColumn.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Select: typeof import('./src/components/Form.vue/Select.vue')['default']
Select: typeof import('./src/components/Form/Select.vue')['default']
ShipmentOrderDetail: typeof import('./src/components/ShipmentOrderDetail.vue')['default']
SplitDiv: typeof import('./src/components/splitDiv/splitDiv.vue')['default']
'Switch ': typeof import('./src/components/Form.vue/Switch .vue')['default']
TableRightMenu: typeof import('./src/components/TableRightMenu.vue')['default']
'Switch ': typeof import('./src/components/Form/Switch .vue')['default']
TableRightClickMenu: typeof import('./src/components/TableRightClickMenu.vue')['default']
TableView: typeof import('./src/components/TableView.vue')['default']
UploadExcel: typeof import('./src/components/UploadExcel.vue')['default']
UploadImage: typeof import('./src/components/UploadImage.vue')['default']
......
......@@ -9,7 +9,7 @@ import { AddDeclarationRuleObj } from '@/views/logistics/types/declarationRule'
import { LogisticsQuotation } from '@/views/logistics/types/logisticsQuotation'
import { LogisticsPartitionObj } from '@/views/logistics/types/logisticsPartition'
import { ShippingAddressObj } from '@/views/logistics/types/shippingAddress'
import { IsortingInfo } from '@/types/api/logistics'
export interface ILogisticsList {
code: string
basicsName: string
......@@ -433,3 +433,37 @@ export function logisticsCompanyAllCodelist() {
'/logisticsCompany/allCodelist',
)
}
export function getsortingConfigListApi(
data: IsortingInfo,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<IsortingInfo>>(
'logistics/sortingConfig/list_page',
{
...data,
currentPage,
pageSize,
},
)
}
export function createSortingApi(data: IsortingInfo) {
return axios.post<never, BaseRespData<never>>(
'logistics/sortingConfig/add',
data,
)
}
export function updateSortingApi(data: IsortingInfo) {
return axios.post<never, BaseRespData<never>>(
'logistics/sortingConfig/update',
data,
)
}
export function deleteSortingApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
'logistics/sortingConfig/delete',
{
params: { ids },
},
)
}
import { BasePaginationData, BaseRespData, RejectParams } from '@/types/api'
import { BasePaginationData, BaseRespData } from '@/types/api'
import axios from './axios'
import { PaymentForm } from '@/types/api/index.ts'
import {
LogListData,
OrderData,
......@@ -11,6 +10,8 @@ import {
ShipmentOrderRes,
Tab,
InspectionData,
PaymentForm,
RejectParams
} from '@/types/api/order'
import {
apiSubmitPodOrderForm,
......@@ -151,7 +152,7 @@ export function apiSetCraftData({
}: {
id: number | undefined
craftTotalPrice: number | undefined
recNumber:string|undefined
recNumber: string | undefined
craftPriceList: IUpdatePrice[]
}) {
return axios.post<never, BaseRespData<never>>(
......
......@@ -37,6 +37,12 @@ export function getOrderList(
},
)
}
export function handleExceptionOrderApi(orderIds: number[]) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/processExceptionOrders',
orderIds,
)
}
export function getCardOrderList(
params: SearchForm,
currentPage: number,
......@@ -80,14 +86,17 @@ export function updateExceptionOrderApi(data: number[]) {
},
)
}
export function changeExceptionOrderApi(ids: number[], value: string) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderUs/exceptionOrders',
{
orderIds: ids,
exceptionReason: value,
},
)
export function changeExceptionOrderApi(
url: string,
ids: number[],
type: string,
value: string,
) {
return axios.post<never, BaseRespData<never>>(url, {
orderIds: ids,
exceptionType: type,
exceptionReason: value,
})
}
export function cancelOrderApi(ids: number[], value: string) {
return axios.post<never, BaseRespData<never>>(
......
......@@ -314,9 +314,9 @@ export function InRecordBatchCheckPrintApi(ids: string) {
},
)
}
export function warehouseInRecordInventory(data: ExportInWarehouseInfo) {
export function warehouseInRecordExport(data: ExportInWarehouseInfo) {
return axios.post<never, BasePaginationData<never>>(
'factory/warehouseInRecord/inventory',
'factory/warehouseInRecord/export',
data,
)
}
......@@ -438,6 +438,20 @@ export function getInRecordLogApi(inRecordId?: number) {
)
}
// 出库单
export function warehouseOutRecordExport(data: ExportInWarehouseInfo) {
return axios.post<never, BasePaginationData<never>>(
'factory/warehouseOutRecord/export',
data,
)
}
export function OutRecordBatchCheckPrintApi(ids: string) {
return axios.get<never, BaseRespData<never[]>>(
'factory/warehouseOutRecord/batchCheckPrint',
{
params: { ids },
},
)
}
export function getOutRecordStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factory/warehouseOutRecord/status_tree',
......
......@@ -2,12 +2,12 @@ import { defineComponent, PropType, ref, computed, h } from 'vue'
import type { Component } from 'vue'
import { ElInput, ElForm, ElFormItem } from 'element-plus'
import type { FormInstance } from 'element-plus'
import AmountInput from './Form.vue/AmountInput.vue' // 金额输入框
import DateRangePicker from './Form.vue/DateRangePicker.vue' // 时间范围选择器
import DatePicker from './Form.vue/DatePicker.vue' // 单个日期选择器
import Select from './Form.vue/Select.vue' // 普通下拉选择框
import Switch from './Form.vue/Switch .vue'
import './Form.vue/form.scss'
import AmountInput from './Form/AmountInput.vue' // 金额输入框
import DateRangePicker from './Form/DateRangePicker.vue' // 时间范围选择器
import DatePicker from './Form/DatePicker.vue' // 单个日期选择器
import Select from './Form/Select.vue' // 普通下拉选择框
import Switch from './Form/Switch .vue'
import './Form/form.scss'
import type { FormItemRule } from 'element-plus'
......
......@@ -10,6 +10,7 @@
mode="horizontal"
background-color="#001529"
text-color="#fff"
style="border-bottom: none;"
:default-active="defaultActive"
router
>
......@@ -86,8 +87,9 @@
>
<div class="nav-tabs-node_label">
<span>{{ item.title }}</span>
<!-- 首页不可删除 -->
<el-icon
v-if="tabs.length > 1"
v-if="item.path != '/dashboard' && tabs.length > 1"
class="el-icon-close"
@click.stop="removeTab(item.name)"
>
......
import { defineComponent, PropType, ref, computed, watch, h } from 'vue'
import type { Component } from 'vue'
import AmountInput from './Form.vue/AmountInput.vue' // 金额输入框
import DateRangePicker from './Form.vue/DateRangePicker.vue' // 时间范围选择器
import DatePicker from './Form.vue/DatePicker.vue' // 单个日期选择器
import Select from './Form.vue/Select.vue' // 普通下拉选择框
import AmountInput from './Form/AmountInput.vue' // 金额输入框
import DateRangePicker from './Form/DateRangePicker.vue' // 时间范围选择器
import DatePicker from './Form/DatePicker.vue' // 单个日期选择器
import Select from './Form/Select.vue' // 普通下拉选择框
import { ElInput, ElForm, ElFormItem, ElButton } from 'element-plus'
import {
ISearchForm,
......
<template>
<div
v-show="visible"
class="right-click-menu"
:style="{ left: position.x + 'px', top: position.y + 'px' }"
>
<div class="menu-item" @click="handleSelectAll">全选</div>
<div class="menu-item" @click="handleUnselectAll">取消全选</div>
<div class="menu-item" @click="onChangeCopy('shop-numbers')">
复制店铺单号
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineExpose, onMounted, onUnmounted } from 'vue'
import type { TableInstance } from 'element-plus'
const visible = ref(false)
const position = ref({ x: 0, y: 0 })
const tableRef = ref<TableInstance>()
const emit = defineEmits(['onChange'])
const setPosition = ({
x,
y,
el,
}: {
x: number
y: number
el: TableInstance
}) => {
position.value = { x, y }
visible.value = true
tableRef.value = el
}
const handleSelectAll = () => {
if (tableRef.value) {
tableRef.value.toggleAllSelection()
}
visible.value = false
}
const handleUnselectAll = () => {
if (tableRef.value) {
tableRef.value.clearSelection()
}
visible.value = false
}
const onChangeCopy = (value: string) => {
emit('onChange', value)
visible.value = false
}
// 点击其他地方关闭菜单
const handleClickOutside = () => {
if (visible.value) {
visible.value = false
}
}
// 监听全局点击事件
onMounted(() => {
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
})
defineExpose({
setPosition,
})
</script>
<style scoped>
.right-click-menu {
position: fixed;
background: white;
border: 1px solid #e4e7ed;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3000;
}
.menu-item {
padding: 8px 16px;
cursor: pointer;
font-size: 14px;
color: #606266;
}
.menu-item:hover {
background-color: #f5f7fa;
color: #409eff;
}
</style>
<template>
<div
v-if="tableRightMenuVisible"
class="table-right-menu"
:style="{
left: rightMenuOptions.contextMenuX + 'px',
top: rightMenuOptions.contextMenuY + 'px',
}"
>
<div
class="table-right-menu-item"
@click="handleChange('copy_shop_number')"
>
<span>复制店铺单号</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
defineProps({
tableRightMenuVisible: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['onCopyChange'])
const handleChange = (type: string) => {
emit('onCopyChange', type)
}
const rightMenuOptions = ref({
contextMenuX: 0,
contextMenuY: 0,
})
const setRightMenuOptions = (options: {
contextMenuX: number
contextMenuY: number
}) => {
rightMenuOptions.value = options
}
defineExpose({
setRightMenuOptions,
})
</script>
<style lang="scss" scoped>
.table-right-menu {
position: fixed;
z-index: 1000;
border: 1px solid #ccc;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
padding: 6px;
}
.table-right-menu-item {
padding: 5px;
cursor: pointer;
font-size: 14px;
&:hover {
background-color: #f0f0f0;
}
}
</style>
......@@ -8,6 +8,7 @@
v-bind="attrs"
header-align="center"
height="100%"
@contextmenu.prevent="handleContextMenu"
>
<ElTableColumn
v-if="selectionable"
......@@ -57,14 +58,20 @@
</RenderColumn>
</template>
</ElTable>
<RightClickMenu ref="rightMenuRef" @on-change="onChange" />
</div>
</template>
<script setup lang="tsx" generic="T">
import { type Slot, useAttrs, useSlots, type PropType, shallowRef } from 'vue'
import type { CustomColumn } from '@/types/table'
import RenderColumn from './RenderColumn.vue'
import RightClickMenu from './TableRightClickMenu.vue'
import { ElTable } from 'element-plus'
const tableRef = shallowRef<InstanceType<typeof ElTable>>()
import type { TableInstance } from 'element-plus'
const tableRef = shallowRef<TableInstance>()
const rightMenuRef = shallowRef<InstanceType<typeof RightClickMenu>>()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
defineProps({
paginatedData: {
......@@ -88,14 +95,30 @@ defineProps({
default: false,
},
})
const attrs = useAttrs()
const slots = useSlots() as Record<string, Slot>
const emit = defineEmits(['onChange'])
const handleContextMenu = (e: MouseEvent) => {
if (rightMenuRef.value && tableRef.value) {
rightMenuRef.value.setPosition({
x: e.clientX,
y: e.clientY,
el: tableRef.value,
})
}
}
const onChange = (type: string) => {
emit('onChange', type)
}
const setCurrentRow = (row: T) => {
tableRef.value?.setCurrentRow(row)
}
const toggleRowSelection = (row: T, selected: boolean = true) => {
tableRef.value?.toggleRowSelection(row, selected)
}
const clearSelection = () => {
tableRef.value?.clearSelection()
}
......@@ -112,5 +135,6 @@ defineExpose({
.table-view {
height: 100%;
overflow: hidden;
position: relative;
}
</style>
[
{
"name": "Shopify",
"lowercase": "shopify",
"type": "SHOPIFY",
"icon": "images/icon/logo-1.png",
"cycle": "today",
"route": "store_profits_shopify"
},
{
"name": "AliExpress",
"lowercase": "aliExpress",
"type": "AE",
"icon": "./images/icon/logo-3.png",
"cycle": "today",
"route": "store_profits_aliexpress"
},
{
"name": "Amazon",
"lowercase": "amazon",
"type": "AMAZON",
"icon": "./images/icon/logo-2.png",
"cycle": "yesterday",
"route": "store_profits_amazon"
},
{
"name": "Magento",
"lowercase": "magento",
"type": "MAGENTO",
"icon": "./images/icon/logo-6.png",
"cycle": "today",
"route": "store_profits_magento"
},
{
"name": "SHOPLINE",
"lowercase": "shopline",
"type": "SHOPLINE",
"cycle": "today",
"icon": "./images/icon/logo-4.png",
"route": "store_profits_shopline"
},
{
"name": "Shoplazza",
"lowercase": "shoplazza",
"type": "SHOPLAZZA",
"cycle": "today",
"icon": "./images/icon/logo-5.png",
"route": "store_profits_shoplazza"
},
{
"name": "temu",
"lowercase": "temu",
"type": "TEMU",
"cycle": "today",
"icon": "./images/icon/temu.png",
"route": "store_profits_temu"
},
{
"name": "eBay",
"lowercase": "ebay",
"type": "EBAY",
"cycle": "today",
"icon": "./images/icon/eBay.png",
"route": "store_profits_ebay"
},
{
"name": "Etsy",
"lowercase": "etsy",
"type": "ETSY",
"cycle": "today",
"icon": "./images/icon/etsy.png",
"route": "store_profits_etsy"
},
{
"name": "Alibaba",
"lowercase": "alibaba",
"type": "ALIBABA",
"cycle": "today",
"icon": "./images/icon/alibaba.png",
"route": "store_profits_alibaba"
},
{
"name": "walmart",
"lowercase": "walmart",
"type": "WALMART",
"cycle": "today",
"icon": "images/icon/walmart.png",
"route": "store_profits_walmart"
},
{
"name": "tiktokshop",
"lowercase": "tiktok",
"type": "TIKTOK",
"cycle": "today",
"icon": "images/icon/tiktokshop.png",
"route": "store_profits_tiktokshop"
},
{
"name": "Customize",
"lowercase": "customize",
"type": "CUSTOMIZE",
"cycle": "today",
"icon": "images/icon/customize.png",
"route": "store_profits_customize"
},
{
"name": "1688",
"type": "ALIBABA_DOMESTIC",
"cycle": "today",
"icon": "images/icon/1688.png",
"route": "store_profits_1688"
}
]
......@@ -27,8 +27,8 @@ import WarehouseManage from '@/views/warehouse/manage.vue'
import WarehouseWarning from '@/views/warehouse/warning.vue'
import WarehousePosition from '@/views/warehouse/position.vue'
import receiptDoc from '@/views/warehouse/receiptDoc.vue'
import issueDoc from '@/views/warehouse/issueDoc.vue'
import ExternalAuthorisationPage from '@/views/system/externalAuthorisationPage.vue'
// import issueDoc from '@/views/warehouse/issueDoc.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
......@@ -176,6 +176,13 @@ const router = createRouter({
},
component: () => import('@/views/logistics/logisticsCalculate.vue'),
},
{
path: '/logistics/sortingConfiguration',
meta: {
title: '分拣配置',
},
component: () => import('@/views/logistics/sortingConfiguration.vue'),
},
{
path: '/warehouse/manage',
meta: {
......@@ -190,13 +197,13 @@ const router = createRouter({
},
component: receiptDoc,
},
// {
// path: '/warehouse/issue-doc',
// meta: {
// title: '出库单',
// },
// component: issueDoc,
// },
{
path: '/warehouse/issue-doc',
meta: {
title: '出库单',
},
component: issueDoc,
},
{
path: '/warehouse/warning',
meta: {
......
......@@ -56,6 +56,11 @@ const menu: MenuItem[] = [
id: 6,
label: '运费试算',
},
{
index: '/logistics/sortingConfiguration',
id: 7,
label: '分拣配置',
},
],
},
{
......@@ -73,11 +78,11 @@ const menu: MenuItem[] = [
id: 123,
label: '入库单',
},
// {
// index: '/warehouse/issue-doc',
// id: 124,
// label: '出库单',
// },
{
index: '/warehouse/issue-doc',
id: 124,
label: '出库单',
},
{
index: '/warehouse/manage',
......
......@@ -35,17 +35,4 @@ export interface baseRes {
code: number
msg: string
}
export interface PaymentForm {
waterList: string
id?: number | string
actualAmount?: number | string
payableAmount?: number | string
recNumber?: number | string
}
export interface RejectParams {
id: number
description?: string
ids?: string
pass?: number
}
export interface Ilogistics {
id: number
name: string
warehouseId: number
warehouseName: string
uinuinWarehouseId: number | null
companyId: number | null
company: string | null
serviceCode: string
siteUrl: string
status: number
factoryId: number
createTime: string
updateTime: string | null
}
export interface IsortingInfo {
id?: number
sortingArea: number | null
sortingAreaName?: string | null
serviceCode: string | null
}
......@@ -81,7 +81,7 @@ export interface ProductList {
subOrderNumber?: string
shopNumber?: string
material?: string
materialPrice?: number|null
materialPrice?: number | null
count?: number
baseSku?: string
erpSubOrderNumber?: string
......@@ -277,3 +277,16 @@ export interface ICompareObjects {
lanshouPost?: string
lanshouRegion?: string
}
export interface PaymentForm {
waterList: string
id?: number | string
actualAmount?: number | string
payableAmount?: number | string
recNumber?: number | string
}
export interface RejectParams {
id: number
description?: string
ids?: string
pass?: number
}
......@@ -16,6 +16,9 @@ export interface SearchForm {
customizedQuantity: string
startTime: string | null
endTime: string | null
exceptionHandling: number | undefined
platform: string
productionClient:string
}
export interface PodUsOrderListData {
id: number
......
......@@ -5,6 +5,8 @@ export interface warehouseSearchForm {
billStatus?: string
createTimeEnd?: string
createTimeStart?: string
startTime?: string
endTime?: string
inNo?: string
outNo?: string
warehouseSku?: string
......@@ -14,6 +16,7 @@ export interface warehouseSearchForm {
export interface InterProductList {
createTime?: string
id?: number
inventoryId?: number | null
inId?: number
productNo?: string | null //custom的货号
buyStored?: number | null //入库数量
......@@ -42,6 +45,7 @@ export interface InterWarehouseBase {
total?: number
totalPrice?: number
billStatus?: string
billStatusTxt?: string
remark?: string | null
dataVersion?: number
createTime?: string | null
......@@ -86,6 +90,9 @@ export interface InterProductList {
warehouseSku?: string
locationId?: number | null
locationCode?: string | null
inventory?: {
usableInventory?: number
}
}
export interface InterskuList {
id?: number
......@@ -101,6 +108,7 @@ export interface InterskuList {
price?: number | null //出库单的
usableInventory?: number | null
warehouseSku?: string
remark?: string | null
}
export interface ILocation {
id?: number
......
......@@ -108,7 +108,6 @@ export function checkUpdateParams(
removeList = arr1.map((item) => item['id'] as IdType)
}
if (isBackKeyName) {
console.log(isBackKeyName)
// 将列表直接添加到 params 顶层
if (addList.length > 0) params['addList'] = addList || undefined
if (updateList.length > 0)
......
<script setup lang="ts">
import { Ilogistics, IsortingInfo } from '@/types/api/logistics'
import { Edit, Delete } from '@element-plus/icons-vue'
import {
getsortingConfigListApi,
usableAllList,
createSortingApi,
updateSortingApi,
deleteSortingApi,
} from '@/api/logistics.ts'
import { nextTick, ref } from 'vue'
import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import usePageList from '@/utils/hooks/usePageList'
const searchForm = ref({
sortingArea: null,
serviceCode: '',
})
const selections = ref<IsortingInfo[]>([])
const formRef = ref()
const form = ref<IsortingInfo>({
sortingArea: null,
sortingAreaName: '',
serviceCode: '',
})
const createData = ref({
title: '',
show: false,
isEdit: false,
form: {
sortingArea: null,
sortingAreaName: '',
serviceCode: '',
},
})
const rules = {
sortingArea: [{ required: true, message: '请选择分拣口', trigger: 'change' }],
serviceCode: [
{ required: true, message: '请选择物流方式', trigger: 'change' },
],
}
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
getsortingConfigListApi(
{
...searchForm.value,
},
page,
pageSize,
).then((res) => res.data),
})
const logisticsMethodsList = ref<Ilogistics[]>([])
const getlogisticsMethods = async () => {
const res = await usableAllList()
logisticsMethodsList.value = res.data || []
}
interface interSorting {
label: string
value: number
}
const sortingList = ref<interSorting[]>([
{
label: 'L1',
value: 1,
},
{
label: 'R1',
value: 2,
},
{
label: 'L2',
value: 3,
},
{
label: 'R2',
value: 4,
},
{
label: 'L3',
value: 5,
},
{
label: 'R3',
value: 6,
},
{
label: 'L4',
value: 7,
},
{
label: 'R4',
value: 8,
},
{
label: 'E0',
value: 9,
},
])
const handleSelectionChange = (data: IsortingInfo[]) => {
selections.value = data
}
const handleConfirm = async () => {
await formRef.value?.validate()
if (!createData.value.isEdit) {
await createSortingApi(form.value)
} else {
await updateSortingApi(form.value)
}
createData.value.show = false
ElMessage.success('操作成功')
await search()
}
const handleBatchDelete = async (row: IsortingInfo | null) => {
if (!row && !selections.value.length) {
return ElMessage.warning('请选择要删除的数据')
}
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
const str =
row && row.id
? row.id?.toString()
: selections.value.map((el: IsortingInfo) => el.id).join(',')
await deleteSortingApi(str)
ElMessage.success('删除成功')
await search()
}
const createWarehouse = () => {
createData.value.show = true
createData.value.isEdit = false
createData.value.title = '新增'
form.value = {
sortingArea: null,
sortingAreaName: '',
serviceCode: '',
}
nextTick(() => {
formRef.value?.clearValidate()
})
}
const updateSorting = (item: IsortingInfo) => {
createData.value.show = true
createData.value.isEdit = true
createData.value.title = '修改'
form.value = {
sortingArea: item.sortingArea,
sortingAreaName: item.sortingAreaName,
serviceCode: item.serviceCode,
}
nextTick(() => {
formRef.value?.clearValidate()
})
}
getlogisticsMethods()
const sortingChange = (v: number) => {
const warehouse = sortingList.value.find((w: interSorting) => w.value == v)
form.value.sortingAreaName = warehouse ? warehouse.label : ''
}
</script>
<template>
<split-div>
<template #top>
<el-card>
<el-form inline :model="searchForm">
<el-form-item label="分拣口">
<el-select
v-model="searchForm.sortingArea"
clearable
style="width: 160px"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="物流方式">
<el-select
v-model="searchForm.serviceCode"
clearable
filterable
style="width: 160px"
>
<el-option
v-for="item in logisticsMethodsList"
:key="item.serviceCode"
:label="item.serviceCode"
:value="item.serviceCode"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="createWarehouse">新增</el-button>
<el-button type="danger" @click="handleBatchDelete(null)"
>删除</el-button
>
</el-form-item>
</el-form>
</el-card>
</template>
<template #bottom>
<el-card style="height: 100%">
<div class="manage">
<div class="table-flex">
<div class="left-table">
<div class="table-container">
<el-table
height="100%"
:data="tableData"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />
<el-table-column type="index" label="序号" width="60" />
<el-table-column
align="center"
label="分拣口名称"
prop="sortingAreaName"
></el-table-column>
<el-table-column
align="center"
label="物流编码"
prop="serviceCode"
></el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="{ row }">
<el-icon
size="24"
title="编辑"
color="#EF6C00"
style="cursor: pointer; vertical-align: middle"
@click="updateSorting(row)"
>
<Edit />
</el-icon>
<el-icon
size="24"
title="删除"
color="#f56c6c"
style="cursor: pointer; vertical-align: middle"
@click="handleBatchDelete(row)"
>
<Delete />
</el-icon>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination">
<!-- <el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:page-sizes="[50, 100, 150, 200]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/> -->
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</div>
</div>
<el-dialog
v-model="createData.show"
width="500px"
:title="createData.title"
>
<el-form
ref="formRef"
label-width="110px"
:rules="rules"
:model="form"
>
<el-form-item label="分拣口" prop="sortingArea">
<el-select
v-model="form.sortingArea"
clearable
@change="sortingChange"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="物流方式" prop="serviceCode">
<el-select v-model="form.serviceCode" clearable filterable>
<el-option
v-for="item in logisticsMethodsList"
:key="item.serviceCode"
:label="item.serviceCode"
:value="item.serviceCode"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="createData.show = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</el-dialog>
</div>
</el-card>
</template>
</split-div>
</template>
<style scoped lang="scss">
.el-card {
::v-deep(.el-card__body) {
height: 100%;
}
}
.manage {
height: 100%;
display: flex;
flex-direction: column;
.header {
margin-bottom: 10px;
}
.table-flex {
flex: 1;
flex-shrink: 0;
overflow: hidden;
display: flex;
}
.right-table {
flex: 1;
margin-left: 10px;
flex-shrink: 0;
}
.left-table {
height: 100%;
display: flex;
width: 100%;
flex-direction: column;
.pagination {
display: flex;
margin-top: 10px;
justify-content: center;
}
.table-container {
flex: 1;
flex-shrink: 0;
overflow: hidden;
}
}
}
</style>
......@@ -271,9 +271,11 @@
v-loading="loading"
element-loading-text="加载中..."
class="order-list flex-1 overflow-hidden"
@contextmenu.prevent="handleContextMenu"
>
<ElTable
v-show="statusCode !== 6"
ref="tableRef"
:data="tableData"
:span-method="arraySpanMethod"
default-expand-all
......@@ -597,6 +599,7 @@
</ElTable>
<ElTable
v-show="statusCode === 6"
ref="tableQaRef"
:data="tableData"
:span-method="arraySpanMethod"
default-expand-all
......@@ -973,6 +976,12 @@
>
<OrderDetail :order-detail-data="orderDetailData" />
</ElDrawer>
<RightMenu
ref="rightMenuRef"
:show-copy-count="false"
:show-copy-sub-shop-number="statusCode !== 6"
@change="onChange"
/>
</template>
<script setup lang="ts">
import Shipment from './Shipment.vue'
......@@ -990,7 +999,12 @@ import type {
} from '@/types/api/order'
import { nextTick, onMounted, reactive, ref } from 'vue'
import useElTableColumnWidth from '@/utils/hooks/useElTableColumnWidth'
import { ArrowDown, ArrowUp, DocumentCopy, EditPen } from '@element-plus/icons-vue'
import {
ArrowDown,
ArrowUp,
DocumentCopy,
EditPen,
} from '@element-plus/icons-vue'
import usePageList from '@/utils/hooks/usePageList'
import {
getOrderList,
......@@ -1023,6 +1037,7 @@ import OrderDetail from './OrderDetail.vue'
import useShipment from './hook/useShipment'
import useQuarantine from './hook/useQuarantine'
import Quarantine from './Quarantine.vue'
import RightMenu from './pod/rightMenu.vue'
const [searchForm] = useValue<SearchForm>({
mainSku: '',
......@@ -1644,7 +1659,65 @@ const cancelOrder = async (id: number) => {
// showError(e)
}
}
const rightMenuRef = ref()
const handleContextMenu = (e: MouseEvent) => {
rightMenuRef.value?.setPosition({
x: e.clientX,
y: e.clientY,
cardItem: e.clientY,
el: e,
})
}
const tableQaRef = ref()
const tableRef = ref()
const onChange = (key: string) => {
if (key === 'check_all') {
if (statusCode.value === 6) {
tableQaRef.value?.toggleAllSelection()
} else {
tableRef.value?.toggleAllSelection()
}
} else if (key === 'clear_check') {
if (statusCode.value === 6) {
tableQaRef.value?.clearSelection()
} else {
tableRef.value?.clearSelection()
}
} else if (key === 'copy_code') {
const shopNumberList: string[] = []
for (const item of selection.value) {
item.productList?.forEach((el) => {
if (el.shopNumber) {
shopNumberList.push(el.shopNumber)
}
})
}
copy(shopNumberList.join(','))
} else if (key === 'copy_shopNumber') {
const subOrderNumber: string[] = []
if (statusCode.value === 6) {
for (const item of selection.value) {
item.detailList?.forEach((el) => {
if (el.shopNumber) {
subOrderNumber.push(el.shopNumber || '')
}
})
}
} else {
for (const item of selection.value) {
item.productList?.forEach((el) => {
if (el.subOrderNumber) {
subOrderNumber.push(el.subOrderNumber)
}
})
}
}
copy(subOrderNumber.join(','))
} else if (key === 'count') {
const count = selection.value.length
copy(count.toString())
}
}
const onChangeCurrentRow = (item: ProductList) => {
currentRow.value = item
}
......
......@@ -231,7 +231,12 @@
v-if="['TO_BE_CONFIRMED', 'IN_PRODUCTION'].includes(status)"
class="item"
>
<ElButton :loading="syncLoading" type="warning" is-dark @click="synchronousPlan">
<ElButton
:loading="syncLoading"
type="warning"
is-dark
@click="synchronousPlan"
>
同步素材图</ElButton
>
</span>
......@@ -481,7 +486,7 @@
"
>
{{ cardItem?.processName }}
</span>
</span>
</el-col>
<el-col
:span="12"
......@@ -544,11 +549,10 @@
>
<img width="20" src="@/assets/images/id.png" />
<el-tooltip :content="cardItem?.productionFileId">
<span class="over-hidden" title="素材ID">
{{ cardItem?.productionFileId }}
</span>
<span class="over-hidden" title="素材ID">
{{ cardItem?.productionFileId }}
</span>
</el-tooltip>
</a>
</el-col>
<el-col
......@@ -594,7 +598,7 @@
default-expand-all
:span-method="arraySpanMethod"
@selection-change="handleSelectionChange"
@contextmenu.prevent="handleContextMenu"
@on-change="onChange"
>
<template #expand="{ row }">
<div v-if="row.productList" class="table-expand">
......@@ -974,6 +978,9 @@
:show-copy-shop-number="
['IN_PRODUCTION', 'TO_BE_CONFIRMED', 'WAIT_SHIPMENT'].includes(status)
"
:show-copy-count="
['IN_PRODUCTION', 'TO_BE_CONFIRMED', 'WAIT_SHIPMENT'].includes(status)
"
@change="rightChange"
/>
<fastProduction
......@@ -986,11 +993,6 @@
@on-success="handleSuccess"
@close="fastClose"
></fastProduction>
<table-right-menu
ref="tableRightMenuRef"
:table-right-menu-visible="tableRightMenuVisible"
@on-copy-change="onCopyChange"
/>
<el-dialog
v-model="completeShipmentVisible"
title="完成发货"
......@@ -1105,7 +1107,6 @@ import {
SearchForm,
Tab,
LogListData,
PodProductList,
cardImages,
imageAryInter,
......@@ -1825,7 +1826,9 @@ const synchronousPlan = async () => {
return
}
try {
const res = await syncSubOrderDesignImages(selection.value.map(item=>item.id))
const res = await syncSubOrderDesignImages(
selection.value.map((item) => item.id),
)
await loadDiffList()
await loadTabData()
syncLoading.value = false
......@@ -2161,10 +2164,8 @@ const invalidOrder = async (row: ProductList) => {
}
})
}
const tableRightMenuVisible = ref(false)
const tableRightMenuRef = ref()
const onCopyChange = (type: string) => {
if (type === 'copy_shop_number') {
const onChange = (type: string) => {
if (type === 'shop-numbers') {
const shopNumberList = []
for (const item of tableData.value) {
if (item.productList) {
......@@ -2174,16 +2175,6 @@ const onCopyChange = (type: string) => {
copy(shopNumberList.join(','))
}
}
const handleContextMenu = (e: MouseEvent) => {
tableRightMenuVisible.value = true
tableRightMenuRef.value?.setRightMenuOptions({
contextMenuX: e.clientX,
contextMenuY: e.clientY,
})
}
const listenerClick = () => {
tableRightMenuVisible.value = false
}
const getUserMark = async () => {
try {
......@@ -2208,7 +2199,6 @@ const openMaterial = async (item: PodProductList) => {
}
onMounted(async () => {
document.addEventListener('keydown', listenerKeydown)
document.addEventListener('click', listenerClick)
await loadTabData()
getUserMark()
getLogisticsList()
......@@ -2216,7 +2206,6 @@ onMounted(async () => {
})
onBeforeUnmount(() => {
document.removeEventListener('keydown', listenerKeydown)
document.removeEventListener('click', listenerClick)
})
</script>
<style lang="scss" scoped>
......@@ -2491,9 +2480,9 @@ onBeforeUnmount(() => {
display: flex;
align-items: center;
}
.over-hidden{
.over-hidden {
width: 150px;
display:inline-block;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
......
<template>
<!-- <div class="wrap" @click="close"> -->
<div v-if="show" ref="right_menu" class="right_menu">
<button @click="$emit('change', 'check_all')">
全部选择
</button>
<button @click="$emit('change', 'check_all')">全部选择</button>
<button @click="$emit('change', 'clear_check')">取消选择</button>
<button @click="$emit('change', 'copy_code')">复制选中生产单号</button>
<button v-if="showCopySubShopNumber" @click="$emit('change', 'copy_code')">
复制选中生产单号
</button>
<button v-if="showCopyShopNumber" @click="$emit('change', 'copy_shopNumber')">复制选中店铺单号</button>
<button v-if="showCopyShopNumber" @click="$emit('change', 'count')">统计数量</button>
<button
v-if="showCopyShopNumber"
@click="$emit('change', 'copy_shopNumber')"
>
复制选中店铺单号
</button>
<button v-if="showCopyCount" @click="$emit('change', 'count')">
统计数量
</button>
</div>
<!-- </div> -->
</template>
<script setup lang="ts">
import {ref,defineProps,defineExpose} from 'vue'
interface E{
x:number
el:HTMLElement
y:number
import { ref, defineProps, defineExpose } from 'vue'
interface E {
x: number
el: HTMLElement
y: number
}
defineProps({
showCopyShopNumber:{
type:Boolean,
default:true
}
showCopyShopNumber: {
type: Boolean,
default: true,
},
showCopyCount: {
type: Boolean,
default: true,
},
showCopySubShopNumber: {
type: Boolean,
default: true,
},
})
const row = ref()
const show = ref(false)
const right_menu = ref<HTMLElement>()
const close = ()=>{
const close = () => {
show.value = false
document.body.onclick = null
}
const setPosition = (o:E)=> {
const setPosition = (o: E) => {
console.log(o)
show.value = true
const clientX = o.x
......@@ -42,18 +57,17 @@ const setPosition = (o:E)=> {
document.body.onclick = function () {
close()
}
row.value =
setTimeout(() => {
if(!right_menu.value) return
row.value = setTimeout(() => {
if (!right_menu.value) return
if (x < 150) {
right_menu.value.style.cssText = `top:${o.y}px;right:${x}px`
} else {
right_menu.value.style.cssText = `top:${o.y}px;left:${o.x}px`
right_menu.value.style.cssText = `top:${o.y}px;left:${o.x}px`
}
}, 1)
}
defineExpose({
setPosition
setPosition,
})
</script>
<style scoped>
......@@ -89,7 +103,7 @@ defineExpose({
background: rgb(65, 192, 251);
color: white;
}
button{
button {
outline: none;
border: none;
}
......
......@@ -35,7 +35,7 @@
v-model="searchForm.userMark"
clearable
filterable
style="width: 180px"
style="width: 100px"
placeholder="客户"
>
<el-option
......@@ -46,12 +46,63 @@
></el-option>
</el-select>
</ElFormItem>
<ElFormItem label="定制类型">
<ElSelect
v-model="searchForm.customizedQuantity"
placeholder="定制类型"
clearable
style="width: 100px"
>
<ElOption label="单面" value="single" />
<ElOption label="多面" value="multiple" />
</ElSelect>
</ElFormItem>
<ElFormItem label="平台">
<ElSelect
v-model="searchForm.platform"
value-key=""
placeholder="请选择"
clearable
filterable
popper-class="customize-select-style"
style="width: 130px"
>
<ElOption
v-for="(item, index) in platformJson"
:key="index"
:label="item.type"
:value="item.type"
style="width: 160px"
>
<img
:src="`/images/icon/${item.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="item.type">{{ item.type }}</span>
</ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="生产端">
<ElSelect
v-model="searchForm.productionClient"
placeholder="生产端"
clearable
style="width: 130px"
>
<ElOption
v-for="(item, index) in productionClient"
:key="index"
:value="item.code || ''"
:label="`${item.remark}(${item.code})`"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="SKU">
<ElInput
v-model.trim="searchForm.sku"
placeholder=" SKU"
clearable
style="width: 180px"
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem label="Base SKU">
......@@ -59,7 +110,7 @@
v-model.trim="searchForm.baseSku"
placeholder=" Base SKU"
clearable
style="width: 180px"
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem label="物流跟踪号">
......@@ -67,7 +118,7 @@
v-model.trim="searchForm.logisticsTracking"
placeholder="物流跟踪号"
clearable
style="width: 180px"
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem label="生产单号">
......@@ -75,7 +126,7 @@
v-model="searchForm.factorySubOrderNumber"
placeholder="生产单号"
clearable
style="width: 180px"
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="订单号">
......@@ -83,7 +134,7 @@
v-model="searchForm.factoryOrderNumber"
placeholder="订单号"
clearable
style="width: 180px"
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="店铺单号">
......@@ -91,20 +142,10 @@
v-model="searchForm.shopNumber"
placeholder="店铺单号"
clearable
style="width: 180px"
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="定制类型">
<ElSelect
v-model="searchForm.customizedQuantity"
placeholder="定制类型"
clearable
style="width: 180px"
>
<ElOption label="单面" value="single" />
<ElOption label="多面" value="multiple" />
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
......@@ -120,11 +161,74 @@
@click="changeTab(item)"
>
<span class="tabs-node_label">{{ item.statusName }}</span>
<span class="tabs-node_count">{{ `(${item.quantity})` }}</span>
<span
class="tabs-node_count"
:class="{
blue: item.quantity && item.quantity > 0,
red: item.status === 'EXCEPTION_ORDER',
}"
>{{ item.quantity }}</span
>
</div>
<!-- <div
v-if="item.status === 'EXCEPTION_ORDER'"
:key="item.status"
class="tabs-node"
>
<el-dropdown @command="handleExceptionCommand">
<div>
<span
class="tabs-node_label"
style="color: #000; font-weight: 500"
>
异常单
</span>
<span
class="tabs-node_count"
:class="{
blue: item.quantity && item.quantity > 0,
red: item.status === 'EXCEPTION_ORDER',
}"
>{{ item.quantity }}</span
>
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="1">待分派</el-dropdown-item>
<el-dropdown-item command="2">待处理</el-dropdown-item>
<el-dropdown-item command="3">已处理</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> -->
</div>
</div>
<div class="order-content flex-1 flex-column overflow-hidden mt-10">
<div v-if="status === 'EXCEPTION_ORDER'" class="sub-status mb-10">
<div
class="sub-status-item"
:class="exceptionStatus === 1 ? 'sub-active' : ''"
@click="handleExceptionCommand(1)"
>
<span class="sub-status-item-label">待分派</span>
</div>
<div
class="sub-status-item"
:class="exceptionStatus === 2 ? 'sub-active' : ''"
@click="handleExceptionCommand(2)"
>
<span class="sub-status-item-label">待处理</span>
</div>
<div
class="sub-status-item"
:class="exceptionStatus === 3 ? 'sub-active' : ''"
@click="handleExceptionCommand(3)"
>
<span class="sub-status-item-label">待同步</span>
</div>
</div>
<div class="operation-box mb-10">
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="success" @click="confirmOrder"> 确认 </ElButton>
......@@ -132,6 +236,20 @@
<span v-if="status === 'EXCEPTION_ORDER'" class="item">
<ElButton type="success" @click="updateOrder"> 转至待确认 </ElButton>
</span>
<span
v-if="status === 'EXCEPTION_ORDER' && exceptionStatus === 1"
class="item"
>
<ElButton type="warning" @click="assignOrder"> 分派 </ElButton>
</span>
<!-- <span
v-if="status === 'EXCEPTION_ORDER' && exceptionStatus === 2"
class="item"
>
<ElButton type="warning" @click="handleExceptionOrder">
处理异常
</ElButton>
</span> -->
<span v-if="status === 'PICKING'" class="item">
<ElButton type="primary" @click="printProductionOrder">
打印生产单
......@@ -246,6 +364,7 @@
:paginated-data="tableData"
:cell-style="onCellStyle"
@selection-change="handleSelectionChange"
@on-change="onChange"
>
<template #goods="{ row }">
<div class="goods-info-box">
......@@ -456,21 +575,17 @@
</div>
<div class="order-detail-item">
<span class="order-detail-item-label">物流跟踪号:</span>
<!-- <span
class="order-detail-item-value"
:title="row.trackingNumber"
>
{{ row.trackingNumber }}
</span> -->
<el-button
type="primary"
:title="row.trackingNumber"
link
:disabled="!row.expressSheet"
@click="downloadFacebook(row.expressSheet)"
>
{{ row.trackingNumber }}</el-button
>
<span class="order-detail-item-value">
<el-button
type="primary"
:title="row.trackingNumber"
link
:disabled="!row.expressSheet"
@click="downloadFacebook(row.expressSheet)"
>
{{ row.trackingNumber }}</el-button
>
</span>
<el-icon class="icon" @click="copy(row.trackingNumber || '')">
<DocumentCopy />
</el-icon>
......@@ -578,7 +693,24 @@
</div>
</template>
<template #time="{ row }">
<div class="order-time-box">
<el-timeline style="max-width: 600px">
<el-timeline-item
:color="row.createTime ? '#409EFF' : ''"
:timestamp="row.createTime"
>创建时间</el-timeline-item
>
<el-timeline-item
:color="row.startStockingTime ? '#E6A23C' : ''"
:timestamp="row.startStockingTime"
>确认时间</el-timeline-item
>
<el-timeline-item
:color="row.finishTime ? '#67C23A' : ''"
:timestamp="row.finishTime"
>完成时间</el-timeline-item
>
</el-timeline>
<!-- <div class="order-time-box">
<div class="order-time-item">
<span class="order-time-item-label">创建时间:</span>
<span class="order-time-item-value">
......@@ -591,19 +723,14 @@
{{ row.startStockingTime }}
</span>
</div>
<!-- <div class="order-time-item">
<span class="order-time-item-label">支付时间:</span>
<span class="order-time-item-value">
{{ row.paymentTime }}
</span>
</div> -->
<div class="order-time-item">
<span class="order-time-item-label">完成时间:</span>
<span class="order-time-item-value">
{{ row.finishTime }}
</span>
</div>
</div>
</div> -->
</template>
<template #innerLabel="{ row }">
<div v-if="row.internalMemoList" class="inner-label-box">
......@@ -782,7 +909,7 @@
</div>
<right-menu
ref="rightMenuRef"
:show-copy-shop-number="false"
:show-copy-count="false"
@change="rightChange"
/>
<el-dialog
......@@ -938,8 +1065,8 @@
:title="wayDialogTitle"
>
<el-table
v-loading="isChangeWayLoading"
ref="changeWayRef"
v-loading="isChangeWayLoading"
height="400px"
class="production-client-table"
:data="logisticsWayData"
......@@ -1004,15 +1131,20 @@
@open="handleExceptionDialogOpen"
>
<ElForm ref="exceptionFormRef" :model="exceptionForm" label-width="100px">
<!-- <ElFormItem
<ElFormItem
label="异常类型"
prop="exceptionType"
:rules="{ required: true, message: '请选择异常类型' }"
:rules="
status === 'EXCEPTION_ORDER'
? { required: true, message: '请选择异常类型' }
: {}
"
>
<ElSelect
v-model="exceptionForm.exceptionType"
style="width: 100%"
placeholder="请选择异常类型"
clearable
>
<ElOption
v-for="type in exceptionTypes"
......@@ -1021,11 +1153,15 @@
:value="type.value"
/>
</ElSelect>
</ElFormItem> -->
</ElFormItem>
<ElFormItem
label="异常原因"
prop="exceptionReason"
:rules="{ required: true, message: '请输入异常原因' }"
:rules="
status !== 'EXCEPTION_ORDER'
? { required: true, message: '请输入异常原因' }
: {}
"
>
<ElInput
v-model="exceptionForm.exceptionReason"
......@@ -1079,6 +1215,7 @@ import {
createLogisticsOrderApi,
updateLogisticsToPickingApi,
createLogisticsOrdersApi,
// handleExceptionOrderApi,
} from '@/api/podUsOrder'
import { BaseRespData } from '@/types/api'
......@@ -1097,7 +1234,7 @@ import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import { showConfirm } from '@/utils/ui'
import { DocumentCopy, EditPen } from '@element-plus/icons-vue'
import { Column } from 'element-plus'
import { Column, ElFormItem } from 'element-plus'
import { computed, onMounted, ref, nextTick } from 'vue'
import FastProduction from './FastProduction.vue'
import { filePath } from '@/api/axios'
......@@ -1108,6 +1245,7 @@ import dayjs from 'dayjs'
import rightMenu from '../pod/rightMenu.vue'
import ResultInfo from './components/ResultInfo.vue'
import { isArray, isString } from '@/utils/validate'
import platformJson from '../../../json/platform.json'
declare global {
interface Window {
ActiveXObject: {
......@@ -1145,7 +1283,11 @@ const [searchForm] = useValue<SearchForm>({
customizedQuantity: '',
startTime: null,
endTime: null,
exceptionHandling: undefined,
platform: '',
productionClient: '',
})
const exceptionStatus = ref(1)
const userMarkList = ref<string[]>([])
const selection = ref<PodUsOrderListData[]>([])
const pickerOptions = {
......@@ -1235,7 +1377,7 @@ const tableColumns = computed(() => [
slot: 'price',
width: 160,
prop: 'price',
align: 'center',
align: 'left',
},
{
label: '时间',
......@@ -1335,6 +1477,10 @@ const {
? timeRange.value[1]
: null,
status: status.value,
exceptionHandling:
status.value === 'EXCEPTION_ORDER'
? exceptionStatus.value || undefined
: undefined,
},
page,
pageSize,
......@@ -1511,6 +1657,44 @@ const updateOrder = async () => {
loading.close()
}
}
const assignOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
currentOrderIds.value = selection.value.map((item) => item.id)
exceptionDialogVisible.value = true
}
// const handleExceptionOrder = async () => {
// if (selection.value.length === 0) {
// return ElMessage.warning('请选择数据')
// }
// try {
// await showConfirm('确定处理异常吗?', {
// confirmButtonText: '确认',
// cancelButtonText: '取消',
// type: 'warning',
// })
// } catch {
// return
// }
// const orderIds = selection.value.map((item) => item.id)
// const loading = ElLoading.service({
// fullscreen: true,
// text: '操作中...',
// background: 'rgba(0, 0, 0, 0.3)',
// })
// try {
// const res = await handleExceptionOrderApi(orderIds)
// if (res.code !== 200) return
// ElMessage.success('操作成功')
// search()
// loadTabData()
// } catch (e) {
// console.error(e)
// } finally {
// loading.close()
// }
// }
const printProductionOrder = async () => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
......@@ -1584,12 +1768,10 @@ const pickingComplete = async () => {
loading.close()
}
}
const exceptionType = ref('')
const exceptionReason = ref('')
// const exceptionTypes = [
// { value: '1', label: '客户' },
// { value: '2', label: '工厂' },
// ]
const exceptionTypes = [
{ value: '1', label: '客户' },
{ value: '2', label: '工厂' },
]
const exceptionDialogVisible = ref(false)
const currentOrderIds = ref<number[]>([])
const exceptionForm = ref({
......@@ -1602,10 +1784,6 @@ const changeExceptionOrder = async () => {
return ElMessage.warning('请选择数据')
}
currentOrderIds.value = selection.value.map((item) => item.id)
// 重置状态
exceptionType.value = ''
exceptionReason.value = ''
exceptionDialogVisible.value = true
}
......@@ -1621,10 +1799,15 @@ const handleExceptionConfirm = async () => {
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const url =
status.value === 'EXCEPTION_ORDER'
? 'factory/podJomallOrderUs/distributionExceptionOrders'
: 'factory/podJomallOrderUs/exceptionOrders'
try {
const res = await changeExceptionOrderApi(
url,
currentOrderIds.value,
// exceptionForm.value.exceptionType,
exceptionForm.value.exceptionType,
exceptionForm.value.exceptionReason,
)
if (res.code !== 200) return
......@@ -1699,6 +1882,10 @@ const rightChange = async (code: string) => {
.join()
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
} else if (code === 'copy_shopNumber') {
const str = cardSelection.value.map((item) => item.shopNumber).join()
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
}
}
const currentImage = ref('')
......@@ -2304,6 +2491,21 @@ onMounted(() => {
loadProductionClient()
loadWarehouseList()
})
const onChange = (value: string) => {
if (value === 'shop-numbers') {
const shopNumbers = (tableData.value as PodUsOrderListData[])
.map((item) => item.shopNumber)
.join(',')
navigator.clipboard.writeText(shopNumbers).then(() => {
ElMessage.success('店铺单号已复制到剪贴板')
})
}
}
const handleExceptionCommand = (command: number) => {
exceptionStatus.value = command
search()
}
</script>
<style lang="scss" scoped>
.header-filter-form {
......@@ -2326,6 +2528,7 @@ onMounted(() => {
color: #000;
cursor: pointer;
height: 40px;
font-weight: 500;
}
.tabs-node:hover {
......@@ -2394,6 +2597,29 @@ onMounted(() => {
height: 100%;
overflow-y: auto;
}
.tabs-node_count {
display: inline-block;
min-width: 20px;
height: 20px;
line-height: 20px;
border-radius: 50%;
font-size: 14px;
text-align: center;
margin-left: 4px;
background: #f2f3f5; // 默认灰色
color: #666;
font-weight: 500;
}
.tabs-node_count.blue {
background: rgb(219, 234, 254);
color: rgb(30, 64, 175);
}
.tabs-node_count.red {
background: rgb(254 226 226);
color: rgb(153 27 27);
}
.empty {
height: 100%;
......@@ -2462,4 +2688,40 @@ onMounted(() => {
}
}
}
.sub-status {
display: flex;
align-items: center;
border-bottom: 1px solid #e5e6eb;
background: #fff;
.sub-status-item {
position: relative;
font-size: 16px;
cursor: pointer;
padding: 6px 24px 6px 24px;
border: 1px solid #e5e6eb;
background: #f7f8fa;
color: #606266;
margin-bottom: -1px;
transition: background 0.2s, color 0.2s;
&:not(:last-child) {
border-right: none;
}
&.sub-active {
background: #fff;
color: #1d2129;
font-weight: 600;
border-bottom: 1px solid transparent;
z-index: 2;
}
}
}
</style>
<style>
.customize-select-style {
.el-select-dropdown__list {
width: 500px;
display: flex;
flex-wrap: wrap;
}
}
</style>
......@@ -31,7 +31,7 @@
<template #top>
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="采购仓库">
<ElFormItem label="仓库">
<ElSelect
v-model="searchForm.warehouseId"
clearable
......@@ -117,10 +117,10 @@
>
删除
</el-button>
<!-- <el-button type="success" @click="handleExport"> 导出 </el-button>
<el-button type="success" @click="handleExport"> 导出 </el-button>
<el-button type="primary" @click="printProductTag">
打印商品SKU标签
</el-button> -->
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="warning"
......@@ -190,7 +190,7 @@
<ElTableColumn
label="单据状态"
width="130"
prop="billStatus"
prop="billStatusTxt"
header-align="center"
align="center"
></ElTableColumn>
......@@ -211,14 +211,6 @@
align="center"
></ElTableColumn>
<ElTableColumn
label="物流单号"
show-overflow-tooltip
prop="shipmentNumber"
width="200"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="总金额(¥)"
show-overflow-tooltip
width="120"
......@@ -259,6 +251,7 @@
align="center"
></ElTableColumn>
<ElTableColumn
v-if="nodeCode === 'PENDING_SUBMIT'"
width="100"
align="center"
header-align="center"
......@@ -572,13 +565,13 @@
<div class="product-dialog-footer">
<div>
<el-input
v-model="selectSku"
v-model.trim="selectSku"
placeholder="商品SKU"
style="width: 200px; margin: 0 10px"
clearable
size="small"
></el-input>
<el-popover placement="top-start" width="900" trigger="click">
<el-popover placement="top-start" width="1000" trigger="click">
<div v-if="skuData.length > 0" style="height: 50vh">
<ElTable size="small" :data="skuData" height="100%" border>
<ElTableColumn
......@@ -658,14 +651,14 @@
</el-button>
</template>
</el-popover>
<!-- <el-button
<el-button
style="margin-left: 6px"
type="success"
size="small"
@click="addPurchase"
>
批量新增
</el-button> -->
</el-button>
<el-button
type="danger"
style="margin-left: 10px"
......@@ -706,7 +699,7 @@
>
<el-form :model="exportForm" label-width="80px">
<el-form-item label="" prop="resource">
<el-radio-group v-model="exportForm.resource">
<el-radio-group v-model="exportForm.resource" @change="isAllExport">
<el-radio :label="0">导出本页</el-radio>
<el-radio :label="1">导出选中</el-radio>
<el-radio :label="2">全部</el-radio>
......@@ -724,7 +717,7 @@
</template>
</ElDialog>
<el-dialog v-model="showPrintDialog" title="打印参数设置">
<el-table height="400px" :data="selections" border>
<el-table height="400px" :data="printData" border>
<el-table-column
width="60"
align="center"
......@@ -743,18 +736,18 @@
></el-table-column>
<el-table-column
align="center"
prop="locationCode"
prop="locationName"
label="库位编码"
></el-table-column>
<el-table-column
align="center"
prop="productNo"
label="货号 "
prop="supplierItemNo"
label="货号"
></el-table-column>
<el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }">
<el-input
v-model="row.number"
v-model.number="row.number"
oninput="value=value.replace(/[^\-?\d.]/g,'')"
placeholder="打印数量"
clearable
......@@ -767,6 +760,33 @@
<el-button type="primary" @click="handlePrintProductTag">打印</el-button>
</template>
</el-dialog>
<ElDialog
v-model="addPurchaseVisible"
title="批量添加"
width="500px"
:close-on-click-modal="false"
>
<div>
<el-input
v-model.trim="purchaseTextarea"
type="textarea"
placeholder="请输入库存 SKU"
:rows="5"
minlength="1"
maxlength="1000"
show-word-limit
/>
<div style="margin-top: 12px; color: #777">
{{ '多个字段使用_##_,_##_隔开' }}
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="addPurchaseVisible = false">取消</el-button>
<el-button type="primary" @click="submitPurchase">确认</el-button>
</span>
</template>
</ElDialog>
</template>
<script setup lang="ts">
......@@ -793,9 +813,11 @@ import {
rejectOutRecordApi,
LogListData,
warehouseInfo,
warehouseOutRecordExport,
factoryWarehouseInventoryPrint,
OutRecordBatchCheckPrintApi,
} from '@/api/warehouse'
// factoryWarehouseInventoryPrint,
// import { filePath } from '@/api/axios.ts'
import { filePath } from '@/api/axios'
import BigNumber from 'bignumber.js'
import { ref, onMounted, watch, nextTick } from 'vue'
import 'element-plus/dist/index.css'
......@@ -943,6 +965,11 @@ const logList = ref<LogListData[]>([])
const rules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const isAllExport = () => {
if (exportForm.value.resource == '2') {
ElMessage.warning('最多支持5000条!')
}
}
const nodeCode = ref<string>(
sessionStorage.getItem('InRecord_NodeCode') || 'all',
)
......@@ -962,12 +989,12 @@ const {
{
...searchForm.value,
billStatus: nodeCode.value == 'all' ? 'all' : nodeCode.value,
createTimeStart: tradingTime.value && tradingTime.value[0],
createTimeEnd: tradingTime.value && tradingTime.value[1],
startTime: tradingTime.value && tradingTime.value[0],
endTime: tradingTime.value && tradingTime.value[1],
},
page,
pageSize,
).then((res) => res.data) as never,
).then((res) => res.data),
})
const setCostPrice = (item: InterProductList) => {
......@@ -995,72 +1022,192 @@ const getTreeNum = async () => {
}
}
const showPrintDialog = ref(false)
// const printProductTag = async () => {
// if (!selections.value.length) {
// return ElMessage.warning('请选择要操作的数据')
// }
// showPrintDialog.value = true
// selections.value.forEach((el:InterWarehousePage) => {
// el.number = ''
// })
// }
const printData = ref([])
const printProductTag = async () => {
if (!selections.value.length) {
return ElMessage.warning('请选择要操作的数据')
}
const str = selections.value.map((el: InterWarehousePage) => el.id).join(',')
try {
const res = await OutRecordBatchCheckPrintApi(str)
if (res.code === 200) {
printData.value = res.data
showPrintDialog.value = true
} else {
ElMessage.error(res.message)
}
} catch (e) {
console.error(e)
}
}
async function handlePrintProductTag() {
// const flag = selections.value.every((el:InterWarehousePage) => el.number && el.number != '0')
// if (!flag) {
// return ElMessage.warning('打印数量需大于0')
// }
// const list = selections.value.map((item:InterWarehousePage) => {
// return {
// skuName: item.skuName,
// warehouseSku: item.warehouseSku,
// supplierItemNo: item.productNumber,
// number: item.number,
// locationName: item.locationCode,
// }
// })
// const res = await factoryWarehouseInventoryPrint({
// list,
// code: 'PT002',
// })
// showPrintDialog.value = false
// window.open(filePath + res.message, '_blank')
const flag = printData.value.every(
(el: InterWarehousePage) => el.number && el.number != '0',
)
if (!flag) {
return ElMessage.warning('打印数量需大于0')
}
const list = printData.value.map(
({
skuName = '',
warehouseSku = '',
supplierItemNo = '',
number = '',
locationName = '',
}) => ({
skuName,
warehouseSku,
supplierItemNo,
number,
locationName,
}),
)
const res = await factoryWarehouseInventoryPrint({
list,
code: 'PT002',
})
showPrintDialog.value = false
window.open(filePath + res.message, '_blank')
}
const batchAddCommodity = async (sku: string): Promise<InterskuList[]> => {
if (!editForm.value.warehouseId) {
ElMessage.error('请选择仓库')
return []
}
try {
const res = await getBySkuAndWarehouseIdApi(editForm.value.warehouseId, sku)
const arr: InterskuList[] = res.data || []
const ids: Record<string, boolean> = {}
// 过滤掉商品列表已经加了的
for (const item of otherPurchaseData.value) {
if (item.warehouseSku !== undefined) {
ids[item.warehouseSku] = true
}
}
// 使用 filter 方法过滤掉已经存在的 SKU
const filteredArr = arr.filter((currentItem: InterskuList) => {
return (
currentItem.warehouseSku === undefined || !ids[currentItem.warehouseSku]
)
})
return filteredArr
} catch (e) {
console.error(e)
return []
}
}
interface InterImportData {
warehouseSku: string;
remark?: string | null;
buyStored?: string | number | null | object; // 扩大 buyStored 类型,以兼容原始数据
[propName: string]: string | number | boolean | undefined | unknown
}
// 前端导入Excel
const excelFieldMap: Record<string, keyof InterProductList> = {
SKU图片: 'skuImage',
const excelFieldMap: Record<string, keyof InterImportData> = {
// SKU图片: 'skuImage',
商品SKU: 'warehouseSku',
SKU名称: 'skuName',
出库数量: 'outCount',
可用库存数量: 'usableInventory',
'成本价(¥)': 'costPrice',
'总成本(¥)': 'totalPrice',
库位: 'locationCode',
// SKU名称: 'skuName',
// 出库数量: 'outCount',
// 可用库存数量: 'usableInventory',
// '成本价(¥)': 'costPrice',
// '总成本(¥)': 'totalPrice',
// 库位: 'locationCode',
备注: 'remark',
}
const handleLocalImport = ({
const handleLocalImport = async ({
path,
data,
}: {
path: string
data: InterProductList[]
data: Record<string, any>[]
}) => {
const result: InterProductList[] = data.map((item) => {
const obj = {} as InterProductList
Object.keys(excelFieldMap).forEach((excelKey) => {
const field = excelFieldMap[excelKey] as keyof InterProductList
const value = item[excelKey]
// // 类型转换和默认值
// if (['outCount', 'costPrice', 'totalPrice'].includes(field)) {
// value = value == null || value === '' ? 0 : Number(value)
// } else {
// value = value == null ? '' : value
// }
obj[field] = value as InterProductList[typeof field]
})
return obj
})
otherPurchaseData.value = result
// 1. 将原始导入数据映射到 InterImportData[]
const importedData: InterImportData[] = data.map(item => {
const obj: InterImportData = { warehouseSku: '' };
Object.keys(excelFieldMap).forEach(excelKey => {
const field = excelFieldMap[excelKey];
const value = item[excelKey];
if (field === 'warehouseSku') {
obj[field] = typeof value === 'string' ? value : String(value ?? '');
} else if (field === 'remark') {
obj[field] = typeof value === 'string' ? value : (value === null || value === undefined ? null : String(value));
} else if (field === 'buyStored') {
// 处理 buyStored: 确保它是一个数字、数字字符串,否则设置为 null
if (typeof value === 'number') {
obj[field] = String(value); // 将数字转换为字符串
} else if (typeof value === 'string' && !isNaN(Number(value))) {
obj[field] = value; // 保持有效的数字字符串
} else {
// 如果不是数字或有效的数字字符串,则设置为 null
obj[field] = null;
}
} else {
obj[field] = value;
}
});
return obj;
}).filter(item => item.warehouseSku);
if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的商品SKU');
importDialogVisible.value = false;
return;
}
// 2. 提取导入的 SKU 列表
const importedSkus = importedData.map(item => item.warehouseSku).join(',');
// 3. 调用 batchAddCommodity 获取商品的完整信息并过滤掉已有的 SKU
const filteredSkusList = await batchAddCommodity(importedSkus);
if (filteredSkusList.length === 0) {
ElMessage.warning('导入的商品SKU已存在或无效');
importedFileUrl.value = path;
importDialogVisible.value = false;
return;
}
// 4. 将备注信息合并到获取到的商品列表中
const mergedProductList = filteredSkusList.map(skuItem => {
const importedItem = importedData.find(item => item.warehouseSku === skuItem.warehouseSku);
let outCountValueForBigNumber: string | number = '0'; // 初始化为安全默认值
if (importedItem?.buyStored !== null && importedItem?.buyStored !== undefined) {
if (typeof importedItem.buyStored === 'string' && !isNaN(Number(importedItem.buyStored))) {
outCountValueForBigNumber = importedItem.buyStored;
} else if (typeof importedItem.buyStored === 'number') {
outCountValueForBigNumber = importedItem.buyStored;
} else {
// 如果是对象或其他意外类型,则默认为 '0'
outCountValueForBigNumber = '0';
}
}
const calculatedOutCount = new BigNumber(outCountValueForBigNumber).toNumber();
return {
skuImage: skuItem.image,
warehouseSku: skuItem.warehouseSku,
skuName: skuItem.skuName,
productNo: skuItem.productNumber,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.price,
outCount: calculatedOutCount,
totalPrice: new BigNumber(calculatedOutCount).multipliedBy(skuItem.price ?? 0).toNumber(),
usableInventory: skuItem.usableInventory,
inventoryId: skuItem.id,
remark: importedItem?.remark ?? skuItem.remark ?? null,
} as InterProductList;
});
// 5. 更新 otherPurchaseData
otherPurchaseData.value = [...otherPurchaseData.value, ...mergedProductList];
importedFileUrl.value = path
importDialogVisible.value = false
}
......@@ -1069,10 +1216,46 @@ const exportForm = ref({
delivery: false,
resource: '',
})
// const handleExport = () => {
// exportVisible.value = true
// }
const submitExportForm = () => {}
const handleExport = () => {
exportVisible.value = true
}
const submitExportForm = async () => {
if (exportForm.value.resource === '') {
return ElMessage.error('请选择导出类型')
}
let purchaseIds: number[] = []
let exportTotal: number | undefined = undefined
const params: AnyObject = {}
const resourceType = Number(exportForm.value.resource)
if (resourceType === 0) {
purchaseIds = (tableData.value as InterWarehousePage[]).map(
(el: InterWarehousePage) => Number(el.id),
)
} else if (resourceType === 1) {
purchaseIds = selections.value.map((el: InterWarehousePage) =>
Number(el.id),
)
} else if (resourceType === 2) {
purchaseIds = []
exportTotal = total.value
params.billStatus = nodeCode.value == 'all' ? 'all' : nodeCode.value
}
params.idList = purchaseIds
if (exportTotal !== undefined) {
params.total = exportTotal
}
try {
const res = await warehouseOutRecordExport({
showDetail: exportForm.value.delivery,
...params,
...searchForm.value,
})
window.open(filePath + res.message, '_blank')
exportVisible.value = false
} catch (e) {
exportVisible.value = false
}
}
const getWarehouseList = async () => {
try {
const res = await warehouseInfoGetAll()
......@@ -1099,7 +1282,25 @@ const selectbySku = async () => {
editForm.value.warehouseId,
selectSku.value,
)
skuData.value = res.data || []
const arr: InterskuList[] = res.data || []
const ids: Record<string, boolean> = {}
// 过滤掉商品列表已经加了的
for (const item of otherPurchaseData.value) {
if (item.warehouseSku !== undefined) {
ids[item.warehouseSku] = true
}
}
for (let i = 0; i < arr.length; i++) {
const currentItem: InterskuList = arr[i]
if (
currentItem.warehouseSku !== undefined &&
ids[currentItem.warehouseSku]
) {
arr.splice(i, 1)
i--
}
}
skuData.value = arr || []
} catch (e) {
console.error(e)
}
......@@ -1109,12 +1310,13 @@ const skudblclick = (val: InterskuList) => {
const {
locationCode = '',
price = null,
productNumber = '',
productNo = '',
warehouseSku = '',
skuName = '',
image = '',
locationId = null,
usableInventory = null,
id = null,
} = val || {}
otherPurchaseData.value = [
...otherPurchaseData.value,
......@@ -1122,13 +1324,14 @@ const skudblclick = (val: InterskuList) => {
skuImage: image,
warehouseSku,
skuName,
productNo: productNumber,
productNo,
locationCode: locationCode ?? '', // 确保空值处理
locationId: locationId ?? null, // 确保空值处理
costPrice: price,
outCount: null, //出库数量
totalPrice: null,
usableInventory, //可用库存数量
inventoryId: id,
},
]
// 使用filter代替forEach+splice,时间复杂度从O(n^2)降到O(n)
......@@ -1197,13 +1400,27 @@ const addDialog = async (i: number, v: InterWarehousePage | null) => {
formId.value = undefined
}
fetchLocationList('')
selectSku.value = ''
newDialogVisible.value = true
}
const getProduct = async (id: number | undefined) => {
try {
const res = await getWarehouseOutRecordDetailApi(id)
const productList = res.data?.productList
const newProductList = (Array.isArray(productList) ? productList : []).map(
(item: InterProductList) => {
const { inventory, ...rest } = item
return {
...rest,
usableInventory: inventory?.usableInventory ?? null,
}
},
)
if (res.data) {
res.data.productList = newProductList
}
editForm.value = JSON.parse(JSON.stringify(res.data))
otherPurchaseData.value = res.data?.productList || []
otherPurchaseData.value = newProductList || []
} catch (e) {
console.error(e)
}
......@@ -1414,7 +1631,7 @@ const upSection = async () => {
editForm.value as unknown as AnyObject,
'id',
{
productList: 'warehouseSku',
productList: 'id',
},
)
try {
......@@ -1427,9 +1644,36 @@ const upSection = async () => {
console.error(e)
}
}
// const addPurchase = async () => {
// if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
// }
const addPurchaseVisible = ref(false)
const purchaseTextarea = ref(null)
const addPurchase = async () => {
addPurchaseVisible.value = true
}
const submitPurchase = async () => {
if (!purchaseTextarea.value) {
ElMessage.warning('请输入库存 SKU')
return
}
const filteredSkusList = await batchAddCommodity(purchaseTextarea.value)
const mergedProductList = filteredSkusList.map((skuItem) => {
return {
skuImage: skuItem.image,
warehouseSku: skuItem.warehouseSku,
skuName: skuItem.skuName,
productNo: skuItem.productNumber,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.price,
outCount: null,
totalPrice: null,
usableInventory: skuItem.usableInventory,
inventoryId: skuItem.id,
remark: null,
} as InterProductList
})
otherPurchaseData.value = [...otherPurchaseData.value, ...mergedProductList]
addPurchaseVisible.value = false
}
const deleteOtherWarehousing = () => {
const arr = otherWarehouseSelection.value
if (arr.length === 0) return
......@@ -1441,8 +1685,8 @@ const deleteOtherWarehousing = () => {
const importDialogVisible = ref(false)
const importedFileUrl = ref('')
const importData = async () => {
// if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
importDialogVisible.value = true
importedFileUrl.value = ''
}
const handleBatchDelete = async () => {
if (!selections.value.length) {
......@@ -1464,11 +1708,6 @@ const nodeClick = (data: InterWarehouseTree) => {
sessionStorage.setItem('InRecord_NodeCode', data.code ?? '')
search()
}
// const detailPager = ref({
// page: 1,
// rows: 100,
// total: 0,
// })
const searchDetail = async () => {
try {
const res = await getItemListByIdApi(currentRow.value?.id)
......@@ -1489,10 +1728,6 @@ const locationList = ref<ILocation[]>([])
const locationLoading = ref(false)
const fetchLocationList = async (query: string) => {
// if (!query) {
// locationList.value = []
// return
// }
if (!editForm.value.warehouseId) return
locationLoading.value = true
try {
......
......@@ -190,7 +190,7 @@
<ElTableColumn
label="单据状态"
width="130"
prop="billStatus"
prop="billStatusTxt"
header-align="center"
align="center"
></ElTableColumn>
......@@ -446,12 +446,6 @@
/>
</div>
</div>
<!-- <template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false">取消</el-button>
<el-button type="primary" @click="packedData">确认</el-button>
</span>
</template> -->
</ElDialog>
<ElDialog
v-model="newDialogVisible"
......@@ -607,7 +601,7 @@
<div class="product-dialog-footer">
<div>
<el-input
v-model="selectSku"
v-model.trim="selectSku"
placeholder="商品SKU"
style="width: 200px; margin: 0 10px"
clearable
......@@ -693,14 +687,14 @@
</el-button>
</template>
</el-popover>
<!-- <el-button
<el-button
style="margin-left: 6px"
type="success"
size="small"
@click="addPurchase"
>
批量新增
</el-button> -->
</el-button>
<el-button
type="danger"
style="margin-left: 10px"
......@@ -741,7 +735,7 @@
>
<el-form :model="exportForm" label-width="80px">
<el-form-item label="" prop="resource">
<el-radio-group v-model="exportForm.resource">
<el-radio-group v-model="exportForm.resource" @change="isAllExport">
<el-radio :label="0">导出本页</el-radio>
<el-radio :label="1">导出选中</el-radio>
<el-radio :label="2">全部</el-radio>
......@@ -789,7 +783,7 @@
<el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }">
<el-input
v-model="row.number"
v-model.number="row.number"
oninput="value=value.replace(/[^\-?\d.]/g,'')"
placeholder="打印数量"
clearable
......@@ -802,6 +796,33 @@
<el-button type="primary" @click="handlePrintProductTag">打印</el-button>
</template>
</el-dialog>
<ElDialog
v-model="addPurchaseVisible"
title="批量添加"
width="500px"
:close-on-click-modal="false"
>
<div>
<el-input
v-model.trim="purchaseTextarea"
type="textarea"
placeholder="请输入库存 SKU"
:rows="5"
minlength="1"
maxlength="1000"
show-word-limit
/>
<div style="margin-top: 12px; color: #777">
{{ '多个字段使用_##_,_##_隔开' }}
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="addPurchaseVisible = false">取消</el-button>
<el-button type="primary" @click="submitPurchase">确认</el-button>
</span>
</template>
</ElDialog>
</template>
<script setup lang="ts">
......@@ -829,7 +850,7 @@ import {
warehouseInfo,
InRecordBatchCheckPrintApi,
factoryWarehouseInventoryPrint,
warehouseInRecordInventory,
warehouseInRecordExport,
} from '@/api/warehouse'
import { filePath } from '@/api/axios.ts'
import BigNumber from 'bignumber.js'
......@@ -979,6 +1000,11 @@ const logList = ref<LogListData[]>([])
const rules = {
warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
}
const isAllExport = () => {
if (exportForm.value.resource == '2') {
ElMessage.warning('最多支持5000条!')
}
}
const nodeCode = ref<string>(
sessionStorage.getItem('InRecord_NodeCode') || 'all',
)
......@@ -1078,41 +1104,130 @@ async function handlePrintProductTag() {
showPrintDialog.value = false
window.open(filePath + res.message, '_blank')
}
const batchAddCommodity = async (sku: string): Promise<InterskuList[]> => {
if (!editForm.value.warehouseId) {
ElMessage.error('请选择仓库')
return []
}
try {
const res = await getBySkuApi(editForm.value.warehouseId, sku)
const arr: InterskuList[] = res.data || []
const ids: Record<string, boolean> = {}
// 过滤掉商品列表已经加了的
for (const item of otherPurchaseData.value) {
if (item.warehouseSku !== undefined) {
ids[item.warehouseSku] = true
}
}
// 使用 filter 方法过滤掉已经存在的 SKU
const filteredArr = arr.filter((currentItem: InterskuList) => {
return currentItem.sku === undefined || !ids[currentItem.sku]
})
return filteredArr
} catch (e) {
console.error(e)
return []
}
}
interface InterImportData {
warehouseSku: string
remark?: string | null
[key: string]: unknown
}
// 前端导入Excel
const excelFieldMap: Record<string, keyof InterProductList> = {
SKU图片: 'skuImage',
// SKU图片: 'skuImage',
商品SKU: 'warehouseSku',
SKU名称: 'skuName',
// SKU名称: 'skuName',
入库数量: 'buyStored',
'成本价(¥)': 'costPrice',
'总成本(¥)': 'totalPrice',
库位: 'locationCode',
// '成本价(¥)': 'costPrice',
// '总成本(¥)': 'totalPrice',
// 库位: 'locationCode',
备注: 'remark',
}
const handleLocalImport = ({
const handleLocalImport = async ({
path,
data,
}: {
path: string
data: InterProductList[]
data: InterImportData[]
}) => {
const result: InterProductList[] = data.map((item) => {
const obj = {} as InterProductList
Object.keys(excelFieldMap).forEach((excelKey) => {
const field = excelFieldMap[excelKey] as keyof InterProductList
const value = item[excelKey]
// // 类型转换和默认值
// if (['buyStored', 'costPrice', 'totalPrice'].includes(field)) {
// value = value == null || value === '' ? 0 : Number(value)
// } else {
// value = value == null ? '' : value
// }
obj[field] = value as InterProductList[typeof field]
// 1. 将原始导入数据映射到 InterImportData[]
const importedData: InterImportData[] = data
.map((item) => {
const obj: InterImportData = { warehouseSku: '' }
Object.keys(excelFieldMap).forEach((excelKey) => {
const field = excelFieldMap[excelKey]
const value = item[excelKey]
if (field === 'warehouseSku') {
obj[field] = typeof value === 'string' ? value : String(value ?? '')
} else if (field === 'remark') {
obj[field] =
typeof value === 'string'
? value
: value === null || value === undefined
? null
: String(value)
} else if (field === 'buyStored') {
// 确保 value 是一个有效的数字或数字字符串,否则设置为 null
if (
typeof value === 'number' ||
(typeof value === 'string' && !isNaN(Number(value)))
) {
obj[field] = String(value) // 转换为字符串
} else {
obj[field] = null // 无效值设置为 null
}
} else {
obj[field] = value
}
})
return obj
})
return obj
.filter((item) => item.warehouseSku)
if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的商品SKU')
importDialogVisible.value = false
return
}
// 2. 提取导入的 SKU 列表
const importedSkus = importedData.map((item) => item.warehouseSku).join(',')
// 3. 调用 batchAddCommodity 获取商品的完整信息并过滤掉已有的 SKU
const filteredSkusList = await batchAddCommodity(importedSkus) // 使用 await 等待结果
if (filteredSkusList.length === 0) {
ElMessage.warning('导入的商品SKU已存在或无效')
importedFileUrl.value = path
importDialogVisible.value = false
return
}
// 4. 将备注信息合并到获取到的商品列表中
const mergedProductList = filteredSkusList.map((skuItem) => {
// 在导入数据中找到匹配的备注信息
const importedItem = importedData.find(
(item) => item.warehouseSku === skuItem.sku,
)
return {
skuImage: skuItem.image,
warehouseSku: skuItem.sku,
skuName: skuItem.skuName,
productNo: skuItem.productNo,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.factoryPrice,
buyStored: importedItem?.buyStored ?? null,
totalPrice: new BigNumber(
(importedItem?.buyStored ?? 0) as number | string,
)
.multipliedBy(skuItem.factoryPrice ?? 0)
.toNumber(),
usableInventory: skuItem.usableInventory,
remark: importedItem?.remark ?? null,
} as InterProductList // 明确类型
})
otherPurchaseData.value = result
// 5. 更新 otherPurchaseData
otherPurchaseData.value = [...otherPurchaseData.value, ...mergedProductList]
importedFileUrl.value = path
importDialogVisible.value = false
}
......@@ -1150,7 +1265,7 @@ const submitExportForm = async () => {
params.total = exportTotal
}
try {
const res = await warehouseInRecordInventory({
const res = await warehouseInRecordExport({
showDetail: exportForm.value.delivery,
...params,
...searchForm.value,
......@@ -1280,6 +1395,7 @@ const addDialog = async (i: number, v: InterWarehousePage | null) => {
formId.value = undefined
}
fetchLocationList('')
selectSku.value = ''
newDialogVisible.value = true
}
const getProduct = async (id: number | undefined) => {
......@@ -1415,31 +1531,6 @@ const addOtherCurrency = async () => {
return
}
}
// 看新增后要不要打印标签
// try {
// if (!editId.value) {
// await addUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// } else {
// await updateUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// }
// ElMessage({
// message: '保存成功',
// type: 'success',
// offset: window.innerHeight / 2,
// })
// newDialogVisible.value = false
// search()
// } catch (e) {
// return
// }
if (!formId.value) {
addSection()
} else {
......@@ -1507,9 +1598,35 @@ const upSection = async () => {
console.error(e)
}
}
// const addPurchase = async () => {
// if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
// }
const addPurchaseVisible = ref(false)
const purchaseTextarea = ref(null)
const addPurchase = async () => {
addPurchaseVisible.value = true
}
const submitPurchase = async () => {
if (!purchaseTextarea.value) {
ElMessage.warning('请输入库存 SKU')
return
}
const filteredSkusList = await batchAddCommodity(purchaseTextarea.value)
const mergedProductList = filteredSkusList.map((skuItem) => {
return {
skuImage: skuItem.image,
warehouseSku: skuItem.sku,
skuName: skuItem.skuName,
productNo: skuItem.productNo,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.factoryPrice,
buyStored: null,
totalPrice: null,
usableInventory: skuItem.usableInventory,
remark: null,
} as InterProductList
})
otherPurchaseData.value = [...otherPurchaseData.value, ...mergedProductList]
addPurchaseVisible.value = false
}
const deleteOtherWarehousing = () => {
const arr = otherWarehouseSelection.value
if (arr.length === 0) return
......@@ -1521,8 +1638,8 @@ const deleteOtherWarehousing = () => {
const importDialogVisible = ref(false)
const importedFileUrl = ref('')
const importData = async () => {
// if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
importDialogVisible.value = true
importedFileUrl.value = ''
}
const handleBatchDelete = async () => {
if (!selections.value.length) {
......
......@@ -112,18 +112,16 @@ const submitExportForm = async () => {
return ElMessage.error('请选择导出类型')
}
exportLoading.value = true
let purchaseIds = ''
let purchaseIds: number[] = []
let exportTotal: number | undefined = undefined
const params: AnyObject = {}
const resourceType = Number(exportForm.value.resource)
if (resourceType === 0) {
purchaseIds = leftData.value.map((el: WarehouseWarning) => el.id).join(',')
purchaseIds = leftData.value.map((el: WarehouseWarning) => Number(el.id))
} else if (resourceType === 1) {
purchaseIds = selections.value
.map((el: WarehouseWarning) => el.id)
.join(',')
purchaseIds = selections.value.map((el: WarehouseWarning) => Number(el.id))
} else if (resourceType === 2) {
purchaseIds = ''
purchaseIds = []
exportTotal = pagination.value.total
}
params.idList = purchaseIds
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment