修改采购ui

This commit is contained in:
2025-11-19 12:54:44 +08:00
parent ecea954d52
commit 7d0492a545
9 changed files with 1169 additions and 566 deletions

View File

@@ -91,7 +91,7 @@ public class ErpPurchaseOrderController extends BaseController {
@Log(title = "采购订单主", businessType = BusinessType.UPDATE)
@PutMapping("/{orderId}/confirm")
public R<Void> confirm(@NotNull(message = "主键不能为空")
@PathVariable Long orderId) {
@PathVariable("orderId") Long orderId) {
return toAjax(iErpPurchaseOrderService.confirmOrder(orderId, getUsername()));
}
@@ -101,7 +101,7 @@ public class ErpPurchaseOrderController extends BaseController {
@Log(title = "采购订单主", businessType = BusinessType.UPDATE)
@PutMapping("/{orderId}/partial")
public R<Void> partial(@NotNull(message = "主键不能为空")
@PathVariable Long orderId) {
@PathVariable("orderId") Long orderId) {
return toAjax(iErpPurchaseOrderService.markPartialArrival(orderId));
}
@@ -111,7 +111,7 @@ public class ErpPurchaseOrderController extends BaseController {
@Log(title = "采购订单主", businessType = BusinessType.UPDATE)
@PutMapping("/{orderId}/complete")
public R<Void> complete(@NotNull(message = "主键不能为空")
@PathVariable Long orderId) {
@PathVariable("orderId") Long orderId) {
return toAjax(iErpPurchaseOrderService.completeOrder(orderId));
}
@@ -121,7 +121,7 @@ public class ErpPurchaseOrderController extends BaseController {
@Log(title = "采购订单主", businessType = BusinessType.UPDATE)
@PutMapping("/{orderId}/cancel")
public R<Void> cancel(@NotNull(message = "主键不能为空")
@PathVariable Long orderId) {
@PathVariable("orderId") Long orderId) {
return toAjax(iErpPurchaseOrderService.cancelOrder(orderId));
}

View File

@@ -319,7 +319,7 @@ body {
background: $--table-bg;
// border: 1px solid $--border-color-light;
border-radius: 8px;
box-shadow: $--metal-shadow;
box-shadow: 0 6px 16px rgba(20, 30, 50, 0.08);
color: $--color-text-regular;
overflow: hidden;
margin-top: $--form-item-margin * 2; // 与表单间距
@@ -332,7 +332,7 @@ body {
// 表头(深灰黑 + 纯白文字)
.el-table__header-wrapper {
th.el-table__cell {
background: $--color-background;
background: lighten($--color-background, 6%);
color: $--color-text-primary;
font-weight: 600;
border-bottom: 1px solid $--border-color-lighter;
@@ -360,8 +360,12 @@ body {
// hover
&:hover .el-table__cell {
background: rgba($--color-primary, 0.25);
color: #888888;
background: rgba($--color-primary, 0.12);
color: #4a4a4a;
}
&:hover .el-table__cell {
background: rgba($--color-primary, 0.12);
color: #4a4a4a;
}
// 当前行
@@ -408,7 +412,7 @@ body {
}
&__empty-block {
background: $--color-background;
background: lighten($--color-background, 8%);
}
// 适配尺寸类(统一紧凑)
@@ -422,7 +426,7 @@ body {
// 表头(深灰黑 + 纯白文字)
.el-table__fixed-header-wrapper {
th.el-table__cell {
background: $--color-background;
background: lighten($--color-background, 6%);
color: $--color-text-primary;
font-weight: 600;
border-bottom: 1px solid $--border-color-lighter;

View File

@@ -1,17 +1,35 @@
<template>
<div class="erp-order-page">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>采购订单列表</span>
<div>
<el-button type="primary" size="mini" @click="openOrderDialog()">新增订单</el-button>
<el-button size="mini" @click="openItemDialog()">维护明细</el-button>
<div class="surface-actions">
<el-button type="primary" size="small" @click="openOrderDialog()">新增订单</el-button>
<el-button size="small" @click="openItemDialog()">维护明细</el-button>
</div>
</div>
<div class="toolbar">
<el-input v-model="orderQuery.orderCode" placeholder="订单编号" size="small" clearable class="toolbar-input" />
<el-input v-model="orderQuery.supplierId" placeholder="供应商ID" size="small" clearable class="toolbar-input" />
<el-select v-model="orderQuery.orderStatus" placeholder="状态" size="small" clearable class="toolbar-input">
</header>
<div class="inline-filter">
<el-input v-model="orderQuery.orderCode" placeholder="订单编号" size="small" clearable />
<el-select
v-model="orderQuery.supplierId"
filterable
remote
reserve-keyword
:remote-method="querySuppliers"
:loading="supplierLoading"
placeholder="供应商"
size="small"
clearable
@visible-change="handleSupplierDropdown"
>
<el-option
v-for="sp in supplierOptions"
:key="sp.supplierId"
:label="sp.name"
:value="sp.supplierId"
/>
</el-select>
<el-select v-model="orderQuery.orderStatus" placeholder="状态" size="small" clearable>
<el-option label="草稿" :value="0" />
<el-option label="执行中" :value="1" />
<el-option label="部分到货" :value="2" />
@@ -27,16 +45,18 @@
end-placeholder="下单结束"
size="small"
/>
<el-button size="small" type="primary" @click="loadOrders">查询</el-button>
<el-button size="small" @click="resetOrderQuery">重置</el-button>
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadOrders">查询</el-button>
<el-button size="small" @click="resetOrderQuery">重置</el-button>
</div>
</div>
<el-table :data="orderList" border stripe highlight-current-row size="small" v-loading="orderLoading">
<el-table-column prop="orderCode" label="订单编号" width="150" fixed="left" />
<el-table-column prop="supplierId" label="供应商ID" width="120" />
<el-table-column prop="orderDate" label="下单日期" width="120" />
<el-table-column prop="expectedArrival" label="期望到货" width="120" />
<el-table-column prop="orderType" label="类型" width="120" />
<el-table-column prop="totalAmount" label="金额" width="120" />
<el-table-column prop="supplierId" label="供应商ID" />
<el-table-column prop="orderDate" label="下单日期" />
<el-table-column prop="expectedArrival" label="期望到货" />
<el-table-column prop="orderType" label="类型" />
<el-table-column prop="totalAmount" label="金额" />
<el-table-column label="状态" width="120">
<template slot-scope="scope">
<el-tag :type="statusTag(scope.row.orderStatus)" size="mini">{{ statusText(scope.row.orderStatus) }}</el-tag>
@@ -61,44 +81,124 @@
:limit.sync="orderQuery.pageSize"
@pagination="loadOrders"
/>
</el-card>
</section>
<!-- 订单弹窗 -->
<el-dialog :title="orderDialog.title" :visible.sync="orderDialog.visible" width="600px">
<el-form :model="orderDialog.form" :rules="orderRules" ref="orderForm" label-width="100px" size="small">
<el-row :gutter="12">
<el-col :span="12">
<el-form-item label="订单编号" prop="orderCode">
<el-input v-model="orderDialog.form.orderCode" />
<el-dialog :title="orderDialog.title" :visible.sync="orderDialog.visible" width="960px" class="order-dialog" @close="closeOrderDialog">
<div class="contract-layout">
<section class="contract-card">
<div class="contract-card__title">基础信息</div>
<el-form :model="orderDialog.form" :rules="orderRules" ref="orderForm" label-width="100px" size="small" class="contract-form">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="订单编号" prop="orderCode">
<el-input v-model="orderDialog.form.orderCode" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="订单类型">
<el-input v-model="orderDialog.form.orderType" placeholder="如标准采购、年度合同" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商" prop="supplierId">
<el-select
v-model="orderDialog.form.supplierId"
filterable
remote
reserve-keyword
:remote-method="querySuppliers"
:loading="supplierLoading"
placeholder="请选择供应商"
@visible-change="handleSupplierDropdown"
@change="handleSupplierChange"
>
<el-option
v-for="sp in supplierOptions"
:key="sp.supplierId"
:label="sp.name"
:value="sp.supplierId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下单日期" prop="orderDate">
<el-date-picker v-model="orderDialog.form.orderDate" type="date" value-format="yyyy-MM-dd" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="期望到货">
<el-date-picker v-model="orderDialog.form.expectedArrival" type="date" value-format="yyyy-MM-dd" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="总金额">
<el-input-number v-model="orderDialog.form.totalAmount" :min="0" :precision="2" placeholder="可选" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注">
<el-input type="textarea" v-model="orderDialog.form.remark" placeholder="付款、质保、交付地点等合同条款" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商ID" prop="supplierId">
<el-input v-model="orderDialog.form.supplierId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下单日期" prop="orderDate">
<el-date-picker v-model="orderDialog.form.orderDate" type="date" value-format="yyyy-MM-dd" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="期望到货">
<el-date-picker v-model="orderDialog.form.expectedArrival" type="date" value-format="yyyy-MM-dd" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="订单类型">
<el-input v-model="orderDialog.form.orderType" />
</el-form-item>
<el-form-item label="金额">
<el-input-number v-model="orderDialog.form.totalAmount" :min="0" :precision="2" />
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="orderDialog.form.remark" />
</el-form-item>
</el-form>
<div slot="footer">
</el-form>
</section>
<section class="contract-card">
<div class="contract-card__title">
采购明细
<span class="subtitle" v-if="orderDialog.form.orderId">订单号{{ orderDialog.form.orderCode || orderDialog.form.orderId }}</span>
</div>
<div class="contract-card__toolbar">
<el-select
v-model="selectedSupplierGood"
placeholder="从供应商价目表快速添加"
filterable
clearable
:disabled="!orderDialog.form.orderId"
@focus="ensureSupplierGoods"
@change="handleSelectGoods"
>
<el-option
v-for="good in supplierGoods"
:key="good.materialTypeCode + '_' + (good.specification || '')"
:label="formatGoodLabel(good)"
:value="good.materialTypeCode"
/>
</el-select>
<el-button
type="primary"
size="mini"
icon="el-icon-plus"
:disabled="!orderDialog.form.orderId"
@click="openItemForm(null, { orderId: orderDialog.form.orderId })"
>
手动新增
</el-button>
<span class="toolbar-tip" v-if="!orderDialog.form.orderId">请先保存订单再维护物料明细</span>
</div>
<el-table
v-loading="dialogItemLoading"
:data="dialogItems"
size="small"
border
empty-text="暂未添加物料"
>
<el-table-column type="index" width="50" />
<el-table-column prop="materialTypeCode" label="物料类型" />
<el-table-column prop="specification" label="规格" />
<el-table-column prop="quantity" label="数量" width="120" />
<el-table-column prop="unitPrice" label="含税单价" width="120" />
<el-table-column label="操作" width="140">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openItemForm(scope.row)">编辑</el-button>
<el-button type="text" size="mini" class="danger" @click="handleDeleteItem(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</section>
</div>
<div slot="footer" class="contract-footer">
<el-button @click="orderDialog.visible = false"> </el-button>
<el-button type="primary" @click="submitOrder"> </el-button>
</div>
@@ -106,19 +206,20 @@
<!-- 明细弹窗 -->
<el-dialog :title="itemDialog.title" :visible.sync="itemDialog.visible" width="640px">
<div class="toolbar">
<el-input v-model="itemQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
<el-button size="small" type="primary" @click="loadItems">查询</el-button>
<el-button size="small" @click="resetItemQuery">重置</el-button>
<div class="toolbar-spacer"></div>
<el-button type="primary" size="small" @click="openItemForm()">新增明细</el-button>
<div class="inline-filter">
<el-input v-model="itemQuery.orderId" placeholder="订单ID" size="small" clearable />
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadItems">查询</el-button>
<el-button size="small" @click="resetItemQuery">重置</el-button>
<el-button type="primary" size="small" @click="openItemForm()">新增明细</el-button>
</div>
</div>
<el-table :data="itemList" border size="small" v-loading="itemLoading">
<el-table-column prop="orderId" label="订单ID" width="120" />
<el-table-column prop="materialTypeCode" label="物料类型" width="150" />
<el-table-column prop="specification" label="规格" min-width="150" />
<el-table-column prop="quantity" label="数量" width="100" />
<el-table-column prop="unitPrice" label="单价" width="100" />
<el-table-column prop="orderId" label="订单ID" />
<el-table-column prop="materialTypeCode" label="物料类型" />
<el-table-column prop="specification" label="规格" />
<el-table-column prop="quantity" label="数量" />
<el-table-column prop="unitPrice" label="单价" />
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openItemForm(scope.row)">编辑</el-button>
@@ -178,7 +279,9 @@ import {
listPurchaseOrderItem,
addPurchaseOrderItem,
updatePurchaseOrderItem,
delPurchaseOrderItem
delPurchaseOrderItem,
listSupplier,
listSupplierPrice
} from '@/api/erp/purchase'
export default {
@@ -193,7 +296,7 @@ export default {
orderDialog: { visible: false, title: '', form: {} },
orderRules: {
orderCode: [{ required: true, message: '请输入订单编号', trigger: 'blur' }],
supplierId: [{ required: true, message: '请输入供应商ID', trigger: 'blur' }]
supplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }]
},
itemDialog: { visible: false, title: '订单明细' },
itemQuery: { pageNum: 1, pageSize: 10, orderId: null },
@@ -205,11 +308,20 @@ export default {
orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
materialTypeCode: [{ required: true, message: '请输入物料类型', trigger: 'blur' }],
quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }]
}
},
supplierOptions: [],
supplierLoading: false,
dialogItems: [],
dialogItemLoading: false,
supplierGoods: [],
goodsLoading: false,
selectedSupplierGood: null
}
},
created() {
this.loadOrders()
// 默认加载一批供应商作为下拉初始选项
this.querySuppliers('')
},
methods: {
loadOrders() {
@@ -228,6 +340,25 @@ export default {
this.orderLoading = false
})
},
async querySuppliers(keyword) {
this.supplierLoading = true
try {
const params = {
pageNum: 1,
pageSize: 10,
name: keyword || undefined
}
const res = await listSupplier(params)
this.supplierOptions = res.rows || []
} finally {
this.supplierLoading = false
}
},
handleSupplierDropdown(visible) {
if (visible && !this.supplierOptions.length && !this.supplierLoading) {
this.querySuppliers('')
}
},
resetOrderQuery() {
this.orderQuery = { pageNum: 1, pageSize: 10, orderCode: null, supplierId: null, orderStatus: null }
this.orderRange = []
@@ -237,13 +368,25 @@ export default {
if (row) {
this.orderDialog.form = { ...row }
this.orderDialog.title = '编辑采购订单'
this.loadDialogItems(row.orderId)
if (row.supplierId) {
this.handleSupplierChange(row.supplierId)
}
} else {
this.orderDialog.form = { orderCode: '', supplierId: '', orderDate: '', orderStatus: 0 }
this.orderDialog.title = '新增采购订单'
this.dialogItems = []
this.supplierGoods = []
this.selectedSupplierGood = null
}
this.orderDialog.visible = true
this.$nextTick(() => this.$refs.orderForm && this.$refs.orderForm.clearValidate())
},
closeOrderDialog() {
this.dialogItems = []
this.supplierGoods = []
this.selectedSupplierGood = null
},
submitOrder() {
this.$refs.orderForm.validate(valid => {
if (!valid) return
@@ -251,6 +394,7 @@ export default {
api(this.orderDialog.form).then(() => {
this.$message.success('保存成功')
this.orderDialog.visible = false
this.closeOrderDialog()
this.loadOrders()
})
})
@@ -326,12 +470,24 @@ export default {
this.itemQuery = { pageNum: 1, pageSize: 10, orderId: null }
this.loadItems()
},
openItemForm(row) {
openItemForm(row, preset = {}) {
if (row) {
this.itemFormDialog.form = { ...row }
this.itemFormDialog.title = '编辑明细'
} else {
this.itemFormDialog.form = { orderId: '', materialTypeCode: '', quantity: 0 }
const targetOrderId = preset.orderId || this.orderDialog.form.orderId || ''
if (!targetOrderId) {
this.$message.warning('请先保存订单,再新增物料')
return
}
this.itemFormDialog.form = {
orderId: targetOrderId,
materialTypeCode: preset.materialTypeCode || '',
specification: preset.specification || '',
quantity: preset.quantity || 0,
unitPrice: preset.unitPrice || 0,
remark: preset.remark || ''
}
this.itemFormDialog.title = '新增明细'
}
this.itemFormDialog.visible = true
@@ -345,6 +501,9 @@ export default {
this.$message.success('保存成功')
this.itemFormDialog.visible = false
this.loadItems()
if (this.orderDialog.form.orderId) {
this.loadDialogItems(this.orderDialog.form.orderId)
}
})
})
},
@@ -354,7 +513,71 @@ export default {
}).then(() => {
this.$message.success('删除成功')
this.loadItems()
if (this.orderDialog.form.orderId) {
this.loadDialogItems(this.orderDialog.form.orderId)
}
})
},
async loadDialogItems(orderId) {
if (!orderId) {
this.dialogItems = []
return
}
this.dialogItemLoading = true
try {
const res = await listPurchaseOrderItem({ pageNum: 1, pageSize: 100, orderId })
this.dialogItems = res.rows || []
} finally {
this.dialogItemLoading = false
}
},
handleSupplierChange(val) {
if (!val) {
this.supplierGoods = []
this.selectedSupplierGood = null
return
}
this.selectedSupplierGood = null
this.loadSupplierGoods(val)
},
ensureSupplierGoods() {
if (!this.orderDialog.form.supplierId || this.supplierGoods.length || this.goodsLoading) return
this.loadSupplierGoods(this.orderDialog.form.supplierId)
},
async loadSupplierGoods(supplierId) {
if (!supplierId) return
this.goodsLoading = true
try {
const res = await listSupplierPrice({ pageNum: 1, pageSize: 50, supplierId })
this.supplierGoods = res.rows || []
} finally {
this.goodsLoading = false
}
},
handleSelectGoods(code) {
if (!code) return
if (!this.orderDialog.form.orderId) {
this.$message.warning('请先保存订单,再添加物料')
this.selectedSupplierGood = null
return
}
const good = this.supplierGoods.find(item => item.materialTypeCode === code)
if (!good) return
this.openItemForm(null, {
orderId: this.orderDialog.form.orderId,
materialTypeCode: good.materialTypeCode,
specification: good.specification,
unitPrice: good.price || 0
})
this.$nextTick(() => {
this.selectedSupplierGood = null
})
},
formatGoodLabel(good) {
if (!good) return ''
const spec = good.specification ? ` / ${good.specification}` : ''
const price = good.price != null ? ` · ¥${good.price}` : ''
return `${good.materialTypeCode}${spec}${price}`
}
}
}
@@ -363,32 +586,84 @@ export default {
<style lang="scss" scoped>
.erp-order-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
}
.panel-card {
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
}
.toolbar {
display: flex;
align-items: center;
color: #1e2c39;
margin-bottom: 12px;
}
.surface-actions {
display: flex;
gap: 8px;
}
.inline-filter {
display: flex;
flex-wrap: wrap;
.toolbar-input {
width: 150px;
margin-right: 8px;
margin-bottom: 6px;
gap: 8px;
margin-bottom: 12px;
> *:not(.filter-actions) {
flex: 1 1 150px;
}
.filter-actions {
display: flex;
gap: 8px;
}
}
.toolbar-spacer {
flex: 1;
.danger {
color: #c0392b;
}
.order-dialog ::v-deep .el-dialog {
max-width: 960px;
}
.contract-layout {
display: flex;
flex-direction: column;
gap: 16px;
}
.contract-card {
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
background: #fff;
}
.contract-card__title {
font-weight: 600;
font-size: 15px;
color: #1f2d3d;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
.subtitle {
font-size: 12px;
color: #9099a8;
}
}
.contract-card__toolbar {
display: flex;
gap: 12px;
align-items: center;
margin-bottom: 12px;
.toolbar-tip {
font-size: 12px;
color: #c97a1a;
}
.el-select {
max-width: 320px;
}
}
.contract-footer {
text-align: right;
}
</style>

View File

@@ -1,52 +1,46 @@
<template>
<div class="erp-purchase-page">
<el-row :gutter="16" class="summary-row">
<el-col :span="6">
<div class="summary-card">
<section class="surface-panel metrics-panel">
<div class="metrics-grid">
<div class="metric">
<p class="label">采购总金额</p>
<p class="value">{{ summary.totalAmount | formatAmount }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="summary-card">
<div class="metric">
<p class="label">计划采购量</p>
<p class="value">{{ summary.suggestionTotal }} </p>
</div>
</el-col>
<el-col :span="6">
<div class="summary-card">
<div class="metric">
<p class="label">待处理订单</p>
<p class="value">{{ summary.pendingOrder }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="summary-card">
<div class="metric">
<p class="label">供应商数量</p>
<p class="value">{{ summary.supplierBrief.length }}</p>
</div>
</el-col>
</el-row>
<el-card class="panel-card" shadow="never">
<div slot="header" class="panel-header">
<span>采购需求分析</span>
<div class="panel-actions">
<el-switch v-model="persistResult" active-text="写入建议表" inactive-text="仅计算" />
<el-button type="primary" size="mini" @click="handleAnalyze" :loading="analysisLoading">执行分析</el-button>
</div>
</div>
</section>
<section class="surface-panel">
<header class="surface-header">
<span>采购需求分析</span>
<div class="surface-actions">
<el-switch v-model="persistResult" active-text="写入建议表" inactive-text="仅计算" />
<el-button type="primary" size="small" @click="handleAnalyze" :loading="analysisLoading">执行分析</el-button>
</div>
</header>
<el-table :data="mappingRows" border size="small" class="mapping-table">
<el-table-column label="产品ID" width="160">
<el-table-column label="产品ID">
<template slot-scope="scope">
<el-input v-model="scope.row.productId" placeholder="产品ID" />
</template>
</el-table-column>
<el-table-column label="原料ID" width="160">
<el-table-column label="原料ID">
<template slot-scope="scope">
<el-input v-model="scope.row.rawMaterialId" placeholder="原料ID" />
</template>
</el-table-column>
<el-table-column label="转换率" width="140">
<el-table-column label="转换率">
<template slot-scope="scope">
<el-input-number v-model="scope.row.conversionRate" :min="0" :max="1" :step="0.01" />
</template>
@@ -69,54 +63,55 @@
show-summary
:summary-method="analysisSummary"
>
<el-table-column label="产品" prop="productName" min-width="180">
<el-table-column label="产品" prop="productName">
<template slot-scope="scope">
<div class="cell-title">{{ scope.row.productName || '-' }}</div>
<div class="cell-sub">ID: {{ scope.row.productId || '-' }}</div>
</template>
</el-table-column>
<el-table-column label="规格" prop="specification" min-width="140" />
<el-table-column label="销售需求(吨)" prop="salesDemand" min-width="120" />
<el-table-column label="成品库存/卷" min-width="140">
<el-table-column label="规格" prop="specification" />
<el-table-column label="销售需求(吨)" prop="salesDemand" />
<el-table-column label="成品库存/卷">
<template slot-scope="scope">
<div>{{ scope.row.productStockWeight }}</div>
<div class="cell-sub">{{ scope.row.productStockCoilCount }} </div>
</template>
</el-table-column>
<el-table-column label="原料折算(吨)" prop="rawStockConverted" min-width="120" />
<el-table-column label="在途折算(吨)" prop="inTransitConverted" min-width="120" />
<el-table-column label="待下达折算(吨)" prop="pendingConverted" min-width="120" />
<el-table-column label="建议采购(吨)" prop="suggestedPurchase" min-width="120" />
<el-table-column label="原料折算(吨)" prop="rawStockConverted" />
<el-table-column label="在途折算(吨)" prop="inTransitConverted" />
<el-table-column label="待下达折算(吨)" prop="pendingConverted" />
<el-table-column label="建议采购(吨)" prop="suggestedPurchase" />
</el-table>
</el-card>
</section>
<el-card class="panel-card" shadow="never">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>执行控制</span>
</div>
<el-tabs v-model="activeTab" type="border-card">
</header>
<el-tabs v-model="activeTab" class="plain-tabs">
<el-tab-pane label="收货记录" name="receipt">
<div class="toolbar">
<el-input v-model="receiptQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
<el-input v-model="receiptQuery.itemId" placeholder="明细ID" size="small" clearable class="toolbar-input" />
<el-button size="small" type="primary" @click="loadReceipts">查询</el-button>
<el-button size="small" @click="resetReceiptQuery">重置</el-button>
<div class="toolbar-spacer"></div>
<el-button type="primary" size="small" @click="openReceiptDialog()">新增收货</el-button>
<div class="inline-filter">
<el-input v-model="receiptQuery.orderId" placeholder="订单ID" size="small" clearable />
<el-input v-model="receiptQuery.itemId" placeholder="明细ID" size="small" clearable />
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadReceipts">查询</el-button>
<el-button size="small" @click="resetReceiptQuery">重置</el-button>
<el-button type="primary" size="small" @click="openReceiptDialog()">新增收货</el-button>
</div>
</div>
<el-table :data="receiptList" v-loading="receiptLoading" border size="small">
<el-table-column prop="receiptId" label="ID" width="80" />
<el-table-column prop="orderId" label="订单ID" width="100" />
<el-table-column prop="itemId" label="明细ID" width="100" />
<el-table-column prop="receivedQty" label="收货数量" width="100" />
<el-table-column prop="qualityResult" label="质检结果" width="120">
<el-table-column prop="orderId" label="订单ID" />
<el-table-column prop="itemId" label="明细ID" />
<el-table-column prop="receivedQty" label="收货数量" />
<el-table-column prop="qualityResult" label="质检结果">
<template slot-scope="scope">
<el-tag :type="scope.row.qualityResult === 'NG' ? 'danger' : 'success'" size="mini">
{{ scope.row.qualityResult || '合格' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="receiptTime" label="收货时间" width="160" />
<el-table-column prop="receiptTime" label="收货时间" />
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openReceiptDialog(scope.row)">编辑</el-button>
@@ -134,24 +129,25 @@
</el-tab-pane>
<el-tab-pane label="退货管理" name="return">
<div class="toolbar">
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable class="toolbar-input">
<div class="inline-filter">
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable />
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable>
<el-option label="草稿" :value="0" />
<el-option label="完成" :value="1" />
</el-select>
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
<el-button size="small" @click="resetReturnQuery">重置</el-button>
<div class="toolbar-spacer"></div>
<el-button type="primary" size="small" @click="openReturnDialog()">新增退货</el-button>
<el-button size="small" @click="openReturnItemDialog()">退货明细</el-button>
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
<el-button size="small" @click="resetReturnQuery">重置</el-button>
<el-button type="primary" size="small" @click="openReturnDialog()">新增退货</el-button>
<el-button size="small" @click="openReturnItemDialog()">退货明细</el-button>
</div>
</div>
<el-table :data="returnList" v-loading="returnLoading" border size="small">
<el-table-column prop="returnId" label="退货单ID" width="120" />
<el-table-column prop="orderId" label="订单ID" width="120" />
<el-table-column prop="returnType" label="类型" width="120" />
<el-table-column prop="reason" label="原因" min-width="150" />
<el-table-column prop="status" label="状态" width="120">
<el-table-column prop="orderId" label="订单ID" />
<el-table-column prop="returnType" label="类型" />
<el-table-column prop="reason" label="原因" />
<el-table-column prop="status" label="状态" width="140">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="mini">
{{ scope.row.status === 1 ? '完成' : '草稿' }}
@@ -174,12 +170,12 @@
/>
</el-tab-pane>
</el-tabs>
</el-card>
</section>
<el-card class="panel-card" shadow="never">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>采购报表</span>
<div class="panel-actions">
<div class="surface-actions">
<el-date-picker
v-model="reportRange"
type="monthrange"
@@ -192,45 +188,39 @@
size="small"
/>
</div>
</header>
<div class="report-grid">
<div class="report-card">
<h4>供应商采购额TOP</h4>
<el-table :data="summary.supplierBrief" size="mini" height="220" border>
<el-table-column prop="supplierId" label="供应商ID" />
<el-table-column prop="totalAmount" label="金额" />
<el-table-column prop="orderCount" label="订单" width="90" />
</el-table>
</div>
<div class="report-card">
<h4>价格趋势</h4>
<el-table :data="priceTrend" size="mini" height="220" border>
<el-table-column prop="period" label="月份" />
<el-table-column prop="materialCode" label="物料编码" />
<el-table-column prop="avgPrice" label="平均含税单价" />
</el-table>
</div>
<div class="report-card">
<h4>供应商退货率</h4>
<el-table :data="supplierQuality" size="mini" height="220" border>
<el-table-column prop="supplierId" label="供应商ID" />
<el-table-column prop="receivedQty" label="收货量" />
<el-table-column prop="returnQty" label="退货量" />
<el-table-column label="退货率">
<template slot-scope="scope">
{{ formatPercent(scope.row.returnRate) }}
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-row :gutter="16">
<el-col :span="8">
<div class="report-block">
<h4>供应商采购额TOP</h4>
<el-table :data="summary.supplierBrief" size="mini" height="220" border>
<el-table-column prop="supplierId" label="供应商ID" width="120" />
<el-table-column prop="totalAmount" label="金额" />
<el-table-column prop="orderCount" label="订单" width="80" />
</el-table>
</div>
</el-col>
<el-col :span="8">
<div class="report-block">
<h4>价格趋势</h4>
<el-table :data="priceTrend" size="mini" height="220" border>
<el-table-column prop="period" label="月份" width="120" />
<el-table-column prop="materialCode" label="物料编码" width="150" />
<el-table-column prop="avgPrice" label="平均含税单价" />
</el-table>
</div>
</el-col>
<el-col :span="8">
<div class="report-block">
<h4>供应商退货率</h4>
<el-table :data="supplierQuality" size="mini" height="220" border>
<el-table-column prop="supplierId" label="供应商ID" width="120" />
<el-table-column prop="receivedQty" label="收货量" />
<el-table-column prop="returnQty" label="退货量" />
<el-table-column label="退货率">
<template slot-scope="scope">
{{ formatPercent(scope.row.returnRate) }}
</template>
</el-table-column>
</el-table>
</div>
</el-col>
</el-row>
</el-card>
</section>
<!-- 收货弹窗 -->
<el-dialog :title="receiptDialog.title" :visible.sync="receiptDialog.visible" width="480px">
@@ -649,48 +639,54 @@ export default {
<style lang="scss" scoped>
.erp-purchase-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
.summary-row {
margin-bottom: 16px;
}
}
.summary-card {
background: #fdfdfd;
border: 1px solid #d9dee4;
padding: 16px;
height: 90px;
display: flex;
flex-direction: column;
justify-content: center;
.label {
color: #5c6b77;
font-size: 14px;
margin-bottom: 6px;
}
.value {
color: #1f2d3d;
font-size: 20px;
font-weight: 600;
}
gap: 16px;
}
.panel-card {
margin-bottom: 18px;
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
color: #1c2b36;
margin-bottom: 12px;
}
.panel-actions {
.surface-actions {
display: flex;
align-items: center;
gap: 12px;
}
.metrics-panel {
padding: 0;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
padding: 16px;
}
.metric {
border: 1px solid #d6dce1;
padding: 12px;
background: #f9fafb;
.label {
font-size: 13px;
color: #6b7785;
margin-bottom: 4px;
}
.value {
font-size: 20px;
font-weight: 600;
color: #16212b;
}
}
.mapping-table {
margin-bottom: 8px;
}
@@ -708,27 +704,41 @@ export default {
color: #7c8792;
font-size: 12px;
}
.toolbar {
.inline-filter {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
> *:not(.filter-actions) {
flex: 1 1 160px;
}
.filter-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
}
.report-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 12px;
}
.report-card {
border: 1px solid #d6dce1;
padding: 12px;
background: #fdfdfd;
h4 {
margin: 0 0 8px;
font-size: 14px;
color: #2a313c;
}
}
.plain-tabs ::v-deep .el-tabs__header {
border-bottom: 1px solid #d6dce1;
margin-bottom: 12px;
}
.toolbar-input {
width: 160px;
margin-right: 8px;
}
.toolbar-spacer {
flex: 1;
}
.report-block {
border: 1px solid #d9dee4;
padding: 12px;
background: #fafbfc;
h4 {
font-weight: 600;
margin: 0 0 8px;
color: #2f3c4c;
}
.plain-tabs ::v-deep .el-tabs__content {
padding: 0;
}
</style>

View File

@@ -1,38 +1,40 @@
<template>
<div class="erp-receipt-page">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>收货记录</span>
<el-button type="primary" size="mini" @click="openDialog()">新增收货</el-button>
</div>
<div class="toolbar">
<el-input v-model="query.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
<el-input v-model="query.itemId" placeholder="订单明细ID" size="small" clearable class="toolbar-input" />
<el-select v-model="query.quality" placeholder="质检结果" size="small" clearable class="toolbar-input">
<el-button type="primary" size="small" @click="openDialog()">新增收货</el-button>
</header>
<div class="inline-filter">
<el-input v-model="query.orderId" placeholder="订单ID" size="small" clearable />
<el-input v-model="query.itemId" placeholder="订单明细ID" size="small" clearable />
<el-select v-model="query.quality" placeholder="质检结果" size="small" clearable>
<el-option label="合格" value="OK" />
<el-option label="不合格" value="NG" />
</el-select>
<el-button size="small" type="primary" @click="loadData">查询</el-button>
<el-button size="small" @click="resetQuery">重置</el-button>
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadData">查询</el-button>
<el-button size="small" @click="resetQuery">重置</el-button>
</div>
</div>
<el-table :data="list" border size="small" v-loading="loading">
<el-table-column prop="receiptId" label="ID" width="80" />
<el-table-column prop="orderId" label="订单ID" width="120" />
<el-table-column prop="itemId" label="明细ID" width="120" />
<el-table-column prop="receivedQty" label="收货数量" width="120" />
<el-table-column prop="qualityResult" label="质检结果" width="120">
<el-table-column prop="orderId" label="订单ID" />
<el-table-column prop="itemId" label="明细ID" />
<el-table-column prop="receivedQty" label="收货数量" />
<el-table-column prop="qualityResult" label="质检结果">
<template slot-scope="scope">
<el-tag :type="scope.row.qualityResult === 'NG' ? 'danger' : 'success'" size="mini">
{{ scope.row.qualityResult || 'OK' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="receiptTime" label="收货时间" width="160" />
<el-table-column label="备注" min-width="160" prop="remark" />
<el-table-column prop="receiptTime" label="收货时间" />
<el-table-column label="备注" prop="remark" />
<el-table-column label="操作" width="140">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDelete(scope.row)">删除</el-button>
<el-button type="text" size="mini" class="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -43,19 +45,19 @@
:limit.sync="query.pageSize"
@pagination="loadData"
/>
</el-card>
</section>
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>到货趋势</span>
</div>
</header>
<el-table :data="chartData" border size="small" height="300">
<el-table-column prop="date" label="日期" width="140" />
<el-table-column prop="date" label="日期" />
<el-table-column prop="totalQty" label="累计收货(吨)" />
<el-table-column prop="qualifiedQty" label="合格数量(吨)" />
<el-table-column prop="ngQty" label="不合格(吨)" />
</el-table>
</el-card>
</section>
<el-dialog :title="dialog.title" :visible.sync="dialog.visible" width="480px">
<el-form :model="dialog.form" :rules="rules" ref="form" label-width="100px" size="small">
@@ -187,28 +189,40 @@ export default {
<style lang="scss" scoped>
.erp-receipt-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
display: flex;
flex-direction: column;
gap: 16px;
}
.panel-card {
margin-bottom: 18px;
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
}
.toolbar {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.toolbar-input {
width: 140px;
margin-right: 8px;
.inline-filter {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
> *:not(.filter-actions) {
flex: 1 1 150px;
}
.filter-actions {
display: flex;
gap: 8px;
}
}
.danger {
color: #c0392b;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="erp-report-page">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>采购汇总</span>
<el-date-picker
v-model="range"
@@ -13,67 +13,49 @@
end-placeholder="结束时间"
@change="loadSummary"
/>
</header>
<div class="metrics-grid">
<div class="metric-card">
<p class="label">采购总金额</p>
<p class="value">{{ summary.totalAmount | formatMoney }}</p>
</div>
<div class="metric-card">
<p class="label">供应商数量</p>
<p class="value">{{ supplierBrief.length }}</p>
</div>
<div class="metric-card">
<p class="label">最大供应商金额</p>
<p class="value">{{ topSupplierAmount | formatMoney }}</p>
</div>
<div class="metric-card">
<p class="label">平均订单金额</p>
<p class="value">{{ avgSupplierAmount | formatMoney }}</p>
</div>
</div>
<el-row :gutter="16">
<el-col :span="6">
<div class="metric-card">
<p class="label">采购总金额</p>
<p class="value">{{ summary.totalAmount | formatMoney }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">供应商数量</p>
<p class="value">{{ supplierBrief.length }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">最大供应商金额</p>
<p class="value">{{ topSupplierAmount | formatMoney }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">平均订单金额</p>
<p class="value">{{ avgSupplierAmount | formatMoney }}</p>
</div>
</el-col>
</el-row>
</el-card>
</section>
<el-row :gutter="16">
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商汇总</span>
</div>
<section class="surface-panel">
<div class="report-grid">
<div class="report-card">
<h4>供应商汇总</h4>
<el-table :data="supplierBrief" border size="small" height="320">
<el-table-column prop="supplierId" label="供应商ID" width="140" />
<el-table-column prop="orderCount" label="订单数" width="100" />
<el-table-column prop="supplierId" label="供应商ID" />
<el-table-column prop="orderCount" label="订单数" />
<el-table-column prop="totalAmount" label="总金额" />
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>价格趋势</span>
</div>
</div>
<div class="report-card">
<h4>价格趋势</h4>
<el-table :data="priceTrend" border size="small" height="320">
<el-table-column prop="period" label="月份" width="120" />
<el-table-column prop="materialCode" label="物料编码" width="140" />
<el-table-column prop="period" label="月份" />
<el-table-column prop="materialCode" label="物料编码" />
<el-table-column prop="avgPrice" label="平均含税价" />
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商退货率</span>
</div>
</div>
<div class="report-card">
<h4>供应商退货率</h4>
<el-table :data="supplierQuality" border size="small" height="320">
<el-table-column prop="supplierId" label="供应商ID" width="140" />
<el-table-column prop="supplierId" label="供应商ID" />
<el-table-column prop="receivedQty" label="收货量" />
<el-table-column prop="returnQty" label="退货量" />
<el-table-column label="退货率">
@@ -82,9 +64,9 @@
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</div>
</section>
</div>
</template>
@@ -154,24 +136,35 @@ export default {
<style lang="scss" scoped>
.erp-report-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
display: flex;
flex-direction: column;
gap: 16px;
}
.panel-card {
margin-bottom: 18px;
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
margin-bottom: 12px;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 12px;
}
.metric-card {
border: 1px solid #d9dee4;
padding: 16px;
background: #fff;
background: #f9fafb;
border-radius: 4px;
.label {
color: #5b6875;
margin-bottom: 6px;
@@ -182,5 +175,22 @@ export default {
color: #1f2d3d;
}
}
.report-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 12px;
}
.report-card {
border: 1px solid #d9dee4;
border-radius: 4px;
padding: 12px;
background: #fbfbfc;
h4 {
margin: 0 0 8px;
font-size: 14px;
font-weight: 600;
color: #2b3440;
}
}
</style>

View File

@@ -1,25 +1,25 @@
<template>
<div class="erp-requirement-page">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>采购需求分析</span>
<div class="panel-actions">
<div class="surface-actions">
<el-switch v-model="persistResult" active-text="写入建议表" inactive-text="仅计算" />
<el-button type="primary" size="mini" @click="handleAnalyze" :loading="loading">执行分析</el-button>
<el-button type="primary" size="small" @click="handleAnalyze" :loading="loading">执行分析</el-button>
</div>
</div>
</header>
<el-table :data="mappingRows" border size="small" class="mapping-table">
<el-table-column label="产品ID" width="180">
<el-table-column label="产品ID">
<template slot-scope="scope">
<el-input v-model="scope.row.productId" placeholder="产品ID" />
</template>
</el-table-column>
<el-table-column label="原料ID" width="180">
<el-table-column label="原料ID">
<template slot-scope="scope">
<el-input v-model="scope.row.rawMaterialId" placeholder="原料ID" />
</template>
</el-table-column>
<el-table-column label="转换率" width="160">
<el-table-column label="转换率">
<template slot-scope="scope">
<el-input-number v-model="scope.row.conversionRate" :min="0" :max="1" :step="0.01" />
</template>
@@ -40,19 +40,19 @@
show-summary
:summary-method="summaryMethod"
>
<el-table-column label="产品" width="220">
<el-table-column label="产品">
<template slot-scope="scope">
<div class="title">{{ scope.row.productName || '-' }}</div>
<div class="cell-sub">ID: {{ scope.row.productId || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="specification" label="规格" width="160" />
<el-table-column prop="salesDemand" label="销售需求(吨)" width="140" />
<el-table-column prop="productStockWeight" label="成品库存(吨)" width="140" />
<el-table-column prop="rawStockConverted" label="原料折算(吨)" width="140" />
<el-table-column prop="inTransitConverted" label="在途折算(吨)" width="140" />
<el-table-column prop="pendingConverted" label="待下达折算(吨)" width="140" />
<el-table-column prop="suggestedPurchase" label="建议采购(吨)" width="160">
<el-table-column prop="specification" label="规格" />
<el-table-column prop="salesDemand" label="销售需求(吨)" />
<el-table-column prop="productStockWeight" label="成品库存(吨)" />
<el-table-column prop="rawStockConverted" label="原料折算(吨)" />
<el-table-column prop="inTransitConverted" label="在途折算(吨)" />
<el-table-column prop="pendingConverted" label="待下达折算(吨)" />
<el-table-column prop="suggestedPurchase" label="建议采购(吨)">
<template slot-scope="scope">
<span :class="scope.row.suggestedPurchase > 0 ? 'highlight' : ''">
{{ scope.row.suggestedPurchase }}
@@ -60,23 +60,23 @@
</template>
</el-table-column>
</el-table>
</el-card>
</section>
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<section class="surface-panel">
<header class="surface-header">
<span>原料折算详情</span>
</div>
</header>
<el-table :data="rawDetailData" size="small" border height="320">
<el-table-column prop="productName" label="产品" width="200" />
<el-table-column prop="rawMaterialName" label="原料" width="200" />
<el-table-column prop="conversionRate" label="转换率" width="120" />
<el-table-column prop="stockWeight" label="库存重量" width="120" />
<el-table-column prop="stockCoilCount" label="库存卷数" width="120" />
<el-table-column prop="convertedStock" label="折算库存" width="120" />
<el-table-column prop="convertedInTransit" label="折算在途" width="120" />
<el-table-column prop="convertedPending" label="折算待下达" width="120" />
<el-table-column prop="productName" label="产品" />
<el-table-column prop="rawMaterialName" label="原料" />
<el-table-column prop="conversionRate" label="转换率" />
<el-table-column prop="stockWeight" label="库存重量" />
<el-table-column prop="stockCoilCount" label="库存卷数" />
<el-table-column prop="convertedStock" label="折算库存" />
<el-table-column prop="convertedInTransit" label="折算在途" />
<el-table-column prop="convertedPending" label="折算待下达" />
</el-table>
</el-card>
</section>
</div>
</template>
@@ -161,21 +161,26 @@ export default {
<style lang="scss" scoped>
.erp-requirement-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
display: flex;
flex-direction: column;
gap: 16px;
}
.panel-card {
margin-bottom: 18px;
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
margin-bottom: 12px;
}
.panel-actions {
.surface-actions {
display: flex;
align-items: center;
gap: 12px;

View File

@@ -1,79 +1,87 @@
<template>
<div class="erp-return-page">
<el-row :gutter="16">
<el-col :span="13">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>退货单</span>
<el-button type="primary" size="mini" @click="openReturnDialog()">新增退货单</el-button>
<section class="surface-panel">
<header class="surface-header">
<span>退货单</span>
<el-button type="primary" size="small" @click="openReturnDialog()">新增退货单</el-button>
</header>
<div class="inline-filter">
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable />
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable>
<el-option label="草稿" :value="0" />
<el-option label="完成" :value="1" />
</el-select>
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
<el-button size="small" @click="resetReturnQuery">重置</el-button>
</div>
</div>
<div class="return-card-grid" v-loading="returnLoading">
<div
v-for="item in returnList"
:key="item.returnId"
class="return-card"
:class="{ active: selectedReturnId === item.returnId }"
@click="selectReturn(item)"
>
<div class="card-header">
<div>
<p class="title">退货单 {{ item.returnId }}</p>
<p class="sub">订单 {{ item.orderId }}</p>
</div>
<el-tag :type="item.status === 1 ? 'success' : 'info'" size="mini">
{{ item.status === 1 ? '完成' : '草稿' }}
</el-tag>
</div>
<div class="toolbar">
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable class="toolbar-input">
<el-option label="草稿" :value="0" />
<el-option label="完成" :value="1" />
</el-select>
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
<el-button size="small" @click="resetReturnQuery">重置</el-button>
<div class="card-body">
<p><span>类型</span>{{ item.returnType || '-' }}</p>
<p><span>原因</span>{{ item.reason || '-' }}</p>
<p><span>退货日期</span>{{ item.returnDate || '-' }}</p>
</div>
<el-table :data="returnList" border size="small" v-loading="returnLoading" height="420">
<el-table-column prop="returnId" label="退货单ID" width="120" />
<el-table-column prop="orderId" label="订单ID" width="120" />
<el-table-column prop="returnType" label="类型" width="120" />
<el-table-column prop="reason" label="原因" min-width="160" />
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="mini">
{{ scope.row.status === 1 ? '完成' : '草稿' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openReturnDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" @click="openReturnItems(scope.row)">明细</el-button>
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDeleteReturn(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<div class="card-actions">
<el-button type="text" size="mini" @click.stop="openReturnDialog(item)">编辑</el-button>
<el-button type="text" size="mini" @click.stop="openReturnItems(item)">明细</el-button>
<el-button type="text" size="mini" class="danger" @click.stop="handleDeleteReturn(item)">删除</el-button>
</div>
</div>
<el-empty v-if="!returnList.length && !returnLoading" description="暂无退货单" />
</div>
</section>
<el-col :span="11">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>退货明细</span>
<el-button type="primary" size="mini" @click="openReturnItemDialog()">新增明细</el-button>
</div>
<div class="toolbar">
<el-input v-model="returnItemQuery.returnId" placeholder="退货单ID" size="small" clearable class="toolbar-input" />
<el-input v-model="returnItemQuery.itemId" placeholder="订单明细ID" size="small" clearable class="toolbar-input" />
<el-button size="small" type="primary" @click="loadReturnItems">查询</el-button>
<el-button size="small" @click="resetReturnItemQuery">重置</el-button>
</div>
<el-table :data="returnItemList" border size="small" height="420" v-loading="returnItemLoading">
<el-table-column prop="returnItemId" label="ID" width="80" />
<el-table-column prop="returnId" label="退货单ID" width="120" />
<el-table-column prop="itemId" label="订单明细ID" width="150" />
<el-table-column prop="returnQty" label="数量" width="100" />
<el-table-column label="问题照片" min-width="140">
<template slot-scope="scope">
<el-tooltip v-if="scope.row.photos" :content="scope.row.photos" placement="top">
<span class="link">查看</span>
</el-tooltip>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="140">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openReturnItemDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDeleteReturnItem(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<section class="surface-panel">
<header class="surface-header">
<span>退货明细</span>
<el-button type="primary" size="small" @click="openReturnItemDialog()">新增明细</el-button>
</header>
<div class="inline-filter">
<el-input v-model="returnItemQuery.returnId" placeholder="退货单ID" size="small" clearable />
<el-input v-model="returnItemQuery.itemId" placeholder="订单明细ID" size="small" clearable />
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadReturnItems">查询</el-button>
<el-button size="small" @click="resetReturnItemQuery">重置</el-button>
</div>
</div>
<el-table :data="returnItemList" border size="small" v-loading="returnItemLoading">
<el-table-column prop="returnItemId" label="ID" width="80" />
<el-table-column prop="returnId" label="退货单ID" />
<el-table-column prop="itemId" label="订单明细ID" />
<el-table-column prop="returnQty" label="数量" />
<el-table-column label="问题照片">
<template slot-scope="scope">
<el-tooltip v-if="scope.row.photos" :content="scope.row.photos" placement="top">
<span class="link">查看</span>
</el-tooltip>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openReturnItemDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" class="danger" @click="handleDeleteReturnItem(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</section>
<el-dialog :title="returnDialog.title" :visible.sync="returnDialog.visible" width="520px">
<el-form :model="returnDialog.form" :rules="returnRules" ref="returnForm" label-width="100px" size="small">
@@ -152,6 +160,7 @@ export default {
returnQuery: { pageNum: 1, pageSize: 10, orderId: null, status: null },
returnList: [],
returnLoading: false,
selectedReturnId: null,
returnDialog: { visible: false, title: '', form: {} },
returnRules: { orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }] },
returnItemQuery: { pageNum: 1, pageSize: 10, returnId: null, itemId: null },
@@ -206,7 +215,12 @@ export default {
})
})
},
selectReturn(row) {
this.selectedReturnId = row.returnId
this.openReturnItems(row)
},
openReturnItems(row) {
this.selectedReturnId = row.returnId
this.returnItemQuery.returnId = row.returnId
this.loadReturnItems()
},
@@ -265,27 +279,93 @@ export default {
<style lang="scss" scoped>
.erp-return-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
display: flex;
flex-direction: column;
gap: 16px;
}
.panel-card {
border: 1px solid #d0d5d8;
margin-bottom: 16px;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
}
.panel-header {
.surface-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
}
.toolbar {
display: flex;
align-items: center;
color: #1e2c39;
margin-bottom: 12px;
}
.toolbar-input {
width: 140px;
margin-right: 8px;
.inline-filter {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
> *:not(.filter-actions) {
flex: 1 1 160px;
}
.filter-actions {
display: flex;
gap: 8px;
}
}
.return-card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 12px;
}
.return-card {
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 12px;
background: #fbfbfc;
display: flex;
flex-direction: column;
gap: 8px;
cursor: pointer;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
&.active {
border-color: #409eff;
transform: scale(1.02);
box-shadow: 0 6px 20px rgba(16, 38, 70, 0.08);
}
}
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
.title {
margin: 0;
font-weight: 600;
color: #15202b;
}
.sub {
margin: 2px 0 0;
color: #7a8699;
font-size: 12px;
}
}
.card-body {
p {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #4a5663;
margin: 0;
span {
color: #98a1ac;
}
}
}
.card-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
.danger {
color: #c0392b;
}
}
.link {
color: #2f86d7;

View File

@@ -1,82 +1,99 @@
<template>
<div class="erp-supplier-page">
<el-row :gutter="16">
<el-col :span="10">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商档案</span>
<el-button type="primary" size="mini" @click="openSupplierDialog()">新增</el-button>
<section class="surface-panel supplier-panel">
<header class="surface-header">
<span>供应商档案</span>
<el-button type="primary" size="small" @click="openSupplierDialog()">新增</el-button>
</header>
<div class="inline-filter">
<el-input v-model="supplierQuery.name" placeholder="供应商名称" size="small" clearable />
<el-select v-model="supplierQuery.creditRating" placeholder="信用等级" size="small" clearable>
<el-option label="A" value="A" />
<el-option label="B" value="B" />
<el-option label="C" value="C" />
<el-option label="D" value="D" />
</el-select>
<div class="filter-actions">
<el-button size="small" type="primary" @click="loadSuppliers">查询</el-button>
<el-button size="small" @click="resetSupplierQuery">重置</el-button>
</div>
</div>
<div class="supplier-grid" v-loading="supplierLoading">
<div
v-for="item in supplierList"
:key="item.supplierId"
class="supplier-card"
>
<div class="card-head">
<div>
<p class="title">{{ item.name }}</p>
<p class="sub">编码{{ item.supplierCode || '-' }}</p>
</div>
<div class="tag-group">
<el-tag size="mini" type="info">{{ supplierTypeLabel(item.type) }}</el-tag>
<el-tag size="mini" type="plain">信用 {{ item.creditRating || '-' }}</el-tag>
</div>
</div>
<div class="toolbar">
<el-input v-model="supplierQuery.name" placeholder="供应商名称" size="small" clearable class="toolbar-input" />
<el-select v-model="supplierQuery.creditRating" placeholder="信用等级" size="small" clearable class="toolbar-input">
<el-option label="A" value="A" />
<el-option label="B" value="B" />
<el-option label="C" value="C" />
<el-option label="D" value="D" />
</el-select>
<el-button size="small" type="primary" @click="loadSuppliers">查询</el-button>
<el-button size="small" @click="resetSupplierQuery">重置</el-button>
<ul class="card-body">
<li><span>联系人</span><strong>{{ item.contactPerson || '-' }}</strong></li>
<li><span>电话</span><strong>{{ item.contactPhone || '-' }}</strong></li>
<li><span>地址</span><strong>{{ item.address || '-' }}</strong></li>
<li><span>备注</span><strong>{{ item.remark || '-' }}</strong></li>
</ul>
<div class="card-actions">
<el-button type="text" size="mini" @click="openSupplierDialog(item)">编辑</el-button>
<el-button type="text" size="mini" @click="openPriceDrawer(item)">价格</el-button>
<el-button type="text" size="mini" class="danger" @click="handleDeleteSupplier(item)">删除</el-button>
</div>
<el-table :data="supplierList" height="420" size="small" border v-loading="supplierLoading">
<el-table-column prop="supplierCode" label="编码" width="120" />
<el-table-column prop="name" label="名称" min-width="160" />
<el-table-column prop="creditRating" label="信用" width="80" />
<el-table-column label="联系人" width="140">
<template slot-scope="scope">
<div>{{ scope.row.contactPerson || '-' }}</div>
<div class="cell-sub">{{ scope.row.contactPhone || '' }}</div>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openSupplierDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" @click="handleDeleteSupplier(scope.row)" style="color:#c0392b">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="14">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商价格表</span>
<el-button type="primary" size="mini" @click="openPriceDialog()">新增价格</el-button>
</div>
<el-empty v-if="!supplierList.length && !supplierLoading" description="暂无数据" />
</div>
</section>
<el-drawer
title="供应商价格表"
:visible.sync="priceDrawer.visible"
size="480px"
direction="rtl"
append-to-body
custom-class="price-drawer"
@close="closePriceDrawer"
>
<div class="price-drawer-body">
<div class="drawer-header" v-if="priceDrawer.supplier">
<div class="drawer-title-block">
<p class="drawer-title">{{ priceDrawer.supplier.name }}</p>
<p class="drawer-sub">编码{{ priceDrawer.supplier.supplierCode || '-' }}</p>
</div>
<div class="toolbar">
<el-input v-model="priceQuery.materialTypeCode" placeholder="物料编码" size="small" clearable class="toolbar-input" />
<el-select v-model="priceQuery.supplierId" placeholder="供应商" size="small" clearable class="toolbar-input">
<el-option v-for="sp in supplierOptions" :key="sp.supplierId" :label="sp.name" :value="sp.supplierId" />
</el-select>
<el-date-picker v-model="priceRange" type="daterange" value-format="yyyy-MM-dd" size="small" range-separator="至"
start-placeholder="生效日期" end-placeholder="失效日期" />
<el-button size="small" type="primary" @click="loadPrices">查询</el-button>
</div>
<el-table :data="priceList" size="small" border v-loading="priceLoading">
<el-table-column prop="supplierId" label="供应商" width="150">
<template slot-scope="scope">
{{ matchSupplier(scope.row.supplierId) }}
</template>
</el-table-column>
<el-table-column prop="materialTypeCode" label="物料类型" width="160" />
<el-table-column prop="specification" label="规格" min-width="140" />
<el-table-column prop="price" label="价格(含税)" width="110" />
<el-table-column label="有效期" width="200">
<template slot-scope="scope">
<div>{{ scope.row.validFrom || '-' }}</div>
<div class="cell-sub">{{ scope.row.validTo || '-' }}</div>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openPriceDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" @click="handleDeletePrice(scope.row)" style="color:#c0392b">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<el-button type="primary" size="mini" @click="openPriceDialog()">新增价格</el-button>
</div>
<div class="drawer-section">
<div class="drawer-section-title">价格列表</div>
<el-collapse v-model="activePricePanels" accordion>
<el-collapse-item
v-for="item in priceList"
:name="item.priceId"
:title="`${item.materialTypeCode || '未指定'} · ¥${item.price || 0}`"
:key="item.priceId"
>
<ul class="price-info">
<li><span>规格</span>{{ item.specification || '-' }}</li>
<li><span>含税价</span>{{ item.price || '-' }}</li>
<li><span>有效期</span>{{ formatRange(item.validFrom, item.validTo) }}</li>
<li><span>备注</span>{{ item.remark || '-' }}</li>
</ul>
<div class="price-actions">
<el-button type="text" size="mini" @click="openPriceDialog(item)">编辑</el-button>
<el-button type="text" size="mini" class="danger" @click="handleDeletePrice(item)">删除</el-button>
</div>
</el-collapse-item>
</el-collapse>
<el-empty v-if="!priceList.length && !priceLoading" description="暂无价格记录" />
<el-skeleton v-if="priceLoading" animated rows="4" />
</div>
</div>
</el-drawer>
<!-- 供应商弹窗 -->
<el-dialog :title="supplierDialog.title" :visible.sync="supplierDialog.visible" width="520px">
@@ -87,8 +104,10 @@
<el-form-item label="名称" prop="name">
<el-input v-model="supplierDialog.form.name" />
</el-form-item>
<el-form-item label="类型">
<el-input v-model="supplierDialog.form.type" />
<el-form-item label="类型" prop="type">
<el-select v-model="supplierDialog.form.type" placeholder="请选择类型">
<el-option v-for="opt in supplierTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="信用等级">
<el-select v-model="supplierDialog.form.creditRating" clearable>
@@ -125,11 +144,14 @@
<el-option v-for="sp in supplierOptions" :key="sp.supplierId" :label="sp.name" :value="sp.supplierId" />
</el-select>
</el-form-item>
<el-form-item label="物料类型" prop="materialTypeCode">
<el-input v-model="priceDialog.form.materialTypeCode" />
<el-form-item label="原料" prop="rawMaterialId">
<RawMaterialSelect v-model="priceDialog.form.rawMaterialId" @change="handleMaterialChange" />
</el-form-item>
<el-form-item label="物料编码">
<el-input v-model="priceDialog.form.materialTypeCode" placeholder="选择原料后自动带出" readonly />
</el-form-item>
<el-form-item label="规格">
<el-input v-model="priceDialog.form.specification" />
<el-input v-model="priceDialog.form.specification" placeholder="选择原料后可调整" />
</el-form-item>
<el-form-item label="含税价格" prop="price">
<el-input-number v-model="priceDialog.form.price" :min="0" :precision="2" />
@@ -166,31 +188,39 @@ import {
updateSupplierPrice,
delSupplierPrice
} from '@/api/erp/purchase'
import RawMaterialSelect from '@/components/KLPService/RawMaterialSelect'
export default {
name: 'ErpSupplierManage',
components: { RawMaterialSelect },
data() {
return {
supplierTypeOptions: [
{ label: '原料供应商', value: 'RAW' },
{ label: '其他供应商', value: 'OTHER' }
],
supplierQuery: { pageNum: 1, pageSize: 50, name: null, creditRating: null },
supplierList: [],
supplierLoading: false,
supplierDialog: { visible: false, title: '', form: {} },
supplierRules: {
supplierCode: [{ required: true, message: '请输入编码', trigger: 'blur' }],
name: [{ required: true, message: '请输入名称', trigger: 'blur' }]
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
type: [{ required: true, message: '请选择类型', trigger: 'change' }]
},
priceQuery: { pageNum: 1, pageSize: 50, supplierId: null, materialTypeCode: null },
priceQuery: { pageNum: 1, pageSize: 50, supplierId: null },
priceList: [],
priceLoading: false,
priceDialog: { visible: false, title: '', form: {} },
priceRules: {
supplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }],
materialTypeCode: [{ required: true, message: '请输入物料类型', trigger: 'blur' }],
rawMaterialId: [{ required: true, message: '请选择原料', trigger: 'change' }],
price: [{ required: true, message: '请输入价格', trigger: 'change' }]
},
priceRange: [],
priceValidRange: [],
supplierOptions: []
supplierOptions: [],
priceDrawer: { visible: false, supplier: null },
activePricePanels: []
}
},
created() {
@@ -218,7 +248,7 @@ export default {
this.supplierDialog.form = { ...row }
this.supplierDialog.title = '编辑供应商'
} else {
this.supplierDialog.form = { supplierCode: '', name: '', creditRating: 'A' }
this.supplierDialog.form = { supplierCode: '', name: '', creditRating: 'A', type: 'RAW' }
this.supplierDialog.title = '新增供应商'
}
this.supplierDialog.visible = true
@@ -243,17 +273,31 @@ export default {
this.loadSuppliers()
})
},
supplierTypeLabel(val) {
const target = this.supplierTypeOptions.find(opt => opt.value === val)
return target ? target.label : '其他供应商'
},
// price
openPriceDrawer(item) {
this.priceDrawer = { visible: true, supplier: item }
this.priceQuery = { ...this.priceQuery, supplierId: item.supplierId, pageNum: 1 }
this.loadPrices()
},
closePriceDrawer() {
this.priceDrawer.visible = false
this.priceDrawer.supplier = null
this.priceList = []
},
loadPrices() {
const query = { ...this.priceQuery }
if (this.priceRange && this.priceRange.length === 2) {
query.beginTime = this.priceRange[0]
query.endTime = this.priceRange[1]
if (!this.priceQuery.supplierId) {
this.priceList = []
return
}
this.priceLoading = true
listSupplierPrice(query)
listSupplierPrice(this.priceQuery)
.then(res => {
this.priceList = res.rows || []
this.activePricePanels = (this.priceList[0] && [this.priceList[0].priceId]) || []
})
.finally(() => {
this.priceLoading = false
@@ -273,7 +317,8 @@ export default {
this.priceValidRange = [row.validFrom, row.validTo]
this.priceDialog.title = '编辑价格'
} else {
this.priceDialog.form = { supplierId: null, materialTypeCode: '', price: 0 }
const currentSupplierId = this.priceDrawer.supplier?.supplierId || null
this.priceDialog.form = { supplierId: currentSupplierId, rawMaterialId: '', materialTypeCode: '', specification: '', price: 0 }
this.priceValidRange = []
this.priceDialog.title = '新增价格'
}
@@ -287,6 +332,10 @@ export default {
this.priceDialog.form.validFrom = this.priceValidRange[0]
this.priceDialog.form.validTo = this.priceValidRange[1]
}
if (!this.priceDialog.form.materialTypeCode) {
this.$message.warning('请先选择原料')
return
}
const api = this.priceDialog.form.priceId ? updateSupplierPrice : addSupplierPrice
api(this.priceDialog.form).then(() => {
this.$message.success('保存成功')
@@ -302,6 +351,18 @@ export default {
this.$message.success('删除成功')
this.loadPrices()
})
},
handleMaterialChange(val, rows) {
const target = Array.isArray(rows) ? rows[0] : null
this.priceDialog.form.rawMaterialId = val
if (target) {
this.priceDialog.form.materialTypeCode = target.rawMaterialCode
this.priceDialog.form.specification = target.specification
}
},
formatRange(start, end) {
if (!start && !end) return '-'
return `${start || '-'} ~ ${end || '-'}`
}
}
}
@@ -309,32 +370,176 @@ export default {
<style lang="scss" scoped>
.erp-supplier-page {
background: #eef1f3;
padding: 16px;
min-height: 100%;
}
.panel-card {
border: 1px solid #d0d5d8;
.surface-panel {
background: #fff;
border: 1px solid #d6dce1;
border-radius: 4px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.panel-header {
.surface-header {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 600;
color: #1b2a38;
}
.inline-filter {
display: flex;
flex-wrap: wrap;
gap: 8px;
.filter-actions {
display: flex;
gap: 8px;
}
> *:not(.filter-actions) {
flex: 1 1 150px;
}
}
.supplier-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 12px;
}
.supplier-card {
border: 1px solid #d6dce1;
padding: 12px;
border-radius: 4px;
background: #fff;
display: flex;
flex-direction: column;
gap: 10px;
}
.card-head {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
align-items: flex-start;
.title {
font-weight: 600;
margin: 0;
color: #15212d;
}
.sub {
margin: 2px 0 0;
color: #79828c;
font-size: 12px;
}
.tag-group {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
}
.toolbar {
.card-body {
list-style: none;
padding: 0;
margin: 0;
li {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #4a5663;
& + li {
margin-top: 4px;
}
span {
color: #8a96a3;
}
strong {
color: #151e26;
}
}
}
.card-actions {
display: flex;
align-items: center;
margin-bottom: 12px;
justify-content: flex-end;
gap: 8px;
.danger {
color: #c0392b;
}
}
.toolbar-input {
width: 150px;
margin-right: 8px;
}
.cell-sub {
font-size: 12px;
color: #7c8792;
.price-drawer {
.price-drawer-body {
padding: 16px 20px 12px;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.drawer-header {
margin-bottom: 12px;
padding: 8px 10px;
border-radius: 4px;
background-color: #f5f7fa;
border: 1px solid #e4e7ed;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.drawer-title-block {
display: flex;
flex-direction: column;
}
.drawer-title {
margin: 0;
font-weight: 600;
color: #1f2a37;
}
.drawer-sub {
margin-top: 4px;
color: #7a8694;
font-size: 12px;
}
.drawer-section {
margin-top: 14px;
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.drawer-section-title {
font-size: 13px;
color: #5c6c7b;
margin-bottom: 8px;
}
::v-deep .el-collapse-item__header {
padding-left: 10px;
}
::v-deep .el-collapse-item__content {
padding: 10px 10px 12px;
}
.price-info {
list-style: none;
padding: 0;
margin: 0 0 4px;
li {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #4a5663;
& + li {
margin-top: 4px;
}
span {
color: #8a96a3;
}
}
}
.price-actions {
margin-top: 8px;
display: flex;
justify-content: flex-end;
gap: 8px;
.danger {
color: #c0392b;
}
}
}
</style>