Browse Source

feat(quality): 添加质量问详情页面及PO列表功能

- 创建了质量问题详情页面com_qualityIssueDetail.vue,展示问题详细信息
- 实现了质量问题PO列表管理页面com_qualityIssuePoList.vue,支持PO的选择和关联
- 添加了质量问题相关的API接口定义,包括PO列表查询和绑定功能
- 集成了PO列表到质量问题主列表页面,实现多标签页展示功能
master
qiankanghui 1 week ago
parent
commit
7353fde4cb
  1. 8
      src/api/quality/qualityIssue.js
  2. 4
      src/views/modules/quality/com_qualityIssueDetail.vue
  3. 424
      src/views/modules/quality/com_qualityIssuePoList.vue
  4. 59
      src/views/modules/quality/qualityIssueList.vue

8
src/api/quality/qualityIssue.js

@ -20,3 +20,11 @@ export const saveClaim = (data) => createAPI(`/srm/qualityIssue/saveClaim`, 'pos
// 关闭质量问题
export const closeQualityIssue = (data) => createAPI(`/srm/qualityIssue/close`, 'post', data)
export const getIssuePoList = data => createAPI('/srm/qualityIssue/getIssuePoList', 'post', data)
export const getAvailablePoList = data => createAPI('/srm/qualityIssue/getAvailablePoList', 'post', data)
export const saveIssuePo = data => createAPI('/srm/qualityIssue/bindIssuePo', 'post', data)
export const deleteIssuePo = data => createAPI('/srm/qualityIssue/deleteIssuePo', 'post', data)

4
src/views/modules/quality/com_qualityIssueDetail.vue

@ -53,10 +53,6 @@
<!-- 新增行PO No批次数量拒收批次数量投诉接收日期样品接收日期 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">PO No</span>
<span class="value">{{ detailData.poNo }}</span>
</div>
<div class="detail-item">
<span class="label">批次数量</span>

424
src/views/modules/quality/com_qualityIssuePoList.vue

@ -0,0 +1,424 @@
<template>
<div class="customer-css">
<!-- 操作按钮 -->
<el-form :inline="true" style="margin-bottom: 2px;">
<el-button type="primary" icon="el-icon-plus" size="mini" @click="showSelectPoDialog" :disabled="!supplierNo">选择PO</el-button>
</el-form>
<!-- 已关联PO列表表格 -->
<el-table
:data="issuePoList"
border
v-loading="loading"
style="width: 100%;"
:height="tableHeight">
<el-table-column
prop="poNo"
label="PO"
width="120"
align="center" />
<el-table-column
prop="poDate"
label="PO Date"
width="100"
align="center" />
<el-table-column
prop="sku"
label="SKU"
min-width="120"
show-overflow-tooltip />
<el-table-column
prop="poQty"
label="Qty"
width="80"
align="right" />
<el-table-column
prop="shippedQty"
label="Qty Shipped"
width="100"
align="right" />
<el-table-column
label="操作"
width="80"
align="center"
fixed="right">
<template slot-scope="scope">
<el-link type="danger" @click="handleDeletePo(scope.row)">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 选择PO对话框 -->
<el-dialog
title="选择PO"
:visible.sync="selectPoDialogVisible"
width="50%"
top="10vh"
:close-on-click-modal="false"
append-to-body>
<!-- 查询条件 -->
<el-form :inline="true" label-position="right" size="mini" class="search-form">
<el-form-item label="PO :">
<el-input v-model="poSearchData.poNo" placeholder="PO号" style="width: 120px" @keyup.enter.native="loadAvailablePoList"/>
</el-form-item>
<el-form-item label="Part No :">
<el-input v-model="poSearchData.partNo" placeholder="料号" style="width: 120px" @keyup.enter.native="loadAvailablePoList"/>
</el-form-item>
<el-form-item label="PO Date :">
<div class="date-range">
<el-date-picker
v-model="poSearchData.beginDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="开始日期"
style="width: 120px"
clearable>
</el-date-picker>
<span class="split">/</span>
<el-date-picker
v-model="poSearchData.endDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="结束日期"
style="width: 120px"
clearable>
</el-date-picker>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadAvailablePoList" size="small">查询</el-button>
</el-form-item>
</el-form>
<!-- 可用PO列表 -->
<el-table
ref="availablePoTable"
:data="availablePoList"
border
size="mini"
style="width: 100%; margin-top: 10px;"
height="300"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" />
<el-table-column prop="poNo" label="PO" width="120" />
<el-table-column prop="poDate" label="PO Date" width="160" />
<el-table-column prop="sku" label="SKU" />
<el-table-column prop="qty" label="Qty" width="100" align="right" />
<el-table-column prop="shippedQty" label="Qty Shipped" width="120" align="right" />
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" :loading="saveLoading" @click="handleSavePo">保存</el-button>
<el-button @click="selectPoDialogVisible = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getIssuePoList, getAvailablePoList, saveIssuePo, deleteIssuePo } from '@/api/quality/qualityIssue.js'
export default {
name: 'QualityIssuePoList',
props: {
issueNo: {
type: String,
default: ''
},
site: {
type: String,
default: ''
},
supplierNo: {
type: String,
default: ''
},
tableHeight: {
type: Number,
default: 400
}
},
data() {
return {
issuePoList: [],
loading: false,
saveLoading: false,
selectPoDialogVisible: false,
availablePoList: [],
selectedPoRows: [],
poSearchData: {
poNo: '',
partNo: '',
beginDate: '',
endDate: ''
}
}
},
watch: {
issueNo: {
immediate: true,
handler(newVal) {
if (newVal) {
this.loadIssuePoList()
} else {
this.issuePoList = []
}
}
}
},
mounted() {
//
if (this.issueNo) {
this.loadIssuePoList()
}
},
methods: {
//
loadData() {
this.loadIssuePoList()
},
// PO
loadIssuePoList() {
if (!this.issueNo) {
this.issuePoList = []
return
}
this.loading = true
getIssuePoList({
site: this.site,
issueNo: this.issueNo
}).then(({ data }) => {
if (data.code === 0) {
this.issuePoList = data.data || []
} else {
this.issuePoList = []
}
this.loading = false
}).catch(error => {
console.error('加载PO列表失败:', error)
this.loading = false
})
},
// PO
showSelectPoDialog() {
if (!this.supplierNo) {
this.$message.warning('请先选择有供应商的质量问题记录')
return
}
this.selectPoDialogVisible = true
//
this.poSearchData = {
poNo: '',
partNo: '',
beginDate: '',
endDate: ''
}
this.loadAvailablePoList()
},
// PO
loadAvailablePoList() {
const params = {
site: this.site,
supplierNo: this.supplierNo,
poNo: this.poSearchData.poNo || undefined,
partNo: this.poSearchData.partNo || undefined,
beginDate: this.poSearchData.beginDate || undefined,
endDate: this.poSearchData.endDate || undefined
}
getAvailablePoList(params).then(({ data }) => {
if (data.code === 0) {
this.availablePoList = (data.page && data.page.list) || []
this.$nextTick(() => {
if (this.$refs.availablePoTable) {
this.$refs.availablePoTable.clearSelection()
}
})
} else {
this.availablePoList = []
}
}).catch(error => {
console.error('加载可用PO列表失败:', error)
this.availablePoList = []
})
},
//
handleSelectionChange(selection) {
this.selectedPoRows = selection
},
// PO
handleSavePo() {
if (this.selectedPoRows.length === 0) {
this.$message.warning('请至少选择一条PO记录')
return
}
// site issueNo
if (!this.site || !this.issueNo) {
this.$message.error('缺少必要参数:site或issueNo为空')
console.error('保存失败:site=', this.site, 'issueNo=', this.issueNo)
return
}
const poList = this.selectedPoRows.map(row => ({
poNo: row.poNo,
itemNo: row.itemNo,
partNo: row.partNo,
sku: row.sku,
qty: row.qty,
shippedQty: row.shippedQty
}))
const params = {
site: this.site,
issueNo: this.issueNo,
poList: poList
}
console.log('保存PO数据:', params)
this.saveLoading = true
saveIssuePo(params).then(({ data }) => {
if (data.code === 0) {
this.$message.success('保存成功')
this.selectPoDialogVisible = false
this.loadIssuePoList()
} else {
this.$message.error(data.msg || '保存失败')
}
this.saveLoading = false
}).catch(error => {
console.error('保存PO失败:', error)
this.$message.error('保存失败,请稍后重试')
this.saveLoading = false
})
},
// PO
handleDeletePo(row) {
this.$confirm('确定要删除该PO吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const params = {
site: this.site,
issueNo: this.issueNo,
poNo: row.poNo,
itemNo: row.itemNo
}
deleteIssuePo(params).then(({ data }) => {
if (data.code === 0) {
this.$message.success('删除成功')
this.loadIssuePoList()
} else {
this.$message.error(data.msg || '删除失败')
}
}).catch(error => {
console.error('删除PO失败:', error)
this.$message.error('删除失败,请稍后重试')
})
}).catch(() => {})
}
}
}
</script>
<style scoped lang="scss">
.customer-css {
padding: 0;
margin: 0;
background: #fff;
height: 100%;
}
.search-form {
background: #f5f7fa;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
}
//
.search-form /deep/ .el-form-item {
margin-bottom: 0;
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.search-form /deep/ .el-form-item__label {
line-height: 32px;
height: 32px;
padding: 0 8px 0 0;
display: inline-flex;
align-items: center;
}
.search-form /deep/ .el-form-item__content {
line-height: 32px;
height: 32px;
display: inline-flex;
align-items: center;
}
.search-form /deep/ .el-input,
.search-form /deep/ .el-date-editor {
line-height: 32px;
}
.search-form /deep/ .el-button {
vertical-align: middle;
}
.date-range {
display: flex;
align-items: center;
}
.split {
padding: 0 6px;
color: #606266;
font-size: 13px;
}
.dialog-footer {
text-align: center;
}
// - 绿
/deep/ .el-table {
font-size: 12px;
}
/deep/ .el-table th {
background-color: #17B3A3;
color: #fff;
font-weight: 500;
}
/deep/ .el-table tr {
background-color: #fff;
}
/deep/ .el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: #f5f7fa;
}
/deep/ .el-link {
font-size: 12px;
}
</style>

