运营段修改

This commit is contained in:
dev 2025-04-12 11:09:40 +08:00
parent b4cc51c1d1
commit 59f490f323
35 changed files with 4734 additions and 655 deletions

23
.deployrc.js Normal file
View File

@ -0,0 +1,23 @@
// .deployrc.js (ESM 格式)
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
export default {
host: '112.74.106.216',
port: 22, // 默认 SSH 端口
username: 'root',
// 密码和私钥二选一
password: 'Smt1618?',
privateKey: null, // 示例: readFileSync(resolve(process.env.HOME, '.ssh/id_rsa')),
// 部署路径
remotePath: '/opt/1panel/apps/openresty/openresty/www/sites/www.amzups.com/index',
// 是否清空目标目录
cleanRemote: true
// 高级选项 (可选)
// uploadIgnore: ['*.map', 'tmp/*'],
// execAfterDeploy: 'sudo systemctl restart nginx'
};

View File

@ -7,6 +7,10 @@ VITE_APP_ENV = 'development'
# 开发环境
VITE_APP_BASE_API = '/dev-api'
VITE_BACKEND_URL = 'http://localhost:8080'
#VITE_BACKEND_URL = 'http://112.74.106.216:8080'
# 应用访问路径 例如使用前缀 /admin/
VITE_APP_CONTEXT_PATH = '/'

View File

@ -16,6 +16,8 @@ VITE_APP_SNAILJOB_ADMIN = '/snail-job'
# 生产环境
VITE_APP_BASE_API = '/prod-api'
VITE_BACKEND_URL = 'http://112.74.106.216:8080'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip

90
deploy.js Normal file
View File

@ -0,0 +1,90 @@
import { NodeSSH } from 'node-ssh';
import path from 'node:path';
import fs from 'node:fs';
import process from 'node:process';
// 动态导入配置文件(支持文件不存在的情况)
const loadConfig = async () => {
try {
const { default: config } = await import('./.deployrc.js');
return config;
} catch (error) {
if (error.code !== 'ERR_MODULE_NOT_FOUND') throw error;
return {
host: process.env.DEPLOY_HOST,
port: process.env.DEPLOY_PORT || 22,
username: process.env.DEPLOY_USER,
password: process.env.DEPLOY_PASSWORD,
privateKey: process.env.DEPLOY_PRIVATE_KEY_PATH ? fs.readFileSync(path.resolve(process.env.DEPLOY_PRIVATE_KEY_PATH)) : null,
remotePath: process.env.DEPLOY_REMOTE_PATH,
cleanRemote: process.env.DEPLOY_CLEAN === 'true'
};
}
};
const ssh = new NodeSSH();
async function deploy() {
try {
// 加载配置
const config = await loadConfig();
validateConfig(config);
// 连接服务器
console.log('🔄 Connecting to server...');
await ssh.connect({
host: config.host,
port: config.port,
username: config.username,
password: config.password,
privateKey: config.privateKey
});
// 确保目录存在
console.log('📂 Ensuring remote directory exists...');
await ssh.execCommand(`mkdir -p ${config.remotePath}`);
// 清理目录
if (config.cleanRemote) {
console.log('🧹 Cleaning remote directory...');
await ssh.execCommand(`rm -rf ${config.remotePath}/*`);
}
// 上传文件
console.log('🚀 Uploading files...');
const uploadResult = await ssh.putDirectory('./dist', config.remotePath, {
recursive: true,
concurrency: 10,
tick: (localPath, remotePath, error) => {
const relativePath = path.relative(process.cwd(), localPath);
console[error ? 'error' : 'log'](`${error ? '❌' : '✅'} ${error ? 'Failed' : 'Uploaded'}: ${relativePath}`);
}
});
if (!uploadResult) throw new Error('Upload failed without specific error');
console.log('🎉 Deployment completed successfully!');
} catch (error) {
console.error('🔥 Deployment failed:', error.message);
process.exit(1);
} finally {
ssh.dispose();
}
}
function validateConfig(config) {
const requiredFields = ['host', 'username', 'remotePath'];
const missing = requiredFields.filter((field) => !config[field]);
if (missing.length) {
throw new Error(`Missing required config fields: ${missing.join(', ')}`);
}
if (!config.password && !config.privateKey) {
throw new Error('Either password or privateKey must be provided');
}
}
// 执行部署
deploy();

View File

