Commit 26c1c86e by wuqian

Merge branch 'dev'

parents e3b054f9 72626d4d
......@@ -294,7 +294,7 @@ export function refreshMaterialApi(data: {
productIds?: string
}) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderProductUs/refreshDesignImages ',
'factory/podJomallOrderProductUs/refreshDesignImages',
data,
)
}
......@@ -376,15 +376,6 @@ export function composingDesignImages(data: number[], type: string) {
data,
)
}
// 转至待拣胚
export function updateLogisticsToPickingApi(params: { ids: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/podJomallOrderUs/updateLogisticsToPicking`,
{
params,
},
)
}
// 转至待排单
export function updateLogisticsToArrangeApi(params: { ids: string }) {
return axios.get<never, BaseRespData<never>>(
......@@ -462,7 +453,7 @@ export function getListCraftApi() {
// 批量下载 列表
export function batchDownloadApi(currentPage: number, pageSize: number) {
return axios.post<never, BaseRespData<never>>(
`factory/podUsBatchDownload/list_page`,
`factory/podBatchDownload/us/list_page`,
{
currentPage,
pageSize,
......@@ -473,7 +464,7 @@ export function batchDownloadApi(currentPage: number, pageSize: number) {
// 批量下载 下载
export function batchDownloadDownloadApi(params: { id: number; type: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/download`,
`factory/podBatchDownload/download`,
{
params,
},
......@@ -483,7 +474,7 @@ export function batchDownloadDownloadApi(params: { id: number; type: string }) {
// 批量下载 删除
export function batchDownloadDeleteApi(params: { ids?: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/delete`,
`factory/podBatchDownload/delete`,
{
params,
},
......@@ -493,7 +484,7 @@ export function batchDownloadDeleteApi(params: { ids?: string }) {
// 批量下载 重新排版
export function batchDownloadRecomposingApi(params: { id: number }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/reComposingDesignImages`,
`factory/podBatchDownload/reComposingDesignImages`,
{
params,
},
......
......@@ -67,6 +67,13 @@ const router = createRouter({
component: PodOrderList,
},
{
path: '/pod-cn-order/list',
meta: {
title: 'POD订单(CN)',
},
component: () => import('@/views/order/podCN/index.vue'),
},
{
path: '/pod-us-order/list',
meta: {
title: 'POD订单(US)',
......
......@@ -113,13 +113,19 @@ const menu: MenuItem[] = [
label: 'POD订单',
},
{
index: '/pod-cn-order/list',
id: 6,
label: 'POD订单(CN)',
},
{
index: '/pod-us-order/list',
id: 8,
label: 'POD订单(US)',
},
{
index: '/pod-us-order/orderTracking',
id: 8,
id: 9,
label: 'POD(US)订单跟踪',
},
],
......
import { defineStore } from 'pinia'
import {
OrderData,
PodMakeOrderData,
ProductList,
} from '@/types/api/podMakeOrder'
import { getPodBoxListApi } from '@/api/podCnOrder'
export interface OrderStoreState {
podBoxList?: PodMakeOrderData[]
podBoxIndex?: number | null
socketConnect?: string
}
const useOrderStore = defineStore('order', {
state: () => {
return {
podBoxList: [],
podBoxIndex: null,
socketConnect: '',
} as OrderStoreState
},
actions: {
async setPodBoxList(content: {
boxList: PodMakeOrderData[] | OrderData | null
factoryNo: number | string
warehouseId: number | string
box?: number
data?: OrderData
}) {
const { factoryNo, warehouseId, boxList, box, data } = content
if (Array.isArray(boxList)) {
this.podBoxList = boxList
} else {
const index = this.podBoxList?.findIndex((item) => item.box === box)
if (index === -1) {
try {
const res = await getPodBoxListApi(factoryNo, warehouseId)
const boxList = res.data.map((item) => {
if (res.data) {
const productList = item?.data?.productList || []
const pickingNumber = productList.reduce(
(prev: number, item1: ProductList) => {
if (item1.count) {
return prev + item1.count
}
return prev
},
0,
)
if (item.data) {
item.data.pickingNumber = pickingNumber
}
}
return item
})
this.podBoxList = boxList
this.podBoxIndex = box
} catch (error) {
console.error(error)
}
} else if (box !== 0 && box !== undefined) {
const arr = this.podBoxList
if (arr) {
arr[box - 1] = {
box,
data: data || boxList || null,
}
}
this.podBoxList = arr
this.podBoxIndex = box
}
}
},
// 清空所有箱子
clearPodBoxList() {
this.podBoxList = []
},
// 设置当前箱子
setPodBox(box: number) {
this.podBoxIndex = box
},
// 清空当前箱子
clearPodBox() {
this.podBoxIndex = null
},
setSocketConnect(connect: string) {
this.socketConnect = connect
},
},
})
export default useOrderStore
......@@ -66,7 +66,6 @@ const useOrderStore = defineStore('order', {
data: data || boxList || null,
}
}
console.log('222arr1111', arr)
this.podBoxList = arr
this.podBoxIndex = box
}
......
export interface Tab {
status?: string
statusName?: string
quantity?: number
}
export interface IconfirmSubmit {
ids: string
warehouseId: number | null
warehouseName: string
}
export interface ExportParams extends SearchForm {
idList?: number[]
exportAll: boolean
}
export interface SearchForm {
timeType?: number | null
shopNumber?: string
shipmentType?: string
userMark?: string
processNumber?: string
trackingNumber?: string
baseSku?: string
factoryOrderNumber?: string
sku?: string
factorySubOrderNumber?: string
status?: string
customizedQuantity?: string
multi?: boolean | null
startTime?: string | null
endTime?: string | null
shipmentArea?: number | undefined
platform?: string
productionClient?: string
warehouseId?: string | number
thirdSkuCode?: string
supplierProductNo?: string
batchArrangeNumber?: string
craftCode?: string
thirdStockSku?: string
exceptionHandling?: number | undefined
interceptStatus?: number | string
}
export interface PodCnOrderListData {
id: number
thirdOrderNumber?: string
factoryOrderNumber?: string
shopNumber?: string
factoryOnlineId?: number | null
factoryNo?: number | null
factoryCode?: string | null
status?: string
weight?: number | null
totalProductAmount?: number | null
productAmount?: number
carriageAmount?: number | null
totalAmount?: number | null
productNum?: number | null
trackStatus?: string | null
receiverName?: string
receiverPhone?: string
receiverCountry?: string
receiverProvince?: string
receiverCity?: string
receiverDistrict?: string
receiverAddress1?: string
receiverAddress2?: string
receiverPostCode?: string
paymentType?: string
paymentTime?: string
startStockingTime?: string
finishTime?: string
shipmentType?: number
expressSheet?: string
trackingNumber?: string
processNumber?: string
createTime?: string
updateTime?: string
remark?: string | null
userMark?: string
serviceAmount?: number | null
prepaidAmount?: number | null
actualAmount?: number | null
version?: number
productList?: ProductList[]
orderNumber?: string
logisticsWayId?: number | null
logisticsWayName?: string
url?: string | null
tiffUrl?: string | null
}
export interface ProductList {
id: number
podJomallOrderCnId: number
thirdSubOrderNumber?: string
thirdStockSku?: string
factorySubOrderNumber?: string
factoryCode?: string
productName?: string
baseSku?: string
variantSku?: string
productPrice?: number
templatePrice?: number
variantImage?: string
craftPrice?: number
craftCode?: string
previewImgs?: []
platform?: string
imageAry?: string
designImages?: string
categoryId?: number
categoryName?: string
num?: number
passNum?: number
notPassNum?: number
payAmount?: number
status?: number
weight?: number | null
diyId?: string
endProductId?: string
customizedQuantity?: number
tagIds?: string
isProduction?: boolean
createTime?: string
updateTime?: string
remark?: string | null
version?: number
subOrderNumber?: string
craftName?: string | null
lanshouAddress?: string | null
shopNumber?: string | null
factoryOrderNumber?: string | null
replenishmentNum?: number | null
isReplenishment?: boolean
thirdSkuCode?: string | null
supplierProductNo?: string | null
userMark?: string | null
replenishmentSumNum?: number | null
interceptStatus?: number | null
batchArrangeNumber?: string | null
}
export interface cardImages {
title: string
url: string
sort: number
id?: number
}
export interface LogListData {
id: number
bizId: number
userId: number
employeeName: string
description: string
deleteContent: string
createTime: string
}
export interface ProductionClient {
code?: string
remark?: string
}
export interface PodOrderRes extends ProductList {
expectDeliveryTime?: string | null
thirdOrderNumber?: string | null
startStockingTime?: string | null
factoryOrderNumber?: string | null
userMark?: string | null
craftName?: string | null
craftId?: string | null
shopNumber?: string | null
color?: string | null
size?: string | null
note?: Array<{ prop: string | number; value: string | number }>
imgList: cardImages[]
}
export interface WarehouseListData {
code?: string
defaulted?: number
factoryCode?: string
factoryId?: number
id: number
name?: string
remarks?: string
sort?: number
}
export interface LogisticsData {
logisticsWayName: string // 物流名称
warehouseName: string // 发货仓库
status: boolean
logisticsWayCode: string // 物流编码
partition: string // 所在分区
logisticsWayId?: number | null
}
export interface AddressInfo {
id?: string
receiverName: string
receiverPhone: string
receiverCountry: string
receiverProvince: string
receiverCity: string
receiverDistrict: string
receiverAddress1: string
receiverAddress2: string
receiverPostCode: string
}
export interface LogisticsFormData {
processNumber: string
trackingNumber: string
expressSheetUrl: string
expressSheet: File | null
}
export interface CraftListData {
craftName: string
craftCode: string
}
......@@ -45,6 +45,7 @@ export interface ProductList {
power?: boolean
variantImage?: string
podJomallUsNo?: string
podJomallCnNo?: string
previewImgs?: { sort: string | number; title: string; url: string }[]
}
......
import { getWsUrl } from '../api/axios'
import useOrderStore from '../store/cnOrder'
interface NotificationOptions {
body: string
icon: string
data: string
requireInteraction: boolean
}
export interface WebSocketMessage {
code?: string
content?: string
type?: string
data?: unknown
[key: string]: string | unknown | undefined
}
interface InitOptions {
account: string
factoryNo: string
}
type MessageCallback = (
data: WebSocketMessage,
sendSystemMessage: (msg: string) => void,
) => void
type OpenCallback = () => void
function sendSystemMessage(msg: string): void {
if (window.Notification && Notification.permission === 'granted') {
const notificationOptions: NotificationOptions = {
body: msg,
icon: './favicon.ico',
data: 'I like peas.',
requireInteraction: true,
}
const n = new Notification('消息通知', notificationOptions)
n.onclick = (event: Event) => {
event.preventDefault()
window.open('/home', '_blank')
}
setTimeout(() => {
n.close()
}, 10000)
}
}
const showReconnectingMsg = (): void => {
ElMessageBox.alert('消息服务已断开,正在重新连接,请稍候', {
showClose: true,
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
}
class Im {
private socket: WebSocket | null = null
private _wsUrl: string = ''
// private userId: string = ''
private _onMessageCallback?: MessageCallback
private _onOpenCallback?: OpenCallback
private _heartbeatTimer: number | null = null
private _heartbeatTimeoutTimer: number | null = null
private _reconnectingTimer: number | null = null
private num: number = 0
constructor() {
this._onWsOpen = this._onWsOpen.bind(this)
this._onWsMessage = this._onWsMessage.bind(this)
this._onWsClose = this._onWsClose.bind(this)
this._onWsError = this._onWsError.bind(this)
}
private _onWsOpen(): void {
console.log('服务器连接成功')
localStorage.setItem('socket_connect', 'online')
this._onOpenCallback?.()
this._startHeartbeat()
}
private _onWsMessage(event: MessageEvent): void {
let data: WebSocketMessage = {}
if (typeof event.data === 'string') {
try {
data = JSON.parse(event.data)
} catch (error) {
data = {}
}
}
this._onHeartbeatMessage()
this._onMessageCallback?.(data, sendSystemMessage)
}
private _onWsClose(): void {
console.log('服务器关闭')
this._destroyWebSocket(true)
}
private _onWsError(): void {
console.log('连接出错')
this._destroyWebSocket(true)
}
private _sendHeartbeat(): void {
if (!this.socket) return
this.send({ code: 'HEALTH' })
if (this._heartbeatTimeoutTimer) {
window.clearTimeout(this._heartbeatTimeoutTimer)
}
this._heartbeatTimeoutTimer = window.setTimeout(() => {
this._destroyWebSocket(true)
}, 5 * 1000)
}
private _onHeartbeatMessage(): void {
console.log('心跳')
useOrderStore().setSocketConnect('online')
if (this._heartbeatTimeoutTimer) {
window.clearTimeout(this._heartbeatTimeoutTimer)
}
}
private _startHeartbeat(): void {
this._stopHeartbeat()
this._sendHeartbeat()
this._heartbeatTimer = window.setInterval(
() => this._sendHeartbeat(),
10 * 1000,
)
}
private _stopHeartbeat(): void {
if (this._heartbeatTimer) {
window.clearInterval(this._heartbeatTimer)
}
if (this._heartbeatTimeoutTimer) {
window.clearTimeout(this._heartbeatTimeoutTimer)
}
}
private _scheduleReconnect(): void {
if (!this.num) this.num = 0
this.num++
if (this.num > 5) {
ElMessageBox.alert('尝试重连消息服务失败,请刷新重试')
return
}
showReconnectingMsg()
this._reconnectingTimer = window.setTimeout(() => {
this._createWebSocket()
}, 2000)
}
private _destroyWebSocket(reconnect?: boolean): void {
if (!this.socket) return
this._stopHeartbeat()
if (this._reconnectingTimer) {
window.clearTimeout(this._reconnectingTimer)
}
this.socket.removeEventListener('open', this._onWsOpen)
this.socket.removeEventListener('message', this._onWsMessage)
this.socket.removeEventListener('close', this._onWsClose)
this.socket.removeEventListener('error', this._onWsError)
this.socket.close(1000)
this.socket = null
localStorage.removeItem('socket_connect')
useOrderStore().setSocketConnect('offline')
if (reconnect) this._scheduleReconnect()
}
private _createWebSocket(): void {
if (!this._wsUrl) return
const socket = new WebSocket(this._wsUrl)
socket.addEventListener('open', this._onWsOpen)
socket.addEventListener('message', this._onWsMessage)
socket.addEventListener('close', this._onWsClose)
socket.addEventListener('error', this._onWsError)
this.socket = socket
}
init(
options: InitOptions,
msgfunc?: MessageCallback,
openfunc?: OpenCallback,
): Promise<void> {
return new Promise((resolve, reject) => {
const { account, factoryNo } = options
const socket_connect = localStorage.getItem('socket_connect')
if (socket_connect === 'online') {
resolve()
return
}
if (!window.WebSocket) {
reject(new Error('WebSocket is not supported'))
return
}
this._onMessageCallback = msgfunc
this._onOpenCallback = () => {
openfunc?.()
resolve()
}
this._destroyWebSocket()
this._wsUrl = `${getWsUrl()}/ws/websocket/${factoryNo}/${account}`
this._createWebSocket()
})
}
send(options: WebSocketMessage): void {
this.socket?.send(JSON.stringify(options))
}
close(): void {
this._destroyWebSocket()
}
}
export default new Im()
<template>
<el-dialog
title="处理结果"
v-model="resultDialog"
width="60%"
:close-on-click-modal="false"
@closed="closedFn"
>
<div style="display: flex">
<el-checkbox
:indeterminate="isIndeterminate"
v-model="checkAll"
@change="checkAllChange"
>
{{ '全选' }}
</el-checkbox>
<el-button
type="success"
style="margin-left: 20px"
@click="resultfilter(true)"
>
{{ '选择正常' }}
</el-button>
<el-button type="danger" @click="resultfilter(false)">
{{ '选择异常' }}
</el-button>
<el-button type="success" @click="copyAllCode('factoryOrderNumber')">
{{ '复制工厂订单号' }}
</el-button>
</div>
<div style="height: 50vh; overflow: auto">
<div style="margin: 15px 0"></div>
<el-checkbox-group v-model="selectedList" @change="checkChange">
<div style="display: block" v-for="(item, index) in list" :key="index">
<el-checkbox :value="item">
{{ '工厂订单号:' + item.factoryOrderNumber + ' ' + item.message }}
</el-checkbox>
</div>
</el-checkbox-group>
</div>
<template #footer>
<div style="display: flex; justify-content: flex-end">
<!-- <el-button @click="resultDialog = false"> 取 消 </el-button>
<div style="width: 50px; display: inline-block"></div> -->
<el-button type="primary" @click="confirm"> 确 定 </el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { copyText } from '@/utils/index'
interface IList {
id: string | number
shopNumber?: string
factoryOrderNumber?: string
message: string
status: boolean
}
const props = withDefaults(
defineProps<{
list: IList[]
}>(),
{
list: () => [],
},
)
// 响应式数据
const resultDialog = ref(false)
const isIndeterminate = ref(false)
const checkAll = ref(false)
const selectedList = ref<IList[]>([])
let key = ''
// 显示弹窗
const showDialog = (type?: string) => {
key = type || ''
resultDialog.value = true
selectedList.value = []
checkAll.value = false
}
// 全选状态改变
const checkAllChange = (value: boolean) => {
selectedList.value = value ? props.list : []
isIndeterminate.value = false
}
// 单个选择改变
const checkChange = () => {
const checkedCount = selectedList.value.length
checkAll.value = checkedCount === props.list.length
isIndeterminate.value = checkedCount > 0 && checkedCount < props.list.length
}
// 确认选择
const confirm = () => {
resultDialog.value = false
// emits('confirm', selectedList.value)
}
// 结果过滤
const resultfilter = (bool: boolean) => {
const arr = props.list.filter((item) => item.status === bool)
selectedList.value = arr
const checkedCount = arr.length
console.log(112, checkedCount)
console.log(113, props.list)
checkAll.value = checkedCount === props.list.length
isIndeterminate.value = checkedCount > 0 && checkedCount < props.list.length
}
// 复制店铺单号
const copyAllCode = (field: string) => {
if (!selectedList.value.length) {
return ElMessage.warning('请先选择数据')
}
const str = selectedList.value.map((el) => el[field as keyof IList]).join(',')
console.log('复制店铺单号', str)
copyText(str)
}
function closedFn() {
if (key === 'stockOut') return
emits('confirm', selectedList.value)
}
// 监听弹窗状态
watch(
() => resultDialog.value,
(v) => {
console.log(v)
},
)
watch(
() => props.list,
(v) => {
if (v.length) {
console.log(127, v)
resultfilter(true)
}
},
)
defineExpose({
showDialog,
})
const emits = defineEmits<{
(e: 'confirm', data: IList[]): void
}>()
</script>
<style lang="scss" scoped></style>
<script setup lang="ts">
import { defineModel } from 'vue'
import { updateAddressApi } from '@/api/podCnOrder.ts'
import {AddressInfo} from '@/types/api/podCnOrder.ts'
const emits = defineEmits(['success'])
defineProps<{
countryList: { countryCode: string }[]
}>()
const visible = defineModel<boolean>('visible')
const form = defineModel<AddressInfo>('form', {
default: {
receiverName: '',
receiverPhone: '',
receiverCountry: '',
receiverProvince: '',
receiverCity: '',
receiverDistrict: '',
receiverAddress1: '',
receiverAddress2: '',
receiverPostCode: '',
},
})
const formRef = ref()
const rules = {
receiverName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
receiverPhone: [{ required: true, message: '请输入电话', trigger: 'blur' }],
receiverCountry: [{ required: true, message: '请输入国家', trigger: 'blur' }],
receiverProvince: [
{ required: true, message: '请输入省/州', trigger: 'blur' },
],
receiverCity: [{ required: true, message: '请输入市', trigger: 'blur' }],
receiverAddress1: [
{ required: true, message: '请输入地址1', trigger: 'blur' },
],
receiverPostCode: [
{ required: true, message: '请输入邮政编码', trigger: 'blur' },
],
}
const submitForm = async () => {
formRef?.value.validate(async (valid: boolean) => {
if (valid) {
await updateAddressApi(form.value as never)
visible.value = false
emits('success')
await ElMessageBox.alert(
'请修改/刷新地址后取消物流或者更换物流在重新创建物流订单、获取跟踪号、获取打印面单',
'提示',
{
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消',
showCancelButton: true,
},
)
}
})
}
</script>
<template>
<el-dialog
v-model="visible"
:close-on-click-modal="false"
title="修改揽收信息"
width="50%"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="姓名" prop="receiverName">
<el-input
v-model="form.receiverName"
clearable
placeholder="请输入姓名"
/>
</el-form-item>
<el-form-item label="电话" prop="receiverPhone">
<el-input
v-model="form.receiverPhone"
clearable
placeholder="请输入电话"
/>
</el-form-item>
<el-form-item label="国家" prop="receiverCountry">
<el-select v-model="form.receiverCountry" clearable filterable>
<el-option
v-for="it in countryList"
:key="it.countryCode"
:label="it.countryCode"
:value="it.countryCode"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="省/州" prop="receiverProvince">
<el-input
v-model="form.receiverProvince"
clearable
placeholder="请输入省/州"
/>
</el-form-item>
<el-form-item label="市" prop="receiverCity">
<el-input
v-model="form.receiverCity"
clearable
placeholder="请输入市"
/>
</el-form-item>
<el-form-item label="区/县" prop="receiverDistrict">
<el-input
v-model="form.receiverDistrict"
clearable
placeholder="请输入区/县"
/>
</el-form-item>
<el-form-item label="地址1" prop="receiverAddress1">
<el-input
v-model="form.receiverAddress1"
clearable
placeholder="请输入地址1"
/>
</el-form-item>
<el-form-item label="地址2" prop="receiverAddress2">
<el-input
v-model="form.receiverAddress2"
clearable
placeholder="请输入地址2"
/>
</el-form-item>
<el-form-item label="邮政编码" prop="receiverPostCode">
<el-input
v-model="form.receiverPostCode"
clearable
placeholder="请输入邮政编码"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="submitForm">提交</el-button>
</template>
</el-dialog>
</template>
<style scoped lang="scss"></style>
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -370,6 +370,9 @@ watch(visible, async (value: boolean) => {
? JSON.parse(locaclWarehouseId)
: props.warehouseList[0].id
_warehouseId.value = locaclWarehouseId
? JSON.parse(locaclWarehouseId)
: props.warehouseList[0].id
if (userStore.user?.factory.id) {
try {
await socket.init(
......
......@@ -547,7 +547,6 @@
<ElButton type="warning" @click="arrangeFinish">排单完成</ElButton>
</span>
</ElFormItem>
<ElFormItem
v-if="status !== 'BATCH_DOWNLOAD' && status !== 'WAIT_SHIPMENT'"
>
......@@ -2137,6 +2136,7 @@
v-model="podOrderVisible"
:print-order="printOrder"
:warehouse-list="warehouseList"
:is-cn="false"
@set-printer="handlePrinterChange"
@set-warehouse-id="handleWarehouseIdChange"
@refresh="onFastRefresh"
......
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