@@ -0,0 +1,259 @@
< template >
< div class = "order-page" >
<!-- ═ ═ ═ 标题栏 ═ ═ ═ -- >
< div class = "page-header" >
< span class = "page-title" > 在途订单 < / span >
< el-tag type = "primary" size = "small" effect = "dark" class = "status-tag" > STATUS : TRANSIT < / el-tag >
< / div >
<!-- ═ ═ ═ 统计卡片 ═ ═ ═ -- >
< el-row :gutter = "12" class = "stat-row" >
< el-col :span = "6" >
< div class = "stat-card" style = "border-top-color:#4A6FA5" >
< div class = "stat-body" > < div class = "stat-num" > { { stats . totalTransit != null ? stats . totalTransit : '-' } } < / div > < div class = "stat-lbl" > 在途总数 < / div > < / div >
< i class = "el-icon-ship stat-icon" style = "color:#4A6FA5" > < / i >
< / div >
< / el-col >
< el-col :span = "6" >
< div class = "stat-card" style = "border-top-color:#67c23a" >
< div class = "stat-body" > < div class = "stat-num" > { { stats . todayShipped != null ? stats . todayShipped : '-' } } < / div > < div class = "stat-lbl" > 今日发货 < / div > < / div >
< i class = "el-icon-upload2 stat-icon" style = "color:#67c23a" > < / i >
< / div >
< / el-col >
< el-col :span = "6" >
< div class = "stat-card" style = "border-top-color:#e6a23c" >
< div class = "stat-body" > < div class = "stat-num" > { { stats . expiringSoon != null ? stats . expiringSoon : '-' } } < / div > < div class = "stat-lbl" > 即将到期 < / div > < / div >
< i class = "el-icon-time stat-icon" style = "color:#e6a23c" > < / i >
< / div >
< / el-col >
< el-col :span = "6" >
< div class = "stat-card" style = "border-top-color:#f56c6c" >
< div class = "stat-body" > < div class = "stat-num" > { { stats . overdue != null ? stats . overdue : '-' } } < / div > < div class = "stat-lbl" > 已逾期 < / div > < / div >
< i class = "el-icon-warning-outline stat-icon" style = "color:#f56c6c" > < / i >
< / div >
< / el-col >
< / el-row >
<!-- ═ ═ ═ 搜索栏 ═ ═ ═ -- >
< div class = "search-bar" >
< el-input v-model = "queryParams.doNo" placeholder="搜索发货单号" clearable size="small" style="width:150px" @keyup.enter.native="handleSearch" / >
< el-input v-model = "queryParams.supplierName" placeholder="搜索供应商名称" clearable size="small" style="width:160px" @keyup.enter.native="handleSearch" / >
< el-button type = "primary" size = "small" icon = "el-icon-search" @click ="handleSearch" > 搜索 < / el -button >
< el-button size = "small" icon = "el-icon-refresh" @click ="resetSearch" > 重置 < / el -button >
< div class = "search-right" >
< el-button size = "small" icon = "el-icon-refresh" @click ="getList" > 刷新 < / el -button >
< / div >
< / div >
<!-- ═ ═ ═ 表格 ═ ═ ═ -- >
< el-table v-loading = "loading" :data="list" border stripe size="small" class="order-table" >
< el -table -column label = "发货单号" prop = "doNo" width = "165" / >
< el-table-column label = "供应商" prop = "supplierName" min -width = " 150 " show -overflow -tooltip / >
< el-table-column label = "金额" width = "130" align = "right" >
< template slot -scope = " s " > < span class = "amount" > ¥ { { s . row . totalAmount } } < / span > < / template >
< / el-table-column >
< el-table-column label = "交货期" width = "100" align = "center" >
< template slot -scope = " s " >
< span :class = "getUrgentClass(s.row)" > { { s . row . deliveryDate } } < / span >
< / template >
< / el-table-column >
< el-table-column label = "延期至" prop = "delayDate" width = "100" align = "center" >
< template slot -scope = " s " > { { s . row . delayDate || '-' } } < / template >
< / el-table-column >
< el-table-column label = "物料" prop = "itemCount" width = "60" align = "center" / >
< el-table-column label = "逾期提示" width = "110" align = "center" >
< template slot -scope = " s " > < span v-html = "getUrgentBadge(s.row)" / > < / template >
< / el-table-column >
< el-table-column label = "状态" width = "90" align = "center" >
< template slot -scope = " s " >
< el-tag :type = "transitTagType(s.row)" size = "small" effect = "dark" > { { transitStatusLabel ( s . row ) } } < / el-tag >
< / template >
< / el-table-column >
< el-table-column label = "操作" width = "230" align = "center" fixed = "right" >
< template slot -scope = " s " >
< el-button size = "mini" type = "text" @click ="handleView(s.row)" > 详情 < / el -button >
< el-button size = "mini" type = "text" style = "color:#67C23A" @click ="handleComplete(s.row)" > 收货完成 < / el -button >
< el-button size = "mini" type = "text" style = "color:#e6a23c" @click ="handleDelay(s.row)" > 延期 < / el -button >
< el-button size = "mini" type = "text" @click ="handleRecall(s.row)" > 撤回 < / el -button >
< / template >
< / el-table-column >
< / el-table >
< pagination v-show = "total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" / >
<!-- ═ ═ ═ 详情弹窗 ═ ═ ═ -- >
< el-dialog title = "发货单详情" :visible.sync = "detailOpen" width = "780px" append -to -body >
< div v-if = "detailData" >
< div class = "detail-grid" >
< div class = "detail-item" > < span class = "dl" > 发货单号 < / span > < span class = "dv" > < b > { { detailData . doNo } } < / b > < / span > < / div >
< div class = "detail-item" > < span class = "dl" > 供应商 < / span > < span class = "dv" > { { detailData . supplierName || '-' } } < / span > < / div >
< div class = "detail-item" > < span class = "dl" > 总金额 < / span > < span class = "dv" style = "color:#409EFF;font-weight:700" > ¥ { { detailData . totalAmount } } < / span > < / div >
< div class = "detail-item" > < span class = "dl" > 状态 < / span > < span class = "dv" > < el-tag type = "primary" size = "small" effect = "dark" > TRANSIT < / el-tag > < / span > < / div >
< div class = "detail-item" > < span class = "dl" > 交货期 < / span > < span class = "dv" > { { detailData . deliveryDate || '-' } } < / span > < / div >
< div class = "detail-item" > < span class = "dl" > 延期日期 < / span > < span class = "dv" > { { detailData . delayDate || '-' } } < / span > < / div >
< / div >
< div v-if = "detailData.remark" class="detail-remark" > 备注 : {{ detailData.remark }} < / div >
< div class = "section-bar" > 物料明细 < / div >
< el-table : data = "detailData.items || []" border size = "small" >
< el-table-column label = "物料名称" prop = "materialName" min -width = " 150 " / >
< el-table-column label = "规格" prop = "spec" width = "120" show -overflow -tooltip / >
< el-table-column label = "单位" prop = "unit" width = "60" / >
< el-table-column label = "数量" prop = "quantity" width = "80" align = "right" / >
< el-table-column label = "单价" width = "100" align = "right" > < template slot -scope = " s " > ¥ { { s . row . unitPrice } } < / template > < / el-table-column >
< el-table-column label = "小计" width = "100" align = "right" > < template slot -scope = " s " > ¥ { { s . row . totalPrice } } < / template > < / el-table-column >
< / el-table >
< / div >
< div slot = "footer" > < el-button @click ="detailOpen = false" > 关闭 < / el -button > < / div >
< / el-dialog >
<!-- ═ ═ ═ 延期弹窗 ═ ═ ═ -- >
< el-dialog title = "申请延期" :visible.sync = "delayOpen" width = "450px" append -to -body >
< el-form :model = "delayForm" label -width = " 90px " size = "small" >
< el-form-item label = "发货单号" > { { delayForm . doNo } } < / el-form-item >
< el-form-item label = "原交货期" > { { delayForm . deliveryDate } } < / el-form-item >
< el-form-item label = "延期至" > < el-date-picker v-model = "delayForm.newDelayDate" type="date" value-format="yyyy-MM-dd" style="width:100%" placeholder="选择新日期" / > < / el-form-item >
< el-form-item label = "延期原因" > < el-input v-model = "delayForm.reason" type="textarea" :rows="3" placeholder="请输入延期原因" / > < / el-form-item >
< / el-form >
< div slot = "footer" >
< el-button @click ="delayOpen = false" > 取消 < / el -button >
< el-button type = "primary" @click ="submitDelay" > 确认延期 < / el -button >
< / div >
< / el-dialog >
< / div >
< / template >
< script >
import { listDelivery , getDelivery , completeDelivery , recallDelivery , updateDelivery } from "@/api/bid/delivery"
import request from '@/utils/request'
export default {
name : "OrderTransit" ,
data ( ) {
return {
loading : false , list : [ ] , total : 0 , stats : { } ,
queryParams : { pageNum : 1 , pageSize : 20 , deliveryStatus : "transit" , doNo : "" , supplierName : "" } ,
detailOpen : false , detailData : null ,
delayOpen : false , delayForm : { }
}
} ,
created ( ) { this . getList ( ) ; this . getStats ( ) } ,
methods : {
getList ( ) {
this . loading = true
listDelivery ( this . queryParams ) . then ( r => {
this . list = ( r . rows || [ ] ) . map ( d => ( { ... d , deliveryDate : d . deliveryDate ? d . deliveryDate . substring ( 0 , 10 ) : '' , delayDate : d . delayDate ? d . delayDate . substring ( 0 , 10 ) : '' } ) )
this . total = r . total || 0 ; this . loading = false
} ) . catch ( ( ) => { this . loading = false } )
} ,
getStats ( ) {
request ( { url : '/bid/delivery/transit/stats' , method : 'get' } ) . then ( r => { this . stats = r . data || { } } ) . catch ( ( ) => { } )
} ,
handleSearch ( ) { this . queryParams . pageNum = 1 ; this . getList ( ) } ,
resetSearch ( ) { this . queryParams . doNo = "" ; this . queryParams . supplierName = "" ; this . handleSearch ( ) } ,
handleView ( row ) { getDelivery ( row . doId ) . then ( r => { this . detailData = r . data ; this . detailOpen = true } ) . catch ( ( ) => { } ) } ,
handleComplete ( row ) {
this . $modal . confirm ( "确认该订单已收货完成?" ) . then ( ( ) => completeDelivery ( row . doId ) )
. then ( ( ) => { this . $modal . msgSuccess ( "已确认收货" ) ; this . getList ( ) ; this . getStats ( ) } ) . catch ( ( ) => { } )
} ,
handleDelay ( row ) {
this . delayForm = { doId : row . doId , doNo : row . doNo , deliveryDate : row . deliveryDate , newDelayDate : "" , reason : "" }
this . delayOpen = true
} ,
submitDelay ( ) {
if ( ! this . delayForm . newDelayDate ) { this . $modal . msgError ( "请选择延期日期" ) ; return }
updateDelivery ( { doId : this . delayForm . doId , delayDate : this . delayForm . newDelayDate } ) . then ( ( ) => {
this . $modal . msgSuccess ( "延期成功" ) ; this . delayOpen = false ; this . getList ( )
} ) . catch ( ( ) => { } )
} ,
handleRecall ( row ) {
this . $modal . confirm ( "确认撤回该订单?将回到待发状态。" ) . then ( ( ) => recallDelivery ( row . doId ) )
. then ( ( ) => { this . $modal . msgSuccess ( "已撤回" ) ; this . getList ( ) ; this . getStats ( ) } ) . catch ( ( ) => { } )
} ,
// 状态判断
transitTagType ( row ) {
if ( ! row . deliveryDate ) return "primary"
const diff = Math . round ( ( new Date ( row . deliveryDate ) - new Date ( ) ) / 86400000 )
if ( diff < 0 ) return "danger"
if ( diff <= 3 ) return "warning"
return "primary"
} ,
transitStatusLabel ( row ) {
if ( ! row . deliveryDate ) return "运输中"
const diff = Math . round ( ( new Date ( row . deliveryDate ) - new Date ( ) ) / 86400000 )
if ( diff < 0 ) return "已逾期"
if ( diff <= 3 ) return "即将到期"
return "正常在途"
} ,
getUrgentClass ( row ) {
if ( ! row . deliveryDate ) return ""
const diff = Math . round ( ( new Date ( row . deliveryDate ) - new Date ( ) ) / 86400000 )
if ( diff < 0 ) return "urgent-overdue"
if ( diff <= 3 ) return "urgent-soon"
return ""
} ,
getUrgentBadge ( row ) {
if ( ! row . deliveryDate ) return ""
const diff = Math . round ( ( new Date ( row . deliveryDate ) - new Date ( ) ) / 86400000 )
if ( diff < 0 ) return '<span class="urgent-overdue">⚠ 逾期' + Math . abs ( diff ) + '天</span>'
if ( diff === 0 ) return '<span class="urgent-overdue">⚠ 今日到期</span>'
if ( diff <= 3 ) return '<span class="urgent-soon">⚡ 剩' + diff + '天</span>'
return ""
}
}
}
< / script >
< style scoped >
. order - page { background : # f5f7fa ; padding : 12 px ; min - height : calc ( 100 vh - 84 px ) ; }
/* ═══ 标题栏 ═══ */
. page - header {
background : # fff ; padding : 12 px 16 px ; border - radius : 4 px ; margin - bottom : 12 px ;
box - shadow : 0 1 px 4 px rgba ( 0 , 0 , 0 , 0.06 ) ; display : flex ; align - items : center ; gap : 12 px ;
}
. page - title { font - size : 16 px ; font - weight : 700 ; color : # 1 a2c4e ; }
. status - tag { margin - left : auto ; }
/* ═══ 统计卡片 ═══ */
. stat - row { margin - bottom : 12 px ! important ; }
. stat - card {
background : # fff ; border - radius : 4 px ; border - top : 3 px solid # 4 A6FA5 ;
padding : 16 px 20 px ; display : flex ; align - items : center ; justify - content : space - between ;
box - shadow : 0 1 px 4 px rgba ( 0 , 0 , 0 , 0.06 ) ;
}
. stat - num { font - size : 26 px ; font - weight : 700 ; color : # 1 a2c4e ; line - height : 1.2 ; }
. stat - lbl { font - size : 12 px ; color : # 8 c97a8 ; margin - top : 4 px ; }
. stat - icon { font - size : 28 px ; opacity : 0.5 ; }
/* ═══ 搜索栏 ═══ */
. search - bar {
background : # fff ; padding : 12 px 16 px ; border - radius : 4 px ;
box - shadow : 0 1 px 4 px rgba ( 0 , 0 , 0 , 0.06 ) ; margin - bottom : 12 px ;
display : flex ; align - items : center ; gap : 8 px ; flex - wrap : wrap ;
}
. search - right { margin - left : auto ; }
/* ═══ 表格 ═══ */
. order - table { box - shadow : 0 1 px 4 px rgba ( 0 , 0 , 0 , 0.06 ) ; }
. amount { color : # 409 EFF ; font - weight : 700 ; }
. urgent - overdue { color : # f56c6c ; font - weight : 700 ; font - size : 12 px ; }
. urgent - soon { color : # e6a23c ; font - weight : 700 ; font - size : 12 px ; }
/* ═══ 详情 ═══ */
. detail - grid {
display : grid ; grid - template - columns : 1 fr 1 fr ; gap : 0 ;
border : 1 px solid # ebeef5 ; border - radius : 4 px ; margin - bottom : 16 px ;
}
. detail - item { display : flex ; border - bottom : 1 px solid # ebeef5 ; }
. detail - item : nth - last - child ( - n + 2 ) { border - bottom : none ; }
. detail - item : nth - child ( odd ) { border - right : 1 px solid # ebeef5 ; }
. dl { width : 90 px ; flex - shrink : 0 ; background : # f5f7fa ; padding : 10 px 12 px ; font - size : 12 px ; color : # 606266 ; font - weight : 600 ; border - right : 1 px solid # ebeef5 ; }
. dv { padding : 10 px 12 px ; font - size : 13 px ; color : # 303133 ; flex : 1 ; }
. detail - remark { padding : 8 px 12 px ; background : # fdf6ec ; border : 1 px solid # faecd8 ; border - radius : 4 px ; font - size : 12 px ; color : # e6a23c ; margin - bottom : 16 px ; }
. section - bar { font - size : 13 px ; font - weight : 700 ; color : # 1 a2c4e ; padding : 6 px 0 6 px 10 px ; margin - bottom : 10 px ; border - left : 4 px solid # 4 A6FA5 ; }
< / style >