59
src/views/modules/quality/qualityIssueList.vue

@ -130,11 +130,19 @@
</el-pagination>
<!-- 详情页签 -->
<el-tabs v-model="activeTab" style="margin-top: 0px; width: 99%;" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<el-tabs v-model="activeTab" :style="{marginTop: '10px', width: '100%'}" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<!-- 详情 -->
<el-tab-pane label="详情" name="detail">
<quality-issue-detail :detail-data="currentRow" />
</el-tab-pane>
<!--PO列表-->
<el-tab-pane label="PO列表" name="po">
<quality-issue-po-list
ref="qualityIssuePo"
:issue-no="currentRow.issueNo"
:site="currentRow.site"
:supplier-no="currentRow.supplierNo" />
</el-tab-pane>
<!-- 附件 -->
<el-tab-pane label="附件" name="attachment">
<quality-issue-attachment :detail-data="currentRow" :table-height="detailHeight" />
@ -191,11 +199,6 @@
<!-- 新增行PO No批次数量拒收批次数量投诉接收日期样品接收日期 -->
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="PO No">
<el-input v-model="addFormData.poNo" placeholder="请输入" size="mini"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="批次数量">
<el-input v-model="addFormData.batchQty" placeholder="请输入" size="mini" type="number"></el-input>
@ -218,9 +221,6 @@
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="样品接收日期">
<el-date-picker
@ -234,7 +234,6 @@
</el-form-item>
</el-col>
</el-row>
<!-- 第二行 -->
<el-row :gutter="10">
<el-col :span="6">
@ -703,13 +702,15 @@ import { queryQualityIssuePage, saveQualityIssue,deleteQualityIssue,updateQualit
import Chooselist from '@/views/modules/common/Chooselist_eam'
import ComQualityIssueDetail from './com_qualityIssueDetail.vue'
import ComQualityIssueAttachment from './com_qualityIssueAttachment.vue'
import ComQualityIssuePo from './com_qualityIssuePoList.vue'
import excel from '@/utils/excel-util.js'
export default {
components: {
Chooselist,
QualityIssueDetail: ComQualityIssueDetail,
QualityIssueAttachment: ComQualityIssueAttachment
QualityIssueAttachment: ComQualityIssueAttachment,
QualityIssuePoList: ComQualityIssuePo
},
data () {
return {
@ -1029,8 +1030,15 @@ export default {
},
mounted () {
this.$nextTick(() => {
this.height = (window.innerHeight - 220) / 2
this.detailHeight = (window.innerHeight - 220) / 2
//
const queryHeight = 220 //
const paginationHeight = 40 //
const availableHeight = window.innerHeight - queryHeight - paginationHeight - 40 // 40
//
this.height = availableHeight * 0.5
this.detailHeight = availableHeight * 0.5
this.getMainData()
})
},
@ -1117,6 +1125,12 @@ export default {
this.$refs.attachmentTab.loadAttachmentList()
}
})
}else if(tab.name === 'po') {
this.$nextTick(() => {
if (this.$refs.qualityIssuePo) {
this.$refs.qualityIssuePo.loadData()
}
})
}
},
@ -1726,8 +1740,25 @@ export default {
font-size: 13px;
}
/deep/ .customer-tab {
overflow: hidden;
margin-top: 10px !important;
height: calc(60vh - 100px);
display: flex;
flex-direction: column;
}
/deep/ .customer-tab .el-tabs__content {
padding: 5px !important;
padding: 0 !important;
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
/deep/ .customer-tab .el-tab-pane {
height: 100%;
overflow-y: auto;
}
.add-dialog-form /deep/ .el-form-item {

Loading…
Cancel
Save