Browse Source

feat(npcIqc): 添加NPC IQC列表页面和详情组件

- 创建com_npcIqcDetail组件用于展示IQC检验详情
- 实现npcIqcList页面包含查询表单和数据表格
- 集成详情标签页功能可查看选中记录详情
- 添加Excel导入导出功能支持数据批量操作
- 实现分页查询和搜索过滤功能
- 完善日期格式化和状态转换显示逻辑
master
qiankanghui 1 week ago
parent
commit
9386ed7cc1
  1. 296
      src/views/modules/npcIqc/com_npcIqcDetail.vue
  2. 371
      src/views/modules/npcIqc/npcIqcList.vue
  3. 34
      src/views/modules/quality/com_qualityIssueDetail.vue

296
src/views/modules/npcIqc/com_npcIqcDetail.vue

@ -0,0 +1,296 @@
<template>
<div class="detail-container">
<div v-if="Object.keys(detailData).length === 0" class="empty-tip">
请选择一条记录查看详情
</div>
<div v-else>
<!-- 第一行 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Inspection Type</span>
<span class="value">{{ detailData.inspectionType }}</span>
</div>
<div class="detail-item">
<span class="label">Date Received</span>
<span class="value">{{ formatDate(detailData.dateReceived) }}</span>
</div>
<div class="detail-item">
<span class="label">PO No</span>
<span class="value">{{ detailData.purOrder }}</span>
</div>
<div class="detail-item">
<span class="label">IQC No</span>
<span class="value">{{ detailData.iqcNo }}</span>
</div>
</div>
<!-- 第二行 -->
<div class="detail-row">
<div class="detail-item long">
<span class="label">供应商名称</span>
<span class="value">{{ detailData.supplierName }}</span>
</div>
<div class="detail-item">
<span class="label">供应商编码</span>
<span class="value">{{ detailData.supplierNo }}</span>
</div>
</div>
<!-- 第三行 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Quantity</span>
<span class="value">{{ detailData.quantity }}</span>
</div>
<div class="detail-item">
<span class="label">Sample Size</span>
<span class="value">{{ detailData.sampleSize }}</span>
</div>
<div class="detail-item">
<span class="label">Item Code</span>
<span class="value">{{ detailData.itemCode }}</span>
</div>
<div class="detail-item">
<span class="label">Item Name</span>
<span class="value">{{ detailData.itemName }}</span>
</div>
</div>
<!-- 第四行 - 尺寸信息 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Dim A</span>
<span class="value">{{ detailData.dimA }}</span>
</div>
<div class="detail-item">
<span class="label">Dim B</span>
<span class="value">{{ detailData.dimB }}</span>
</div>
<div class="detail-item">
<span class="label">Dim C</span>
<span class="value">{{ detailData.dimC }}</span>
</div>
<div class="detail-item">
<span class="label">Dim D</span>
<span class="value">{{ detailData.dimD }}</span>
</div>
<div class="detail-item">
<span class="label">Dim E</span>
<span class="value">{{ detailData.dimE }}</span>
</div>
</div>
<!-- 第五行 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Inspection Total</span>
<span class="value">{{ detailData.inspectionTotal }}</span>
</div>
<div class="detail-item">
<span class="label">Status</span>
<span class="value">{{ getStatusText(detailData.inspectionStatus) }}</span>
</div>
<div class="detail-item">
<span class="label">Inspector</span>
<span class="value">{{ detailData.inspectorName }}</span>
</div>
<div class="detail-item">
<span class="label">Entry Date</span>
<span class="value">{{ formatDate(detailData.entryDate) }}</span>
</div>
</div>
<!-- 第六行 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Supplier Email</span>
<span class="value">{{ detailData.supplierEmail }}</span>
</div>
<div class="detail-item">
<span class="label">CA Request</span>
<span class="value">{{ detailData.caRequest ? '是' : '否' }}</span>
</div>
<div class="detail-item">
<span class="label">Collection Batch</span>
<span class="value">{{ detailData.collectionBatch }}</span>
</div>
</div>
<!-- 第七行 - 问题描述 -->
<div class="detail-row full-width">
<span class="label">Problem</span>
<div class="value textarea">{{ detailData.problem }}</div>
</div>
<!-- 第八行 - 备注 -->
<div class="detail-row full-width">
<span class="label">Comments</span>
<div class="value textarea">{{ detailData.comments }}</div>
</div>
<!-- 第九行 - 返工信息 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Rework Hours</span>
<span class="value">{{ detailData.reworkHours }}</span>
</div>
<div class="detail-item">
<span class="label">Rework Rate</span>
<span class="value">{{ detailData.reworkRate }}</span>
</div>
<div class="detail-item">
<span class="label">Rework Total</span>
<span class="value">{{ detailData.reworkTotal }}</span>
</div>
<div class="detail-item">
<span class="label">Material Cost</span>
<span class="value">{{ detailData.materialCost }}</span>
</div>
</div>
<!-- 第十行 - 其他信息 -->
<div class="detail-row">
<div class="detail-item">
<span class="label">Created By</span>
<span class="value">{{ detailData.createdBy }}</span>
</div>
<div class="detail-item">
<span class="label">Update By</span>
<span class="value">{{ detailData.updateBy }}</span>
</div>
<div class="detail-item">
<span class="label">Update Date</span>
<span class="value">{{ formatDate(detailData.updateDate) }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'NpcIqcDetail',
props: {
detailData: {
type: Object,
default: () => ({})
}
},
methods: {
formatDate (dateStr) {
if (!dateStr) return ''
if (typeof dateStr === 'string' && dateStr.length > 10) {
return dateStr.substring(0, 10)
}
return dateStr
},
getStatusText (status) {
const statusMap = {
'Confirmed': '已确认',
'Analyzed': '已分析',
'Closed': '已关闭',
'Cancelled': '已取消'
}
return statusMap[status] || status
}
}
}
</script>
<style scoped lang="scss">
.detail-container {
padding: 15px;
border: 1px solid #e4e7ed;
background: #fff;
min-height: 300px;
max-height: 100%;
overflow-y: auto;
}
.empty-tip {
text-align: center;
color: #909399;
font-size: 14px;
padding: 80px 0;
}
.detail-row {
display: flex;
align-items: center;
margin-bottom: 12px;
flex-wrap: wrap;
}
.detail-row.full-width {
flex-direction: column;
align-items: flex-start;
.label {
margin-bottom: 5px;
}
}
.detail-item {
display: flex;
align-items: center;
min-width: 280px;
margin-right: 20px;
margin-bottom: 5px;
}
.detail-item.long {
min-width: 400px;
flex: 1;
}
.label {
color: #606266;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.value {
flex: 1;
min-height: 26px;
line-height: 26px;
padding: 0 8px;
border: 1px solid #dcdfe6;
background: #fff;
color: #303133;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.value.textarea {
width: 100%;
min-height: 50px;
line-height: 1.5;
padding: 8px;
white-space: pre-wrap;
word-break: break-all;
}
</style>

