运营段修改
Some checks failed
自动部署测试 / build-and-deploy (push) Has been cancelled

This commit is contained in:
dev 2025-07-03 11:20:40 +08:00
parent 1171a8b533
commit 0dfc0caf6b
19 changed files with 1018 additions and 284 deletions

View File

@ -121,9 +121,12 @@
#loader-wrapper .loader-section { #loader-wrapper .loader-section {
position: fixed; position: fixed;
top: 0; top: 0;
width: 51%; width: 100%;
height: 100%; height: 100%;
background: #7171c6; //background: #7171c6;
background: radial-gradient(circle at 90% 50%, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.4) 60%, transparent 100%),
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1500 1000' preserveAspectRatio='xMidYMid slice'><defs><radialGradient id='a' cx='50%' cy='50%' r='50%' gradientTransform='scale(1.5)'><stop offset='0%' stop-color='%230c0d25'/><stop offset='100%' stop-color='%230f172a'/></radialGradient><filter id='b' x='-50%' y='-50%' width='200%' height='200%'><feTurbulence type='fractalNoise' baseFrequency='0.01' numOctaves='3'/><feColorMatrix type='saturate' values='0'/><feComponentTransfer><feFuncR type='linear' slope='0.05'/><feFuncG type='linear' slope='0.08'/><feFuncB type='linear' slope='0.12'/></feComponentTransfer></filter></defs><rect width='100%' height='100%' fill='url(%23a)'/><g fill='none' stroke='rgba(0,150,255,0.06)' stroke-width='1' stroke-opacity='0.15'><path d='M0,0 L1500,1000'/><path d='M0,1000 L1500,0'/></g><g transform='translate(0,0)'><rect width='1500' height='1000' fill='transparent' filter='url(%23b)'/></g><g fill='rgba(0,150,255,0.12)'><circle cx='200' cy='170' r='1.2'/><circle cx='950' cy='400' r='1.5'/><circle cx='1200' cy='780' r='1.2'/><circle cx='450' cy='600' r='1'/><circle cx='800' cy='150' r='1.3'/><circle cx='1300' cy='300' r='1.2'/><circle cx='400' cy='900' r='1.7'/><circle cx='1100' cy='50' r='1.1'/></g><g transform='rotate(10)' stroke='rgba(64,158,255,0.15)' stroke-width='0.8' stroke-dasharray='4,8' opacity='0.15'><path d='M-500,500 L2000,500'/><path d='M-500,800 L2000,800'/></g><path d='M0,500 Q350,250 700,500 T1400,500' stroke='rgba(64,158,255,0.1)' stroke-width='3' fill='none' stroke-linecap='round' stroke-dasharray='10,12'/></svg>") center/cover;
z-index: 1000; z-index: 1000;
-webkit-transform: translateX(0); -webkit-transform: translateX(0);
-ms-transform: translateX(0); -ms-transform: translateX(0);

View File

@ -74,3 +74,16 @@ export const delPurchaseOrder = (orderSn: string | number | Array<string | numbe
}); });
}; };
export const takeTodayPurchaseOrder = () => {
return request({
url: '/amz/purchaseOrder/take-today-purchase-order',
method: 'get'
});
};
export const updateTodayPurchaseOrder = () => {
return request({
url: '/amz/purchaseOrder/update-today-purchase-order',
method: 'get'
});
};

View File

