Commit f047343b by wuqian
parents c3d44811 19a60471
......@@ -12,7 +12,8 @@
"rules": {
"vue/require-default-prop": "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" } }]
}
......@@ -32,7 +32,6 @@ declare module 'vue' {
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
......@@ -65,6 +64,7 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView']
Select: typeof import('./src/components/Form/Select.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']
'Switch ': typeof import('./src/components/Form/Switch .vue')['default']
TableView: typeof import('./src/components/TableView.vue')['default']
......
......@@ -18,7 +18,9 @@
"dayjs": "^1.11.13",
"element-plus": "^2.6.0",
"lodash-es": "^4.17.21",
"luxon": "^3.7.1",
"pinia": "^2.1.7",
"qrcode": "^1.5.4",
"splitpanes": "^3.1.5",
"vue": "^3.4.19",
"vue-dompurify-html": "^5.1.0",
......@@ -28,6 +30,8 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/luxon": "^3.7.1",
"@types/qrcode": "^1.5.5",
"@types/splitpanes": "^2.2.6",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
......
......@@ -60,6 +60,12 @@ export function getFilePath() {
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() {
if (location.protocol === 'https:') {
return 'wss://' + location.host
......@@ -68,5 +74,6 @@ export function getWsUrl() {
}
}
export const filePath = getFilePath()
export const FileCnPath = getFileCnPath()
export default axios
import { BaseRespData } from '@/types/api'
import axios from './axios'
import { LogisticsData } from '@/types/api/order'
import { LogisticBill } from '@/types/api/podMakeOrder'
import { userData } from '@/types/api/user'
import { VersionImageList } from '@/types/api/typesetting'
......@@ -12,9 +14,7 @@ export function getLogisticsCompanyList() {
}
// 获取客户
export function getUserMarkList() {
return axios.get<never, BaseRespData<string[]>>(
'dbDiyUser/getUserMarkList',
)
return axios.get<never, BaseRespData<string[]>>('dbDiyUser/getUserMarkList')
}
// 获取用户
......@@ -35,3 +35,17 @@ export function uploadFileApi(data: FormData) {
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'
import axios from './axios'
import { ExternalAuthListData } from '@/types/api/externalAuth'
export function getExternalAuthorisationListApi(
data: {
type: string
data?: {
type?: string
},
page: number,
pageSize: number,
page?: number,
pageSize?: number,
) {
return axios.post<never, BasePaginationData<ExternalAuthListData>>(
'factory/baseExternalAccount/list_page',
......@@ -36,6 +36,12 @@ export function deleteExternalAuthorisationApi(ids: string) {
`factory/baseExternalAccount/delete?ids=${ids}`,
)
}
export function baseExternalAccountLogsApi(params: { ids: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/baseExternalAccount/logs`,
{ params },
)
}
export function addExternalAuthorisationApi(
url: string,
data: ExternalAuthListData,
......
......@@ -144,6 +144,12 @@ export function getUniuniList() {
},
)
}
// 获取tictok物流承运商
export function getTiktokCarrier() {
return axios.get<never, BaseRespData<{ name: string; id: number }[]>>(
'logisticsWay/getTiktokShippingProvider',
)
}
/**
* @description 发货地址
......
......@@ -196,9 +196,9 @@ export function getPodJomallOrderByFactoryNumber(factoryOrderNumber: string) {
return axios.get<never, BaseRespData<OrderData>>(
'factory/podJomallOrder/getPodJomallOrderByFactoryNumber',
{
params:{
factoryOrderNumber
}
params: {
factoryOrderNumber,
},
},
)
}
......@@ -247,3 +247,9 @@ export function completeDeliveryApi(
{ 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 {
ProductionClient,
WarehouseListData,
LogisticsData,
ExportParams,
InterceptStateGroupData,
} from '@/types/api/podUsOrder'
import axios from './axios'
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[]) {
return axios.post<never, BaseRespData<never>>(
......@@ -37,12 +44,19 @@ export function getOrderTabData() {
'/factory/podJomallOrderUs/findStateGroupList',
)
}
// 拦截状态数量
export function getgetInterceptStateGroupList() {
return axios.get<never, BaseRespData<InterceptStateGroupData>>(
'factory/podJomallOrderUs/findInterceptStateGroupList',
)
}
export function getOrderList(
params: SearchForm,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<PodUsOrderListData[]>>(
return axios.post<never, BasePaginationData<PodUsOrderListData>>(
'/factory/podJomallOrderUs/list_page',
{
...params,
......@@ -332,7 +346,7 @@ export function createLogisticsOrderApi(params: {
)
}
// 创建物流
// 物流面单上传
export function uploadExpressSheet(params: {
trackingNumber: string
file: File
......@@ -341,7 +355,8 @@ export function uploadExpressSheet(params: {
'factory/podJomallOrderUs/uploadExpressSheet',
params,
)
} // 创建物流
}
// 更新物流信息确认
export function updateSelfLogistics(params: {
trackingNumber: string
expressSheet: string
......@@ -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>>(
`factory/podJomallOrderUs/composingDesignImages?type=${type}`,
data,
......@@ -443,3 +458,119 @@ export function getListCraftApi() {
`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 {
ILocation,
AnyObject,
InterProductList,
ExportInWarehouseInfo
ExportInWarehouseInfo,
} from '@/types/api/warehouse'
export interface LogListData {
createTime: string
......@@ -60,7 +60,18 @@ export interface factoryWarehouseInfo {
remark?: string
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 {
pageSize?: number
currentPage?: number
......@@ -120,6 +131,9 @@ export interface WarehouseWarning {
productNumber: string
number: string
locationName: string
warehouseId: string | number
customSku?: string
productNo?: string
}
export interface positionInfo {
......@@ -143,7 +157,12 @@ export interface positionFormInfo {
remark: string
status: number
}
export interface loactionData {
id?: number
warehouseId?: number | string
warehouseName?: string
locationCode?: number | string
}
interface WarehouseWarningData {
id: number
factoryId: number
......@@ -173,6 +192,28 @@ export function getFactoryLocation(data: factoryWarehouseInfo) {
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) {
return axios.post<never, BasePaginationData<positionInfo>>(
'factoryWarehouseInventory/inventory',
......@@ -240,6 +281,14 @@ export function warehouseInfoGetAll() {
'/factoryWarehouseInfo/getAll',
)
}
export function LocationInfoGetAll(wareHouseId?: string | number) {
return axios.get<never, BaseRespData<loactionData[]>>(
'/factoryWarehouseLocation/getByWareHouse',
{
params: { wareHouseId },
},
)
}
export function createWarehouseInventoryApi(data: WarehouseWarningData) {
return axios.post<never, BaseRespData<never>>(
......
......@@ -76,36 +76,40 @@ import type { TypesettingListData } from '../types/api/typesetting'
// 定义通用字段接口,用于处理动态属性
interface CommonFields {
[key: string]: unknown;
variantImage?: string;
mainImage?: string;
sku?: string;
productName?: string;
[key: string]: unknown
variantImage?: string
mainImage?: string
sku?: string
productName?: string
}
// 定义图片列表项接口
interface ImageListItem {
[key: string]: unknown;
imagePath?: string;
[key: string]: unknown
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 类型
interface Props {
cardItem: CardItem;
active?: boolean;
showSelectIcon?: boolean;
showSku?: boolean;
showProductInfo?: boolean;
showImageList?: boolean;
imageField?: string;
imageListField?: string;
imagePathField?: string;
cardItem: CardItem
active?: boolean
showSelectIcon?: boolean
showSku?: boolean
showProductInfo?: boolean
showImageList?: boolean
imageField?: string
imageListField?: string
imagePathField?: string
}
// 定义默认值
......@@ -122,45 +126,45 @@ const props = withDefaults(defineProps<Props>(), {
// 获取主图片源
const mainImageSrc = computed<string>(() => {
const item = props.cardItem as IndexableObject;
const item = props.cardItem as IndexableObject
// 使用索引访问避免联合类型的属性访问问题
if (
props.imageField === 'variantImage' &&
typeof item[props.imageField] === 'string'
) {
return item[props.imageField] as string;
return item[props.imageField] as string
}
if (
props.imageField === 'mainImage' &&
typeof item[props.imageField] === 'string'
) {
return item[props.imageField] as string;
return item[props.imageField] as string
}
// 默认返回空字符串
return '';
return ''
})
// 获取图片列表
const imageList = computed<ImageListItem[]>(() => {
const item = props.cardItem as IndexableObject;
const list = item[props.imageListField];
return Array.isArray(list) ? list as ImageListItem[] : [];
const item = props.cardItem as IndexableObject
const list = item[props.imageListField]
return Array.isArray(list) ? (list as ImageListItem[]) : []
})
// 判断是否有图片列表
const hasImageList = computed<boolean>(() => {
return imageList.value.length > 0;
return imageList.value.length > 0
})
// 获取图片列表项的图片路径
function getItemImagePath(item: IndexableObject): string {
return (item[props.imagePathField] as string) || '';
return (item[props.imagePathField] as string) || ''
}
const copy = (text: string) => {
navigator.clipboard.writeText(text);
ElMessage.success('复制成功');
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
}
</script>
......@@ -174,11 +178,16 @@ const copy = (text: string) => {
.commodity-card-image {
position: relative;
border: 1px solid #eee;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
.img_top_left {
position: absolute;
top: 5px;
left: 5px;
display: flex;
align-items: center;
gap: 4px;
}
.img_top_right {
......
<template>
<div class="log-list">
<div
v-for="l in logList"
:key="l.id"
class="log-item flex"
>
<div v-for="l in logList" :key="l.id" class="log-item flex">
<div class="log-item-icon">
<Icon name="a-2labadianji3x" />
</div>
<div class="log-item-time">
<span>{{ l.createTime }}</span>
<span>{{ l.local && `${l.local}:` }}{{ l.createTime }}</span>
</div>
<div v-if="l.employeeName" class="log-item-name">
<span>{{ l.employeeName }}</span>
......@@ -45,7 +41,7 @@ defineProps({
}
.log-item-time {
width: 140px;
// width: 220px;
}
.log-item-name {
......
......@@ -34,7 +34,11 @@
</el-sub-menu>
</template>
</el-menu>
<SideBar />
<div v-if="userInfo" class="user-info">
<span class="user-avatar" style="color: #fff; font-size: 14px">
工厂: {{ userInfo.factoryCode }}
</span>
<span class="user-avatar">
<el-icon><User /></el-icon>
</span>
......@@ -175,9 +179,15 @@ import {
import { useRoute, useRouter } from 'vue-router'
import Menu from '@/router/menu'
import userUserStore from '@/store/user'
import type { FormRules } from 'element-plus'
import { useValue } from '@/utils/hooks/useValue'
import { changePasswordApi } from '@/api/auth'
import { ElMessage } from 'element-plus'
import SideBar from './SideBar.vue'
interface MenuItem {
index: string
id: number
......@@ -530,4 +540,8 @@ onUnmounted(() => {
border: none !important;
}
}
.user-info {
display: flex;
align-items: center;
}
</style>
......@@ -198,15 +198,6 @@ export default defineComponent({
</div>
)}
<div style={{ display: 'flex', alignItems: 'center' }}>
{props.isSearchBtn && (
<ElButton
class="btn"
type="primary"
onClick={() => emit('search', searchForm.value)}
>
查询
</ElButton>
)}
{props.isResetBtn && (
<ElButton
class="btn"
......@@ -215,10 +206,23 @@ export default defineComponent({
// emit('update:modelValue', {})
emit('reset')
}}
link
>
重置
<span title="重置查询条件" style={{ fontSize: '12px' }}>
重置
</span>
</ElButton>
)}
{props.isSearchBtn && (
<ElButton
class="btn"
type="primary"
onClick={() => emit('search', searchForm.value)}
>
查询
</ElButton>
)}
{props.isAddBtn && (
<ElButton class="btn" type="success" onClick={() => emit('add')}>
新增
......
......@@ -5,14 +5,14 @@
:data="paginatedData"
border
:stripe="stripe"
v-bind="attrs"
header-align="center"
height="100%"
v-bind="attrs"
>
<ElTableColumn
v-if="selectionable"
type="selection"
width="50"
width="40"
fixed="left"
header-align="center"
align="center"
......@@ -21,7 +21,7 @@
v-if="serialNumberable"
label="序号"
type="index"
width="60"
width="55"
fixed="left"
header-align="center"
align="center"
......
......@@ -17,6 +17,10 @@
/>
<div class="custom-tip">
<span>请上传Excel文件(.xls 或 .xlsx)</span>
<div class="down-load" @click="downloadTemplate">
<el-icon><Download /></el-icon>
<span> 下载{{ importName }}模板</span>
</div>
</div>
</div>
<div v-if="fileList.length > 0">
......@@ -54,7 +58,12 @@ import {
computed,
defineExpose,
} 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 { uploadFileApi } from '@/api/common'
interface FileItem {
......@@ -64,6 +73,8 @@ interface FileItem {
const props = defineProps<{
modelValue: string
importType: string
importName: string
importUrl:string
}>()
const emit = defineEmits(['update:modelValue', 'imported'])
......@@ -149,7 +160,6 @@ const onFileChange = async (e: Event) => {
emit('imported', { path: file.name, data: jsonData })
fileList.value = [{ path: file.name, filename: file.name }]
value.value = file.name || ''
ElMessage.success('导入成功')
loading.value = false
}
reader.readAsBinaryString(file)
......@@ -189,7 +199,20 @@ const fileUpload = async (file: File) => {
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) => {
fileList.value.splice(idx, 1)
value.value = ''
......@@ -262,9 +285,17 @@ const removeFile = (idx: number) => {
display: flex;
align-items: center;
color: #666;
margin-top: 12px;
i {
margin-right: 6px;
padding-top: 15px;
.down-load {
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({
type: Boolean,
default: true,
},
otherAttrs: {
type: Object,
default: () => ({}),
},
},
emits: ['update:modelValue', 'checkbox-change', 'getCheckboxRecords'],
setup(props, { emit, attrs }) {
const tableRef = ref<VxeTableInstance | null>(null)
const tableData = ref<Record<string, unknown>[]>([])
const tableColumns = ref<TableColumn[]>([])
const editConfig = computed(() => {
return {
trigger: 'dblclick',
......@@ -139,10 +144,21 @@ export default defineComponent({
{...this.attrs}
>
{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) => (
<vxe-column
key={index}
......
......@@ -10,7 +10,7 @@ const props = defineProps({
type: String || Number,
},
otherSize: {
default: 20,
default: '20',
type: String || Number,
},
})
......@@ -19,7 +19,7 @@ const domSize = ref<string>('0')
function domResize() {
const father = document.getElementsByClassName('splitpanes')[0]
const top = document.getElementById('top')
if(top && father){
if (top && father) {
const v = ((top.clientHeight / father?.clientHeight) * 100).toFixed(2)
if (props.size === '') {
......@@ -28,9 +28,8 @@ function domResize() {
domSize.value = props.size
}
}
}
onUnmounted(()=>{
onUnmounted(() => {
window.removeEventListener('resize', domResize)
})
onMounted(() => {
......@@ -38,7 +37,7 @@ onMounted(() => {
domResize()
})
defineExpose({
domResize
domResize,
})
</script>
......@@ -48,7 +47,6 @@ defineExpose({
<div id="top">
<slot name="top"></slot>
</div>
</pane>
<pane style="flex: 1; flex-shrink: 0">
<div id="bottom">
......@@ -67,15 +65,15 @@ defineExpose({
#top {
height: fit-content;
}
#other-pane{
#other-pane {
height: 100%;
}
#bottom {
height: 100%;
}
#top, #bottom {
#top,
#bottom {
display: flex;
flex-direction: column;
}
......@@ -99,11 +97,11 @@ defineExpose({
transform: translate(-50%);
width: 30px;
height: 1px;
content: "";
content: '';
position: absolute;
top: 50%;
left: 50%;
transition: background-color .3s;
transition: background-color 0.3s;
}
&::after {
......@@ -112,11 +110,11 @@ defineExpose({
transform: translate(-50%);
width: 30px;
height: 1px;
content: "";
content: '';
position: absolute;
top: 50%;
left: 50%;
transition: background-color .3s;
transition: background-color 0.3s;
}
}
......
......@@ -7,13 +7,18 @@ import './styles/index.scss'
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
import { isPermissionBtn } from '@/utils/index'
// 确保在渲染用户提供的HTML内容时,不会执行任何潜在的恶意脚本,从而提高应用的安全性
import vueDomPurifyHTMLPlugin from 'vue-dompurify-html'
createApp(App)
const app = createApp(App)
app
.use(vueDomPurifyHTMLPlugin)
.use(router)
.use(store)
.use(VxeUITable)
.mount('#app')
app.config.globalProperties.$isPermissionBtn = isPermissionBtn
......@@ -74,6 +74,13 @@ const router = createRouter({
component: PodUsOrderList,
},
{
path: '/pod-us-order/orderTracking',
meta: {
title: 'POD(US)订单跟踪',
},
component: () => import('@/views/order/orderTracking/index.vue'),
},
{
path: '/pod-delivery-note/list',
meta: {
title: 'POD发货单',
......@@ -95,6 +102,28 @@ const router = createRouter({
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',
meta: {
title: '外部授权',
......@@ -228,82 +257,11 @@ const router = createRouter({
component: WarehousePosition,
},
{
path: '/logistics/logisticsMethod',
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',
path: '/setting/settingIndex',
meta: {
title: '运费试算',
title: '设置',
},
component: () => import('@/views/logistics/logisticsCalculate.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,
component: () => import('@/views/setting/settingIndex.vue'),
},
],
},
......
......@@ -117,6 +117,11 @@ const menu: MenuItem[] = [
id: 8,
label: 'POD订单(US)',
},
{
index: '/pod-us-order/orderTracking',
id: 8,
label: 'POD(US)订单跟踪',
},
],
},
......@@ -171,6 +176,11 @@ const menu: MenuItem[] = [
label: '用户管理',
},
{
index: '/system/downloadClient',
id: 4,
label: '下载生产客户端',
},
{
index: '/system/external-authorisation',
id: 5,
label: '外部授权',
......@@ -182,6 +192,11 @@ const menu: MenuItem[] = [
},
],
},
{
index: '/setting/settingIndex',
id: 7,
label: '设置',
},
// {
// 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', {
async login(data: LoginReq) {
try {
const resp = await loginApi(data)
console.log(33, resp)
this.setUser(resp.data.sysUser)
setToken(resp.data.token)
localStorage.setItem(
'baseExternalAccountTypes',
JSON.stringify(resp.data.sysUser.baseExternalAccountTypes),
)
router.push({ path: '/dashboard' })
} catch (error) {
// showError(error)
......
......@@ -24,6 +24,7 @@ export interface SysUser {
factoryCode: string
status: number
factory: Factory
baseExternalAccountTypes?: []
}
export interface Factory {
......@@ -36,4 +37,4 @@ export interface Factory {
goodsNumber: number
authorizeNumber: number
status: number
}
\ No newline at end of file
}
......@@ -16,4 +16,5 @@ export interface ExternalAuthListData {
token?: string
refreshToken?: string
refreshTokenFailureTime?: string
enable?: boolean
}
......@@ -200,6 +200,7 @@ export interface LogListData {
employeeName?: string
description?: string
createTime?: string
local?: string
}
export interface QaData {
......
......@@ -27,6 +27,7 @@ export interface OrderData {
printResult?: string
remark?: string
version?: number
factoryOrderNumber?: number | string
}
export interface ProductList {
......@@ -44,4 +45,24 @@ export interface ProductList {
power?: boolean
variantImage?: 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 {
endTime?: string | null
internalMemo?: string
productionFileId?: string
interceptedStatus?: boolean
platform?: string
}
export interface CardOrderData {
id: number
......
......@@ -3,29 +3,38 @@ export interface Tab {
statusName?: string
quantity?: number
}
export interface ExportParams extends SearchForm {
idList?: number[]
exportAll: boolean
status?: string
}
export interface SearchForm {
timeType: number | null
shopNumber: string
shipmentType: string
userMark: string
logisticsTracking: string
baseSku: string
factoryOrderNumber: string
sku: string
factorySubOrderNumber: string
status: string
customizedQuantity: string
multi: boolean | null
startTime: string | null
endTime: string | null
exceptionHandling: number | undefined
platform: string
productionClient: string
warehouseId: string | number
thirdSkuCode: string
supplierProductNo: string
batchArrangeNumber: string
craftCode: string
timeType?: number | null
shopNumber?: string
shipmentType?: string
userMark?: string
processNumber?: string
trackingNumber?: string
baseSku?: string
factoryOrderNumber?: string
sku?: string
factorySubOrderNumber?: string
status?: string
customizedQuantity?: string
multi?: boolean | null
startTime?: string | null
endTime?: string | null
exceptionHandling?: number | undefined
platform?: string
productionClient?: string
warehouseId?: string | number
thirdSkuCode?: string
supplierProductNo?: string
batchArrangeNumber?: string
craftCode?: string
thirdStockSku?: string
interceptStatus?: number | string
}
export interface PodUsOrderListData {
id: number
......@@ -56,7 +65,7 @@ export interface PodUsOrderListData {
paymentTime?: string
startStockingTime?: string
finishTime?: string
shipmentType?: string
shipmentType?: number
expressSheet?: string
trackingNumber?: string
processNumber?: string
......@@ -69,11 +78,14 @@ export interface PodUsOrderListData {
orderNumber?: string
logisticsWayId?: number | null
logisticsWayName?: string
url?: string | null
tiffUrl?: string | null
}
export interface ProductList {
id: number
podJomallOrderUsId: number
thirdSubOrderNumber?: string
thirdStockSku?: string
factorySubOrderNumber?: string
factoryCode?: string
productName?: string
......@@ -83,7 +95,10 @@ export interface ProductList {
templatePrice?: number
variantImage?: string
craftPrice?: number
craftCode?: string
platform?: string
imageAry?: string
previewImgs?: []
designImages?: string
categoryId?: number
categoryName?: string
......@@ -113,6 +128,7 @@ export interface ProductList {
supplierProductNo?: string | null
replenishmentSumNum?: number | null
batchArrangeNumber?: string | null
interceptStatus?: number | null
}
export interface cardImages {
title: string
......@@ -128,6 +144,7 @@ export interface LogListData {
description: string
deleteContent: string
createTime: string
local?: string
}
export interface ProductionClient {
code?: string
......@@ -187,3 +204,12 @@ export interface CraftListData {
craftName: string
craftCode: string
}
export interface InterceptStateGroupData {
shipment: {
[key: string]: number
}
production: {
[key: string]: number
}
}
......@@ -12,3 +12,7 @@ export function useValue<T extends object>(
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 { ElMessage } from 'element-plus'
import { DateTime } from 'luxon'
import usePermissionBtnStore from '@/store/permission'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function val<T>(data: T, key: string | ((data: T) => any)) {
if (typeof key === 'function') return key(data)
......@@ -20,3 +23,29 @@ export function copyText(text: string) {
document.body.removeChild(oInput)
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 @@
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</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>
</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
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
......
......@@ -20,7 +20,7 @@ import NavMenu from '@/components/NavMenu.vue'
.container {
flex: 1;
padding: 0 10px 10px;
padding: 0 50px 10px 10px;
background-color: #f6f6f6;
overflow: hidden;
}
......
......@@ -29,7 +29,7 @@ let timer: number | undefined
const second = ref(5)
const router = useRouter()
props.showBtn &&
(timer = setInterval(() => {
(timer = window.setInterval(() => {
if (second.value === 0) {
clearInterval(timer)
router.go(-1)
......
......@@ -21,6 +21,7 @@ const styles = {
display: 'flex',
padding: '10px',
justifyContent: 'flex-start',
flexWrap: 'wrap',
backgroundColor: '#efefef',
},
} as const
......
......@@ -43,6 +43,9 @@
align="center"
border="full"
@getCheckboxRecords="handleCheckboxRecords"
:otherAttrs="{
fixed: 'left',
}"
></CustomizeTable>
</div>
</div>
......@@ -58,7 +61,6 @@ import {
updateLogisticsZone,
deleteLogisticsZone,
importLogisticsZone,
exportExcelLogisticsZone,
getlogisticsWayAllList,
} from '@/api/logistics'
......@@ -217,7 +219,11 @@ async function getList(data?: {
logisticsIdList?: string[] | string
codePrefix?: string
}) {
loading.value = true
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const res = await getLogisticsZoneList({
...data,
......@@ -232,6 +238,7 @@ async function getList(data?: {
{
prop: 'zoneName',
label: '分区',
attrs: { 'min-width': '100px', fixed: 'left' },
},
]
const newConfig = []
......@@ -243,6 +250,7 @@ async function getList(data?: {
label: key,
attrs: {
'edit-render': {},
'min-width': '300px',
},
render: {
edit: ({
......@@ -296,7 +304,7 @@ async function getList(data?: {
} catch (error) {
console.log(error)
} finally {
loading.value = false
loading.close()
}
}
......@@ -387,13 +395,11 @@ function onBeforeUploadImage(file: File) {
*/
async function downloadExcel() {
try {
const res = await exportExcelLogisticsZone()
const blob = new Blob([res as unknown as BlobPart])
const filename = '物流分区模版.xlsx'
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = filename
link.href = '/files/logisticsZoning.xlsx'
link.download = '物流分区模版.xlsx'
link.click()
document.body.removeChild(link)
} catch (error) {
console.log(error)
}
......@@ -410,10 +416,11 @@ async function exportExcel(file: { file: File }) {
const res = await importLogisticsZone(formData)
if (res.code === 200) {
ElMessage.success('导入成功!')
getList(searchForm.value)
}
} catch (error) {
ElMessage.error('导入失败!')
} finally {
getList(searchForm.value)
}
}
......
......@@ -30,7 +30,13 @@ export default function useShipment(callback?: () => void) {
const shipmentLoading = ref(false)
const shipmentOrderRef = ref<ShipmentType>()
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
if (!code) {
isLock.value = false
......
import { getQaOrderBySubOrderNumber, qaFinishedApi } from '@/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 { computed, ref } from 'vue'
......@@ -45,9 +45,10 @@ export default function useQuarantine() {
return indexList
}
const searchQaByOrderNumber = () => {
const uid = shipmentUid.value
const code = qaCode.value
const code = qaCode.value.startsWith('GCSC')
? qaCode.value
: getLastSegment(qaCode.value)
if (!code) {
isLock.value = false
playAudio('picking_warning')
......@@ -83,7 +84,12 @@ export default function useQuarantine() {
// 查找是否已经存在
const row = sourceData.value.find(
(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) {
// 质检数量不能大于发货数量
......@@ -100,7 +106,10 @@ export default function useQuarantine() {
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 indexList = findAllIndex(code1)
......@@ -111,7 +120,6 @@ export default function useQuarantine() {
sourceData.value[i]['scansNum'] = scansNum + 1
}
})
} else {
if (row.shipmentNum !== scansNum) {
sourceData.value[index]['scansNum'] = scansNum + 1
......@@ -163,17 +171,32 @@ export default function useQuarantine() {
Number(e.shipmentNum || 0) ===
Number(e.passNum || 0) + Number(e.notPassNum || 0),
).length
const row = sourceData.value.find(item => {
return (uid === item.shipmentUid && (code1 === item.subOrderNumber || item.factorySubOrderNumber == code1)) || (!uid && (item.factorySubOrderNumber == code1 || item.subOrderNumber == code1))
const row = sourceData.value.find((item) => {
return (
(uid === item.shipmentUid &&
(code1 === item.subOrderNumber ||
item.factorySubOrderNumber == code1)) ||
(!uid &&
(item.factorySubOrderNumber == code1 ||
item.subOrderNumber == code1))
)
})
const index = sourceData.value.findIndex(item => {
return (uid === item.shipmentUid && (code1 === item.subOrderNumber || item.factorySubOrderNumber == code1)) || (!uid && (item.factorySubOrderNumber == code1 || item.subOrderNumber == code1))
const index = sourceData.value.findIndex((item) => {
return (
(uid === item.shipmentUid &&
(code1 === item.subOrderNumber ||
item.factorySubOrderNumber == code1)) ||
(!uid &&
(item.factorySubOrderNumber == code1 ||
item.subOrderNumber == code1))
)
})
if (row) {
// row.passNum += 1
currentRow.value = row
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()
isLock.value = false
......
import { getOrderBySubOrderNumber, saveOrder } from '@/api/order'
import { ICompareObjects, OrderData, ProductList, ShipmentForm, ShipmentOrderRes } from '@/types/api/order'
import { useValue } from '@/utils/hooks/useValue'
import {
ICompareObjects,
OrderData,
ProductList,
ShipmentForm,
ShipmentOrderRes,
} from '@/types/api/order'
import { useValue, getLastSegment } from '@/utils/hooks/useValue'
import { nextTick, ref } from 'vue'
import { ShipmentType } from '../Shipment.vue'
......@@ -24,7 +30,10 @@ export default function useShipment(callback?: () => void) {
const shipmentLoading = ref(false)
const shipmentOrderRef = ref<ShipmentType>()
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
if (!code) {
isLock.value = false
......@@ -98,8 +107,7 @@ export default function useShipment(callback?: () => void) {
ElMessageBox.confirm('不能加入,地址信息不一致!', '重要提示', {
confirmButtonText: '确定',
type: 'warning',
}).catch(() => {
})
}).catch(() => {})
} else {
canJoin(res.data, code)
}
......@@ -213,7 +221,7 @@ export default function useShipment(callback?: () => void) {
try {
const res = await saveOrder(data, shipmentForm.value)
fetch(res.message || '')
.then(response => {
.then((response) => {
// 确保响应是 OK
if (!response.ok) {
throw new Error('网络响应错误')
......@@ -221,14 +229,16 @@ export default function useShipment(callback?: () => void) {
// 返回图片的二进制数据(Blob)
return response.blob()
})
.then(blob => {
.then((blob) => {
const a = document.createElement('a')
a.href = window.URL.createObjectURL(blob)
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()
})
.catch(error => {
.catch((error) => {
console.error('下载图片时出错:', error)
})
ElMessage.success('发货成功')
......
......@@ -97,7 +97,7 @@
{{ detail?.factorySubOrderNumber }}
</p>
</div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<span>第三方生产单号</span>
<p>
{{ detail?.thirdSubOrderNumber }}
......@@ -392,8 +392,20 @@ watch(
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId },
].filter((el) => el.url)
} 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([
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId },
])
......@@ -579,7 +591,7 @@ const trackcodeInput = async () => {
localStorage.setItem('historyData', JSON.stringify(historyData.value))
}
const orderNumber = TrackingNumber.value
let orderNumber = TrackingNumber.value
TrackingNumber.value = ''
if (props.type === 1) {
if (isAutoSure.value) {
......@@ -588,9 +600,17 @@ const trackcodeInput = async () => {
} else {
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 {
const res = await getSubOrderBySubOrderNumber(orderNumber)
if(!res.data){
if (!res.data) {
return ElMessage.error('生产单不存在')
}
const d = JSON.parse(JSON.stringify(res.data))
......@@ -607,10 +627,28 @@ const trackcodeInput = async () => {
{ url: d.negativeImage, title: '反面', id: d.negativeDesignId },
].filter((el) => el.url)
} 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([
{ 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 = []
arr = arr.filter((el: ImageItemInter) => el.url)
......
......@@ -6,7 +6,12 @@
:fullscreen="true"
:close-on-click-modal="false"
@opened="onOpened"
@close="emit('close')"
@close="
() => {
emit('onSuccess')
emit('close')
}
"
>
<div class="detail-div">
<div class="detail-content">
......@@ -85,12 +90,26 @@
<p>
{{ detail?.factorySubOrderNumber }}
</p>
<el-icon
v-if="detail?.factorySubOrderNumber"
class="icon"
@click="copy(detail?.factorySubOrderNumber || '')"
>
<DocumentCopy />
</el-icon>
</div>
<div :title="detail?.thirdSubOrderNumber || ''" class="div-item">
<span>第三方生产单号</span>
<p>
{{ detail?.thirdSubOrderNumber }}
</p>
<el-icon
v-if="detail?.thirdSubOrderNumber"
class="icon"
@click="copy(detail?.thirdSubOrderNumber || '')"
>
<DocumentCopy />
</el-icon>
</div>
<div :title="String(detail?.craftName)" class="div-item">
<span>生产工艺</span>
......@@ -120,6 +139,13 @@
<div :title="detail?.shopNumber ?? ''" class="div-item">
<span>店铺单号</span>
<p>{{ detail?.shopNumber ?? '' }}</p>
<el-icon
v-if="detail?.shopNumber"
class="icon"
@click="copy(detail?.shopNumber || '')"
>
<DocumentCopy />
</el-icon>
</div>
<div :title="detail?.createTime" class="div-item">
......@@ -198,6 +224,8 @@ import {
getSubOrderBySubOrderNumber,
downloadMaterialApi,
} from '@/api/podUsOrder'
import { DocumentCopy } from '@element-plus/icons-vue'
import { cardImages, PodOrderRes } from '@/types/api/podUsOrder'
import { showConfirm } from '@/utils/ui'
import { filePath } from '@/api/axios'
......@@ -313,22 +341,27 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
type: 'warning',
})
.then(async () => {
TrackingNumber.value = el.orderNumber
await trackCodeInput()
await setData(el.orderNumber)
ElMessage.success('生产完成')
if (len[i + 1]) {
confirmQuery(len, i + 1)
try {
TrackingNumber.value = el.orderNumber
await trackCodeInput()
await setData(el.orderNumber)
// ElMessage.success('生产完成')
} catch (error) {
console.log(777)
console.log(error)
removeFromHistory()
} finally {
if (len[i + 1]) {
confirmQuery(len, i + 1)
}
}
})
.catch(() => {
const index = historyData.value.findIndex(
(item: HistoryDataItem) => item.orderNumber === el.orderNumber,
)
if (index >= 0) {
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
removeFromHistory()
if (len[i + 1]) {
confirmQuery(len, i + 1)
}
......@@ -336,6 +369,11 @@ const confirmQuery = (len: HistoryDataItem[], i: number) => {
})
}
const removeFromHistory = () => {
historyData.value = []
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
const changeStatus = async () => {
if (!detail.value || Object.keys(detail.value).length <= 1) {
return ElMessage.warning('请扫码生产单号')
......@@ -353,19 +391,46 @@ const setData = async (orderNumber: string) => {
try {
const id = detail.value.id
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) {
const index = historyData.value.findIndex(
(el: HistoryDataItem) => el.orderNumber === orderNumber,
)
if (index >= 0) {
// 扫单完成删除
historyData.value.splice(index, 1)
localStorage.setItem('historyUsData', JSON.stringify(historyData.value))
}
removeFromHistory()
}
emit('onSuccess')
playAudio('weight_success')
detail.value = {
id: -1,
......@@ -377,13 +442,19 @@ const setData = async (orderNumber: string) => {
trackingNumberRef.value && trackingNumberRef.value.focus()
} catch (e) {
console.error(e)
if (orderNumber) {
removeFromHistory()
}
detail.value = {
id: -1,
podJomallOrderUsId: -1,
imgList: [] as cardImages[],
}
trackingNumberRef.value && trackingNumberRef.value.focus()
playAudio('weight_search_error')
throw e
// playAudio('weight_search_error')
}
}
......@@ -453,29 +524,32 @@ const trackCodeInput = async () => {
trackingNumberRef.value && trackingNumberRef.value.focus()
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
if (isAutoSure.value) {
await setData(
historyData.value[historyData.value.length - 1].orderNumber || '',
)
try {
if (isAutoSure.value) {
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 {
const res = await getSubOrderBySubOrderNumber(orderNumber)
if (!res.data) {
removeFromHistory()
return ElMessage.error('生产单不存在')
}
const d = JSON.parse(JSON.stringify(res.data))
......@@ -496,11 +570,11 @@ const trackCodeInput = async () => {
download()
}
playAudio('weight_search_success')
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
} catch (e) {
console.error(e)
console.error(549, e)
trackingNumberRef.value && trackingNumberRef.value.focus()
TrackingNumber.value = ''
}
......@@ -508,6 +582,15 @@ const trackCodeInput = async () => {
const onOpened = () => {
trackingNumberRef.value && trackingNumberRef.value.focus()
}
const copy = (text: string) => {
try {
navigator.clipboard.writeText(text)
ElMessage.success('复制成功')
} catch (err) {
console.error('复制失败:', err)
}
}
</script>
<style lang="scss" scoped>
.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>
......@@ -2,7 +2,7 @@
<el-dialog
title="处理结果"
v-model="resultDialog"
width="600px"
width="1200px"
:close-on-click-modal="false"
@closed="closedFn"
>
......@@ -33,8 +33,17 @@
<div style="margin: 15px 0"></div>
<el-checkbox-group v-model="selectedList" @change="checkChange">
<div style="display: block" v-for="(item, index) in list" :key="index">
<el-checkbox :value="item">
{{ '工厂订单号:' + item.factoryOrderNumber + ' ' + item.message }}
<span
style="
display: inline-block;
width: 100%;
white-space: wrap;
line-height: 22px;
"
> <span>订单号:{{item.factoryOrderNumber}},</span>{{ item.message }}</span
>
</el-checkbox>
</div>
</el-checkbox-group>
......@@ -131,16 +140,12 @@ function closedFn() {
}
// 监听弹窗状态
// watch(
// () => resultDialog.value,
// (v) => {
// if (v) {
// console.log(127, props.list)
// resultfilter(true)
// }
// },
// )
watch(
() => resultDialog.value,
(v) => {
console.log(v)
},
)
watch(
() => props.list,
(v) => {
......
<script setup lang="ts">
import { defineModel } from 'vue'
import { updateAddressApi } from '@/api/podUsOrder.ts'
import {AddressInfo} from '@/types/api/podUsOrder.ts'
import { AddressInfo } from '@/types/api/podUsOrder.ts'
const emits = defineEmits(['success'])
defineProps<{
......@@ -45,7 +45,7 @@ const submitForm = async () => {
visible.value = false
emits('success')
await ElMessageBox.alert(
'请修改/刷新地址后取消物流重新创建物流订单、获取跟踪号、获取打印面单。',
'请修改/刷新地址后取消物流或者更换物流在重新创建物流订单、获取跟踪号、获取打印面单',
'提示',
{
type: 'warning',
......@@ -117,6 +117,8 @@ const submitForm = async () => {
v-model="form.receiverAddress1"
clearable
placeholder="请输入地址1"
maxlength="50"
show-word-limit
/>
</el-form-item>
<el-form-item label="地址2" prop="receiverAddress2">
......@@ -124,6 +126,8 @@ const submitForm = async () => {
v-model="form.receiverAddress2"
clearable
placeholder="请输入地址2"
maxlength="50"
show-word-limit
/>
</el-form-item>
<el-form-item label="邮政编码" prop="receiverPostCode">
......
......@@ -79,32 +79,24 @@
<ElFormItem>
<ElButton @click="reset">重置</ElButton>
</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>
</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
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
......@@ -685,8 +677,8 @@
layout="total, sizes, prev, pager, next, jumper"
:total="detailPager.total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@size-change="handleDetailSizeChange"
@current-change="handleDetailCurrentChange"
></ElPagination>
</el-tab-pane>
<el-tab-pane name="1" label="操作日志">
......@@ -994,6 +986,15 @@ const getSelectionsProperty = (property: keyof AccountStatementNote) => {
.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 treeRef = ref<InstanceType<typeof ElTree>>()
const {
......@@ -1196,8 +1197,8 @@ const submitPodPrice = async () => {
try {
const res = await apiSetCraftData({
id: currentRow.value?.id,
craftTotalPrice:currentRow.value?.craft_total_amount,
recNumber: currentRow.value?.rec_number,
craftTotalPrice: currentRow.value?.craft_total_amount,
recNumber: currentRow.value?.rec_number,
craftPriceList: filteredList,
})
if (res.code !== 200) return
......
<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 @@
<div class="search-form">
<ElForm
:model="searchForm"
size="large"
inline
@submit.prevent
@keyup.enter="search"
......@@ -59,12 +58,12 @@
></ElInput>
</ElFormItem> -->
<ElFormItem>
<ElButton type="primary" size="large" @click="search"
<ElButton type="primary" @click="search"
>查询</ElButton
>
</ElFormItem>
<ElFormItem v-if="treeId === '201'">
<el-button size="large" type="danger" @click="reject"
<el-button type="danger" @click="reject"
>驳回</el-button
>
</ElFormItem>
......
......@@ -93,63 +93,53 @@
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</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>
</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
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
......@@ -321,7 +311,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn
......@@ -395,21 +385,17 @@
</div>
<ElDialog
v-model="importDialogVisible"
title="导入"
title="导入出库单"
width="500px"
:close-on-click-modal="false"
>
<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">
<UploadExcel
v-model="importedFileUrl"
:import-type="'localAndXlsx'"
:import-name="'出库单'"
:import-url="'/files/outboundOrder.xlsx'"
@imported="handleLocalImport"
/>
</div>
......@@ -500,7 +486,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn
......@@ -616,7 +602,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn
......@@ -748,7 +734,7 @@
<el-table-column
align="center"
prop="supplierItemNo"
label="供应货号"
label="号"
></el-table-column>
<el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }">
......@@ -797,7 +783,7 @@
<script setup lang="ts">
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 { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
......@@ -957,14 +943,6 @@ function getStartTime() {
const day = date.getDate()
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 treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
......@@ -1171,9 +1149,9 @@ const handleLocalImport = async ({
.filter((item) => item.warehouseSku)
if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的库存SKU');
importDialogVisible.value = false;
return;
ElMessage.warning('导入数据中没有有效的库存SKU')
importDialogVisible.value = false
return
}
// 2. 提取导入的 SKU 列表
......@@ -1183,10 +1161,10 @@ const handleLocalImport = async ({
const filteredSkusList = await batchAddCommodity(importedSkus)
if (filteredSkusList.length === 0) {
ElMessage.warning('导入的库存SKU已存在或无效');
importedFileUrl.value = path;
importDialogVisible.value = false;
return;
ElMessage.warning('导入的库存SKU已存在或无效')
importedFileUrl.value = path
importDialogVisible.value = false
return
}
// 4. 将备注信息合并到获取到的商品列表中
......@@ -1999,11 +1977,6 @@ $border: solid 1px #ddd;
}
.import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content {
padding-bottom: 20px;
}
......
......@@ -14,7 +14,6 @@ import {
importWarehouseLocation,
} from '@/api/warehouse.ts'
const uploadExcelRef = ref()
import { Download } from '@element-plus/icons-vue'
import { nextTick, ref } from 'vue'
import SplitDiv from '@/components/splitDiv/splitDiv.vue'
import { filePath } from '@/api/axios.ts'
......@@ -55,14 +54,6 @@ const handleLocalImport = async ({
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 searchForm = ref({
warehouseId: '',
......@@ -490,24 +481,20 @@ getWarehouse()
</el-card>
</template>
</split-div>
<ElDialog
<ElDialog
v-model="importDialogVisible"
title="导入"
title="导入库位"
width="500px"
:close-on-click-modal="false"
>
<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-dialog">
<div class="import-content">
<UploadExcel
ref="uploadExcelRef"
ref="uploadExcelRef"
v-model="importedFileUrl"
:import-type="'localAndUpload'"
:import-name="'库位'"
:import-url="'/files/warehouseLocationTemplate.xlsx'"
@imported="handleLocalImport"
/>
</div>
......
......@@ -93,63 +93,57 @@
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</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>
</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
class="delivery-note-content flex-1 flex-column overflow-hidden"
>
......@@ -329,7 +323,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn
......@@ -427,21 +421,17 @@
</div>
<ElDialog
v-model="importDialogVisible"
title="导入"
title="导入入库单"
width="500px"
:close-on-click-modal="false"
>
<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">
<UploadExcel
v-model="importedFileUrl"
:import-type="'localAndXlsx'"
:import-name="'入库单'"
:import-url="'/files/warehousingEntry.xlsx'"
@imported="handleLocalImport"
/>
</div>
......@@ -532,7 +522,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn align="center" label="入库数量" prop="buyStored">
......@@ -646,7 +636,7 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="供应货号"
label="号"
prop="productNo"
/>
<ElTableColumn
......@@ -778,7 +768,7 @@
<el-table-column
align="center"
prop="supplierItemNo"
label="供应货号"
label="号"
></el-table-column>
<el-table-column align="center" prop="number" label="打印数量">
<template #default="{ row }">
......@@ -827,7 +817,7 @@
<script setup lang="ts">
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 { ElTable } from 'element-plus'
import usePageList from '@/utils/hooks/usePageList'
......@@ -987,14 +977,6 @@ function getStartTime() {
const day = date.getDate()
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 treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
......@@ -1156,7 +1138,7 @@ const excelFieldMap: Record<string, keyof InterProductList> = {
入库数量: 'buyStored',
// '成本价(¥)': 'costPrice',
// '总成本(¥)': 'totalPrice',
// 库位: 'locationCode',
库位编码: 'locationCode',
备注: 'remark',
}
......@@ -1201,6 +1183,7 @@ const handleLocalImport = async ({
return obj
})
.filter((item) => item.warehouseSku)
// console.log('@', importedData, data)
if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的商品SKU')
importDialogVisible.value = false
......@@ -1222,13 +1205,16 @@ const handleLocalImport = async ({
const importedItem = importedData.find(
(item) => item.warehouseSku === skuItem.sku,
)
const target = locationList.value.find((item: InterProductList) => {
return item.locationCode == importedItem?.locationCode
})
return {
skuImage: skuItem.image,
warehouseSku: skuItem.sku,
skuName: skuItem.skuName,
productNo: skuItem.productNo,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
locationId: skuItem.locationId || target?.locationId,
costPrice: skuItem.factoryPrice,
buyStored: importedItem?.buyStored ?? null,
totalPrice: new BigNumber(
......@@ -1535,6 +1521,7 @@ const addOtherCurrency = async () => {
ElMessage.error('请至少选择一条数据')
return
}
for (let i = 0; i < arr.length; i++) {
if (!arr[i].buyStored) {
ElMessage.error('请输入入库数量')
......@@ -1544,6 +1531,12 @@ const addOtherCurrency = async () => {
ElMessage.error('请选择库位')
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) {
addSection()
......@@ -1554,7 +1547,7 @@ const addOtherCurrency = async () => {
const filterSkuData = computed(() => {
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))
})
const addSection = async () => {
......@@ -1959,11 +1952,6 @@ $border: solid 1px #ddd;
}
.import-dialog {
.import-header {
display: flex;
justify-content: flex-end;
}
.import-content {
padding-bottom: 20px;
}
......
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