Commit f047343b by wuqian
parents c3d44811 19a60471
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
"rules": { "rules": {
"vue/require-default-prop": "off", "vue/require-default-prop": "off",
"vue/multi-word-component-names": "off", "vue/multi-word-component-names": "off",
"no-console": "off","no-unused-vars": "off", "no-console": "off",
"@typescript-eslint/no-explicit-any": "error"
}, },
"overrides": [{ "files": "*.vue", "rules": { "no-undef": "off" } }] "overrides": [{ "files": "*.vue", "rules": { "no-undef": "off" } }]
} }
...@@ -32,7 +32,6 @@ declare module 'vue' { ...@@ -32,7 +32,6 @@ declare module 'vue' {
ElImage: typeof import('element-plus/es')['ElImage'] ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
...@@ -65,6 +64,7 @@ declare module 'vue' { ...@@ -65,6 +64,7 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
Select: typeof import('./src/components/Form/Select.vue')['default'] Select: typeof import('./src/components/Form/Select.vue')['default']
ShipmentOrderDetail: typeof import('./src/components/ShipmentOrderDetail.vue')['default'] ShipmentOrderDetail: typeof import('./src/components/ShipmentOrderDetail.vue')['default']
SideBar: typeof import('./src/components/SideBar.vue')['default']
SplitDiv: typeof import('./src/components/splitDiv/splitDiv.vue')['default'] SplitDiv: typeof import('./src/components/splitDiv/splitDiv.vue')['default']
'Switch ': typeof import('./src/components/Form/Switch .vue')['default'] 'Switch ': typeof import('./src/components/Form/Switch .vue')['default']
TableView: typeof import('./src/components/TableView.vue')['default'] TableView: typeof import('./src/components/TableView.vue')['default']
......
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"element-plus": "^2.6.0", "element-plus": "^2.6.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.7.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"qrcode": "^1.5.4",
"splitpanes": "^3.1.5", "splitpanes": "^3.1.5",
"vue": "^3.4.19", "vue": "^3.4.19",
"vue-dompurify-html": "^5.1.0", "vue-dompurify-html": "^5.1.0",
...@@ -26,6 +28,8 @@ ...@@ -26,6 +28,8 @@
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@types/luxon": "^3.7.1",
"@types/qrcode": "^1.5.5",
"@types/splitpanes": "^2.2.6", "@types/splitpanes": "^2.2.6",
"@typescript-eslint/eslint-plugin": "^7.1.1", "@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1", "@typescript-eslint/parser": "^7.1.1",
...@@ -1989,6 +1993,33 @@ ...@@ -1989,6 +1993,33 @@
"@types/lodash": "*" "@types/lodash": "*"
} }
}, },
"node_modules/@types/luxon": {
"version": "3.7.1",
"resolved": "https://registry.npmmirror.com/@types/luxon/-/luxon-3.7.1.tgz",
"integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.2.0",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-24.2.0.tgz",
"integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.10.0"
}
},
"node_modules/@types/qrcode": {
"version": "1.5.5",
"resolved": "https://registry.npmmirror.com/@types/qrcode/-/qrcode-1.5.5.tgz",
"integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.7.0", "version": "7.7.0",
"resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.7.0.tgz", "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.7.0.tgz",
...@@ -3059,7 +3090,6 @@ ...@@ -3059,7 +3090,6 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
...@@ -3069,7 +3099,6 @@ ...@@ -3069,7 +3099,6 @@
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"color-convert": "^2.0.1" "color-convert": "^2.0.1"
...@@ -3255,6 +3284,15 @@ ...@@ -3255,6 +3284,15 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001718", "version": "1.0.30001718",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz",
...@@ -3322,6 +3360,17 @@ ...@@ -3322,6 +3360,17 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/codepage": { "node_modules/codepage": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz", "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
...@@ -3335,7 +3384,6 @@ ...@@ -3335,7 +3384,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"color-name": "~1.1.4" "color-name": "~1.1.4"
...@@ -3348,7 +3396,6 @@ ...@@ -3348,7 +3396,6 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/combined-stream": { "node_modules/combined-stream": {
...@@ -3479,6 +3526,15 @@ ...@@ -3479,6 +3526,15 @@
} }
} }
}, },
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/deep-is": { "node_modules/deep-is": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz",
...@@ -3509,6 +3565,12 @@ ...@@ -3509,6 +3565,12 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
"license": "MIT"
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz",
...@@ -3606,6 +3668,12 @@ ...@@ -3606,6 +3668,12 @@
"vue": "^3.2.0" "vue": "^3.2.0"
} }
}, },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/entities": { "node_modules/entities": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
...@@ -4272,6 +4340,15 @@ ...@@ -4272,6 +4340,15 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
...@@ -4607,6 +4684,15 @@ ...@@ -4607,6 +4684,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-glob": { "node_modules/is-glob": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
...@@ -4882,6 +4968,15 @@ ...@@ -4882,6 +4968,15 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/luxon": {
"version": "3.7.1",
"resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.7.1.tgz",
"integrity": "sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==",
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.17", "version": "0.30.17",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz", "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz",
...@@ -5142,6 +5237,15 @@ ...@@ -5142,6 +5237,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/package-manager-detector": { "node_modules/package-manager-detector": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-1.3.0.tgz", "resolved": "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-1.3.0.tgz",
...@@ -5172,7 +5276,6 @@ ...@@ -5172,7 +5276,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
...@@ -5275,6 +5378,15 @@ ...@@ -5275,6 +5378,15 @@
"pathe": "^2.0.1" "pathe": "^2.0.1"
} }
}, },
"node_modules/pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.3", "version": "8.5.3",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz", "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz",
...@@ -5379,6 +5491,23 @@ ...@@ -5379,6 +5491,23 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"bin": {
"qrcode": "bin/qrcode"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/quansync": { "node_modules/quansync": {
"version": "0.2.10", "version": "0.2.10",
"resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz", "resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz",
...@@ -5431,6 +5560,21 @@ ...@@ -5431,6 +5560,21 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"license": "ISC"
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.10", "version": "1.22.10",
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz",
...@@ -5604,6 +5748,12 @@ ...@@ -5604,6 +5748,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
...@@ -5728,11 +5878,24 @@ ...@@ -5728,11 +5878,24 @@
"node": ">=0.6.19" "node": ">=0.6.19"
} }
}, },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": { "node_modules/strip-ansi": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ansi-regex": "^5.0.1" "ansi-regex": "^5.0.1"
...@@ -5908,6 +6071,13 @@ ...@@ -5908,6 +6071,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici-types": {
"version": "7.10.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.10.0.tgz",
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
"dev": true,
"license": "MIT"
},
"node_modules/unimport": { "node_modules/unimport": {
"version": "3.14.6", "version": "3.14.6",
"resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.14.6.tgz", "resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.14.6.tgz",
...@@ -6468,6 +6638,12 @@ ...@@ -6468,6 +6638,12 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"license": "ISC"
},
"node_modules/wildcard": { "node_modules/wildcard": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz", "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
...@@ -6502,6 +6678,20 @@ ...@@ -6502,6 +6678,20 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
...@@ -6546,6 +6736,12 @@ ...@@ -6546,6 +6736,12 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"license": "ISC"
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
...@@ -6553,6 +6749,93 @@ ...@@ -6553,6 +6749,93 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/yargs/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yargs/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yargs/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/yargs/node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"element-plus": "^2.6.0", "element-plus": "^2.6.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.7.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"qrcode": "^1.5.4",
"splitpanes": "^3.1.5", "splitpanes": "^3.1.5",
"vue": "^3.4.19", "vue": "^3.4.19",
"vue-dompurify-html": "^5.1.0", "vue-dompurify-html": "^5.1.0",
...@@ -28,6 +30,8 @@ ...@@ -28,6 +30,8 @@
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@types/luxon": "^3.7.1",
"@types/qrcode": "^1.5.5",
"@types/splitpanes": "^2.2.6", "@types/splitpanes": "^2.2.6",
"@typescript-eslint/eslint-plugin": "^7.1.1", "@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1", "@typescript-eslint/parser": "^7.1.1",
......
...@@ -60,6 +60,12 @@ export function getFilePath() { ...@@ -60,6 +60,12 @@ export function getFilePath() {
import.meta.env.VITE_API_BASE_URL + import.meta.env.VITE_API_BASE_UPLOAD_URL import.meta.env.VITE_API_BASE_URL + import.meta.env.VITE_API_BASE_UPLOAD_URL
) )
} }
export function getFileCnPath() {
if (!/(http|https):\/\/([^/]+)/i.test(import.meta.env.BASE_URL)) {
return location.origin
}
return import.meta.env.VITE_API_BASE_URL
}
export function getWsUrl() { export function getWsUrl() {
if (location.protocol === 'https:') { if (location.protocol === 'https:') {
return 'wss://' + location.host return 'wss://' + location.host
...@@ -68,5 +74,6 @@ export function getWsUrl() { ...@@ -68,5 +74,6 @@ export function getWsUrl() {
} }
} }
export const filePath = getFilePath() export const filePath = getFilePath()
export const FileCnPath = getFileCnPath()
export default axios export default axios
import { BaseRespData } from '@/types/api' import { BaseRespData } from '@/types/api'
import axios from './axios' import axios from './axios'
import { LogisticsData } from '@/types/api/order' import { LogisticsData } from '@/types/api/order'
import { LogisticBill } from '@/types/api/podMakeOrder'
import { userData } from '@/types/api/user' import { userData } from '@/types/api/user'
import { VersionImageList } from '@/types/api/typesetting' import { VersionImageList } from '@/types/api/typesetting'
...@@ -12,9 +14,7 @@ export function getLogisticsCompanyList() { ...@@ -12,9 +14,7 @@ export function getLogisticsCompanyList() {
} }
// 获取客户 // 获取客户
export function getUserMarkList() { export function getUserMarkList() {
return axios.get<never, BaseRespData<string[]>>( return axios.get<never, BaseRespData<string[]>>('dbDiyUser/getUserMarkList')
'dbDiyUser/getUserMarkList',
)
} }
// 获取用户 // 获取用户
...@@ -35,3 +35,17 @@ export function uploadFileApi(data: FormData) { ...@@ -35,3 +35,17 @@ export function uploadFileApi(data: FormData) {
data, data,
) )
} }
// 打印物流面单 US
export function getLogisticUSApi(content: string) {
return axios.get<never, BaseRespData<LogisticBill>>(
`factory/podJomallOrderUs/getOrderByFactorySubOrderNumber?factorySubOrderNumber=${content}`,
)
}
// 打印物流面单 CN
export function getLogisticCNApi(content: string) {
return axios.get<never, BaseRespData<LogisticBill>>(
`factory/podJomallOrder/getOrderByThirdSubOrderNumber?thirdSubOrderNumber=${content}`,
)
}
...@@ -2,11 +2,11 @@ import { BasePaginationData, BaseRespData } from '@/types/api' ...@@ -2,11 +2,11 @@ import { BasePaginationData, BaseRespData } from '@/types/api'
import axios from './axios' import axios from './axios'
import { ExternalAuthListData } from '@/types/api/externalAuth' import { ExternalAuthListData } from '@/types/api/externalAuth'
export function getExternalAuthorisationListApi( export function getExternalAuthorisationListApi(
data: { data?: {
type: string type?: string
}, },
page: number, page?: number,
pageSize: number, pageSize?: number,
) { ) {
return axios.post<never, BasePaginationData<ExternalAuthListData>>( return axios.post<never, BasePaginationData<ExternalAuthListData>>(
'factory/baseExternalAccount/list_page', 'factory/baseExternalAccount/list_page',
...@@ -36,6 +36,12 @@ export function deleteExternalAuthorisationApi(ids: string) { ...@@ -36,6 +36,12 @@ export function deleteExternalAuthorisationApi(ids: string) {
`factory/baseExternalAccount/delete?ids=${ids}`, `factory/baseExternalAccount/delete?ids=${ids}`,
) )
} }
export function baseExternalAccountLogsApi(params: { ids: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/baseExternalAccount/logs`,
{ params },
)
}
export function addExternalAuthorisationApi( export function addExternalAuthorisationApi(
url: string, url: string,
data: ExternalAuthListData, data: ExternalAuthListData,
......
...@@ -144,6 +144,12 @@ export function getUniuniList() { ...@@ -144,6 +144,12 @@ export function getUniuniList() {
}, },
) )
} }
// 获取tictok物流承运商
export function getTiktokCarrier() {
return axios.get<never, BaseRespData<{ name: string; id: number }[]>>(
'logisticsWay/getTiktokShippingProvider',
)
}
/** /**
* @description 发货地址 * @description 发货地址
......
...@@ -196,9 +196,9 @@ export function getPodJomallOrderByFactoryNumber(factoryOrderNumber: string) { ...@@ -196,9 +196,9 @@ export function getPodJomallOrderByFactoryNumber(factoryOrderNumber: string) {
return axios.get<never, BaseRespData<OrderData>>( return axios.get<never, BaseRespData<OrderData>>(
'factory/podJomallOrder/getPodJomallOrderByFactoryNumber', 'factory/podJomallOrder/getPodJomallOrderByFactoryNumber',
{ {
params:{ params: {
factoryOrderNumber factoryOrderNumber,
} },
}, },
) )
} }
...@@ -247,3 +247,9 @@ export function completeDeliveryApi( ...@@ -247,3 +247,9 @@ export function completeDeliveryApi(
{ productIdList, ...data }, { productIdList, ...data },
) )
} }
export function exportStatementApi(data: SearchForm, status: string) {
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrder/exportPodJomallReconciliation',
{ ...data, status },
)
}
...@@ -8,10 +8,17 @@ import { ...@@ -8,10 +8,17 @@ import {
ProductionClient, ProductionClient,
WarehouseListData, WarehouseListData,
LogisticsData, LogisticsData,
ExportParams,
InterceptStateGroupData,
} from '@/types/api/podUsOrder' } from '@/types/api/podUsOrder'
import axios from './axios' import axios from './axios'
import { PodMakeOrderData } from '@/types/api/podMakeOrder' import { PodMakeOrderData } from '@/types/api/podMakeOrder'
export function exportPodUSInfo(data: ExportParams) {
return axios.post<never, BasePaginationData<never>>(
'factory/podJomallOrderUs/exportPodUsOrder',
data,
)
}
// 同步收货地址 // 同步收货地址
export function syncReceiverAddress(data: number[]) { export function syncReceiverAddress(data: number[]) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
...@@ -37,12 +44,19 @@ export function getOrderTabData() { ...@@ -37,12 +44,19 @@ export function getOrderTabData() {
'/factory/podJomallOrderUs/findStateGroupList', '/factory/podJomallOrderUs/findStateGroupList',
) )
} }
// 拦截状态数量
export function getgetInterceptStateGroupList() {
return axios.get<never, BaseRespData<InterceptStateGroupData>>(
'factory/podJomallOrderUs/findInterceptStateGroupList',
)
}
export function getOrderList( export function getOrderList(
params: SearchForm, params: SearchForm,
currentPage: number, currentPage: number,
pageSize: number, pageSize: number,
) { ) {
return axios.post<never, BasePaginationData<PodUsOrderListData[]>>( return axios.post<never, BasePaginationData<PodUsOrderListData>>(
'/factory/podJomallOrderUs/list_page', '/factory/podJomallOrderUs/list_page',
{ {
...params, ...params,
...@@ -332,7 +346,7 @@ export function createLogisticsOrderApi(params: { ...@@ -332,7 +346,7 @@ export function createLogisticsOrderApi(params: {
) )
} }
// 创建物流 // 物流面单上传
export function uploadExpressSheet(params: { export function uploadExpressSheet(params: {
trackingNumber: string trackingNumber: string
file: File file: File
...@@ -341,7 +355,8 @@ export function uploadExpressSheet(params: { ...@@ -341,7 +355,8 @@ export function uploadExpressSheet(params: {
'factory/podJomallOrderUs/uploadExpressSheet', 'factory/podJomallOrderUs/uploadExpressSheet',
params, params,
) )
} // 创建物流 }
// 更新物流信息确认
export function updateSelfLogistics(params: { export function updateSelfLogistics(params: {
trackingNumber: string trackingNumber: string
expressSheet: string expressSheet: string
...@@ -355,7 +370,7 @@ export function updateSelfLogistics(params: { ...@@ -355,7 +370,7 @@ export function updateSelfLogistics(params: {
} }
// 更改物流 // 更改物流
export function composingDesignImages(data: number[],type:string) { export function composingDesignImages(data: number[], type: string) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/composingDesignImages?type=${type}`, `factory/podJomallOrderUs/composingDesignImages?type=${type}`,
data, data,
...@@ -443,3 +458,119 @@ export function getListCraftApi() { ...@@ -443,3 +458,119 @@ export function getListCraftApi() {
`factory/podJomallOrderProductUs/listCraft`, `factory/podJomallOrderProductUs/listCraft`,
) )
} }
// 批量下载 列表
export function batchDownloadApi(currentPage: number, pageSize: number) {
return axios.post<never, BaseRespData<never>>(
`factory/podUsBatchDownload/list_page`,
{
currentPage,
pageSize,
},
)
}
// 批量下载 下载
export function batchDownloadDownloadApi(params: { id: number; type: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/download`,
{
params,
},
)
}
// 批量下载 删除
export function batchDownloadDeleteApi(params: { ids?: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/delete`,
{
params,
},
)
}
// 批量下载 重新排版
export function batchDownloadRecomposingApi(params: { id: number }) {
return axios.get<never, BaseRespData<never>>(
`factory/podUsBatchDownload/reComposingDesignImages`,
{
params,
},
)
}
// 生产完成
export function updateToWaitShipmentApi(params: {
usUpdateParams: Array<{
id: number | string
podJomallOrderUsId: number | string
factorySubOrderNumber: number | string
version: number | string
}>
}) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/updateToWaitShipment`,
params,
)
}
// 拦截状态改变
export function interceptUpdateApi(params: {
orderIds: (string | number)[]
interceptStatus: number
}) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/updateInterceptStatus`,
params,
)
}
// 驳回
export function rejectToApi(params: {
orderStatus: string
productList: ProductList[]
reasonStr: string
}) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/rejectTo`,
params,
)
}
// 状态推送
export function statusPushApi(params: (string | number)[]) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/statusPush`,
params,
)
}
// 完成发货
export function completeDeliveryApi(params: {
orderIdList: (string | number)[]
}) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/completeDelivery`,
params,
)
}
// 物流轨迹
export function get17TrackInfoApi(params: { id: string | number }) {
return axios.get(`factory/podJomallOrderUs/get17TrackInfo`, { params })
}
// 获取riin 权限
export function getAccountCodeByFactoryIdApi(params: { token: string }) {
return axios.get(`factory/baseExternalAccount/getAccountCodeByFactoryId`, {
params,
})
}
// 打印拣货单item
export function printPickPdfByBatchNumberApi(params: {
batchArrangeNumber: string
}) {
return axios.get<never, BaseRespData<never>>(
`factory/podJomallOrderProductUs/printPickPdfByBatchNumber`,
{
params,
},
)
}
...@@ -9,7 +9,7 @@ import { ...@@ -9,7 +9,7 @@ import {
ILocation, ILocation,
AnyObject, AnyObject,
InterProductList, InterProductList,
ExportInWarehouseInfo ExportInWarehouseInfo,
} from '@/types/api/warehouse' } from '@/types/api/warehouse'
export interface LogListData { export interface LogListData {
createTime: string createTime: string
...@@ -60,7 +60,18 @@ export interface factoryWarehouseInfo { ...@@ -60,7 +60,18 @@ export interface factoryWarehouseInfo {
remark?: string remark?: string
idList?: string | number[] idList?: string | number[]
} }
export interface factoryLocation {
locationId?: string
idList?: string | number[]
}
export interface productNo {
productNo?: string
idList?: string | number[]
}
export interface customSku {
customSku?: string
idList?: string | number[]
}
export interface ExportFactoryWarehouseInfo { export interface ExportFactoryWarehouseInfo {
pageSize?: number pageSize?: number
currentPage?: number currentPage?: number
...@@ -120,6 +131,9 @@ export interface WarehouseWarning { ...@@ -120,6 +131,9 @@ export interface WarehouseWarning {
productNumber: string productNumber: string
number: string number: string
locationName: string locationName: string
warehouseId: string | number
customSku?: string
productNo?: string
} }
export interface positionInfo { export interface positionInfo {
...@@ -143,7 +157,12 @@ export interface positionFormInfo { ...@@ -143,7 +157,12 @@ export interface positionFormInfo {
remark: string remark: string
status: number status: number
} }
export interface loactionData {
id?: number
warehouseId?: number | string
warehouseName?: string
locationCode?: number | string
}
interface WarehouseWarningData { interface WarehouseWarningData {
id: number id: number
factoryId: number factoryId: number
...@@ -173,6 +192,28 @@ export function getFactoryLocation(data: factoryWarehouseInfo) { ...@@ -173,6 +192,28 @@ export function getFactoryLocation(data: factoryWarehouseInfo) {
data, data,
) )
} }
// 修改库位
export function updateLocationApi(data: factoryLocation) {
return axios.post<never, BasePaginationData<never>>(
'factoryWarehouseInventory/updateLocation',
data,
)
}
// 修改款号
export function updateProductNoApi(data: productNo) {
return axios.post<never, BasePaginationData<never>>(
'factoryWarehouseInventory/updateProductNo',
data,
)
}
// 修改自定义sku
export function updateCustomSkuApi(data: customSku) {
return axios.post<never, BasePaginationData<never>>(
'factoryWarehouseInventory/updateCustomSku',
data,
)
}
export function exportWarehouseInfo(data: ExportFactoryWarehouseInfo) { export function exportWarehouseInfo(data: ExportFactoryWarehouseInfo) {
return axios.post<never, BasePaginationData<positionInfo>>( return axios.post<never, BasePaginationData<positionInfo>>(
'factoryWarehouseInventory/inventory', 'factoryWarehouseInventory/inventory',
...@@ -240,6 +281,14 @@ export function warehouseInfoGetAll() { ...@@ -240,6 +281,14 @@ export function warehouseInfoGetAll() {
'/factoryWarehouseInfo/getAll', '/factoryWarehouseInfo/getAll',
) )
} }
export function LocationInfoGetAll(wareHouseId?: string | number) {
return axios.get<never, BaseRespData<loactionData[]>>(
'/factoryWarehouseLocation/getByWareHouse',
{
params: { wareHouseId },
},
)
}
export function createWarehouseInventoryApi(data: WarehouseWarningData) { export function createWarehouseInventoryApi(data: WarehouseWarningData) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
......
...@@ -76,36 +76,40 @@ import type { TypesettingListData } from '../types/api/typesetting' ...@@ -76,36 +76,40 @@ import type { TypesettingListData } from '../types/api/typesetting'
// 定义通用字段接口,用于处理动态属性 // 定义通用字段接口,用于处理动态属性
interface CommonFields { interface CommonFields {
[key: string]: unknown; [key: string]: unknown
variantImage?: string; variantImage?: string
mainImage?: string; mainImage?: string
sku?: string; sku?: string
productName?: string; productName?: string
} }
// 定义图片列表项接口 // 定义图片列表项接口
interface ImageListItem { interface ImageListItem {
[key: string]: unknown; [key: string]: unknown
imagePath?: string; imagePath?: string
} }
// 创建一个工具类型,用于使用字符串索引访问对象属性 // 创建一个工具类型,用于使用字符串索引访问对象属性
type IndexableObject = Record<string, unknown>; type IndexableObject = Record<string, unknown>
// 扩展现有类型以确保它们有通用字段 // 扩展现有类型以确保它们有通用字段
type CardItem = PodProductList | CardOrderData | TypesettingListData | CommonFields; type CardItem =
| PodProductList
| CardOrderData
| TypesettingListData
| CommonFields
// 定义 props 类型 // 定义 props 类型
interface Props { interface Props {
cardItem: CardItem; cardItem: CardItem
active?: boolean; active?: boolean
showSelectIcon?: boolean; showSelectIcon?: boolean
showSku?: boolean; showSku?: boolean
showProductInfo?: boolean; showProductInfo?: boolean
showImageList?: boolean; showImageList?: boolean
imageField?: string; imageField?: string
imageListField?: string; imageListField?: string
imagePathField?: string; imagePathField?: string
} }
// 定义默认值 // 定义默认值
...@@ -122,45 +126,45 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -122,45 +126,45 @@ const props = withDefaults(defineProps<Props>(), {
// 获取主图片源 // 获取主图片源
const mainImageSrc = computed<string>(() => { const mainImageSrc = computed<string>(() => {
const item = props.cardItem as IndexableObject; const item = props.cardItem as IndexableObject
// 使用索引访问避免联合类型的属性访问问题 // 使用索引访问避免联合类型的属性访问问题
if ( if (
props.imageField === 'variantImage' && props.imageField === 'variantImage' &&
typeof item[props.imageField] === 'string' typeof item[props.imageField] === 'string'
) { ) {
return item[props.imageField] as string; return item[props.imageField] as string
} }
if ( if (
props.imageField === 'mainImage' && props.imageField === 'mainImage' &&
typeof item[props.imageField] === 'string' typeof item[props.imageField] === 'string'
) { ) {
return item[props.imageField] as string; return item[props.imageField] as string
} }
// 默认返回空字符串 // 默认返回空字符串
return ''; return ''
}) })
// 获取图片列表 // 获取图片列表
const imageList = computed<ImageListItem[]>(() => { const imageList = computed<ImageListItem[]>(() => {
const item = props.cardItem as IndexableObject; const item = props.cardItem as IndexableObject
const list = item[props.imageListField]; const list = item[props.imageListField]
return Array.isArray(list) ? list as ImageListItem[] : []; return Array.isArray(list) ? (list as ImageListItem[]) : []
}) })
// 判断是否有图片列表 // 判断是否有图片列表
const hasImageList = computed<boolean>(() => { const hasImageList = computed<boolean>(() => {
return imageList.value.length > 0; return imageList.value.length > 0
}) })
// 获取图片列表项的图片路径 // 获取图片列表项的图片路径
function getItemImagePath(item: IndexableObject): string { function getItemImagePath(item: IndexableObject): string {
return (item[props.imagePathField] as string) || ''; return (item[props.imagePathField] as string) || ''
} }
const copy = (text: string) => { const copy = (text: string) => {
navigator.clipboard.writeText(text); navigator.clipboard.writeText(text)
ElMessage.success('复制成功'); ElMessage.success('复制成功')
} }
</script> </script>
...@@ -174,11 +178,16 @@ const copy = (text: string) => { ...@@ -174,11 +178,16 @@ const copy = (text: string) => {
.commodity-card-image { .commodity-card-image {
position: relative; position: relative;
border: 1px solid #eee;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
.img_top_left { .img_top_left {
position: absolute; position: absolute;
top: 5px; top: 5px;
left: 5px; left: 5px;
display: flex;
align-items: center;
gap: 4px;
} }
.img_top_right { .img_top_right {
......
<template> <template>
<div class="log-list"> <div class="log-list">
<div <div v-for="l in logList" :key="l.id" class="log-item flex">
v-for="l in logList"
:key="l.id"
class="log-item flex"
>
<div class="log-item-icon"> <div class="log-item-icon">
<Icon name="a-2labadianji3x" /> <Icon name="a-2labadianji3x" />
</div> </div>
<div class="log-item-time"> <div class="log-item-time">
<span>{{ l.createTime }}</span> <span>{{ l.local && `${l.local}:` }}{{ l.createTime }}</span>
</div> </div>
<div v-if="l.employeeName" class="log-item-name"> <div v-if="l.employeeName" class="log-item-name">
<span>{{ l.employeeName }}</span> <span>{{ l.employeeName }}</span>
...@@ -45,7 +41,7 @@ defineProps({ ...@@ -45,7 +41,7 @@ defineProps({
} }
.log-item-time { .log-item-time {
width: 140px; // width: 220px;
} }
.log-item-name { .log-item-name {
......
...@@ -34,7 +34,11 @@ ...@@ -34,7 +34,11 @@
</el-sub-menu> </el-sub-menu>
</template> </template>
</el-menu> </el-menu>
<SideBar />
<div v-if="userInfo" class="user-info"> <div v-if="userInfo" class="user-info">
<span class="user-avatar" style="color: #fff; font-size: 14px">
工厂: {{ userInfo.factoryCode }}
</span>
<span class="user-avatar"> <span class="user-avatar">
<el-icon><User /></el-icon> <el-icon><User /></el-icon>
</span> </span>
...@@ -175,9 +179,15 @@ import { ...@@ -175,9 +179,15 @@ import {
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import Menu from '@/router/menu' import Menu from '@/router/menu'
import userUserStore from '@/store/user' import userUserStore from '@/store/user'
import type { FormRules } from 'element-plus' import type { FormRules } from 'element-plus'
import { useValue } from '@/utils/hooks/useValue' import { useValue } from '@/utils/hooks/useValue'
import { changePasswordApi } from '@/api/auth' import { changePasswordApi } from '@/api/auth'
import { ElMessage } from 'element-plus'
import SideBar from './SideBar.vue'
interface MenuItem { interface MenuItem {
index: string index: string
id: number id: number
...@@ -530,4 +540,8 @@ onUnmounted(() => { ...@@ -530,4 +540,8 @@ onUnmounted(() => {
border: none !important; border: none !important;
} }
} }
.user-info {
display: flex;
align-items: center;
}
</style> </style>
...@@ -198,15 +198,6 @@ export default defineComponent({ ...@@ -198,15 +198,6 @@ export default defineComponent({
</div> </div>
)} )}
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: 'flex', alignItems: 'center' }}>
{props.isSearchBtn && (
<ElButton
class="btn"
type="primary"
onClick={() => emit('search', searchForm.value)}
>
查询
</ElButton>
)}
{props.isResetBtn && ( {props.isResetBtn && (
<ElButton <ElButton
class="btn" class="btn"
...@@ -215,10 +206,23 @@ export default defineComponent({ ...@@ -215,10 +206,23 @@ export default defineComponent({
// emit('update:modelValue', {}) // emit('update:modelValue', {})
emit('reset') emit('reset')
}} }}
link
> >
重置 <span title="重置查询条件" style={{ fontSize: '12px' }}>
重置
</span>
</ElButton> </ElButton>
)} )}
{props.isSearchBtn && (
<ElButton
class="btn"
type="primary"
onClick={() => emit('search', searchForm.value)}
>
查询
</ElButton>
)}
{props.isAddBtn && ( {props.isAddBtn && (
<ElButton class="btn" type="success" onClick={() => emit('add')}> <ElButton class="btn" type="success" onClick={() => emit('add')}>
新增 新增
......
<template>
<!-- 右侧工具栏 -->
<div class="tool_warper">
<div title="格式工具" class="tool-item" @click="formatDrawer = true">
<img src="../assets/images/brush-no.png" width="24" height="24" />
</div>
<div
title="打印物流面单"
class="tool-item"
@click="getLogisticDrawer = true"
>
<img src="../assets/images/printer.png" width="24" height="24" />
</div>
</div>
<!-- 格式工具 -->
<span>
<el-drawer
v-model="formatDrawer"
class="format-drawer"
title="格式工具"
direction="rtl"
size="45%"
>
<el-input
v-model="textareaT"
style="width: 100%"
:rows="10"
type="textarea"
placeholder="请输入"
@input="confimTools"
/>
<div
style="
margin-top: 10px;
height: 250px;
overflow: auto;
border: 1px solid #ddd;
padding: 10px;
"
>
{{ newTextareaT }}
</div>
<template #footer>
<span style="display: flex; justify-content: center">
<el-button @click="formatDrawer = false"> 取 消 </el-button>
<el-button type="primary" @click="copy"> 拷 贝 </el-button>
</span>
</template>
</el-drawer>
</span>
<!-- 打印物流面单 -->
<span>
<el-dialog
v-model="getLogisticDrawer"
class="get-logistic-dialog"
title="打印物流面单"
width="1200px"
:before-close="
() => {
getLogisticDrawer = false
content = ''
tableData = {}
productCount = null
}
"
>
<ElSelect
v-model="sheetPrinter"
placeholder="请选择打印机"
style="width: 200px; margin-right: 10px"
@change="handlePrinterChange"
>
<ElOption
v-for="item in printDeviceList"
:key="item"
:label="item"
:value="item"
/>
</ElSelect>
<el-input
v-model="content"
placeholder="请输入单号"
style="width: 700px; margin-right: 10px"
clearable
@keyup.enter="getLogistic"
/>
<el-button type="primary" @click="getLogistic">查 询</el-button>
<el-button type="success" @click="printLogistic">打印面单</el-button>
<div style="font-size: 20px; margin: 20px 0px; color: #666666">
<div style="margin-bottom: 10px; display: flex; gap: 20px">
<div style="width: 400px">店铺单号: {{ tableData.shopNumber }}</div>
<div>
包含产品数:
<span style="color: red">{{ tableData.purchaseNumber }}</span>
</div>
</div>
<div>物流跟踪号: {{ tableData.trackingNumber }}</div>
</div>
<TableView :columns="tableColumns" :data="tableData.productList">
<template #warehouseSkuImage="scope">
<span
style="
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
"
>
<img
:src="scope.row.warehouseSkuImage"
alt="商品图片"
height="50"
style="cursor: pointer"
@click="handlePictureCardPreview(scope.row.warehouseSkuImage)"
/>
<span
class="mark-tag"
:title="handleMark(scope.row.productMark).label"
:style="{
background: handleMark(scope.row.productMark).color,
width: handleMark(scope.row.productMark).width || '20px',
}"
>
{{ handleMark(scope.row.productMark).name }}
</span>
</span>
</template>
</TableView>
</el-dialog>
</span>
<!-- 预览图片 -->
<el-dialog v-model="dialogVisible" width="35%">
<img :src="dialogImageUrl" alt="商品预览图片" />
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, watch, computed } from 'vue'
import { ElMessage } from 'element-plus'
import useLodop from '@/utils/hooks/useLodop'
import { getLogisticUSApi, getLogisticCNApi } from '@/api/common'
import { filePath, FileCnPath } from '@/api/axios'
import { LogisticBill } from '@/types/api/podMakeOrder'
import TableView from '@/components/TableView.vue'
const formatDrawer = ref(false)
const getLogisticDrawer = ref(false)
const textareaT = ref('')
const newTextareaT = ref('')
const content = ref('')
const printDeviceList = ref<string[]>([])
const sheetPrinter = ref('')
// 表格列配置
const tableColumns = computed(() => [
{
label: '图片',
prop: 'warehouseSkuImage',
align: 'center',
width: 150,
slot: 'warehouseSkuImage',
},
{
label: '商品sku',
prop: 'warehouseSku',
align: 'center',
},
{
label: '店铺sku',
prop: 'shopSku',
align: 'center',
},
{
label: 'sku名称',
prop: 'warehouseSkuName',
align: 'center',
},
{
label: '数量',
prop: 'purchaseNumber',
align: 'center',
width: 80,
},
{
label: '包裹号',
prop: 'orderItemId',
align: 'center',
},
{
label: '生产单号',
prop: 'podJomallNo',
align: 'center',
},
])
// 商品标记
const handleMark = (v: string) => {
switch (v) {
case 'virtual':
return {
name: 'VIR',
color: '#ff9900',
label: '虚拟商品',
}
case 'normal':
return {
name: 'G',
color: '#67C23A',
label: '普通商品',
}
case 'pod':
return {
name: 'P',
color: '#F56C6C',
label: 'pod商品',
}
case 'custom':
return {
name: 'C',
color: '#6d9eeb',
label: '一件定制商品',
}
case 'custom_part':
return {
name: 'CP',
color: '#6d9eeb',
label: '一件定制局部印商品',
}
case 'custom_full':
return {
name: 'CF',
color: '#6d9eeb',
label: '一件定制满印商品',
}
default:
return {
name: '',
color: '#FFFFFF',
width: '0',
}
}
}
// 格式工具输入格式化
const confimTools = (v: string) => {
// 先处理结尾的多个空格,只保留一个
let text = v.replace(/\s+$/, ' ')
// 处理开头的多个空格,只保留一个
text = text.replace(/^\s+/, ' ')
// 将多个连续空格替换为单个空格
text = text.replace(/\s+/g, ' ')
// 然后将所有空格和换行符替换为逗号
text = text.replace(/(\s|[\r\n])/g, ',')
// 如果结尾是逗号,则删除
if (text.slice(-1) === ',') {
newTextareaT.value = text.slice(0, -1)
} else {
newTextareaT.value = text
}
}
// 复制
const copy = () => {
const oInput = document.createElement('input')
oInput.value = newTextareaT.value
document.body.appendChild(oInput)
oInput.select() // 选择对象
document.execCommand('Copy') // 执行浏览器复制命令
oInput.className = 'oInput'
oInput.style.display = 'none'
document.body.removeChild(oInput)
ElMessage({
message: '复制成功',
type: 'success',
})
}
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
// 放大图片
const handlePictureCardPreview = (fileUrl: string) => {
dialogImageUrl.value = fileUrl
dialogVisible.value = true
}
const { getCLodop } = useLodop()
// 初始化打印机
const initPrintDevice = () => {
const lodop = getCLodop(null, null)
if (!lodop) {
printDeviceList.value = []
return
}
try {
const arr = []
// 获取打印机数量
const length = lodop.GET_PRINTER_COUNT()
for (let i = 0; i < length; i++) {
// 根据设备序号获取设备名
const name = lodop.GET_PRINTER_NAME(i)
if (name) {
arr.push(name)
}
}
// 获取默认打印机
const defaultPrinter = lodop.GET_PRINTER_NAME(0)
if (defaultPrinter) {
sheetPrinter.value = defaultPrinter
}
printDeviceList.value = arr
} catch (error) {
console.error('初始化打印机失败:', error)
printDeviceList.value = []
}
}
// 处理打印机选择变化,保存到 localStorage
const handlePrinterChange = (value: string) => {
sheetPrinter.value = value
localStorage.setItem('sheetPrinter', JSON.stringify(value))
}
const tableData = ref<LogisticBill>({})
const productCount = ref<number | null>(null)
const type = ref('')
// 查询并打印物流面单
const getLogistic = () => {
content.value = content.value.trim()
if (!content.value) {
ElMessage.warning('请输入单号')
return
}
// 按_分割字符串
const parts = content.value.split('_')
// 检查是否有足够的_分隔符
if (parts.length < 4) {
ElMessage.error('单号格式错误,请检查输入')
return
}
// 获取第三个_后面的内容
type.value = parts[3]
if (type.value.startsWith('USPSC')) {
// 美国物流
getLogisticUSApi(content.value).then((res) => {
if (res.code === 200) {
tableData.value = res.data
productCount.value = tableData.value.productList?.length || 0
window.open(filePath + tableData.value.expressSheet, '_blank')
}
})
} else if (type.value.startsWith('JMPSC')) {
// 中国物流
getLogisticCNApi(content.value).then((res) => {
if (res.code === 200) {
tableData.value = res.data
productCount.value = tableData.value.productList?.length || 0
window.open(FileCnPath + tableData.value.expressSheet, '_blank')
}
})
} else {
ElMessage.error('单号格式错误,请检查输入')
}
}
// 手动打印面单
const printLogistic = () => {
if (!tableData.value.expressSheet) {
ElMessage.warning('请先查询面单')
return
}
if (type.value.startsWith('USPSC')) {
window.open(filePath + tableData.value.expressSheet, '_blank')
} else if (type.value.startsWith('JMPSC')) {
window.open(FileCnPath + tableData.value.expressSheet, '_blank')
}
}
// 监听打印机状态
watch(getLogisticDrawer, async (value: boolean) => {
if (value) {
initPrintDevice()
const locaclPrinter = localStorage.getItem('sheetPrinter')
if (
locaclPrinter &&
Array.isArray(printDeviceList.value) &&
printDeviceList.value.length > 0
) {
try {
const savedPrinter = JSON.parse(locaclPrinter)
// 检查保存的打印机是否在当前打印机列表中
if (printDeviceList.value.includes(savedPrinter)) {
sheetPrinter.value = savedPrinter
} else {
// 如果保存的打印机不在当前列表中,清空 localStorage 并设置为空
localStorage.removeItem('sheetPrinter')
sheetPrinter.value = ''
}
} catch (error) {
console.error('解析保存的打印机信息失败:', error)
localStorage.removeItem('sheetPrinter')
sheetPrinter.value = ''
}
}
}
})
</script>
<style lang="scss" scoped>
.tool_warper {
position: absolute;
top: 50px;
right: 0;
bottom: 0;
width: 40px;
background: #001529;
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
// 格式工具
::v-deep(.format-drawer.el-drawer.rtl) {
height: 650px !important;
right: 40px;
top: calc(50% - 325px) !important;
}
// 打印物流面单
::v-deep(.el-dialog.get-logistic-dialog) {
height: 700px !important;
padding: 30px;
}
.tool-item {
width: 24px;
height: 24px;
cursor: pointer;
margin-bottom: 10px;
}
.mark-tag {
display: inline-block;
background: #f56c6c;
width: 20px;
height: 20px;
border-radius: 11px;
line-height: 20px;
color: white;
}
</style>
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
:data="paginatedData" :data="paginatedData"
border border
:stripe="stripe" :stripe="stripe"
v-bind="attrs"
header-align="center" header-align="center"
height="100%" height="100%"
v-bind="attrs"
> >
<ElTableColumn <ElTableColumn
v-if="selectionable" v-if="selectionable"
type="selection" type="selection"
width="50" width="40"
fixed="left" fixed="left"
header-align="center" header-align="center"
align="center" align="center"
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
v-if="serialNumberable" v-if="serialNumberable"
label="序号" label="序号"
type="index" type="index"
width="60" width="55"
fixed="left" fixed="left"
header-align="center" header-align="center"
align="center" align="center"
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
/> />
<div class="custom-tip"> <div class="custom-tip">
<span>请上传Excel文件(.xls 或 .xlsx)</span> <span>请上传Excel文件(.xls 或 .xlsx)</span>
<div class="down-load" @click="downloadTemplate">
<el-icon><Download /></el-icon>
<span> 下载{{ importName }}模板</span>
</div>
</div> </div>
</div> </div>
<div v-if="fileList.length > 0"> <div v-if="fileList.length > 0">
...@@ -54,7 +58,12 @@ import { ...@@ -54,7 +58,12 @@ import {
computed, computed,
defineExpose, defineExpose,
} from 'vue' } from 'vue'
import { UploadFilled, Document, Close } from '@element-plus/icons-vue' import {
UploadFilled,
Document,
Close,
Download,
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { uploadFileApi } from '@/api/common' import { uploadFileApi } from '@/api/common'
interface FileItem { interface FileItem {
...@@ -64,6 +73,8 @@ interface FileItem { ...@@ -64,6 +73,8 @@ interface FileItem {
const props = defineProps<{ const props = defineProps<{
modelValue: string modelValue: string
importType: string importType: string
importName: string
importUrl:string
}>() }>()
const emit = defineEmits(['update:modelValue', 'imported']) const emit = defineEmits(['update:modelValue', 'imported'])
...@@ -149,7 +160,6 @@ const onFileChange = async (e: Event) => { ...@@ -149,7 +160,6 @@ const onFileChange = async (e: Event) => {
emit('imported', { path: file.name, data: jsonData }) emit('imported', { path: file.name, data: jsonData })
fileList.value = [{ path: file.name, filename: file.name }] fileList.value = [{ path: file.name, filename: file.name }]
value.value = file.name || '' value.value = file.name || ''
ElMessage.success('导入成功')
loading.value = false loading.value = false
} }
reader.readAsBinaryString(file) reader.readAsBinaryString(file)
...@@ -189,7 +199,20 @@ const fileUpload = async (file: File) => { ...@@ -189,7 +199,20 @@ const fileUpload = async (file: File) => {
loading.value = false loading.value = false
} }
} }
const downloadTemplate = () => {
// 获取当前日期
const currentDate = new Date()
const year = currentDate.getFullYear()
const month = String(currentDate.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
const day = String(currentDate.getDate()).padStart(2, '0')
// 生成文件名
const fileName = `${props.importName}模板_${year}${month}${day}.xlsx`
// 设置链接的href和download属性
const link = document.createElement('a')
link.href = props.importUrl // 服务器上的文件路径
link.download = fileName // 设置下载文件的文件名
link.click() // 触发下载
}
const removeFile = (idx: number) => { const removeFile = (idx: number) => {
fileList.value.splice(idx, 1) fileList.value.splice(idx, 1)
value.value = '' value.value = ''
...@@ -262,9 +285,17 @@ const removeFile = (idx: number) => { ...@@ -262,9 +285,17 @@ const removeFile = (idx: number) => {
display: flex; display: flex;
align-items: center; align-items: center;
color: #666; color: #666;
margin-top: 12px; padding-top: 15px;
i { .down-load {
margin-right: 6px; display: flex;
align-items: center;
color: #409eff;
text-decoration: none;
}
.down-load:hover {
cursor: pointer;
text-decoration: underline; /* 鼠标划过时添加下划线 */
} }
} }
} }
......
...@@ -51,12 +51,17 @@ export default defineComponent({ ...@@ -51,12 +51,17 @@ export default defineComponent({
type: Boolean, type: Boolean,
default: true, default: true,
}, },
otherAttrs: {
type: Object,
default: () => ({}),
},
}, },
emits: ['update:modelValue', 'checkbox-change', 'getCheckboxRecords'], emits: ['update:modelValue', 'checkbox-change', 'getCheckboxRecords'],
setup(props, { emit, attrs }) { setup(props, { emit, attrs }) {
const tableRef = ref<VxeTableInstance | null>(null) const tableRef = ref<VxeTableInstance | null>(null)
const tableData = ref<Record<string, unknown>[]>([]) const tableData = ref<Record<string, unknown>[]>([])
const tableColumns = ref<TableColumn[]>([]) const tableColumns = ref<TableColumn[]>([])
const editConfig = computed(() => { const editConfig = computed(() => {
return { return {
trigger: 'dblclick', trigger: 'dblclick',
...@@ -139,10 +144,21 @@ export default defineComponent({ ...@@ -139,10 +144,21 @@ export default defineComponent({
{...this.attrs} {...this.attrs}
> >
{this.isShowCheckBox && ( {this.isShowCheckBox && (
<vxe-column type="checkbox" width="50" align="center"></vxe-column> <vxe-column
type="checkbox"
width="50"
align="center"
{...this.otherAttrs}
></vxe-column>
)} )}
<vxe-column align="center" type="seq" width="50" title="序号" /> <vxe-column
align="center"
type="seq"
width="50"
title="序号"
{...this.otherAttrs}
/>
{this.tableColumns.map((item: TableColumn, index: number) => ( {this.tableColumns.map((item: TableColumn, index: number) => (
<vxe-column <vxe-column
key={index} key={index}
......
...@@ -10,7 +10,7 @@ const props = defineProps({ ...@@ -10,7 +10,7 @@ const props = defineProps({
type: String || Number, type: String || Number,
}, },
otherSize: { otherSize: {
default: 20, default: '20',
type: String || Number, type: String || Number,
}, },
}) })
...@@ -19,7 +19,7 @@ const domSize = ref<string>('0') ...@@ -19,7 +19,7 @@ const domSize = ref<string>('0')
function domResize() { function domResize() {
const father = document.getElementsByClassName('splitpanes')[0] const father = document.getElementsByClassName('splitpanes')[0]
const top = document.getElementById('top') const top = document.getElementById('top')
if(top && father){ if (top && father) {
const v = ((top.clientHeight / father?.clientHeight) * 100).toFixed(2) const v = ((top.clientHeight / father?.clientHeight) * 100).toFixed(2)
if (props.size === '') { if (props.size === '') {
...@@ -28,9 +28,8 @@ function domResize() { ...@@ -28,9 +28,8 @@ function domResize() {
domSize.value = props.size domSize.value = props.size
} }
} }
} }
onUnmounted(()=>{ onUnmounted(() => {
window.removeEventListener('resize', domResize) window.removeEventListener('resize', domResize)
}) })
onMounted(() => { onMounted(() => {
...@@ -38,7 +37,7 @@ onMounted(() => { ...@@ -38,7 +37,7 @@ onMounted(() => {
domResize() domResize()
}) })
defineExpose({ defineExpose({
domResize domResize,
}) })
</script> </script>
...@@ -48,7 +47,6 @@ defineExpose({ ...@@ -48,7 +47,6 @@ defineExpose({
<div id="top"> <div id="top">
<slot name="top"></slot> <slot name="top"></slot>
</div> </div>
</pane> </pane>
<pane style="flex: 1; flex-shrink: 0"> <pane style="flex: 1; flex-shrink: 0">
<div id="bottom"> <div id="bottom">
...@@ -67,15 +65,15 @@ defineExpose({ ...@@ -67,15 +65,15 @@ defineExpose({
#top { #top {
height: fit-content; height: fit-content;
} }
#other-pane{ #other-pane {
height: 100%; height: 100%;
} }
#bottom { #bottom {
height: 100%; height: 100%;
} }
#top, #bottom { #top,
#bottom {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
...@@ -99,11 +97,11 @@ defineExpose({ ...@@ -99,11 +97,11 @@ defineExpose({
transform: translate(-50%); transform: translate(-50%);
width: 30px; width: 30px;
height: 1px; height: 1px;
content: ""; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transition: background-color .3s; transition: background-color 0.3s;
} }
&::after { &::after {
...@@ -112,11 +110,11 @@ defineExpose({ ...@@ -112,11 +110,11 @@ defineExpose({
transform: translate(-50%); transform: translate(-50%);
width: 30px; width: 30px;
height: 1px; height: 1px;
content: ""; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transition: background-color .3s; transition: background-color 0.3s;
} }
} }
......
...@@ -7,13 +7,18 @@ import './styles/index.scss' ...@@ -7,13 +7,18 @@ import './styles/index.scss'
import VxeUITable from 'vxe-table' import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css' import 'vxe-table/lib/style.css'
import { isPermissionBtn } from '@/utils/index'
// 确保在渲染用户提供的HTML内容时,不会执行任何潜在的恶意脚本,从而提高应用的安全性 // 确保在渲染用户提供的HTML内容时,不会执行任何潜在的恶意脚本,从而提高应用的安全性
import vueDomPurifyHTMLPlugin from 'vue-dompurify-html' import vueDomPurifyHTMLPlugin from 'vue-dompurify-html'
createApp(App) const app = createApp(App)
app
.use(vueDomPurifyHTMLPlugin) .use(vueDomPurifyHTMLPlugin)
.use(router) .use(router)
.use(store) .use(store)
.use(VxeUITable) .use(VxeUITable)
.mount('#app') .mount('#app')
app.config.globalProperties.$isPermissionBtn = isPermissionBtn
...@@ -74,6 +74,13 @@ const router = createRouter({ ...@@ -74,6 +74,13 @@ const router = createRouter({
component: PodUsOrderList, component: PodUsOrderList,
}, },
{ {
path: '/pod-us-order/orderTracking',
meta: {
title: 'POD(US)订单跟踪',
},
component: () => import('@/views/order/orderTracking/index.vue'),
},
{
path: '/pod-delivery-note/list', path: '/pod-delivery-note/list',
meta: { meta: {
title: 'POD发货单', title: 'POD发货单',
...@@ -95,6 +102,28 @@ const router = createRouter({ ...@@ -95,6 +102,28 @@ const router = createRouter({
component: UserPage, component: UserPage,
}, },
{ {
path: '/system/downloadClient',
meta: {
title: '下载生产客户端',
},
component: () => {},
beforeEnter() {
// 假设你的下载链接是这个
const downloadLink = '/exeFiles/JomallProductionAssistantSetup.exe'
// 创建一个 a 标签来触发下载
const a = document.createElement('a')
a.href = downloadLink
a.download = '生产客户端.exe' // 你可以指定文件名,或者保持为空来自动使用原始文件名
// 不显示 a 标签,直接触发下载
a.style.display = 'none'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
},
},
{
path: '/system/external-authorisation', path: '/system/external-authorisation',
meta: { meta: {
title: '外部授权', title: '外部授权',
...@@ -228,82 +257,11 @@ const router = createRouter({ ...@@ -228,82 +257,11 @@ const router = createRouter({
component: WarehousePosition, component: WarehousePosition,
}, },
{ {
path: '/logistics/logisticsMethod', path: '/setting/settingIndex',
meta: {
title: '物流方式',
},
component: () => import('@/views/logistics/logisticsMethod.vue'),
},
{
path: '/logistics/shippingAddress',
meta: {
title: '发货地址',
},
component: () => import('@/views/logistics/shippingAddress.vue'),
},
{
path: '/logistics/logisticsQuotation',
meta: {
title: '物流报价',
},
component: () => import('@/views/logistics/logisticsQuotation.vue'),
},
{
path: '/logistics/declarationRule',
meta: {
title: '申报规则',
},
component: () => import('@/views/logistics/declarationRule.vue'),
},
{
path: '/logistics/logisticsPartition',
meta: {
title: '物流分区',
},
component: () => import('@/views/logistics/logisticsPartition.vue'),
},
{
path: '/logistics/logisticsCalculate',
meta: { meta: {
title: '运费试算', title: '设置',
}, },
component: () => import('@/views/logistics/logisticsCalculate.vue'), component: () => import('@/views/setting/settingIndex.vue'),
},
{
path: '/warehouse/manage',
meta: {
title: '仓库管理',
},
component: WarehouseManage,
},
{
path: '/warehouse/receipt-doc',
meta: {
title: '入库单',
},
component: receiptDoc,
},
// {
// path: '/warehouse/issue-doc',
// meta: {
// title: '出库单',
// },
// component: issueDoc,
// },
{
path: '/warehouse/warning',
meta: {
title: '仓库预警',
},
component: WarehouseWarning,
},
{
path: '/warehouse/position',
meta: {
title: '库位管理',
},
component: WarehousePosition,
}, },
], ],
}, },
......
...@@ -117,6 +117,11 @@ const menu: MenuItem[] = [ ...@@ -117,6 +117,11 @@ const menu: MenuItem[] = [
id: 8, id: 8,
label: 'POD订单(US)', label: 'POD订单(US)',
}, },
{
index: '/pod-us-order/orderTracking',
id: 8,
label: 'POD(US)订单跟踪',
},
], ],
}, },
...@@ -171,6 +176,11 @@ const menu: MenuItem[] = [ ...@@ -171,6 +176,11 @@ const menu: MenuItem[] = [
label: '用户管理', label: '用户管理',
}, },
{ {
index: '/system/downloadClient',
id: 4,
label: '下载生产客户端',
},
{
index: '/system/external-authorisation', index: '/system/external-authorisation',
id: 5, id: 5,
label: '外部授权', label: '外部授权',
...@@ -182,6 +192,11 @@ const menu: MenuItem[] = [ ...@@ -182,6 +192,11 @@ const menu: MenuItem[] = [
}, },
], ],
}, },
{
index: '/setting/settingIndex',
id: 7,
label: '设置',
},
// { // {
// index: '', // index: '',
......
import { defineStore } from 'pinia'
const usePermissionBtnStore = defineStore('permissionBtn', {
state: () => ({
permissionBtns: [] as string[], // 权限按钮数组
}),
actions: {
setBtn(state: string[]) {
this.permissionBtns = state
},
},
})
export default usePermissionBtnStore
...@@ -30,8 +30,15 @@ const useUserStore = defineStore('user', { ...@@ -30,8 +30,15 @@ const useUserStore = defineStore('user', {
async login(data: LoginReq) { async login(data: LoginReq) {
try { try {
const resp = await loginApi(data) const resp = await loginApi(data)
console.log(33, resp)
this.setUser(resp.data.sysUser) this.setUser(resp.data.sysUser)
setToken(resp.data.token) setToken(resp.data.token)
localStorage.setItem(
'baseExternalAccountTypes',
JSON.stringify(resp.data.sysUser.baseExternalAccountTypes),
)
router.push({ path: '/dashboard' }) router.push({ path: '/dashboard' })
} catch (error) { } catch (error) {
// showError(error) // showError(error)
......
...@@ -24,6 +24,7 @@ export interface SysUser { ...@@ -24,6 +24,7 @@ export interface SysUser {
factoryCode: string factoryCode: string
status: number status: number
factory: Factory factory: Factory
baseExternalAccountTypes?: []
} }
export interface Factory { export interface Factory {
...@@ -36,4 +37,4 @@ export interface Factory { ...@@ -36,4 +37,4 @@ export interface Factory {
goodsNumber: number goodsNumber: number
authorizeNumber: number authorizeNumber: number
status: number status: number
} }
\ No newline at end of file
...@@ -16,4 +16,5 @@ export interface ExternalAuthListData { ...@@ -16,4 +16,5 @@ export interface ExternalAuthListData {
token?: string token?: string
refreshToken?: string refreshToken?: string
refreshTokenFailureTime?: string refreshTokenFailureTime?: string
enable?: boolean
} }
...@@ -200,6 +200,7 @@ export interface LogListData { ...@@ -200,6 +200,7 @@ export interface LogListData {
employeeName?: string employeeName?: string
description?: string description?: string
createTime?: string createTime?: string
local?: string
} }
export interface QaData { export interface QaData {
......
...@@ -27,6 +27,7 @@ export interface OrderData { ...@@ -27,6 +27,7 @@ export interface OrderData {
printResult?: string printResult?: string
remark?: string remark?: string
version?: number version?: number
factoryOrderNumber?: number | string
} }
export interface ProductList { export interface ProductList {
...@@ -44,4 +45,24 @@ export interface ProductList { ...@@ -44,4 +45,24 @@ export interface ProductList {
power?: boolean power?: boolean
variantImage?: string variantImage?: string
podJomallUsNo?: string podJomallUsNo?: string
previewImgs?: { sort: string | number; title: string; url: string }[]
}
export interface LogisticBill {
expressSheet?: string
salesPlatform?: string
orderStatus?: string
shopWay?: string
blocked?: boolean
logisticsCompanyName?: string
logisticsWayNameId?: string
shopNumber?: string
id?: string
shopId?: string
orderId?: string
orderNumber?: string
trackingNumber?: string
systemWeight?: number | string
purchaseNumber?: number
productList?: ProductList[]
} }
...@@ -21,6 +21,8 @@ export interface SearchForm { ...@@ -21,6 +21,8 @@ export interface SearchForm {
endTime?: string | null endTime?: string | null
internalMemo?: string internalMemo?: string
productionFileId?: string productionFileId?: string
interceptedStatus?: boolean
platform?: string
} }
export interface CardOrderData { export interface CardOrderData {
id: number id: number
......
...@@ -3,29 +3,38 @@ export interface Tab { ...@@ -3,29 +3,38 @@ export interface Tab {
statusName?: string statusName?: string
quantity?: number quantity?: number
} }
export interface ExportParams extends SearchForm {
idList?: number[]
exportAll: boolean
status?: string
}
export interface SearchForm { export interface SearchForm {
timeType: number | null timeType?: number | null
shopNumber: string shopNumber?: string
shipmentType: string shipmentType?: string
userMark: string userMark?: string
logisticsTracking: string processNumber?: string
baseSku: string trackingNumber?: string
factoryOrderNumber: string baseSku?: string
sku: string factoryOrderNumber?: string
factorySubOrderNumber: string sku?: string
status: string factorySubOrderNumber?: string
customizedQuantity: string status?: string
multi: boolean | null customizedQuantity?: string
startTime: string | null multi?: boolean | null
endTime: string | null startTime?: string | null
exceptionHandling: number | undefined endTime?: string | null
platform: string exceptionHandling?: number | undefined
productionClient: string platform?: string
warehouseId: string | number productionClient?: string
thirdSkuCode: string warehouseId?: string | number
supplierProductNo: string thirdSkuCode?: string
batchArrangeNumber: string supplierProductNo?: string
craftCode: string batchArrangeNumber?: string
craftCode?: string
thirdStockSku?: string
interceptStatus?: number | string
} }
export interface PodUsOrderListData { export interface PodUsOrderListData {
id: number id: number
...@@ -56,7 +65,7 @@ export interface PodUsOrderListData { ...@@ -56,7 +65,7 @@ export interface PodUsOrderListData {
paymentTime?: string paymentTime?: string
startStockingTime?: string startStockingTime?: string
finishTime?: string finishTime?: string
shipmentType?: string shipmentType?: number
expressSheet?: string expressSheet?: string
trackingNumber?: string trackingNumber?: string
processNumber?: string processNumber?: string
...@@ -69,11 +78,14 @@ export interface PodUsOrderListData { ...@@ -69,11 +78,14 @@ export interface PodUsOrderListData {
orderNumber?: string orderNumber?: string
logisticsWayId?: number | null logisticsWayId?: number | null
logisticsWayName?: string logisticsWayName?: string
url?: string | null
tiffUrl?: string | null
} }
export interface ProductList { export interface ProductList {
id: number id: number
podJomallOrderUsId: number podJomallOrderUsId: number
thirdSubOrderNumber?: string thirdSubOrderNumber?: string
thirdStockSku?: string
factorySubOrderNumber?: string factorySubOrderNumber?: string
factoryCode?: string factoryCode?: string
productName?: string productName?: string
...@@ -83,7 +95,10 @@ export interface ProductList { ...@@ -83,7 +95,10 @@ export interface ProductList {
templatePrice?: number templatePrice?: number
variantImage?: string variantImage?: string
craftPrice?: number craftPrice?: number
craftCode?: string
platform?: string
imageAry?: string imageAry?: string
previewImgs?: []
designImages?: string designImages?: string
categoryId?: number categoryId?: number
categoryName?: string categoryName?: string
...@@ -113,6 +128,7 @@ export interface ProductList { ...@@ -113,6 +128,7 @@ export interface ProductList {
supplierProductNo?: string | null supplierProductNo?: string | null
replenishmentSumNum?: number | null replenishmentSumNum?: number | null
batchArrangeNumber?: string | null batchArrangeNumber?: string | null
interceptStatus?: number | null
} }
export interface cardImages { export interface cardImages {
title: string title: string
...@@ -128,6 +144,7 @@ export interface LogListData { ...@@ -128,6 +144,7 @@ export interface LogListData {
description: string description: string
deleteContent: string deleteContent: string
createTime: string createTime: string
local?: string
} }
export interface ProductionClient { export interface ProductionClient {
code?: string code?: string
...@@ -187,3 +204,12 @@ export interface CraftListData { ...@@ -187,3 +204,12 @@ export interface CraftListData {
craftName: string craftName: string
craftCode: string craftCode: string
} }
export interface InterceptStateGroupData {
shipment: {
[key: string]: number
}
production: {
[key: string]: number
}
}
...@@ -12,3 +12,7 @@ export function useValue<T extends object>( ...@@ -12,3 +12,7 @@ export function useValue<T extends object>(
return [value, resetToDefault] return [value, resetToDefault]
} }
export function getLastSegment(str: string): string {
const lastIndex = str.lastIndexOf('_')
return lastIndex !== -1 ? str.slice(lastIndex + 1) : str
}
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { DateTime } from 'luxon'
import usePermissionBtnStore from '@/store/permission'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function val<T>(data: T, key: string | ((data: T) => any)) { export function val<T>(data: T, key: string | ((data: T) => any)) {
if (typeof key === 'function') return key(data) if (typeof key === 'function') return key(data)
...@@ -20,3 +23,29 @@ export function copyText(text: string) { ...@@ -20,3 +23,29 @@ export function copyText(text: string) {
document.body.removeChild(oInput) document.body.removeChild(oInput)
ElMessage.success('复制成功') ElMessage.success('复制成功')
} }
/**
* 将本地时间转换为北京时间(自动检测时区)
* @param {string} localTime - 本地时间字符串,格式 YYYY-MM-DD HH:mm:ss
* @returns {string} 北京时间,格式 YYYY-MM-DD HH:mm:ss
*/
export function convertToChinaTime(
timeString: string,
currentZone: string = 'local',
targetZone: string = 'Asia/Shanghai',
) {
// 将输入的时间字符串解析为本地时间,假设输入时间是本地时间
const inputTime = DateTime.fromFormat(timeString, 'yyyy-MM-dd HH:mm:ss', {
zone: currentZone,
})
const chinaTime = inputTime.setZone(targetZone)
return chinaTime.toFormat('yyyy-MM-dd HH:mm:ss')
}
export function isPermissionBtn(key: string) {
const permissionBtns = usePermissionBtnStore().permissionBtns
if (!permissionBtns) return false
return permissionBtns.includes(key)
}
...@@ -76,32 +76,28 @@ ...@@ -76,32 +76,28 @@
<ElFormItem> <ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton> <ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem> </ElFormItem>
<ElFormItem v-if="nodeId === 10">
<el-button type="primary" @click="confirmOrder">
确认对账单
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeId === 10">
<el-button type="warning" @click="rejectOrder">
驳回
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="exportExcel">
导出
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeId === 30">
<el-button type="danger" @click="auditOrder('archive')">
归档
</el-button>
</ElFormItem>
</ElForm> </ElForm>
</div> </div>
<div class="btn-list">
<el-button
v-if="nodeId === 10"
type="primary"
@click="confirmOrder"
>
确认对账单
</el-button>
<el-button
v-if="nodeId === 10"
type="warning"
@click="rejectOrder"
>
驳回
</el-button>
<el-button type="success" @click="exportExcel"> 导出 </el-button>
<el-button
v-if="nodeId === 30"
type="danger"
@click="auditOrder('archive')"
>
归档
</el-button>
</div>
<div <div
class="delivery-note-content flex-1 flex-column overflow-hidden" class="delivery-note-content flex-1 flex-column overflow-hidden"
> >
......
...@@ -20,7 +20,7 @@ import NavMenu from '@/components/NavMenu.vue' ...@@ -20,7 +20,7 @@ import NavMenu from '@/components/NavMenu.vue'
.container { .container {
flex: 1; flex: 1;
padding: 0 10px 10px; padding: 0 50px 10px 10px;
background-color: #f6f6f6; background-color: #f6f6f6;
overflow: hidden; overflow: hidden;
} }
......
...@@ -29,7 +29,7 @@ let timer: number | undefined ...@@ -29,7 +29,7 @@ let timer: number | undefined
const second = ref(5) const second = ref(5)
const router = useRouter() const router = useRouter()
props.showBtn && props.showBtn &&
(timer = setInterval(() => { (timer = window.setInterval(() => {
if (second.value === 0) { if (second.value === 0) {
clearInterval(timer) clearInterval(timer)
router.go(-1) router.go(-1)
......
...@@ -21,6 +21,7 @@ const styles = { ...@@ -21,6 +21,7 @@ const styles = {
display: 'flex', display: 'flex',
padding: '10px', padding: '10px',
justifyContent: 'flex-start', justifyContent: 'flex-start',
flexWrap: 'wrap',
backgroundColor: '#efefef', backgroundColor: '#efefef',
}, },
} as const } as const
......
...@@ -4,9 +4,13 @@ import SplitDiv from '@/components/splitDiv/splitDiv.vue' ...@@ -4,9 +4,13 @@ import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import { import {
getLogisticsLog, getLogisticsLog,
IForm, IForm,
ILogisticsCompany, ILogisticsCompanyData, ILogisticsList, ILogisticsCompany,
ILogisticsCompanyData,
ILogisticsList,
logisticsCompany, logisticsCompany,
logisticsCompanyAdd, logisticsCompanyAllCodelist, logisticsCompanyDelete, logisticsCompanyAdd,
logisticsCompanyAllCodelist,
logisticsCompanyDelete,
logisticsCompanyUpdate, logisticsCompanyUpdate,
} from '@/api/logistics.ts' } from '@/api/logistics.ts'
import LogDialog from '@/views/logistics/components/LogDialog.tsx' import LogDialog from '@/views/logistics/components/LogDialog.tsx'
...@@ -51,25 +55,12 @@ const createData = ref({ ...@@ -51,25 +55,12 @@ const createData = ref({
}, },
}) })
const rules = { const rules = {
code: [ code: [{ required: true, message: '请选择物流公司编码', trigger: 'change' }],
{ required: true, message: '请选择物流公司编码', trigger: 'change' },
],
name: [
{ required: true, message: '请输入名称', trigger: 'blur' },
],
contact: [
{ required: true, message: '请输入联系人', trigger: 'blur' },
],
phone: [
{ required: true, message: '请输入电话/手机', trigger: 'blur' },
],
siteUrl: [
{ required: true, message: '请输入网址', trigger: 'blur' },
], contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
address: [ phone: [{ required: true, message: '请输入电话/手机', trigger: 'blur' }],
{ required: true, message: '请输入地址', trigger: 'blur' }, siteUrl: [{ required: true, message: '请输入网址', trigger: 'blur' }],
], address: [{ required: true, message: '请输入地址', trigger: 'blur' }],
} }
const leftData = ref<ILogisticsCompany[]>([]) const leftData = ref<ILogisticsCompany[]>([])
const pagination = ref<ILogisticsCompanyData>({ const pagination = ref<ILogisticsCompanyData>({
...@@ -127,7 +118,10 @@ const handleBatchDelete = async (row: ILogisticsCompany | null) => { ...@@ -127,7 +118,10 @@ const handleBatchDelete = async (row: ILogisticsCompany | null) => {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}) })
const str = row && row.id ? row.id?.toString() : selections.value.map((el) => el.id).join(',') const str =
row && row.id
? row.id?.toString()
: selections.value.map((el) => el.id).join(',')
await logisticsCompanyDelete(str) await logisticsCompanyDelete(str)
ElMessage.success('删除成功') ElMessage.success('删除成功')
await getData() await getData()
...@@ -173,9 +167,10 @@ const updateWarehouse = (item: IForm) => { ...@@ -173,9 +167,10 @@ const updateWarehouse = (item: IForm) => {
} }
const codeChange = (v: string) => { const codeChange = (v: string) => {
const item = logisticsList.value.find(d => d.code === v) const item = logisticsList.value.find((d) => d.code === v)
if (item) { if (item) {
otherFields.value = Object.keys(item.apiData || {}) otherFields.value = Object.keys(item.apiData || {})
form.value.name = item.basicsName
} }
} }
...@@ -194,19 +189,27 @@ getLogisticsList() ...@@ -194,19 +189,27 @@ getLogisticsList()
<el-form inline :model="searchForm"> <el-form inline :model="searchForm">
<el-form-item label="名称"> <el-form-item label="名称">
<el-input <el-input
v-model="searchForm.name" style="width: 140px;" placeholder="请输入名称" v-model="searchForm.name"
clearable></el-input> style="width: 140px"
placeholder="请输入名称"
clearable
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="编码"> <el-form-item label="编码">
<el-input <el-input
v-model="searchForm.code" style="width: 140px;" placeholder="请输入编码" v-model="searchForm.code"
clearable></el-input> style="width: 140px"
placeholder="请输入编码"
clearable
></el-input>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="getData">查询</el-button> <el-button type="primary" @click="getData">查询</el-button>
<el-button type="success" @click="createWarehouse">新增</el-button> <el-button type="success" @click="createWarehouse">新增</el-button>
<el-button type="danger" @click="handleBatchDelete(null)">删除</el-button> <el-button type="danger" @click="handleBatchDelete(null)"
>删除</el-button
>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
...@@ -217,53 +220,76 @@ getLogisticsList() ...@@ -217,53 +220,76 @@ getLogisticsList()
<div class="table-flex"> <div class="table-flex">
<div class="left-table"> <div class="left-table">
<div class="table-container"> <div class="table-container">
<el-table height="100%" :data="leftData" border @selection-change="handleSelectionChange"> <el-table
height="100%"
:data="leftData"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" /> <el-table-column type="selection" />
<el-table-column type="index" label="序号" width="60" /> <el-table-column type="index" label="序号" width="60" />
<el-table-column <el-table-column
label="名称" label="名称"
prop="name" prop="name"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="编码" label="编码"
prop="code" prop="code"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="联系人" label="联系人"
prop="contact" prop="contact"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="电话" label="电话"
prop="phone" prop="phone"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="网址" label="网址"
prop="siteUrl" prop="siteUrl"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="地址" label="地址"
prop="address" prop="address"
align="center" align="center"
show-overflow-tooltip> show-overflow-tooltip
>
</el-table-column> </el-table-column>
<el-table-column width="260" label="操作" align="center"> <el-table-column width="260" label="操作" align="center">
<template #default="{row}"> <template #default="{ row }">
<el-button text type="primary" @click="updateWarehouse(row)">编辑</el-button> <el-button
<el-button text type="danger" @click="handleBatchDelete(row)">删除</el-button> text
<el-button text type="info" @click="handleShowLog(row)">操作日志</el-button> type="primary"
@click="updateWarehouse(row)"
>编辑</el-button
>
<el-button
text
type="danger"
@click="handleBatchDelete(row)"
>删除</el-button
>
<el-button text type="info" @click="handleShowLog(row)"
>操作日志</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -279,7 +305,6 @@ getLogisticsList() ...@@ -279,7 +305,6 @@ getLogisticsList()
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
/> />
</div> </div>
</div> </div>
</div> </div>
<LogDialog <LogDialog
...@@ -287,46 +312,105 @@ getLogisticsList() ...@@ -287,46 +312,105 @@ getLogisticsList()
title="操作日志" title="操作日志"
@close="logDialogVisible = false" @close="logDialogVisible = false"
> >
<div v-for="item in logList" :key="item.id" style="margin-bottom: 8px"> <div
v-for="item in logList"
:key="item.id"
style="margin-bottom: 8px"
>
<span style="margin-right: 10px">{{ item.createTime }}</span> <span style="margin-right: 10px">{{ item.createTime }}</span>
<span>{{ item.description }}</span> <span>{{ item.description }}</span>
</div> </div>
</LogDialog> </LogDialog>
<el-dialog v-model="createData.show" :close-on-click-modal="false" width="900px" :title="createData.title"> <el-dialog
<el-form v-if="createData.show" ref="formRef" style="padding: 30px" label-width="110px" :rules="rules" :model="form" class="el-row"> v-model="createData.show"
:close-on-click-modal="false"
width="900px"
:title="createData.title"
>
<el-form
v-if="createData.show"
ref="formRef"
style="padding: 30px"
label-width="110px"
:rules="rules"
:model="form"
class="el-row"
>
<el-form-item class="el-col-12" label="物流公司编码" prop="code"> <el-form-item class="el-col-12" label="物流公司编码" prop="code">
<el-select v-model="form.code" clearable filterable @change="codeChange"> <el-select
v-model="form.code"
clearable
filterable
@change="codeChange"
>
<el-option <el-option
v-for="it in logisticsList" :key="it.code" :label="it.code" v-for="it in logisticsList"
:value="it.code"> :key="it.code"
:label="it.code"
:value="it.code"
>
{{ it.code }} {{ it.code }}
<span style="font-size: 14px; color: #999; line-height: 24px"> <span
({{ it.basicsName }}) style="font-size: 14px; color: #999; line-height: 24px"
</span> >
({{ it.basicsName }})
</span>
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item class="el-col-12" label="名称" prop="name"> <el-form-item class="el-col-12" label="名称">
<el-input v-model="form.name" clearable placeholder="请输入名称"></el-input> <el-input
v-model="form.name"
clearable
disabled
placeholder="选择物流公司编码后展示"
></el-input>
</el-form-item> </el-form-item>
<el-form-item class="el-col-12" label="联系人" prop="contact"> <el-form-item class="el-col-12" label="联系人" prop="contact">
<el-input v-model="form.contact" clearable placeholder="请输入联系人"></el-input> <el-input
v-model="form.contact"
clearable
placeholder="请输入联系人"
></el-input>
</el-form-item> </el-form-item>
<el-form-item class="el-col-12" label="电话/手机" prop="phone"> <el-form-item class="el-col-12" label="电话/手机" prop="phone">
<el-input v-model="form.phone" clearable placeholder="请输入电话/手机"></el-input> <el-input
v-model="form.phone"
clearable
placeholder="请输入电话/手机"
></el-input>
</el-form-item> </el-form-item>
<el-form-item class="el-col-12" label="网址" prop="siteUrl"> <el-form-item class="el-col-12" label="网址" prop="siteUrl">
<el-input v-model="form.siteUrl" clearable placeholder="请输入网址"></el-input> <el-input
v-model="form.siteUrl"
clearable
placeholder="请输入网址"
></el-input>
</el-form-item> </el-form-item>
<el-form-item class="el-col-12" label="地址" prop="address"> <el-form-item class="el-col-12" label="地址" prop="address">
<el-input v-model="form.address" clearable placeholder="请输入地址"></el-input> <el-input
v-model="form.address"
clearable
placeholder="请输入地址"
></el-input>
</el-form-item> </el-form-item>
<el-form-item v-for="o in otherFields" :key="o" class="el-col-12" required :label="o" :prop="`apiData.${o}`"> <el-form-item
<el-input v-model="form.apiData[o]" clearable :placeholder="`请输入${o}`"></el-input> v-for="o in otherFields"
:key="o"
class="el-col-12"
required
:label="o"
:prop="`apiData.${o}`"
>
<el-input
v-model="form.apiData[o]"
clearable
:placeholder="`请输入${o}`"
></el-input>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="createData.show=false">取消</el-button> <el-button @click="createData.show = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button> <el-button type="primary" @click="handleConfirm">确定</el-button>
</template> </template>
</el-dialog> </el-dialog>
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
v-model="editForm" v-model="editForm"
:config="formConfig" :config="formConfig"
form-item-width="100%" form-item-width="100%"
labelWidth="125" labelWidth="110"
> >
</CustomizeForm> </CustomizeForm>
...@@ -76,16 +76,18 @@ import { ...@@ -76,16 +76,18 @@ import {
updateLogisticsWay, updateLogisticsWay,
updateStatusLogisticsWay, updateStatusLogisticsWay,
deleteLogisticsWay, deleteLogisticsWay,
getWarehouseList,
getRuleList, getRuleList,
getPlatformList, getPlatformList,
getLogisticsLog, getLogisticsLog,
getLogisticsCompanyList, getLogisticsCompanyList,
getUniuniList, getUniuniList,
getTiktokCarrier,
} from '@/api/logistics' } from '@/api/logistics'
import { WarehouseListData } from '@/types/api/podUsOrder'
import { ISeachFormConfig } from '@/types/searchType' import { ISeachFormConfig } from '@/types/searchType'
import { TableColumn } from '@/components/VxeTable' import { TableColumn } from '@/components/VxeTable'
// import type { PromiseSettledResult } from 'types' import { loadWarehouseListApi } from '@/api/podUsOrder'
import type { import type {
LogisticsMethod, LogisticsMethod,
platformObj, platformObj,
...@@ -98,12 +100,14 @@ import { IFormConfig } from '@/components/CustomizeForm.tsx' ...@@ -98,12 +100,14 @@ import { IFormConfig } from '@/components/CustomizeForm.tsx'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
import { useValue } from './hooks/useValue' import { useValue } from './hooks/useValue'
import { showConfirm } from '@/utils/ui' import { showConfirm } from '@/utils/ui'
import { Edit, Delete, List } from '@element-plus/icons-vue' import { Edit, Delete, List, WarningFilled } from '@element-plus/icons-vue'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import UPARCELImage from '@/assets/images/UPARCEL物流编码.png'
const [searchForm] = useValue({}) const [searchForm] = useValue({})
const [editForm, resetEditForm] = useValue<LogisticsMethod>({ const [editForm, resetEditForm] = useValue<LogisticsMethod>({
platformList: [{ platform: '', logisticsName: '', showPlatform: [] }], platformList: [
{ platform: '', logisticsName: '', showPlatform: ['default'] },
],
ruleRef: { ruleId: '', ruleName: '' }, ruleRef: { ruleId: '', ruleName: '' },
status: 1, status: 1,
}) })
...@@ -131,6 +135,14 @@ const dialogVisible = ref(false) ...@@ -131,6 +135,14 @@ const dialogVisible = ref(false)
const logDialogVisible = ref(false) const logDialogVisible = ref(false)
const editFormRef = ref<InstanceType<typeof CustomizeForm> | null>(null) const editFormRef = ref<InstanceType<typeof CustomizeForm> | null>(null)
const selection = ref([]) const selection = ref([])
const warehouseList = ref<WarehouseListData[]>([])
interface ImageList {
[key: string]: string
}
const imgeList = ref<ImageList>({
UPARCEL: UPARCELImage,
})
const searchConfig = ref<ISeachFormConfig[]>([ const searchConfig = ref<ISeachFormConfig[]>([
{ {
prop: 'name', prop: 'name',
...@@ -166,48 +178,13 @@ const searchConfig = ref<ISeachFormConfig[]>([ ...@@ -166,48 +178,13 @@ const searchConfig = ref<ISeachFormConfig[]>([
}, },
]) ])
const platformList = ref([]) const platformList = ref([])
const warehouseList = ref([])
const ruleNameList = ref([]) const ruleNameList = ref([])
const uniuniList = ref([]) const uniuniList = ref([])
const logisticsCompanyList = ref([]) const logisticsCompanyList = ref([])
const formConfig = computed<IFormConfig[]>(() => [ const formConfig = computed<IFormConfig[]>(() => [
{ title: '物流基础信息' }, { title: '物流基础信息' },
{ {
prop: 'name',
type: 'input',
label: '物流名称',
attrs: {
placeholder: '请输入物流名称',
},
rules: [
{
required: true,
message: '请输入物流名称',
},
],
},
{
prop: 'warehouseId',
type: 'select',
label: '仓库名称',
attrs: {
placeholder: '请选择仓库名称',
label: 'name',
value: 'id',
options: [...(warehouseList.value || [])],
onChange: (value: { name: string; id: string | number }) => {
editForm.value.warehouseName = value.name
},
},
rules: [
{
required: true,
message: '请选择仓库名称',
},
],
},
{
prop: 'companyId', prop: 'companyId',
type: 'select', type: 'select',
label: '物流公司', label: '物流公司',
...@@ -282,15 +259,51 @@ const formConfig = computed<IFormConfig[]>(() => [ ...@@ -282,15 +259,51 @@ const formConfig = computed<IFormConfig[]>(() => [
}, },
], ],
}, },
{ {
prop: 'serviceCode', prop: 'serviceCode',
type: 'input',
label: '物流编码', label: '物流编码',
fixed: 'last', fixed: 'last',
attrs: { render: () => {
placeholder: '请输入物流编码', const company = editForm.value.company
return (
<div style="display: flex; width:100%;height: 100%">
<el-input
v-model={editForm.value.serviceCode}
placeholder="请输入物流编码"
/>
<el-popover
placement="bottom-end"
width={1050}
v-slots={{
default: () => (
<div style="width: 100%; height: 100%;">
<div style="font-size: 20px; font-weight: bold;margin-bottom: 10px;">
{company ? `${company}物流编码来源图:` : '请先选择物流公司'}
</div>
{company && imgeList.value[company] && (
<img
src={imgeList.value[company]}
style={{ width: '100%' }}
alt={`${company}物流编码图`}
/>
)}
</div>
),
reference: () => (
<el-icon
style={{ marginLeft: '10px', height: '100%' }}
size={25}
>
<WarningFilled />
</el-icon>
),
}}
></el-popover>
</div>
)
}, },
rules: [ rules: [
{ {
required: true, required: true,
...@@ -299,6 +312,37 @@ const formConfig = computed<IFormConfig[]>(() => [ ...@@ -299,6 +312,37 @@ const formConfig = computed<IFormConfig[]>(() => [
], ],
}, },
{ {
prop: 'name',
type: 'input',
label: '物流名称',
fixed: 'last',
attrs: {
placeholder: '请输入物流名称',
},
rules: [
{
required: true,
message: '请输入物流名称',
},
],
},
{
prop: 'warehouseId',
type: 'select',
label: '仓库名称',
fixed: 'last',
attrs: {
placeholder: '请选择仓库名称',
label: 'name',
value: 'id',
options: [...(warehouseList.value || [])],
onChange: (item: WarehouseListData) => {
editForm.value.warehouseName = item.name
},
},
},
{
prop: 'siteUrl', prop: 'siteUrl',
type: 'input', type: 'input',
label: '查询网址', label: '查询网址',
...@@ -351,32 +395,64 @@ const formConfig = computed<IFormConfig[]>(() => [ ...@@ -351,32 +395,64 @@ const formConfig = computed<IFormConfig[]>(() => [
collapse-tags collapse-tags
collapse-tags-tooltip collapse-tags-tooltip
v-model={item['showPlatform']} v-model={item['showPlatform']}
disabled={index === 0}
> >
{platformList.value?.map((el, idx) => ( {platformList.value?.map((el, idx) => (
<el-option label={el} value={el} key={idx}></el-option> <el-option label={el} value={el} key={idx}></el-option>
))} ))}
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item {item['showPlatform'].length === 1 &&
key={index} item['showPlatform'][0] === 'TIKTOK' ? (
class="renderItem" <el-form-item
label="物流名称" key={index}
style="display: flex;flex:50%" class="renderItem"
prop={`platformList.${index}.logisticsName`} label="物流名称"
rules={[ style="display: flex;flex:50%"
{ prop={`platformList.${index}.logisticsName`}
required: true, rules={[
message: '请输入物流名称', {
trigger: 'blur', required: true,
}, message: '请输入物流名称',
]} trigger: 'blur',
> },
<el-input ]}
v-model={item.logisticsName} >
placeholder="请输入物流名称" <el-select
/> v-model={item.logisticsName}
</el-form-item> placeholder="请选择物流名称"
<div style="display: flex;flex:20%"> >
{tiktokCarriers.value?.map((el) => (
<el-option
label={el.name}
value={el.name}
key={el.id}
></el-option>
))}{' '}
</el-select>
</el-form-item>
) : (
<el-form-item
key={index}
class="renderItem"
label="物流名称"
style="display: flex;flex:50%"
prop={`platformList.${index}.logisticsName`}
rules={[
{
required: true,
message: '请输入物流名称',
trigger: 'blur',
},
]}
>
<el-input
v-model={item.logisticsName}
placeholder="请输入物流名称"
/>
</el-form-item>
)}
<div style="display: flex;flex:17%">
{(formData?.platformList as platformObj[])?.length - 1 === {(formData?.platformList as platformObj[])?.length - 1 ===
index && ( index && (
<el-button <el-button
...@@ -531,6 +607,7 @@ const tableConfig = ref<TableColumn[]>([ ...@@ -531,6 +607,7 @@ const tableConfig = ref<TableColumn[]>([
onMounted(() => { onMounted(() => {
getAllList() getAllList()
getTiktokCarriers()
}) })
/** /**
...@@ -674,7 +751,7 @@ const save = debounce(async () => { ...@@ -674,7 +751,7 @@ const save = debounce(async () => {
return return
} }
} }
}, 400) }, 200)
/** /**
* @description: 新增按钮打开弹窗 * @description: 新增按钮打开弹窗
...@@ -751,14 +828,20 @@ function deleteCol(index: number) { ...@@ -751,14 +828,20 @@ function deleteCol(index: number) {
async function getAllList() { async function getAllList() {
try { try {
const res = await Promise.allSettled([ const res = await Promise.allSettled([
getWarehouseList(), loadWarehouseListApi(),
getRuleList(), getRuleList(),
getPlatformList(), getPlatformList(),
getLogisticsCompanyList(), getLogisticsCompanyList(),
getUniuniList(), getUniuniList(),
]) ])
res.forEach( res.forEach(
(item: PromiseSettledResult<{ code: number; data: never[] }>, index) => { (
item: PromiseSettledResult<{
code: number
data: WarehouseListData[] | never[]
}>,
index,
) => {
if (item.status === 'fulfilled') { if (item.status === 'fulfilled') {
if (item.value.code === 200) { if (item.value.code === 200) {
if (index == 0) { if (index == 0) {
...@@ -766,13 +849,13 @@ async function getAllList() { ...@@ -766,13 +849,13 @@ async function getAllList() {
} else if (index == 1) { } else if (index == 1) {
console.log(758, item.value.data) console.log(758, item.value.data)
ruleNameList.value = item.value.data || [] ruleNameList.value = (item.value.data as never[]) || []
} else if (index == 2) { } else if (index == 2) {
platformList.value = item.value.data || [] platformList.value = (item.value.data as never[]) || []
} else if (index == 3) { } else if (index == 3) {
logisticsCompanyList.value = item.value.data || [] logisticsCompanyList.value = (item.value.data as never[]) || []
} else if (index == 4) { } else if (index == 4) {
uniuniList.value = item.value.data || [] uniuniList.value = (item.value.data as never[]) || []
} }
} }
} }
...@@ -785,6 +868,15 @@ async function getAllList() { ...@@ -785,6 +868,15 @@ async function getAllList() {
} }
} }
const tiktokCarriers = ref<{ name: string; id: number }[]>([])
/**
* @description: 获取tictok物流承运商
*/
async function getTiktokCarriers() {
const { data } = await getTiktokCarrier()
tiktokCarriers.value = data
}
/** /**
* @description: 日志弹窗 * @description: 日志弹窗
*/ */
......
...@@ -43,6 +43,9 @@ ...@@ -43,6 +43,9 @@
align="center" align="center"
border="full" border="full"
@getCheckboxRecords="handleCheckboxRecords" @getCheckboxRecords="handleCheckboxRecords"
:otherAttrs="{
fixed: 'left',
}"
></CustomizeTable> ></CustomizeTable>
</div> </div>
</div> </div>
...@@ -58,7 +61,6 @@ import { ...@@ -58,7 +61,6 @@ import {
updateLogisticsZone, updateLogisticsZone,
deleteLogisticsZone, deleteLogisticsZone,
importLogisticsZone, importLogisticsZone,
exportExcelLogisticsZone,
getlogisticsWayAllList, getlogisticsWayAllList,
} from '@/api/logistics' } from '@/api/logistics'
...@@ -217,7 +219,11 @@ async function getList(data?: { ...@@ -217,7 +219,11 @@ async function getList(data?: {
logisticsIdList?: string[] | string logisticsIdList?: string[] | string
codePrefix?: string codePrefix?: string
}) { }) {
loading.value = true const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try { try {
const res = await getLogisticsZoneList({ const res = await getLogisticsZoneList({
...data, ...data,
...@@ -232,6 +238,7 @@ async function getList(data?: { ...@@ -232,6 +238,7 @@ async function getList(data?: {
{ {
prop: 'zoneName', prop: 'zoneName',
label: '分区', label: '分区',
attrs: { 'min-width': '100px', fixed: 'left' },
}, },
] ]
const newConfig = [] const newConfig = []
...@@ -243,6 +250,7 @@ async function getList(data?: { ...@@ -243,6 +250,7 @@ async function getList(data?: {
label: key, label: key,
attrs: { attrs: {
'edit-render': {}, 'edit-render': {},
'min-width': '300px',
}, },
render: { render: {
edit: ({ edit: ({
...@@ -296,7 +304,7 @@ async function getList(data?: { ...@@ -296,7 +304,7 @@ async function getList(data?: {
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} finally { } finally {
loading.value = false loading.close()
} }
} }
...@@ -387,13 +395,11 @@ function onBeforeUploadImage(file: File) { ...@@ -387,13 +395,11 @@ function onBeforeUploadImage(file: File) {
*/ */
async function downloadExcel() { async function downloadExcel() {
try { try {
const res = await exportExcelLogisticsZone()
const blob = new Blob([res as unknown as BlobPart])
const filename = '物流分区模版.xlsx'
const link = document.createElement('a') const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob) link.href = '/files/logisticsZoning.xlsx'
link.download = filename link.download = '物流分区模版.xlsx'
link.click() link.click()
document.body.removeChild(link)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
...@@ -410,10 +416,11 @@ async function exportExcel(file: { file: File }) { ...@@ -410,10 +416,11 @@ async function exportExcel(file: { file: File }) {
const res = await importLogisticsZone(formData) const res = await importLogisticsZone(formData)
if (res.code === 200) { if (res.code === 200) {
ElMessage.success('导入成功!') ElMessage.success('导入成功!')
getList(searchForm.value)
} }
} catch (error) { } catch (error) {
ElMessage.error('导入失败!') ElMessage.error('导入失败!')
} finally {
getList(searchForm.value)
} }
} }
......
...@@ -30,7 +30,13 @@ export default function useShipment(callback?: () => void) { ...@@ -30,7 +30,13 @@ export default function useShipment(callback?: () => void) {
const shipmentLoading = ref(false) const shipmentLoading = ref(false)
const shipmentOrderRef = ref<ShipmentType>() const shipmentOrderRef = ref<ShipmentType>()
const searchShipmentByOrderNumber = async () => { const searchShipmentByOrderNumber = async () => {
const code = productionOrderNumber.value let code = productionOrderNumber.value
// AAAB_60527128-9_1_JMSC250121017 新版示例
const regex = /^[A-Z]{4}_/ //是否以四个大写字母加下划线开头
if (regex.test(code)) {
code =
code.split('_')[0] + '-' + code.split('_')[code.split('_').length - 1]
}
shipmentVisible.value = true shipmentVisible.value = true
if (!code) { if (!code) {
isLock.value = false isLock.value = false
......
import { getQaOrderBySubOrderNumber, qaFinishedApi } from '@/api/order' import { getQaOrderBySubOrderNumber, qaFinishedApi } from '@/api/order'
import { InspectionData, QaData, shopRemark } from '@/types/api/order' import { InspectionData, QaData, shopRemark } from '@/types/api/order'
import { useValue } from '@/utils/hooks/useValue' import { useValue, getLastSegment } from '@/utils/hooks/useValue'
import { showConfirm } from '@/utils/ui' import { showConfirm } from '@/utils/ui'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
...@@ -45,9 +45,10 @@ export default function useQuarantine() { ...@@ -45,9 +45,10 @@ export default function useQuarantine() {
return indexList return indexList
} }
const searchQaByOrderNumber = () => { const searchQaByOrderNumber = () => {
const uid = shipmentUid.value const uid = shipmentUid.value
const code = qaCode.value const code = qaCode.value.startsWith('GCSC')
? qaCode.value
: getLastSegment(qaCode.value)
if (!code) { if (!code) {
isLock.value = false isLock.value = false
playAudio('picking_warning') playAudio('picking_warning')
...@@ -83,7 +84,12 @@ export default function useQuarantine() { ...@@ -83,7 +84,12 @@ export default function useQuarantine() {
// 查找是否已经存在 // 查找是否已经存在
const row = sourceData.value.find( const row = sourceData.value.find(
(item) => (item) =>
(uid === item.shipmentUid && (code1 === item.subOrderNumber || item.factorySubOrderNumber == code1)) || (!uid && (item.factorySubOrderNumber == code1 || item.subOrderNumber == code1)), (uid === item.shipmentUid &&
(code1 === item.subOrderNumber ||
item.factorySubOrderNumber == code1)) ||
(!uid &&
(item.factorySubOrderNumber == code1 ||
item.subOrderNumber == code1)),
) )
if (row) { if (row) {
// 质检数量不能大于发货数量 // 质检数量不能大于发货数量
...@@ -100,7 +106,10 @@ export default function useQuarantine() { ...@@ -100,7 +106,10 @@ export default function useQuarantine() {
offset: window.innerHeight / 2, offset: window.innerHeight / 2,
}) })
} }
const len = sourceData.value.filter(el => el.factorySubOrderNumber == code1 || code1 === el.subOrderNumber) const len = sourceData.value.filter(
(el) =>
el.factorySubOrderNumber == code1 || code1 === el.subOrderNumber,
)
const scansNum = sourceData.value[index].scansNum || 0 const scansNum = sourceData.value[index].scansNum || 0
const indexList = findAllIndex(code1) const indexList = findAllIndex(code1)
...@@ -111,7 +120,6 @@ export default function useQuarantine() { ...@@ -111,7 +120,6 @@ export default function useQuarantine() {
sourceData.value[i]['scansNum'] = scansNum + 1 sourceData.value[i]['scansNum'] = scansNum + 1
} }
}) })
} else { } else {
if (row.shipmentNum !== scansNum) { if (row.shipmentNum !== scansNum) {
sourceData.value[index]['scansNum'] = scansNum + 1 sourceData.value[index]['scansNum'] = scansNum + 1
...@@ -163,17 +171,32 @@ export default function useQuarantine() { ...@@ -163,17 +171,32 @@ export default function useQuarantine() {
Number(e.shipmentNum || 0) === Number(e.shipmentNum || 0) ===
Number(e.passNum || 0) + Number(e.notPassNum || 0), Number(e.passNum || 0) + Number(e.notPassNum || 0),
).length ).length
const row = sourceData.value.find(item => { const row = sourceData.value.find((item) => {
return (uid === item.shipmentUid && (code1 === item.subOrderNumber || item.factorySubOrderNumber == code1)) || (!uid && (item.factorySubOrderNumber == code1 || item.subOrderNumber == code1)) return (
(uid === item.shipmentUid &&
(code1 === item.subOrderNumber ||
item.factorySubOrderNumber == code1)) ||
(!uid &&
(item.factorySubOrderNumber == code1 ||
item.subOrderNumber == code1))
)
}) })
const index = sourceData.value.findIndex(item => { const index = sourceData.value.findIndex((item) => {
return (uid === item.shipmentUid && (code1 === item.subOrderNumber || item.factorySubOrderNumber == code1)) || (!uid && (item.factorySubOrderNumber == code1 || item.subOrderNumber == code1)) return (
(uid === item.shipmentUid &&
(code1 === item.subOrderNumber ||
item.factorySubOrderNumber == code1)) ||
(!uid &&
(item.factorySubOrderNumber == code1 ||
item.subOrderNumber == code1))
)
}) })
if (row) { if (row) {
// row.passNum += 1 // row.passNum += 1
currentRow.value = row currentRow.value = row
cloneRow.value = JSON.parse(JSON.stringify(currentRow.value)) cloneRow.value = JSON.parse(JSON.stringify(currentRow.value))
if (!row.inspectionStatus && !sourceData.value[index].scansNum) sourceData.value[index].scansNum = 1 if (!row.inspectionStatus && !sourceData.value[index].scansNum)
sourceData.value[index].scansNum = 1
} }
qaInputRef.value.focus() qaInputRef.value.focus()
isLock.value = false isLock.value = false
......
import { getOrderBySubOrderNumber, saveOrder } from '@/api/order' import { getOrderBySubOrderNumber, saveOrder } from '@/api/order'
import { ICompareObjects, OrderData, ProductList, ShipmentForm, ShipmentOrderRes } from '@/types/api/order' import {
import { useValue } from '@/utils/hooks/useValue' ICompareObjects,
OrderData,
ProductList,
ShipmentForm,
ShipmentOrderRes,
} from '@/types/api/order'
import { useValue, getLastSegment } from '@/utils/hooks/useValue'
import { nextTick, ref } from 'vue' import { nextTick, ref } from 'vue'
import { ShipmentType } from '../Shipment.vue' import { ShipmentType } from '../Shipment.vue'
...@@ -24,7 +30,10 @@ export default function useShipment(callback?: () => void) { ...@@ -24,7 +30,10 @@ export default function useShipment(callback?: () => void) {
const shipmentLoading = ref(false) const shipmentLoading = ref(false)
const shipmentOrderRef = ref<ShipmentType>() const shipmentOrderRef = ref<ShipmentType>()
const searchShipmentByOrderNumber = async () => { const searchShipmentByOrderNumber = async () => {
const code = productionOrderNumber.value // const code = getLastSegment(productionOrderNumber.value)
const code = productionOrderNumber.value.startsWith('GCSC')
? productionOrderNumber.value
: getLastSegment(productionOrderNumber.value)
shipmentVisible.value = true shipmentVisible.value = true
if (!code) { if (!code) {
isLock.value = false isLock.value = false
...@@ -98,8 +107,7 @@ export default function useShipment(callback?: () => void) { ...@@ -98,8 +107,7 @@ export default function useShipment(callback?: () => void) {
ElMessageBox.confirm('不能加入,地址信息不一致!', '重要提示', { ElMessageBox.confirm('不能加入,地址信息不一致!', '重要提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
type: 'warning', type: 'warning',
}).catch(() => { }).catch(() => {})
})
} else { } else {
canJoin(res.data, code) canJoin(res.data, code)
} }
...@@ -213,7 +221,7 @@ export default function useShipment(callback?: () => void) { ...@@ -213,7 +221,7 @@ export default function useShipment(callback?: () => void) {
try { try {
const res = await saveOrder(data, shipmentForm.value) const res = await saveOrder(data, shipmentForm.value)
fetch(res.message || '') fetch(res.message || '')
.then(response => { .then((response) => {
// 确保响应是 OK // 确保响应是 OK
if (!response.ok) { if (!response.ok) {
throw new Error('网络响应错误') throw new Error('网络响应错误')
...@@ -221,14 +229,16 @@ export default function useShipment(callback?: () => void) { ...@@ -221,14 +229,16 @@ export default function useShipment(callback?: () => void) {
// 返回图片的二进制数据(Blob) // 返回图片的二进制数据(Blob)
return response.blob() return response.blob()
}) })
.then(blob => { .then((blob) => {
const a = document.createElement('a') const a = document.createElement('a')
a.href = window.URL.createObjectURL(blob) a.href = window.URL.createObjectURL(blob)
a.target = '_blank' a.target = '_blank'
a.download = (res.message as string).split('/')[ (res.message as string).split('/').length - 1] a.download = (res.message as string).split('/')[
(res.message as string).split('/').length - 1
]
a.click() a.click()
}) })
.catch(error => { .catch((error) => {
console.error('下载图片时出错:', error) console.error('下载图片时出错:', error)
}) })
ElMessage.success('发货成功') ElMessage.success('发货成功')
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
v-model="searchForm.mainSku" v-model="searchForm.mainSku"
placeholder=" SKU" placeholder=" SKU"
clearable clearable
style="width: 130px" style="width: 125px"
@blur="searchForm.mainSku = searchForm.mainSku.trim()" @blur="searchForm.mainSku = searchForm.mainSku.trim()"
></ElInput> ></ElInput>
</ElFormItem> </ElFormItem>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
v-model="searchForm.endProductId" v-model="searchForm.endProductId"
placeholder="请输入成品ID" placeholder="请输入成品ID"
clearable clearable
style="width: 130px" style="width: 125px"
@blur=" @blur="
searchForm.endProductId = searchForm.endProductId.trim() searchForm.endProductId = searchForm.endProductId.trim()
" "
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
v-model="searchForm.subOrderNumber" v-model="searchForm.subOrderNumber"
placeholder="生产单号" placeholder="生产单号"
clearable clearable
style="width: 130px" style="width: 125px"
@blur=" @blur="
searchForm.subOrderNumber = searchForm.subOrderNumber.trim() searchForm.subOrderNumber = searchForm.subOrderNumber.trim()
" "
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
v-model="searchForm.orderNumber" v-model="searchForm.orderNumber"
placeholder="订单号" placeholder="订单号"
clearable clearable
style="width: 130px" style="width: 125px"
@blur="searchForm.orderNumber = searchForm.orderNumber.trim()" @blur="searchForm.orderNumber = searchForm.orderNumber.trim()"
></ElInput> ></ElInput>
</ElFormItem> </ElFormItem>
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
v-model="searchForm.shopNumber" v-model="searchForm.shopNumber"
placeholder="店铺单号" placeholder="店铺单号"
clearable clearable
style="width: 130px" style="width: 125px"
@blur="searchForm.shopNumber = searchForm.shopNumber.trim()" @blur="searchForm.shopNumber = searchForm.shopNumber.trim()"
></ElInput> ></ElInput>
</ElFormItem> </ElFormItem>
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
v-model="searchForm.internalMemo" v-model="searchForm.internalMemo"
placeholder="内部标签" placeholder="内部标签"
clearable clearable
style="width: 130px" style="width: 125px"
@blur=" @blur="
searchForm.internalMemo = searchForm.internalMemo.trim() searchForm.internalMemo = searchForm.internalMemo.trim()
" "
...@@ -111,7 +111,7 @@ ...@@ -111,7 +111,7 @@
v-model="searchForm.logisticsTracking" v-model="searchForm.logisticsTracking"
placeholder="物流跟踪号" placeholder="物流跟踪号"
clearable clearable
style="width: 130px" style="width: 125px"
@blur=" @blur="
searchForm.logisticsTracking = searchForm.logisticsTracking =
searchForm.logisticsTracking.trim() searchForm.logisticsTracking.trim()
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
v-model="searchForm.billNumber" v-model="searchForm.billNumber"
placeholder="发货单号" placeholder="发货单号"
clearable clearable
style="width: 130px" style="width: 125px"
@blur="searchForm.billNumber = searchForm.billNumber.trim()" @blur="searchForm.billNumber = searchForm.billNumber.trim()"
></ElInput> ></ElInput>
</ElFormItem> </ElFormItem>
...@@ -132,7 +132,7 @@ ...@@ -132,7 +132,7 @@
v-model="searchForm.lanshouName" v-model="searchForm.lanshouName"
placeholder="收货人" placeholder="收货人"
clearable clearable
style="width: 130px" style="width: 125px"
></ElInput> ></ElInput>
</ElFormItem> </ElFormItem>
<ElFormItem label="排序"> <ElFormItem label="排序">
...@@ -152,6 +152,90 @@ ...@@ -152,6 +152,90 @@
<!-- <ElFormItem>--> <!-- <ElFormItem>-->
<!-- <ElButton @click="resetSearchForm">重置</ElButton>--> <!-- <ElButton @click="resetSearchForm">重置</ElButton>-->
<!-- </ElFormItem>--> <!-- </ElFormItem>-->
<ElFormItem v-if="statusCode === 2">
<ElButton type="success" @click="confirmProduce"
>确认生产</ElButton
>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30)
"
type="warning"
is-dark
@click="downloadManuscript"
>下载稿件</ElButton
>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30) ||
selection.length !== 1
"
type="success"
is-dark
@click="reGenerateManuscript"
>重新打包稿件
</ElButton>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30) ||
selection.length !== 1
"
type="warning"
is-dark
@click="reCreateManuscript"
>重新生成稿件
</ElButton>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
>
<ElButton
:loading="btnLoading"
type="primary"
dark
@click="printManuscript"
>打印生产单</ElButton
>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 7"
>
<ElButton type="success" dark @click="exportManuscript"
>导出生产单</ElButton
>
</ElFormItem>
<ElFormItem>
<ElButton type="warning" @click="addInternalTag"
>添加内部标签</ElButton
>
</ElFormItem>
<ElFormItem
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
>
<ElButton type="primary" @click="refreshProduct"
>刷新商品信息</ElButton
>
</ElFormItem>
<ElFormItem v-if="statusCode === 3 || statusCode === 4">
<ElButton type="success" @click="confirmDelivery"
>发货</ElButton
>
</ElFormItem>
<ElFormItem v-if="statusCode === 6">
<ElButton type="success" @click="confirmCheck">质检</ElButton>
</ElFormItem>
</ElForm> </ElForm>
</div> </div>
<div class="header-filter-tab"> <div class="header-filter-tab">
...@@ -174,98 +258,6 @@ ...@@ -174,98 +258,6 @@
</template> </template>
<template #bottom> <template #bottom>
<div class="order-content flex-1 flex-column overflow-hidden"> <div class="order-content flex-1 flex-column overflow-hidden">
<!-- 操作按钮 -->
<div class="order-operate-btn">
<span v-if="statusCode === 2" class="item">
<ElButton type="success" @click="confirmProduce"
>确认生产</ElButton
>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
class="item"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30)
"
type="warning"
is-dark
@click="downloadManuscript"
>下载稿件</ElButton
>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
class="item"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30) ||
selection.length !== 1
"
type="success"
is-dark
@click="reGenerateManuscript"
>重新打包稿件
</ElButton>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
class="item"
>
<ElButton
:disabled="
selection.find((item) => item.manuscriptStatus !== 30) ||
selection.length !== 1
"
type="warning"
is-dark
@click="reCreateManuscript"
>重新生成稿件
</ElButton>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
class="item"
>
<ElButton
:loading="btnLoading"
type="primary"
dark
@click="printManuscript"
>打印生产单</ElButton
>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 7"
class="item"
>
<ElButton type="success" dark @click="exportManuscript"
>导出生产单</ElButton
>
</span>
<span class="item">
<ElButton type="warning" @click="addInternalTag"
>添加内部标签</ElButton
>
</span>
<span
v-if="statusCode === 2 || statusCode === 3 || statusCode === 4"
class="item"
>
<ElButton type="primary" @click="refreshProduct"
>刷新商品信息</ElButton
>
</span>
<span v-if="statusCode === 3 || statusCode === 4" class="item">
<ElButton type="success" @click="confirmDelivery">发货</ElButton>
</span>
<span v-if="statusCode === 6" class="item">
<ElButton type="success" @click="confirmCheck">质检</ElButton>
</span>
</div>
<div <div
ref="tableWrapperRef" ref="tableWrapperRef"
v-loading="loading" v-loading="loading"
......
<script setup lang="ts">
defineOptions({
name: 'OrderTracking',
})
import {
factoryWarehouseInfo,
warehouseInfo,
warehouseInfoGetAll,
} from '@/api/warehouse.ts'
import {
getListCraftApi,
getProductionClientApi,
getOrderList,
getOperationLogApi,
getOrderTabData,
getfaceSimplexFileApi,
exportPodUSInfo,
} from '@/api/podUsOrder'
import {
SearchForm,
CraftListData,
ProductionClient,
ProductList,
PodUsOrderListData,
LogListData,
Tab,
ExportParams,
} from '@/types/api/podUsOrder'
import platformJson from '../../../json/platform.json'
import dayjs from 'dayjs'
import { getUserMarkList } from '@/api/common'
import { CaretBottom, CaretTop } from '@element-plus/icons-vue'
import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import { BaseRespData } from '@/types/api'
import { showConfirm } from '@/utils/ui'
import { isArray, isString } from '@/utils/validate'
import ResultInfo from '../podUs/components/ResultInfo.vue'
import { filePath } from '@/api/axios'
import { convertToChinaTime } from '@/utils/index'
import { useValue } from '@/utils/hooks/useValue'
const [searchForm, resetSearchForm] = useValue<SearchForm>({
timeType: 1,
shopNumber: '',
shipmentType: '',
userMark: '',
processNumber: '',
baseSku: '',
factoryOrderNumber: '',
sku: '',
factorySubOrderNumber: '',
status: '',
customizedQuantity: '',
multi: null,
startTime: null,
endTime: null,
exceptionHandling: undefined,
platform: '',
productionClient: '',
warehouseId: '',
thirdSkuCode: '',
supplierProductNo: '',
batchArrangeNumber: '',
craftCode: '',
thirdStockSku: '',
})
const tableColumns = computed(() => {
return [
{
label: '订单号',
prop: 'factoryOrderNumber',
width: 160,
align: 'center',
},
{
label: '第三方订单号',
prop: 'thirdOrderNumber',
width: 240,
align: 'center',
},
{
label: '店铺单号',
prop: 'shopNumber',
width: 160,
align: 'center',
},
{
label: '订单状态',
prop: 'status',
slot: 'status',
width: 160,
align: 'center',
},
{
label: '物流类型',
slot: 'shipmentType',
prop: 'shipmentType',
width: 120,
align: 'center',
},
{
label: '物流跟踪号',
prop: 'trackingNumber',
width: 160,
align: 'center',
},
{
label: '总克重(g)',
prop: 'weight',
width: 100,
align: 'center',
},
{
label: '生产端',
prop: 'productionClient',
width: 100,
align: 'center',
},
{
label: '发货仓库',
prop: 'warehouseName',
width: 120,
align: 'center',
},
{
label: '物流方式',
prop: 'logisticsWayName',
width: 120,
align: 'center',
},
{
label: '收货人',
prop: 'receiverName',
width: 100,
align: 'center',
},
{
label: '收货人电话',
prop: 'receiverPhone',
width: 140,
align: 'center',
},
{
label: '收货人邮编',
prop: 'receiverPostCode',
width: 140,
align: 'center',
},
{
label: '收货地址',
prop: 'lanshouAddress',
width: 500,
align: 'center',
},
]
})
const goodsColumns = computed(() => {
return [
{
label: '商品图片',
prop: 'productImg',
slot: 'productImg',
width: 90,
},
{
label: '商品名称',
prop: 'productName',
width: 170,
align: 'center',
showOverflowTooltip: true,
},
{
label: '数量',
prop: 'num',
width: 100,
align: 'center',
},
{
label: '状态',
prop: 'subStatus',
width: 130,
align: 'center',
showOverflowTooltip: true,
},
{
label: '生产单号',
prop: 'factorySubOrderNumber',
width: 170,
align: 'center',
showOverflowTooltip: true,
},
{
label: '变体sku',
prop: 'variantSku',
width: 170,
align: 'center',
showOverflowTooltip: true,
},
{
label: '第三方生产单号',
prop: 'thirdSubOrderNumber',
width: 170,
align: 'center',
showOverflowTooltip: true,
},
{
label: '库存SKU',
prop: 'thirdSkuCode',
width: 170,
align: 'center',
showOverflowTooltip: true,
},
{
label: '工厂',
prop: 'factoryCode',
width: 100,
align: 'center',
},
{
label: '货号',
prop: 'thirdStockSku',
width: 130,
align: 'center',
},
{
label: '款号',
prop: 'supplierProductNo',
width: 162,
align: 'center',
},
{
label: '工艺',
prop: 'craftName',
width: 140,
align: 'center',
},
{
label: '价格($)',
prop: 'productPrice',
align: 'center',
},
{
label: '模板金额($)',
prop: 'templatePrice',
width: 120,
align: 'center',
},
{
label: '工艺金额($)',
prop: 'craftPrice',
width: 120,
align: 'center',
},
{
label: '付款金额($)',
prop: 'payAmount',
width: 120,
align: 'center',
},
{
label: '未生产数量',
prop: 'notPassNum',
width: 100,
align: 'center',
},
{
label: '补胚数量',
prop: 'replenishmentSumNum',
width: 100,
align: 'center',
},
{
label: '克重(g)',
prop: 'weight',
width: 100,
align: 'center',
},
{
label: '备注',
prop: 'remark',
width: 100,
align: 'center',
},
]
})
const tableData = ref<PodUsOrderListData[]>([])
const goodsData = ref<ProductList[]>([])
const searchVisible = ref(false)
const goodsLoading = ref(false)
const logList = ref<LogListData[]>([])
const selection = ref<PodUsOrderListData[]>([])
const warehouseList = ref<warehouseInfo[]>([])
const timeRange = ref<string[]>([])
const pickerOptions = {
shortcuts: [
{
text: '今日',
value: () => getDateRange(0),
},
{
text: '昨天',
value: () => getDateRange(1),
},
{
text: '最近7天',
value: () => getDateRange(6),
},
{
text: '最近14天',
value: () => getDateRange(13),
},
{
text: '最近30天',
value: () => getDateRange(29),
},
{
text: '本周',
value: () => getWeekRange(0),
},
{
text: '上周',
value: () => getWeekRange(1),
},
{
text: '本月',
value: () => getMonthRange(0),
},
{
text: '上月',
value: () => getMonthRange(1),
},
{
text: '历史',
value: () => {
const end = dayjs().endOf('day').toDate()
const start = dayjs('2000-01-01').startOf('day').toDate()
return [start, end]
},
},
{
text: '转换中国时间',
value: () => {
console.log(3469, timeRange.value)
if (timeRange.value?.length) {
const end = timeRange.value[1] ?? ''
const start = timeRange.value[0] ?? ''
return [convertToChinaTime(start), convertToChinaTime(end)]
} else {
return getDateRange(0)
}
},
},
],
}
const pagination = ref<factoryWarehouseInfo>({
pageSize: 50,
currentPage: 1,
total: 0,
})
const search = () => {
goodsData.value = []
logList.value = []
getOrderListFn()
}
const getDateRange = (days = 0, type: 'past' | 'future' = 'past') => {
const end = dayjs()
const start =
type === 'past' ? end.subtract(days, 'day') : end.add(days, 'day')
return [start.startOf('day').toDate(), end.endOf('day').toDate()]
}
const getMonthRange = (months = 0, type: 'past' | 'future' = 'past') => {
const now = dayjs()
const start =
type === 'past' ? now.subtract(months, 'month') : now.add(months, 'month')
return [start.startOf('month').toDate(), start.endOf('month').toDate()]
}
const getWeekRange = (weeks = 0, type: 'past' | 'future' = 'past') => {
const now = dayjs()
const start =
type === 'past' ? now.subtract(weeks, 'week') : now.add(weeks, 'week')
return [start.startOf('week').toDate(), start.endOf('week').toDate()]
}
const exportLoading = ref(false)
const exportVisible = ref(false)
const exportForm = ref({
resource: '',
})
const exportData = () => {
exportVisible.value = true
}
const submitExportForm = async () => {
if (exportForm.value.resource === '') {
return ElMessage.error('请选择导出类型')
}
exportLoading.value = true
const resourceType = Number(exportForm.value.resource)
const params: ExportParams = {
exportAll: false,
idList: [],
}
// 使用函数封装映射逻辑
const mapIds = (items: PodUsOrderListData[]) =>
items.map((el) => Number(el.id))
switch (resourceType) {
case 0:
params.idList = mapIds(tableData.value as PodUsOrderListData[])
break
case 1:
params.idList = mapIds(selection.value)
break
case 2:
params.exportAll = true
params.idList = undefined
break
default:
console.error('未知的资源类型:', resourceType)
}
try {
const res = await exportPodUSInfo({
...params,
...(resourceType === 2 ? searchForm.value : {}),
})
window.open(filePath + res.message, '_blank')
exportVisible.value = false
exportLoading.value = false
} catch (e) {
exportVisible.value = false
exportLoading.value = false
}
}
const handleSizeChange = (pageSize: number) => {
pagination.value.pageSize = pageSize
getOrderListFn()
}
const handleCurrentChange = (currentPage: number) => {
pagination.value.currentPage = currentPage
getOrderListFn()
}
const productionClient = ref<ProductionClient[]>()
const loadProductionClient = async () => {
try {
const res = await getProductionClientApi()
if (res.code !== 200) return
productionClient.value = res.data
} catch (e) {
console.error(e)
}
}
const getWarehouse = async () => {
const { data } = await warehouseInfoGetAll()
warehouseList.value = data
}
const userMarkList = ref<string[]>([])
const getUserMark = async () => {
try {
const res = await getUserMarkList()
userMarkList.value = res.data
} catch (error) {
//showError(error)
}
}
const craftList = ref<CraftListData[]>([])
const loadCraftList = async () => {
try {
const res = await getListCraftApi()
if (res.code !== 200) return
craftList.value = res.data
} catch (e) {
console.error(e)
}
}
const tableRef = ref()
const getOrderListFn = async () => {
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const { currentPage, pageSize } = pagination.value
try {
const { data } = await getOrderList(
{ ...searchForm.value },
currentPage,
pageSize,
)
tableData.value = data.records
pagination.value.total = data.total
if (tableData.value?.length) {
nextTick(async () => {
await tableRef.value?.setCurrentRow(tableData.value[0])
rowClick(tableData.value[0] as unknown as PodUsOrderListData)
})
}
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const currentRowId = ref<number>()
function rowClick(row: PodUsOrderListData) {
currentRowId.value = row.id
goodsLoading.value = true
goodsData.value = row.productList as ProductList[]
const timer = setTimeout(() => {
goodsLoading.value = false
clearTimeout(timer)
}, 500)
}
const logLoading = ref(false)
const operationLog = async () => {
logLoading.value = true
try {
if (currentRowId.value) {
const res = await getOperationLogApi(currentRowId.value as number)
if (res.code !== 200) return
logList.value = res.data.map((el) => {
return {
...el,
local: 'BeiJing',
}
})
tempChinaLogs.value = [...logList.value]
}
} catch (e) {
console.error(e)
} finally {
const timer = setTimeout(() => {
logLoading.value = false
clearTimeout(timer)
}, 500)
}
}
const tabsNav = ref<Tab[]>([])
const loadTabData = async () => {
try {
const res = await getOrderTabData()
tabsNav.value = res.data.filter((el) => el.status !== 'BATCH_DOWNLOAD')
} catch (error) {
// showError(error)
}
}
function getStatus(status: string) {
const item = tabsNav.value.find((el) => el.status === status)
if (item) {
return item.statusName
}
return ''
}
const resultInfo = ref<
{
id: string | number
status: boolean
factoryOrderNumber?: string
message: string
}[]
>([])
const resultRefs = ref<InstanceType<typeof ResultInfo> | null>(null)
/**
* @description: 获取打印面单
*/
const getOrderByIdApi = async (type: string) => {
if (selection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const operationMap: {
[key: string]: {
message: string
Fn: (orderIds: (string | number)[]) => Promise<BaseRespData<never>>
}
} = {
getPrintOrder: { message: '获取打印面单', Fn: getfaceSimplexFileApi },
}
let loading
const operation = operationMap[type]
if (operation) {
try {
await showConfirm(`确定对该订单 ${operation.message}?`, {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
const ids = selection.value.map((el) => el.id)
loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const res = await operation.Fn(ids)
if (res.code === 200) {
if (isArray(res.data)) {
resultInfo.value =
(res.data as {
id: string | number
status: boolean
factoryOrderNumber?: string
message: string
}[]) || []
resultRefs.value?.showDialog()
console.log(33)
} else if (isString(res.data)) {
window.open(filePath + res.data)
}
} else {
ElMessage.error(res.message)
}
} catch (e) {
resultInfo.value = []
console.error(e)
} finally {
loading && loading.close()
}
} else {
ElMessage.warning('未知操作类型')
}
}
const tempChinaLogs = ref<LogListData[]>([])
const zoneType = ref<string>('Asia/Shanghai')
function changeChinaTime(zone: string) {
zoneType.value = zone
logList.value = tempChinaLogs.value.map((el) => {
return {
...el,
createTime: convertToChinaTime(el.createTime, 'Asia/Shanghai', zone),
local: zone.split('/')[1] === 'Shanghai' ? 'BeiJing' : zone.split('/')[1],
}
})
}
const resultConfirm = () => {
search()
loadTabData()
}
const handleSelectionChange = (val: PodUsOrderListData[]) => {
selection.value = val
}
watch(
() => currentRowId.value,
(newValue, oldValue) => {
if (newValue !== oldValue) {
operationLog()
}
},
)
loadTabData()
loadProductionClient()
getUserMark()
loadCraftList()
getWarehouse()
onMounted(() => {
getOrderListFn()
})
</script>
<template>
<split-div otherSize="35">
<template #top>
<el-card>
<ElForm :model="searchForm" size="default" inline class="search-form">
<ElFormItem label="仓库">
<ElSelect
v-model="searchForm.warehouseId"
clearable
filterable
placeholder="请输入"
style="width: 150px"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</ElSelect>
</ElFormItem>
<ElFormItem label="平台">
<ElSelect
v-model="searchForm.platform"
value-key=""
placeholder="请选择"
clearable
filterable
popper-class="customize-select-style"
style="width: 150px"
>
<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="订单号">
<ElInput
v-model="searchForm.factoryOrderNumber"
placeholder="订单号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="物流类型">
<ElSelect
v-model="searchForm.shipmentType"
placeholder="物流类型"
clearable
style="width: 150px"
>
<ElOption
v-for="(item, index) in ['自有物流', '工厂物流']"
:key="index"
:value="index"
:label="item"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="物流跟踪号">
<ElInput
v-model.trim="searchForm.trackingNumber"
placeholder="物流跟踪号"
clearable
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem label="店铺单号">
<ElInput
v-model="searchForm.shopNumber"
placeholder="店铺单号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="生产单号">
<ElInput
v-model="searchForm.factorySubOrderNumber"
placeholder="生产单号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="状态">
<ElSelect
v-model="searchForm.status"
clearable
filterable
placeholder="请输入"
style="width: 150px"
>
<el-option
v-for="item in tabsNav"
:key="item.status"
:label="item.statusName"
:value="item.status"
></el-option>
</ElSelect>
</ElFormItem>
<ElFormItem label="类型">
<el-radio-group v-model="searchForm.customizedQuantity">
<el-radio-button value="single">单面</el-radio-button>
<el-radio-button value="multiple">多面</el-radio-button>
</el-radio-group>
</ElFormItem>
<ElFormItem label="数量">
<el-radio-group v-model="searchForm.multi">
<el-radio-button :value="false">单件</el-radio-button>
<el-radio-button :value="true">多件</el-radio-button>
</el-radio-group>
</ElFormItem>
<ElFormItem>
<ElPopover placement="bottom" width="600" trigger="click">
<ElForm
:model="searchForm"
size="default"
inline
label-width="100px"
>
<ElFormItem style="width: 100%; padding-right: 40px">
<div style="width: 100%; display: flex; flex-wrap: nowrap">
<el-select
v-model="searchForm.timeType"
clearable
:teleported="false"
placeholder="时间类型"
style="flex: 1; margin-right: 10px"
>
<el-option :value="1" label="创建时间"></el-option>
<el-option :value="2" label="确认时间"></el-option>
<el-option :value="3" label="完成时间"></el-option>
</el-select>
<el-date-picker
v-model="timeRange"
:teleported="false"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
placeholder="收货人"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
style="width: 280px"
:shortcuts="pickerOptions.shortcuts"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
>
</el-date-picker>
</div>
</ElFormItem>
<ElFormItem label="工艺">
<ElSelect
v-model="searchForm.craftCode"
clearable
filterable
placeholder="请输入工艺"
style="width: 150px"
>
<el-option
v-for="item in craftList"
:key="item.craftCode"
:label="item.craftName"
:value="item.craftCode"
></el-option>
</ElSelect>
</ElFormItem>
<ElFormItem label="款号">
<ElInput
v-model="searchForm.supplierProductNo"
placeholder="款号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="客户">
<el-select
v-model="searchForm.userMark"
clearable
filterable
:teleported="false"
style="width: 150px"
placeholder="客户"
>
<el-option
v-for="item in userMarkList"
:key="item"
:value="item"
:label="item"
></el-option>
</el-select>
</ElFormItem>
<ElFormItem label="批次号">
<ElInput
v-model="searchForm.batchArrangeNumber"
placeholder="批次号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="生产端">
<ElSelect
v-model="searchForm.productionClient"
placeholder="生产端"
clearable
:teleported="false"
style="width: 150px"
>
<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.thirdSkuCode"
placeholder="库存SKU"
clearable
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem label="Variant SKU">
<ElInput
v-model.trim="searchForm.sku"
placeholder="Variant SKU"
clearable
style="width: 150px"
></ElInput>
</ElFormItem>
<!-- <ElFormItem label="Base SKU">
<ElInput
v-model.trim="searchForm.baseSku"
placeholder=" Base SKU"
clearable
style="width: 150px"
></ElInput>
</ElFormItem> -->
</ElForm>
<template #reference>
<el-button
type="warning"
@click="searchVisible = !searchVisible"
>
<el-icon v-if="searchVisible">
<CaretTop />
</el-icon>
<el-icon v-else>
<CaretBottom />
</el-icon>
</el-button>
</template>
</ElPopover>
</ElFormItem>
<ElFormItem>
<span>
<ElButton link @click="resetSearchForm" style="font-size: 12px"
><span title="重置查询条件">重置</span></ElButton
>
</span>
</ElFormItem>
<ElFormItem>
<span>
<ElButton type="primary" @click="search">查询</ElButton>
</span>
</ElFormItem>
<ElFormItem>
<span>
<ElButton type="primary" @click="getOrderByIdApi('getPrintOrder')"
>获取打印面单</ElButton
>
</span>
</ElFormItem>
<ElFormItem>
<ElButton type="success" @click="exportData">导出</ElButton>
</ElFormItem>
</ElForm>
</el-card>
</template>
<template #bottom>
<el-card style="height: 100%">
<div class="manage">
<div class="table-flex">
<div class="top-table">
<div class="table-container">
<TableView
ref="tableRef"
:columns="tableColumns"
:serial-numberable="true"
:selectionable="true"
:paginated-data="tableData"
highlight-current-row
@row-click="rowClick"
@selection-change="handleSelectionChange"
>
<template #status="{ row }">
<div>{{ getStatus(row.status) }}</div>
</template>
<template #shipmentType="{ row }">
{{ ['自有物流', '工厂物流'][row.shipmentType] }}
</template>
</TableView>
</div>
<div class="pagination">
<el-pagination
size="small"
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"
/>
</div>
</div>
</div>
</div>
</el-card>
</template>
<template #other>
<div class="bottom-table">
<el-tabs>
<el-tab-pane label="商品明细">
<TableView
ref="goodsRef"
v-loading="goodsLoading"
:columns="goodsColumns"
:serial-numberable="true"
:paginated-data="goodsData"
>
<template #productImg="{ row }">
<ImageView :src="row.variantImage" width="30px" height="30px" />
</template>
</TableView>
</el-tab-pane>
<el-tab-pane label="操作日志" @tab-click="operationLog">
<div>
<el-button
:type="zoneType === 'Asia/Shanghai' ? 'primary' : ''"
size="small"
link
style="margin-left: 10px"
@click="changeChinaTime('Asia/Shanghai')"
>北京时间</el-button
>
<el-button
:type="zoneType === 'America/New_York' ? 'primary' : ''"
size="small"
link
style="margin-left: 10px"
@click="changeChinaTime('America/New_York')"
>新泽西时间</el-button
>
<el-button
:type="zoneType === 'America/Los_Angeles' ? 'primary' : ''"
size="small"
link
style="margin-left: 10px"
@click="changeChinaTime('America/Los_Angeles')"
>洛杉矶时间</el-button
>
</div>
<LogList
v-loading="logLoading"
:log-list="logList"
style="font-size: 14px; height: 100%"
/>
</el-tab-pane>
</el-tabs>
</div>
</template>
</split-div>
<ElDialog
v-model="exportVisible"
title="导出选项"
width="500px"
:close-on-click-modal="false"
>
<el-form :model="exportForm" label-width="80px">
<el-form-item label="" prop="resource">
<el-radio-group v-model="exportForm.resource">
<el-radio :label="0">导出本页</el-radio>
<el-radio :label="1">导出选中</el-radio>
<el-radio :label="2">全部</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="exportVisible = false">取消</el-button>
<el-button
:loading="exportLoading"
type="primary"
@click="submitExportForm"
>确认</el-button
>
</span>
</template>
</ElDialog>
<ResultInfo
ref="resultRefs"
:list="resultInfo"
@confirm="resultConfirm"
></ResultInfo>
</template>
<style scoped lang="scss">
::v-deep(.search-form) {
.el-form-item {
margin-bottom: 10px;
margin-right: 14px;
}
}
.el-card {
::v-deep(.el-card__body) {
padding: 10px;
padding-bottom: 0;
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;
flex-direction: column;
}
.right-table {
flex: 1;
margin-left: 10px;
flex-shrink: 0;
}
.top-table {
height: 100%;
display: flex;
width: 100%;
flex-direction: column;
.pagination {
display: flex;
margin: 10px 0;
justify-content: center;
}
.table-container {
flex: 1;
flex-shrink: 0;
overflow: hidden;
}
}
}
.bottom-table {
height: 100%;
background: white;
box-sizing: border-box;
padding: 10px;
::v-deep(.el-tabs) {
height: 100%;
display: flex;
.el-tabs__content {
flex: 1;
flex-shrink: 0;
.el-tab-pane {
height: 100%;
ul {
height: 100%;
}
}
}
}
}
</style>
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
{{ detail?.factorySubOrderNumber }} {{ detail?.factorySubOrderNumber }}
</p> </p>
</div> </div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item"> <div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<span>第三方生产单号</span> <span>第三方生产单号</span>
<p> <p>
{{ detail?.thirdSubOrderNumber }} {{ detail?.thirdSubOrderNumber }}
...@@ -392,8 +392,20 @@ watch( ...@@ -392,8 +392,20 @@ watch(
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId }, { url: d.negativeImage, title: '反面', id: d.negativeDesignId },
].filter((el) => el.url) ].filter((el) => el.url)
} else { } else {
arr = arr = Array.isArray(d.imageAry)
typeof d.imageAry == 'string' ? JSON.parse(d.imageAry) : d.imageAry ? d.imageAry
: typeof d.imageAry === 'string'
? (() => {
try {
const parsed = JSON.parse(d.imageAry)
return parsed
} catch {
return [{ url: d.imageAry }]
}
})()
: [d.imageAry]?.filter?.((v) => v != null) || []
// arr =
// typeof d.imageAry == 'string' ? JSON.parse(d.imageAry) : d.imageAry
arr = arr.concat([ arr = arr.concat([
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId }, { url: d.negativeImage, title: '反面', id: d.negativeDesignId },
]) ])
...@@ -579,7 +591,7 @@ const trackcodeInput = async () => { ...@@ -579,7 +591,7 @@ const trackcodeInput = async () => {
localStorage.setItem('historyData', JSON.stringify(historyData.value)) localStorage.setItem('historyData', JSON.stringify(historyData.value))
} }
const orderNumber = TrackingNumber.value let orderNumber = TrackingNumber.value
TrackingNumber.value = '' TrackingNumber.value = ''
if (props.type === 1) { if (props.type === 1) {
if (isAutoSure.value) { if (isAutoSure.value) {
...@@ -588,9 +600,17 @@ const trackcodeInput = async () => { ...@@ -588,9 +600,17 @@ const trackcodeInput = async () => {
} else { } else {
await setData(orderNumber) await setData(orderNumber)
} }
// AAAB_60527128-9_1_JMSC250121017 新版示例
const regex = /^[A-Z]{4}_/ //是否以四个大写字母加下划线开头
if (regex.test(orderNumber)) {
orderNumber =
orderNumber.split('_')[0] +
'-' +
orderNumber.split('_')[orderNumber.split('_').length - 1]
}
try { try {
const res = await getSubOrderBySubOrderNumber(orderNumber) const res = await getSubOrderBySubOrderNumber(orderNumber)
if(!res.data){ if (!res.data) {
return ElMessage.error('生产单不存在') return ElMessage.error('生产单不存在')
} }
const d = JSON.parse(JSON.stringify(res.data)) const d = JSON.parse(JSON.stringify(res.data))
...@@ -607,10 +627,28 @@ const trackcodeInput = async () => { ...@@ -607,10 +627,28 @@ const trackcodeInput = async () => {
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId }, { url: d.negativeImage, title: '反面', id: d.negativeDesignId },
].filter((el) => el.url) ].filter((el) => el.url)
} else { } else {
arr = typeof d.imageAry == 'string' ? JSON.parse(d.imageAry) : d.imageAry arr = Array.isArray(d.imageAry)
? d.imageAry
: typeof d.imageAry === 'string'
? (() => {
try {
const parsed = JSON.parse(d.imageAry)
return parsed
} catch {
return [{ url: d.imageAry }]
}
})()
: [d.imageAry]?.filter?.((v) => v != null) || []
// arr = typeof d.imageAry == 'string' ? JSON.parse(d.imageAry) : d.imageAry
arr = arr.concat([ arr = arr.concat([
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId }, { url: d.negativeImage, title: '反面', id: d.negativeDesignId },
]) ])
arr.forEach((item: { url: string; id: string; title: string }) => {
if (item.url && item.url.startsWith('/')) {
item.url = 'https://img.jomalls.com/upload/erp' + item.url
}
})
} }
const result = [] const result = []
arr = arr.filter((el: ImageItemInter) => el.url) arr = arr.filter((el: ImageItemInter) => el.url)
......
...@@ -47,6 +47,31 @@ ...@@ -47,6 +47,31 @@
></el-option> ></el-option>
</el-select> </el-select>
</ElFormItem> </ElFormItem>
<ElFormItem label="平台">
<ElSelect
v-model="searchForm.platform"
value-key=""
placeholder="请选择"
clearable
filterable
popper-class="customize-select-style"
style="width: 150px"
>
<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="SKU"> <ElFormItem label="SKU">
<ElInput <ElInput
v-model.trim="searchForm.sku" v-model.trim="searchForm.sku"
...@@ -125,71 +150,45 @@ ...@@ -125,71 +150,45 @@
<el-option value="multiple" label="多面"></el-option> <el-option value="multiple" label="多面"></el-option>
</el-select> </el-select>
</ElFormItem> </ElFormItem>
<ElFormItem> <ElFormItem>
<ElButton type="primary" @click="loadDiffList">查询</ElButton> <ElButton type="primary" @click="loadDiffList">查询</ElButton>
</ElFormItem> </ElFormItem>
</ElForm> <ElFormItem v-if="status === 'TO_BE_CONFIRMED'">
</div>
<div class="header-filter-tab">
<div class="tabs">
<div
v-for="item in tabsNav"
:key="item.status"
class="tabs-node"
:class="item.status === status ? 'tabs-node_active' : ''"
@click="changeTab(item)"
>
<span class="tabs-node_label">{{ item.statusName }}</span>
<span class="tabs-node_count">{{ `(${item.quantity})` }}</span>
</div>
</div>
</div>
<div class="order-content flex-1 flex-column overflow-hidden mt-10">
<div style="margin-bottom: 10px">
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="success" @click="confirmProduce">确认生产</ElButton> <ElButton type="success" @click="confirmProduce">确认生产</ElButton>
</span> </ElFormItem>
<span v-if="status === 'IN_PRODUCTION'" class="item"> <ElFormItem v-if="status === 'IN_PRODUCTION'">
<ElButton type="success" dark @click="fastToProduction('快捷生产', 1)" <ElButton type="success" dark @click="fastToProduction('快捷生产', 1)"
>快捷生产</ElButton >快捷生产</ElButton
> >
</span> </ElFormItem>
<span <ElFormItem
v-if=" v-if="
status === 'TO_BE_CONFIRMED' || ['TO_BE_CONFIRMED', 'IN_PRODUCTION', 'PART_SHIPPING'].includes(
status === 'IN_PRODUCTION' || status,
status === 'PART_SHIPPING' )
" "
class="item"
> >
<ElButton type="primary" dark @click="printManuscript" <ElButton type="primary" dark @click="printManuscript"
>打印生产单</ElButton >打印生产单</ElButton
> >
</span> </ElFormItem>
<!-- <span v-if="status === 'TO_BE_CONFIRMED'" class="item">--> <ElFormItem>
<!-- <ElButton type="success" dark @click="exportManuscript"-->
<!-- >导出生产单</ElButton-->
<!-- >-->
<!-- </span>-->
<span class="item">
<ElButton type="warning" @click="addInternalTag" <ElButton type="warning" @click="addInternalTag"
>添加内部标签</ElButton >添加内部标签</ElButton
> >
</span> </ElFormItem>
<span <ElFormItem
v-if=" v-if="
status === 'TO_BE_CONFIRMED' || ['TO_BE_CONFIRMED', 'IN_PRODUCTION', 'PART_SHIPPING'].includes(
status === 'IN_PRODUCTION' || status,
status === 'PART_SHIPPING' )
" "
class="item"
> >
<ElButton type="warning" is-dark @click="downloadMaterial"> <ElButton type="warning" is-dark @click="downloadMaterial">
下载素材</ElButton 下载素材</ElButton
> >
</span> </ElFormItem>
<span <ElFormItem
v-if=" v-if="
[ [
'TO_BE_CONFIRMED', 'TO_BE_CONFIRMED',
...@@ -198,38 +197,34 @@ ...@@ -198,38 +197,34 @@
'WAIT_SHIPMENT', 'WAIT_SHIPMENT',
].includes(status) ].includes(status)
" "
class="item"
> >
<ElButton type="primary" @click="refreshProduct" <ElButton type="primary" @click="refreshProduct"
>刷新商品信息</ElButton >刷新商品信息</ElButton
> >
</span> </ElFormItem>
<span <ElFormItem
v-if="status === 'WAIT_SHIPMENT' || status === 'PART_SHIPPING'" v-if="status === 'WAIT_SHIPMENT' || status === 'PART_SHIPPING'"
class="item"
> >
<ElButton type="success" @click="confirmDelivery">发货</ElButton> <ElButton type="success" @click="confirmDelivery">发货</ElButton>
</span> </ElFormItem>
<span v-if="status === 'WAIT_SHIPMENT'" class="item"> <ElFormItem v-if="status === 'WAIT_SHIPMENT'">
<ElButton type="warning" @click="completeDelivery">完成发货</ElButton> <ElButton type="warning" @click="completeDelivery">完成发货</ElButton>
</span> </ElFormItem>
<span <ElFormItem
v-if="['TO_BE_CONFIRMED', 'IN_PRODUCTION'].includes(status)" v-if="['TO_BE_CONFIRMED', 'IN_PRODUCTION'].includes(status)"
class="item"
> >
<ElButton type="danger" @click="voidedBtn">作废</ElButton> <ElButton type="danger" @click="voidedBtn">作废</ElButton>
</span> </ElFormItem>
<span <ElFormItem v-if="['WAIT_SHIPMENT', 'IN_PRODUCTION'].includes(status)">
v-if="['WAIT_SHIPMENT', 'IN_PRODUCTION'].includes(status)"
class="item"
>
<ElButton type="warning" is-dark @click="applyForReplacement"> <ElButton type="warning" is-dark @click="applyForReplacement">
申请补胚</ElButton 申请补胚</ElButton
> >
</span> </ElFormItem>
<span <ElFormItem v-if="['COMPLETE'].includes(status)">
<ElButton type="success" @click="toExport"> 导出对账单</ElButton>
</ElFormItem>
<ElFormItem
v-if="['TO_BE_CONFIRMED', 'IN_PRODUCTION'].includes(status)" v-if="['TO_BE_CONFIRMED', 'IN_PRODUCTION'].includes(status)"
class="item"
> >
<ElButton <ElButton
:loading="syncLoading" :loading="syncLoading"
...@@ -239,8 +234,24 @@ ...@@ -239,8 +234,24 @@
> >
同步素材图</ElButton 同步素材图</ElButton
> >
</span> </ElFormItem>
</ElForm>
</div>
<div class="header-filter-tab">
<div class="tabs">
<div
v-for="item in tabsNav"
:key="item.status"
class="tabs-node"
:class="item.status === status ? 'tabs-node_active' : ''"
@click="changeTab(item)"
>
<span class="tabs-node_label">{{ item.statusName }}</span>
<span class="tabs-node_count">{{ `(${item.quantity})` }}</span>
</div>
</div> </div>
</div>
<div class="order-content flex-1 flex-column overflow-hidden mt-10">
<template <template
v-if=" v-if="
[ [
...@@ -249,6 +260,7 @@ ...@@ -249,6 +260,7 @@
'WAIT_SHIPMENT', 'WAIT_SHIPMENT',
'TO_BE_REPLENISHMENT', 'TO_BE_REPLENISHMENT',
'INVALID', 'INVALID',
'INTERCEPTED',
].includes(status) ].includes(status)
" "
> >
...@@ -331,21 +343,42 @@ ...@@ -331,21 +343,42 @@
<img :src="item?.image" height="28" /> <img :src="item?.image" height="28" />
</div> </div>
</div> </div>
<b <div class="flex-row">
v-if="cardItem" <el-tooltip
:style="{ class="item"
color: effect="dark"
:content="'用户编码: ' + cardItem?.userMark"
placement="bottom"
>
<span
style="
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
display: inline-block;
"
@click.stop="copy(String(cardItem?.userMark || ''))"
>
{{ cardItem?.userMark }}
</span>
</el-tooltip>
<b
v-if="cardItem"
:style="{
color:
(Number(cardItem.customizedQuantity) || 0) > 1
? 'red'
: '#67C23A',
}"
>
{{
(Number(cardItem.customizedQuantity) || 0) > 1 (Number(cardItem.customizedQuantity) || 0) > 1
? 'red' ? '多'
: '#67C23A', : '单'
}" }}
> </b>
{{ </div>
(Number(cardItem.customizedQuantity) || 0) > 1
? '多'
: '单'
}}
</b>
</div> </div>
</template> </template>
<template #info> <template #info>
...@@ -355,11 +388,10 @@ ...@@ -355,11 +388,10 @@
<el-tooltip <el-tooltip
class="item" class="item"
effect="dark" effect="dark"
:content="cardItem?.baseSku" :content="'Base SKU: ' + cardItem?.baseSku"
placement="bottom" placement="bottom"
> >
<span <span
title="Base SKU"
style=" style="
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
...@@ -381,14 +413,14 @@ ...@@ -381,14 +413,14 @@
<el-tooltip <el-tooltip
class="item" class="item"
effect="dark" effect="dark"
:content="'补胚数量'" :content="
'补胚数量: ' + (cardItem?.replenishmentNum || '--')
"
placement="bottom" placement="bottom"
> >
<span <span
>补胚数量:{{ >补胚数量:{{ cardItem?.replenishmentNum || '--' }}
cardItem?.replenishmentNum || '--' </span>
}}</span
>
</el-tooltip> </el-tooltip>
</el-col> </el-col>
<el-col <el-col
...@@ -397,11 +429,16 @@ ...@@ -397,11 +429,16 @@
:offset="0" :offset="0"
style="text-align: right" style="text-align: right"
> >
<span <el-tooltip
v-if="['INVALID', 'TO_BE_CONFIRMED'].includes(status)" v-if="['INVALID', 'TO_BE_CONFIRMED'].includes(status)"
class="item"
effect="dark"
:content="'数量: ' + (cardItem?.num || '--')"
placement="bottom"
> >
数量:{{ cardItem?.num }} <span> 数量:{{ cardItem?.num }} </span>
</span> </el-tooltip>
<template v-else> <template v-else>
<el-tooltip <el-tooltip
v-if="status !== 'TO_BE_REPLENISHMENT'" v-if="status !== 'TO_BE_REPLENISHMENT'"
...@@ -411,8 +448,8 @@ ...@@ -411,8 +448,8 @@
['TO_BE_REPLENISHMENT', 'IN_PRODUCTION'].includes( ['TO_BE_REPLENISHMENT', 'IN_PRODUCTION'].includes(
status, status,
) )
? '未生产数量' ? '未生产数量: ' + cardItem?.notPassNum
: '已生产数量' : '已生产数量: ' + cardItem?.passNum
" "
placement="bottom" placement="bottom"
> >
...@@ -440,23 +477,31 @@ ...@@ -440,23 +477,31 @@
align-items: center; align-items: center;
" "
> >
<span <el-tooltip
title="Variant SKU" class="item"
style=" effect="dark"
display: inline-block; :content="'Variant SKU: ' + cardItem?.variantSku"
width: 100%; placement="bottom"
overflow: hidden;
text-overflow: ellipsis;
"
> >
{{ cardItem?.variantSku }} <span
</span> style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ cardItem?.variantSku }}
</span>
</el-tooltip>
</el-col> </el-col>
<el-col :span="10" :offset="0" style="text-align: right"> <el-col :span="10" :offset="0" style="text-align: right">
<el-tooltip <el-tooltip
class="item" class="item"
effect="dark" effect="dark"
:content="'货号'" :content="
'货号: ' + (cardItem?.supplierItemNo || '--')
"
placement="bottom" placement="bottom"
> >
<span <span
...@@ -475,35 +520,46 @@ ...@@ -475,35 +520,46 @@
align-items: center; align-items: center;
" "
> >
<span>工艺:</span> <el-tooltip
<span class="item"
:title="String(cardItem?.processName)" effect="dark"
style=" :content="'工艺: ' + (cardItem?.processName || '--')"
display: inline-block; placement="bottom"
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
> >
{{ cardItem?.processName }} <span
</span> style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ '工艺:' + (cardItem?.processName || '--') }}
</span>
</el-tooltip>
</el-col> </el-col>
<el-col <el-col
:span="12" :span="12"
:offset="0" :offset="0"
style="white-space: nowrap; text-align: right" style="white-space: nowrap; text-align: right"
> >
<span <el-tooltip
:title="`店铺单号:${cardItem?.shopNumber}`" class="item"
style=" effect="dark"
display: inline-block; :content="'店铺单号: ' + cardItem?.shopNumber"
width: 100%; placement="bottom"
overflow: hidden;
text-overflow: ellipsis;
"
> >
{{ cardItem?.shopNumber }} <span
</span> style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ cardItem?.shopNumber }}
</span>
</el-tooltip>
</el-col> </el-col>
</el-row> </el-row>
<el-row style="margin-top: 5px"> <el-row style="margin-top: 5px">
...@@ -512,29 +568,63 @@ ...@@ -512,29 +568,63 @@
:offset="0" :offset="0"
style="white-space: nowrap" style="white-space: nowrap"
> >
<span <el-tooltip
:title="`第三方生产单号:${cardItem?.thirdSubOrderNumber}`" class="item"
style=" effect="dark"
display: inline-block; :content="
width: 100%; '第三方生产单号: ' + cardItem?.thirdSubOrderNumber
overflow: hidden;
text-overflow: ellipsis;
"
@click.stop="
copy(String(cardItem?.thirdSubOrderNumber || ''))
" "
placement="bottom"
> >
{{ cardItem?.thirdSubOrderNumber }} <span
</span> style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
@click.stop="
copy(String(cardItem?.thirdSubOrderNumber || ''))
"
>
{{ cardItem?.thirdSubOrderNumber }}
</span>
</el-tooltip>
</el-col> </el-col>
<el-col :span="12" :offset="0" style="text-align: right"> <el-col
:span="12"
:offset="0"
style="white-space: nowrap; text-align: right"
>
<el-tooltip
class="item"
effect="dark"
:content="'批次号: ' + cardItem?.factoryOrderNumber"
placement="bottom"
>
<span
style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
@click.stop="
copy(String(cardItem?.factoryOrderNumber || ''))
"
>
{{ cardItem?.factoryOrderNumber }}
</span>
</el-tooltip>
</el-col>
<!-- <el-col :span="12" :offset="0" style="text-align: right">
<span v-if="!cardItem?.expectDeliveryTime" <span v-if="!cardItem?.expectDeliveryTime"
>期望交货时间:--</span >期望交货时间:--</span
> >
<span v-else title="期望交货时间"> <span v-else title="期望交货时间">
{{ cardItem?.expectDeliveryTime || '--' }} {{ cardItem?.expectDeliveryTime || '--' }}
</span> </span>
</el-col> </el-col> -->
</el-row> </el-row>
<el-row style="margin-top: 5px"> <el-row style="margin-top: 5px">
<el-col <el-col
...@@ -560,20 +650,28 @@ ...@@ -560,20 +650,28 @@
:offset="0" :offset="0"
style="white-space: nowrap; text-align: right" style="white-space: nowrap; text-align: right"
> >
<span <el-tooltip
:title="`第三方订单号:${cardItem?.thirdOrderNumber}`" class="item"
style=" effect="dark"
display: inline-block; :content="
width: 100%; '第三方订单号: ' + cardItem?.thirdOrderNumber
overflow: hidden;
text-overflow: ellipsis;
"
@click.stop="
copy(String(cardItem?.thirdOrderNumber || ''))
" "
placement="bottom"
> >
{{ cardItem?.thirdOrderNumber }} <span
</span> style="
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
"
@click.stop="
copy(String(cardItem?.thirdOrderNumber || ''))
"
>
{{ cardItem?.thirdOrderNumber }}
</span>
</el-tooltip>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
...@@ -958,6 +1056,50 @@ ...@@ -958,6 +1056,50 @@
</template> </template>
</el-dialog> </el-dialog>
<el-dialog <el-dialog
v-model="exportVisible"
title="导出对账单"
:close-on-click-modal="false"
width="500PX"
>
<div class="margin-top-20">
<ElForm
style="margin: 20px 0"
:model="shipForm"
label-width="120px"
size="small"
>
<ElRow :gutter="20">
<ElFormItem required label="实际交货时间">
<el-date-picker
v-model="exportTime"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
placeholder="实际交货时间"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
style="width: 280px"
:shortcuts="pickerOptions.shortcuts"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
>
</el-date-picker>
</ElFormItem>
</ElRow>
</ElForm>
</div>
<template #footer>
<div class="dialog-footer">
<el-button size="large" @click="exportVisible = false">取消 </el-button>
<el-button size="large" type="primary" @click="exportData"
>导出
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
v-model="logVisible" v-model="logVisible"
title="操作日志" title="操作日志"
width="1000px" width="1000px"
...@@ -1084,6 +1226,7 @@ import { ...@@ -1084,6 +1226,7 @@ import {
syncSubOrderDesignImages, syncSubOrderDesignImages,
applyForReplenishmentApi, applyForReplenishmentApi,
completeDeliveryApi, completeDeliveryApi,
exportStatementApi,
} from '@/api/podOrder' } from '@/api/podOrder'
import TableView from '@/components/TableView.vue' import TableView from '@/components/TableView.vue'
import { import {
...@@ -1127,6 +1270,7 @@ import { CustomColumn } from '@/types/table' ...@@ -1127,6 +1270,7 @@ import { CustomColumn } from '@/types/table'
import LogList from '@/components/LogList.vue' import LogList from '@/components/LogList.vue'
import CommonCard from '@/components/CommonCard.vue' import CommonCard from '@/components/CommonCard.vue'
import RightClickMenu from '@/components/RightClickMenu.vue' import RightClickMenu from '@/components/RightClickMenu.vue'
import platformJson from '../../../json/platform.json'
const tableRef = ref() const tableRef = ref()
const loading = ref(false) const loading = ref(false)
const currentPage = ref(1) const currentPage = ref(1)
...@@ -1336,7 +1480,20 @@ const openDetail = async (id: number) => { ...@@ -1336,7 +1480,20 @@ const openDetail = async (id: number) => {
const res = await getOrderDetail(id) const res = await getOrderDetail(id)
if (res.code == 200) { if (res.code == 200) {
if (res.data.imageAry) { if (res.data.imageAry) {
res.data.imageAry = JSON.parse(res.data.imageAry as string) const newarr = res.data.imageAry
res.data.imageAry = Array.isArray(newarr)
? newarr
: typeof newarr === 'string'
? (() => {
try {
const parsed = JSON.parse(newarr)
return parsed
} catch {
return [{ url: newarr }]
}
})()
: [newarr]?.filter?.((v) => v != null) || []
// res.data.imageAry = JSON.parse(res.data.imageAry as string)
} }
detailData.value = res.data || {} detailData.value = res.data || {}
detailVisible.value = true detailVisible.value = true
...@@ -1344,10 +1501,45 @@ const openDetail = async (id: number) => { ...@@ -1344,10 +1501,45 @@ const openDetail = async (id: number) => {
fastType.value = 0 fastType.value = 0
} }
} catch (e) { } catch (e) {
console.log(e)
//showError(e) //showError(e)
} }
} }
const shipForm = ref({})
const exportVisible = ref(false)
const exportTime = ref<string[]>([])
const toExport = () => {
exportVisible.value = true
exportTime.value = []
}
const exportData = async () => {
if (!exportTime.value || exportTime.value.length === 0) {
return ElMessage.warning('请选择时间')
}
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const params = {
startTime: exportTime.value[0],
endTime: exportTime.value[1],
...searchForm.value,
// tagIds: searchForm.value.tagIds.length > 0 ? searchForm.value.tagIds : null,
}
try {
const res = await exportStatementApi(params, status.value)
if (res.code !== 200) return
ElMessage.success('导出成功')
window.open(filePath + res.message)
exportVisible.value = false
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
const saveCompleteShipment = async () => { const saveCompleteShipment = async () => {
try { try {
await completeShipmentFormRef.value.validate() await completeShipmentFormRef.value.validate()
...@@ -1374,20 +1566,27 @@ const CardOrderList = ref<(PodProductList | CardOrderData)[]>([]) ...@@ -1374,20 +1566,27 @@ const CardOrderList = ref<(PodProductList | CardOrderData)[]>([])
const loadCardList = async () => { const loadCardList = async () => {
loading.value = true loading.value = true
try { try {
const params = {
...searchForm.value,
timeType: searchForm.value.timeType,
startTime:
timeRange.value && timeRange.value.length > 0
? timeRange.value[0]
: null,
endTime:
timeRange.value && timeRange.value.length > 0
? timeRange.value[1]
: null,
}
if (status.value === 'INTERCEPTED') {
params.interceptedStatus = true
} else {
params.status = status.value
}
const res = await getCardOrderList( const res = await getCardOrderList(
{ params,
...searchForm.value,
status: status.value,
timeType: searchForm.value.timeType,
startTime:
timeRange.value && timeRange.value.length > 0
? timeRange.value[0]
: null,
endTime:
timeRange.value && timeRange.value.length > 0
? timeRange.value[1]
: null,
},
currentPage.value, currentPage.value,
pageSize.value, pageSize.value,
) )
...@@ -1555,6 +1754,7 @@ const loadDiffList = async () => { ...@@ -1555,6 +1754,7 @@ const loadDiffList = async () => {
'TO_BE_REPLENISHMENT', 'TO_BE_REPLENISHMENT',
'TO_BE_CONFIRMED', 'TO_BE_CONFIRMED',
'INVALID', 'INVALID',
'INTERCEPTED',
].includes(status.value) ].includes(status.value)
) { ) {
await loadCardList() await loadCardList()
...@@ -1570,6 +1770,7 @@ const [searchForm] = useValue<SearchForm>({ ...@@ -1570,6 +1770,7 @@ const [searchForm] = useValue<SearchForm>({
userMark: '', userMark: '',
customizedQuantity: '', customizedQuantity: '',
order: 'desc', order: 'desc',
platform: '',
}) })
const tableColumns = computed<CustomColumn<CardOrderData[]>>(() => { const tableColumns = computed<CustomColumn<CardOrderData[]>>(() => {
return [ return [
...@@ -2317,6 +2518,13 @@ onBeforeUnmount(() => { ...@@ -2317,6 +2518,13 @@ onBeforeUnmount(() => {
font-size: 15px; font-size: 15px;
} }
} }
.flex-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 15px;
}
} }
} }
.no-data { .no-data {
......
...@@ -6,7 +6,12 @@ ...@@ -6,7 +6,12 @@
:fullscreen="true" :fullscreen="true"
:close-on-click-modal="false" :close-on-click-modal="false"
@opened="onOpened" @opened="onOpened"
@close="emit('close')" @close="
() => {
emit('onSuccess')
emit('close')
}
"
> >
<div class="detail-div"> <div class="detail-div">
<div class="detail-content"> <div class="detail-content">
...@@ -85,12 +90,26 @@ ...@@ -85,12 +90,26 @@
<p> <p>
{{ detail?.factorySubOrderNumber }} {{ detail?.factorySubOrderNumber }}
</p> </p>
<el-icon
v-if="detail?.factorySubOrderNumber"
class="icon"
@click="copy(detail?.factorySubOrderNumber || '')"
>
<DocumentCopy />
</el-icon>
</div> </div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item"> <div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<span>第三方生产单号</span> <span>第三方生产单号</span>
<p> <p>
{{ detail?.thirdSubOrderNumber }} {{ detail?.thirdSubOrderNumber }}
</p> </p>
<el-icon
v-if="detail?.thirdSubOrderNumber"
class="icon"
@click="copy(detail?.thirdSubOrderNumber || '')"
>
<DocumentCopy />
</el-icon>
</div> </div>
<div :title="String(detail?.craftName)" class="div-item"> <div :title="String(detail?.craftName)" class="div-item">
<span>生产工艺</span> <span>生产工艺</span>
...@@ -120,6 +139,13 @@ ...@@ -120,6 +139,13 @@
<div :title="detail?.shopNumber ?? ''" class="div-item"> <div :title="detail?.shopNumber ?? ''" class="div-item">
<span>店铺单号</span> <span>店铺单号</span>
<p>{{ detail?.shopNumber ?? '' }}</p> <p>{{ detail?.shopNumber ?? '' }}</p>
<el-icon
v-if="detail?.shopNumber"
class="icon"
@click="copy(detail?.shopNumber || '')"
>
<DocumentCopy />
</el-icon>
</div> </div>
<div :title="detail?.createTime" class="div-item"> <div :title="detail?.createTime" class="div-item">
...@@ -198,6 +224,8 @@ import { ...@@ -198,6 +224,8 @@ import {
getSubOrderBySubOrderNumber, getSubOrderBySubOrderNumber,
downloadMaterialApi, downloadMaterialApi,
} from '@/api/podUsOrder' } from '@/api/podUsOrder'
import { DocumentCopy } from '@element-plus/icons-vue'
import { cardImages, PodOrderRes } from '@/types/api/podUsOrder' import { cardImages, PodOrderRes } from '@/types/api/podUsOrder'
import { showConfirm } from '@/utils/ui' import { showConfirm } from '@/utils/ui'
import { filePath } from '@/api/axios' import { filePath } from '@/api/axios'
...@@ -313,22 +341,27 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => { ...@@ -313,22 +341,27 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
type: 'warning', type: 'warning',
}) })
.then(async () => { .then(async () => {
TrackingNumber.value = el.orderNumber try {
await trackCodeInput() TrackingNumber.value = el.orderNumber
await setData(el.orderNumber) await trackCodeInput()
ElMessage.success('生产完成')
if (len[i + 1]) { await setData(el.orderNumber)
confirmQuery(len, i + 1)
// ElMessage.success('生产完成')
} catch (error) {
console.log(777)
console.log(error)
removeFromHistory()
} finally {
if (len[i + 1]) {
confirmQuery(len, i + 1)
}
} }
}) })
.catch(() => { .catch(() => {
const index = historyData.value.findIndex( removeFromHistory()
(item: HistoryDataItem) => item.orderNumber === el.orderNumber,
)
if (index >= 0) {
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
if (len[i + 1]) { if (len[i + 1]) {
confirmQuery(len, i + 1) confirmQuery(len, i + 1)
} }
...@@ -336,6 +369,11 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => { ...@@ -336,6 +369,11 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
}) })
} }
const removeFromHistory = () => {
historyData.value = []
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
const changeStatus = async () => { const changeStatus = async () => {
if (!detail.value || Object.keys(detail.value).length <= 1) { if (!detail.value || Object.keys(detail.value).length <= 1) {
return ElMessage.warning('请扫码生产单号') return ElMessage.warning('请扫码生产单号')
...@@ -353,19 +391,46 @@ const setData = async (orderNumber: string) => { ...@@ -353,19 +391,46 @@ const setData = async (orderNumber: string) => {
try { try {
const id = detail.value.id const id = detail.value.id
const podJomallOrderUsId = detail.value.podJomallOrderUsId const podJomallOrderUsId = detail.value.podJomallOrderUsId
await productionQueryApi(id, podJomallOrderUsId) if (
detail.value?.num !== undefined &&
detail.value?.passNum !== undefined
) {
const { num, passNum } = detail.value
if (num == passNum) {
await showConfirm('该生产单已经完成生产,请勿重复生产', {
confirmButtonText: '确定',
type: 'warning',
})
TrackingNumber.value = ''
isDownloadImage.value = false
trackingNumberRef.value && trackingNumberRef.value.focus()
throw new Error()
} else if (num < passNum) {
await showConfirm(
`生产单号:${detail.value.factorySubOrderNumber} 已经重复生产${
passNum - num
}件,请检查!`,
{
confirmButtonText: '确定',
type: 'warning',
},
)
TrackingNumber.value = ''
isDownloadImage.value = false
trackingNumberRef.value && trackingNumberRef.value.focus()
throw new Error()
} else {
await productionQueryApi(id, podJomallOrderUsId)
ElMessage.success('生产完成')
}
}
console.log(999)
if (orderNumber) { if (orderNumber) {
const index = historyData.value.findIndex( removeFromHistory()
(el: HistoryDataItem) => el.orderNumber === orderNumber,
)
if (index >= 0) {
// 扫单完成删除
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
} }
emit('onSuccess')
playAudio('weight_success') playAudio('weight_success')
detail.value = { detail.value = {
id: -1, id: -1,
...@@ -377,13 +442,19 @@ const setData = async (orderNumber: string) => { ...@@ -377,13 +442,19 @@ const setData = async (orderNumber: string) => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
if (orderNumber) {
removeFromHistory()
}
detail.value = { detail.value = {
id: -1, id: -1,
podJomallOrderUsId: -1, podJomallOrderUsId: -1,
imgList: [] as cardImages[], imgList: [] as cardImages[],
} }
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
playAudio('weight_search_error') throw e
// playAudio('weight_search_error')
} }
} }
...@@ -453,29 +524,32 @@ const trackCodeInput = async () => { ...@@ -453,29 +524,32 @@ const trackCodeInput = async () => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
return return
} }
const item = historyData.value.find(
(el: HistoryDataItem) => el.orderNumber === TrackingNumber.value,
)
if (!item) {
// 记录扫单
historyData.value.push({
orderNumber: TrackingNumber.value,
finished: false,
})
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
const orderNumber = TrackingNumber.value const orderNumber = TrackingNumber.value
if (isAutoSure.value) { try {
await setData( if (isAutoSure.value) {
historyData.value[historyData.value.length - 1].orderNumber || '', await setData(
) historyData.value[historyData.value.length - 1]?.orderNumber || '',
)
}
} catch (error) {
console.log(error)
} }
// 记录扫单
historyData.value = [
{
orderNumber,
finished: false,
},
]
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
try { try {
const res = await getSubOrderBySubOrderNumber(orderNumber) const res = await getSubOrderBySubOrderNumber(orderNumber)
if (!res.data) { if (!res.data) {
removeFromHistory()
return ElMessage.error('生产单不存在') return ElMessage.error('生产单不存在')
} }
const d = JSON.parse(JSON.stringify(res.data)) const d = JSON.parse(JSON.stringify(res.data))
...@@ -496,11 +570,11 @@ const trackCodeInput = async () => { ...@@ -496,11 +570,11 @@ const trackCodeInput = async () => {
download() download()
} }
playAudio('weight_search_success') playAudio('weight_search_success')
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = '' TrackingNumber.value = ''
} catch (e) { } catch (e) {
console.error(e) console.error(549, e)
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = '' TrackingNumber.value = ''
} }
...@@ -508,6 +582,15 @@ const trackCodeInput = async () => { ...@@ -508,6 +582,15 @@ const trackCodeInput = async () => {
const onOpened = () => { const onOpened = () => {
trackingNumberRef.value && trackingNumberRef.value.focus() trackingNumberRef.value && trackingNumberRef.value.focus()
} }
const copy = (text: string) => {
try {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
} catch (err) {
console.error('复制失败:', err)
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sure-btn { .sure-btn {
......
<template>
<div>
<ElDialog
v-model="visible"
title="质检包装"
fullscreen
:close-on-click-modal="false"
:close-on-press-escape="false"
style="top: 60px"
center
modal-class="pod-make-order-dialog"
>
<div class="detail-div">
<div class="left">
<div class="left-images">
<div
class="imagBox"
v-for="(item, index) in detail?.imgList"
:key="index"
>
<div
v-show="item?.title && item?.url"
style="font-size: 30px; font-weight: 700; text-align: center"
>
{{ item?.title }}
</div>
<img :src="item.url" alt="" />
</div>
</div>
<div class="tips">
<div>第一次扫码:就绪</div>
<div>第二次扫码:完成</div>
<div>
单子为就绪状态,如果下一个单子状态为完成,则从就绪变为错误
</div>
</div>
</div>
<div class="right">
<div class="input">
<el-input
ref="trackingNumberRef"
v-model="TrackingNumber"
:placeholder="placeholderText"
style="margin-right: 10px"
clearable
@keydown.enter="trackCodeInput()"
></el-input>
<el-button type="primary" @click="trackCodeInput()">
查询
</el-button>
</div>
<div class="printerContent">
<div class="qr">
二维码:<span style="color: #ff0000">{{ 111 }}</span>
</div>
<el-form style="display: flex; gap: 10px">
<el-form-item label="打印机:" style="flex: 1">
<ElSelect
v-model="sheetPrinter"
placeholder="请选择打印机"
@change="handlePrinterChange"
>
<ElOption
v-for="item in printDeviceList"
:key="item"
:label="item"
:value="item"
/>
</ElSelect>
</el-form-item>
<el-form-item label="标签尺寸:" style="flex: 1">
<ElSelect
v-model="sheetPrinter"
placeholder="请选择标签尺寸"
@change="handlePrinterChange"
>
<ElOption
v-for="item in printDeviceList"
:key="item"
:label="item"
:value="item"
/>
</ElSelect>
</el-form-item>
</el-form>
<div class="canvas-container">
<canvas id="canvas" ref="canvas"></canvas>
</div>
</div>
<div class="printQueue">
<div style="font-size: 18px; font-weight: 700; margin-bottom: 10px">
打印队列
</div>
<ul>
<li
v-for="value in 10"
:key="value"
:style="{
color:
value == 1 ? `#006000` : value == 2 ? `#ff0000` : '#000',
}"
>
value
</li>
</ul>
</div>
</div>
</div></ElDialog
>
</div>
</template>
<script setup lang="ts">
import QRCode from 'qrcode'
const visible = ref(false)
const TrackingNumber = ref('')
const placeholderText = ref('扫描枪输入生产单号')
const sheetPrinter = ref('')
const printDeviceList = ref([])
const trackingNumberRef = ref()
const detail = ref({
imgList: [
{
title: 'A',
id: '',
url: 'https://pic3.zhimg.com/v2-e52354ffdbd94a8e0a7649eacd34a788_r.jpg?source=1940ef5c',
},
{
title: 'b',
id: '',
url: 'https://bpic.588ku.com/element_origin_min_pic/23/07/11/d32dabe266d10da8b21bd640a2e9b611.jpg!r650',
},
],
})
function trackCodeInput() {
QRCode.toCanvas(document.getElementById('canvas'), '11', function (error) {
if (error) console.error(error)
console.log('QR code generated!')
})
}
function handlePrinterChange() {}
function open() {
visible.value = true
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.detail-div {
display: flex;
height: 100%;
gap: 20px;
justify-content: space-between;
.left {
flex: 5;
display: flex;
flex-direction: column;
align-items: center;
.left-images {
flex: 1;
display: flex;
height: 100%;
gap: 10px;
.imagBox {
width: 50%;
}
}
.tips {
font-size: 25px;
color: #afafaf;
}
}
.right {
flex: 3;
gap: 20px;
flex-direction: column;
display: flex;
.input {
display: flex;
}
.printerContent {
flex: 6;
border: 1px solid #dcdfe6;
padding: 10px;
padding-bottom: 0;
.qr {
margin-bottom: 10px;
}
}
.printQueue {
flex: 5;
border: 1px solid #dcdfe6;
padding: 10px;
}
}
}
:deep() {
.el-dialog {
.el-dialog__header {
.el-dialog__title {
font-size: 30px !important;
font-weight: 700 !important;
}
}
}
}
.el-form-item {
margin-bottom: 0;
}
.canvas-container {
position: relative;
width: 100%;
height: calc(100% - 61px); /* 1:1 宽高比 */
}
#canvas {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: auto !important;
height: 100% !important;
}
</style>
<template> <template>
<ElDialog <ElDialog
v-model="visible" v-model="visible"
title="POD打单" title="播种墙配货"
fullscreen fullscreen
:close-on-click-modal="false" :close-on-click-modal="false"
:close-on-press-escape="false" :close-on-press-escape="false"
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
> >
<template #header> <template #header>
<div class="title"> <div class="title">
<span>POD打单</span> <span>播种墙配货</span>
<span v-if="socketConnect === 'online'" class="online">[在线]</span> <span v-if="socketConnect === 'online'" class="online">[在线]</span>
<span v-else class="offline">[离线]</span> <span v-else class="offline">[离线]</span>
</div> </div>
...@@ -72,10 +72,24 @@ ...@@ -72,10 +72,24 @@
<div class="basic-info-item"> <div class="basic-info-item">
<span>物流跟踪号:</span> <span>物流跟踪号:</span>
<span>{{ podOrderDetailsData?.trackingNumber }}</span> <span>{{ podOrderDetailsData?.trackingNumber }}</span>
<el-icon
v-if="podOrderDetailsData?.trackingNumber"
class="icon"
@click="copy(podOrderDetailsData?.trackingNumber || '')"
>
<DocumentCopy />
</el-icon>
</div> </div>
<div class="basic-info-item"> <div class="basic-info-item">
<span>店铺单号:</span> <span>店铺单号:</span>
<span>{{ podOrderDetailsData?.shopNumber }}</span> <span>{{ podOrderDetailsData?.shopNumber }}</span>
<el-icon
v-if="podOrderDetailsData?.shopNumber"
class="icon"
@click="copy(podOrderDetailsData?.shopNumber || '')"
>
<DocumentCopy />
</el-icon>
</div> </div>
<div class="basic-info-item"> <div class="basic-info-item">
<span>商品总数量:</span> <span>商品总数量:</span>
...@@ -97,7 +111,21 @@ ...@@ -97,7 +111,21 @@
<span>发货备注:</span> <span>发货备注:</span>
<span>{{ podOrderDetailsData?.remark }}</span> <span>{{ podOrderDetailsData?.remark }}</span>
</div> </div>
<div class="basic-info-item">
<span>订单号:</span>
<span>{{ podOrderDetailsData?.factoryOrderNumber }}</span>
<el-icon
v-if="podOrderDetailsData?.factoryOrderNumber"
class="icon"
@click="
copy((podOrderDetailsData.factoryOrderNumber as string) || '')
"
>
<DocumentCopy />
</el-icon>
</div>
</div> </div>
<div class="table-content"> <div class="table-content">
<TableView <TableView
ref="tableRef" ref="tableRef"
...@@ -105,10 +133,21 @@ ...@@ -105,10 +133,21 @@
:columns="podOrderDetailsColumns" :columns="podOrderDetailsColumns"
highlight-current-row highlight-current-row
@row-click="handleRowClick" @row-click="handleRowClick"
@current-change="handleCurrentChange"
> >
<template #image="{ row }"> <template #image="{ row }">
<img :src="row.variantImage" alt="" /> <div
style="display: flex; flex-wrap: nowrap"
v-if="row.previewImgs?.length"
>
<div
v-for="img in row.previewImgs"
:key="img"
@click.stop="handleCurrentChange(img.url)"
style="cursor: pointer; margin-right: 5px; flex: 1"
>
<img v-if="img.url" :src="img.url" alt="" />
</div>
</div>
</template> </template>
<template #verifyResult="{ row }"> <template #verifyResult="{ row }">
<el-icon <el-icon
...@@ -203,6 +242,8 @@ ...@@ -203,6 +242,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue' import { computed, nextTick, ref, watch } from 'vue'
import { DocumentCopy } from '@element-plus/icons-vue'
import useLodop from '@/utils/hooks/useLodop' import useLodop from '@/utils/hooks/useLodop'
import TableView from '@/components/TableView.vue' import TableView from '@/components/TableView.vue'
import type { WebSocketMessage } from '@/utils/websocket' import type { WebSocketMessage } from '@/utils/websocket'
...@@ -231,7 +272,12 @@ const props = defineProps<{ ...@@ -231,7 +272,12 @@ const props = defineProps<{
printOrder: (data: OrderData, callback: (status: boolean) => void) => void printOrder: (data: OrderData, callback: (status: boolean) => void) => void
warehouseList: WarehouseListData[] warehouseList: WarehouseListData[]
}>() }>()
const emit = defineEmits(['update:modelValue', 'set-printer', 'refresh']) const emit = defineEmits([
'update:modelValue',
'set-printer',
'refresh',
'set-warehouseId',
])
const visible = computed({ const visible = computed({
get() { get() {
return props.modelValue return props.modelValue
...@@ -243,23 +289,30 @@ const visible = computed({ ...@@ -243,23 +289,30 @@ const visible = computed({
const printDeviceList = ref<string[]>([]) const printDeviceList = ref<string[]>([])
const sheetPrinter = ref<string>('') const sheetPrinter = ref<string>('')
const productionOrder = ref<string>('') const productionOrder = ref<string>('')
const podOrderDetailsData = ref<OrderData>() const podOrderDetailsData = ref<OrderData>()
const podOrderDetailsColumns = computed(() => [ const podOrderDetailsColumns = computed(() => [
{ {
label: '图片', label: '图片',
prop: 'image', prop: 'image',
width: 60, width: 250,
slot: 'image', slot: 'image',
align: 'center', align: 'center',
fixed: 'left', fixed: 'left',
}, },
{ {
label: 'base SKU', label: '生产单号',
prop: 'baseSku', prop: 'podJomallUsNo',
width: 140, width: 150,
align: 'center', align: 'center',
}, },
// {
// label: 'base SKU',
// prop: 'baseSku',
// width: 140,
// align: 'center',
// },
{ {
label: 'variant SKU', label: 'variant SKU',
prop: 'variantSku', prop: 'variantSku',
...@@ -272,12 +325,6 @@ const podOrderDetailsColumns = computed(() => [ ...@@ -272,12 +325,6 @@ const podOrderDetailsColumns = computed(() => [
}, },
{ {
label: '生产单号',
prop: 'podJomallUsNo',
width: 150,
align: 'center',
},
{
label: '购买数量', label: '购买数量',
prop: 'purchaseNumber', prop: 'purchaseNumber',
width: 90, width: 90,
...@@ -312,6 +359,7 @@ watch(visible, async (value: boolean) => { ...@@ -312,6 +359,7 @@ watch(visible, async (value: boolean) => {
currentCode = '' currentCode = ''
warehouseId.value = props.warehouseList[0].id warehouseId.value = props.warehouseList[0].id
_warehouseId.value = props.warehouseList[0].id _warehouseId.value = props.warehouseList[0].id
if (userStore.user?.factory.id) { if (userStore.user?.factory.id) {
try { try {
await socket.init( await socket.init(
...@@ -333,6 +381,10 @@ watch(visible, async (value: boolean) => { ...@@ -333,6 +381,10 @@ watch(visible, async (value: boolean) => {
initOrderDetailBox() initOrderDetailBox()
initPrintDevice() initPrintDevice()
const locaclPrinter = localStorage.getItem('sheetPrinter')
const locaclWarehouseId = localStorage.getItem('locaclWarehouseId')
if (locaclPrinter) sheetPrinter.value = JSON.parse(locaclPrinter)
if (locaclWarehouseId) warehouseId.value = JSON.parse(locaclWarehouseId)
} else { } else {
if (userStore.user?.factory.id) { if (userStore.user?.factory.id) {
socket.send({ socket.send({
...@@ -346,7 +398,6 @@ watch(visible, async (value: boolean) => { ...@@ -346,7 +398,6 @@ watch(visible, async (value: boolean) => {
}) })
watch(boxIndex, (value: number | null) => { watch(boxIndex, (value: number | null) => {
if (value) { if (value) {
console.log('boxIndex', value, boxChange.value)
const bool = !boxChange.value const bool = !boxChange.value
boxChange.value = false boxChange.value = false
renderItemBox(bool) renderItemBox(bool)
...@@ -370,6 +421,17 @@ watch( ...@@ -370,6 +421,17 @@ watch(
}, },
{ deep: true }, { deep: true },
) )
watch(
() => podOrderDetailsData.value,
(val) => {
if (val && val.productList?.length)
val.productList.forEach((el) => {
if (!el.previewImgs) el.previewImgs = JSON.parse(el.imageAry)
})
},
{ deep: true },
)
const podBoxIndex = computed(() => orderStore.podBoxIndex) const podBoxIndex = computed(() => orderStore.podBoxIndex)
let renderLock = false let renderLock = false
...@@ -385,8 +447,12 @@ const renderItemBox = (bool: boolean) => { ...@@ -385,8 +447,12 @@ const renderItemBox = (bool: boolean) => {
if (renderLock) return if (renderLock) return
renderLock = true renderLock = true
let boxItem = podBoxList.value.find((item) => item.box === boxIndex.value) let boxItem = podBoxList.value.find((item) => item.box === boxIndex.value)
if (!boxItem) boxItem = { data: { productList: [] } } if (!boxItem) boxItem = { data: { productList: [] } }
const { data } = boxItem const { data } = boxItem
data?.productList?.forEach((el) => {
if (!el.previewImgs) el.previewImgs = JSON.parse(el.imageAry)
})
if (!data) { if (!data) {
renderLock = false renderLock = false
currentCode = '' currentCode = ''
...@@ -394,20 +460,30 @@ const renderItemBox = (bool: boolean) => { ...@@ -394,20 +460,30 @@ const renderItemBox = (bool: boolean) => {
return return
} }
const { productList = [] } = data const { productList = [] } = data
const pickingNumber = productList.reduce((prev, product) => { const pickingNumber = productList.reduce((prev, product) => {
return prev + (product.count || 0) return prev + (product.count || 0)
}, 0) }, 0)
data.pickingNumber = pickingNumber data.pickingNumber = pickingNumber
coverImage.value = productList[0].variantImage || '' // coverImage.value = productList[0].previewImgs?.[0]?.url || ''
for (const product of productList) { for (const product of productList) {
if (product.count === product.purchaseNumber) { if (product.count === product.purchaseNumber) {
product.power = true product.power = true
} }
} }
if (currentCode) { if (currentCode) {
const parts = currentCode.split('_')
currentCode =
parts.length > 3 && parts[3].startsWith('USPSC')
? parts[3]
: parts.length > 1
? parts[1]
: parts[0]
for (const product of productList) { for (const product of productList) {
if (product.podJomallUsNo === currentCode) { if (product.podJomallUsNo === currentCode) {
coverImage.value = product.variantImage || '' coverImage.value = product.previewImgs?.[0]?.url || ''
console.log(441, coverImage.value)
nextTick(() => { nextTick(() => {
tableRef.value?.setCurrentRow(product) tableRef.value?.setCurrentRow(product)
}) })
...@@ -416,7 +492,9 @@ const renderItemBox = (bool: boolean) => { ...@@ -416,7 +492,9 @@ const renderItemBox = (bool: boolean) => {
} }
currentCode = '' currentCode = ''
} }
podOrderDetailsData.value = data podOrderDetailsData.value = data
if (productList.every((item) => item.power)) { if (productList.every((item) => item.power)) {
print(data, false, () => { print(data, false, () => {
renderLock = false renderLock = false
...@@ -540,6 +618,8 @@ const getPackingData = async (code: string) => { ...@@ -540,6 +618,8 @@ const getPackingData = async (code: string) => {
return return
} }
const { box } = res.data const { box } = res.data
console.log('box', box)
if (box) { if (box) {
boxIndex.value = box boxIndex.value = box
} }
...@@ -630,13 +710,16 @@ const initOrderDetailBox = async () => { ...@@ -630,13 +710,16 @@ const initOrderDetailBox = async () => {
} }
return item return item
}) })
podOrderDetailsData.value = podOrderDetailsData.value =
boxList.find((item) => item.data)?.data || undefined boxList.find((item) => item.data)?.data || undefined
boxIndex.value = boxList.find((item) => item.data)?.box || null boxIndex.value = boxList.find((item) => item.data)?.box || null
podOrderDetailsData.value?.productList?.forEach((el) => {
if (!el.previewImgs) el.previewImgs = JSON.parse(el.imageAry)
})
coverImage.value = coverImage.value =
boxList.find((item) => item.data)?.data?.productList?.[0]?.variantImage || podOrderDetailsData.value?.productList?.[0]?.previewImgs?.[0].url || ''
''
if ( if (
podOrderDetailsData.value && podOrderDetailsData.value &&
podOrderDetailsData.value.pickingNumber === podOrderDetailsData.value.pickingNumber ===
...@@ -856,12 +939,14 @@ const clearAllBox = async () => { ...@@ -856,12 +939,14 @@ const clearAllBox = async () => {
console.error(error) console.error(error)
} }
} }
const handleRowClick = () => { const handleRowClick = (row: ProductList) => {
console.log(907, row)
coverImage.value = row.previewImgs?.[0]?.url || ''
productionOrderRef.value.focus() productionOrderRef.value.focus()
} }
const handleCurrentChange = (row: ProductList) => { const handleCurrentChange = (url: string) => {
if (row) { if (url) {
coverImage.value = row.variantImage || '' coverImage.value = url || ''
} }
} }
const warehouseId = ref<string | number>('') const warehouseId = ref<string | number>('')
...@@ -876,6 +961,7 @@ const handleWarehouseChange = (value: string | number) => { ...@@ -876,6 +961,7 @@ const handleWarehouseChange = (value: string | number) => {
}) })
} }
warehouseId.value = value warehouseId.value = value
emit('set-warehouseId', value)
socket.send({ socket.send({
code: 'STARTORDER', code: 'STARTORDER',
factoryNo: userStore.user?.factory.id, factoryNo: userStore.user?.factory.id,
...@@ -884,6 +970,15 @@ const handleWarehouseChange = (value: string | number) => { ...@@ -884,6 +970,15 @@ const handleWarehouseChange = (value: string | number) => {
_warehouseId.value = value _warehouseId.value = value
initOrderDetailBox() initOrderDetailBox()
} }
const copy = (text: string) => {
try {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
} catch (err) {
console.error('复制失败:', err)
}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
...@@ -1067,10 +1162,13 @@ const handleWarehouseChange = (value: string | number) => { ...@@ -1067,10 +1162,13 @@ const handleWarehouseChange = (value: string | number) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: calc(100% - 60px); height: calc(100% - 60px);
width: calc(100% - 40px);
margin-left: 0;
} }
.el-dialog__body { .el-dialog__body {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
display: flex;
} }
} }
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<el-dialog <el-dialog
title="处理结果" title="处理结果"
v-model="resultDialog" v-model="resultDialog"
width="600px" width="1200px"
:close-on-click-modal="false" :close-on-click-modal="false"
@closed="closedFn" @closed="closedFn"
> >
...@@ -33,8 +33,17 @@ ...@@ -33,8 +33,17 @@
<div style="margin: 15px 0"></div> <div style="margin: 15px 0"></div>
<el-checkbox-group v-model="selectedList" @change="checkChange"> <el-checkbox-group v-model="selectedList" @change="checkChange">
<div style="display: block" v-for="(item, index) in list" :key="index"> <div style="display: block" v-for="(item, index) in list" :key="index">
<el-checkbox :value="item"> <el-checkbox :value="item">
{{ '工厂订单号:' + item.factoryOrderNumber + ' ' + item.message }} <span
style="
display: inline-block;
width: 100%;
white-space: wrap;
line-height: 22px;
"
> <span>订单号:{{item.factoryOrderNumber}},</span>{{ item.message }}</span
>
</el-checkbox> </el-checkbox>
</div> </div>
</el-checkbox-group> </el-checkbox-group>
...@@ -131,16 +140,12 @@ function closedFn() { ...@@ -131,16 +140,12 @@ function closedFn() {
} }
// 监听弹窗状态 // 监听弹窗状态
// watch( watch(
// () => resultDialog.value, () => resultDialog.value,
// (v) => { (v) => {
// if (v) { console.log(v)
// console.log(127, props.list) },
)
// resultfilter(true)
// }
// },
// )
watch( watch(
() => props.list, () => props.list,
(v) => { (v) => {
......
<script setup lang="ts"> <script setup lang="ts">
import { defineModel } from 'vue' import { defineModel } from 'vue'
import { updateAddressApi } from '@/api/podUsOrder.ts' import { updateAddressApi } from '@/api/podUsOrder.ts'
import {AddressInfo} from '@/types/api/podUsOrder.ts' import { AddressInfo } from '@/types/api/podUsOrder.ts'
const emits = defineEmits(['success']) const emits = defineEmits(['success'])
defineProps<{ defineProps<{
...@@ -45,7 +45,7 @@ const submitForm = async () => { ...@@ -45,7 +45,7 @@ const submitForm = async () => {
visible.value = false visible.value = false
emits('success') emits('success')
await ElMessageBox.alert( await ElMessageBox.alert(
'请修改/刷新地址后取消物流重新创建物流订单、获取跟踪号、获取打印面单。', '请修改/刷新地址后取消物流或者更换物流在重新创建物流订单、获取跟踪号、获取打印面单',
'提示', '提示',
{ {
type: 'warning', type: 'warning',
...@@ -117,6 +117,8 @@ const submitForm = async () => { ...@@ -117,6 +117,8 @@ const submitForm = async () => {
v-model="form.receiverAddress1" v-model="form.receiverAddress1"
clearable clearable
placeholder="请输入地址1" placeholder="请输入地址1"
maxlength="50"
show-word-limit
/> />
</el-form-item> </el-form-item>
<el-form-item label="地址2" prop="receiverAddress2"> <el-form-item label="地址2" prop="receiverAddress2">
...@@ -124,6 +126,8 @@ const submitForm = async () => { ...@@ -124,6 +126,8 @@ const submitForm = async () => {
v-model="form.receiverAddress2" v-model="form.receiverAddress2"
clearable clearable
placeholder="请输入地址2" placeholder="请输入地址2"
maxlength="50"
show-word-limit
/> />
</el-form-item> </el-form-item>
<el-form-item label="邮政编码" prop="receiverPostCode"> <el-form-item label="邮政编码" prop="receiverPostCode">
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -79,32 +79,24 @@ ...@@ -79,32 +79,24 @@
<ElFormItem> <ElFormItem>
<ElButton @click="reset">重置</ElButton> <ElButton @click="reset">重置</ElButton>
</ElFormItem> </ElFormItem>
<ElFormItem v-if="nodeId === 15">
<el-button type="warning" @click="rejectOrder">
驳回
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="exportExcel">
导出</el-button
>
</ElFormItem>
<ElFormItem v-if="nodeId === 30">
<el-button type="danger" @click="auditOrder('archive')">
归档
</el-button>
</ElFormItem>
</ElForm> </ElForm>
</div> </div>
<div class="btn-list">
<!-- <el-button
v-if="nodeId === 10"
type="primary"
@click="confirmOrder()"
>
确认
</el-button> -->
<el-button
v-if="nodeId === 15"
type="warning"
@click="rejectOrder"
>
驳回
</el-button>
<el-button type="success" @click="exportExcel"> 导出</el-button>
<el-button
v-if="nodeId === 30"
type="danger"
@click="auditOrder('archive')"
>
归档
</el-button>
</div>
<div <div
class="delivery-note-content flex-1 flex-column overflow-hidden" class="delivery-note-content flex-1 flex-column overflow-hidden"
> >
...@@ -685,8 +677,8 @@ ...@@ -685,8 +677,8 @@
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
:total="detailPager.total" :total="detailPager.total"
style="margin: 10px auto 0; text-align: right" style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange" @size-change="handleDetailSizeChange"
@current-change="handleCurrentChange" @current-change="handleDetailCurrentChange"
></ElPagination> ></ElPagination>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="1" label="操作日志"> <el-tab-pane name="1" label="操作日志">
...@@ -994,6 +986,15 @@ const getSelectionsProperty = (property: keyof AccountStatementNote) => { ...@@ -994,6 +986,15 @@ const getSelectionsProperty = (property: keyof AccountStatementNote) => {
.join(',') .join(',')
} }
const handleDetailSizeChange = (size: number) => {
detailPager.value.rows = size
searchDetail()
}
const handleDetailCurrentChange = (size: number) => {
detailPager.value.page = size
searchDetail()
}
const nodeId = ref<number | string>(0) const nodeId = ref<number | string>(0)
const treeRef = ref<InstanceType<typeof ElTree>>() const treeRef = ref<InstanceType<typeof ElTree>>()
const { const {
...@@ -1196,8 +1197,8 @@ const submitPodPrice = async () => { ...@@ -1196,8 +1197,8 @@ const submitPodPrice = async () => {
try { try {
const res = await apiSetCraftData({ const res = await apiSetCraftData({
id: currentRow.value?.id, id: currentRow.value?.id,
craftTotalPrice:currentRow.value?.craft_total_amount, craftTotalPrice: currentRow.value?.craft_total_amount,
recNumber: currentRow.value?.rec_number, recNumber: currentRow.value?.rec_number,
craftPriceList: filteredList, craftPriceList: filteredList,
}) })
if (res.code !== 200) return if (res.code !== 200) return
......
<template>
<div class="h100">
<div class="wraper" @mouseout="closeShow">
<div class="image-box" :title="data.name">
<el-image
style="width: 100%; height: 100%"
:src="imageUrl"
fit="cover"
/>
<div
v-if="isShowHomeSku === 'bottom'"
class="app-btn-bottom"
style="width: 100%"
>
<transition>
<div
class="more_wrap"
style="max-width: 100%; overflow-x: auto; overflow-y: hidden"
>
<slot name="operations" />
</div>
</transition>
</div>
</div>
<div class="content">
<div class="colors_main">
<div class="colors_wrap">
<ul class="colors">
<li v-for="(val, index) in data.colorImageList" :key="index">
<img
style="display: block"
width="30"
loading="lazy"
height="30"
:src="val"
alt=""
@mouseenter.stop="setCurrentImg(val)"
/>
</li>
</ul>
</div>
</div>
<!-- <slot name="skuid" v-if="$slots.skuid"></slot> -->
<slot name="content">
<div
style="
display: flex;
align-items: center;
position: relative;
/* height: 24px; */
"
>
<slot name="product-name"></slot>
<slot name="price" />
<slot name="synthesizeStatus"></slot>
<slot name="level-time"></slot>
</div>
</slot>
<slot name="otherContent"></slot>
</div>
<slot name="extra" />
</div>
</div>
</template>
<script lang="ts" setup>
import {computed} from 'vue'
const props = defineProps({
// 控制一些元素显示与否
isStore: {
type: Boolean,
},
width: {
type: Number,
default: 300,
},
hasWidth: {
type: Boolean,
default: false,
},
isFormat: {
type: Boolean,
default: false,
},
smallWidth: {
type: Number,
default: 45,
},
isShowTag: {
type: Boolean,
default: false,
},
isShowHomeSku: {
type: [String, Boolean],
validator: (v) => v === "top" || v === "bottom" || !v,
},
isSkuImageList: {
type: Boolean,
},
isShowSkuId: {
type: Boolean,
default: true,
},
isShowTitle: {
type: Boolean,
default: false,
},
isShowLevel: {
type: Boolean,
default: true,
},
isShowStatus: {
type: Boolean,
default: true,
},
isShowSku: {
type: Boolean,
default: true,
},
isShowSales: {
type: Boolean,
default: true,
},
showSelectable: {
type: Boolean,
default: true,
},
openly: {
type: Number,
default: 1,
},
showOpenly: {
type: Boolean,
default: false,
},
proportion: {
type: Number,
default: 125,
},
data: {
type: Object,
default: () => ({ colorImageList: [] }),
},
selectIds: {
type: Array,
default: () => [],
},
activeFn: {
type: Function,
default: () => {},
},
index: {
type: Number,
default: null,
},
searchForm: {
type: Object,
default: () => {},
},
operational: {
type: Boolean,
default: true,
},
customTagList: {
type: Array,
default: () => [],
},
isCustom: {
type: Boolean,
default: () => false,
},
});
const emits = defineEmits(["setCurrentImg"]);
const imageUrl = computed(() => {
return props.data.img_url;
});
const setCurrentImg = (val: string) => {
if (!val) return;
emits("setCurrentImg", val);
};
const closeShow = () => {
if (!props.data.colorImageList.length) return;
emits("setCurrentImg", props.data.colorImageList[0]);
};
// edit(item) {
// this.$emit('showEdit', item)
// }
</script>
<style lang="scss" scoped>
.wraper {
position: relative;
border-radius: 12px 0px 0px 0px;
border: 1px solid #efefef;
background: #eeeeee;
overflow: hidden;
}
.wraper:hover {
border: 1px solid #4168ff;
}
.addtag {
display: none;
}
.wraper:hover .addtag {
display: block;
}
.sales_wrap {
padding-top: 5px;
height: 24px;
display: flex;
align-items: center;
}
.sales_wrap svg {
margin-bottom: 5px;
}
.sales {
flex: 1;
height: 24px;
margin-left: 5px;
line-height: 24px;
box-sizing: border-box;
background-position: left center;
background-size: contain;
background-repeat: no-repeat;
display: inline-block;
font-size: 14px;
vertical-align: bottom;
padding-top: 1px;
font-weight: bold;
text-align: center;
}
.high {
color: red;
font-weight: bold;
color: #444444;
background: linear-gradient(0deg, rgb(255, 255, 255) 0%, #dddddd 100%);
border-radius: 4px 4px 0 0;
position: relative;
}
.high::before {
position: absolute;
top: -11px;
right: 0;
left: 0;
text-align: center;
line-height: 20px;
font-size: 12px;
font-weight: normal;
}
.today.high::before {
content: "today";
}
.seven.high::before {
content: "seven";
}
.thirty.high::before {
content: "thirty";
}
.history.high::before {
content: "history";
}
.active-icon {
position: relative;
display: block;
width: 16px;
height: 16px;
border: 1px solid #cccccc;
box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.4) inset;
border-radius: 8px;
background: #fff;
}
.active-icon.active {
background: #4168ff;
position: relative;
border-color: #4168ff;
box-shadow: none;
font-size: 18px;
top: -1px;
left: -1px;
}
.active-icon.active::after {
position: absolute;
content: "";
top: 0px;
left: 4px;
width: 4px;
height: 8px;
border-width: 2px;
border-style: solid;
border-color: transparent #fff #fff transparent;
transform: rotate(45deg) scale(0.8);
}
.colors_main {
height: 40px;
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.colors_wrap {
height: 40px;
flex: 1;
overflow-x: auto;
overflow-y: hidden;
}
.colors {
white-space: nowrap;
display: flex;
}
.colors_wrap::-webkit-scrollbar {
height: 5px;
width: 5px;
}
.colors li {
border-right: 1px solid #fff;
width: 30px;
min-width: 30px;
height: 30px;
background: #ddd;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
margin-right: 5px;
border-radius: 5px;
overflow: hidden;
border: 1px solid #ddd;
box-sizing: border-box;
}
.colors li img {
object-fit: contain;
object-position: center;
}
.star {
display: inline-block;
width: 80px;
color: red;
padding-left: 2px;
}
.star span {
display: inline-block;
height: 14px;
width: 14px;
margin-right: 2px;
background-position: center;
background-size: contain;
// background-image: url('../../assets/icon/star-no.svg');
}
// .star span.active {
// background-image: url('../../assets/icon/star.svg');
// }
// .moneyall {
// background-image: url('../../assets/images/moneyall.png');
// }
// .moneyone {
// background-image: url('../../assets/images/moneyone.png');
// }
// .rmb {
// background-image: url('../../assets/images/rmb.png');
// }
.version {
display: block;
width: 18px;
height: 18px;
line-height: 14px;
font-size: 12px;
color: #fff;
padding: 0 0 3px 2px;
text-align: center;
box-sizing: border-box;
// background: no-repeat url('../../assets/images/supply/no-version.png');
}
.repeat {
display: inline-block;
height: 24px;
width: 24px;
border-radius: 12px;
font-size: 12px;
background: red;
line-height: 22px;
color: #fff;
text-align: center;
}
// .version.main {
// background-image: url('../../assets/images/supply/version.png');
// }
// .dollar {
// background-image: url('../../assets/images/supply/money.png');
// }
// .eidt_title {
// background-image: url('../../assets/images/edit001.png');
// }
// .edit_online {
// background-image: url('../../assets/images/plane.png');
// }
.scroll {
overflow: auto;
padding-top: 10px;
user-select: none;
border: 1px solid #ddd;
}
.empty.elements {
border: none;
}
.select-number {
position: absolute;
left: 5px;
top: 10px;
}
.left_mark {
position: absolute;
top: 5px;
left: 5px;
}
.right_check {
position: absolute;
top: 5px;
right: 5px;
display: flex;
}
.right_check > * {
display: block;
margin-bottom: 5px;
}
.app-btn-top {
position: relative;
height: 30px;
}
.app-btn-top > .more_wrap {
position: absolute;
right: 5px;
}
.image-box {
position: relative;
padding-top: 100%;
width: 100%;
.el-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.app-btn-bottom {
position: absolute;
bottom: 5px;
left: 0;
}
}
.log_btn {
height: 22px;
display: inline-block;
background: #ffffff;
margin-right: 5px;
padding: 0 8px;
font-size: 12px;
vertical-align: middle;
box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.2);
border-radius: 13px;
text-align: center;
cursor: pointer;
}
.edit {
vertical-align: middle;
}
.content {
padding: 5px 10px;
background: linear-gradient(
90deg,
rgba(228, 228, 228, 0.4) 0%,
rgba(255, 255, 255, 1) 100%
);
}
.wraper:hover .content {
background: linear-gradient(
90deg,
rgba(26, 125, 255, 0.404) 0%,
rgba(64, 158, 255, 0) 100%
);
}
.footer_wrap {
display: flex;
align-items: center;
padding: 5px 0px 0;
}
.more_wrap {
display: none;
height: 35px;
/* //display: flex; */
align-items: center;
}
.wraper:hover .more_wrap {
display: flex;
}
.more_wrap :deep(> img) {
margin-left: 6px;
cursor: pointer;
}
.more_wrap :deep(> img:hover) {
transform: scale(1.3);
}
.price {
color: rgba(181, 124, 91, 1);
font-size: 14px;
font-weight: bold;
}
.new {
display: block;
width: 43px;
height: 16px;
line-height: 14px;
background: #8fc31f;
text-align: center;
border-radius: 8px;
font-size: 12px;
font-family: Alibaba PuHuiTi;
font-weight: 400;
color: #ffffff;
}
.bottom-home-sku {
cursor: pointer;
display: flex;
align-items: center;
padding: 2px 5px 2px 0;
background: rgba(255, 255, 255, 0.5);
border-radius: 5px;
margin-right: 6px;
position: relative;
z-index: 1;
}
.bottom-home-sku span,
.top-home-sku span {
font-size: 14px;
vertical-align: top;
margin-left: 5px;
color: #222;
}
.more_wrap :deep(> .delete:hover),
.more_wrap :deep(> .download:hover) {
transform: scale(1.3);
}
.delete,
.download {
display: inline-block;
width: 20px;
height: 20px;
background: rgba(255, 0, 0, 0.678);
padding: 0 4px;
border-radius: 10px;
box-sizing: border-box;
}
.delete svg,
.download svg {
margin-top: -1px;
width: 12px;
height: 12px;
}
.product {
right: 66px;
background: #4168ff;
color: #ffffff;
padding: 0 8px 8px 8px;
border-radius: 18px;
}
.variants {
display: flex;
padding: 5px 0;
}
.variants + .variants {
border-top: 1px solid #ddd;
}
.variants .title {
width: 120px;
min-width: 110px;
color: #303133;
font-size: 14px;
font-weight: bold;
line-height: 20px;
}
.variants li {
display: inline-block;
position: relative;
width: 96px;
padding: 0 6px;
margin-left: 6px;
box-sizing: border-box;
border: 1px solid #dcdfe6;
background: #fff;
border-radius: 4px;
overflow: hidden;
white-space: nowrap;
font-weight: 500;
font-size: 12px;
line-height: 24px;
color: #606266;
cursor: pointer;
text-overflow: ellipsis;
padding-right: 10px;
}
.variants li.active {
border: 1px solid blue;
}
.variants li i {
position: absolute;
top: 7px;
right: 5px;
}
.value {
display: inline-block;
width: 150px;
text-align: left;
color: #000;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wraper:hover .store::after {
display: none;
}
.img_footer_cont {
position: absolute;
display: none;
right: 0;
bottom: 0;
left: 0;
padding-top: 50px;
background-image: linear-gradient(
to top,
rgba(255, 255, 255, 0.9),
rgba(255, 255, 255, 0)
);
}
.img_footer_cont .title {
min-height: 24px;
line-height: 24px;
font-size: 12px;
color: #222;
padding: 5px 8px 0;
}
.wraper:hover .img_footer_cont {
display: block;
}
.top-home-sku {
position: absolute;
bottom: 5px;
left: 5px;
z-index: 888;
display: flex;
align-items: center;
padding: 2px 5px;
background: hsla(0, 0%, 100%, 0.5);
border-radius: 5px;
}
.top-home-sku > span {
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
}
.openly {
top: 5px;
z-index: 3;
right: 5px;
position: absolute;
}
</style>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import cardWrapper from './cardWrapper.vue'
const queryParams = reactive({
name: "",
sku: "",
diy_sku: "",
print_type: "",
category_id: "",
});
const pager = reactive({
page:1,
size:100,
loading: false ,
count: 0,
lists: [] ,
extend: {}
})
const setCurrentImg = (item: any, val: string) => {
item.img_url = val;
};
const categoryTree = ref([])
const resetPage = () => {
}
</script>
<template>
<div class="product">
<el-card>
<el-form
ref="formRef"
class="searchForm"
label-width="80px"
:model="queryParams"
:inline="true"
>
<el-form-item label="商品名称">
<el-input
v-model="queryParams.name"
clearable
maxlength="40"
style="width: 150px"
show-word-limit
placeholder="请输入商品名称"
/>
</el-form-item>
<el-form-item label="SKU">
<el-input
v-model="queryParams.sku"
clearable
style="width: 150px"
placeholder="请输入sku"
/>
</el-form-item>
<el-form-item label="印花类型">
<el-select
v-model="queryParams.print_type"
style="width: 150px"
clearable
placeholder="请选择"
>
<el-option
v-for="(item, index) in ['满印', '局部印']"
:key="index"
:label="item"
:value="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="商品分类">
<el-cascader
ref="categoryCascader"
v-model="queryParams.category_id"
:options="categoryTree"
clearable
style="width: 150px"
:props="{
label: 'name',
value: 'id',
emitPath: false,
}"
:show-all-levels="false"
></el-cascader>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="product-list">
<el-card
style="flex: 1; flex-shrink: 0; overflow: hidden"
class="!border-none"
shadow="never"
>
<div
v-loading="pager.loading"
class="eltable"
element-loading-text="加载中..."
>
<div v-if="pager.lists.length > 0" id="shopline" class="card-mode">
<div
v-for="(item, index) in pager.lists"
:key="index"
class="card-item"
>
<card-wrapper
:data="item"
:index="index"
is-show-home-sku="bottom"
:is-sku-image-list="true"
:has-width="true"
:is-show-sku="false"
:is-show-sales="false"
:is-custom="true"
@set-current-img="(val) => setCurrentImg(item, val)"
>
<template #operations>
<!-- <img-->
<!-- title="操作日志"-->
<!-- width="24"-->
<!-- height="24"-->
<!-- src="@/assets/images/log.png"-->
<!-- alt=""-->
<!-- @click.stop="viewTheLog(item.id)"-->
<!-- />-->
<img
title="编辑"
width="24"
height="24"
src="@/assets/images/edit.png"
alt=""
@click.stop="editInfo(item, 'edit')"
/>
</template>
<template #price>
<span
style="margin: 0 5px"
class="price"
:title="'建议零售价' + item.sales_price"
>
{{ item.sales_price ? "¥" : ""
}}{{ item.sales_price }}&nbsp;
</span>
</template>
<template #level-time>
<div
class="create-time"
:title="`上架时间:${item.create_time}`"
>
<span>{{ item.create_time }}</span>
</div>
</template>
<template #synthesizeStatus>
<div title="印花状态" style="position: absolute; right: 0">
<el-tag :type="item.print_type == 0 ? '' : 'warning'">
{{ item.print_type == 0 ? "满印" : "局部印" }}
</el-tag>
</div>
</template>
<template #otherContent>
<div class="sds-keyid">
<div class="product-id" @click.stop="copy(item.id)">
<img
:title="'复制' + item.id"
width="20"
src="@/assets/images/id.png"
alt=""
/>
<span :title="item.id">
{{ item.id }}
</span>
</div>
<div class="product-sku" @click.stop="copy(item.sku)">
<span :title="item.sku">
{{ item.sku }}
</span>
</div>
</div>
</template>
</card-wrapper>
</div>
</div>
<div v-else class="empty">暂无数据</div>
</div>
<div class="flex justify-center mt-4">
<div
style="
display: flex;
align-items: center;
margin-left: 20px;
width: max-content;
"
>
<span>一行展示</span>
<el-input
v-model="rowNumber"
type="number"
style="width: 80px; margin: 0 10px"
placeholder="请输入"
clearable
@change="changeRowNumber"
/>
<span>条</span>
</div>
&emsp;&emsp;&emsp;
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
</div>
</div>
</template>
<style scoped lang="scss">
.product{
display: flex;
flex-direction: column;
height: 100%;
}
.searchForm{
::v-deep(.el-form-item){
margin-bottom: 0;
}
}
.justify-center{
display: flex;
justify-content: center;
}
.product-list{
flex: 1;
margin-top: 10px;
flex-shrink: 0;
::v-deep(.el-card){
height: 100%;
.el-card__body{
display: flex;
height: 100%;
flex-direction: column;
.eltable{
flex: 1;
flex-shrink: 0;
overflow: auto;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>
<template>
<div
class="user-page flex-column card h-100 overflow-hidden"
style="position: relative"
>
<div class="card-header">
<span>系统配置</span>
</div>
<div class="cardBox">
<div v-for="(item, index) in formList" style="width: 600px" :key="index">
<el-form
v-if="item.type === 'RIIN'"
class="form"
ref="formRef"
label-width="120"
:model="item"
>
<div class="formBox">
<el-form-item label="转至RIIN生产">
<el-switch
v-model="item.enable"
class="ml-2"
style="--el-switch-on-color: #42b983"
/>
</el-form-item>
<div class="formContent" v-if="item.enable">
<el-form-item
label="账号"
prop="appKey"
:rules="[{ required: true, message: '请输入RIIN账号' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appKey"
placeholder="请输入RIIN账号"
clearable
style="width: 100%"
/></el-form-item>
<el-form-item
label="App Secret"
prop="appSecret"
:rules="[{ required: true, message: '请输入App Secret' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appSecret"
placeholder="请输入App Secret"
clearable
style="width: 100%"
/></el-form-item>
</div>
</div>
<ElButton
class="btn"
color="#42b983"
@click="saveConfiguration(item, index)"
>保存配置</ElButton
>
</el-form>
<el-form
v-if="item.type === 'TRACK'"
class="form"
ref="formRef"
label-width="120"
:model="item"
>
<div class="formBox">
<el-form-item label="物流轨迹跟踪">
<el-switch
v-model="item.enable"
class="ml-2"
style="--el-switch-on-color: #42b983"
/>
</el-form-item>
<div class="formContent" v-if="item.enable">
<el-form-item
label="17Track账号"
prop="appKey"
:rules="[{ required: true, message: '请输入17Track账号' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appKey"
placeholder="请输入17Track账号"
clearable
style="width: 100%"
/></el-form-item>
<el-form-item
label="账号Token"
prop="token"
:rules="[{ required: true, message: '请输入账号Token' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.token"
placeholder="请输入账号Token"
clearable
style="width: 100%"
/></el-form-item>
</div>
</div>
<ElButton
class="btn"
color="#42b983"
@click="saveConfiguration(item, index)"
>保存配置</ElButton
>
</el-form>
</div>
</div>
<div class="logBox">
<div>操作日志</div>
<LogList :log-list="logList" style="font-size: 14px; height: 90%" />
</div>
</div>
</template>
<script setup lang="ts">
import {
addExternalAuthorisationApi,
getExternalAuthorisationListApi,
baseExternalAccountLogsApi,
} from '@/api/externalAuth'
import { ExternalAuthListData } from '@/types/api/externalAuth'
interface formType {
id?: number
enable?: boolean
appKey?: string
appSecret?: string
type?: string
}
const formRef = ref()
const logList = ref([])
async function saveConfiguration(item: formType, index: number) {
let loading
try {
await formRef.value[index]?.validate()
const params = { ...item }
const url = !params.id
? 'factory/baseExternalAccount/add'
: 'factory/baseExternalAccount/update'
loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const res = await addExternalAuthorisationApi(url, params)
console.log(res)
// ElMessage.success('保存配置成功')
await ElMessageBox.confirm('保存配置成功!!需重新登录才能生效', '提示', {
confirmButtonText: '确定',
showCancelButton: false,
type: 'success',
})
await getDetail()
handleClick()
} catch (error) {
console.log(error)
} finally {
loading?.close()
}
}
const formList = ref<ExternalAuthListData[]>([])
async function getDetail() {
let loading
try {
loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const res = await getExternalAuthorisationListApi({}, 1, 100)
const records = res.data.records || []
const newArr = records.filter((el) => el.type)
const typeSet = new Set(newArr.map((el) => el.type))
const hasRIIN = typeSet.has('RIIN')
const hasTRACK = typeSet.has('TRACK')
if (newArr.length === 0) {
formList.value = [{ type: 'RIIN' }, { type: 'TRACK' }]
} else {
const result = [...newArr]
if (!hasRIIN) result.push({ type: 'RIIN' })
if (!hasTRACK) result.push({ type: 'TRACK' })
formList.value = result
}
console.log('Form list:', formList.value)
} catch (error) {
console.error('Failed to get external authorizations:', error)
} finally {
loading?.close()
}
}
async function handleClick() {
try {
let ids = ''
const idList = formList.value.map((el) => el.id).filter((el) => el)
console.log(222, idList)
if (idList.length) {
ids = idList.join(',')
}
console.log(205, ids)
const res = await baseExternalAccountLogsApi({
ids,
})
logList.value = res.data
console.log(res)
} catch (error) {
console.log(error)
}
}
onMounted(async () => {
await getDetail()
handleClick()
})
</script>
<style lang="scss" scoped>
.card-header {
margin-left: 200px;
font-size: 30px;
margin-bottom: 20px;
}
:deep() {
.demo-tabs {
height: calc(100% - 60px);
}
.cardBox {
flex: 3;
overflow-y: scroll;
height: 100%;
.el-card__footer {
border: none !important;
}
.formBox {
width: 100%;
margin-bottom: 15px;
padding: 20px;
border: 1px solid #ebebeb;
border-radius: 8px;
&:last-child {
margin-bottom: 0;
}
.formContent {
padding: 20px;
background-color: #f9f9f9;
border-radius: 5px;
.el-form-item:last-child {
margin-bottom: 0 !important;
}
}
}
.btn {
color: #fff;
}
}
.logBox {
border-top: 1px solid #ebebeb;
padding-top: 10px;
height: 200px;
}
.form {
margin-bottom: 15px;
}
}
</style>
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
<div class="search-form"> <div class="search-form">
<ElForm <ElForm
:model="searchForm" :model="searchForm"
size="large"
inline inline
@submit.prevent @submit.prevent
@keyup.enter="search" @keyup.enter="search"
...@@ -59,12 +58,12 @@ ...@@ -59,12 +58,12 @@
></ElInput> ></ElInput>
</ElFormItem> --> </ElFormItem> -->
<ElFormItem> <ElFormItem>
<ElButton type="primary" size="large" @click="search" <ElButton type="primary" @click="search"
>查询</ElButton >查询</ElButton
> >
</ElFormItem> </ElFormItem>
<ElFormItem v-if="treeId === '201'"> <ElFormItem v-if="treeId === '201'">
<el-button size="large" type="danger" @click="reject" <el-button type="danger" @click="reject"
>驳回</el-button >驳回</el-button
> >
</ElFormItem> </ElFormItem>
......
...@@ -93,63 +93,53 @@ ...@@ -93,63 +93,53 @@
<ElFormItem> <ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton> <ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem> </ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="primary" @click="addDialog(1, null)">
新增
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="rejectedInRecord">
驳回
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="danger" @click="handleBatchDelete">
删除
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="handleExport">
导出
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="warning" @click="auditOrder('audit')">
审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="success" @click="auditOrder('submitAudit')">
提交审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="auditOrder('invalid')">
作废
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'COMPLETED'">
<el-button type="success" @click="auditOrder('archiving')">
归档
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="primary" @click="printProductTag">
打印库存SKU标签
</el-button>
</ElFormItem>
</ElForm> </ElForm>
</div> </div>
<div class="btn-list">
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="primary"
@click="addDialog(1, null)"
>
新增
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="rejectedInRecord"
>
驳回
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="danger"
@click="handleBatchDelete"
>
删除
</el-button>
<el-button type="success" @click="handleExport"> 导出 </el-button>
<el-button type="primary" @click="printProductTag">
打印库存SKU标签
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="warning"
@click="auditOrder('audit')"
>
审核
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="success"
@click="auditOrder('submitAudit')"
>
提交审核
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="auditOrder('invalid')"
>
作废
</el-button>
<el-button
v-if="nodeCode === 'COMPLETED'"
type="success"
@click="auditOrder('archiving')"
>
归档
</el-button>
</div>
<div <div
class="delivery-note-content flex-1 flex-column overflow-hidden" class="delivery-note-content flex-1 flex-column overflow-hidden"
> >
...@@ -321,7 +311,7 @@ ...@@ -321,7 +311,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn <ElTableColumn
...@@ -395,21 +385,17 @@ ...@@ -395,21 +385,17 @@
</div> </div>
<ElDialog <ElDialog
v-model="importDialogVisible" v-model="importDialogVisible"
title="导入" title="导入出库单"
width="500px" width="500px"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<div class="import-dialog"> <div class="import-dialog">
<div class="import-header">
<el-button type="primary" link @click="downloadTemplate">
<el-icon><Download /></el-icon>
下载模板
</el-button>
</div>
<div class="import-content"> <div class="import-content">
<UploadExcel <UploadExcel
v-model="importedFileUrl" v-model="importedFileUrl"
:import-type="'localAndXlsx'" :import-type="'localAndXlsx'"
:import-name="'出库单'"
:import-url="'/files/outboundOrder.xlsx'"
@imported="handleLocalImport" @imported="handleLocalImport"
/> />
</div> </div>
...@@ -500,7 +486,7 @@ ...@@ -500,7 +486,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn <ElTableColumn
...@@ -616,7 +602,7 @@ ...@@ -616,7 +602,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn <ElTableColumn
...@@ -748,7 +734,7 @@ ...@@ -748,7 +734,7 @@
<el-table-column <el-table-column
align="center" align="center"
prop="supplierItemNo" prop="supplierItemNo"
label="供应货号" label="号"
></el-table-column> ></el-table-column>
<el-table-column align="center" prop="number" label="打印数量"> <el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }"> <template #default="{ row }">
...@@ -797,7 +783,7 @@ ...@@ -797,7 +783,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTree } from 'element-plus' import { ElMessage, ElRadioGroup, ElTree } from 'element-plus'
import { CirclePlusFilled,Download } from '@element-plus/icons-vue' import { CirclePlusFilled } from '@element-plus/icons-vue'
import splitDiv from '@/components/splitDiv/splitDiv.vue' import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus' import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
...@@ -957,14 +943,6 @@ function getStartTime() { ...@@ -957,14 +943,6 @@ function getStartTime() {
const day = date.getDate() const day = date.getDate()
return `${year}-${month}-${day} 00:00:00` return `${year}-${month}-${day} 00:00:00`
} }
const downloadTemplate = () => {
const link = document.createElement('a')
link.href = '/files/outboundOrder.xlsx'
link.download = 'outboundOrder.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
const selectSku = ref('') const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>() const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({}) const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
...@@ -1171,9 +1149,9 @@ const handleLocalImport = async ({ ...@@ -1171,9 +1149,9 @@ const handleLocalImport = async ({
.filter((item) => item.warehouseSku) .filter((item) => item.warehouseSku)
if (importedData.length === 0) { if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的库存SKU'); ElMessage.warning('导入数据中没有有效的库存SKU')
importDialogVisible.value = false; importDialogVisible.value = false
return; return
} }
// 2. 提取导入的 SKU 列表 // 2. 提取导入的 SKU 列表
...@@ -1183,10 +1161,10 @@ const handleLocalImport = async ({ ...@@ -1183,10 +1161,10 @@ const handleLocalImport = async ({
const filteredSkusList = await batchAddCommodity(importedSkus) const filteredSkusList = await batchAddCommodity(importedSkus)
if (filteredSkusList.length === 0) { if (filteredSkusList.length === 0) {
ElMessage.warning('导入的库存SKU已存在或无效'); ElMessage.warning('导入的库存SKU已存在或无效')
importedFileUrl.value = path; importedFileUrl.value = path
importDialogVisible.value = false; importDialogVisible.value = false
return; return
} }
// 4. 将备注信息合并到获取到的商品列表中 // 4. 将备注信息合并到获取到的商品列表中
...@@ -1999,11 +1977,6 @@ $border: solid 1px #ddd; ...@@ -1999,11 +1977,6 @@ $border: solid 1px #ddd;
} }
.import-dialog { .import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content { .import-content {
padding-bottom: 20px; padding-bottom: 20px;
} }
......
...@@ -14,7 +14,6 @@ import { ...@@ -14,7 +14,6 @@ import {
importWarehouseLocation, importWarehouseLocation,
} from '@/api/warehouse.ts' } from '@/api/warehouse.ts'
const uploadExcelRef = ref() const uploadExcelRef = ref()
import { Download } from '@element-plus/icons-vue'
import { nextTick, ref } from 'vue' import { nextTick, ref } from 'vue'
import SplitDiv from '@/components/splitDiv/splitDiv.vue' import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import { filePath } from '@/api/axios.ts' import { filePath } from '@/api/axios.ts'
...@@ -55,14 +54,6 @@ const handleLocalImport = async ({ ...@@ -55,14 +54,6 @@ const handleLocalImport = async ({
importedFileUrl.value = '' importedFileUrl.value = ''
} }
} }
const downloadTemplate = () => {
const link = document.createElement('a')
link.href = '/files/warehouseLocationTemplate.xlsx'
link.download = 'warehouseLocationTemplate.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// const importLoading = ref(false) // const importLoading = ref(false)
const searchForm = ref({ const searchForm = ref({
warehouseId: '', warehouseId: '',
...@@ -490,24 +481,20 @@ getWarehouse() ...@@ -490,24 +481,20 @@ getWarehouse()
</el-card> </el-card>
</template> </template>
</split-div> </split-div>
<ElDialog <ElDialog
v-model="importDialogVisible" v-model="importDialogVisible"
title="导入" title="导入库位"
width="500px" width="500px"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<div class="import-dialog"> <div class="import-dialog">
<div class="import-header">
<el-button type="primary" link @click="downloadTemplate">
<el-icon><Download /></el-icon>
下载模板
</el-button>
</div>
<div class="import-content"> <div class="import-content">
<UploadExcel <UploadExcel
ref="uploadExcelRef" ref="uploadExcelRef"
v-model="importedFileUrl" v-model="importedFileUrl"
:import-type="'localAndUpload'" :import-type="'localAndUpload'"
:import-name="'库位'"
:import-url="'/files/warehouseLocationTemplate.xlsx'"
@imported="handleLocalImport" @imported="handleLocalImport"
/> />
</div> </div>
......
...@@ -93,63 +93,57 @@ ...@@ -93,63 +93,57 @@
<ElFormItem> <ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton> <ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem> </ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="primary" @click="addDialog(1, null)">
新增
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="rejectedInRecord">
驳回
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="danger" @click="handleBatchDelete">
删除
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="handleExport">
导出</el-button
>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="warning" @click="auditOrder('audit')">
审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="success" @click="auditOrder('submitAudit')">
提交审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="auditOrder('invalid')">
作废
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="primary" @click="printProductTag">
打印库存SKU标签
</el-button>
</ElFormItem>
<ElFormItem>
<el-button
v-if="nodeCode === 'COMPLETED'"
type="success"
@click="auditOrder('archiving')"
>
归档
</el-button>
</ElFormItem>
</ElForm> </ElForm>
</div> </div>
<div class="btn-list">
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="primary"
@click="addDialog(1, null)"
>
新增
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="rejectedInRecord"
>
驳回
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="danger"
@click="handleBatchDelete"
>
删除
</el-button>
<el-button type="success" @click="handleExport"> 导出</el-button>
<el-button type="primary" @click="printProductTag">
打印库存SKU标签
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="warning"
@click="auditOrder('audit')"
>
审核
</el-button>
<el-button
v-if="nodeCode === 'PENDING_SUBMIT'"
type="success"
@click="auditOrder('submitAudit')"
>
提交审核
</el-button>
<el-button
v-if="nodeCode === 'PENDING_AUDIT'"
type="danger"
@click="auditOrder('invalid')"
>
作废
</el-button>
<el-button
v-if="nodeCode === 'COMPLETED'"
type="success"
@click="auditOrder('archiving')"
>
归档
</el-button>
</div>
<div <div
class="delivery-note-content flex-1 flex-column overflow-hidden" class="delivery-note-content flex-1 flex-column overflow-hidden"
> >
...@@ -329,7 +323,7 @@ ...@@ -329,7 +323,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn <ElTableColumn
...@@ -427,21 +421,17 @@ ...@@ -427,21 +421,17 @@
</div> </div>
<ElDialog <ElDialog
v-model="importDialogVisible" v-model="importDialogVisible"
title="导入" title="导入入库单"
width="500px" width="500px"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<div class="import-dialog"> <div class="import-dialog">
<div class="import-header">
<el-button type="primary" link @click="downloadTemplate">
<el-icon><Download /></el-icon>
下载模板
</el-button>
</div>
<div class="import-content"> <div class="import-content">
<UploadExcel <UploadExcel
v-model="importedFileUrl" v-model="importedFileUrl"
:import-type="'localAndXlsx'" :import-type="'localAndXlsx'"
:import-name="'入库单'"
:import-url="'/files/warehousingEntry.xlsx'"
@imported="handleLocalImport" @imported="handleLocalImport"
/> />
</div> </div>
...@@ -532,7 +522,7 @@ ...@@ -532,7 +522,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn align="center" label="入库数量" prop="buyStored"> <ElTableColumn align="center" label="入库数量" prop="buyStored">
...@@ -646,7 +636,7 @@ ...@@ -646,7 +636,7 @@
<ElTableColumn <ElTableColumn
show-overflow-tooltip show-overflow-tooltip
align="center" align="center"
label="供应货号" label="号"
prop="productNo" prop="productNo"
/> />
<ElTableColumn <ElTableColumn
...@@ -778,7 +768,7 @@ ...@@ -778,7 +768,7 @@
<el-table-column <el-table-column
align="center" align="center"
prop="supplierItemNo" prop="supplierItemNo"
label="供应货号" label="号"
></el-table-column> ></el-table-column>
<el-table-column align="center" prop="number" label="打印数量"> <el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }"> <template #default="{ row }">
...@@ -827,7 +817,7 @@ ...@@ -827,7 +817,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ElMessage, ElRadioGroup, ElTree } from 'element-plus' import { ElMessage, ElRadioGroup, ElTree } from 'element-plus'
import { CirclePlusFilled, Download } from '@element-plus/icons-vue' import { CirclePlusFilled } from '@element-plus/icons-vue'
import splitDiv from '@/components/splitDiv/splitDiv.vue' import splitDiv from '@/components/splitDiv/splitDiv.vue'
import { ElTable } from 'element-plus' import { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
...@@ -987,14 +977,6 @@ function getStartTime() { ...@@ -987,14 +977,6 @@ function getStartTime() {
const day = date.getDate() const day = date.getDate()
return `${year}-${month}-${day} 00:00:00` return `${year}-${month}-${day} 00:00:00`
} }
const downloadTemplate = () => {
const link = document.createElement('a')
link.href = '/files/warehousingEntry.xlsx'
link.download = 'warehousingEntry.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
const selectSku = ref('') const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>() const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({}) const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
...@@ -1156,7 +1138,7 @@ const excelFieldMap: Record<string, keyof InterProductList> = { ...@@ -1156,7 +1138,7 @@ const excelFieldMap: Record<string, keyof InterProductList> = {
入库数量: 'buyStored', 入库数量: 'buyStored',
// '成本价(¥)': 'costPrice', // '成本价(¥)': 'costPrice',
// '总成本(¥)': 'totalPrice', // '总成本(¥)': 'totalPrice',
// 库位: 'locationCode', 库位编码: 'locationCode',
备注: 'remark', 备注: 'remark',
} }
...@@ -1201,6 +1183,7 @@ const handleLocalImport = async ({ ...@@ -1201,6 +1183,7 @@ const handleLocalImport = async ({
return obj return obj
}) })
.filter((item) => item.warehouseSku) .filter((item) => item.warehouseSku)
// console.log('@', importedData, data)
if (importedData.length === 0) { if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的商品SKU') ElMessage.warning('导入数据中没有有效的商品SKU')
importDialogVisible.value = false importDialogVisible.value = false
...@@ -1222,13 +1205,16 @@ const handleLocalImport = async ({ ...@@ -1222,13 +1205,16 @@ const handleLocalImport = async ({
const importedItem = importedData.find( const importedItem = importedData.find(
(item) => item.warehouseSku === skuItem.sku, (item) => item.warehouseSku === skuItem.sku,
) )
const target = locationList.value.find((item: InterProductList) => {
return item.locationCode == importedItem?.locationCode
})
return { return {
skuImage: skuItem.image, skuImage: skuItem.image,
warehouseSku: skuItem.sku, warehouseSku: skuItem.sku,
skuName: skuItem.skuName, skuName: skuItem.skuName,
productNo: skuItem.productNo, productNo: skuItem.productNo,
locationCode: skuItem.locationCode ?? '', locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null, locationId: skuItem.locationId || target?.locationId,
costPrice: skuItem.factoryPrice, costPrice: skuItem.factoryPrice,
buyStored: importedItem?.buyStored ?? null, buyStored: importedItem?.buyStored ?? null,
totalPrice: new BigNumber( totalPrice: new BigNumber(
...@@ -1535,6 +1521,7 @@ const addOtherCurrency = async () => { ...@@ -1535,6 +1521,7 @@ const addOtherCurrency = async () => {
ElMessage.error('请至少选择一条数据') ElMessage.error('请至少选择一条数据')
return return
} }
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
if (!arr[i].buyStored) { if (!arr[i].buyStored) {
ElMessage.error('请输入入库数量') ElMessage.error('请输入入库数量')
...@@ -1544,6 +1531,12 @@ const addOtherCurrency = async () => { ...@@ -1544,6 +1531,12 @@ const addOtherCurrency = async () => {
ElMessage.error('请选择库位') ElMessage.error('请选择库位')
return return
} }
const found = locationList.value.find(
(item: InterProductList) => item.locationId === arr[i].locationId,
)
if (!arr[i].locationCode) {
arr[i].locationCode = found ? found?.locationCode : ''
}
} }
if (!formId.value) { if (!formId.value) {
addSection() addSection()
...@@ -1554,7 +1547,7 @@ const addOtherCurrency = async () => { ...@@ -1554,7 +1547,7 @@ const addOtherCurrency = async () => {
const filterSkuData = computed(() => { const filterSkuData = computed(() => {
const skuList = otherPurchaseData.value.map((el) => el.warehouseSku) const skuList = otherPurchaseData.value.map((el) => el.warehouseSku)
console.log(skuList, skuData.value) // console.log(skuList, skuData.value)
return skuData.value.filter((el) => !skuList.includes(el.sku)) return skuData.value.filter((el) => !skuList.includes(el.sku))
}) })
const addSection = async () => { const addSection = async () => {
...@@ -1959,11 +1952,6 @@ $border: solid 1px #ddd; ...@@ -1959,11 +1952,6 @@ $border: solid 1px #ddd;
} }
.import-dialog { .import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content { .import-content {
padding-bottom: 20px; padding-bottom: 20px;
} }
......
...@@ -3,15 +3,20 @@ import { ...@@ -3,15 +3,20 @@ import {
factoryWarehouseInfo, factoryWarehouseInfo,
warehouseInfo, warehouseInfo,
warehouseInfoGetAll, warehouseInfoGetAll,
updateLocationApi,
updateProductNoApi,
updateCustomSkuApi,
LocationInfoGetAll,
getWarehouseInventoryInfo, getWarehouseInventoryInfo,
factoryLogWarehouseLog, factoryLogWarehouseLog,
LogListData, LogListData,
WarehouseWarning, WarehouseWarning,
factoryWarehouseInventoryPrint, factoryWarehouseInventoryPrint,
exportWarehouseInfo, exportWarehouseInfo,
loactionData,
} from '@/api/warehouse.ts' } from '@/api/warehouse.ts'
import { AnyObject } from '@/types/api/warehouse' import { AnyObject } from '@/types/api/warehouse'
import { ref } from 'vue' import { ref, computed } from 'vue'
import SplitDiv from '@/components/splitDiv/splitDiv.vue' import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import { filePath } from '@/api/axios.ts' import { filePath } from '@/api/axios.ts'
...@@ -39,6 +44,121 @@ const pagination = ref<factoryWarehouseInfo>({ ...@@ -39,6 +44,121 @@ const pagination = ref<factoryWarehouseInfo>({
currentPage: 1, currentPage: 1,
total: 0, total: 0,
}) })
const isSameWarehouse = computed(() => {
if (selections.value.length === 0) return false
const firstId = selections.value[0]?.warehouseId
return selections.value.every(
(item: WarehouseWarning) => item.warehouseId === firstId,
)
})
const modifyLocationDialog = ref(false)
const modifyProductNoDialog = ref(false)
const modifyCustomSkuDialog = ref(false)
/** 修改库位 */
const locationForm = ref({
warehouseId: '',
})
const submitLocationForm = async () => {
if (locationForm.value.warehouseId) {
const idList = selections.value.map((el: WarehouseWarning) => Number(el.id))
const res = await updateLocationApi({
idList: idList,
locationId: locationForm.value.warehouseId,
})
if (res.code == 200) {
modifyLocationDialog.value = false
ElMessage.success('修改成功')
getData()
}
} else {
ElMessage.warning('请选择库位')
}
}
const LocationList = ref<loactionData[]>([])
const modifyStorageLocation = async () => {
locationForm.value.warehouseId = ''
modifyLocationDialog.value = true
const { data } = await LocationInfoGetAll(selections.value[0]?.warehouseId)
LocationList.value = data
}
/** 修改款号 */
const productNoForm = ref({
productNo: '',
})
const productNoRules = {
productNo: [{ required: true, message: '款号不能为空', trigger: 'change' }],
}
const productNoFormRef = ref()
const modifyProductNo = async () => {
productNoForm.value.productNo = ''
productNoFormRef.value?.resetFields()
modifyProductNoDialog.value = true
}
const submitProductNoForm = async () => {
productNoFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const idList = selections.value.map((el: WarehouseWarning) => Number(el.id))
await updateProductNoApi({
idList: idList,
productNo: productNoForm.value.productNo,
})
.then(() => {
modifyProductNoDialog.value = false
ElMessage.success('修改成功')
getData()
})
.finally(() => {
loading.close()
})
})
}
/** 修改自定义SKU */
const customSkuForm = ref({
customSku: '',
})
const customSkuRules = {
customSku: [
{ required: true, message: '自定义SKU不能为空', trigger: 'change' },
],
}
const customSkuFormRef = ref()
const modifyCustomSku = async () => {
customSkuForm.value.customSku = selections.value[0].customSku || ''
customSkuFormRef.value?.resetFields()
modifyCustomSkuDialog.value = true
}
const submitCustomSkuForm = async () => {
customSkuFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const idList = selections.value.map((el: WarehouseWarning) => Number(el.id))
updateCustomSkuApi({
idList: idList,
customSku: customSkuForm.value.customSku,
})
.then(() => {
modifyCustomSkuDialog.value = false
ElMessage.success('修改成功')
getData()
})
.finally(() => {
loading.close()
})
})
}
const showPrintDialog = ref(false) const showPrintDialog = ref(false)
const exportLoading = ref(false) const exportLoading = ref(false)
const clickItem = (row: WarehouseWarning) => { const clickItem = (row: WarehouseWarning) => {
...@@ -204,7 +324,7 @@ getWarehouse() ...@@ -204,7 +324,7 @@ getWarehouse()
<el-table-column <el-table-column
align="center" align="center"
prop="productNo" prop="productNo"
label="供应货号 " label="号 "
></el-table-column> ></el-table-column>
<el-table-column align="center" prop="number" label="打印数量"> <el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }"> <template #default="{ row }">
...@@ -258,11 +378,11 @@ getWarehouse() ...@@ -258,11 +378,11 @@ getWarehouse()
clearable clearable
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="供应货号"> <el-form-item label="号">
<el-input <el-input
v-model="searchForm.productNo" v-model="searchForm.productNo"
style="width: 140px" style="width: 140px"
placeholder="请输入号" placeholder="请输入号"
clearable clearable
></el-input> ></el-input>
</el-form-item> </el-form-item>
...@@ -327,6 +447,30 @@ getWarehouse() ...@@ -327,6 +447,30 @@ getWarehouse()
>导出</el-button >导出</el-button
> >
</el-form-item> </el-form-item>
<el-form-item style="margin-top: 5px">
<el-button
type="warning"
:disabled="!isSameWarehouse"
@click="modifyStorageLocation"
>修改库位</el-button
>
</el-form-item>
<el-form-item style="margin-top: 5px">
<el-button
type="warning"
:disabled="!selections.length"
@click="modifyProductNo"
>修改款号
</el-button>
</el-form-item>
<el-form-item style="margin-top: 5px">
<el-button
type="warning"
:disabled="selections.length !== 1"
@click="modifyCustomSku"
>修改自定义sku</el-button
>
</el-form-item>
</el-form> </el-form>
</el-card> </el-card>
</template> </template>
...@@ -356,7 +500,7 @@ getWarehouse() ...@@ -356,7 +500,7 @@ getWarehouse()
align="center" align="center"
prop="warehouseName" prop="warehouseName"
label="图片" label="图片"
width="100" width="80"
> >
<template #default="scope"> <template #default="scope">
<el-image <el-image
...@@ -371,31 +515,37 @@ getWarehouse() ...@@ -371,31 +515,37 @@ getWarehouse()
align="center" align="center"
prop="warehouseName" prop="warehouseName"
label="仓库名称" label="仓库名称"
width="180" width="140"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="locationCode" prop="locationCode"
label="库位" label="库位"
width="160" width="100"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="warehouseSku" prop="warehouseSku"
label="库存SKU" label="库存SKU"
width="180" min-width="180"
></el-table-column>
<el-table-column
align="center"
prop="customSku"
label="自定义SKU"
min-width="180"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="skuName" prop="skuName"
label="商品名称" label="商品名称"
width="250" min-width="230"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="productNo" prop="productNo"
label="供应货号" label="号"
width="150" width="180"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
...@@ -406,32 +556,32 @@ getWarehouse() ...@@ -406,32 +556,32 @@ getWarehouse()
<el-table-column <el-table-column
align="center" align="center"
prop="price" prop="price"
label="商品成本价()" label="商品成本价($)"
width="160" width="140"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="usableInventory" prop="usableInventory"
label="可用数量" label="可用数量"
width="120" width="90"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="inventory" prop="inventory"
label="库存数量" label="库存数量"
width="120" width="90"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="occupyInventory" prop="occupyInventory"
label="占用数量" label="占用数量"
width="120" width="90"
></el-table-column> ></el-table-column>
<el-table-column <el-table-column
align="center" align="center"
prop="freezeInventory" prop="freezeInventory"
label="冻结数量" label="冻结数量"
width="120" width="90"
></el-table-column> ></el-table-column>
</el-table> </el-table>
</div> </div>
...@@ -475,6 +625,8 @@ getWarehouse() ...@@ -475,6 +625,8 @@ getWarehouse()
</div> </div>
</template> </template>
</split-div> </split-div>
<!-- 导出 -->
<ElDialog <ElDialog
v-model="exportVisible" v-model="exportVisible"
title="导出选项" title="导出选项"
...@@ -497,6 +649,100 @@ getWarehouse() ...@@ -497,6 +649,100 @@ getWarehouse()
</span> </span>
</template> </template>
</ElDialog> </ElDialog>
<!-- 修改库位 -->
<ElDialog
v-model="modifyLocationDialog"
title="修改库位"
width="500px"
:close-on-click-modal="false"
>
<el-form :model="locationForm" label-width="80px">
<el-form-item label="选择库位" prop="warehouseId">
<el-select
v-model="locationForm.warehouseId"
clearable
filterable
placeholder="请选择库位"
>
<el-option
v-for="item in LocationList"
:key="item.id"
:label="item.locationCode"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="modifyLocationDialog = false">取消</el-button>
<el-button type="primary" @click="submitLocationForm">确认</el-button>
</span>
</template>
</ElDialog>
<!-- 修改款号 -->
<ElDialog
v-model="modifyProductNoDialog"
title="修改款号"
width="500px"
:close-on-click-modal="false"
>
<el-form
ref="productNoFormRef"
:model="productNoForm"
:rules="productNoRules"
label-width="80px"
@submit.prevent
>
<el-form-item label="款号" prop="productNo">
<el-input
v-model="productNoForm.productNo"
style="width: 100%"
placeholder="请输入款号"
clearable
></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="modifyProductNoDialog = false">取消</el-button>
<el-button type="primary" @click="submitProductNoForm">确认</el-button>
</span>
</template>
</ElDialog>
<!-- 修改自定义sku -->
<ElDialog
v-model="modifyCustomSkuDialog"
title="修改自定义sku"
width="500px"
:close-on-click-modal="false"
>
<el-form
ref="customSkuFormRef"
:model="customSkuForm"
:rules="customSkuRules"
label-width="100px"
@submit.prevent
>
<el-form-item label="自定义sku" prop="customSku">
<el-input
v-model="customSkuForm.customSku"
style="width: 100%"
placeholder="请输入自定义sku"
clearable
></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="modifyCustomSkuDialog = false">取消</el-button>
<el-button type="primary" @click="submitCustomSkuForm">确认</el-button>
</span>
</template>
</ElDialog>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
......
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