371
src/views/modules/npcIqc/npcIqcList.vue

@ -0,0 +1,371 @@
<template>
<div class="customer-css npc-iqc-container">
<!-- 查询条件 -->
<el-form :inline="true" label-position="top" class="search-form-inline">
<div class="search-row">
<el-form-item label="供应商编码" class="search-item">
<el-input v-model="searchData.supplierNo" style="width: 120px" @keyup.enter.native="getMainData"/>
</el-form-item>
<el-form-item label="供应商名称" class="search-item">
<el-input v-model="searchData.supplierName" style="width: 180px" @keyup.enter.native="getMainData"/>
</el-form-item>
<el-form-item label="问题日期" class="search-item">
<div class="date-range">
<el-date-picker
v-model="searchData.issueDateStart"
type="date"
value-format="yyyy-MM-dd"
placeholder="开始日期"
style="width: 140px"
clearable>
</el-date-picker>
<span class="split">~</span>
<el-date-picker
v-model="searchData.issueDateEnd"
type="date"
value-format="yyyy-MM-dd"
placeholder="结束日期"
style="width: 140px"
clearable>
</el-date-picker>
</div>
</el-form-item>
<el-form-item label="状态" class="search-item">
<el-select v-model="searchData.inspectionStatus" clearable placeholder="全部" style="width: 120px">
<el-option label="全部" value="" />
<el-option label="已确认" value="Confirmed" />
<el-option label="已分析" value="Analyzed" />
<el-option label="已关闭" value="Closed" />
<el-option label="已取消" value="Cancelled" />
</el-select>
</el-form-item>
</div>
<div class="search-row">
<el-form-item label="反馈单号" class="search-item">
<el-input v-model="searchData.issueNo" style="width: 120px" @keyup.enter.native="getMainData"/>
</el-form-item>
<el-form-item label="PO" class="search-item">
<el-input v-model="searchData.purOrder" style="width: 120px" @keyup.enter.native="getMainData"/>
</el-form-item>
<el-form-item label="Part No" class="search-item">
<el-input v-model="searchData.itemCode" style="width: 120px" @keyup.enter.native="getMainData"/>
</el-form-item>
<el-form-item label=" " class="search-item search-btn-item">
<el-button type="primary" @click="getMainData">查询</el-button>
<el-button type="primary" @click="excelImport" style="margin-left: 2px">Excel导入</el-button>
<el-button type="primary" @click="exportExcel" style="margin-left: 2px">导出</el-button>
</el-form-item>
</div>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="mainDataList"
border
ref="mainTable"
highlight-current-row
@row-click="changeData"
v-loading="dataListLoading"
style="width: 100%;"
size="mini">
<el-table-column prop="iqcNo" label="Insp STAND" width="80" align="center" header-align="center" />
<el-table-column prop="purOrder" label="PUR C6" width="80" align="center" header-align="center" />
<el-table-column prop="supplierName" label="Supplier" min-width="150" align="left" header-align="center" show-overflow-tooltip />
<el-table-column prop="dateReceived" label="Date R" width="90" align="center" header-align="center" />
<el-table-column prop="itemCode" label="Item" width="100" align="left" header-align="center" />
<el-table-column prop="quantity" label="Quan" width="60" align="right" header-align="center" />
<el-table-column prop="sampleSize" label="Samp" width="60" align="right" header-align="center" />
<el-table-column prop="dimA" label="Di A" width="60" align="right" header-align="center" />
<el-table-column prop="dimB" label="Di B" width="60" align="right" header-align="center" />
<el-table-column prop="dimC" label="Di C" width="60" align="right" header-align="center" />
<el-table-column prop="dimD" label="Di D" width="60" align="right" header-align="center" />
<el-table-column prop="dimE" label="Di E" width="60" align="right" header-align="center" />
<el-table-column prop="inspectionTotal" label="Total Re" width="80" align="right" header-align="center" />
<el-table-column prop="problem" label="PROBLEM" min-width="150" align="left" header-align="center" show-overflow-tooltip />
<el-table-column prop="comments" label="Comment" min-width="120" align="left" header-align="center" show-overflow-tooltip />
<el-table-column prop="inspectorName" label="INSPEC" width="90" align="left" header-align="center" />
<el-table-column prop="supplierEmail" label="SUPPLIER E" width="120" align="left" header-align="center" show-overflow-tooltip />
<el-table-column prop="caRequest" label="CA R" width="60" align="center" header-align="center" />
<el-table-column prop="reworkHours" label="Rework" width="70" align="right" header-align="center" />
<el-table-column prop="reworkRate" label="Rewo" width="70" align="right" header-align="center" />
<el-table-column prop="reworkTotal" label="Rewo" width="70" align="right" header-align="center" />
<el-table-column prop="materialCost" label="Mater" width="70" align="right" header-align="center" />
<el-table-column prop="collectionBatch" label="Collec" width="80" align="left" header-align="center" />
<el-table-column prop="entryDate" label="Entry" width="90" align="center" header-align="center" />
</el-table>
<!-- 分页插件 -->
<el-pagination style="margin-top: 10px"
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[20, 50, 100, 200, 500]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
<!-- 详情页签 -->
<el-tabs v-model="activeTab" :style="{marginTop: '10px', width: '100%', height: detailHeight + 'px'}" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<el-tab-pane label="详情" name="detail">
<div style="height: 100%; overflow: auto;">
<npc-iqc-detail :detail-data="currentRow" />
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { searchNpcIqc } from '@/api/npcIqc/npcIqc.js'
import ComNpcIqcDetail from './com_npcIqcDetail.vue'
import excel from '@/utils/excel-util.js'
export default {
components: {
NpcIqcDetail: ComNpcIqcDetail
},
data () {
return {
functionId: this.$route.meta.menuId,
tableHeight: 400,
detailHeight: 400,
currentRow: {},
activeTab: 'detail',
searchData: {
site: '',
iqcNo: '',
supplierNo: '',
supplierName: '',
itemCode: '',
purOrder: '',
inspectionStatus: '',
issueDateStart: '',
issueDateEnd: '',
page: 1,
limit: 50
},
pageIndex: 1,
pageSize: 50,
totalPage: 0,
mainDataList: [],
dataListLoading: false
}
},
mounted () {
this.$nextTick(() => {
//
const availableHeight = window.innerHeight - 320
this.tableHeight = availableHeight / 2
this.detailHeight = availableHeight / 2
this.getMainData()
})
},
methods: {
//
getMainData () {
this.searchData.limit = this.pageSize
this.searchData.page = this.pageIndex
this.searchData.site = this.$store.state.user.site
this.dataListLoading = true
searchNpcIqc(this.searchData).then(({ data }) => {
if (data.code === 0) {
this.mainDataList = data.page.list
this.pageIndex = data.page.currPage
this.pageSize = data.page.pageSize
this.totalPage = data.page.totalCount
this.$nextTick(() => {
if (this.$refs.mainTable) {
this.$refs.mainTable.clearSelection()
}
})
if (this.mainDataList.length > 0) {
this.$refs.mainTable.setCurrentRow(this.mainDataList[0])
this.changeData(this.mainDataList[0])
} else {
this.changeData(null)
}
}
this.dataListLoading = false
}).catch(() => {
this.dataListLoading = false
})
},
sizeChangeHandle (val) {
this.pageSize = val
this.pageIndex = 1
this.getMainData()
},
currentChangeHandle (val) {
this.pageIndex = val
this.getMainData()
},
handleTabClick (tab) {
//
},
changeData (row) {
this.currentRow = row ? JSON.parse(JSON.stringify(row)) : {}
},
excelImport () {
this.$message.info('Excel导入功能待开发')
},
exportExcel () {
console.log('开始导出...')
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
const hour = String(now.getHours()).padStart(2, '0')
const minute = String(now.getMinutes()).padStart(2, '0')
const second = String(now.getSeconds()).padStart(2, '0')
const exportName = `NPC_IQC_${year}${month}${day}${hour}${minute}${second}`
const exportParams = {
...this.searchData,
limit: -1,
page: 1
}
try {
excel.exportTable({
url: '/npcIqc/search',
columnMapping: [],
mergeSetting: [],
params: exportParams,
fileName: exportName + '.xlsx',
rowFetcher: res => {
return res.data.page.list
},
columnFormatter: [],
dropColumns: []
})
} catch (error) {
console.error('导出失败:', error)
this.$message.error('导出失败: ' + error.message)
}
}
},
created () {
this.getMainData()
}
}
</script>
<style scoped lang="scss">
.npc-iqc-container {
padding: 0;
margin: 0;
}
.npc-iqc-container /deep/ .el-table {
margin-top: 0 !important;
}
.page-title {
margin-bottom: 15px;
h2 {
font-size: 20px;
color: #303133;
margin: 0 0 5px 0;
font-weight: 500;
}
p {
font-size: 13px;
color: #909399;
margin: 0;
}
}
.search-form-inline {
background: #fff;
padding: 5px 10px;
margin-bottom: 5px;
}
.search-row {
display: flex;
align-items: flex-end;
flex-wrap: nowrap;
gap: 8px;
margin-bottom: 5px;
}
.search-row:last-child {
margin-bottom: 0;
}
.search-item {
flex: none;
margin-bottom: 0;
}
.search-item /deep/ .el-form-item__label {
font-size: 12px;
color: #606266;
padding-bottom: 2px;
line-height: 1;
height: auto;
}
.search-item /deep/ .el-form-item__content {
line-height: normal;
}
.search-btn-item /deep/ .el-form-item__content {
line-height: normal;
}
/* 按钮样式调整 */
.customer-bun-min {
padding: 7px 12px;
font-size: 12px;
border-radius: 2px;
}
.date-range {
display: flex;
align-items: center;
}
.split {
padding: 0 6px;
color: #606266;
font-size: 13px;
}
/deep/ .customer-tab {
overflow: hidden;
margin-top: 5px !important;
}
/deep/ .customer-tab .el-tabs__content {
padding: 0 !important;
height: 100%;
overflow: hidden;
}
/* 分页插件紧凑化 */
/deep/ .el-pagination {
margin-top: 5px !important;
padding: 3px 0;
}
/* 表格紧凑化 */
/deep/ .el-table__header th,
/deep/ .el-table__body td {
padding: 4px 0;
}
</style>

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

