Browse Source

feat(npcIqc): 新增物流管理模块和附件功能

- 创建物流管理页面,包含进仓编号、供应商信息查询功能
- 实现主表数据展示和分页功能
- 添加PO清单页签显示订单明细信息
- 开发附件上传、下载、删除功能组件
- 集成附件管理到物流管理页面页签中
- 添加物流相关API接口定义
- 调整首页样式以适配技术框架布局
master
qiankanghui 7 days ago
parent
commit
c29bcab1da
  1. 6
      src/api/npcIqc/npcIqc.js
  2. 29
      src/views/common/home.vue
  3. 266
      src/views/modules/npcIqc/com_logisticsAttachmentTab.vue
  4. 323
      src/views/modules/npcIqc/logisticsManagement.vue

6
src/api/npcIqc/npcIqc.js

@ -2,6 +2,12 @@ import { createAPI } from '@/utils/httpRequest.js'
export const searchNpcIqc = (data) => createAPI(`/npcIqc/search`, 'post', data) export const searchNpcIqc = (data) => createAPI(`/npcIqc/search`, 'post', data)
// 查询物流记录
export const searchLogistics = (data) => createAPI(`/srm/logistics/search`, 'post', data)
// 查询PO清单
export const getPoList = (data) => createAPI(`/srm/logistics/getPoList`, 'post', data)
// 下载导入模板 // 下载导入模板
export const downloadTemplate = () => { export const downloadTemplate = () => {
return createAPI('/npcIqc/downloadTemplate', 'post', {}, { responseType: 'blob' }) return createAPI('/npcIqc/downloadTemplate', 'post', {}, { responseType: 'blob' })

29
src/views/common/home.vue

@ -360,4 +360,33 @@ export default {
color: #64748b; color: #64748b;
margin-top: 6px; margin-top: 6px;
} }
/* 强制整体靠左顶格 + 靠上顶格 */
.mod-home--tech .tech-frame {
max-width: none !important;
margin: 0 !important;
padding: 0 !important;
}
.mod-home--tech .tech-backdrop {
padding: 0 !important; /* 去掉顶部内边距 */
margin: 0 !important;
}
.mod-home--tech .home-reminders {
margin-top: 12px !important;
}
.mod-home--tech .tech-header--simple {
margin: 0 !important; /* 去掉标题上边距 */
padding: 0 !important;
}
.mod-home--tech .tech-header__title {
margin: 0 !important;
padding: 0 !important;
}
.mod-home--tech .tech-header--simple::after {
left: 0;
}
</style> </style>

266
src/views/modules/npcIqc/com_logisticsAttachmentTab.vue

@ -0,0 +1,266 @@
<template>
<div class="customer-css">
<!-- 操作按钮 -->
<el-form :inline="true" style="margin-bottom: 2px;">
<el-button type="primary" icon="el-icon-upload" @click="handleUpload" :disabled="!searchData.flexId">上传附件</el-button>
</el-form>
<!-- 附件文件列表表格 -->
<el-table
:data="fileList"
:height="tableHeight"
border
v-loading="loading"
style="width: 100%;">
<el-table-column
type="index"
label="序号"
width="80"
align="center" />
<el-table-column
prop="fileName"
label="附件名称"
min-width="250"
show-overflow-tooltip />
<el-table-column
prop="createdBy"
label="创建人"
width="120"
align="center" />
<el-table-column
prop="createDate"
label="创建时间"
width="160"
align="center" />
<el-table-column
label="操作"
width="150"
align="center"
fixed="right">
<template slot-scope="scope">
<el-link type="primary" @click="handleDownload(scope.row)">查看 |</el-link>
<el-link type="danger" @click="handleRemove(scope.row)">删除</el-link>
</template>
</el-table-column>
</el-table>
<!-- 上传附件弹窗 -->
<el-dialog title="上传附件" :visible.sync="ossVisible" width="450px" append-to-body :close-on-click-modal="false">
<el-form ref="form" :model="ossForm" label-width="80px" label-position="top">
<el-form-item label=" " class="auto">
<el-upload
drag
:file-list="uploadFileList"
action="#"
ref="upload"
:on-remove="onRemoveFile"
:on-change="onChangeFile"
multiple
:auto-upload="false">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" :loading="uploadLoading" @click="submitData">确定</el-button>
<el-button @click="ossVisible = false">取消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { queryOssFilePlus, removeOss, previewOssFileById } from '@/api/oss/oss'
import { ossUploadNoSaveOSSForYJY } from '@/api/oss/oss'
export default {
name: 'LogisticsAttachmentTab',
props: {
detailData: {
type: Object,
default: () => ({})
},
tableHeight: {
type: Number,
default: 400
}
},
data() {
return {
fileList: [],
loading: false,
searchData: {
flexId: '',
site: ''
},
ossVisible: false,
uploadLoading: false,
uploadFileList: [],
ossForm: {
remark: ''
}
}
},
watch: {
// detailData
detailData: {
handler(newVal) {
if (newVal && newVal.flexId) {
this.searchData.flexId = newVal.flexId
this.searchData.site = newVal.site || ''
this.searchTable()
} else {
this.fileList = []
}
},
deep: true,
immediate: true
}
},
methods: {
//
searchTable() {
if (!this.searchData.flexId) {
this.fileList = []
return
}
console.log('当前 searchData:', this.searchData)
this.loading = true
let params = {
orderRef1: this.searchData.site,
orderRef2: this.searchData.flexId,
orderRef3: '',
orderReftype: 'LogisticsAttachment'
}
console.log('查询附件参数:', params)
queryOssFilePlus(params).then(({ data }) => {
console.log('查询附件返回:', data)
if (data && data.code === 0) {
this.fileList = data.rows || []
console.log('附件列表:', this.fileList)
} else {
this.fileList = []
}
this.loading = false
}).catch((error) => {
console.error('查询附件失败:', error)
this.loading = false
})
},
//
handleUpload() {
this.$nextTick(() => {
if (this.$refs.upload) {
this.$refs.upload.clearFiles()
}
})
this.uploadFileList = []
this.ossForm.remark = ''
this.ossVisible = true
},
//
onRemoveFile(file, fileList) {
this.uploadFileList = fileList
},
//
onChangeFile(file, fileList) {
this.uploadFileList = fileList
},
//
submitData() {
if (this.uploadFileList.length === 0) {
this.$message.error('请选择文件')
return
}
this.uploadLoading = true
let formData = new FormData()
for (let i = 0; i < this.uploadFileList.length; i++) {
formData.append('file', this.uploadFileList[i].raw)
}
formData.append('orderRef1', this.searchData.site)
formData.append('orderRef2', this.searchData.flexId)
formData.append('orderRef3', '')
formData.append('createdBy', this.$store.state.user.name)
formData.append('fileRemark', this.ossForm.remark || '')
formData.append('orderReftype', 'LogisticsAttachment')
ossUploadNoSaveOSSForYJY(formData).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('上传成功')
this.searchTable()
this.ossVisible = false
} else {
this.$message.warning(data.msg || '上传失败')
}
this.uploadLoading = false
}).catch((error) => {
this.$message.error('上传失败')
this.uploadLoading = false
})
},
//
handleDownload(row) {
let params = {
id: row.id
}
previewOssFileById(params).then((response) => {
const blob = new Blob([response.data], { type: response.headers['content-type'] })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.setAttribute('download', row.fileName)
link.target = '_blank'
link.click()
URL.revokeObjectURL(link.href)
})
},
//
handleRemove(row) {
this.$confirm('确定要删除该附件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let ids = [row.id]
removeOss(ids).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('删除成功')
this.searchTable()
} else {
this.$message.warning(data.msg || '删除失败')
}
}).catch((error) => {
this.$message.error('删除失败')
})
}).catch(() => {})
}
}
}
</script>
<style scoped lang="scss">
.customer-css {
padding: 0;
margin: 0;
background: #fff;
}
.auto /deep/ .el-form-item__content {
height: auto;
line-height: 1.5;
}
</style>

