Files
klp-oa/klp-ui/src/views/wms/post/aps/requirement.vue

1023 lines
33 KiB
Vue
Raw Normal View History

<template>
<div class="aps-req-page">
<el-row :gutter="20" class="aps-req-row">
<!-- 左侧产需单列表 -->
<el-col :span="8" class="aps-req-left" v-loading="reqLoading">
<!-- 筛选区 -->
<div class="filter-section" style="padding: 10px; border-bottom: 1px solid #e4e7ed;">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
<div style="display: flex; align-items: center; gap: 4px; flex-wrap: wrap;">
<el-input v-model="queryParams.scheduleNo" placeholder="排产单号" clearable @keyup.enter.native="handleSearch"
style="width: 130px;" size="small" />
<el-input v-model="queryParams.customerName" placeholder="客户名" clearable
@keyup.enter.native="handleSearch" style="width: 130px;" size="small" />
<el-date-picker v-model="queryParams.prodDate" type="date" placeholder="生产日期" value-format="yyyy-MM-dd"
style="width: 130px;" size="small" clearable @change="handleSearch" />
<el-button class="aps-btn-red" icon="el-icon-search" size="mini" @click="handleSearch">筛选</el-button>
<el-button class="aps-btn-red" icon="el-icon-plus" size="mini" @click="handleAdd"></el-button>
</div>
</div>
</div>
<div class="panel-header">
<span>产需单列表</span>
<span style="font-weight:normal;color:var(--text-muted);font-size:11px;"> {{ total }} </span>
</div>
<div class="list-container">
<div v-for="item in reqList" :key="item.scheduleId" class="list-item"
:class="{ active: currentReq && currentReq.scheduleId === item.scheduleId }" @click="handleReqClick(item)">
<div class="item-title">
{{ item.scheduleNo }}
<span class="badge" :class="'badge-' + statusBadgeType(item.scheduleStatus)">{{
statusMap[item.scheduleStatus] || '未知' }}</span>
</div>
<div class="item-sub">
生产日期{{ item.prodDate || '-' }} 客户{{ item.customerName || '-' }} 业务员{{ item.businessUser || '-' }}
</div>
<div class="item-actions">
<button class="link-btn" @click.stop="handleDelete(item)">删除</button>
</div>
</div>
<div v-if="reqList.length === 0 && !reqLoading" style="padding: 40px; text-align: center; color: #909399;">
暂无产需单数据
</div>
</div>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList"
style="padding: 10px; margin-bottom: 10px !important;" />
</el-col>
<!-- 右侧详情区 -->
<el-col :span="16" class="aps-req-right">
<el-empty v-if="!currentReq" description="选择产需单查看更多信息" />
<div v-else class="detail-panel">
<div class="detail-card">
<div class="detail-card-header">
<span>产需单信息</span>
<button class="header-btn" @click="handleEdit(currentReq)">编辑</button>
</div>
<div class="detail-card-body">
<table class="req-info-table">
<tbody>
<tr>
<td class="req-td-label">排产单号</td>
<td class="req-td-value">{{ currentReq.scheduleNo }}</td>
<td class="req-td-label">生产日期</td>
<td class="req-td-value">{{ currentReq.prodDate }}</td>
</tr>
<tr>
<td class="req-td-label">排产状态</td>
<td class="req-td-value"><span class="aps-status-tag"
:class="'status-' + (currentReq.scheduleStatus || 0)">{{ statusMap[currentReq.scheduleStatus] ||
'未知' }}</span></td>
<td class="req-td-label">业务员</td>
<td class="req-td-value">{{ currentReq.businessUser }}</td>
</tr>
<tr>
<td class="req-td-label">联系电话</td>
<td class="req-td-value">{{ currentReq.businessPhone }}</td>
<td class="req-td-label">订货单位</td>
<td class="req-td-value">{{ currentReq.customerName }}</td>
</tr>
<tr>
<td class="req-td-label">交货期()</td>
<td class="req-td-value">{{ currentReq.deliveryCycle }}</td>
<td class="req-td-label">产品用途</td>
<td class="req-td-value">{{ currentReq.usePurpose }}</td>
</tr>
<tr>
<td class="req-td-label">品名</td>
<td class="req-td-value" colspan="3">{{ currentReq.productType }}</td>
</tr>
<tr>
<td class="req-td-label">厚度公差</td>
<td class="req-td-value">{{ currentReq.thicknessTolerance }}</td>
<td class="req-td-label">宽度公差</td>
<td class="req-td-value">{{ currentReq.widthTolerance }}</td>
</tr>
<tr>
<td class="req-td-label">表面质量</td>
<td class="req-td-value">{{ currentReq.surfaceQuality }}</td>
<td class="req-td-label">表面处理</td>
<td class="req-td-value">{{ currentReq.surfaceTreatment }}</td>
</tr>
<tr>
<td class="req-td-label">内径尺寸</td>
<td class="req-td-value">{{ currentReq.innerDiameter }}</td>
<td class="req-td-label">外径要求</td>
<td class="req-td-value">{{ currentReq.outerDiameter }}</td>
</tr>
<tr>
<td class="req-td-label">包装要求</td>
<td class="req-td-value">{{ currentReq.packReq }}</td>
<td class="req-td-label">切边要求</td>
<td class="req-td-value">{{ currentReq.cutEdgeReq }}</td>
</tr>
<tr>
<td class="req-td-label">单件重量</td>
<td class="req-td-value">{{ currentReq.singleCoilWeight }}</td>
<td class="req-td-label">交货重量偏差</td>
<td class="req-td-value">{{ currentReq.weightDeviation }}</td>
</tr>
<tr>
<td class="req-td-label">其他技术要求</td>
<td class="req-td-value" colspan="3">{{ currentReq.otherTechReq }}</td>
</tr>
<tr>
<td class="req-td-label">付款情况说明</td>
<td class="req-td-value" colspan="3">{{ currentReq.paymentDesc }}</td>
</tr>
<tr>
<td class="req-td-label">备注</td>
<td class="req-td-value" colspan="3">{{ currentReq.remark }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="detail-card">
<div class="detail-card-header">
<span>已绑定的销售订单{{ boundOrderList.length }} </span>
<button class="header-btn" @click="openBindDialog">+ 添加订单</button>
</div>
<div class="detail-card-body" v-loading="boundLoading">
<div v-if="(currentReq.orderList || []).length === 0"
style="padding: 16px; text-align: center; color: #909399;">暂无绑定订单</div>
<div v-else class="bound-order-cards">
<div v-for="order in currentReq.orderList" :key="order.orderId" class="bound-order-card">
<div class="bound-order-card-header">
<span>{{ order.orderCode || ('订单 #' + order.orderId) }}</span>
<button class="link-btn" @click="handleUnbindByOrderId(order.orderId)">解绑</button>
</div>
<div class="bound-order-card-body">
<div style="font-size:12px; color:#7f8c8d; margin-bottom:3px;">
客户<span style="color:#2c3e50;">{{ order.companyName || '-' }}</span>
</div>
<div style="font-size:12px; color:#7f8c8d; margin-bottom:3px;">
销售员<span style="color:#2c3e50;">{{ order.salesman || '-' }}</span>
</div>
<div style="font-size:12px; color:#7f8c8d;">
交货日期<span style="color:#2c3e50;">{{ order.deliveryDate || '-' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="detail-card">
<div class="detail-card-header">
<span>排产明细{{ requirementDetailList.length }} 合计 {{ detailTotalWeight }} T</span>
</div>
<div class="detail-card-body" style="padding:0;">
<el-table :data="requirementDetailList" border size="small" v-loading="detailLoading" class="aps-table">
<el-table-column label="规格" prop="spec" min-width="120" />
<el-table-column label="材质" prop="material" width="90" align="center" />
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" />
<el-table-column label="备注" prop="remark" min-width="120" />
</el-table>
<el-empty v-if="requirementDetailList.length === 0 && !detailLoading" description="暂无排产明细" />
</div>
</div>
</div>
</el-col>
</el-row>
<!-- 新增/编辑对话框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="700px" append-to-body
:close-on-click-modal="false">
<el-form ref="reqForm" :model="reqForm" :rules="reqRules" label-width="110px" size="small">
<!-- 第一行必填项 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="排产单号" prop="scheduleNo">
<el-input v-model="reqForm.scheduleNo" placeholder="自动生成或手动填写" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产日期" prop="prodDate">
<el-date-picker v-model="reqForm.prodDate" type="date" value-format="yyyy-MM-dd" style="width:100%" />
</el-form-item>
</el-col>
</el-row>
<!-- 基本信息 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="订货单位" prop="customerName">
<el-input v-model="reqForm.customerName" />
</el-form-item>
<el-form-item label="业务员" prop="businessUser">
<el-input v-model="reqForm.businessUser" />
</el-form-item>
<el-form-item label="联系电话" prop="businessPhone">
<el-input v-model="reqForm.businessPhone" />
</el-form-item>
<el-form-item label="品名" prop="productType">
<el-input v-model="reqForm.productType" />
</el-form-item>
<el-form-item label="交货期(天)" prop="deliveryCycle">
<el-input-number v-model="reqForm.deliveryCycle" :min="0" :max="999" style="width:100%" />
</el-form-item>
<el-form-item label="产品用途" prop="usePurpose">
<el-input v-model="reqForm.usePurpose" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="厚度公差" prop="thicknessTolerance">
<el-input v-model="reqForm.thicknessTolerance" />
</el-form-item>
<el-form-item label="宽度公差" prop="widthTolerance">
<el-input v-model="reqForm.widthTolerance" />
</el-form-item>
<el-form-item label="表面质量" prop="surfaceQuality">
<el-input v-model="reqForm.surfaceQuality" />
</el-form-item>
<el-form-item label="表面处理" prop="surfaceTreatment">
<el-input v-model="reqForm.surfaceTreatment" />
</el-form-item>
<el-form-item label="内径尺寸" prop="innerDiameter">
<el-input v-model="reqForm.innerDiameter" />
</el-form-item>
<el-form-item label="外径要求" prop="outerDiameter">
<el-input v-model="reqForm.outerDiameter" />
</el-form-item>
</el-col>
</el-row>
<!-- 包装及其他 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="包装要求" prop="packReq">
<el-input v-model="reqForm.packReq" />
</el-form-item>
<el-form-item label="切边要求" prop="cutEdgeReq">
<el-input v-model="reqForm.cutEdgeReq" />
</el-form-item>
<el-form-item label="单件重量" prop="singleCoilWeight">
<el-input v-model="reqForm.singleCoilWeight" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="交货重量偏差" prop="weightDeviation">
<el-input v-model="reqForm.weightDeviation" />
</el-form-item>
<el-form-item label="其他技术要求" prop="otherTechReq">
<el-input v-model="reqForm.otherTechReq" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="付款情况说明" prop="paymentDesc">
<el-input v-model="reqForm.paymentDesc" type="textarea" :rows="2" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input v-model="reqForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="btnLoading" type="danger" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</div>
</el-dialog>
<!-- 绑定订单对话框 -->
<el-dialog title="添加绑定订单" :visible.sync="bindDialogVisible" width="860px" append-to-body
:close-on-click-modal="false" class="aps-bind-dialog">
<div style="display: flex; gap: 16px; height: 420px;">
<!-- 左侧订单列表 -->
<div style="width: 45%; display: flex; flex-direction: column;">
<div style="display: flex; gap: 6px; margin-bottom: 10px;">
<el-input v-model="bindQuery.keyword" placeholder="搜索订单编号/客户名" size="small" clearable style="flex:1;"
@change="searchBindOrders" />
<el-button size="small" class="aps-btn-red" icon="el-icon-search" @click="searchBindOrders">搜索</el-button>
</div>
<div style="flex:1; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px;"
v-loading="bindSearchLoading" element-loading-text="搜索中...">
<div v-for="item in candidateOrderList" :key="item.orderId" class="bind-order-item"
:class="{ selected: isBindSelected(item), previewing: bindPreviewOrder && bindPreviewOrder.orderId === item.orderId }"
@click="handleBindRowClick(item)">
<el-checkbox :value="isBindSelected(item)" @change="toggleBindOrder(item)" @click.stop
style="margin-right: 8px;" />
<div style="flex:1; min-width:0;">
<div style="font-weight:500; font-size:13px; color:#2c3e50;">{{ item.orderCode }}</div>
<div style="font-size:11px; color:#7f8c8d; margin-top:2px;">{{ item.companyName }} · {{ item.salesman }}
</div>
</div>
</div>
<div v-if="candidateOrderList.length === 0" style="padding:30px; text-align:center; color:#909399;">暂无订单
</div>
</div>
</div>
<!-- 右侧产品内容预览 -->
<div style="width: 55%; display: flex; flex-direction: column;">
<div
style="font-size:13px; font-weight:600; color:#2c3e50; margin-bottom:8px; padding-left:8px; border-left:3px solid #ff4d4f;">
{{ bindPreviewOrder ? bindPreviewOrder.orderCode + ' - 产品明细' : '点击订单行预览产品明细' }}
</div>
<div style="flex:1; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px; padding: 10px;"
v-if="bindPreviewOrder">
<el-table :data="bindPreviewProducts" border size="small" style="width:100%;">
<el-table-column label="规格" prop="spec" min-width="100" />
<el-table-column label="材质" prop="material" width="80" />
<el-table-column label="数量(吨)" prop="quantity" width="80" align="right" />
<!-- <el-table-column label="含税单价" prop="taxPrice" width="80" align="right" /> -->
<el-table-column label="备注" prop="remark" min-width="80" />
</el-table>
<div style="margin-top:8px; font-size:12px; color:#7f8c8d; display:flex; gap:16px;">
<span>产品名称{{ bindPreviewProductName }}</span>
<span>总数量{{ bindPreviewTotalQty }} </span>
<span>含税总额{{ bindPreviewTotalAmount }}</span>
</div>
</div>
<div v-else
style="flex:1; display:flex; align-items:center; justify-content:center; color:#bfbfbf; font-size:13px;">
请点击左侧订单行查看产品明细
</div>
</div>
</div>
<div slot="footer" class="dialog-footer" style="margin-top:12px;">
<span style="font-size:12px; color:#7f8c8d; margin-right:auto;">已选 {{ selectedBindOrders.length }} 个订单</span>
<el-button :loading="bindBtnLoading" type="danger" @click="confirmBind"> </el-button>
<el-button @click="bindDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listRequirement,
getRequirement,
addRequirement,
updateRequirement,
delRequirement,
addRel,
delRel,
addRequirementDetail
} from '@/api/aps/requirement'
import { listCrmOrder } from '@/api/aps/order'
import { parseProductContent } from '@/utils/productContent'
export default {
name: 'ApsRequirement',
data() {
return {
// 左侧列表
reqLoading: false,
reqList: [],
total: 0,
currentReq: null,
queryParams: {
scheduleNo: '',
prodDate: '',
customerName: '',
pageNum: 1,
pageSize: 10
},
statusMap: { 0: '草稿', 1: '待审核', 2: '已下达', 3: '已退回' },
statusBadgeMap: { 0: 'gray', 1: 'blue', 2: 'green', 3: 'red' },
// 绑定订单
boundOrderList: [],
bindDialogVisible: false,
bindQuery: { keyword: '', pageNum: 1, pageSize: 50 },
candidateOrderList: [],
selectedBindOrders: [],
bindBtnLoading: false,
bindSearchLoading: false,
bindPreviewOrder: null,
bindPreviewProducts: [],
bindPreviewProductName: '',
bindPreviewTotalQty: 0,
bindPreviewTotalAmount: 0,
// 排产明细
detailLoading: false,
requirementDetailList: [],
// 新增/编辑对话框
dialogVisible: false,
dialogTitle: '新增产需单',
btnLoading: false,
reqForm: this.getEmptyForm(),
reqRules: {
scheduleNo: [{ required: true, message: '排产单号不能为空', trigger: 'blur' }],
prodDate: [{ required: true, message: '生产日期不能为空', trigger: 'change' }]
}
}
},
computed: {
detailTotalWeight() {
return this.requirementDetailList.reduce((sum, item) => {
const n = Number(item.scheduleWeight)
return isNaN(n) ? sum : sum + n
}, 0)
}
},
created() {
this.getList()
},
methods: {
getEmptyForm() {
return {
scheduleId: undefined,
scheduleNo: '',
prodDate: '',
customerName: '',
businessUser: '',
businessPhone: '',
deliveryCycle: undefined,
usePurpose: '',
productType: '',
thicknessTolerance: '',
widthTolerance: '',
surfaceQuality: '',
surfaceTreatment: '',
innerDiameter: '',
outerDiameter: '',
packReq: '',
cutEdgeReq: '',
singleCoilWeight: '',
weightDeviation: '',
otherTechReq: '',
paymentDesc: '',
remark: ''
}
},
handleSearch() {
this.queryParams.pageNum = 1
this.getList()
},
statusBadgeType(status) {
return this.statusBadgeMap[status] || 'gray'
},
getList() {
this.reqLoading = true
listRequirement(this.queryParams).then(res => {
this.reqList = res.rows || []
this.total = res.total || 0
}).catch(() => {
this.reqList = []
this.total = 0
}).finally(() => {
this.reqLoading = false
})
},
handleReqClick(item) {
this.currentReq = item
this.detailLoading = true
getRequirement(item.scheduleId).then(res => {
if (res.data) {
this.currentReq = res.data
this.requirementDetailList = res.data.detailList || []
}
}).catch(() => {
this.requirementDetailList = []
}).finally(() => {
this.detailLoading = false
})
},
// ====== 新增/编辑 ======
resetForm() {
this.reqForm = this.getEmptyForm()
},
handleAdd() {
this.resetForm()
this.dialogTitle = '新增产需单'
this.dialogVisible = true
this.$nextTick(() => {
this.$refs.reqForm && this.$refs.reqForm.clearValidate()
})
},
handleEdit(item) {
getRequirement(item.scheduleId).then(res => {
this.reqForm = { ...this.getEmptyForm(), ...res.data }
this.dialogTitle = '编辑产需单'
this.dialogVisible = true
this.$nextTick(() => {
this.$refs.reqForm && this.$refs.reqForm.clearValidate()
})
})
},
submitForm() {
this.$refs.reqForm.validate(valid => {
if (!valid) return
this.btnLoading = true
const action = this.reqForm.scheduleId ? updateRequirement : addRequirement
action(this.reqForm).then(() => {
this.$modal.msgSuccess(this.reqForm.scheduleId ? '修改成功' : '新增成功')
this.dialogVisible = false
this.getList()
}).catch(() => {
this.$modal.msgError('操作失败')
}).finally(() => {
this.btnLoading = false
})
})
},
handleDelete(item) {
this.$confirm(`确认删除产需单「${item.scheduleNo}」吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delRequirement(item.scheduleId).then(() => {
this.$modal.msgSuccess('删除成功')
if (this.currentReq && this.currentReq.scheduleId === item.scheduleId) {
this.currentReq = null
}
this.getList()
})
}).catch(() => { })
},
openBindDialog() {
this.bindDialogVisible = true
this.selectedBindOrders = []
this.bindPreviewOrder = null
this.bindPreviewProducts = []
this.bindPreviewProductName = ''
this.bindPreviewTotalQty = 0
this.bindPreviewTotalAmount = 0
this.searchBindOrders()
},
searchBindOrders() {
this.bindSearchLoading = true
listCrmOrder(this.bindQuery).then(res => {
this.candidateOrderList = res.rows || []
}).catch(() => {
this.candidateOrderList = []
}).finally(() => {
this.bindSearchLoading = false
})
},
isBindSelected(order) {
return this.selectedBindOrders.some(o => o.orderId === order.orderId)
},
toggleBindOrder(order) {
const idx = this.selectedBindOrders.findIndex(o => o.orderId === order.orderId)
if (idx >= 0) {
this.selectedBindOrders.splice(idx, 1)
} else {
this.selectedBindOrders.push(order)
}
},
handleBindRowClick(order) {
this.bindPreviewOrder = order
if (order.productContent) {
const parsed = parseProductContent(order.productContent)
this.bindPreviewProducts = parsed.products || []
this.bindPreviewProductName = parsed.productName || ''
this.bindPreviewTotalQty = parsed.totalQuantity || 0
this.bindPreviewTotalAmount = parsed.totalTaxTotal || 0
} else {
this.bindPreviewProducts = []
this.bindPreviewProductName = ''
this.bindPreviewTotalQty = 0
this.bindPreviewTotalAmount = 0
}
},
confirmBind() {
if (this.selectedBindOrders.length === 0) {
this.$message.warning('请选择要绑定的订单')
return
}
this.bindBtnLoading = true
const scheduleId = this.currentReq.scheduleId
const allPromises = []
this.selectedBindOrders.forEach(order => {
// 1. 创建订单关联
allPromises.push(
addRel({
orderId: order.orderId,
scheduleId: scheduleId,
relWeight: null,
remark: ''
})
)
// 2. 解析 productContent每行产品创建一条排产明细
if (order.productContent) {
const parsed = parseProductContent(order.productContent)
const products = parsed.products || []
const productType = parsed.productName || ''
products.forEach(prod => {
allPromises.push(
addRequirementDetail({
scheduleId: scheduleId,
orderDetailId: order.orderId,
spec: prod.spec || '',
material: prod.material || '',
scheduleWeight: prod.quantity || 0,
productType: productType,
remark: prod.remark || ''
})
)
})
}
})
Promise.all(allPromises).then(() => {
this.$modal.msgSuccess('绑定成功,排产明细已生成')
this.bindDialogVisible = false
this.handleReqClick(this.currentReq)
}).catch(() => {
this.$modal.msgError('绑定或创建明细失败')
}).finally(() => {
this.bindBtnLoading = false
})
},
handleUnbindByOrderId(orderId) {
const rel = this.boundOrderList.find(r => r.orderId === orderId)
if (!rel) {
this.$message.warning('未找到关联记录')
return
}
this.$confirm('确认解绑该订单吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delRel(rel.relId).then(() => {
this.$modal.msgSuccess('解绑成功')
this.handleReqClick(this.currentReq)
})
}).catch(() => { })
},
}
}
</script>
<style scoped lang="scss">
@import './scss/aps-theme.scss';
.aps-req-page {
height: 100%;
padding: 8px;
box-sizing: border-box;
background: $aps-silver-1;
}
.aps-req-row {
height: 100%;
}
// ====== 左侧(参照 HTML 产需单列表) ======
.aps-req-left {
display: flex;
flex-direction: column;
height: 100%;
background: #fff;
border: 1px solid $aps-silver-3;
border-radius: 6px;
box-sizing: border-box;
overflow: hidden;
min-height: 0;
}
.panel-header {
background: $aps-silver-mid;
padding: 8px 12px;
font-size: 12px;
font-weight: 600;
color: $aps-text;
border-bottom: 1px solid $aps-border;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.list-container {
flex: 1;
overflow-y: auto;
min-height: 0;
}
.list-item {
padding: 10px 12px;
border-bottom: 1px solid $aps-silver-1;
cursor: pointer;
transition: background 0.15s;
}
.list-item:hover {
background: $aps-silver-1;
}
.list-item.active {
background: $aps-red-1;
border-left: 3px solid $aps-red-2;
}
.list-item .item-title {
font-weight: 500;
color: $aps-text;
font-size: 13px;
margin-bottom: 3px;
display: flex;
align-items: center;
gap: 6px;
}
.list-item .item-sub {
font-size: 12px;
color: $aps-text-muted;
margin-bottom: 4px;
}
.list-item .item-actions {
display: flex;
gap: 8px;
}
// ====== 徽标 ======
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
}
.badge-red {
background: #fdecea;
color: $aps-red-2;
border: 1px solid #f5b7b1;
}
.badge-green {
background: #eafaf1;
color: #27ae60;
border: 1px solid #a9dfbf;
}
.badge-blue {
background: #eaf4fb;
color: #2980b9;
border: 1px solid #aed6f1;
}
.badge-gray {
background: $aps-silver-1;
color: $aps-text-muted;
border: 1px solid $aps-border;
}
// ====== 右侧(平铺) ======
.aps-req-right {
height: 100%;
background: #fff;
border: 1px solid $aps-silver-3;
border-radius: 6px;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.detail-panel {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
background: $aps-bg;
min-height: 0;
}
// ====== 右侧详情卡片 ======
.detail-card {
background: $aps-white;
border: 1px solid $aps-border;
border-radius: $aps-radius;
box-shadow: $aps-shadow-sm;
overflow: hidden;
}
.detail-card-header {
background: linear-gradient(to right, $aps-red-2, $aps-red-3);
color: white;
padding: 8px 14px;
font-size: 13px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: space-between;
}
.detail-card-header .header-btn {
background: rgba(255, 255, 255, 0.25);
color: white;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 3px;
padding: 4px 12px;
font-size: 12px;
font-family: inherit;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.detail-card-header .header-btn:hover {
background: rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.7);
}
.detail-card-body {
padding: 0;
}
.req-info-table {
width: 100%;
border-collapse: collapse;
border: 1px solid $aps-border;
font-size: 13px;
td {
border: 1px solid $aps-border;
padding: 6px 10px;
vertical-align: middle;
}
.req-td-label {
background: $aps-silver-1;
color: $aps-text-muted;
font-weight: 500;
font-size: 12px;
white-space: nowrap;
width: 100px;
text-align: right;
}
.req-td-value {
color: $aps-text;
background: #fff;
word-break: break-all;
&:empty::after {
content: '-';
color: $aps-silver-3;
}
}
}
.aps-status-tag {
display: inline-block;
padding: 2px 10px;
border-radius: 3px;
font-size: 12px;
font-weight: 500;
&.status-0 {
background: $aps-silver-2;
color: $aps-silver-4;
}
&.status-1 {
background: #e6f7ff;
color: #1890ff;
}
&.status-2 {
background: #f6ffed;
color: #52c41a;
}
&.status-3 {
background: $aps-red-1;
color: $aps-red-2;
}
}
.aps-table {
width: 100%;
::v-deep th {
background: $aps-silver-1 !important;
color: $aps-silver-5 !important;
font-weight: 600 !important;
}
}
.link-btn {
color: $aps-red-2;
cursor: pointer;
font-size: 12px;
text-decoration: none;
background: none;
border: none;
padding: 0;
font-family: inherit;
}
.link-btn:hover {
text-decoration: underline;
}
// ====== Element 按钮覆盖 ======
::v-deep .el-button--danger {
background: $aps-red-2;
border-color: $aps-red-2;
}
::v-deep .el-button--danger:hover {
background: $aps-red-3;
border-color: $aps-red-3;
}
// ====== 按钮 ======
.aps-btn-red {
@include aps-btn-red;
}
.aps-btn-silver {
@include aps-btn-silver;
}
// ====== 绑定订单卡片 ======
.bound-order-cards {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.bound-order-card {
border: 1px solid $aps-border;
border-radius: $aps-radius;
background: $aps-white;
flex: 1;
min-width: 200px;
max-width: 300px;
}
.bound-order-card .bound-order-card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: $aps-silver-1;
border-bottom: 1px solid $aps-border;
font-size: 13px;
font-weight: 600;
color: $aps-text;
border-radius: $aps-radius $aps-radius 0 0;
}
.bound-order-card .bound-order-card-body {
padding: 10px 12px;
}
// ====== 绑定弹窗 ======
.bind-order-item {
display: flex;
align-items: center;
padding: 8px 10px;
border-bottom: 1px solid #ecf0f1;
cursor: pointer;
transition: background 0.15s;
}
.bind-order-item:hover {
background: #f5f5f5;
}
.bind-order-item.selected {
background: #fdecea;
}
.bind-order-item.previewing {
background: #fdecea;
border-left: 3px solid $aps-red-2;
}
.aps-bind-dialog ::v-deep .el-dialog__body {
padding: 16px 20px 0 20px;
}
</style>