@ -262,7 +262,7 @@ export default {
<style scoped lang="scss">
.detail-container {
padding: 15px 20px;
padding: 10px 15px;
border: 1px solid #dcdfe6;
background: #fff;
}
@ -270,7 +270,7 @@ export default {
.detail-row {
display: flex;
align-items: center;
margin-bottom: 18px;
margin-bottom: 12px;
}
.detail-row.full-width {
@ -285,30 +285,30 @@ export default {
.detail-item {
display: flex;
align-items: center;
width: 300px;
margin-right: 30px;
width: 280px;
margin-right: 20px;
}
.detail-item.long {
width: 450px;
width: 400px;
}
.label {
color: #606266;
font-size: 14px;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.value {
flex: 1;
min-height: 28px;
line-height: 28px;
padding: 0 10px;
min-height: 26px;
line-height: 26px;
padding: 0 8px;
border: 1px solid #dcdfe6;
background: #fff;
color: #303133;
font-size: 14px;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -316,9 +316,9 @@ export default {
.value.textarea {
width: 100%;
min-height: 60px;
min-height: 50px;
line-height: 1.5;
padding: 10px;
padding: 8px;
white-space: pre-wrap;
word-break: break-all;
}
@ -337,17 +337,17 @@ export default {
/* 索赔信息区域样式 */
.claim-section {
border: 1px solid #dcdfe6;
padding: 15px;
margin-bottom: 18px;
padding: 10px 12px;
margin-bottom: 12px;
background: #fff;
}
.claim-title {
font-size: 14px;
font-size: 13px;
font-weight: 500;
color: #303133;
margin-bottom: 15px;
padding-left: 10px;
margin-bottom: 10px;
padding-left: 8px;
border-left: 3px solid #409eff;
}

Loading…
Cancel
Save