323
src/views/modules/npcIqc/logisticsManagement.vue

@ -0,0 +1,323 @@
<template>
<div class="customer-css">
<!-- 查询条件 -->
<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.flexId" style="width: 150px" @keyup.enter.native="getMainData"/>
</el-form-item>
<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: 200px" @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-form-item>
</div>
</el-form>
<el-table
:height="height"
:data="mainDataList"
border
ref="mainTable"
highlight-current-row
@row-click="changeData"
v-loading="dataListLoading"
style="margin-top: 0px; width: 100%;">
<el-table-column
type="index"
label="序号"
width="80"
align="center" />
<el-table-column
prop="flexId"
label="进仓编号"
min-width="150"
show-overflow-tooltip />
<el-table-column
prop="supplierNo"
label="供应商编码"
width="120"
align="center" />
<el-table-column
prop="supplierName"
label="供应商名称"
min-width="200"
show-overflow-tooltip />
<el-table-column
prop="poCount"
label="PO数量"
width="100"
align="center" />
<el-table-column
prop="shippedQty"
label="已出货数量"
width="120"
align="center" />
<el-table-column
label="操作"
width="150"
align="center"
fixed="right">
<template slot-scope="scope">
<el-link type="danger" @click="handleDeleteAttachment(scope.row)">删除附件</el-link>
</template>
</el-table-column>
</el-table>
<!-- 分页插件 -->
<el-pagination style="margin-top: 0px"
@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="margin-top: 0px; width: 99%;" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<!-- PO清单 -->
<el-tab-pane label="PO清单" name="poList">
<el-table
:data="poListData"
border
:height="detailHeight"
v-loading="poListLoading"
style="width: 100%;">
<el-table-column
type="index"
label="序号"
width="80"
align="center" />
<el-table-column
prop="orderNo"
label="PO"
min-width="150"
show-overflow-tooltip />
<el-table-column
prop="orderDate"
label="PO Date"
width="120"
align="center" />
<el-table-column
prop="partNo"
label="SKU"
min-width="150"
show-overflow-tooltip />
<el-table-column
prop="qty"
label="Qty"
width="100"
align="center" />
<el-table-column
prop="shippedQty"
label="Qty Shipped"
width="120"
align="center" />
</el-table>
</el-tab-pane>
<!-- 附件 -->
<el-tab-pane label="附件" name="attachment">
<logistics-attachment-tab ref="attachmentTab" :detail-data="currentRow" :table-height="detailHeight" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import LogisticsAttachmentTab from './com_logisticsAttachmentTab.vue'
import { searchLogistics, getPoList } from '@/api/npcIqc/npcIqc.js'
export default {
components: {
LogisticsAttachmentTab
},
data () {
return {
height: 400,
detailHeight: 400,
currentRow: {},
activeTab: 'poList',
searchData: {
flexId: '',
supplierNo: '',
supplierName: '',
site: this.$store.state.user.site,
page: 1,
limit: 50
},
pageIndex: 1,
pageSize: 50,
totalPage: 0,
mainDataList: [],
poListData: [],
dataListLoading: false,
poListLoading: false
}
},
mounted () {
this.$nextTick(() => {
this.height = (window.innerHeight - 220) / 2
this.detailHeight = (window.innerHeight - 220) / 2
this.getMainData()
})
},
methods: {
//
getMainData () {
this.searchData.limit = this.pageSize
this.searchData.page = this.pageIndex
this.dataListLoading = true
searchLogistics(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) {
if (tab.name === 'poList') {
this.loadPoList()
} else if (tab.name === 'attachment') {
this.$nextTick(() => {
if (this.$refs.attachmentTab) {
this.$refs.attachmentTab.searchTable()
}
})
}
},
//
changeData (row) {
this.currentRow = row ? JSON.parse(JSON.stringify(row)) : {}
this.loadPoList()
},
// PO
loadPoList () {
if (!this.currentRow.flexId) {
this.poListData = []
return
}
this.poListLoading = true
const params = {
flexId: this.currentRow.flexId,
supplierNo: this.currentRow.supplierNo || '',
site: this.$store.state.user.site,
page: 1,
limit: 1000
}
getPoList(params).then(({ data }) => {
if (data.code === 0 && data.page) {
this.poListData = data.page.list || []
} else {
this.poListData = []
}
this.poListLoading = false
}).catch(() => {
this.poListData = []
this.poListLoading = false
})
},
//
handleDeleteAttachment (row) {
this.$message.info('删除附件功能待开发')
}
},
created () {
this.getMainData()
}
}
</script>
<style scoped lang="scss">
.customer-css {
padding: 0;
margin: 0;
background: #fff;
}
.search-form-inline {
background: #fff;
}
.search-row {
display: flex;
align-items: flex-end;
flex-wrap: nowrap;
gap: 15px;
}
.search-item {
flex: none;
margin-bottom: 10px;
}
.search-btn-item {
flex: none;
margin-bottom: 10px;
}
.search-btn-item /deep/ .el-form-item__content {
line-height: normal;
}
.search-item /deep/ .el-form-item__label {
font-size: 13px;
color: #606266;
padding-bottom: 5px;
line-height: 1;
height: auto;
}
.search-item /deep/ .el-form-item__content {
line-height: normal;
}
/deep/ .customer-tab .el-tabs__content {
padding: 5px !important;
}
</style>
Loading…
Cancel
Save