@ -60,6 +60,8 @@ export default [
globals: {
// 自动导入的配置 undef
...autoImportGlobals.globals,
process: 'readonly',
require: 'readonly',
DialogOption: 'readonly',
LayoutSetting: 'readonly'
}

View File

@ -9,6 +9,8 @@
"scripts": {
"dev": "vite serve --mode development",
"build:prod": "vite build --mode production",
"deploy": "node deploy.js",
"build-and-deploy": "npm run build:prod && npm run deploy",
"build:dev": "vite build --mode development",
"preview": "vite preview",
"lint:eslint": "eslint",
@ -40,6 +42,7 @@
"image-conversion": "2.1.1",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"node-ssh": "^13.2.1",
"nprogress": "0.2.0",
"pinia": "2.2.6",
"screenfull": "6.0.2",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -29,7 +29,7 @@ export const getInquiryRequest = (id: string | number): AxiosPromise<InquiryRequ
});
};
export const createWithDesAndChannel = (destination: string, channelId: string, date: string): AxiosPromise<void> => {
export const createWithDesAndChannel = (destination: string | number, channelId: string, date: string): AxiosPromise<void> => {
return request({
url: '/amz/inquiryRequest/create/' + destination + '/' + channelId + '/' + date,
method: 'get'
@ -44,7 +44,7 @@ export const createWithDesAndChannel = (destination: string, channelId: string,
* @param date
*/
export const queryWithDesAndChannel = (destination: string, channelId: string, date: string): AxiosPromise<LogisticsQuoteVO[]> => {
export const queryWithDesAndChannel = (destination: string | number, channelId: string, date: string): AxiosPromise<LogisticsQuoteVO[]> => {
return request({
url: '/amz/inquiryRequest/query/' + destination + '/' + channelId + '/' + date,
method: 'get'

View File

@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LogisticsOrderVO, LogisticsOrderForm, LogisticsOrderQuery, createOrderForm } from '@/api/amz/logisticsOrder/types';
import { LogisticsOrderVO, LogisticsOrderForm, LogisticsOrderQuery, createOrderForm, InquiryQuoteStatusVO } from '@/api/amz/logisticsOrder/types';
/**
*
@ -20,13 +20,24 @@ export const listLogisticsOrder = (query?: LogisticsOrderQuery): AxiosPromise<Lo
*
* @param id
*/
export const getLogisticsOrder = (id: string | number): AxiosPromise<LogisticsOrderVO> => {
export const getLogisticsOrder = (id: string | number): AxiosPromise<InquiryQuoteStatusVO> => {
return request({
url: '/amz/logisticsOrder/' + id,
method: 'get'
});
};
// /**
// * 查询物流订单详细
// * @param id
// */
// export const getTodayQuoteStatus = (): AxiosPromise<InquiryQuoteStatusVO[]> => {
// return request({
// url: '/amz/logisticsOrder/today-quote-status',
// method: 'get'
// });
// };
/**
*
* @param data

View File

@ -55,6 +55,18 @@ export interface LogisticsOrderVO {
shelfTimeliness: number;
}
export interface InquiryQuoteStatusVO {
// private Long inquiryId;
// private String inquiryNo;
// private Long providerId;
// private String quoteStatus; // "已报价" 或 "未报价"
inquiryId: string | number;
inquiryNo: string;
providerId: string | number;
quoteStatus: string;
}
export interface LogisticsOrderForm extends BaseEntity {
/**
* ID
@ -84,7 +96,7 @@ export interface LogisticsOrderForm extends BaseEntity {
/**
* //
*/
logisticsChannel?: string;
channelName?: string;
/**
*

View File

@ -1,6 +1,8 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LogisticsQuoteVO, LogisticsQuoteForm, LogisticsQuoteQuery } from '@/api/amz/logisticsQuote/types';
import { InquiryQuoteStatusVO } from '@/api/amz/logisticsOrder/types';
import { UnwrapRef } from 'vue';
/**
*
@ -24,7 +26,7 @@ export const listLogisticsQuote = (query?: LogisticsQuoteQuery): AxiosPromise<Lo
* @param date
*/
export const queryLogisticsQuote = (destination: string, channelId: string, date: string): AxiosPromise<LogisticsQuoteVO[]> => {
export const queryLogisticsQuote = (destination: string | number, channelId: string, date: string): AxiosPromise<LogisticsQuoteVO[]> => {
return request({
url: '/amz/logisticsQuote/query/' + destination + '/' + channelId + '/' + date,
method: 'get'
@ -46,7 +48,7 @@ export const getLogisticsQuote = (id: string | number): AxiosPromise<LogisticsQu
*
* @param id
*/
export const getTodayQuoteStatus = () => {
export const getTodayQuoteStatus = (): AxiosPromise<InquiryQuoteStatusVO[]> => {
return request({
url: '/amz/logisticsQuote/today-quote-status',
method: 'get'
@ -77,6 +79,18 @@ export const addMostLogisticsQuote = (data: LogisticsQuoteForm) => {
});
};
/**
*
* @param data
*/
export const checkPriceQuoteByBo = (data: LogisticsQuoteForm) => {
return request({
url: '/amz/logisticsQuote/check-quote-price',
method: 'post',
data: data
});
};
/**
*
* @param data

View File

@ -16,6 +16,14 @@ export const listShipmentPlan = (query?: ShipmentPlanQuery): AxiosPromise<Shipme
});
};
export const listShipmentPlanOrder = (query?: ShipmentPlanQuery): AxiosPromise<ShipmentPlanVO[]> => {
return request({
url: '/amz/shipmentPlan/list/order',
method: 'get',
params: query
});
};
/**
*
* @param id
@ -27,6 +35,16 @@ export const getShipmentPlan = (id: string | number): AxiosPromise<ShipmentPlanV
});
};
/**
*
* @param id
*/
export const takeTodayAmzPlanData = () => {
return request({
url: '/amz/shipmentPlan/take-today-amz-plan-data',
method: 'get'
});
};
/**
*

View File

@ -1,3 +1,7 @@
import { LogisticsOrderVO } from '@/api/amz/logisticsOrder/types';
import { LogisticsOrderDetailVO } from '@/api/amz/logisticsOrderDetail/types';
import { ShipmentItemVO } from '@/api/amz/shipmentItem/types';
export interface ShipmentPlanVO {
/**
* ID
@ -32,7 +36,7 @@ export interface ShipmentPlanVO {
/**
*
*/
destination: string | number;
destination: string;
/**
*
@ -57,7 +61,7 @@ export interface ShipmentPlanVO {
/**
*
*/
syncTime: string;
receivingTime: string;
/**
*
@ -99,7 +103,205 @@ export interface ShipmentPlanVO {
*/
isSta: string;
/**
*
*/
shipmentUniqueId: string | number;
/**
* STA任务编号
*/
inboundPlanId: string | number;
/**
*
*/
fbaStatus: string;
/**
*
*/
boxQuantity: number;
/**
*
*/
boxSize: string;
/**
* KG
*/
vendorWeight: number;
/**
*
*/
setTotal: number;
/**
* ID
*/
channelId: string | number;
/**
*
*/
channelName: string;
}
export interface ShipmentPlanOrderVO {
/**
* ID
*/
id: string | number;
/**
* ID
*/
sid: string | number;
/**
*
*/
shipmentId: string | number;
/**
*
*/
shipmentName: string;
/**
*
*/
isClosed: string;
/**
*
*/
shipmentStatus: string;
/**
*
*/
destination: string;
/**
*
*/
shippingMode: string;
/**
*
*/
shippingSolution: string;
/**
*
*/
gmtModified: string;
/**
*
*/
gmtCreate: string;
/**
*
*/
receivingTime: string;
/**
*
*/
staShipmentDate: string;
/**
*
*/
staDeliveryStartDate: string;
/**
*
*/
staDeliveryEndDate: string;
/**
*
*/
shipFromAddress: string;
/**
*
*/
shipToAddress: string;
/**
*
*/
referenceId: string | number;
/**
* ID
*/
staInboundPlanId: string | number;
/**
* STA计划
*/
isSta: string;
/**
*
*/
shipmentUniqueId: string | number;
/**
* STA任务编号
*/
inboundPlanId: string | number;
/**
*
*/
fbaStatus: string;
/**
*
*/
boxQuantity: number;
/**
*
*/
boxSize: string;
/**
* KG
*/
logisticsWeight: number;
/**
*
*/
setTotal: number;
/**
* ID
*/
channelId: string | number;
/**
*
*/
channelName: string;
order?: LogisticsOrderVO;
detailList?: LogisticsOrderDetailVO[];
itemVoList?: ShipmentItemVO[];
quote?: LogisticsOrderVO;
}
export interface ShipmentPlanForm extends BaseEntity {
@ -136,7 +338,7 @@ export interface ShipmentPlanForm extends BaseEntity {
/**
*
*/
destination?: string | number;
destination?: string;
/**
*
@ -161,7 +363,7 @@ export interface ShipmentPlanForm extends BaseEntity {
/**
*
*/
syncTime?: string;
receivingTime?: string;
/**
*
@ -203,10 +405,53 @@ export interface ShipmentPlanForm extends BaseEntity {
*/
isSta?: string;
/**
*
*/
shipmentUniqueId?: string | number;
/**
* STA任务编号
*/
inboundPlanId?: string | number;
/**
*
*/
fbaStatus?: string;
/**
*
*/
boxQuantity?: number;
/**
*
*/
boxSize?: string;
/**
*
*/
vendorWeight?: number;
/**
*
*/
setTotal?: number;
/**
* ID
*/
channelId?: string | number;
/**
*
*/
channelName?: string;
}
export interface ShipmentPlanQuery extends PageQuery {
/**
* ID
*/
@ -235,7 +480,7 @@ export interface ShipmentPlanQuery extends PageQuery {
/**
*
*/
destination?: string | number;
destination?: string;
/**
*
@ -260,7 +505,7 @@ export interface ShipmentPlanQuery extends PageQuery {
/**
*
*/
syncTime?: string;
receivingTime?: string;
/**
*
@ -302,11 +547,53 @@ export interface ShipmentPlanQuery extends PageQuery {
*/
isSta?: string;
/**
*
*/
params?: any;
/**
*
*/
shipmentUniqueId?: string | number;
/**
* STA任务编号
*/
inboundPlanId?: string | number;
/**
*
*/
fbaStatus?: string;
/**
*
*/
boxQuantity?: number;
/**
*
*/
boxSize?: string;
/**
* KG
*/
logisticsWeight?: number;
/**
*
*/
setTotal?: number;
/**
* ID
*/
channelId?: string | number;
/**
*
*/
channelName?: string;
/**
*
*/
params?: any;
}

View File

@ -19,6 +19,66 @@ export interface ShipmentTrackingVO {
*/
trackingNumber: string;
/**
*
*/
localBoxId: string | number;
/**
*
*/
packageId: string | number;
/**
*
*/
total: number;
/**
*
*/
weight: number;
/**
*
*/
weightUnit: string;
/**
*
*/
length: number;
/**
*
*/
width: string | number;
/**
*
*/
height: number;
/**
*
*/
lengthUnit: string;
/**
*
*/
boxName: string;
/**
*
*/
shipmentUniqueId: string | number;
/**
* STA任务编号
*/
inboundPlanId: string | number;
}
export interface ShipmentTrackingForm extends BaseEntity {
@ -42,6 +102,66 @@ export interface ShipmentTrackingForm extends BaseEntity {
*/
trackingNumber?: string;
/**
*
*/
localBoxId?: string | number;
/**
*
*/
packageId?: string | number;
/**
*
*/
total?: number;
/**
*
*/
weight?: number;
/**
*
*/
weightUnit?: string;
/**
*
*/
length?: number;
/**
*
*/
width?: string | number;
/**
*
*/
height?: number;
/**
*
*/
lengthUnit?: string;
/**
*
*/
boxName?: string;
/**
*
*/
shipmentUniqueId?: string | number;
/**
* STA任务编号
*/
inboundPlanId?: string | number;
}
export interface ShipmentTrackingQuery extends PageQuery {
@ -61,6 +181,66 @@ export interface ShipmentTrackingQuery extends PageQuery {
*/
trackingNumber?: string;
/**
*
*/
localBoxId?: string | number;
/**
*
*/
packageId?: string | number;
/**
*
*/
total?: number;
/**
*
*/
weight?: number;
/**
*
*/
weightUnit?: string;
/**
*
*/
length?: number;
/**
*
*/
width?: string | number;
/**
*
*/
height?: number;
/**
*
*/
lengthUnit?: string;
/**
*
*/
boxName?: string;
/**
*
*/
shipmentUniqueId?: string | number;
/**
* STA任务编号
*/
inboundPlanId?: string | number;
/**
*
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,98 @@
<!-- EnhancedTable.vue -->
<template>
<div class="enhanced-table-container">
<!-- 列控制按钮 -->
<div class="column-control">
<el-tooltip content="列配置" placement="left">
<el-button circle size="small" class="control-btn" @click="showConfigDialog = true">
<el-icon>
<Operation />
</el-icon>
</el-button>
</el-tooltip>
</div>
<!-- 列配置弹窗 -->
<el-dialog v-model="showConfigDialog" title="列显示配置" width="500px">
<el-checkbox-group v-model="visibleKeys">
<el-row :gutter="20">
<el-col v-for="col in configurableColumns" :key="col.uniqueKey" :span="8">
<el-checkbox :value="col.uniqueKey" :disabled="col.fixed">
{{ col.displayLabel }}
</el-checkbox>
</el-col>
</el-row>
</el-checkbox-group>
</el-dialog>
<!-- 动态渲染表格 -->
<el-table ref="tableRef" v-bind="$attrs" :data="tableData" v-loading="loading" @current-change="handleCurrentChange" highlight-current-row>
<template v-for="col in visibleColumns" :key="col.uniqueKey">
<component :is="col.component" v-bind="col.props">
<template v-for="(slot, name) in col.slots" #[name]="scope">
<slot :name="name" v-bind="scope" />
</template>
</component>
</template>
</el-table>
</div>
</template>
<script setup>
import { ref, computed, watch, useSlots, onMounted } from 'vue';
//
const generateStableKey = (node) => {
//
if (node.props?.type) {
return `special_${node.props.type}`;
}
// propprop+label
if (node.props?.prop) {
return `prop_${node.props.prop}_${node.props.label || 'nolabel'}`;
}
// proplabellabel+
if (node.props?.label) {
return `label_${node.props.label.replace(/\W/g, '_')}_${hashCode(node.type?.name)}`;
}
// 退使slot
return `slot_${hashCode(JSON.stringify(node.children))}`;
};
// 8
const hashCode = (str) => {
let hash = 0;
for (let i = 0; i < (str || '').length; i++) {
hash = (hash << 5) - hash + str.charCodeAt(i);
hash |= 0;
}
return Math.abs(hash).toString(16).padStart(8, '0');
};
//
const parsedColumns = ref([]);
const parseColumns = () => {
const slots = useSlots().default?.();
parsedColumns.value = (slots || [])
.filter((node) => !node.type?.toString().includes('Comment'))
.map((node) => ({
uniqueKey: generateStableKey(node),
label: node.props?.label,
component: node.type,
props: node.props,
slots: node.children,
fixed: !!node.props?.type
}));
};
//
onMounted(parseColumns);
watch(useSlots(), parseColumns, { deep: true });
</script>
<style scoped>
/* 保持原有样式不变 */
</style>

View File

@ -0,0 +1,126 @@
<!-- 最后修改之前封装的组件 -->
<template>
<div class="l-table">
<!-- 表格 -->
<el-table
:data="props.tableModule.dataList"
border
height="100%"
style="width: 100%; overflow-y: scroll"
v-loading="props.tableModule.loading"
@selection-change="props.tableModule.selectChange"
:row-class-name="tableRowClassName"
:cell-class-name="tableCellClassName"
@cell-dblclick="cellDblClick"
>
<el-table-column type="selection" width="50" align="center" />
<!-- v-for 循环拿到了外层 el-table-column 判断 item.show 就可以了 -->
<template v-if="tableChildren == '1'" v-for="(item, index) in props.tableModule.columns">
<el-table-column
:prop="item.prop"
:label="item.label"
:align="item.align || 'left'"
:width="item.width"
:min-width="item.min_width"
:fixed="item.fixed"
v-if="item.show"
>
<template slot-scope="scope" #default="scope">
<div v-if="item.type == 'switch'">
<el-switch
v-model="scope.row[item.prop]"
:active-value="item.activeValue"
:inactive-value="item.inactiveValue"
@change="props.tableModule.switchChange(scope.row)"
>
</el-switch>
</div>
<div v-else-if="item.type == 'status'">
<el-tag :type="item.color ? item.color[scope.row[item.prop]] : ''"
>{{ props.tableModule.fieldChange(scope.row[item.prop], item.option) }}
</el-tag>
</div>
<div v-else-if="item.type == 'image'">
<el-image style="width: 60px; height: 60px" :src="scope.row[item.prop]" :preview-src-list="[scope.row[item.prop]]"> </el-image>
</div>
<div v-else-if="item.type == 'time'">{{ formatDate(scope.row[item.prop]) }}</div>
<div v-else-if="item.isEdit">
<el-input
v-model="scope.row[item.prop]"
:placeholder="'请输入' + item.label"
@blur="inputBlur(scope.row)"
autofocus
ref="inputRef"
v-if="scope.row['index'] == rowIndex && scope.column['index'] == columnIndex"
/>
<div v-else>{{ scope.row[item.prop] }}</div>
</div>
<div v-else>{{ scope.row[item.prop] }}</div>
</template>
</el-table-column>
</template>
<!-- 这里无论循环一级还是二级都需要在template上去写循环 -->
<template v-else-if="tableChildren == '2'" v-for="(one, index) in props.tableModule.columns">
<el-table-column :label="one.label" v-if="one.show">
<template v-for="item in props.tableModule.columns[index].children">
<el-table-column
:prop="item.prop"
:label="item.label"
:align="item.align || 'left'"
:width="item.width"
:min-width="item.min_width"
:fixed="item.fixed"
v-if="item.show"
>
<template slot-scope="scope" #default="scope">
<div v-if="item.type == 'switch'">
<el-switch
v-model="scope.row[item.prop]"
:active-value="item.activeValue"
:inactive-value="item.inactiveValue"
@change="props.tableModule.switchChange(scope.row)"
>
</el-switch>
</div>
<div v-else-if="item.type == 'status'">
<el-tag :type="item.color ? item.color[scope.row[item.prop]] : ''"
>{{ props.tableModule.fieldChange(scope.row[item.prop], item.option) }}
</el-tag>
</div>
<div v-else-if="item.type == 'image'">
<el-image style="width: 60px; height: 60px" :src="scope.row[item.prop]" :preview-src-list="[scope.row[item.prop]]"> </el-image>
</div>
<div v-else-if="item.type == 'time'">{{ formatDate(scope.row[item.prop]) }}</div>
<div v-else-if="item.isEdit">
<el-input
v-model="scope.row[item.prop]"
:placeholder="'请输入' + item.label"
@blur="inputBlur(scope.row)"
autofocus
ref="inputRef"
v-if="scope.row['index'] == rowIndex && scope.column['index'] == columnIndex"
/>
<div v-else>{{ scope.row[item.prop] }}</div>
</div>
<div v-else>{{ scope.row[item.prop] }}</div>
</template>
</el-table-column>
</template>
</el-table-column>
</template>
<slot name="event"></slot>
</el-table>
<div class="l-pages">
<!-- 分页 -->
<el-pagination
:current-page="props.tableModule.pages.page"
:page-size.sync="props.tableModule.pages.limit"
:page-sizes="pageSizes"
:layout="layout"
:total="props.tableModule.pages.total"
@size-change="props.tableModule.sizeChange"
@current-change="props.tableModule.currentChange"
/>
</div>
</div>
</template>

View File

@ -0,0 +1,237 @@
<template>
<div class="upload-file">
<el-upload
ref="fileUploadRef"
multiple
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
class="upload-file-uploader"
>
<!-- 上传按钮 -->
<el-button plain icon="Plus" type="warning">导入文件</el-button>
</el-upload>
<!-- 上传提示 -->
<div v-if="showTip" class="el-upload__tip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
<el-link :href="`${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
<el-button type="danger" link @click="handleDelete(index)">删除</el-button>
</div>
</li>
</transition-group>
</div>
</template>
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes';
import { delOss, listByIds } from '@/api/system/oss';
import { globalHeaders } from '@/utils/request';
const props = defineProps({
modelValue: {
type: [String, Object, Array],
default: () => []
},
//
limit: propTypes.number.def(5),
// (MB)
fileSize: propTypes.number.def(5),
// , ['png', 'jpg', 'jpeg']
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']),
//
isShowTip: propTypes.bool.def(true)
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const emit = defineEmits(['update:modelValue']);
const number = ref(0);
const uploadList = ref<any[]>([]);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(baseUrl + '/amz/logisticsOrderDetail/importData'); //
const headers = ref(globalHeaders());
const fileList = ref<any[]>([]);
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
const fileUploadRef = ref<ElUploadInstance>();
watch(
() => props.modelValue,
async (val) => {
if (val) {
let temp = 1;
//
let list: any[] = [];
if (Array.isArray(val)) {
list = val;
} else {
const res = await listByIds(val);
list = res.data.map((oss) => {
return {
name: oss.originalName,
url: oss.url,
ossId: oss.ossId
};
});
}
//
fileList.value = list.map((item) => {
item = { name: item.name, url: item.url, ossId: item.ossId };
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
fileList.value = [];
return [];
}
},
{ deep: true, immediate: true }
);
//
const handleBeforeUpload = (file: any) => {
//
if (props.fileType.length) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) {
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`);
return false;
}
}
//
if (file.name.includes(',')) {
proxy?.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
}
//
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
proxy?.$modal.loading('正在上传文件,请稍候...');
number.value++;
return true;
};
//
const handleExceed = () => {
proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
};
//
const handleUploadError = () => {
proxy?.$modal.msgError('上传文件失败');
};
//
const handleUploadSuccess = (res: any, file: UploadFile) => {
if (res.code === 200) {
// uploadList.value.push({
// name: res.data.fileName,
// url: res.data.url,
// ossId: res.data.ossId
// });
// uploadedSuccessfully();
proxy?.$modal.msgSuccess('上传文件成功');
} else {
// number.value--;
// proxy?.$modal.closeLoading();
// proxy?.$modal.msgError(res.msg);
// fileUploadRef.value?.handleRemove(file);
// uploadedSuccessfully();
proxy?.$modal.msgError('上传文件失败');
}
proxy?.$modal.closeLoading();
};
//
const handleDelete = (index: number) => {
let ossId = fileList.value[index].ossId;
delOss(ossId);
fileList.value.splice(index, 1);
emit('update:modelValue', listToString(fileList.value));
};
//
const uploadedSuccessfully = () => {
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
uploadList.value = [];
number.value = 0;
emit('update:modelValue', listToString(fileList.value));
proxy?.$modal.closeLoading();
}
};
//
const getFileName = (name: string) => {
// url
if (name.lastIndexOf('/') > -1) {
return name.slice(name.lastIndexOf('/') + 1);
} else {
return name;
}
};
//
const listToString = (list: any[], separator?: string) => {
let strs = '';
separator = separator || ',';
list.forEach((item) => {
if (item.ossId) {
strs += item.ossId + separator;
}
});
return strs != '' ? strs.substring(0, strs.length - 1) : '';
};
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
</style>

View File

@ -129,6 +129,8 @@ const roleNmae = computed(() => {
return '物流商';
} else if (roles.includes('yunying')) {
return '运营';
} else if (roles.includes('manager')) {
return '管理员';
} else {
return '普通用户';
}

View File

@ -91,6 +91,9 @@
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:amazonStore:edit']"></el-button>
</el-tooltip>
<el-tooltip content="指定运营" placement="top">
<el-button link type="primary" icon="Avatar" @click="changeUser(scope.row)" v-hasPermi="['amz:amazonStore:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:amazonStore:remove']"></el-button>
</el-tooltip>
@ -152,6 +155,7 @@
import { listAmazonStore, getAmazonStore, delAmazonStore, addAmazonStore, updateAmazonStore, collectAmzStoreData } from '@/api/amz/amazonStore';
import { AmazonStoreVO, AmazonStoreQuery, AmazonStoreForm } from '@/api/amz/amazonStore/types';
import AssignUser from '@/views/amz/amazonStore/assignUser.vue';
import { getInquiryRequest } from '@/api/amz/inquiryRequest';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -283,6 +287,17 @@ const handleAdd = () => {
/** 修改按钮操作 */
const handleUpdate = async (row?: AmazonStoreVO) => {
reset();
const _id = row?.id || ids.value[0];
form.value.id = _id;
console.log('form.value.id', _id);
const res = await getInquiryRequest(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改亚马逊店铺信息';
};
const changeUser = async (row?: AmazonStoreVO) => {
reset();
const _id = row?.id || ids.value[0];
form.value.id = _id;

View File

@ -234,6 +234,12 @@
</el-form-item>
<el-form-item label="时效" prop="leadTime">
<div class="kgprice">
<el-input-number v-model="minDay" :min="1" :max="100">
<template #suffix>
<span></span>
</template>
</el-input-number>
<el-input-number v-model="quoteForm.leadTime" :min="1" :max="100">
<template #suffix>
<span></span>
@ -242,7 +248,11 @@
</div>
</el-form-item>
<el-form-item label="附加费" prop="surcharge">
<el-input v-model="quoteForm.surcharge" placeholder="请输入附加费" />
<el-input-number v-model="quoteForm.surcharge" :precision="2" :step="0.1" :min="1" :max="100">
<template #suffix>
<span></span>
</template>
</el-input-number>
</el-form-item>
<el-form-item label="报价生效起止日期" prop="quoteDate">
<el-date-picker
@ -279,7 +289,7 @@
import { listInquiryRequest, getInquiryRequest, delInquiryRequest, addInquiryRequest, updateInquiryRequest } from '@/api/amz/inquiryRequest';
import { InquiryRequestVO, InquiryRequestQuery, InquiryRequestForm } from '@/api/amz/inquiryRequest/types';
import { LogisticsMostQuoteForm, LogisticsQuoteForm } from '@/api/amz/logisticsQuote/types';
import { addMostLogisticsQuote } from '@/api/amz/logisticsQuote';
import { addMostLogisticsQuote, checkPriceQuoteByBo, getTodayQuoteStatus } from '@/api/amz/logisticsQuote';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -294,6 +304,8 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const minDay = ref(0);
const queryFormRef = ref<ElFormInstance>();
const inquiryRequestFormRef = ref<ElFormInstance>();
@ -329,6 +341,7 @@ const initQuoteForm: LogisticsMostQuoteForm = {
price: 10,
leadTime: 10,
surcharge: undefined,
channelName: undefined,
quoteStartDate: undefined,
quoteEndDate: undefined,
quoteDate: [] as Date[],
@ -403,6 +416,11 @@ const getList = async () => {
loading.value = false;
};
const queryTodayQuoteStatus = async () => {
const res = await getTodayQuoteStatus();
console.log('queryTodayQuoteStatus', res);
};
/** 取消按钮 */
const cancel = () => {
reset();
@ -478,11 +496,33 @@ const submitQuoteForm = async () => {
data.quoteForm.quoteEndDate = data.quoteForm.quoteDate[1];
data.quoteForm.isSubmitted = 'Y';
console.log('submitQuoteForm', data.quoteForm);
const res = await addMostLogisticsQuote(data.quoteForm);
const res = await checkPriceQuoteByBo(data.quoteForm);
console.log('submitQuoteForm', res);
if (res.code === 200) {
ElMessage.success('提交成功');
quoteDialog.visible = false;
// ElMessage.success('');
// quoteDialog.visible = false;
if (res.data === true) {
const res = await addMostLogisticsQuote(data.quoteForm);
if (res.code === 200) {
ElMessage.success('提交成功');
quoteDialog.visible = false;
}
} else {
ElMessageBox.confirm('价格没有竞争力,问他是否需要修改价格?', '提示', {
confirmButtonText: '确认提交',
cancelButtonText: '修改价格',
type: 'warning'
})
.then(async () => {
const res = await addMostLogisticsQuote(data.quoteForm);
if (res.code === 200) {
ElMessage.success('提交成功');
quoteDialog.visible = false;
}
})
.catch(() => {});
}
}
};
@ -515,8 +555,8 @@ const handleSubmit = async (row?: InquiryRequestVO) => {
data.quoteForm.channelName = row.channelName;
quoteDialog.visible = true;
console.log(row.effectiveStartTime);
// data.quoteForm.quoteDate[0] = row.effectiveStartTime;
// data.quoteForm.quoteDate[1] = row.effectiveEndTime;
// quoteForm.quoteDate[0] = row.effectiveStartTime;
// quoteForm.quoteDate[1] = row.effectiveEndTime;
const dateString = row.effectiveStartTime.replace(' ', 'T');
const dateString2 = row.effectiveEndTime.replace(' ', 'T');
const date = new Date(dateString); // Date
@ -538,6 +578,7 @@ const handleExport = () => {
onMounted(() => {
getList();
queryTodayQuoteStatus();
});
</script>
<style scoped>

View File

@ -90,13 +90,27 @@
<dict-tag :options="biz_shipping_method" :value="scope.row.shippingMethod" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" v-hasRoles="['superadmin']" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:logisticsChannel:edit']"></el-button>
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:logisticsChannel:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:logisticsChannel:remove']"></el-button>
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:logisticsChannel:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>

View File

@ -10,36 +10,15 @@
<el-form-item label="订单编号" prop="orderId">
<el-input v-model="queryParams.orderId" placeholder="请输入订单编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流商ID" prop="logisticsProviderId">
<el-input v-model="queryParams.logisticsProviderId" placeholder="请输入物流商ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流商名称" prop="logisticsProviderName">
<el-input v-model="queryParams.logisticsProviderName" placeholder="请输入物流商名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流渠道" prop="logisticsChannel">
<el-input v-model="queryParams.logisticsChannel" placeholder="请输入物流渠道" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="目的地仓库名称或编码" prop="destination">
<el-form-item label="仓库名称" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入目的地仓库名称或编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="总箱子数量" prop="boxQuantity">
<el-input v-model="queryParams.boxQuantity" placeholder="请输入总箱子数量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="总货件数量" prop="shipmentQuantity">
<el-input v-model="queryParams.shipmentQuantity" placeholder="请输入总货件数量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="亚马逊仓库实际上架日期" prop="amazonShelfDate">
<el-date-picker
clearable
v-model="queryParams.amazonShelfDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择亚马逊仓库实际上架日期"
/>
</el-form-item>
<el-form-item label="上架时效" prop="shelfTimeliness">
<el-input v-model="queryParams.shelfTimeliness" placeholder="请输入上架时效" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -78,7 +57,7 @@
<el-table-column label="订单编号" align="center" prop="orderId" />
<el-table-column label="创建日期" align="center" prop="createTime" />
<el-table-column label="物流商名称" align="center" prop="logisticsProviderName" />
<el-table-column label="物流渠道" align="center" prop="logisticsChannel" />
<el-table-column label="物流渠道" align="center" prop="channelName" />
<el-table-column label="目的地仓库名称或编码" align="center" prop="destination" />
<el-table-column label="总箱子数量" align="center" prop="boxQuantity" />
<el-table-column label="总货件数量" align="center" prop="shipmentQuantity" />
@ -103,7 +82,7 @@
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:logisticsOrder:remove']"></el-button>
</el-tooltip>
<el-button type="primary" @click="openDetail(scope.row)" v-hasRoles="['wuliu']"> 编辑订单明细</el-button>
<el-button link size="small" type="primary" @click="openDetail(scope.row)" v-hasRoles="['wuliu']"> 编辑订单明细 </el-button>
</template>
</el-table-column>
</el-table>
@ -129,7 +108,7 @@
<el-input v-model="form.logisticsProviderName" placeholder="请输入物流商名称" />
</el-form-item>
<el-form-item label="物流渠道" prop="logisticsChannel">
<el-input v-model="form.logisticsChannel" placeholder="请输入物流渠道" />
<el-input v-model="form.channelName" placeholder="请输入物流渠道" />
</el-form-item>
<el-form-item label="目的地仓库名称或编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入目的地仓库名称或编码" />
@ -167,6 +146,14 @@
<h4>订单明细</h4>
</template>
<template #default>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Document" @click="handleExportDetail"> 导出模板文件</el-button>
</el-col>
<el-col :span="1.5">
<OrderDetailFileUpload :file-type="['xlsx', 'xls']" :file-size="20" />
</el-col>
</el-row>
<HotTable class="hot-container" ref="hotTable" :settings="hotSettings" :data="processedData" :key="tableKey"></HotTable>
<pagination
v-show="detailTotal > 0"
@ -303,12 +290,11 @@ const hotSettings = ref({
'订单号',
'FBA货件编号',
'FBA箱号',
'物流商ID',
'物流商名称',
'物流渠道',
'目的地仓库',
'计划数量',
'实际货件数量',
'实际数量',
'物流追踪号',
'物流商计重',
'称重差异',
@ -334,17 +320,33 @@ const hotSettings = ref({
{ data: 'fbaShipmentId', className: 'htCenter', readOnly: true },
// ...
{ data: 'fbaBoxNumber', className: 'htCenter', readOnly: true }, // FBA
{ data: 'logisticsProviderId', className: 'htCenter', readOnly: true }, // ID
{ data: 'logisticsProviderName', className: 'htCenter', readOnly: true }, //
{ data: 'logisticsChannel', className: 'htCenter', readOnly: true }, //
{ data: 'destinationWarehouse', className: 'htCenter', readOnly: true }, //
{ data: 'plannedQuantity', className: 'htCenter', readOnly: true }, //
{ data: 'actualShipmentQuantity', className: 'htCenter', readOnly: true }, //
{ data: 'shipmentQuantity', className: 'htCenter', readOnly: false, type: 'numeric' }, //
{ data: 'trackingNumber', className: 'htCenter', readOnly: false }, //
{ data: 'logisticsWeight', className: 'htCenter', readOnly: true }, //
{
data: 'logisticsWeight',
className: 'htCenter',
readOnly: false,
type: 'numeric',
renderer: function (instance, td, row, col, prop, value, cellProperties) {
//
//
if (typeof value === 'number' && !isNaN(value)) {
td.textContent = value.toLocaleString() + ' kg'; //
}
// className
return td;
}
}, //
{
data: 'weightDiff', //
className: 'htCenter',
readOnly: true,
type: 'numeric',
renderer: (instance, td) => {
//
const value = instance.getDataAtCell(td.row, td.col);
@ -353,9 +355,39 @@ const hotSettings = ref({
return td;
}
},
{ data: 'pricePerKg', className: 'htCenter', readOnly: true }, //
{ data: 'logisticsBillingWeight', className: 'htCenter', readOnly: true }, //
{ data: 'otherLogisticsFee', className: 'htCenter', readOnly: true }, //
{
data: 'pricePerKg',
className: 'htCenter',
type: 'numeric',
readOnly: true,
renderer: function (instance, td, row, col, prop, value, cellProperties) {
//
//
if (typeof value === 'number' && !isNaN(value)) {
td.textContent = value.toLocaleString() + ' 元/kg'; //
}
// className
return td;
}
}, //
{ data: 'logisticsBillingWeight', className: 'htCenter', type: 'numeric', readOnly: true }, //
{
data: 'otherLogisticsFee',
className: 'htCenter',
type: 'numeric',
readOnly: false,
renderer: function (instance, td, row, col, prop, value, cellProperties) {
//
//
if (typeof value === 'number' && !isNaN(value)) {
td.textContent = value.toLocaleString() + ' 元'; //
}
// className
return td;
}
}, //
{ data: 'totalFee', className: 'htCenter', readOnly: true }, //
{
data: 'logisticsStatus',
@ -410,46 +442,20 @@ const hotSettings = ref({
className: 'htCenter' //
},
{
//
// renderer: (instance, td, row, col, prop, value, cellProperties) => {
// const canEdit = checkPermi(['amz:logisticsOrderDetail:edit']);
// const canDelete = checkPermi(['amz:logisticsOrderDetail:remove']);
//
// td.innerHTML = `
// <div class="action-buttons">
// ${
// canEdit
// ? `
// <button
// class="edit-btn"
// data-row="${row}"
// :disabled="buttonLoading"
// >
// <i class="icon-edit"></i>
// </button>
// `
// : ''
// }
// ${
// canDelete
// ? `
// <button
// class="delete-btn"
// data-row="${row}"
// :disabled="buttonLoading"
// >
// <i class="icon-delete"></i>
// </button>
// `
// : ''
// }
// </div>
// `;
// td.className = 'htCenter';
// return td;
// },
readOnly: true,
width: 150
data: 'timeliness',
readOnly: false,
width: 150,
type: 'numeric',
renderer: function (instance, td, row, col, prop, value, cellProperties) {
//
//
if (typeof value === 'number' && !isNaN(value)) {
td.textContent = value.toLocaleString() + ' 天'; //
}
// className
return td;
}
}
],
afterOnCellMouseDown: (event, coords) => {
@ -524,7 +530,7 @@ const initFormData: LogisticsOrderForm = {
orderId: undefined,
logisticsProviderId: undefined,
logisticsProviderName: undefined,
logisticsChannel: undefined,
channelName: undefined,
destination: undefined,
boxQuantity: undefined,
shipmentQuantity: undefined,
@ -710,6 +716,16 @@ const handleExport = () => {
);
};
const handleExportDetail = () => {
proxy?.download(
'amz/logisticsOrderDetail/export',
{
...queryDetailParams.value
},
`logisticsOrderDetail_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});

View File

@ -4,9 +4,6 @@
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="物流商用户ID" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入物流商用户ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="目的地" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入目的地" clearable @keyup.enter="handleQuery" />
</el-form-item>
@ -25,9 +22,6 @@
<el-form-item label="报价生效日期" prop="quoteDate">
<el-date-picker clearable v-model="queryParams.quoteDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择报价生效日期" />
</el-form-item>
<el-form-item label="渠道ID" prop="channelId">
<el-input v-model="queryParams.channelId" placeholder="请输入渠道ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="queryParams.unit" placeholder="请输入单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
@ -92,12 +86,12 @@
<el-table-column label="物流商" align="center" prop="logisticsName" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price">
<el-table-column label="基础价格" align="center" sortable prop="price">
<template #default="scope">
<span>{{ scope.row.price + '元/kg' }}</span>
</template>
</el-table-column>
<el-table-column label="时效" align="center" prop="leadTime">
<el-table-column label="时效" align="center" sortable prop="leadTime">
<template #default="scope">
<span>{{ scope.row.leadTime + '天' }}</span>
</template>
@ -129,7 +123,7 @@
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" v-hasRoles="['wuliu']" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button

View File

@ -29,12 +29,7 @@
<el-input v-model="queryParams.sku" placeholder="请输入商品SKU" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="有效期" prop="expiration">
<el-date-picker clearable
v-model="queryParams.expiration"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择有效期"
/>
<el-date-picker clearable v-model="queryParams.expiration" type="date" value-format="YYYY-MM-DD" placeholder="请选择有效期" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@ -49,16 +44,20 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentItem:add']">新增</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentItem:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentItem:edit']">修改</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentItem:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentItem:remove']">删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentItem:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentItem:export']">导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentItem:export']">导出 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -125,11 +124,7 @@
<el-input v-model="form.sku" placeholder="请输入商品SKU" />
</el-form-item>
<el-form-item label="有效期" prop="expiration">
<el-date-picker clearable
v-model="form.expiration"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择有效期">
<el-date-picker clearable v-model="form.expiration" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择有效期">
</el-date-picker>
</el-form-item>
</el-form>
@ -176,10 +171,10 @@ const initFormData: ShipmentItemForm = {
prepInstruction: undefined,
prepOwner: undefined,
sku: undefined,
expiration: undefined,
}
expiration: undefined
};
const data = reactive<PageData<ShipmentItemForm, ShipmentItemQuery>>({
form: {...initFormData},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
@ -192,40 +187,19 @@ const data = reactive<PageData<ShipmentItemForm, ShipmentItemQuery>>({
prepOwner: undefined,
sku: undefined,
expiration: undefined,
params: {
}
params: {}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
shipmentId: [
{ required: true, message: "关联货件ID不能为空", trigger: "blur" }
],
msku: [
{ required: true, message: "商家SKU不能为空", trigger: "blur" }
],
fnsku: [
{ required: true, message: "仓储编码不能为空", trigger: "blur" }
],
quantityShipped: [
{ required: true, message: "发货量不能为空", trigger: "blur" }
],
quantityReceived: [
{ required: true, message: "收货量不能为空", trigger: "blur" }
],
prepInstruction: [
{ required: true, message: "预处理说明不能为空", trigger: "blur" }
],
prepOwner: [
{ required: true, message: "责任方不能为空", trigger: "blur" }
],
sku: [
{ required: true, message: "商品SKU不能为空", trigger: "blur" }
],
expiration: [
{ required: true, message: "有效期不能为空", trigger: "blur" }
],
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
shipmentId: [{ required: true, message: '关联货件ID不能为空', trigger: 'blur' }],
msku: [{ required: true, message: '商家SKU不能为空', trigger: 'blur' }],
fnsku: [{ required: true, message: '仓储编码不能为空', trigger: 'blur' }],
quantityShipped: [{ required: true, message: '发货量不能为空', trigger: 'blur' }],
quantityReceived: [{ required: true, message: '收货量不能为空', trigger: 'blur' }],
prepInstruction: [{ required: true, message: '预处理说明不能为空', trigger: 'blur' }],
prepOwner: [{ required: true, message: '责任方不能为空', trigger: 'blur' }],
sku: [{ required: true, message: '商品SKU不能为空', trigger: 'blur' }],
expiration: [{ required: true, message: '有效期不能为空', trigger: 'blur' }]
}
});
@ -238,55 +212,55 @@ const getList = async () => {
shipmentItemList.value = res.rows;
total.value = res.total;
loading.value = false;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
};
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
form.value = { ...initFormData };
shipmentItemFormRef.value?.resetFields();
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ShipmentItemVO[]) => {
ids.value = selection.map(item => item.id);
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加货品明细";
}
dialog.title = '添加货品明细';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentItemVO) => {
reset();
const _id = row?.id || ids.value[0]
const _id = row?.id || ids.value[0];
const res = await getShipmentItem(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改货品明细";
}
dialog.title = '修改货品明细';
};
/** 提交按钮 */
const submitForm = () => {
@ -294,32 +268,36 @@ const submitForm = () => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateShipmentItem(form.value).finally(() => buttonLoading.value = false);
await updateShipmentItem(form.value).finally(() => (buttonLoading.value = false));
} else {
await addShipmentItem(form.value).finally(() => buttonLoading.value = false);
await addShipmentItem(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess("操作成功");
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: ShipmentItemVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除货品明细编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
await proxy?.$modal.confirm('是否确认删除货品明细编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delShipmentItem(_ids);
proxy?.$modal.msgSuccess("删除成功");
proxy?.$modal.msgSuccess('删除成功');
await getList();
}
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('amz/shipmentItem/export', {
...queryParams.value
}, `shipmentItem_${new Date().getTime()}.xlsx`)
}
proxy?.download(
'amz/shipmentItem/export',
{
...queryParams.value
},
`shipmentItem_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();

View File

@ -1,413 +1,444 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="queryParams.sid" placeholder="请输入关联系统ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="queryParams.shipmentId" placeholder="请输入货件编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="queryParams.shipmentName" placeholder="请输入货件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入物流中心编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="运输模式" prop="shippingMode">
<el-input v-model="queryParams.shippingMode" placeholder="请输入运输模式" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="运输方案" prop="shippingSolution">
<el-input v-model="queryParams.shippingSolution" placeholder="请输入运输方案" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="最后更新时间" prop="gmtModified">
<el-date-picker clearable v-model="queryParams.gmtModified" type="date" value-format="YYYY-MM-DD" placeholder="请选择最后更新时间" />
</el-form-item>
<el-form-item label="创建时间" prop="gmtCreate">
<el-date-picker clearable v-model="queryParams.gmtCreate" type="date" value-format="YYYY-MM-DD" placeholder="请选择创建时间" />
</el-form-item>
<el-form-item label="同步时间" prop="syncTime">
<el-date-picker clearable v-model="queryParams.syncTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择同步时间" />
</el-form-item>
<el-form-item label="计划发货日期" prop="staShipmentDate">
<el-date-picker
clearable
v-model="queryParams.staShipmentDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择计划发货日期"
/>
</el-form-item>
<el-form-item label="预计到货开始日" prop="staDeliveryStartDate">
<el-date-picker
clearable
v-model="queryParams.staDeliveryStartDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择预计到货开始日"
/>
</el-form-item>
<el-form-item label="预计到货截止日" prop="staDeliveryEndDate">
<el-date-picker
clearable
v-model="queryParams.staDeliveryEndDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择预计到货截止日"
/>
</el-form-item>
<el-form-item label="参考编号" prop="referenceId">
<el-input v-model="queryParams.referenceId" placeholder="请输入参考编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="入库计划ID" prop="staInboundPlanId">
<el-input v-model="queryParams.staInboundPlanId" placeholder="请输入入库计划ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentPlan:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentPlan:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentPlan:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentPlan:export']">导出 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="shipmentPlanList" @current-change="handleCurrentChange" highlight-current-row ref="singleTableRef">
<el-table-column type="expand">
<template #default="props">
<el-descriptions size="small" border title="货件详情">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>
<el-descriptions-item label="是否关闭">{{ props.row.isClosed }}</el-descriptions-item>
<el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>
<el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>
<el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>
<el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>
<el-descriptions-item label="同步时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>
<el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>
<el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>
<el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>
</el-descriptions>
</template>
</el-table-column>
<el-table-column label="领星ID" align="center" prop="sid" />
<el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="最后更新时间" align="center" prop="gmtModified" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.gmtModified, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.gmtCreate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column width="150" label="发货地址" align="center" prop="shipFromAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipFromAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column width="150" label="收货地址" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="参考编号" align="center" prop="referenceId" />
<el-table-column label="是否STA计划" align="center" prop="isSta" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"></el-button>
</el-tooltip>
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>-->
<!-- </el-tooltip>-->
<el-tooltip content="发货" placement="top">
<el-button link type="primary" icon="Promotion" @click="handleSend(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="form.sid" placeholder="请输入关联系统ID" />
</el-form-item>
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="form.shipmentId" placeholder="请输入货件编号" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="form.shipmentName" placeholder="请输入货件名称" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入物流中心编码" />
</el-form-item>
<el-form-item label="运输模式" prop="shippingMode">
<el-input v-model="form.shippingMode" placeholder="请输入运输模式" />
</el-form-item>
<el-form-item label="运输方案" prop="shippingSolution">
<el-input v-model="form.shippingSolution" placeholder="请输入运输方案" />
</el-form-item>
<el-form-item label="最后更新时间" prop="gmtModified">
<el-date-picker clearable v-model="form.gmtModified" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择最后更新时间">
</el-date-picker>
</el-form-item>
<el-form-item label="创建时间" prop="gmtCreate">
<el-date-picker clearable v-model="form.gmtCreate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="同步时间" prop="syncTime">
<el-date-picker clearable v-model="form.syncTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择同步时间">
</el-date-picker>
</el-form-item>
<el-form-item label="计划发货日期" prop="staShipmentDate">
<el-date-picker
clearable
v-model="form.staShipmentDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择计划发货日期"
>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到货开始日" prop="staDeliveryStartDate">
<el-date-picker
clearable
v-model="form.staDeliveryStartDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择预计到货开始日"
>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到货截止日" prop="staDeliveryEndDate">
<el-date-picker
clearable
v-model="form.staDeliveryEndDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择预计到货截止日"
>
</el-date-picker>
</el-form-item>
<el-form-item label="参考编号" prop="referenceId">
<el-input v-model="form.referenceId" placeholder="请输入参考编号" />
</el-form-item>
<el-form-item label="入库计划ID" prop="staInboundPlanId">
<el-input v-model="form.staInboundPlanId" placeholder="请输入入库计划ID" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
<el-watermark :content="['Element+', 'Element Plus']">
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="queryParams.sid" placeholder="请输入关联系统ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="queryParams.shipmentId" placeholder="请输入货件编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="queryParams.shipmentName" placeholder="请输入货件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入物流中心编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="运输模式" prop="shippingMode">
<el-input v-model="queryParams.shippingMode" placeholder="请输入运输模式" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="运输方案" prop="shippingSolution">
<el-input v-model="queryParams.shippingSolution" placeholder="请输入运输方案" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="最后更新时间" prop="gmtModified">
<el-date-picker clearable v-model="queryParams.gmtModified" type="date" value-format="YYYY-MM-DD" placeholder="请选择最后更新时间" />
</el-form-item>
<el-form-item label="创建时间" prop="gmtCreate">
<el-date-picker clearable v-model="queryParams.gmtCreate" type="date" value-format="YYYY-MM-DD" placeholder="请选择创建时间" />
</el-form-item>
<el-form-item label="同步时间" prop="syncTime">
<el-date-picker clearable v-model="queryParams.syncTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择同步时间" />
</el-form-item>
<el-form-item label="计划发货日期" prop="staShipmentDate">
<el-date-picker
clearable
v-model="queryParams.staShipmentDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择计划发货日期"
/>
</el-form-item>
<el-form-item label="预计到货开始日" prop="staDeliveryStartDate">
<el-date-picker
clearable
v-model="queryParams.staDeliveryStartDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择预计到货开始日"
/>
</el-form-item>
<el-form-item label="预计到货截止日" prop="staDeliveryEndDate">
<el-date-picker
clearable
v-model="queryParams.staDeliveryEndDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择预计到货截止日"
/>
</el-form-item>
<el-form-item label="参考编号" prop="referenceId">
<el-input v-model="queryParams.referenceId" placeholder="请输入参考编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="入库计划ID" prop="staInboundPlanId">
<el-input v-model="queryParams.staInboundPlanId" placeholder="请输入入库计划ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog v-model="dialogVisible" title="地址详细信息" width="60%">
<el-table :data="addressTableData">
<el-table-column prop="key" label="字段" width="180" />
<el-table-column prop="value" label="值" />
</el-table>
</el-dialog>
</transition>
<el-dialog v-model="channelDialogVisible" title="查询报价" width="60%">
<!-- <el-radio-group v-model="form.status">-->
<!-- <el-radio v-for="dict in biz_transport_channel" :key="dict.value" :value="dict.value">-->
<!-- {{ dict.label }}-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentPlan:add']"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentPlan:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentPlan:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentPlan:export']">导出 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="snycTodayPlan" v-hasPermi="['amz:shipmentPlan:export']"
>同步今天的货件
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<!-- <el-radio-group v-model="form.status">-->
<!-- &lt;!&ndash; 按国家分组循环 &ndash;&gt;-->
<!-- <div v-for="(transportDict, country) in groupedChannels" :key="country">-->
<!-- &lt;!&ndash; 国家标题 &ndash;&gt;-->
<!-- <div class="country-title">{{ country }}</div>-->
<el-table v-loading="loading" :data="shipmentPlanList" @current-change="handleCurrentChange" highlight-current-row ref="singleTableRef">
<el-table-column type="expand">
<template #default="props">
<el-descriptions size="small" border title="货件详情">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>
<el-descriptions-item label="是否关闭">
<dict-tag :options="sys_zero_one" :value="props.row.isClosed" />
</el-descriptions-item>
<!-- <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>-->
<el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>
<!-- &lt;!&ndash; 运输方式子分组 &ndash;&gt;-->
<!-- <div-->
<!-- v-for="(channels, transport) in transportDict"-->
<!-- :key="transport"-->
<!-- class="transport-group"-->
<!-- >-->
<!-- <el-radio-->
<!-- v-for="dict in channels"-->
<!-- :key="dict.value"-->
<!-- :value="dict.value"-->
<!-- border-->
<!-- class="channel-item"-->
<!-- >-->
<!-- {{ transport }} - {{ getChannelName(dict.label) }}-->
<!-- </el-radio>-->
<!-- </div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="目的地仓库">
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<!-- <el-collapse v-model="activeCollapse">-->
<!-- &lt;!&ndash; 遍历国家分组 &ndash;&gt;-->
<!-- <el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">-->
<!-- &lt;!&ndash; 遍历运输方式 &ndash;&gt;-->
<!-- <div v-for="(methodGroup, method) in countryGroup" :key="method">-->
<!-- <div class="shipping-method-title">-->
<!-- {{ getShippingMethodName(method) }}-->
<!-- </div>-->
<!-- <el-radio-group v-model="selectedChannel" @change="handleChannelSelect">-->
<!-- &lt;!&ndash; 遍历具体渠道 &ndash;&gt;-->
<!-- <div v-for="channel in methodGroup" :key="channel.id" class="channel-item">-->
<!-- <el-radio :label="channel.id">-->
<!-- {{ getChannelLabel(channel.channelName) }}-->
<!-- </el-radio>-->
<!-- <div class="channel-description">{{ channel.description }}</div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
</el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="checkPrice()">查询报价</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="dialogTableVisible" title="已经存在的询价单" width="1800">
<el-table :data="tableData" style="width: 100%" border stripe>
<!-- 基础文本列 -->
<el-table-column prop="inquiryNo" label="询价编号" width="180" />
<el-table-column prop="channelName" label="渠道名称" width="200" />
<el-table-column prop="transportChannel" label="运输方式" width="120" />
<el-table-column prop="quoteDate" label="询价日期" width="200" />
<!-- 时间格式化列 -->
<el-table-column prop="deadline" label="截止时间" width="180">
<template #default="{ row }">
{{ formatTime(row.deadline) }}
</template>
</el-table-column>
<el-table-column prop="effectiveStartTime" label="生效开始时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveStartTime) }}
</template>
</el-table-column>
<el-table-column prop="effectiveEndTime" label="生效结束时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveEndTime) }}
</template>
</el-table-column>
<!-- 状态标签列 -->
<el-table-column prop="inquiryStatus" label="询价状态" width="120">
<template #default="{ row }">
<el-tag :type="statusTagType(row.inquiryStatus)" effect="light">
{{ row.inquiryStatus }}
</el-tag>
</template>
</el-table-column>
<!-- 其他信息列 -->
<el-table-column prop="destination" label="目的地" width="120" />
<el-table-column prop="requesterId" label="请求方ID" width="120" />
<!-- 空值处理 -->
<el-table-column prop="targetProviders" label="目标供应商">
<template #default="{ row }">
{{ row.targetProviders || '-' }}
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-drawer size="60%" v-model="drawer" :direction="direction">
<template #header>
<h4>物流商报价</h4>
</template>
<template #default>
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="80">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
<el-descriptions-item label="创建时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>
<!-- <el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
</el-descriptions>
</template>
</el-table-column>
<el-table-column label="领星ID" align="center" prop="sid" />
<el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="商品详情" align="center">
<template #default="scope">
<el-popover placement="top" :width="600" trigger="hover" @show="showPop(scope.row)">
<template #reference>
<el-button style="margin-right: 16px">查看</el-button>
</template>
<el-table :data="scope.row.itemVoList">
<el-table-column width="200" property="productName" label="品名" />
<el-table-column width="200" property="msku" label="msku" />
</el-table>
</el-popover>
</template>
</el-table-column>
<el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="箱子数量" align="center" prop="boxNum" />
<el-table-column label="货件状态" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<el-tag>{{ scope.row.shipmentStatus }}</el-tag>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.staShipmentDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column width="150" label="发货地址" align="center" prop="shipFromAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipFromAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column width="150" label="收货地址" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="是否STA计划" align="center" prop="isSta">
<template #default="scope">
<dict-tag :options="sys_zero_one" :value="scope.row.isSta" />
</template>
</el-table-column>
<el-table-column label="提交状态" align="center" prop="isSubmitted" />
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button text size="small" type="primary" @click="createOrder(scope.row)" v-hasPermi="['amz:logisticsQuote:edit']">
创建货运订单
</el-button>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"></el-button>
</el-tooltip>
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>-->
<!-- </el-tooltip>-->
<el-tooltip content="发货" placement="top">
<el-button link type="primary" icon="Promotion" @click="handleSend(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
</div>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="form.sid" placeholder="请输入关联系统ID" />
</el-form-item>
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="form.shipmentId" placeholder="请输入货件编号" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="form.shipmentName" placeholder="请输入货件名称" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入物流中心编码" />
</el-form-item>
<el-form-item label="运输模式" prop="shippingMode">
<el-input v-model="form.shippingMode" placeholder="请输入运输模式" />
</el-form-item>
<el-form-item label="运输方案" prop="shippingSolution">
<el-input v-model="form.shippingSolution" placeholder="请输入运输方案" />
</el-form-item>
<el-form-item label="最后更新时间" prop="gmtModified">
<el-date-picker clearable v-model="form.gmtModified" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择最后更新时间">
</el-date-picker>
</el-form-item>
<el-form-item label="创建时间" prop="gmtCreate">
<el-date-picker clearable v-model="form.gmtCreate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="同步时间" prop="syncTime">
<el-date-picker clearable v-model="form.syncTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择同步时间">
</el-date-picker>
</el-form-item>
<el-form-item label="计划发货日期" prop="staShipmentDate">
<el-date-picker
clearable
v-model="form.staShipmentDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择计划发货日期"
>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到货开始日" prop="staDeliveryStartDate">
<el-date-picker
clearable
v-model="form.staDeliveryStartDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择预计到货开始日"
>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到货截止日" prop="staDeliveryEndDate">
<el-date-picker
clearable
v-model="form.staDeliveryEndDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择预计到货截止日"
>
</el-date-picker>
</el-form-item>
<el-form-item label="参考编号" prop="referenceId">
<el-input v-model="form.referenceId" placeholder="请输入参考编号" />
</el-form-item>
<el-form-item label="入库计划ID" prop="staInboundPlanId">
<el-input v-model="form.staInboundPlanId" placeholder="请输入入库计划ID" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog v-model="dialogVisible" title="地址详细信息" width="60%">
<el-table :data="addressTableData">
<el-table-column prop="key" label="字段" width="180" />
<el-table-column prop="value" label="值" />
</el-table>
</el-dialog>
<el-dialog v-model="channelDialogVisible" title="查询报价" width="60%">
<!-- <el-radio-group v-model="form.status">-->
<!-- <el-radio v-for="dict in biz_transport_channel" :key="dict.value" :value="dict.value">-->
<!-- {{ dict.label }}-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<!-- <el-radio-group v-model="form.status">-->
<!-- &lt;!&ndash; 按国家分组循环 &ndash;&gt;-->
<!-- <div v-for="(transportDict, country) in groupedChannels" :key="country">-->
<!-- &lt;!&ndash; 国家标题 &ndash;&gt;-->
<!-- <div class="country-title">{{ country }}</div>-->
<!-- &lt;!&ndash; 运输方式子分组 &ndash;&gt;-->
<!-- <div-->
<!-- v-for="(channels, transport) in transportDict"-->
<!-- :key="transport"-->
<!-- class="transport-group"-->
<!-- >-->
<!-- <el-radio-->
<!-- v-for="dict in channels"-->
<!-- :key="dict.value"-->
<!-- :value="dict.value"-->
<!-- border-->
<!-- class="channel-item"-->
<!-- >-->
<!-- {{ transport }} - {{ getChannelName(dict.label) }}-->
<!-- </el-radio>-->
<!-- </div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="目的地仓库">
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<!-- <el-collapse v-model="activeCollapse">-->
<!-- &lt;!&ndash; 遍历国家分组 &ndash;&gt;-->
<!-- <el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">-->
<!-- &lt;!&ndash; 遍历运输方式 &ndash;&gt;-->
<!-- <div v-for="(methodGroup, method) in countryGroup" :key="method">-->
<!-- <div class="shipping-method-title">-->
<!-- {{ getShippingMethodName(method) }}-->
<!-- </div>-->
<!-- <el-radio-group v-model="selectedChannel" @change="handleChannelSelect">-->
<!-- &lt;!&ndash; 遍历具体渠道 &ndash;&gt;-->
<!-- <div v-for="channel in methodGroup" :key="channel.id" class="channel-item">-->
<!-- <el-radio :label="channel.id">-->
<!-- {{ getChannelLabel(channel.channelName) }}-->
<!-- </el-radio>-->
<!-- <div class="channel-description">{{ channel.description }}</div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
</el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="checkPrice()">查询报价</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="dialogTableVisible" title="已经存在的询价单" width="1800">
<el-table :data="tableData" style="width: 100%" border stripe>
<!-- 基础文本列 -->
<el-table-column prop="inquiryNo" label="询价编号" width="180" />
<el-table-column prop="channelName" label="渠道名称" width="200" />
<el-table-column prop="transportChannel" label="运输方式" width="120" />
<el-table-column prop="quoteDate" label="询价日期" width="200" />
<!-- 时间格式化列 -->
<el-table-column prop="deadline" label="截止时间" width="180">
<template #default="{ row }">
{{ formatTime(row.deadline) }}
</template>
</el-table-column>
<el-table-column prop="effectiveStartTime" label="生效开始时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveStartTime) }}
</template>
</el-table-column>
<el-table-column prop="effectiveEndTime" label="生效结束时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveEndTime) }}
</template>
</el-table-column>
<!-- 状态标签列 -->
<el-table-column prop="inquiryStatus" label="询价状态" width="120">
<template #default="{ row }">
<el-tag :type="statusTagType(row.inquiryStatus)" effect="light">
{{ row.inquiryStatus }}
</el-tag>
</template>
</el-table-column>
<!-- 其他信息列 -->
<el-table-column prop="destination" label="目的地" width="120" />
<el-table-column prop="requesterId" label="请求方ID" width="120" />
<!-- 空值处理 -->
<el-table-column prop="targetProviders" label="目标供应商">
<template #default="{ row }">
{{ row.targetProviders || '-' }}
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-drawer size="60%" v-model="drawer" :direction="direction">
<template #header>
<h4>物流商报价</h4>
</template>
<template #default>
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="80">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="提交状态" align="center" prop="isSubmitted" />
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button text size="small" type="primary" @click="createOrder(scope.row)" v-hasPermi="['amz:logisticsQuote:edit']">
创建货运订单
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
</div>
</el-watermark>
</template>
<script setup name="ShipmentPlan" lang="ts">
import { listShipmentPlan, getShipmentPlan, delShipmentPlan, addShipmentPlan, updateShipmentPlan } from '@/api/amz/shipmentPlan';
import {
listShipmentPlan,
getShipmentPlan,
delShipmentPlan,
addShipmentPlan,
updateShipmentPlan,
takeTodayAmzPlanData
} from '@/api/amz/shipmentPlan';
import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel';
import type { DrawerProps } from 'element-plus';
import { createWithDesAndChannel, queryWithDesAndChannel } from '@/api/amz/inquiryRequest';
@ -423,6 +454,8 @@ import { createLogisticsOrder } from '@/api/amz/logisticsOrder';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_transport_channel } = toRefs<any>(proxy?.useDict('biz_transport_channel'));
const { sys_zero_one } = toRefs<any>(proxy?.useDict('sys_zero_one'));
const shipmentPlanList = ref<ShipmentPlanVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -460,7 +493,13 @@ const initFormData: ShipmentPlanForm = {
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined
isSta: undefined,
boxQuantity: undefined,
boxSize: undefined,
logisticsWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined
};
const data = reactive<PageData<ShipmentPlanForm, ShipmentPlanQuery>>({
form: { ...initFormData },
@ -486,6 +525,12 @@ const data = reactive<PageData<ShipmentPlanForm, ShipmentPlanQuery>>({
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
boxQuantity: undefined,
boxSize: undefined,
logisticsWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined,
params: {}
},
rules: {
@ -532,6 +577,7 @@ const createOrder = async (row: ShipmentPlanVO) => {
} else {
ElMessage.error('创建失败');
}
drawer.value = false;
};
const dialogTableVisible = ref(false);
@ -598,7 +644,7 @@ const cascaderChange = (value) => {
};
function confirmClick() {
ElMessageBox.confirm(`Are you confirm to chose ${radio1.value} ?`)
ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`)
.then(() => {
drawer.value = false;
})
@ -688,8 +734,8 @@ function transformChannels(channels) {
return result;
}
const currentDes = ref('');
const currentFBAData = ref('');
const currentDes = ref<string | number>('');
const currentFBAData = ref<ShipmentPlanVO>();
//
const groupedChannels = computed(() => {
@ -781,24 +827,26 @@ const checkPrice = async () => {
if (requestQuote.total == 0) {
console.log('询价单也没数据');
channelDialogVisible.value = false;
ElMessageBox.confirm('未查询到价格信息,是否要向物流商发布询价?', 'Warning', {
ElMessageBox.confirm('未查询到价格信息,是否要向物流商发布询价?', '提醒', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
ElMessage({
type: 'success',
message: 'Delete completed'
});
const res2 = await createWithDesAndChannel(currentDes.value, selectedChannel.value, shipDate.value);
console.log('checkPriceEnd2', res2);
if (res2.code == 200) {
ElMessage({
type: 'success',
message: '询价单创建成功'
});
}
})
.catch(() => {
ElMessage({
type: 'info',
message: 'Delete canceled'
});
// ElMessage({
// type: 'info',
// message: 'Delete canceled'
// });
});
} else {
//
@ -833,6 +881,15 @@ const handleSend = async (row?: ShipmentPlanVO) => {
currentFBAData.value = row;
currentDes.value = row.destination;
};
const snycTodayPlan = async () => {
const res = await takeTodayAmzPlanData();
if (res.code == 200) {
proxy?.$modal.msgSuccess('同步成功');
await getList();
}
};
/** 提交按钮 */
const submitForm = () => {
shipmentPlanFormRef.value?.validate(async (valid: boolean) => {

View File

@ -0,0 +1,907 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="queryParams.shipmentId" placeholder="请输入货件编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="queryParams.shipmentName" placeholder="请输入货件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入物流中心编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasRoles="['superadmin']" v-hasPermi="['amz:shipmentPlan:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentPlan:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentPlan:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentPlan:export']">导出 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="snycTodayPlan" v-hasPermi="['amz:shipmentPlan:export']"
>同步今天的货件
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="shipmentPlanList" @current-change="handleCurrentChange" highlight-current-row ref="singleTableRef">
<el-table-column type="expand">
<template #default="props">
<el-descriptions size="small" border title="货件详情">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>
<!-- <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>-->
<el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>
<!-- <el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
</el-descriptions>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.staShipmentDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="店铺名称" align="center" prop="sellerName" />
<el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="商品详情" align="center">
<template #default="scope">
<el-popover placement="top" :width="600" trigger="hover" @show="showPop(scope.row)">
<template #reference>
<el-button style="margin-right: 16px">查看</el-button>
</template>
<el-table :data="scope.row.itemVoList">
<el-table-column width="200" property="productName" label="品名" />
<el-table-column width="200" property="msku" label="msku" />
<el-table-column width="150" property="asin" label="asin" />
</el-table>
</el-popover>
</template>
</el-table-column>
<el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="总箱子数量" align="center" prop="boxQuantity" />
<el-table-column label="箱子尺寸" align="center" prop="boxSize" />
<el-table-column label="供应商称重" align="center" prop="vendorWeight" />
<el-table-column label="套数" align="center" prop="setTotal" />
<!-- <el-table-column label="渠道ID" align="center" prop="channelId" />-->
<el-table-column width="150" label="仓库配送地址" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="亚马逊货件状态" align="center" width="180">
<template #default="scope">
<el-tag>{{ scope.row.shipmentStatus }}</el-tag>
</template>
</el-table-column>
<el-table-column label="物流渠道" align="center" prop="channelName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"></el-button>
</el-tooltip>
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>-->
<!-- </el-tooltip>-->
<el-button link type="primary" size="small" @click="handleSend(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']">询价 </el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="form.shipmentId" placeholder="请输入货件编号" disabled />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="form.shipmentName" placeholder="请输入货件名称" disabled />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入物流中心编码" disabled />
</el-form-item>
<el-form-item label="物流渠道">
<el-cascader
ref="channelCascaderRef"
v-model="selectedChannel"
:props="{ emitPath: false }"
placeholder="请选择渠道"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="总箱子数量" prop="boxQuantity">
<el-input v-model="form.boxQuantity" placeholder="请输入总箱子数量" />
</el-form-item>
<el-form-item label="箱子尺寸" prop="boxSize">
<el-input v-model="form.boxSize" placeholder="请输入箱子尺寸" />
</el-form-item>
<el-form-item label="供应商称重" prop="vendorWeight">
<el-input v-model="form.vendorWeight" placeholder="请输入供应商称重" />
</el-form-item>
<el-form-item label="套数" prop="setTotal">
<el-input v-model="form.setTotal" placeholder="请输入套数" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog v-model="dialogVisible" title="地址详细信息" width="60%">
<el-table :data="addressTableData">
<el-table-column prop="key" label="字段" width="180" />
<el-table-column prop="value" label="值" />
</el-table>
</el-dialog>
<el-dialog v-model="channelDialogVisible" title="查询报价" width="60%">
<!-- <el-radio-group v-model="form.status">-->
<!-- <el-radio v-for="dict in biz_transport_channel" :key="dict.value" :value="dict.value">-->
<!-- {{ dict.label }}-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<!-- <el-radio-group v-model="form.status">-->
<!-- &lt;!&ndash; 按国家分组循环 &ndash;&gt;-->
<!-- <div v-for="(transportDict, country) in groupedChannels" :key="country">-->
<!-- &lt;!&ndash; 国家标题 &ndash;&gt;-->
<!-- <div class="country-title">{{ country }}</div>-->
<!-- &lt;!&ndash; 运输方式子分组 &ndash;&gt;-->
<!-- <div-->
<!-- v-for="(channels, transport) in transportDict"-->
<!-- :key="transport"-->
<!-- class="transport-group"-->
<!-- >-->
<!-- <el-radio-->
<!-- v-for="dict in channels"-->
<!-- :key="dict.value"-->
<!-- :value="dict.value"-->
<!-- border-->
<!-- class="channel-item"-->
<!-- >-->
<!-- {{ transport }} - {{ getChannelName(dict.label) }}-->
<!-- </el-radio>-->
<!-- </div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="目的地仓库">
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<!-- <el-collapse v-model="activeCollapse">-->
<!-- &lt;!&ndash; 遍历国家分组 &ndash;&gt;-->
<!-- <el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">-->
<!-- &lt;!&ndash; 遍历运输方式 &ndash;&gt;-->
<!-- <div v-for="(methodGroup, method) in countryGroup" :key="method">-->
<!-- <div class="shipping-method-title">-->
<!-- {{ getShippingMethodName(method) }}-->
<!-- </div>-->
<!-- <el-radio-group v-model="selectedChannel" @change="handleChannelSelect">-->
<!-- &lt;!&ndash; 遍历具体渠道 &ndash;&gt;-->
<!-- <div v-for="channel in methodGroup" :key="channel.id" class="channel-item">-->
<!-- <el-radio :label="channel.id">-->
<!-- {{ getChannelLabel(channel.channelName) }}-->
<!-- </el-radio>-->
<!-- <div class="channel-description">{{ channel.description }}</div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
</el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="checkPrice()">查询报价</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="dialogTableVisible" title="已经存在的询价单" width="1800">
<el-table :data="tableData" style="width: 100%" border stripe>
<!-- 基础文本列 -->
<el-table-column prop="inquiryNo" label="询价编号" width="180" />
<el-table-column prop="channelName" label="渠道名称" width="200" />
<el-table-column prop="transportChannel" label="运输方式" width="120" />
<el-table-column prop="quoteDate" label="询价日期" width="200" />
<!-- 时间格式化列 -->
<el-table-column prop="deadline" label="截止时间" width="180">
<template #default="{ row }">
{{ formatTime(row.deadline) }}
</template>
</el-table-column>
<el-table-column prop="effectiveStartTime" label="生效开始时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveStartTime) }}
</template>
</el-table-column>
<el-table-column prop="effectiveEndTime" label="生效结束时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveEndTime) }}
</template>
</el-table-column>
<!-- 状态标签列 -->
<el-table-column prop="inquiryStatus" label="询价状态" width="120">
<template #default="{ row }">
<el-tag :type="statusTagType(row.inquiryStatus)" effect="light">
{{ row.inquiryStatus }}
</el-tag>
</template>
</el-table-column>
<!-- 其他信息列 -->
<el-table-column prop="destination" label="目的地" width="120" />
<el-table-column prop="requesterId" label="请求方ID" width="120" />
<!-- 空值处理 -->
<el-table-column prop="targetProviders" label="目标供应商">
<template #default="{ row }">
{{ row.targetProviders || '-' }}
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-drawer size="60%" v-model="drawer" :direction="direction">
<template #header>
<h4>物流商报价</h4>
</template>
<template #default>
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="80">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="提交状态" align="center" prop="isSubmitted" />
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button text size="small" type="primary" @click="createOrder(scope.row)" v-hasPermi="['amz:logisticsQuote:edit']">
创建货运订单
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
</div>
</template>
<script setup name="ShipmentPlan" lang="ts">
import {
listShipmentPlan,
getShipmentPlan,
delShipmentPlan,
addShipmentPlan,
updateShipmentPlan,
takeTodayAmzPlanData
} from '@/api/amz/shipmentPlan';
import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel';
import type { DrawerProps } from 'element-plus';
import { createWithDesAndChannel, queryWithDesAndChannel } from '@/api/amz/inquiryRequest';
import { queryLogisticsQuote } from '@/api/amz/logisticsQuote';
import { ShipmentPlanVO, ShipmentPlanQuery, ShipmentPlanForm } from '@/api/amz/shipmentPlan/types';
import { ElTable } from 'element-plus';
import { LogisticsQuoteVO } from '@/api/amz/logisticsQuote/types';
import { createOrderForm } from '@/api/amz/logisticsOrder/types';
import { createLogisticsOrder } from '@/api/amz/logisticsOrder';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_transport_channel } = toRefs<any>(proxy?.useDict('biz_transport_channel'));
const { sys_zero_one } = toRefs<any>(proxy?.useDict('sys_zero_one'));
const shipmentPlanList = ref<ShipmentPlanVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const shipmentPlanFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: ShipmentPlanForm = {
id: undefined,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
boxQuantity: undefined,
boxSize: undefined,
vendorWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined
};
const data = reactive<PageData<ShipmentPlanForm, ShipmentPlanQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
fbaStatus: 'ask',
boxQuantity: undefined,
boxSize: undefined,
vendorWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
sid: [{ required: true, message: '关联系统ID不能为空', trigger: 'blur' }],
shipmentId: [{ required: true, message: '货件编号不能为空', trigger: 'blur' }],
shipmentName: [{ required: true, message: '货件名称不能为空', trigger: 'blur' }],
isClosed: [{ required: true, message: '是否关闭不能为空', trigger: 'blur' }],
shipmentStatus: [{ required: true, message: '货件状态不能为空', trigger: 'change' }],
destination: [{ required: true, message: '物流中心编码不能为空', trigger: 'blur' }],
shippingMode: [{ required: true, message: '运输模式不能为空', trigger: 'blur' }],
shippingSolution: [{ required: true, message: '运输方案不能为空', trigger: 'blur' }],
gmtModified: [{ required: true, message: '最后更新时间不能为空', trigger: 'blur' }],
gmtCreate: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }],
syncTime: [{ required: true, message: '同步时间不能为空', trigger: 'blur' }],
staShipmentDate: [{ required: true, message: '计划发货日期不能为空', trigger: 'blur' }],
staDeliveryStartDate: [{ required: true, message: '预计到货开始日不能为空', trigger: 'blur' }],
staDeliveryEndDate: [{ required: true, message: '预计到货截止日不能为空', trigger: 'blur' }],
shipFromAddress: [{ required: true, message: '发货地址不能为空', trigger: 'blur' }],
shipToAddress: [{ required: true, message: '收货地址不能为空', trigger: 'blur' }],
referenceId: [{ required: true, message: '参考编号不能为空', trigger: 'blur' }],
staInboundPlanId: [{ required: true, message: '入库计划ID不能为空', trigger: 'blur' }],
isSta: [{ required: true, message: '是否STA计划不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
const createOrderData = ref<createOrderForm>({
fbaShipmentId: undefined,
logicQuoteId: undefined
});
const createOrder = async (row: ShipmentPlanVO) => {
//
console.log('row', row);
console.log('currentFBAData', currentFBAData.value);
createOrderData.value.fbaShipmentId = currentFBAData.value.shipmentId;
createOrderData.value.logicQuoteId = row.id;
const res = await createLogisticsOrder(createOrderData.value);
console.log('res', res);
if (res.code === 200) {
ElMessage.success('创建成功');
} else {
ElMessage.error('创建失败');
}
drawer.value = false;
};
const dialogTableVisible = ref(false);
const logisticsQuoteList = ref<LogisticsQuoteVO[]>([]);
const tableData = ref([
{
channelId: '1902912289404719106',
channelName: '美国-海运-美森正班船',
deadline: '2025-03-22 11:00:00',
destination: 'LGB8',
effectiveEndTime: '2025-03-30 15:30:19',
effectiveStartTime: '2025-03-23 15:30:19',
id: '1903348528587018242',
inquiryNo: 'INQ20250322000004',
inquiryStatus: 'OPEN',
quoteDate: '2025-03-22 00:00:00',
requesterId: 1,
targetProviders: null,
transportChannel: 'sea'
}
]);
//
const formatTime = (timeString) => {
return timeString.replace(' ', '\n'); //
};
//
const statusTagType = (status) => {
switch (status) {
case 'OPEN':
return 'success';
case 'CLOSED':
return 'info';
case 'EXPIRED':
return 'warning';
default:
return '';
}
};
const drawer = ref(false);
const direction = ref<DrawerProps['direction']>('ltr');
const radio1 = ref('Option 1');
const handleClose = (done: () => void) => {
ElMessageBox.confirm('Are you sure you want to close this?')
.then(() => {
done();
})
.catch(() => {
// catch error
});
};
function cancelClick() {
drawer.value = false;
}
const channelCascaderRef = ref(null);
const cascaderChange = (value) => {
console.log(value);
console.log('selectedChannel', selectedChannel);
console.log('groupedChannels', groupedChannels);
// console.log('channelCascaderRef', channelCascaderRef);
console.log('label====', channelCascaderRef.value.getCheckedNodes()[0].label);
};
function confirmClick() {
ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`)
.then(() => {
drawer.value = false;
})
.catch(() => {
// catch error
});
}
const getLocalDate = () => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const shipDate = ref(getLocalDate());
/** 查询货件计划列表 */
const getList = async () => {
loading.value = true;
const res = await listShipmentPlan(queryParams.value);
shipmentPlanList.value = res.rows;
total.value = res.total;
loading.value = false;
};
let channelTableData = ref([]);
const getAllChannelData = async () => {
const res = await listAllLogisticsChannel();
console.log('getAllChannelData');
console.log(res);
channelTableData.value = res.rows;
console.log('groupedChannels:', groupedChannels.value);
};
//
const countryMap = {
us: '美国'
//
};
const shippingMethodMap = {
air: '空运',
sea: '海运'
//
};
function transformChannels(channels) {
const result = [];
const countryGroups = {}; //
channels.forEach((channel) => {
const { country, shippingMethod, channelName, id } = channel;
//
const countryValue = country;
const countryLabel = countryMap[country] || country;
if (!countryGroups[countryValue]) {
countryGroups[countryValue] = {
value: countryValue,
label: countryLabel,
children: []
};
result.push(countryGroups[countryValue]);
}
//
const methodValue = shippingMethod;
const methodLabel = shippingMethodMap[shippingMethod] || shippingMethod;
let methodNode = countryGroups[countryValue].children.find((m) => m.value === methodValue);
if (!methodNode) {
methodNode = {
value: methodValue,
label: methodLabel,
children: []
};
countryGroups[countryValue].children.push(methodNode);
}
//
methodNode.children.push({
value: id,
label: channelName
});
});
return result;
}
const currentDes = ref<string | number>('');
const currentFBAData = ref<ShipmentPlanVO>();
//
const groupedChannels = computed(() => {
// return channelTableData.value.reduce((acc, channel) => {
// const country = channel.country;
// const method = channel.shippingMethod;
//
// if (!acc[country]) acc[country] = {};
// if (!acc[country][method]) acc[country][method] = [];
//
// acc[country][method].push(channel);
// return acc;
// }, {});
return transformChannels(channelTableData.value);
});
// +
const getChannelLabel = (name) => {
return name.split('-').slice(2).join('-');
};
//
const getCountryName = (code) => {
return countryMap[code] || code.toUpperCase();
};
//
const getShippingMethodName = (method) => {
return shippingMethodMap[method] || method;
};
//
const activeCollapse = ref(['us']); //
const selectedChannel = ref(null);
const handleChannelSelect = (channelId) => {
console.log('Selected channel ID:', channelId);
// API
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
shipmentPlanFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ShipmentPlanVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加货件计划';
};
const checkPrice = async () => {
form.value.fbaStatus = 'send';
console.log('checkPrice', currentDes.value, selectedChannel.value);
//
console.log('sshipDate.value', shipDate.value);
if (currentFBAData.value.channelId == null) {
ElMessage({
type: 'warning',
message: '请先设置渠道!'
});
return;
}
const updateForm = ref({
id: currentFBAData.value.id,
fbaStatus: 'send'
});
await updateShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
const res = await queryLogisticsQuote(currentDes.value, currentFBAData.value.channelId, shipDate.value);
console.log('查询报价单', res);
if (res.total == 0) {
//
const requestQuote = await queryWithDesAndChannel(currentDes.value, currentFBAData.value.channelId, shipDate.value);
console.log('查询询价单', requestQuote);
if (requestQuote.total == 0) {
console.log('询价单也没数据');
channelDialogVisible.value = false;
const res2 = await createWithDesAndChannel(currentDes.value, currentFBAData.value.channelId, shipDate.value);
console.log('checkPriceEnd2', res2);
if (res2.code == 200) {
ElMessage({
type: 'success',
message: '询价单创建成功'
});
}
} else {
//
// channelDialogVisible.value = false;
// dialogTableVisible.value = true;
// tableData.value = requestQuote.rows;
// console.log('requestQuote.rows', requestQuote.rows);
// console.log('tableData', tableData.value);
ElMessage.success('已经有人询价了');
}
} else {
//
ElMessage.success('已经有人报价了');
// channelDialogVisible.value = false;
// drawer.value = true;
// logisticsQuoteList.value = res.rows;
}
getList();
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentPlanVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getShipmentPlan(_id);
Object.assign(form.value, res.data);
console.log('form.value', form.value);
selectedChannel.value = res.data.channelId;
console.log('selectedChannel', selectedChannel);
dialog.visible = true;
dialog.title = '修改货件计划';
};
const handleSend = async (row?: ShipmentPlanVO) => {
// reset();
// channelDialogVisible.value = true;
console.log(row);
currentFBAData.value = row;
currentDes.value = row.destination;
checkPrice();
};
const showPop = async (row: any) => {
console.log('row', row);
};
const snycTodayPlan = async () => {
const res = await takeTodayAmzPlanData();
if (res.code == 200) {
proxy?.$modal.msgSuccess('同步成功');
await getList();
}
};
/** 提交按钮 */
const submitForm = () => {
console.log('selectedChannel', selectedChannel);
console.log('groupedChannels', groupedChannels);
// console.log('channelCascaderRef', channelCascaderRef);
console.log('label====', channelCascaderRef.value.getCheckedNodes()[0].label);
form.value.channelName = channelCascaderRef.value.getCheckedNodes()[0].label;
form.value.channelId = selectedChannel;
const updateForm = ref({
id: form.value.id,
boxQuantity: form.value.boxQuantity,
boxSize: form.value.boxSize,
vendorWeight: form.value.vendorWeight,
setTotal: form.value.setTotal,
channelId: selectedChannel,
channelName: channelCascaderRef.value.getCheckedNodes()[0].label
});
shipmentPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (updateForm.value.id) {
await updateShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
} else {
await addShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: ShipmentPlanVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除货件计划编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delShipmentPlan(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'amz/shipmentPlan/export',
{
...queryParams.value
},
`shipmentPlan_${new Date().getTime()}.xlsx`
);
};
const dialogVisible = ref(false);
const addressTableData = ref([]);
const channelDialogVisible = ref(false);
//
const convertAddressToTableData = (address) => {
return Object.entries(address).map(([key, value]) => ({
key: key,
value: value
}));
};
//
const openAddressDialog = (address) => {
addressTableData.value = convertAddressToTableData(address);
dialogVisible.value = true;
};
const currentRow = ref();
const singleTableRef = ref<InstanceType<typeof ElTable>>();
const handleCurrentChange = (val: ShipmentPlanVO | undefined) => {
currentRow.value = val;
};
onMounted(() => {
getList();
getAllChannelData();
});
</script>

View File

@ -0,0 +1,883 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="queryParams.shipmentId" placeholder="请输入货件编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="queryParams.shipmentName" placeholder="请输入货件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入物流中心编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasRoles="['superadmin']" v-hasPermi="['amz:shipmentPlan:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate()"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:remove']"
>删除
</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentPlan:export']">导出 </el-button>-->
<!-- </el-col>-->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="shipmentPlanList" @current-change="handleCurrentChange" highlight-current-row ref="singleTableRef">
<el-table-column type="expand">
<template #default="props">
<el-descriptions size="small" border title="货件详情">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>
<!-- <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>-->
<el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ props.row.gmtCreate }}</el-descriptions-item>
<!-- <el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>
-->
<el-descriptions-item label="时效">{{ props.row.quote.leadTime + ' 天' }}</el-descriptions-item>
<el-descriptions-item label="订单创建时间">{{ props.row.order.createTime }}</el-descriptions-item>
<el-descriptions-item label="亚马逊接收日期">{{ props.row.receivingTime }}</el-descriptions-item>
<el-descriptions-item label="上架天数">{{ props.row.order.createTime }}</el-descriptions-item>
</el-descriptions>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.staShipmentDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="店铺名称" align="center" prop="sellerName" />
<el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="商品详情" align="center">
<template #default="scope">
<el-popover placement="top" :width="600" trigger="hover" @show="showPop(scope.row)">
<template #reference>
<el-button style="margin-right: 16px">查看</el-button>
</template>
<el-table :data="scope.row.itemVoList">
<el-table-column width="200" property="productName" label="品名" />
<el-table-column width="200" property="msku" label="msku" />
<el-table-column width="150" property="asin" label="asin" />
</el-table>
</el-popover>
</template>
</el-table-column>
<el-table-column width="150" label="货件明细" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openDetailDialog(row.detailList)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="总箱子数量" align="center" prop="boxQuantity" />
<el-table-column label="箱子尺寸" align="center" prop="boxSize" />
<el-table-column label="供应商称重" align="center" prop="vendorWeight" />
<el-table-column label="套数" align="center" prop="setTotal" />
<!-- <el-table-column label="渠道ID" align="center" prop="channelId" />-->
<el-table-column width="150" label="仓库配送地址" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="亚马逊货件状态" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<el-tag>{{ scope.row.shipmentStatus }}</el-tag>
</template>
</el-table-column>
<el-table-column label="物流渠道" align="center" prop="channelName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="发货" placement="top">
<el-button
link
type="primary"
icon="Promotion"
@click="handleSend(scope.row)"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="form.sid" placeholder="请输入关联系统ID" />
</el-form-item>
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="form.shipmentId" placeholder="请输入货件编号" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="form.shipmentName" placeholder="请输入货件名称" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入物流中心编码" />
</el-form-item>
<el-form-item label="运输模式" prop="shippingMode">
<el-input v-model="form.shippingMode" placeholder="请输入运输模式" />
</el-form-item>
<el-form-item label="运输方案" prop="shippingSolution">
<el-input v-model="form.shippingSolution" placeholder="请输入运输方案" />
</el-form-item>
<el-form-item label="最后更新时间" prop="gmtModified">
<el-date-picker clearable v-model="form.gmtModified" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择最后更新时间">
</el-date-picker>
</el-form-item>
<el-form-item label="创建时间" prop="gmtCreate">
<el-date-picker clearable v-model="form.gmtCreate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择创建时间">
</el-date-picker>
</el-form-item>
<el-form-item label="参考编号" prop="referenceId">
<el-input v-model="form.referenceId" placeholder="请输入参考编号" />
</el-form-item>
<el-form-item label="入库计划ID" prop="staInboundPlanId">
<el-input v-model="form.staInboundPlanId" placeholder="请输入入库计划ID" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog v-model="dialogVisible" title="地址详细信息" width="60%">
<el-table :data="addressTableData">
<el-table-column prop="key" label="字段" width="180" />
<el-table-column prop="value" label="值" />
</el-table>
</el-dialog>
<el-dialog v-model="detailDialogVisible" title="货件明细" width="60%">
<el-table :data="detailTableData">
<el-table-column label="FBA货件编号" align="center" prop="fbaShipmentId" />
<el-table-column label="FBA箱号" align="center" prop="fbaBoxNumber" />
<el-table-column label="物流商名称" align="center" prop="logisticsProviderName" />
<el-table-column label="实际货件数量" align="center" prop="shipmentQuantity" />
<el-table-column label="物流称重" align="center" prop="logisticsWeight">
<template #default="scope">
{{ scope.row.logisticsWeight != null ? `${scope.row.logisticsWeight} kg` : '' }}
</template>
</el-table-column>
<el-table-column label="物流追踪号" align="center" prop="trackingNumber">
<template #default="scope">
<el-link :underline="true" type="success" :href="`https://t.17track.net/zh-cn#nums=${scope.row.trackingNumber}`" target="_blank">
{{ scope.row.trackingNumber }}
</el-link>
</template>
</el-table-column>
<el-table-column label="物流状态" align="center" prop="logisticsStatus">
<template #default="scope">
<dict-tag :options="biz_logistics_status" :value="scope.row.logisticsStatus" />
</template>
</el-table-column>
<el-table-column label="更新时间" align="center" prop="updateTime" />
</el-table>
</el-dialog>
<el-dialog v-model="channelDialogVisible" title="查询报价" width="60%">
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="目的地仓库">
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
</el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="checkPrice()">查询报价</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="dialogTableVisible" title="已经存在的询价单" width="1800">
<el-table :data="tableData" style="width: 100%" border stripe>
<!-- 基础文本列 -->
<el-table-column prop="inquiryNo" label="询价编号" width="180" />
<el-table-column prop="channelName" label="渠道名称" width="200" />
<el-table-column prop="transportChannel" label="运输方式" width="120" />
<el-table-column prop="quoteDate" label="询价日期" width="200" />
<!-- 时间格式化列 -->
<el-table-column prop="deadline" label="截止时间" width="180">
<template #default="{ row }">
{{ formatTime(row.deadline) }}
</template>
</el-table-column>
<el-table-column prop="effectiveStartTime" label="生效开始时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveStartTime) }}
</template>
</el-table-column>
<el-table-column prop="effectiveEndTime" label="生效结束时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveEndTime) }}
</template>
</el-table-column>
<!-- 状态标签列 -->
<el-table-column prop="inquiryStatus" label="询价状态" width="120">
<template #default="{ row }">
<el-tag :type="statusTagType(row.inquiryStatus)" effect="light">
{{ row.inquiryStatus }}
</el-tag>
</template>
</el-table-column>
<!-- 其他信息列 -->
<el-table-column prop="destination" label="目的地" width="120" />
<el-table-column prop="requesterId" label="请求方ID" width="120" />
<!-- 空值处理 -->
<el-table-column prop="targetProviders" label="目标供应商">
<template #default="{ row }">
{{ row.targetProviders || '-' }}
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-drawer size="60%" v-model="drawer" :direction="direction">
<template #header>
<h4>物流商报价</h4>
</template>
<template #default>
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="80">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="提交状态" align="center" prop="isSubmitted" />
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button text size="small" type="primary" @click="createOrder(scope.row)" v-hasPermi="['amz:logisticsQuote:edit']">
创建货运订单
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
</div>
</template>
<script setup name="ShipmentPlan" lang="ts">
import {
listShipmentPlan,
getShipmentPlan,
delShipmentPlan,
addShipmentPlan,
updateShipmentPlan,
takeTodayAmzPlanData,
listShipmentPlanOrder
} from '@/api/amz/shipmentPlan';
import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel';
import type { DrawerProps } from 'element-plus';
import { createWithDesAndChannel, queryWithDesAndChannel } from '@/api/amz/inquiryRequest';
import { queryLogisticsQuote } from '@/api/amz/logisticsQuote';
import { ShipmentPlanVO, ShipmentPlanQuery, ShipmentPlanForm, ShipmentPlanOrderVO } from '@/api/amz/shipmentPlan/types';
import { ElTable } from 'element-plus';
import { LogisticsQuoteVO } from '@/api/amz/logisticsQuote/types';
import { createOrderForm } from '@/api/amz/logisticsOrder/types';
import { createLogisticsOrder } from '@/api/amz/logisticsOrder';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_logistics_status } = toRefs<any>(proxy?.useDict('biz_logistics_status'));
const { sys_zero_one } = toRefs<any>(proxy?.useDict('sys_zero_one'));
const shipmentPlanList = ref<ShipmentPlanOrderVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const shipmentPlanFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: ShipmentPlanForm = {
id: undefined,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined
};
const data = reactive<PageData<ShipmentPlanForm, ShipmentPlanQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
fbaStatus: 'query',
params: {}
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
sid: [{ required: true, message: '关联系统ID不能为空', trigger: 'blur' }],
shipmentId: [{ required: true, message: '货件编号不能为空', trigger: 'blur' }],
shipmentName: [{ required: true, message: '货件名称不能为空', trigger: 'blur' }],
isClosed: [{ required: true, message: '是否关闭不能为空', trigger: 'blur' }],
shipmentStatus: [{ required: true, message: '货件状态不能为空', trigger: 'change' }],
destination: [{ required: true, message: '物流中心编码不能为空', trigger: 'blur' }],
shippingMode: [{ required: true, message: '运输模式不能为空', trigger: 'blur' }],
shippingSolution: [{ required: true, message: '运输方案不能为空', trigger: 'blur' }],
gmtModified: [{ required: true, message: '最后更新时间不能为空', trigger: 'blur' }],
gmtCreate: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }],
syncTime: [{ required: true, message: '同步时间不能为空', trigger: 'blur' }],
staShipmentDate: [{ required: true, message: '计划发货日期不能为空', trigger: 'blur' }],
staDeliveryStartDate: [{ required: true, message: '预计到货开始日不能为空', trigger: 'blur' }],
staDeliveryEndDate: [{ required: true, message: '预计到货截止日不能为空', trigger: 'blur' }],
shipFromAddress: [{ required: true, message: '发货地址不能为空', trigger: 'blur' }],
shipToAddress: [{ required: true, message: '收货地址不能为空', trigger: 'blur' }],
referenceId: [{ required: true, message: '参考编号不能为空', trigger: 'blur' }],
staInboundPlanId: [{ required: true, message: '入库计划ID不能为空', trigger: 'blur' }],
isSta: [{ required: true, message: '是否STA计划不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
const createOrderData = ref<createOrderForm>({
fbaShipmentId: undefined,
logicQuoteId: undefined
});
const showPop = async (row: any) => {
console.log('row', row);
};
const createOrder = async (row: ShipmentPlanVO) => {
//
console.log('row', row);
console.log('currentFBAData', currentFBAData.value);
createOrderData.value.fbaShipmentId = currentFBAData.value.shipmentId;
createOrderData.value.logicQuoteId = row.id;
const res = await createLogisticsOrder(createOrderData.value);
console.log('res', res);
if (res.code === 200) {
ElMessage.success('创建成功');
} else {
ElMessage.error('创建失败');
}
drawer.value = false;
};
const dialogTableVisible = ref(false);
const logisticsQuoteList = ref<LogisticsQuoteVO[]>([]);
const tableData = ref([
{
channelId: '1902912289404719106',
channelName: '美国-海运-美森正班船',
deadline: '2025-03-22 11:00:00',
destination: 'LGB8',
effectiveEndTime: '2025-03-30 15:30:19',
effectiveStartTime: '2025-03-23 15:30:19',
id: '1903348528587018242',
inquiryNo: 'INQ20250322000004',
inquiryStatus: 'OPEN',
quoteDate: '2025-03-22 00:00:00',
requesterId: 1,
targetProviders: null,
transportChannel: 'sea'
}
]);
//
const formatTime = (timeString) => {
return timeString.replace(' ', '\n'); //
};
//
const statusTagType = (status) => {
switch (status) {
case 'OPEN':
return 'success';
case 'CLOSED':
return 'info';
case 'EXPIRED':
return 'warning';
default:
return '';
}
};
const drawer = ref(false);
const direction = ref<DrawerProps['direction']>('ltr');
const radio1 = ref('Option 1');
const handleClose = (done: () => void) => {
ElMessageBox.confirm('Are you sure you want to close this?')
.then(() => {
done();
})
.catch(() => {
// catch error
});
};
function cancelClick() {
drawer.value = false;
}
const cascaderChange = (value) => {
console.log(value);
console.log('selectedChannel', selectedChannel);
};
function confirmClick() {
ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`)
.then(() => {
drawer.value = false;
})
.catch(() => {
// catch error
});
}
const getLocalDate = () => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const shipDate = ref(getLocalDate());
/** 查询货件计划列表 */
const getList = async () => {
loading.value = true;
const res = await listShipmentPlanOrder(queryParams.value);
shipmentPlanList.value = res.rows;
total.value = res.total;
loading.value = false;
};
let channelTableData = ref([]);
const getAllChannelData = async () => {
const res = await listAllLogisticsChannel();
console.log('getAllChannelData');
console.log(res);
channelTableData.value = res.rows;
console.log('groupedChannels:', groupedChannels.value);
};
//
const countryMap = {
us: '美国'
//
};
const shippingMethodMap = {
air: '空运',
sea: '海运'
//
};
function transformChannels(channels) {
const result = [];
const countryGroups = {}; //
channels.forEach((channel) => {
const { country, shippingMethod, channelName, id } = channel;
//
const countryValue = country;
const countryLabel = countryMap[country] || country;
if (!countryGroups[countryValue]) {
countryGroups[countryValue] = {
value: countryValue,
label: countryLabel,
children: []
};
result.push(countryGroups[countryValue]);
}
//
const methodValue = shippingMethod;
const methodLabel = shippingMethodMap[shippingMethod] || shippingMethod;
let methodNode = countryGroups[countryValue].children.find((m) => m.value === methodValue);
if (!methodNode) {
methodNode = {
value: methodValue,
label: methodLabel,
children: []
};
countryGroups[countryValue].children.push(methodNode);
}
//
methodNode.children.push({
value: id,
label: channelName
});
});
return result;
}
const currentDes = ref<string | number>('');
const currentFBAData = ref<ShipmentPlanVO>();
//
const groupedChannels = computed(() => {
// return channelTableData.value.reduce((acc, channel) => {
// const country = channel.country;
// const method = channel.shippingMethod;
//
// if (!acc[country]) acc[country] = {};
// if (!acc[country][method]) acc[country][method] = [];
//
// acc[country][method].push(channel);
// return acc;
// }, {});
return transformChannels(channelTableData.value);
});
// +
const getChannelLabel = (name) => {
return name.split('-').slice(2).join('-');
};
//
const getCountryName = (code) => {
return countryMap[code] || code.toUpperCase();
};
//
const getShippingMethodName = (method) => {
return shippingMethodMap[method] || method;
};
//
const activeCollapse = ref(['us']); //
const selectedChannel = ref(null);
const handleChannelSelect = (channelId) => {
console.log('Selected channel ID:', channelId);
// API
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
shipmentPlanFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ShipmentPlanVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加货件计划';
};
const checkPrice = async () => {
console.log('checkPrice', currentDes.value, selectedChannel.value);
//
console.log('sshipDate.value', shipDate.value);
const res = await queryLogisticsQuote(currentDes.value, selectedChannel.value, shipDate.value);
console.log('查询报价单', res);
if (res.total == 0) {
//
const requestQuote = await queryWithDesAndChannel(currentDes.value, selectedChannel.value, shipDate.value);
console.log('查询询价单', requestQuote);
if (requestQuote.total == 0) {
console.log('询价单也没数据');
channelDialogVisible.value = false;
ElMessageBox.confirm('未查询到价格信息,是否要向物流商发布询价?', '提醒', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
const res2 = await createWithDesAndChannel(currentDes.value, selectedChannel.value, shipDate.value);
console.log('checkPriceEnd2', res2);
if (res2.code == 200) {
ElMessage({
type: 'success',
message: '询价单创建成功'
});
}
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: 'Delete canceled'
// });
});
} else {
//
channelDialogVisible.value = false;
dialogTableVisible.value = true;
tableData.value = requestQuote.rows;
console.log('requestQuote.rows', requestQuote.rows);
console.log('tableData', tableData.value);
}
} else {
//
channelDialogVisible.value = false;
drawer.value = true;
logisticsQuoteList.value = res.rows;
}
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentPlanVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getShipmentPlan(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改货件计划';
};
const handleSend = async (row?: ShipmentPlanVO) => {
reset();
channelDialogVisible.value = true;
console.log(row);
currentFBAData.value = row;
currentDes.value = row.destination;
};
const snycTodayPlan = async () => {
const res = await takeTodayAmzPlanData();
if (res.code == 200) {
proxy?.$modal.msgSuccess('同步成功');
await getList();
}
};
/** 提交按钮 */
const submitForm = () => {
shipmentPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateShipmentPlan(form.value).finally(() => (buttonLoading.value = false));
} else {
await addShipmentPlan(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: ShipmentPlanVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除货件计划编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delShipmentPlan(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'amz/shipmentPlan/export',
{
...queryParams.value
},
`shipmentPlan_${new Date().getTime()}.xlsx`
);
};
const dialogVisible = ref(false);
const detailDialogVisible = ref(false);
const addressTableData = ref([]);
const detailTableData = ref([]);
const channelDialogVisible = ref(false);
//
const convertAddressToTableData = (address) => {
return Object.entries(address).map(([key, value]) => ({
key: key,
value: value
}));
};
//
const openAddressDialog = (address) => {
addressTableData.value = convertAddressToTableData(address);
dialogVisible.value = true;
};
const openDetailDialog = (detail) => {
detailTableData.value = detail;
detailDialogVisible.value = true;
};
const currentRow = ref();
const singleTableRef = ref<InstanceType<typeof ElTable>>();
const handleCurrentChange = (val: ShipmentPlanVO | undefined) => {
currentRow.value = val;
};
onMounted(() => {
getList();
getAllChannelData();
});
</script>

View File

@ -0,0 +1,932 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="queryParams.shipmentId" placeholder="请输入货件编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="queryParams.shipmentName" placeholder="请输入货件名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入物流中心编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasRoles="['superadmin']" v-hasPermi="['amz:shipmentPlan:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate()"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:shipmentPlan:remove']"
>删除
</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentPlan:export']">导出 </el-button>-->
<!-- </el-col>-->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="shipmentPlanList" @current-change="handleCurrentChange" highlight-current-row ref="singleTableRef">
<el-table-column type="expand">
<template #default="props">
<el-descriptions size="small" border title="货件详情">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>
<!-- <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>-->
<el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>
<!-- <el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- <el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
</el-descriptions>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.staShipmentDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="店铺名称" align="center" prop="sellerName" />
<el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="商品详情" align="center">
<template #default="scope">
<el-popover placement="top" :width="600" trigger="hover" @show="showPop(scope.row)">
<template #reference>
<el-button style="margin-right: 16px">查看</el-button>
</template>
<el-table :data="scope.row.itemVoList">
<el-table-column width="200" property="productName" label="品名" />
<el-table-column width="200" property="msku" label="msku" />
<el-table-column width="150" property="asin" label="asin" />
</el-table>
</el-popover>
</template>
</el-table-column>
<el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="总箱子数量" align="center" prop="boxQuantity" />
<el-table-column label="箱子尺寸" align="center" prop="boxSize" />
<el-table-column label="供应商称重" align="center" prop="vendorWeight" />
<el-table-column label="套数" align="center" prop="setTotal" />
<!-- <el-table-column label="渠道ID" align="center" prop="channelId" />-->
<el-table-column width="150" label="仓库配送地址" align="center" prop="shipToAddress">
<template #default="{ row }">
<el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>
</template>
</el-table-column>
<el-table-column label="亚马逊货件状态" align="center" prop="gmtCreate" width="180">
<template #default="scope">
<el-tag>{{ scope.row.shipmentStatus }}</el-tag>
</template>
</el-table-column>
<el-table-column label="物流渠道" align="center" prop="channelName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"></el-button>
</el-tooltip>
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>-->
<!-- </el-tooltip>-->
<el-button link type="primary" size="small" @click="handleSend(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']">查询报价 </el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="货件编号" prop="shipmentId">
<el-input v-model="form.shipmentId" placeholder="请输入货件编号" disabled />
</el-form-item>
<el-form-item label="货件名称" prop="shipmentName">
<el-input v-model="form.shipmentName" placeholder="请输入货件名称" disabled />
</el-form-item>
<el-form-item label="物流中心编码" prop="destination">
<el-input v-model="form.destination" placeholder="请输入物流中心编码" disabled />
</el-form-item>
<el-form-item label="物流渠道">
<el-cascader
ref="channelCascaderRef"
v-model="selectedChannel"
:props="{ emitPath: false }"
placeholder="请选择渠道"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="总箱子数量" prop="boxQuantity">
<el-input v-model="form.boxQuantity" placeholder="请输入总箱子数量" />
</el-form-item>
<el-form-item label="箱子尺寸" prop="boxSize">
<el-input v-model="form.boxSize" placeholder="请输入箱子尺寸" />
</el-form-item>
<el-form-item label="供应商称重" prop="vendorWeight">
<el-input v-model="form.vendorWeight" placeholder="请输入供应商称重" />
</el-form-item>
<el-form-item label="套数" prop="setTotal">
<el-input v-model="form.setTotal" placeholder="请输入套数" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 详情对话框 -->
<el-dialog v-model="dialogVisible" title="地址详细信息" width="60%">
<el-table :data="addressTableData">
<el-table-column prop="key" label="字段" width="180" />
<el-table-column prop="value" label="值" />
</el-table>
</el-dialog>
<el-dialog v-model="channelDialogVisible" title="查询报价" width="60%">
<!-- <el-radio-group v-model="form.status">-->
<!-- <el-radio v-for="dict in biz_transport_channel" :key="dict.value" :value="dict.value">-->
<!-- {{ dict.label }}-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<!-- <el-radio-group v-model="form.status">-->
<!-- &lt;!&ndash; 按国家分组循环 &ndash;&gt;-->
<!-- <div v-for="(transportDict, country) in groupedChannels" :key="country">-->
<!-- &lt;!&ndash; 国家标题 &ndash;&gt;-->
<!-- <div class="country-title">{{ country }}</div>-->
<!-- &lt;!&ndash; 运输方式子分组 &ndash;&gt;-->
<!-- <div-->
<!-- v-for="(channels, transport) in transportDict"-->
<!-- :key="transport"-->
<!-- class="transport-group"-->
<!-- >-->
<!-- <el-radio-->
<!-- v-for="dict in channels"-->
<!-- :key="dict.value"-->
<!-- :value="dict.value"-->
<!-- border-->
<!-- class="channel-item"-->
<!-- >-->
<!-- {{ transport }} - {{ getChannelName(dict.label) }}-->
<!-- </el-radio>-->
<!-- </div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="目的地仓库">
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<!-- <el-collapse v-model="activeCollapse">-->
<!-- &lt;!&ndash; 遍历国家分组 &ndash;&gt;-->
<!-- <el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">-->
<!-- &lt;!&ndash; 遍历运输方式 &ndash;&gt;-->
<!-- <div v-for="(methodGroup, method) in countryGroup" :key="method">-->
<!-- <div class="shipping-method-title">-->
<!-- {{ getShippingMethodName(method) }}-->
<!-- </div>-->
<!-- <el-radio-group v-model="selectedChannel" @change="handleChannelSelect">-->
<!-- &lt;!&ndash; 遍历具体渠道 &ndash;&gt;-->
<!-- <div v-for="channel in methodGroup" :key="channel.id" class="channel-item">-->
<!-- <el-radio :label="channel.id">-->
<!-- {{ getChannelLabel(channel.channelName) }}-->
<!-- </el-radio>-->
<!-- <div class="channel-description">{{ channel.description }}</div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
</el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="checkPrice()">查询报价</el-button>
</el-form>
</el-dialog>
<el-dialog v-model="dialogTableVisible" title="已经存在的询价单" width="1800">
<el-table :data="tableData" style="width: 100%" border stripe>
<!-- 基础文本列 -->
<el-table-column prop="inquiryNo" label="询价编号" width="180" />
<el-table-column prop="channelName" label="渠道名称" width="200" />
<el-table-column prop="transportChannel" label="运输方式" width="120" />
<el-table-column prop="quoteDate" label="询价日期" width="200" />
<!-- 时间格式化列 -->
<el-table-column prop="deadline" label="截止时间" width="180">
<template #default="{ row }">
{{ formatTime(row.deadline) }}
</template>
</el-table-column>
<el-table-column prop="effectiveStartTime" label="生效开始时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveStartTime) }}
</template>
</el-table-column>
<el-table-column prop="effectiveEndTime" label="生效结束时间" width="180">
<template #default="{ row }">
{{ formatTime(row.effectiveEndTime) }}
</template>
</el-table-column>
<!-- 状态标签列 -->
<el-table-column prop="inquiryStatus" label="询价状态" width="120">
<template #default="{ row }">
<el-tag :type="statusTagType(row.inquiryStatus)" effect="light">
{{ row.inquiryStatus }}
</el-tag>
</template>
</el-table-column>
<!-- 其他信息列 -->
<el-table-column prop="destination" label="目的地" width="120" />
<el-table-column prop="requesterId" label="请求方ID" width="120" />
<!-- 空值处理 -->
<el-table-column prop="targetProviders" label="目标供应商">
<template #default="{ row }">
{{ row.targetProviders || '-' }}
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-drawer size="80%" v-model="drawer" :direction="direction">
<template #header>
<h4>物流商报价</h4>
</template>
<template #default>
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="120">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="提交状态" align="center" prop="isSubmitted" />
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button text size="small" type="primary" @click="createOrder(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']">
创建货运订单
</el-button>
</template>
</el-table-column>
</el-table>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" @click="confirmClick">确认</el-button>
</div>
</template>
</el-drawer>
</div>
</template>
<script setup name="ShipmentPlan" lang="ts">
import {
listShipmentPlan,
getShipmentPlan,
delShipmentPlan,
addShipmentPlan,
updateShipmentPlan,
takeTodayAmzPlanData
} from '@/api/amz/shipmentPlan';
import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel';
import type { DrawerProps } from 'element-plus';
import { createWithDesAndChannel, queryWithDesAndChannel } from '@/api/amz/inquiryRequest';
import { queryLogisticsQuote } from '@/api/amz/logisticsQuote';
import { ShipmentPlanVO, ShipmentPlanQuery, ShipmentPlanForm } from '@/api/amz/shipmentPlan/types';
import { ElTable } from 'element-plus';
import { LogisticsQuoteVO } from '@/api/amz/logisticsQuote/types';
import { createOrderForm } from '@/api/amz/logisticsOrder/types';
import { createLogisticsOrder } from '@/api/amz/logisticsOrder';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_transport_channel } = toRefs<any>(proxy?.useDict('biz_transport_channel'));
const { sys_zero_one } = toRefs<any>(proxy?.useDict('sys_zero_one'));
const shipmentPlanList = ref<ShipmentPlanVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const shipmentPlanFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: ShipmentPlanForm = {
id: undefined,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
boxQuantity: undefined,
boxSize: undefined,
vendorWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined
};
const data = reactive<PageData<ShipmentPlanForm, ShipmentPlanQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
sid: undefined,
shipmentId: undefined,
shipmentName: undefined,
isClosed: undefined,
shipmentStatus: undefined,
destination: undefined,
shippingMode: undefined,
shippingSolution: undefined,
gmtModified: undefined,
gmtCreate: undefined,
syncTime: undefined,
staShipmentDate: undefined,
staDeliveryStartDate: undefined,
staDeliveryEndDate: undefined,
shipFromAddress: undefined,
shipToAddress: undefined,
referenceId: undefined,
staInboundPlanId: undefined,
isSta: undefined,
fbaStatus: 'send',
boxQuantity: undefined,
boxSize: undefined,
vendorWeight: undefined,
setTotal: undefined,
channelId: undefined,
channelName: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
sid: [{ required: true, message: '关联系统ID不能为空', trigger: 'blur' }],
shipmentId: [{ required: true, message: '货件编号不能为空', trigger: 'blur' }],
shipmentName: [{ required: true, message: '货件名称不能为空', trigger: 'blur' }],
isClosed: [{ required: true, message: '是否关闭不能为空', trigger: 'blur' }],
shipmentStatus: [{ required: true, message: '货件状态不能为空', trigger: 'change' }],
destination: [{ required: true, message: '物流中心编码不能为空', trigger: 'blur' }],
shippingMode: [{ required: true, message: '运输模式不能为空', trigger: 'blur' }],
shippingSolution: [{ required: true, message: '运输方案不能为空', trigger: 'blur' }],
gmtModified: [{ required: true, message: '最后更新时间不能为空', trigger: 'blur' }],
gmtCreate: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }],
syncTime: [{ required: true, message: '同步时间不能为空', trigger: 'blur' }],
staShipmentDate: [{ required: true, message: '计划发货日期不能为空', trigger: 'blur' }],
staDeliveryStartDate: [{ required: true, message: '预计到货开始日不能为空', trigger: 'blur' }],
staDeliveryEndDate: [{ required: true, message: '预计到货截止日不能为空', trigger: 'blur' }],
shipFromAddress: [{ required: true, message: '发货地址不能为空', trigger: 'blur' }],
shipToAddress: [{ required: true, message: '收货地址不能为空', trigger: 'blur' }],
referenceId: [{ required: true, message: '参考编号不能为空', trigger: 'blur' }],
staInboundPlanId: [{ required: true, message: '入库计划ID不能为空', trigger: 'blur' }],
isSta: [{ required: true, message: '是否STA计划不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
const createOrderData = ref<createOrderForm>({
fbaShipmentId: undefined,
logicQuoteId: undefined
});
const createOrder = async (row: ShipmentPlanVO) => {
//
console.log('row', row);
console.log('currentFBAData', currentFBAData.value);
createOrderData.value.fbaShipmentId = currentFBAData.value.shipmentId;
createOrderData.value.logicQuoteId = row.id;
const res = await createLogisticsOrder(createOrderData.value);
console.log('res', res);
if (res.code === 200) {
ElMessage.success('创建成功');
const updateForm = ref({
id: currentFBAData.value.id,
fbaStatus: 'query'
});
await updateShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
} else {
ElMessage.error('创建失败');
}
drawer.value = false;
};
const dialogTableVisible = ref(false);
const logisticsQuoteList = ref<LogisticsQuoteVO[]>([]);
const tableData = ref([
{
channelId: '1902912289404719106',
channelName: '美国-海运-美森正班船',
deadline: '2025-03-22 11:00:00',
destination: 'LGB8',
effectiveEndTime: '2025-03-30 15:30:19',
effectiveStartTime: '2025-03-23 15:30:19',
id: '1903348528587018242',
inquiryNo: 'INQ20250322000004',
inquiryStatus: 'OPEN',
quoteDate: '2025-03-22 00:00:00',
requesterId: 1,
targetProviders: null,
transportChannel: 'sea'
}
]);
//
const formatTime = (timeString) => {
return timeString.replace(' ', '\n'); //
};
//
const statusTagType = (status) => {
switch (status) {
case 'OPEN':
return 'success';
case 'CLOSED':
return 'info';
case 'EXPIRED':
return 'warning';
default:
return '';
}
};
const drawer = ref(false);
const direction = ref<DrawerProps['direction']>('ltr');
const radio1 = ref('Option 1');
const handleClose = (done: () => void) => {
ElMessageBox.confirm('Are you sure you want to close this?')
.then(() => {
done();
})
.catch(() => {
// catch error
});
};
function cancelClick() {
drawer.value = false;
}
const channelCascaderRef = ref(null);
const cascaderChange = (value) => {
console.log(value);
console.log('selectedChannel', selectedChannel);
console.log('groupedChannels', groupedChannels);
// console.log('channelCascaderRef', channelCascaderRef);
console.log('label====', channelCascaderRef.value.getCheckedNodes()[0].label);
};
function confirmClick() {
ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`)
.then(() => {
drawer.value = false;
})
.catch(() => {
// catch error
});
}
const getLocalDate = () => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const shipDate = ref(getLocalDate());
/** 查询货件计划列表 */
const getList = async () => {
loading.value = true;
const res = await listShipmentPlan(queryParams.value);
shipmentPlanList.value = res.rows;
total.value = res.total;
loading.value = false;
};
let channelTableData = ref([]);
const getAllChannelData = async () => {
const res = await listAllLogisticsChannel();
console.log('getAllChannelData');
console.log(res);
channelTableData.value = res.rows;
console.log('groupedChannels:', groupedChannels.value);
};
//
const countryMap = {
us: '美国'
//
};
const shippingMethodMap = {
air: '空运',
sea: '海运'
//
};
function transformChannels(channels) {
const result = [];
const countryGroups = {}; //
channels.forEach((channel) => {
const { country, shippingMethod, channelName, id } = channel;
//
const countryValue = country;
const countryLabel = countryMap[country] || country;
if (!countryGroups[countryValue]) {
countryGroups[countryValue] = {
value: countryValue,
label: countryLabel,
children: []
};
result.push(countryGroups[countryValue]);
}
//
const methodValue = shippingMethod;
const methodLabel = shippingMethodMap[shippingMethod] || shippingMethod;
let methodNode = countryGroups[countryValue].children.find((m) => m.value === methodValue);
if (!methodNode) {
methodNode = {
value: methodValue,
label: methodLabel,
children: []
};
countryGroups[countryValue].children.push(methodNode);
}
//
methodNode.children.push({
value: id,
label: channelName
});
});
return result;
}
const currentDes = ref<string | number>('');
const currentFBAData = ref<ShipmentPlanVO>();
//
const groupedChannels = computed(() => {
// return channelTableData.value.reduce((acc, channel) => {
// const country = channel.country;
// const method = channel.shippingMethod;
//
// if (!acc[country]) acc[country] = {};
// if (!acc[country][method]) acc[country][method] = [];
//
// acc[country][method].push(channel);
// return acc;
// }, {});
return transformChannels(channelTableData.value);
});
// +
const getChannelLabel = (name) => {
return name.split('-').slice(2).join('-');
};
//
const getCountryName = (code) => {
return countryMap[code] || code.toUpperCase();
};
//
const getShippingMethodName = (method) => {
return shippingMethodMap[method] || method;
};
//
const activeCollapse = ref(['us']); //
const selectedChannel = ref(null);
const handleChannelSelect = (channelId) => {
console.log('Selected channel ID:', channelId);
// API
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
shipmentPlanFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ShipmentPlanVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加货件计划';
};
const checkPrice = async () => {
// form.value.fbaStatus = 'send';
//
// const updateForm = ref({
// id: currentFBAData.value.id,
// fbaStatus: 'send'
// });
// await updateShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
console.log('checkPrice', currentDes.value, selectedChannel.value);
//
console.log('sshipDate.value', shipDate.value);
if (currentFBAData.value.channelId == null) {
ElMessage({
type: 'warning',
message: '请先设置渠道!'
});
return;
}
const res = await queryLogisticsQuote(currentDes.value, currentFBAData.value.channelId, shipDate.value);
console.log('查询报价单', res);
if (res.total == 0) {
// //
// const requestQuote = await queryWithDesAndChannel(currentDes.value, currentFBAData.value.channelId, shipDate.value);
// console.log('', requestQuote);
// if (requestQuote.total == 0) {
// console.log('');
// channelDialogVisible.value = false;
// ElMessageBox.confirm(',', '', {
// confirmButtonText: '',
// cancelButtonText: '',
// type: 'warning'
// })
// .then(async () => {
// const res2 = await createWithDesAndChannel(currentDes.value, currentFBAData.value.channelId, shipDate.value);
// console.log('checkPriceEnd2', res2);
// if (res2.code == 200) {
// ElMessage({
// type: 'success',
// message: ''
// });
// }
// })
// .catch(() => {
// // ElMessage({
// // type: 'info',
// // message: 'Delete canceled'
// // });
// });
// } else {
// //
// // channelDialogVisible.value = false;
// // dialogTableVisible.value = true;
// // tableData.value = requestQuote.rows;
// // console.log('requestQuote.rows', requestQuote.rows);
// // console.log('tableData', tableData.value);
// ElMessage.success('');
// }
ElMessage.warning('暂时没有物流商报价');
} else {
//
// ElMessage.success('');
channelDialogVisible.value = false;
drawer.value = true;
logisticsQuoteList.value = res.rows;
}
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentPlanVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getShipmentPlan(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改货件计划';
};
const handleSend = async (row?: ShipmentPlanVO) => {
// reset();
// channelDialogVisible.value = true;
console.log(row);
currentFBAData.value = row;
currentDes.value = row.destination;
checkPrice();
};
const showPop = async (row: any) => {
console.log('row', row);
};
const snycTodayPlan = async () => {
const res = await takeTodayAmzPlanData();
if (res.code == 200) {
proxy?.$modal.msgSuccess('同步成功');
await getList();
}
};
/** 提交按钮 */
const submitForm = () => {
console.log('selectedChannel', selectedChannel);
console.log('groupedChannels', groupedChannels);
// console.log('channelCascaderRef', channelCascaderRef);
console.log('label====', channelCascaderRef.value.getCheckedNodes()[0].label);
form.value.channelName = channelCascaderRef.value.getCheckedNodes()[0].label;
form.value.channelId = selectedChannel;
const updateForm = ref({
id: form.value.id,
boxQuantity: form.value.boxQuantity,
boxSize: form.value.boxSize,
vendorWeight: form.value.vendorWeight,
setTotal: form.value.setTotal,
channelId: selectedChannel,
channelName: channelCascaderRef.value.getCheckedNodes()[0].label
});
shipmentPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (updateForm.value.id) {
await updateShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
} else {
await addShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: ShipmentPlanVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除货件计划编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delShipmentPlan(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'amz/shipmentPlan/export',
{
...queryParams.value
},
`shipmentPlan_${new Date().getTime()}.xlsx`
);
};
const dialogVisible = ref(false);
const addressTableData = ref([]);
const channelDialogVisible = ref(false);
//
const convertAddressToTableData = (address) => {
return Object.entries(address).map(([key, value]) => ({
key: key,
value: value
}));
};
//
const openAddressDialog = (address) => {
addressTableData.value = convertAddressToTableData(address);
dialogVisible.value = true;
};
const currentRow = ref();
const singleTableRef = ref<InstanceType<typeof ElTable>>();
const handleCurrentChange = (val: ShipmentPlanVO | undefined) => {
currentRow.value = val;
};
onMounted(() => {
getList();
getAllChannelData();
});
</script>

View File

@ -13,6 +13,42 @@
<el-form-item label="物流单号" prop="trackingNumber">
<el-input v-model="queryParams.trackingNumber" placeholder="请输入物流单号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="本地箱子编号" prop="localBoxId">
<el-input v-model="queryParams.localBoxId" placeholder="请输入本地箱子编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="包裹唯一标识" prop="packageId">
<el-input v-model="queryParams.packageId" placeholder="请输入包裹唯一标识" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="总数量" prop="total">
<el-input v-model="queryParams.total" placeholder="请输入总数量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="重量" prop="weight">
<el-input v-model="queryParams.weight" placeholder="请输入重量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="重量单位" prop="weightUnit">
<el-input v-model="queryParams.weightUnit" placeholder="请输入重量单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="长度" prop="length">
<el-input v-model="queryParams.length" placeholder="请输入长度" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="宽度" prop="width">
<el-input v-model="queryParams.width" placeholder="请输入宽度" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="高度" prop="height">
<el-input v-model="queryParams.height" placeholder="请输入高度" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="尺寸单位" prop="lengthUnit">
<el-input v-model="queryParams.lengthUnit" placeholder="请输入尺寸单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="箱子展示名称" prop="boxName">
<el-input v-model="queryParams.boxName" placeholder="请输入箱子展示名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="货件唯一编号" prop="shipmentUniqueId">
<el-input v-model="queryParams.shipmentUniqueId" placeholder="请输入货件唯一编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="STA任务编号" prop="inboundPlanId">
<el-input v-model="queryParams.inboundPlanId" placeholder="请输入STA任务编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -26,16 +62,20 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentTracking:add']">新增</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:shipmentTracking:add']"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentTracking:edit']">修改</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:shipmentTracking:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentTracking:remove']">删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:shipmentTracking:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentTracking:export']">导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:shipmentTracking:export']">导出 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -46,6 +86,18 @@
<el-table-column label="关联货件ID" align="center" prop="shipmentId" />
<el-table-column label="箱号" align="center" prop="boxId" />
<el-table-column label="物流单号" align="center" prop="trackingNumber" />
<el-table-column label="本地箱子编号" align="center" prop="localBoxId" />
<!-- <el-table-column label="包裹唯一标识" align="center" prop="packageId" />-->
<el-table-column label="总数量" align="center" prop="total" />
<el-table-column label="重量" align="center" prop="weight" />
<el-table-column label="重量单位" align="center" prop="weightUnit" />
<el-table-column label="长度" align="center" prop="length" />
<el-table-column label="宽度" align="center" prop="width" />
<el-table-column label="高度" align="center" prop="height" />
<el-table-column label="尺寸单位" align="center" prop="lengthUnit" />
<el-table-column label="箱子展示名称" align="center" prop="boxName" />
<!-- <el-table-column label="货件唯一编号" align="center" prop="shipmentUniqueId" />-->
<!-- <el-table-column label="STA任务编号" align="center" prop="inboundPlanId" />-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
@ -75,6 +127,42 @@
<el-form-item label="物流单号" prop="trackingNumber">
<el-input v-model="form.trackingNumber" placeholder="请输入物流单号" />
</el-form-item>
<el-form-item label="本地箱子编号" prop="localBoxId">
<el-input v-model="form.localBoxId" placeholder="请输入本地箱子编号" />
</el-form-item>
<!-- <el-form-item label="包裹唯一标识" prop="packageId">-->
<!-- <el-input v-model="form.packageId" placeholder="请输入包裹唯一标识" />-->
<!-- </el-form-item>-->
<el-form-item label="总数量" prop="total">
<el-input v-model="form.total" placeholder="请输入总数量" />
</el-form-item>
<el-form-item label="重量" prop="weight">
<el-input v-model="form.weight" placeholder="请输入重量" />
</el-form-item>
<el-form-item label="重量单位" prop="weightUnit">
<el-input v-model="form.weightUnit" placeholder="请输入重量单位" />
</el-form-item>
<el-form-item label="长度" prop="length">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
<el-form-item label="宽度" prop="width">
<el-input v-model="form.width" placeholder="请输入宽度" />
</el-form-item>
<el-form-item label="高度" prop="height">
<el-input v-model="form.height" placeholder="请输入高度" />
</el-form-item>
<el-form-item label="尺寸单位" prop="lengthUnit">
<el-input v-model="form.lengthUnit" placeholder="请输入尺寸单位" />
</el-form-item>
<el-form-item label="箱子展示名称" prop="boxName">
<el-input v-model="form.boxName" placeholder="请输入箱子展示名称" />
</el-form-item>
<!-- <el-form-item label="货件唯一编号" prop="shipmentUniqueId">-->
<!-- <el-input v-model="form.shipmentUniqueId" placeholder="请输入货件唯一编号" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="STA任务编号" prop="inboundPlanId">-->
<!-- <el-input v-model="form.inboundPlanId" placeholder="请输入STA任务编号" />-->
<!-- </el-form-item>-->
</el-form>
<template #footer>
<div class="dialog-footer">
@ -87,7 +175,13 @@
</template>
<script setup name="ShipmentTracking" lang="ts">
import { listShipmentTracking, getShipmentTracking, delShipmentTracking, addShipmentTracking, updateShipmentTracking } from '@/api/amz/shipmentTracking';
import {
listShipmentTracking,
getShipmentTracking,
delShipmentTracking,
addShipmentTracking,
updateShipmentTracking
} from '@/api/amz/shipmentTracking';
import { ShipmentTrackingVO, ShipmentTrackingQuery, ShipmentTrackingForm } from '@/api/amz/shipmentTracking/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -114,31 +208,58 @@ const initFormData: ShipmentTrackingForm = {
shipmentId: undefined,
boxId: undefined,
trackingNumber: undefined,
}
localBoxId: undefined,
packageId: undefined,
total: undefined,
weight: undefined,
weightUnit: undefined,
length: undefined,
width: undefined,
height: undefined,
lengthUnit: undefined,
boxName: undefined,
shipmentUniqueId: undefined,
inboundPlanId: undefined
};
const data = reactive<PageData<ShipmentTrackingForm, ShipmentTrackingQuery>>({
form: {...initFormData},
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
shipmentId: undefined,
boxId: undefined,
trackingNumber: undefined,
params: {
}
localBoxId: undefined,
packageId: undefined,
total: undefined,
weight: undefined,
weightUnit: undefined,
length: undefined,
width: undefined,
height: undefined,
lengthUnit: undefined,
boxName: undefined,
shipmentUniqueId: undefined,
inboundPlanId: undefined,
params: {}
},
rules: {
id: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
shipmentId: [
{ required: true, message: "关联货件ID不能为空", trigger: "blur" }
],
boxId: [
{ required: true, message: "箱号不能为空", trigger: "blur" }
],
trackingNumber: [
{ required: true, message: "物流单号不能为空", trigger: "blur" }
],
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
shipmentId: [{ required: true, message: '关联货件ID不能为空', trigger: 'blur' }],
boxId: [{ required: true, message: '箱号不能为空', trigger: 'blur' }],
trackingNumber: [{ required: true, message: '物流单号不能为空', trigger: 'blur' }],
localBoxId: [{ required: true, message: '本地箱子编号不能为空', trigger: 'blur' }],
packageId: [{ required: true, message: '包裹唯一标识不能为空', trigger: 'blur' }],
total: [{ required: true, message: '总数量不能为空', trigger: 'blur' }],
weight: [{ required: true, message: '重量不能为空', trigger: 'blur' }],
weightUnit: [{ required: true, message: '重量单位不能为空', trigger: 'blur' }],
length: [{ required: true, message: '长度不能为空', trigger: 'blur' }],
width: [{ required: true, message: '宽度不能为空', trigger: 'blur' }],
height: [{ required: true, message: '高度不能为空', trigger: 'blur' }],
lengthUnit: [{ required: true, message: '尺寸单位不能为空', trigger: 'blur' }],
boxName: [{ required: true, message: '箱子展示名称不能为空', trigger: 'blur' }],
shipmentUniqueId: [{ required: true, message: '货件唯一编号不能为空', trigger: 'blur' }],
inboundPlanId: [{ required: true, message: 'STA任务编号不能为空', trigger: 'blur' }]
}
});
@ -151,55 +272,55 @@ const getList = async () => {
shipmentTrackingList.value = res.rows;
total.value = res.total;
loading.value = false;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
};
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
form.value = { ...initFormData };
shipmentTrackingFormRef.value?.resetFields();
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ShipmentTrackingVO[]) => {
ids.value = selection.map(item => item.id);
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = "添加物流追踪";
}
dialog.title = '添加物流追踪';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentTrackingVO) => {
reset();
const _id = row?.id || ids.value[0]
const _id = row?.id || ids.value[0];
const res = await getShipmentTracking(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = "修改物流追踪";
}
dialog.title = '修改物流追踪';
};
/** 提交按钮 */
const submitForm = () => {
@ -207,32 +328,36 @@ const submitForm = () => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateShipmentTracking(form.value).finally(() => buttonLoading.value = false);
await updateShipmentTracking(form.value).finally(() => (buttonLoading.value = false));
} else {
await addShipmentTracking(form.value).finally(() => buttonLoading.value = false);
await addShipmentTracking(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess("操作成功");
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
}
};
/** 删除按钮操作 */
const handleDelete = async (row?: ShipmentTrackingVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除物流追踪编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
await proxy?.$modal.confirm('是否确认删除物流追踪编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delShipmentTracking(_ids);
proxy?.$modal.msgSuccess("删除成功");
proxy?.$modal.msgSuccess('删除成功');
await getList();
}
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('amz/shipmentTracking/export', {
...queryParams.value
}, `shipmentTracking_${new Date().getTime()}.xlsx`)
}
proxy?.download(
'amz/shipmentTracking/export',
{
...queryParams.value
},
`shipmentTracking_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();

View File

@ -81,7 +81,10 @@
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2005 瑷胜科技 All Rights Reserved.</span>
<span
>Copyright © 2005 瑷胜科技 <el-link type="primary" href="https://beian.miit.gov.cn/" target="_blank">粤ICP备2025398203号</el-link> All Rights
Reserved.</span
>
</div>
</div>
</template>

View File

@ -275,7 +275,7 @@ const dialog = reactive<DialogOption>({
const getList = () => {
loading.value = true;
listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
roleList.value = res.rows;
roleList.value = res.rows.filter(item => item.roleKey !== 'superadmin');
total.value = res.total;
loading.value = false;
});

View File

@ -60,7 +60,7 @@
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
@ -76,13 +76,15 @@
<el-dropdown class="mt-[1px]">
<el-button plain type="info">
更多
<el-icon class="el-icon--right"><arrow-down /></el-icon
></el-button>
<el-icon class="el-icon--right">
<arrow-down />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport">导出数据</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据 </el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport"> 导出数据 </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@ -199,7 +201,7 @@
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -268,9 +270,12 @@
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="text-center el-upload__tip">
<div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
<div class="el-upload__tip">
<el-checkbox v-model="upload.updateSupport" />
是否更新已经存在的用户数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板 </el-link>
</div>
</template>
</el-upload>
@ -287,7 +292,7 @@
<script setup name="User" lang="ts">
import api from '@/api/system/user';
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import {DeptTreeVO, DeptVO} from '@/api/system/dept/types';
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
import { RoleVO } from '@/api/system/role/types';
import { PostQuery, PostVO } from '@/api/system/post/types';
import { treeselect } from '@/api/system/dept';
@ -437,7 +442,7 @@ const getList = async () => {
loading.value = true;
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false;
userList.value = res.rows;
userList.value = res.rows.filter((user) => user.userId !== 1);
total.value = res.total;
};
@ -450,7 +455,7 @@ const getDeptTree = async () => {
/** 过滤禁用的部门 */
const filterDisabledDept = (deptList: DeptTreeVO[]) => {
return deptList.filter(dept => {
return deptList.filter((dept) => {
if (dept.disabled) {
return false;
}

View File

@ -25,7 +25,7 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
open: true,
proxy: {
[env.VITE_APP_BASE_API]: {
target: 'http://localhost:8080',
target: env.VITE_BACKEND_URL,
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')