@ -95,6 +95,7 @@ export interface ShipForwardForm extends BaseEntity {
* *
*/ */
orderSn?: string; orderSn?: string;
inOrderSn?: string;
/** /**
* *
@ -169,6 +170,7 @@ export interface ShipForwardForm extends BaseEntity {
expDeliveryDate?: string; expDeliveryDate?: string;
boxNum?: number; boxNum?: number;
totalPrice?: number;
/** /**
* ID * ID

View File

@ -89,6 +89,14 @@ export const linkShipmentPlan = (data: ShipmentPlanForm) => {
}); });
}; };
export const createBatchRelations = (data: any) => {
return request({
url: '/amz/sendShipmentRel/createBatchRelations',
method: 'post',
data: data
});
};
export const updateShipmentPlanList = (data: string[]) => { export const updateShipmentPlanList = (data: string[]) => {
return request({ return request({
url: '/amz/shipmentPlan/update/list/send', url: '/amz/shipmentPlan/update/list/send',
@ -107,3 +115,10 @@ export const delShipmentPlan = (id: string | number | Array<string | number>) =>
method: 'delete' method: 'delete'
}); });
}; };
export const deleteShipmentPlanSendOrder = (shipmentPlanId: string | number, sendOrderId: string | number) => {
return request({
url: '/amz/shipmentPlan/delete/' + shipmentPlanId + '/' + sendOrderId,
method: 'delete'
});
};

View File

@ -1,6 +1,7 @@
import { LogisticsOrderVO } from '@/api/amz/logisticsOrder/types'; import { LogisticsOrderVO } from '@/api/amz/logisticsOrder/types';
import { LogisticsOrderDetailVO } from '@/api/amz/logisticsOrderDetail/types'; import { LogisticsOrderDetailVO } from '@/api/amz/logisticsOrderDetail/types';
import { ShipmentItemVO } from '@/api/amz/shipmentItem/types'; import { ShipmentItemVO } from '@/api/amz/shipmentItem/types';
import { SendOrderVO } from '@/api/amz/sendOrder/types';
export interface ShipmentPlanVO { export interface ShipmentPlanVO {
/** /**
@ -18,6 +19,8 @@ export interface ShipmentPlanVO {
*/ */
shipmentId: string | number; shipmentId: string | number;
shipmentIds?: string[] | number[];
/** /**
* *
*/ */
@ -152,10 +155,13 @@ export interface ShipmentPlanVO {
*/ */
channelName: string; channelName: string;
sendOrders?: SendOrderVO[];
/** /**
* id * id
*/ */
sendOrderId?: string | number; sendOrderId?: string | number;
sendOrderIds?: string[] | number[];
} }
interface Address { interface Address {
@ -476,6 +482,8 @@ export interface ShipmentPlanForm extends BaseEntity {
* *
*/ */
channelName?: string; channelName?: string;
linkType?: string;
} }
export interface ShipmentPlanQuery extends PageQuery { export interface ShipmentPlanQuery extends PageQuery {

View File

@ -0,0 +1,66 @@
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1500 1000' preserveAspectRatio='xMidYMid slice'>
<defs>
<radialGradient id='a' cx='50%' cy='50%' r='50%' gradientTransform='scale(1.5)'>
<stop offset='0%' stop-color='#0c0d25'/>
<stop offset='100%' stop-color='#0f172a'/>
</radialGradient>
<filter id='b' x='-50%' y='-50%' width='200%' height='200%'>
<feTurbulence type='fractalNoise' baseFrequency='0.01' numOctaves='3'/>
<feColorMatrix type='saturate' values='0'/>
<feComponentTransfer>
<feFuncR type='linear' slope='0.05'/>
<feFuncG type='linear' slope='0.08'/>
<feFuncB type='linear' slope='0.12'/>
</feComponentTransfer>
</filter>
<linearGradient id='c' x1='0%' y1='50%' x2='100%' y2='50%'>
<stop offset='0%' stop-color='rgba(0,150,255,0.3)' stop-opacity='0.3'/>
<stop offset='100%' stop-color='rgba(0,150,255,0)' stop-opacity='0'/>
</linearGradient>
</defs>
<rect width='100%' height='100%' fill='url(#a)'/>
<g fill='none' stroke='rgba(0,150,255,0.06)' stroke-width='1' stroke-opacity='0.15'>
<path d='M0,0 L1500,1000'/>
<path d='M0,1000 L1500,0'/>
</g>
<g transform='translate(0,0)'>
<rect width='1500' height='1000' fill='transparent' filter='url(#b)'/>
</g>
<g fill='rgba(0,150,255,0.12)'>
<circle cx='200' cy='170' r='1.2'/>
<circle cx='950' cy='400' r='1.5'/>
<circle cx='1200' cy='780' r='1.2'/>
<circle cx='450' cy='600' r='1'/>
<circle cx='800' cy='150' r='1.3'/>
<circle cx='1300' cy='300' r='1.2'/>
<circle cx='400' cy='900' r='1.7'/>
<circle cx='1100' cy='50' r='1.1'/>
</g>
<g transform='rotate(10)' stroke='rgba(64,158,255,0.15)' stroke-width='0.8' stroke-dasharray='4,8' opacity='0.15'>
<path d='M-500,500 L2000,500'/>
<path d='M-500,800 L2000,800'/>
</g>
<path d='M0,500 Q350,250 700,500 T1400,500' stroke='rgba(64,158,255,0.1)' stroke-width='3' fill='none'
stroke-linecap='round' stroke-dasharray='10,12'/><!-- 左侧增强科技元素:电路板样式的网格 -->
<g stroke='rgba(64,158,255,0.15)' stroke-width='0.3' stroke-opacity='0.2'>
<path d='M100,100 L100,900'/>
<path d='M300,100 L300,900'/>
<path d='M500,100 L500,900'/>
<path d='M0,200 L700,200'/>
<path d='M0,400 L700,400'/>
<path d='M0,600 L700,600'/>
<path d='M0,800 L700,800'/>
</g><!-- 左侧粒子流:从左上到右下流动的光点 -->
<g stroke='rgba(64,158,255,0.25)' stroke-width='0.1'>
<path d='M50,100 L350,600' opacity='0.6'/>
<path d='M200,200 L500,700' opacity='0.4'/>
</g>
<g>
<circle cx='50' cy='100' r='1.8' fill='rgba(64,158,255,0.8)' filter='url(#f)'/>
<circle cx='100' cy='300' r='1.5' fill='rgba(64,158,255,0.7)' filter='url(#f)'/>
<circle cx='150' cy='500' r='1.3' fill='rgba(64,158,255,0.6)'/>
<circle cx='200' cy='700' r='1' fill='rgba(64,158,255,0.5)'/>
<circle cx='250' cy='900' r='0.8' fill='rgba(64,158,255,0.4)'/>
</g><!-- 左侧发光条状特效 -->
<path d='M0,0 L700,0 L700,1000 L0,1000 Z' fill='url(#c)' opacity='0.2'/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

18
src/assets/logo/logo.svg Normal file
View File

@ -0,0 +1,18 @@
<svg width="200" height="200" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- 风车轮廓 -->
<path d="M50 0
L70.71 20.71
L100 50
L70.71 79.29
L50 100
L29.29 79.29
L0 50
L29.29 20.71
Z"
fill="none"
stroke="#007BFF"
stroke-width="1"/>
<!-- 中心点 -->
<circle cx="50" cy="50" r="3" fill="#00C6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

View File

@ -56,9 +56,9 @@
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
<el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom"> <!-- <el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom">-->
<lang-select id="lang-select" class="right-menu-item hover-effect" /> <!-- <lang-select id="lang-select" class="right-menu-item hover-effect" />-->
</el-tooltip> <!-- </el-tooltip>-->
<el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom"> <el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" /> <size-select id="size-select" class="right-menu-item hover-effect" />

View File

@ -407,7 +407,7 @@ const data = reactive<PageData<InquiryRequestForm, InquiryRequestQuery>>({
surcharge: [{ required: true, message: '附加费不能为空', trigger: 'blur' }], surcharge: [{ required: true, message: '附加费不能为空', trigger: 'blur' }],
quoteDate: [{ required: true, message: '报价生效日期不能为空', trigger: 'blur' }], quoteDate: [{ required: true, message: '报价生效日期不能为空', trigger: 'blur' }],
isSubmitted: [{ required: true, message: '提交状态不能为空', trigger: 'blur' }], isSubmitted: [{ required: true, message: '提交状态不能为空', trigger: 'blur' }],
remark: [{ required: true, message: '报价备注不能为空', trigger: 'blur' }], // remark: [{ required: true, message: '', trigger: 'blur' }],
channelType: [{ required: true, message: '渠道类型不能为空', trigger: 'change' }], channelType: [{ required: true, message: '渠道类型不能为空', trigger: 'change' }],
isDdp: [{ required: true, message: '是否双清包税不能为空', trigger: 'blur' }], isDdp: [{ required: true, message: '是否双清包税不能为空', trigger: 'blur' }],
unit: [{ required: true, message: '单位不能为空', trigger: 'blur' }] unit: [{ required: true, message: '单位不能为空', trigger: 'blur' }]
@ -607,8 +607,31 @@ const handleDelete = async (row?: InquiryRequestVO) => {
}; };
const handleSubmit = async (row?: InquiryRequestVO) => { const handleSubmit = async (row?: InquiryRequestVO) => {
reset();
console.log('handleSubmit'); console.log('handleSubmit');
console.log(row.channelId); console.log(row.channelId);
quoteForm.value = {
id: undefined,
userId: undefined,
destination: undefined,
transportChannel: undefined,
price: 10,
minLeadTime: 10,
leadTime: 10,
surcharge: 0,
channelName: undefined,
quoteStartDate: undefined,
quoteEndDate: undefined,
quoteDate: [] as Date[],
isSubmitted: undefined,
remark: undefined,
channelType: undefined,
channelId: undefined,
isDdp: 'Y',
unit: 'kg',
backLogisticsType: '快递'
};
quoteForm.value.id = row.id; quoteForm.value.id = row.id;
quoteForm.value.destination = row.destination; quoteForm.value.destination = row.destination;
quoteForm.value.transportChannel = row.transportChannel; quoteForm.value.transportChannel = row.transportChannel;

View File

@ -275,7 +275,7 @@ const data = reactive<PageData<LogisticsQuoteForm, LogisticsQuoteQuery>>({
surcharge: [{ required: true, message: '附加费不能为空', trigger: 'blur' }], surcharge: [{ required: true, message: '附加费不能为空', trigger: 'blur' }],
quoteDate: [{ required: true, message: '报价生效日期不能为空', trigger: 'blur' }], quoteDate: [{ required: true, message: '报价生效日期不能为空', trigger: 'blur' }],
isSubmitted: [{ required: true, message: '提交状态不能为空', trigger: 'blur' }], isSubmitted: [{ required: true, message: '提交状态不能为空', trigger: 'blur' }],
remark: [{ required: true, message: '报价备注不能为空', trigger: 'blur' }], // remark: [{ required: true, message: '', trigger: 'blur' }],
channelType: [{ required: true, message: '渠道类型不能为空', trigger: 'change' }], channelType: [{ required: true, message: '渠道类型不能为空', trigger: 'change' }],
channelId: [{ required: true, message: '渠道ID不能为空', trigger: 'blur' }], channelId: [{ required: true, message: '渠道ID不能为空', trigger: 'blur' }],
isDdp: [{ required: true, message: '是否双清包税不能为空', trigger: 'blur' }], isDdp: [{ required: true, message: '是否双清包税不能为空', trigger: 'blur' }],

View File

@ -28,14 +28,16 @@
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">--> <el-col :span="1.5">
<!-- <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:purchaseOrder:add']">新增 </el-button>--> <el-button type="primary" plain icon="RefreshRight" @click="handleOrderAdd" v-hasPermi="['amz:purchaseOrder:add']">
<!-- </el-col>--> 同步今天的采购单
<!-- <el-col :span="1.5">--> </el-button>
<!-- <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:purchaseOrder:edit']"--> </el-col>
<!-- >修改--> <el-col :span="1.5">
<!-- </el-button>--> <el-button type="success" plain icon="Refresh" @click="handleOrderUpdate()" v-hasPermi="['amz:purchaseOrder:edit']"
<!-- </el-col>--> >更新采购单状态
</el-button>
</el-col>
<!-- <el-col :span="1.5">--> <!-- <el-col :span="1.5">-->
<!-- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:purchaseOrder:remove']"--> <!-- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:purchaseOrder:remove']"-->
<!-- >删除--> <!-- >删除-->
@ -388,7 +390,9 @@ import {
delPurchaseOrder, delPurchaseOrder,
addPurchaseOrder, addPurchaseOrder,
updatePurchaseOrder, updatePurchaseOrder,
confirmPurchaseOrder confirmPurchaseOrder,
takeTodayPurchaseOrder,
updateTodayPurchaseOrder
} from '@/api/amz/purchaseOrder'; } from '@/api/amz/purchaseOrder';
import { PurchaseOrderVO, PurchaseOrderQuery, PurchaseOrderForm } from '@/api/amz/purchaseOrder/types'; import { PurchaseOrderVO, PurchaseOrderQuery, PurchaseOrderForm } from '@/api/amz/purchaseOrder/types';
@ -654,6 +658,19 @@ const handleSelectionChange = (selection: PurchaseOrderVO[]) => {
multiple.value = !selection.length; multiple.value = !selection.length;
}; };
const handleOrderAdd = async () => {
//
const res = await takeTodayPurchaseOrder();
console.log(res);
};
const handleOrderUpdate = async () => {
//
//
const res = await updateTodayPurchaseOrder();
console.log(res);
};
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
reset(); reset();

View File

@ -98,7 +98,7 @@
<dict-tag :options="vendor_order_status" :value="scope.row.orderStatus" /> <dict-tag :options="vendor_order_status" :value="scope.row.orderStatus" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="订单状态时间线" align="center" prop="casesNum"> <el-table-column label="订单状态时间线" align="center" prop="casesNum" width="200px">
<template #default="scope"> <template #default="scope">
<el-timeline style="max-width: 600px; margin-top: 25px"> <el-timeline style="max-width: 600px; margin-top: 25px">
<el-timeline-item <el-timeline-item
@ -257,9 +257,9 @@
<el-table-column label="备注" align="center" prop="remark" /> <el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-hasRoles="['superadmin', 'gengdan', 'gongying']"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-hasRoles="['superadmin', 'gengdan', 'gongying']">
<template #default="scope"> <template #default="scope">
<el-tooltip content="修改" placement="top"> <el-button link type="primary" size=" small" @click="handleUpdate(scope.row)" v-hasPermi="['amz:purchaseOrder:edit']"
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:purchaseOrder:edit']"></el-button> >设置延期
</el-tooltip> </el-button>
<!-- <el-button size="small" link type="primary" @click="handleConfirm(scope.row)" v-hasPermi="['amz:purchaseOrder:remove']"> 确认 </el-button>--> <!-- <el-button size="small" link type="primary" @click="handleConfirm(scope.row)" v-hasPermi="['amz:purchaseOrder:remove']"> 确认 </el-button>-->
</template> </template>
@ -418,6 +418,7 @@
<el-form-item label="发货方" prop="outSupplierName"> <el-form-item label="发货方" prop="outSupplierName">
<el-input v-model="forwardForm.outSupplierName" placeholder="请输入发货供应商名称" disabled /> <el-input v-model="forwardForm.outSupplierName" placeholder="请输入发货供应商名称" disabled />
</el-form-item> </el-form-item>
<!-- <el-form-item label="发货方ID" prop="outSupplierId">--> <!-- <el-form-item label="发货方ID" prop="outSupplierId">-->
<!-- <el-input v-model="forwardForm.outSupplierId" placeholder="请输入发货供应商系统ID" />--> <!-- <el-input v-model="forwardForm.outSupplierId" placeholder="请输入发货供应商系统ID" />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
@ -427,12 +428,15 @@
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.rawData" :disabled="item.disabled"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.rawData" :disabled="item.disabled">
<!-- 自定义选项内容 --> <!-- 自定义选项内容 -->
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
<span style="float: right; color: #8492a6; font-size: 13px"> <!-- <span style="float: right; color: #8492a6; font-size: 13px">-->
{{ item.rawData.userName }} <!-- {{ item.rawData.userName }}-->
</span> <!-- </span>-->
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="收货方采购单" prop="inOrderSn">
<el-input v-model="forwardForm.inOrderSn" placeholder="请输入收货方采购单" />
</el-form-item>
<!-- <el-form-item label="收货方ID" prop="inSupplierId">--> <!-- <el-form-item label="收货方ID" prop="inSupplierId">-->
<!-- <el-input v-model="forwardForm.inSupplierId" placeholder="请输入收货供应商系统ID" />--> <!-- <el-input v-model="forwardForm.inSupplierId" placeholder="请输入收货供应商系统ID" />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
@ -461,7 +465,7 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="forwardSubmitForm"> </el-button> <el-button :loading="buttonLoading" type="primary" @click="forwardSubmitForm"> </el-button>
<el-button @click="cancel"> </el-button> <el-button @click="forwardDialog.visible = false"> </el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
@ -881,6 +885,7 @@ const data = reactive<PageData<PurchaseOrderForm, PurchaseOrderQuery>>({
rules2: { rules2: {
id: [{ required: true, message: '$comment不能为空', trigger: 'blur' }], id: [{ required: true, message: '$comment不能为空', trigger: 'blur' }],
orderSn: [{ required: true, message: '采购单号不能为空', trigger: 'blur' }], orderSn: [{ required: true, message: '采购单号不能为空', trigger: 'blur' }],
inOrderSn: [{ required: true, message: '收货方采购单号不能为空', trigger: 'blur' }],
storeName: [{ required: true, message: '采购店铺名称不能为空', trigger: 'blur' }], storeName: [{ required: true, message: '采购店铺名称不能为空', trigger: 'blur' }],
sku: [{ required: true, message: '产品唯一标识码不能为空', trigger: 'blur' }], sku: [{ required: true, message: '产品唯一标识码不能为空', trigger: 'blur' }],
productName: [{ required: true, message: '产品全称不能为空', trigger: 'blur' }], productName: [{ required: true, message: '产品全称不能为空', trigger: 'blur' }],
@ -1119,7 +1124,7 @@ const handleUpdate = async (row?: PurchaseOrderVO) => {
const res = await getPurchaseOrder(_id); const res = await getPurchaseOrder(_id);
Object.assign(form.value, res.data); Object.assign(form.value, res.data);
dialog.visible = true; dialog.visible = true;
dialog.title = '修改订单状态'; dialog.title = '设置延期';
}; };
const handleConfirm = async (row?: PurchaseOrderVO) => { const handleConfirm = async (row?: PurchaseOrderVO) => {
@ -1407,7 +1412,7 @@ const shipSubmitForm = () => {
numberToLetter(index) + numberToLetter(index) +
': ' + ': ' +
group.boxCount + group.boxCount +
'箱' + '箱x' +
group.itemCount + group.itemCount +
'件,长' + '件,长' +
group.lengthPerBox + group.lengthPerBox +

View File

@ -58,8 +58,9 @@
<el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" />--> <!-- <el-table-column type="selection" width="55" align="center" />-->
<el-table-column label="发货单号" align="center" prop="id" />
<el-table-column label="采购单号" align="center" prop="orderSn" /> <el-table-column label="采购单号" align="center" prop="orderSn" />
<el-table-column label="发货单号" align="center" prop="id" />
<el-table-column label="创建日期" align="center" prop="createTime" width="180"> <el-table-column label="创建日期" align="center" prop="createTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
@ -407,13 +408,6 @@ const addGroup = () => {
}); });
}; };
const formatText = (text) => {
if (text === null) {
return '';
}
return text.replace(/\n/g, '<br>');
};
// //
const removeGroup = (index) => { const removeGroup = (index) => {
groups.value.splice(index, 1); groups.value.splice(index, 1);

View File

@ -59,8 +59,9 @@
<el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" />--> <!-- <el-table-column type="selection" width="55" align="center" />-->
<!-- <el-table-column label="主键ID" align="center" prop="id" />--> <!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<el-table-column label="发货单号" align="center" prop="id" />
<el-table-column label="采购单号" align="center" prop="orderSn" /> <el-table-column label="采购单号" align="center" prop="orderSn" />
<el-table-column label="发货单号" align="center" prop="id" />
<el-table-column label="创建日期" align="center" prop="createTime" width="180"> <el-table-column label="创建日期" align="center" prop="createTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>

View File

@ -59,9 +59,80 @@
<el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="sendOrderList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" />--> <!-- <el-table-column type="selection" width="55" align="center" />-->
<!-- <el-table-column label="主键ID" align="center" prop="id" />--> <!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<el-table-column label="发货单号" align="center" prop="id" /> <el-table-column type="expand">
<template #default="props">
<el-card shadow="never">
<el-table :data="props.row.bizShipmentPlans">
<!-- <el-table-column type="selection" width="55" align="center" />-->
<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 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="750" trigger="hover">-->
<!-- <template #reference>-->
<!-- <el-button size="small" plain 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="150" property="asin" label="asin" />-->
<!-- <el-table-column width="150" property="fnsku" label="fnsku" />-->
<!-- <el-table-column width="200" property="msku" label="msku" />-->
<!-- </el-table>-->
<!-- </el-popover>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="国家" align="center" prop="shipToAddress.countryCode" />
<el-table-column label="物流中心编码" align="center" prop="destination" />
<!-- <el-table-column label="关联的采购单" align="center">-->
<!-- <template #default="scope">-->
<!-- <el-tag v-if="scope.row.sendOrders != null" type="success">已关联</el-tag>-->
<!-- <el-tag v-else type="info">未关联</el-tag>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column width="150" label="仓库配送地址" align="center" prop="shipToAddress">-->
<!-- <template #default="{ row }">-->
<!-- &lt;!&ndash; <el-button @click="openAddressDialog(row.shipToAddress)"> 查看详情</el-button>&ndash;&gt;-->
<!-- <el-popover placement="left" :width="800" trigger="click">-->
<!-- <template #reference>-->
<!-- &lt;!&ndash; <el-button style="margin-right: 16px">Click to activate</el-button>&ndash;&gt;-->
<!-- <el-button plain size="small" type="success"> 点击查看详情</el-button>-->
<!-- </template>-->
<!-- <el-descriptions title="收货地址信息" :column="3" border>-->
<!-- <el-descriptions-item v-for="item in descriptItems" :key="item.prop" :label="item.label">-->
<!-- {{ row.shipToAddress[item.prop] || 'N/A' }}-->
<!-- </el-descriptions-item>-->
<!-- </el-descriptions>-->
<!-- </el-popover>-->
<!-- </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" class-name="small-padding fixed-width">-->
<!-- <template #default="scope">-->
<!-- &lt;!&ndash; <el-tooltip content="修改" placement="top" v-if="scope.row.sendStatus === 'pending'">&ndash;&gt;-->
<!-- &lt;!&ndash; <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:sendOrder:edit']"></el-button>&ndash;&gt;-->
<!-- &lt;!&ndash; </el-tooltip>&ndash;&gt;-->
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:sendOrder:remove']"></el-button>-->
<!-- </el-tooltip>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
</el-card>
</template>
</el-table-column>
<el-table-column label="采购单号" align="center" prop="orderSn" /> <el-table-column label="采购单号" align="center" prop="orderSn" />
<el-table-column label="发货单号" align="center" prop="id" />
<el-table-column label="创建日期" align="center" prop="createTime" width="180"> <el-table-column label="创建日期" align="center" prop="createTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
@ -102,6 +173,12 @@
<!-- <el-table-column label="箱子尺寸" align="center" prop="boxDimensions" />--> <!-- <el-table-column label="箱子尺寸" align="center" prop="boxDimensions" />-->
<el-table-column label="总重量" align="center" prop="weightPerBox" /> <el-table-column label="总重量" align="center" prop="weightPerBox" />
<el-table-column label="实际发货店铺" align="center" prop="realStoreName" /> <el-table-column label="实际发货店铺" align="center" prop="realStoreName" />
<el-table-column label="关联的采购单" align="center">
<template #default="scope">
<el-tag v-if="scope.row.bizShipmentPlans != null" type="success">已关联</el-tag>
<el-tag v-else type="info">未关联</el-tag>
</template>
</el-table-column>
<el-table-column label="发货状态" align="center" prop="sendStatus"> <el-table-column label="发货状态" align="center" prop="sendStatus">
<template #default="scope"> <template #default="scope">
<dict-tag :options="send_status" :value="scope.row.sendStatus" /> <dict-tag :options="send_status" :value="scope.row.sendStatus" />
@ -110,13 +187,13 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
v-if="scope.row.sendStatus === 'confirm'" v-if="scope.row.sendStatus === 'confirm' || scope.row.sendStatus === 'set_store'"
size="small" size="small"
link link
type="primary" type="primary"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasRoles="['superadmin', 'gengdan', 'yunying']" v-hasRoles="['superadmin', 'gengdan', 'yunying']"
>待创建FBA >确认发货
</el-button> </el-button>
<el-tooltip content="删除" placement="top"> <el-tooltip content="删除" placement="top">
@ -186,6 +263,7 @@
import { listSendOrder, getSendOrder, delSendOrder, addSendOrder, updateSendOrder } from '@/api/amz/sendOrder'; import { listSendOrder, getSendOrder, delSendOrder, addSendOrder, updateSendOrder } from '@/api/amz/sendOrder';
import { SendOrderVO, SendOrderQuery, SendOrderForm } from '@/api/amz/sendOrder/types'; import { SendOrderVO, SendOrderQuery, SendOrderForm } from '@/api/amz/sendOrder/types';
import { formatText } from '@/utils/asinkj'; import { formatText } from '@/utils/asinkj';
import { ElTable } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { send_status } = toRefs<any>(proxy?.useDict('send_status')); const { send_status } = toRefs<any>(proxy?.useDict('send_status'));
@ -311,11 +389,12 @@ const handleUpdate = async (row?: SendOrderVO) => {
const res = await getSendOrder(_id); const res = await getSendOrder(_id);
Object.assign(form.value, res.data); Object.assign(form.value, res.data);
dialog.visible = true; dialog.visible = true;
dialog.title = '待创建FBA货件信息'; dialog.title = '确认发货';
}; };
/** 提交按钮 */ /** 提交按钮 */
const submitForm = () => { const submitForm = () => {
form.value.sendStatus = 'set_store';
sendOrderFormRef.value?.validate(async (valid: boolean) => { sendOrderFormRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
buttonLoading.value = true; buttonLoading.value = true;
@ -355,3 +434,66 @@ onMounted(() => {
getList(); getList();
}); });
</script> </script>
<style scoped>
/* 展开行容器 */
:deep(.el-table__expanded-cell) {
background: #f5fbfd !important;
padding: 0 !important;
border-bottom: none !important;
}
/* 内嵌表格容器 */
:deep(.el-table__expanded-cell) .el-table {
--el-table-bg-color: #ebf3ff !important;
--el-table-tr-bg-color: #f5fbfd !important;
--el-table-header-bg-color: #cfe2ff !important; /* 表头变量 */
--el-table-header-text-color: #2c3e50 !important; /* 新增文字颜色 */
}
/* 表格主体容器 */
:deep(.el-table__expanded-cell) .el-table__body-wrapper {
background: #ebf3ff !important;
}
/* 表头单元格精准控制 */
:deep(.el-table__expanded-cell) .el-table__header th {
background-color: #cfe2ff !important; /* 覆盖默认背景 */
border-bottom: 2px solid #a6c5ff !important; /* 表头下边框 */
}
/* 表头文字样式 */
:deep(.el-table__expanded-cell) .el-table__header .cell {
color: #1a2b3c !important;
font-weight: 600; /* 加粗字体 */
}
/* 单元格背景 */
:deep(.el-table__expanded-cell) .el-table__body tr td {
background-color: transparent !important;
}
/* 消除卡片干扰 */
:deep(.el-card) {
background: transparent !important;
border: none !important;
}
/* 内嵌表格hover效果 */
:deep(.el-table__expanded-cell) .el-table__body tr:hover > td {
background-color: #ffffff !important;
}
/* 表头hover状态 */
:deep(.el-table__expanded-cell) .el-table__header tr:hover th {
background-color: #b6d4ff !important;
}
/* 表头排序按钮颜色 */
:deep(.el-table__expanded-cell) .el-table__header .sort-caret.ascending {
border-bottom-color: #1a2b3c;
}
:deep(.el-table__expanded-cell) .el-table__header .sort-caret.descending {
border-top-color: #1a2b3c;
}
</style>

View File

@ -76,12 +76,14 @@
<!-- <el-table-column type="selection" width="55" align="center" />--> <!-- <el-table-column type="selection" width="55" align="center" />-->
<el-table-column label="转发单号" align="center" prop="id" /> <el-table-column label="转发单号" align="center" prop="id" />
<el-table-column label="采购单号" align="center" prop="orderSn" /> <el-table-column label="发货方采购单号" align="center" prop="orderSn" />
<el-table-column label="收货方采购单号" align="center" prop="inOrderSn" />
<el-table-column label="采购店铺名称" align="center" prop="storeName" /> <el-table-column label="采购店铺名称" align="center" prop="storeName" />
<el-table-column label="SKU" align="center" prop="sku" /> <el-table-column label="SKU" align="center" prop="sku" />
<el-table-column label="产品全称" align="center" prop="productName" /> <el-table-column label="产品全称" align="center" prop="productName" />
<el-table-column label="发货数量" align="center" prop="quantitySend" /> <el-table-column label="发货数量" align="center" prop="quantitySend" />
<el-table-column label="发货箱数" align="center" prop="boxNum" /> <el-table-column label="发货箱数" align="center" prop="boxNum" />
<el-table-column label="总金额" align="center" prop="totalPrice" />
<el-table-column label="发货方" align="center" prop="outSupplierName" /> <el-table-column label="发货方" align="center" prop="outSupplierName" />
<!-- <el-table-column label="发货供应商系统ID" align="center" prop="outSupplierId" />--> <!-- <el-table-column label="发货供应商系统ID" align="center" prop="outSupplierId" />-->

View File

@ -179,9 +179,9 @@
<el-form-item label="发货数量" prop="quantitySend"> <el-form-item label="发货数量" prop="quantitySend">
<el-input v-model="form.quantitySend" placeholder="请输入发货数量" disabled /> <el-input v-model="form.quantitySend" placeholder="请输入发货数量" disabled />
</el-form-item> </el-form-item>
<el-form-item label="发货箱数" prop="quantitySend"> <!-- <el-form-item label="发货箱数" prop="quantitySend">-->
<el-input v-model="form.boxNum" placeholder="请输入发货箱数" disabled /> <!-- <el-input v-model="form.boxNum" placeholder="请输入发货箱数" disabled />-->
</el-form-item> <!-- </el-form-item>-->
<el-form-item label="发货时间" prop="sendTime"> <el-form-item label="发货时间" prop="sendTime">
<el-date-picker clearable v-model="form.sendTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择发货时间" disabled> <el-date-picker clearable v-model="form.sendTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择发货时间" disabled>
</el-date-picker> </el-date-picker>
@ -199,7 +199,20 @@
<el-form-item label="发货箱数" prop="boxNum"> <el-form-item label="发货箱数" prop="boxNum">
<!-- <el-input v-model="form.boxNum" placeholder="请输入发货数量" />--> <!-- <el-input v-model="form.boxNum" placeholder="请输入发货数量" />-->
<el-input-number v-model="form.boxNum" :min="1" :max="10" controls-position="right" size="default" /> <el-input-number v-model="form.boxNum" :min="1" :max="100000" controls-position="right" size="default" />
</el-form-item>
<el-form-item label="总金额" prop="totalPrice">
<!-- <el-input v-model="form.totalPrice" placeholder="请输入总金额" suffix="元">-->
<!-- <template #prefix>-->
<!-- <span class="suffix-text"></span>-->
<!-- &lt;!&ndash; 可自定义样式 &ndash;&gt;-->
<!-- </template>-->
<!-- </el-input>-->
<el-input-number v-model="form.totalPrice" :min="0" :max="10000000" controls-position="right">
<template #prefix>
<span></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>

View File

@ -57,6 +57,9 @@
>同步今天的货件 >同步今天的货件
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button type="primary" plain @click="batchLinkOrderAction" v-hasPermi="['amz:shipmentPlan:export']"> 关联采购单 </el-button>
</el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="Check" @click="channelDialogVisibleAction" v-hasPermi="['amz:shipmentPlan:export']" <el-button type="primary" plain icon="Check" @click="channelDialogVisibleAction" v-hasPermi="['amz:shipmentPlan:export']"
>批量提交询价 >批量提交询价
@ -77,20 +80,93 @@
> >
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<el-descriptions size="small" border title="货件详情"> <el-card shadow="never">
<el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item> <el-table :data="props.row.sendOrders">
<!-- <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>--> <!-- <el-table-column type="selection" width="55" align="center" />-->
<!-- <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>--> <el-table-column label="采购单号" align="center" prop="orderSn" />
<!-- <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>--> <el-table-column label="发货单号" align="center" prop="id" />
<!-- <el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>--> <el-table-column label="创建日期" align="center" prop="createTime" width="180">
<template #default="scope">
<!-- <el-descriptions-item label="创建时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>--> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
<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> </template>
</el-table-column> </el-table-column>
<el-table-column label="发货日期" align="center" prop="sendDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.sendDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="采购店铺" align="center" prop="storeName" />
<el-table-column label="供应商名称" align="center" prop="sendName" />
<el-table-column label="物流商名称" align="center" prop="logisticsProviderName">
<!-- <template #default="{ row }">-->
<!-- <el-popover placement="top" title="物流商地址" :width="200" trigger="click">-->
<!-- <template #reference>-->
<!-- <el-button v-if="row.logisticsProviderName !== null" text size="small" type="primary">-->
<!-- {{ row.logisticsProviderName }}-->
<!-- </el-button>-->
<!-- </template>-->
<!-- <div>{{ row.address || '暂无地址' }}</div>-->
<!-- </el-popover>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="发货数量" align="center" prop="quantitySend" />
<!-- <el-table-column label="单箱产品数量" align="center" prop="quantityPerBox" />-->
<el-table-column label="箱数" align="center" prop="boxCount">
<template #default="{ row }">
<el-popover placement="top" title="装箱明细" :width="500" trigger="click">
<template #reference>
<el-button text size="small" type="primary"> {{ row.boxCount }}</el-button>
</template>
<div v-if="row.sendDetail !== null" v-html="formatText(row.sendDetail)"></div>
<div v-else>暂无数据</div>
</el-popover>
</template>
</el-table-column>
<!-- <el-table-column label="箱子尺寸" align="center" prop="boxDimensions" />-->
<el-table-column label="总重量" align="center" prop="weightPerBox" />
<el-table-column label="实际发货店铺" align="center" prop="realStoreName" />
<!-- <el-table-column label="发货状态" align="center" prop="sendStatus">-->
<!-- <template #default="scope">-->
<!-- <dict-tag :options="send_status" :value="scope.row.sendStatus" />-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<!-- <el-tooltip content="修改" placement="top" v-if="scope.row.sendStatus === 'pending'">-->
<!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['amz:sendOrder:edit']"></el-button>-->
<!-- </el-tooltip>-->
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDeleteRelation(props.row.id, scope.row.id)"
v-hasRoles="['superadmin', 'yunying']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</el-table-column>
<!-- <el-table-column type="expand">-->
<!-- <template #default="props">-->
<!-- <el-descriptions size="small" border title="货件详情">-->
<!-- <el-descriptions-item label="货件名称">{{ props.row.shipmentName }}</el-descriptions-item>-->
<!-- &lt;!&ndash; <el-descriptions-item label="货件状态">{{ props.row.shipmentStatus }}</el-descriptions-item>&ndash;&gt;-->
<!-- &lt;!&ndash; <el-descriptions-item label="运输模式">{{ props.row.shippingMode }}</el-descriptions-item>&ndash;&gt;-->
<!-- &lt;!&ndash; <el-descriptions-item label="运输方案">{{ props.row.shippingSolution }}</el-descriptions-item>&ndash;&gt;-->
<!-- &lt;!&ndash; <el-descriptions-item label="入库计划ID">{{ props.row.staInboundPlanId }}</el-descriptions-item>&ndash;&gt;-->
<!-- &lt;!&ndash; <el-descriptions-item label="创建时间">{{ parseTime(props.row.gmtCreate, '{y}-{m}-{d}') }} </el-descriptions-item>&ndash;&gt;-->
<!-- <el-descriptions-item label="计划发货日期">{{ parseTime(props.row.staShipmentDate, '{y}-{m}-{d}') }} </el-descriptions-item>-->
<!-- &lt;!&ndash; <el-descriptions-item label="预计到货开始日">{{ parseTime(props.row.staDeliveryStartDate, '{y}-{m}-{d}') }} </el-descriptions-item>&ndash;&gt;-->
<!-- &lt;!&ndash; <el-descriptions-item label="预计到货截止日">{{ parseTime(props.row.staDeliveryEndDate, '{y}-{m}-{d}') }} </el-descriptions-item>&ndash;&gt;-->
<!-- </el-descriptions>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="创建日期" align="center" prop="gmtCreate" width="180"> <el-table-column label="创建日期" align="center" prop="gmtCreate" width="180">
<template #default="scope"> <template #default="scope">
@ -98,6 +174,7 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="店铺名称" align="center" prop="sellerName" /> <el-table-column label="店铺名称" align="center" prop="sellerName" />
<el-table-column label="货件编号" align="center" prop="shipmentId" /> <el-table-column label="货件编号" align="center" prop="shipmentId" />
<el-table-column label="商品详情" align="center"> <el-table-column label="商品详情" align="center">
<template #default="scope"> <template #default="scope">
@ -116,6 +193,12 @@
</el-table-column> </el-table-column>
<el-table-column label="国家" align="center" prop="shipToAddress.countryCode" /> <el-table-column label="国家" align="center" prop="shipToAddress.countryCode" />
<el-table-column label="物流中心编码" align="center" prop="destination" /> <el-table-column label="物流中心编码" align="center" prop="destination" />
<el-table-column label="关联的采购单" align="center">
<template #default="scope">
<el-tag v-if="scope.row.sendOrders != null" type="success">已关联</el-tag>
<el-tag v-else type="info">未关联</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="物流中心编码" align="center" prop="destination">--> <!-- <el-table-column label="物流中心编码" align="center" prop="destination">-->
<!-- <template #default="scope">--> <!-- <template #default="scope">-->
<!-- <RouterLink--> <!-- <RouterLink-->
@ -130,35 +213,35 @@
<!-- <el-table-column label="箱子尺寸" align="center" prop="boxSize" />--> <!-- <el-table-column label="箱子尺寸" align="center" prop="boxSize" />-->
<!-- <el-table-column label="供应商称重-总重量" align="center" prop="vendorWeight" />--> <!-- <el-table-column label="供应商称重-总重量" align="center" prop="vendorWeight" />-->
<!-- <el-table-column label="套数" align="center" prop="setTotal" />--> <!-- <el-table-column label="套数" align="center" prop="setTotal" />-->
<el-table-column label="关联采购单" align="center" prop="sendOrderId"> <!-- <el-table-column label="关联采购单" align="center" prop="sendOrderId">-->
<template #default="scope"> <!-- <template #default="scope">-->
<el-popover v-if="scope.row.sendOrderId" placement="top" :width="800" trigger="click"> <!-- <el-popover v-if="scope.row.sendOrderId" placement="top" :width="800" trigger="click">-->
<template #reference> <!-- <template #reference>-->
<!-- <el-button style="margin-right: 16px">Click to activate</el-button>--> <!-- &lt;!&ndash; <el-button style="margin-right: 16px">Click to activate</el-button>&ndash;&gt;-->
<el-button size="small" plain v-if="scope.row.sendOrderId" type="success"> 已关联</el-button> <!-- <el-button size="small" plain v-if="scope.row.sendOrderId" type="success"> 已关联</el-button>-->
</template> <!-- </template>-->
<el-descriptions v-if="scope.row.sendOrderId" title="供应商发货单" border :column="2" label-class-name="desc-label"> <!-- <el-descriptions v-if="scope.row.sendOrderId" title="供应商发货单" border :column="2" label-class-name="desc-label">-->
<!-- 订单信息 --> <!-- &lt;!&ndash; 订单信息 &ndash;&gt;-->
<el-descriptions-item label="订单编号" min-width="120px"> <!-- <el-descriptions-item label="订单编号" min-width="120px">-->
{{ scope.row.sendOrder.orderSn }} <!-- {{ scope.row.sendOrder.orderSn }}-->
</el-descriptions-item> <!-- </el-descriptions-item>-->
<el-descriptions-item label="产品名称"> <!-- <el-descriptions-item label="产品名称">-->
{{ scope.row.sendOrder.productName }} <!-- {{ scope.row.sendOrder.productName }}-->
</el-descriptions-item> <!-- </el-descriptions-item>-->
<el-descriptions-item label="总箱数"> {{ scope.row.sendOrder.boxCount }} </el-descriptions-item> <!-- <el-descriptions-item label="总箱数"> {{ scope.row.sendOrder.boxCount }} </el-descriptions-item>-->
<el-descriptions-item label="总重量"> {{ scope.row.sendOrder.weightPerBox }} kg</el-descriptions-item> <!-- <el-descriptions-item label="总重量"> {{ scope.row.sendOrder.weightPerBox }} kg</el-descriptions-item>-->
<el-descriptions-item label="箱体规格"> {{ scope.row.sendOrder.sendDetail }}</el-descriptions-item> <!-- <el-descriptions-item label="箱体规格"> {{ scope.row.sendOrder.sendDetail }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="每箱数量"> {{ scope.row.sendOrder.quantityPerBox }} / </el-descriptions-item>--> <!-- &lt;!&ndash; <el-descriptions-item label="每箱数量"> {{ scope.row.sendOrder.quantityPerBox }} / </el-descriptions-item>&ndash;&gt;-->
</el-descriptions> <!-- </el-descriptions>-->
</el-popover> <!-- </el-popover>-->
<el-tooltip class="box-item" effect="dark" content="点击关联采购单" placement="top"> <!-- &lt;!&ndash; <el-tooltip class="box-item" effect="dark" content="点击关联采购单" placement="top">&ndash;&gt;-->
<el-button size="small" plain v-if="!scope.row.sendOrderId" type="info" @click="handleLink(scope.row)"> 未关联 </el-button> <!-- <el-button size="small" plain v-if="!scope.row.sendOrderId" type="info" @click="handleLink(scope.row)"> 未关联 </el-button>-->
</el-tooltip> <!-- &lt;!&ndash; </el-tooltip>&ndash;&gt;-->
</template> <!-- </template>-->
</el-table-column> <!-- </el-table-column>-->
<!-- <el-table-column label="渠道ID" align="center" prop="channelId" />--> <!-- <el-table-column label="渠道ID" align="center" prop="channelId" />-->
@ -190,16 +273,16 @@
<el-tooltip content="向物流商询价" placement="top"> <el-tooltip content="向物流商询价" placement="top">
<el-button link type="primary" size="small" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"> </el-button> <el-button link type="primary" size="small" @click="handleUpdate(scope.row)" v-hasPermi="['amz:shipmentPlan:edit']"> </el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="关联采购单" placement="top"> <!-- <el-tooltip content="关联采购单" placement="top">-->
<el-button <!-- <el-button-->
link <!-- link-->
type="primary" <!-- type="primary"-->
icon="Link" <!-- icon="Link"-->
size="small" <!-- size="small"-->
@click="handleLink(scope.row)" <!-- @click="handleLink(scope.row)"-->
v-hasPermi="['amz:shipmentPlan:edit']" <!-- v-hasPermi="['amz:shipmentPlan:edit']"-->
></el-button> <!-- ></el-button>-->
</el-tooltip> <!-- </el-tooltip>-->
<!-- <el-tooltip content="删除" placement="top">--> <!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>--> <!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:shipmentPlan:remove']"></el-button>-->
<!-- </el-tooltip>--> <!-- </el-tooltip>-->
@ -354,10 +437,11 @@
</el-dialog> </el-dialog>
<el-dialog v-model="orderTableVisible.visible" title="选择需要关联的采购单" width="1800"> <el-dialog v-model="orderTableVisible.visible" title="选择需要关联的采购单" width="1800">
<el-table v-loading="loading" :data="sendOrderList"> <el-table v-loading="loading" :data="sendOrderList" @selection-change="linkOrderSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="id" />--> <!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<el-table-column label="采购单号" align="center" prop="orderSn" /> <el-table-column label="采购单号" align="center" prop="orderSn" />
<el-table-column label="送货单号" align="center" prop="id" width="180" />
<el-table-column label="发货日期" align="center" prop="sendDate" width="180"> <el-table-column label="发货日期" align="center" prop="sendDate" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.sendDate, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.sendDate, '{y}-{m}-{d}') }}</span>
@ -371,21 +455,28 @@
<!-- <el-table-column label="箱子尺寸" align="center" prop="boxDimensions" />--> <!-- <el-table-column label="箱子尺寸" align="center" prop="boxDimensions" />-->
<el-table-column label="总重量" align="center" prop="weightPerBox" /> <el-table-column label="总重量" align="center" prop="weightPerBox" />
<el-table-column label="实际采购店铺" align="center" prop="realStoreName" /> <el-table-column label="实际采购店铺" align="center" prop="realStoreName" />
<el-table-column label="发货状态" align="center" prop="sendStatus"> <!-- <el-table-column label="发货状态" align="center" prop="sendStatus">-->
<template #default="scope"> <!-- <template #default="scope">-->
<dict-tag :options="send_status" :value="scope.row.sendStatus" /> <!-- <dict-tag :options="send_status" :value="scope.row.sendStatus" />-->
</template> <!-- </template>-->
</el-table-column> <!-- </el-table-column>-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">-->
<template #default="scope"> <!-- <template #default="scope">-->
<el-button link type="primary" size="small" @click="handleLinkOrder(scope.row)">关联采购单</el-button> <!-- <el-button link type="primary" size="small" @click="handleLinkOrder(scope.row)">关联采购单</el-button>-->
<!-- <el-tooltip content="删除" placement="top">--> <!-- &lt;!&ndash; <el-tooltip content="删除" placement="top">&ndash;&gt;-->
<!-- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:sendOrder:remove']"></el-button>--> <!-- &lt;!&ndash; <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:sendOrder:remove']"></el-button>&ndash;&gt;-->
<!-- </el-tooltip>--> <!-- &lt;!&ndash; </el-tooltip>&ndash;&gt;-->
</template> <!-- </template>-->
</el-table-column> <!-- </el-table-column>-->
</el-table> </el-table>
<template #footer>
<div class="dialog-footer">
<!-- <el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>-->
<!-- <el-button @click="cancel"> </el-button>-->
<el-button type="primary" @click="handleLinkBatchOrder()">关联采购单</el-button>
</div>
</template>
</el-dialog> </el-dialog>
<el-drawer size="60%" v-model="drawer" :direction="direction"> <el-drawer size="60%" v-model="drawer" :direction="direction">
@ -437,7 +528,9 @@ import {
addShipmentPlan, addShipmentPlan,
updateShipmentPlan, updateShipmentPlan,
takeTodayAmzPlanData, takeTodayAmzPlanData,
linkShipmentPlan linkShipmentPlan,
createBatchRelations,
deleteShipmentPlanSendOrder
} from '@/api/amz/shipmentPlan'; } from '@/api/amz/shipmentPlan';
import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel'; import { listAllLogisticsChannel } from '@/api/amz/logisticsChannel';
import type { DrawerProps } from 'element-plus'; import type { DrawerProps } from 'element-plus';
@ -454,6 +547,7 @@ import { InquiryRequestItemVO } from '@/api/amz/inquiryRequest/types';
import { listSendOrder } from '@/api/amz/sendOrder'; import { listSendOrder } from '@/api/amz/sendOrder';
import { PurchaseOrderVO } from '@/api/amz/purchaseOrder/types'; import { PurchaseOrderVO } from '@/api/amz/purchaseOrder/types';
import { SendOrderVO } from '@/api/amz/sendOrder/types'; import { SendOrderVO } from '@/api/amz/sendOrder/types';
import { formatText } from '@/utils/asinkj';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_transport_channel } = toRefs<any>(proxy?.useDict('biz_transport_channel')); const { biz_transport_channel } = toRefs<any>(proxy?.useDict('biz_transport_channel'));
@ -790,7 +884,7 @@ const batchCascaderChange = (value) => {
// console.log('channelCascaderRef', channelCascaderRef); // console.log('channelCascaderRef', channelCascaderRef);
// console.log('label====', channelCascaderRef.value.getCheckedNodes()); // console.log('label====', channelCascaderRef.value.getCheckedNodes());
}; };
const multiSelect = ref(true);
const channelDialogVisibleAction = () => { const channelDialogVisibleAction = () => {
if (selectionDatas.value === undefined || selectionDatas.value?.length === 0) { if (selectionDatas.value === undefined || selectionDatas.value?.length === 0) {
ElMessage.error('请选择需要批量提交的数据'); ElMessage.error('请选择需要批量提交的数据');
@ -798,7 +892,7 @@ const channelDialogVisibleAction = () => {
} }
let allHasSendOrder = true; let allHasSendOrder = true;
selectionDatas.value.forEach((item) => { selectionDatas.value.forEach((item) => {
if (!item.sendOrderId) { if (item.sendOrders == null || item.sendOrders.length === 0) {
allHasSendOrder = false; allHasSendOrder = false;
} }
}); });
@ -815,6 +909,38 @@ const channelDialogVisibleAction = () => {
}); });
}; };
const batchLinkOrderAction = async () => {
multiSelect.value = false;
if (selectionDatas.value === undefined || selectionDatas.value?.length === 0) {
ElMessage.error('请勾选需要关联的数据');
return;
}
orderQueryParams.value.sendStatus = 'confirm,completed,set_store';
console.log('orderQueryParams', orderQueryParams.value);
const res = await listSendOrder(orderQueryParams.value);
sendOrderList.value = res.rows;
orderTableVisible.visible = true;
// let allHasSendOrder = true;
// selectionDatas.value.forEach((item) => {
// if (!item.sendOrderId) {
// allHasSendOrder = false;
// }
// });
//
// if (!allHasSendOrder) {
// ElMessage.error('');
// return;
// }
// channelDialogVisible.value = true;
// console.log('channelDialogVisibleAction', selectionDatas.value.length);
// selectionDatas.value.forEach((item) => {
// console.log(item.channelId);
// });
};
function confirmClick() { function confirmClick() {
ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`) ElMessageBox.confirm(`你确定要关闭 ${radio1.value} ?`)
.then(() => { .then(() => {
@ -979,6 +1105,7 @@ const reset = () => {
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
console.log('queryParams.value.gmtCreate', queryParams.value.gmtCreate); console.log('queryParams.value.gmtCreate', queryParams.value.gmtCreate);
queryParams.value.shipmentId = queryParams.value.shipmentId.trim();
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
getList(); getList();
}; };
@ -998,11 +1125,17 @@ const handleSelectionChange = (selection: ShipmentPlanVO[]) => {
const selectionDatas = ref<ShipmentPlanVO[]>(); const selectionDatas = ref<ShipmentPlanVO[]>();
const selectionLinkDatas = ref<SendOrderVO[]>();
/** 多选框选中数据 */ /** 多选框选中数据 */
const fbaDataSelectionChange = (selection: ShipmentPlanVO[]) => { const fbaDataSelectionChange = (selection: ShipmentPlanVO[]) => {
selectionDatas.value = selection; selectionDatas.value = selection;
}; };
const linkOrderSelectionChange = (selection: SendOrderVO[]) => {
selectionLinkDatas.value = selection;
};
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
reset(); reset();
@ -1092,9 +1225,21 @@ const checkPrice = async () => {
// } // }
}; };
const handleDeleteRelation = async (shipmentPlanId: number, sendOrderId: number) => {
console.log('shipmentPlanId', shipmentPlanId);
console.log('sendOrderId', sendOrderId);
const res = await deleteShipmentPlanSendOrder(shipmentPlanId, sendOrderId);
if (res.code == 200) {
ElMessage.success('删除成功');
getList();
} else {
ElMessage.error('删除失败');
}
};
/** 修改按钮操作 */ /** 修改按钮操作 */
const handleUpdate = async (row?: ShipmentPlanVO) => { const handleUpdate = async (row?: ShipmentPlanVO) => {
if (!row.sendOrderId) { console.log('row', row);
if (row.sendOrders == null || row.sendOrders.length === 0) {
ElMessage.warning('请先关联采购单!'); ElMessage.warning('请先关联采购单!');
return; return;
} }
@ -1125,6 +1270,7 @@ const linkShipmentPlanVO = ref<ShipmentPlanVO>();
const handleLink = async (row: any) => { const handleLink = async (row: any) => {
console.log('row', row); console.log('row', row);
return;
// const res = await getShipmentPlan(row.id); // const res = await getShipmentPlan(row.id);
// console.log('res', res); // console.log('res', res);
// if (res.code == 200) { // if (res.code == 200) {
@ -1132,8 +1278,8 @@ const handleLink = async (row: any) => {
// getList(); // getList();
// } // }
linkShipmentPlanVO.value = row; linkShipmentPlanVO.value = row;
orderQueryParams.value.realStoreName = row.sellerName; // orderQueryParams.value.realStoreName = row.sellerName;
orderQueryParams.value.sendStatus = 'confirm'; orderQueryParams.value.sendStatus = 'confirm,completed';
console.log('orderQueryParams', orderQueryParams.value); console.log('orderQueryParams', orderQueryParams.value);
const res = await listSendOrder(orderQueryParams.value); const res = await listSendOrder(orderQueryParams.value);
sendOrderList.value = res.rows; sendOrderList.value = res.rows;
@ -1142,21 +1288,69 @@ const handleLink = async (row: any) => {
orderTableVisible.title = '选择需要关联的采购单'; orderTableVisible.title = '选择需要关联的采购单';
console.log('res', res); console.log('res', res);
}; };
//plan sendOrder
const handleLinkOrder = async (row: SendOrderVO) => { const handleLinkOrder = async (row: ShipmentPlanVO) => {
console.log('row', row); console.log('row', row);
const shipmentIds: (string | number)[] = [];
selectionDatas.value.forEach((item) => {
shipmentIds.push(item.id);
});
const updateForm = ref({ const updateForm = ref({
id: linkShipmentPlanVO.value.id, linkType: '1',
sendOrderId: row.id, // id: linkShipmentPlanVO.value.id,
// sendOrderIds: sendOrderIds,
sendStatus: 'completed', sendStatus: 'completed',
shipmentId: linkShipmentPlanVO.value.shipmentId // shipmentId: row.id,
sendOrderIds: [row.id],
shipmentIds: shipmentIds
// boxSize: plength.value + '*' + pwidth.value + '*' + pheight.value, // boxSize: plength.value + '*' + pwidth.value + '*' + pheight.value,
// vendorWeight: form.value.vendorWeight, // vendorWeight: form.value.vendorWeight,
// setTotal: form.value.setTotal // setTotal: form.value.setTotal
// channelId: selectedChannel, // channelId: selectedChannel,
// channelName: channelCascaderRef.value.getCheckedNodes()[0].label // channelName: channelCascaderRef.value.getCheckedNodes()[0].label
}); });
const res = await linkShipmentPlan(updateForm.value).finally(() => (buttonLoading.value = false)); const res = await createBatchRelations(updateForm.value).finally(() => (buttonLoading.value = false));
console.log('res', res);
if (res.code == 200) {
orderTableVisible.visible = false;
ElMessage.success('关联成功');
getList();
}
};
//plan sendOrder
const handleLinkBatchOrder = async () => {
if (selectionLinkDatas.value === undefined || selectionLinkDatas.value?.length === 0) {
ElMessage.error('请勾选需要关联的数据');
return;
}
const sendOrderIds: (string | number)[] = [];
selectionLinkDatas.value.forEach((item) => {
sendOrderIds.push(item.id);
});
const shipmentIds: (string | number)[] = [];
selectionDatas.value.forEach((item) => {
shipmentIds.push(item.id);
});
const updateForm = ref({
linkType: '2',
// id: linkShipmentPlanVO.value.id,
sendOrderIds: sendOrderIds,
shipmentIds: shipmentIds,
sendStatus: 'completed'
// shipmentIds: shipmentIds
// boxSize: plength.value + '*' + pwidth.value + '*' + pheight.value,
// vendorWeight: form.value.vendorWeight,
// setTotal: form.value.setTotal
// channelId: selectedChannel,
// channelName: channelCascaderRef.value.getCheckedNodes()[0].label
});
const res = await createBatchRelations(updateForm.value).finally(() => (buttonLoading.value = false));
console.log('res', res); console.log('res', res);
if (res.code == 200) { if (res.code == 200) {
orderTableVisible.visible = false; orderTableVisible.visible = false;
@ -1293,3 +1487,66 @@ onMounted(() => {
getAllChannelData(); getAllChannelData();
}); });
</script> </script>
<style scoped>
/* 展开行容器 */
:deep(.el-table__expanded-cell) {
background: #f5fbfd !important;
padding: 0 !important;
border-bottom: none !important;
}
/* 内嵌表格容器 */
:deep(.el-table__expanded-cell) .el-table {
--el-table-bg-color: #ebf3ff !important;
--el-table-tr-bg-color: #f5fbfd !important;
--el-table-header-bg-color: #cfe2ff !important; /* 表头变量 */
--el-table-header-text-color: #2c3e50 !important; /* 新增文字颜色 */
}
/* 表格主体容器 */
:deep(.el-table__expanded-cell) .el-table__body-wrapper {
background: #ebf3ff !important;
}
/* 表头单元格精准控制 */
:deep(.el-table__expanded-cell) .el-table__header th {
background-color: #cfe2ff !important; /* 覆盖默认背景 */
border-bottom: 2px solid #a6c5ff !important; /* 表头下边框 */
}
/* 表头文字样式 */
:deep(.el-table__expanded-cell) .el-table__header .cell {
color: #1a2b3c !important;
font-weight: 600; /* 加粗字体 */
}
/* 单元格背景 */
:deep(.el-table__expanded-cell) .el-table__body tr td {
background-color: transparent !important;
}
/* 消除卡片干扰 */
:deep(.el-card) {
background: transparent !important;
border: none !important;
}
/* 内嵌表格hover效果 */
:deep(.el-table__expanded-cell) .el-table__body tr:hover > td {
background-color: #ffffff !important;
}
/* 表头hover状态 */
:deep(.el-table__expanded-cell) .el-table__header tr:hover th {
background-color: #b6d4ff !important;
}
/* 表头排序按钮颜色 */
:deep(.el-table__expanded-cell) .el-table__header .sort-caret.ascending {
border-bottom-color: #1a2b3c;
}
:deep(.el-table__expanded-cell) .el-table__header .sort-caret.descending {
border-top-color: #1a2b3c;
}
</style>

View File

@ -1,48 +1,35 @@
<template> <template>
<div class="login"> <div class="login">
<!-- 登录表单 -->
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<div class="title-box"> <div class="title-box">
<h3 class="title">香港SMT订单物流管理系统</h3> <h3 class="title">香港SMT订单物流管理系统</h3>
<!-- <lang-select />--> <p class="subtitle">智能化物流解决方案</p>
<!-- 右上角语言切换按钮 -->
<!-- <div class="language-switcher" @click="toggleLanguage">-->
<!-- <svg-icon icon-class="language" class="language-icon" />-->
<!-- </div>-->
</div> </div>
<!-- <el-form-item v-if="tenantEnabled" prop="tenantId">-->
<!-- <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">-->
<!-- <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>-->
<!-- <template #prefix>-->
<!-- <svg-icon icon-class="company" class="el-input__icon input-icon" />-->
<!-- </template>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')"> <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="用户名">
<template #prefix> <template #prefix>
<svg-icon icon-class="user" class="el-input__icon input-icon" /> <svg-icon icon-class="user" class="el-input__icon input-icon" />
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
v-model="loginForm.password"
type="password"
size="large"
auto-complete="off"
:placeholder="proxy.$t('login.password')"
@keyup.enter="handleLogin"
>
<template #prefix> <template #prefix>
<svg-icon icon-class="password" class="el-input__icon input-icon" /> <svg-icon icon-class="password" class="el-input__icon input-icon" />
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="captchaEnabled" prop="code"> <el-form-item v-if="captchaEnabled" prop="code">
<el-input <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
v-model="loginForm.code"
size="large"
auto-complete="off"
:placeholder="proxy.$t('login.code')"
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix> <template #prefix>
<svg-icon icon-class="validCode" class="el-input__icon input-icon" /> <svg-icon icon-class="validCode" class="el-input__icon input-icon" />
</template> </template>
@ -51,45 +38,43 @@
<img :src="codeUrl" class="login-code-img" @click="getCode" /> <img :src="codeUrl" class="login-code-img" @click="getCode" />
</div> </div>
</el-form-item> </el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }} </el-checkbox>
<!-- <el-form-item style="float: right">--> <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0"> 记住密码</el-checkbox>
<!-- <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">-->
<!-- <svg-icon icon-class="wechat" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">-->
<!-- <svg-icon icon-class="maxkey" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">-->
<!-- <svg-icon icon-class="topiam" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">-->
<!-- <svg-icon icon-class="gitee" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">-->
<!-- <svg-icon icon-class="github" />-->
<!-- </el-button>-->
<!-- </el-form-item>-->
<el-form-item style="width: 100%"> <el-form-item style="width: 100%">
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin"> <el-button :loading="loading" size="large" type="primary" class="login-btn" @click.prevent="handleLogin">
<span v-if="!loading">{{ proxy.$t('login.login') }}</span> <span v-if="!loading"> </span>
<span v-else>{{ proxy.$t('login.logging') }}</span> <span v-else> 中...</span>
</el-button> </el-button>
<div v-if="register" style="float: right">
<router-link class="link-type" :to="'/register'">{{ proxy.$t('login.switchRegisterPage') }}</router-link> <!-- <div style="float: right; margin-top: 15px">-->
</div> <!-- <router-link class="link-type" to="/register"> 注册新账号 </router-link>-->
<!-- </div>-->
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部 -->
<!-- 品牌展示区域 -->
<div class="brand-section">
<div class="brand-logo"></div>
<div class="slogan">
<h2>智慧物流管理系统</h2>
<p>让供应链更智能让物流更高效</p>
</div>
</div>
<!-- 底部版权信息 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span <span>
>Copyright © 2005 瑷胜科技 <el-link type="primary" href="https://beian.miit.gov.cn/" target="_blank">粤ICP备2025398203号</el-link> All Rights Copyright © 2005 瑷胜科技
Reserved.</span <el-link type="primary" href="https://beian.miit.gov.cn/" target="_blank"> 粤ICP备2025398203号 </el-link>
> All Rights Reserved.
</span>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { getCodeImg, getTenantList } from '@/api/login'; import { getCodeImg, getTenantList } from '@/api/login';
import { authBinding } from '@/api/system/social/auth'; import { authBinding } from '@/api/system/social/auth';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
@ -97,12 +82,12 @@ import { LoginData, TenantVO } from '@/api/types';
import { to } from 'await-to-js'; import { to } from 'await-to-js';
import { HttpStatus } from '@/enums/RespEnum'; import { HttpStatus } from '@/enums/RespEnum';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { ElForm, ElMessage } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { t, locale } = useI18n();
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const { t } = useI18n();
const loginForm = ref<LoginData>({ const loginForm = ref<LoginData>({
tenantId: '000000', tenantId: '000000',
@ -113,78 +98,66 @@ const loginForm = ref<LoginData>({
uuid: '' uuid: ''
} as LoginData); } as LoginData);
const loginRules: ElFormRules = { const loginRules = ref({
tenantId: [{ required: true, trigger: 'blur', message: t('login.rule.tenantId.required') }], tenantId: [{ required: true, trigger: 'blur', message: t('login.rule.tenantId.required') }],
username: [{ required: true, trigger: 'blur', message: t('login.rule.username.required') }], username: [{ required: true, trigger: 'blur', message: t('login.rule.username.required') }],
password: [{ required: true, trigger: 'blur', message: t('login.rule.password.required') }], password: [{ required: true, trigger: 'blur', message: t('login.rule.password.required') }],
code: [{ required: true, trigger: 'change', message: t('login.rule.code.required') }] code: [{ required: true, trigger: 'change', message: t('login.rule.code.required') }]
}; });
const codeUrl = ref(''); const codeUrl = ref('');
const loading = ref(false); const loading = ref(false);
//
const captchaEnabled = ref(true); const captchaEnabled = ref(true);
//
const tenantEnabled = ref(true); const tenantEnabled = ref(true);
//
const register = ref(false); const register = ref(false);
const redirect = ref('/'); const redirect = ref('/');
const loginRef = ref<ElFormInstance>(); const loginRef = ref<InstanceType<typeof ElForm>>();
//
const tenantList = ref<TenantVO[]>([]); const tenantList = ref<TenantVO[]>([]);
watch( watch(
() => router.currentRoute.value, () => router.currentRoute.value,
(newRoute: any) => { (newRoute) => {
redirect.value = newRoute.query && newRoute.query.redirect && decodeURIComponent(newRoute.query.redirect); redirect.value = newRoute.query.redirect && decodeURIComponent(newRoute.query.redirect as string);
}, },
{ immediate: true } { immediate: true }
); );
const handleLogin = () => { const handleLogin = () => {
loginRef.value?.validate(async (valid: boolean, fields: any) => { loginRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true;
// localStorage
if (loginForm.value.rememberMe) { if (loginForm.value.rememberMe) {
localStorage.setItem('tenantId', String(loginForm.value.tenantId)); localStorage.setItem('tenantId', loginForm.value.tenantId);
localStorage.setItem('username', String(loginForm.value.username)); localStorage.setItem('username', loginForm.value.username);
localStorage.setItem('password', String(loginForm.value.password)); localStorage.setItem('password', loginForm.value.password);
localStorage.setItem('rememberMe', String(loginForm.value.rememberMe)); localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
} else { } else {
//
localStorage.removeItem('tenantId'); localStorage.removeItem('tenantId');
localStorage.removeItem('username'); localStorage.removeItem('username');
localStorage.removeItem('password'); localStorage.removeItem('password');
localStorage.removeItem('rememberMe'); localStorage.removeItem('rememberMe');
} }
// action
const [err] = await to(userStore.login(loginForm.value)); try {
if (!err) { await userStore.login(loginForm.value);
const redirectUrl = redirect.value || '/'; const redirectUrl = redirect.value || '/';
await router.push(redirectUrl); await router.push(redirectUrl);
loading.value = false; } catch (error) {
} else { console.error('登录失败:', error);
loading.value = false;
//
if (captchaEnabled.value) { if (captchaEnabled.value) {
await getCode(); await getCode();
} }
} finally {
loading.value = false;
} }
} else {
console.log('error submit!', fields);
} }
}); });
}; };
/**
* 获取验证码
*/
const getCode = async () => { const getCode = async () => {
const res = await getCodeImg(); const res = await getCodeImg();
const { data } = res; const { data } = res;
captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled; captchaEnabled.value = data.captchaEnabled ?? true;
if (captchaEnabled.value) { if (captchaEnabled.value) {
codeUrl.value = 'data:image/gif;base64,' + data.img; codeUrl.value = 'data:image/gif;base64,' + data.img;
loginForm.value.uuid = data.uuid; loginForm.value.uuid = data.uuid;
@ -192,40 +165,28 @@ const getCode = async () => {
}; };
const getLoginData = () => { const getLoginData = () => {
const tenantId = localStorage.getItem('tenantId');
const username = localStorage.getItem('username');
const password = localStorage.getItem('password');
const rememberMe = localStorage.getItem('rememberMe');
loginForm.value = { loginForm.value = {
tenantId: tenantId === null ? String(loginForm.value.tenantId) : tenantId, tenantId: localStorage.getItem('tenantId') || '000000',
username: username === null ? String(loginForm.value.username) : username, username: localStorage.getItem('username') || '',
password: password === null ? String(loginForm.value.password) : String(password), password: localStorage.getItem('password') || '',
rememberMe: rememberMe === null ? false : Boolean(rememberMe) rememberMe: localStorage.getItem('rememberMe') === 'true'
} as LoginData; };
}; };
/**
* 获取租户列表
*/
const initTenantList = async () => { const initTenantList = async () => {
const { data } = await getTenantList(false); const { data } = await getTenantList(false);
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled; tenantEnabled.value = data.tenantEnabled ?? true;
if (tenantEnabled.value) { if (tenantEnabled.value) {
tenantList.value = data.voList; tenantList.value = data.voList;
if (tenantList.value != null && tenantList.value.length !== 0) { if (tenantList.value?.length) {
loginForm.value.tenantId = tenantList.value[0].tenantId; loginForm.value.tenantId = tenantList.value[0].tenantId;
} }
} }
}; };
/**
* 第三方登录
* @param type
*/
const doSocialLogin = (type: string) => { const doSocialLogin = (type: string) => {
authBinding(type, loginForm.value.tenantId).then((res: any) => { authBinding(type, loginForm.value.tenantId).then((res: any) => {
if (res.code === HttpStatus.SUCCESS) { if (res.code === HttpStatus.SUCCESS) {
//
window.location.href = res.data; window.location.href = res.data;
} else { } else {
ElMessage.error(res.msg); ElMessage.error(res.msg);
@ -233,6 +194,11 @@ const doSocialLogin = (type: string) => {
}); });
}; };
const toggleLanguage = () => {
locale.value = locale.value === 'zh-CN' ? 'en-US' : 'zh-CN';
ElMessage.success(t('login.languageChanged'));
};
onMounted(() => { onMounted(() => {
getCode(); getCode();
initTenantList(); initTenantList();
@ -241,83 +207,272 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.login { .brand-section {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 50%;
display: flex; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; padding-left: 10%;
background-image: url('../assets/images/login-background.jpg'); z-index: 1;
background-size: cover; @media (max-width: 768px) {
display: none;
}
.brand-logo {
width: 120px;
height: 120px;
background: linear-gradient(135deg, #ffffff 0%, #e3f2fd 100%);
border-radius: 24px;
margin-bottom: 30px;
position: relative;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80px;
height: 80px;
background: url('../assets/logo/logo.png') no-repeat center;
background-size: contain;
}
}
.slogan {
color: white;
text-align: center;
h2 {
font-size: 36px;
font-weight: 600;
margin-bottom: 15px;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
p {
font-size: 18px;
opacity: 0.9;
}
}
}
.login {
display: flex;
justify-content: flex-end;
align-items: center;
min-height: 100vh;
padding-right: 20%;
position: relative;
overflow: hidden;
// 使
background:
radial-gradient(circle at 90% 50%, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.4) 60%, transparent 100%),
url('@/assets/images/background.svg') center/cover;
//
.login-form {
position: relative;
z-index: 10;
width: 400px;
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
padding: 30px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(220, 220, 235, 0.3);
transition:
transform 0.3s,
box-shadow 0.3s;
&:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
} }
.title-box { .title-box {
display: flex; text-align: center;
margin-bottom: 25px;
position: relative;
.title { .title {
margin: 0px auto 30px auto; margin: 0 0 8px 0;
text-align: center; color: #2c3e50;
color: #707070; font-size: 24px;
} font-weight: 700;
letter-spacing: 0.5px;
position: relative;
padding-bottom: 15px;
:deep(.lang-select--style) { &::after {
line-height: 0; content: '';
color: #7483a3; position: absolute;
bottom: 0;
left: 20%;
right: 20%;
height: 2px;
background: linear-gradient(90deg, transparent, #409eff, transparent);
} }
} }
.login-form { .subtitle {
border-radius: 6px; color: #5a5e66;
background: #ffffff; font-size: 14px;
width: 400px; font-weight: 400;
padding: 25px 25px 5px 25px; margin-top: 5px;
}
.language-switcher {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
padding: 8px;
border-radius: 50%;
transition: all 0.3s;
color: #409eff;
&:hover {
background-color: rgba(64, 158, 255, 0.1);
transform: scale(1.1);
}
.language-icon {
font-size: 20px;
}
}
}
.el-form-item {
margin-bottom: 22px;
.el-input { .el-input {
height: 40px; height: 46px;
transition: all 0.3s;
border-radius: 8px;
input { :deep(.el-input__wrapper) {
height: 40px; border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.25);
}
&:focus-within {
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.3);
}
}
} }
} }
.input-icon { .login-btn {
height: 39px; height: 48px;
width: 14px; width: 100%;
margin-left: 0px; border-radius: 8px;
font-weight: 500;
letter-spacing: 0.8px;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
transition: all 0.3s;
background: linear-gradient(135deg, #1a5098, #409eff);
border: none;
&:hover {
transform: translateY(-2px);
box-shadow: 0 7px 14px rgba(64, 158, 255, 0.5);
}
&:active {
transform: translateY(0);
} }
} }
.login-tip { .el-checkbox {
font-size: 13px; .el-checkbox__label {
text-align: center; color: #5a5e66;
color: #bfbfbf; font-weight: 500;
}
} }
.login-code { .login-code {
width: 33%; border-radius: 6px;
height: 40px; overflow: hidden;
float: right; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
img { &:hover {
cursor: pointer; transform: translateY(-3px);
vertical-align: middle; box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial, serif;
font-size: 12px;
letter-spacing: 1px;
} }
.login-code-img { .login-code-img {
height: 40px; height: 42px;
padding-left: 12px; cursor: pointer;
display: block;
width: 120px;
}
}
.link-type {
color: #1a5098;
font-size: 14px;
text-decoration: none;
font-weight: 500;
transition: all 0.2s;
&:hover {
color: #409eff;
text-decoration: underline;
}
}
}
//
.el-login-footer {
position: fixed;
bottom: 20px;
left: 0;
right: 0;
text-align: center;
color: #fff;
font-size: 13px;
letter-spacing: 0.4px;
z-index: 10;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
.el-link {
color: rgba(255, 255, 255, 0.9);
font-size: 13px;
text-decoration: none;
&:hover {
color: #fff;
text-decoration: underline;
}
}
}
}
@media (max-width: 768px) {
.login {
justify-content: center;
padding-right: 0;
.login-form {
width: 90%;
margin: 0 auto;
&:hover {
transform: none;
}
}
}
} }
</style> </style>