Browse Source

新品流程OK

master
常熟吴彦祖 2 weeks ago
parent
commit
3b7692805b
  1. 11
      src/api/inspection/inspectionRequestHeader.js
  2. 181
      src/views/modules/inspection/com_inspectionScheduleView.vue
  3. 46
      src/views/modules/inspection/myTodoList.vue
  4. 105
      src/views/modules/qc/IQCFileTable.vue

11
src/api/inspection/inspectionRequestHeader.js

@ -53,7 +53,16 @@ export const scheduleInspectionRequest = (data) => createAPI(`/inspection/schedu
export const getQcPersonList = (data) => createAPI(`/inspection/getQcPersonList`, 'post', data)
// 查询排程视图
export const getScheduleView = (qcOperator) => createAPI(`/inspection/scheduleView?qcOperator=${qcOperator}`, 'get')
export const getScheduleView = (qcOperator, startDate, site) => {
const params = [`qcOperator=${encodeURIComponent(qcOperator || '')}`]
if (startDate) {
params.push(`startDate=${encodeURIComponent(startDate)}`)
}
if (site) {
params.push(`site=${encodeURIComponent(site)}`)
}
return createAPI(`/inspection/scheduleView?${params.join('&')}`, 'get')
}
// 修改验货申请(仅允许修改建议验货日期、验货地址和联系人)
export const updateInspectionRequest = (data) => createAPI(`/inspection/update`, 'post', data)

181
src/views/modules/inspection/com_inspectionScheduleView.vue

@ -55,8 +55,7 @@
:key="task.requestNo"
class="task-item"
@click="handleTaskClick(task)">
<div class="task-no">单号{{ task.requestNo }}</div>
<div class="task-supplier" :title="task.supplierName">{{ task.supplierName }}</div>
<div class="task-line-text" :title="buildTaskLineText(task)">{{ buildTaskLineText(task) }}</div>
<!-- <div v-if="task.inspectAddress" class="task-address" :title="task.inspectAddress">
<i class="el-icon-location"></i> {{ task.inspectAddress }}
</div> -->
@ -105,6 +104,19 @@
:close-on-click-modal="false"
append-to-body
top="5vh">
<el-form :inline="true" size="small" class="all-qc-query-form">
<el-form-item label="起始日期">
<el-date-picker
v-model="allQcQuery.startDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择起始日期"
style="width: 150px;" />
</el-form-item>
<el-form-item label=" ">
<el-button type="primary" size="small" @click="queryAllQcSchedule">查询</el-button>
</el-form-item>
</el-form>
<div class="all-qc-schedule-container" v-loading="allQcLoading">
<div class="schedule-days-grid">
<div v-for="day in allScheduleDays" :key="day.date" class="schedule-day-card">
@ -116,13 +128,14 @@
<div
v-for="qcTask in day.qcTasks"
:key="qcTask.userName"
class="qc-task-item"
@click="handleQcTaskClick(qcTask)">
<div class="qc-name-tag">{{ qcTask.qcName }}</div>
class="qc-task-item">
<div class="task-list">
<div v-for="task in qcTask.tasks" :key="task.requestNo" class="mini-task">
<span class="task-no-text">{{ task.requestNo }}</span>
<span class="task-supplier-text" :title="task.supplierName">{{ task.supplierName }}</span>
<div
v-for="task in qcTask.tasks"
:key="task.requestNo"
class="mini-task"
@click="handleQcTaskClick({ ...task, qcName: qcTask.qcName, userName: qcTask.userName })">
<span class="task-line-text" :title="buildTaskLineText(task, qcTask.qcName)">{{ buildTaskLineText(task, qcTask.qcName) }}</span>
</div>
</div>
</div>
@ -162,6 +175,9 @@ export default {
allQcLoading: false,
allQcScheduleData: {}, // QC { userName: [days] }
allScheduleDays: [], // [{ date, dateLabel, weekday, qcTasks: [...] }]
allQcQuery: {
startDate: ''
},
scheduleForm: {
qcOperator: '',
qcUserName: '',
@ -224,7 +240,11 @@ export default {
loadQcList() {
console.log('[排程视图] 开始加载QC列表')
const params = { page: 1, limit: 100 }
const params = {
page: 1,
limit: 100,
site: this.$store.state.user.site
}
getQcPersonList(params)
.then(({ data }) => {
if (data.code === 0 && data.page && data.page.list) {
@ -356,23 +376,25 @@ export default {
}
this.loading = true
console.log('[排程视图] 开始加载排程数据, QC:', qc.userName)
getScheduleView(qc.userName)
getScheduleView(qc.userName, this.getTodayDateString(), this.$store.state.user.site)
.then(({ data }) => {
if (data.code === 0) {
const days = this.generateNextDays(10)
const tasksByDate = {}
;(data.list || []).forEach(task => {
const startDate = new Date(task.planStartDate)
const endDate = new Date(task.planEndDate || task.planStartDate)
let currentDate = new Date(startDate)
while (currentDate <= endDate) {
const taskStartDate = new Date(task.planStartDate)
const taskEndDate = new Date(task.planEndDate || task.planStartDate)
let currentDate = new Date(taskStartDate)
while (currentDate <= taskEndDate) {
const dateStr = this.formatDate(currentDate)
if (!tasksByDate[dateStr]) tasksByDate[dateStr] = []
const exists = tasksByDate[dateStr].some(t => t.requestNo === task.requestNo)
if (!exists) {
tasksByDate[dateStr].push({
requestNo: task.requestNo,
poNo: task.poNo,
supplierName: task.supplierName,
qcDisplay: qc.qcName,
inspectAddress: task.inspectAddress,
planStartDate: task.planStartDate,
planEndDate: task.planEndDate
@ -408,13 +430,13 @@ export default {
this.loading = false
})
},
generateNextDays(days) {
generateNextDays(days, startDate) {
const result = []
const today = new Date()
const baseDate = this.parseDateString(startDate) || new Date()
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
for (let i = 0; i < days; i++) {
const date = new Date(today)
date.setDate(today.getDate() + i)
const date = new Date(baseDate)
date.setDate(baseDate.getDate() + i)
result.push({
date: this.formatDate(date),
dateLabel: `${date.getMonth() + 1}/${date.getDate()}`,
@ -424,6 +446,36 @@ export default {
}
return result
},
getTodayDateString() {
return this.formatDate(new Date())
},
parseDateString(dateStr) {
if (!dateStr) {
return null
}
const parts = String(dateStr).split('-')
if (parts.length !== 3) {
return null
}
const year = Number(parts[0])
const month = Number(parts[1]) - 1
const day = Number(parts[2])
const parsedDate = new Date(year, month, day)
if (Number.isNaN(parsedDate.getTime())) {
return null
}
return parsedDate
},
getSupplierDisplayName(supplierName) {
const value = supplierName || ''
return value.length > 30 ? value.substring(0, 30) : value
},
buildTaskLineText(task, qcDisplayName) {
const displayName = qcDisplayName || task.qcDisplay || (this.selectedQc ? this.selectedQc.qcName : '')
const poNo = task.poNo || ''
const supplierName = this.getSupplierDisplayName(task.supplierName)
return [displayName, poNo, supplierName].filter(item => item).join(' | ')
},
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
@ -437,6 +489,14 @@ export default {
// QC
showAllQcSchedule() {
this.allQcScheduleDialogVisible = true
this.allQcQuery.startDate = this.getTodayDateString()
this.loadAllQcSchedule()
},
// QC
queryAllQcSchedule() {
if (!this.allQcQuery.startDate) {
this.allQcQuery.startDate = this.getTodayDateString()
}
this.loadAllQcSchedule()
},
// QC
@ -445,23 +505,26 @@ export default {
this.$message.warning('暂无QC人员数据')
return
}
const startDate = this.allQcQuery.startDate || this.getTodayDateString()
this.allQcQuery.startDate = startDate
this.allQcLoading = true
const promises = this.qcList.map(qc => {
return getScheduleView(qc.userName).then(({ data }) => {
return getScheduleView(qc.userName, startDate, this.$store.state.user.site).then(({ data }) => {
if (data.code === 0) {
const days = this.generateNextDays(10)
const days = this.generateNextDays(10, startDate)
const tasksByDate = {}
;(data.list || []).forEach(task => {
const startDate = new Date(task.planStartDate)
const endDate = new Date(task.planEndDate || task.planStartDate)
let currentDate = new Date(startDate)
while (currentDate <= endDate) {
const taskStartDate = new Date(task.planStartDate)
const taskEndDate = new Date(task.planEndDate || task.planStartDate)
let currentDate = new Date(taskStartDate)
while (currentDate <= taskEndDate) {
const dateStr = this.formatDate(currentDate)
if (!tasksByDate[dateStr]) tasksByDate[dateStr] = []
const exists = tasksByDate[dateStr].some(t => t.requestNo === task.requestNo)
if (!exists) {
tasksByDate[dateStr].push({
requestNo: task.requestNo,
poNo: task.poNo,
supplierName: task.supplierName,
inspectAddress: task.inspectAddress,
planStartDate: task.planStartDate,
@ -477,17 +540,17 @@ export default {
}))
return { userName: qc.userName, qcName: qc.qcName, scheduleDays }
} else {
return { userName: qc.userName, qcName: qc.qcName, scheduleDays: this.generateNextDays(10) }
return { userName: qc.userName, qcName: qc.qcName, scheduleDays: this.generateNextDays(10, startDate) }
}
}).catch(() => {
return { userName: qc.userName, qcName: qc.qcName, scheduleDays: this.generateNextDays(10) }
return { userName: qc.userName, qcName: qc.qcName, scheduleDays: this.generateNextDays(10, startDate) }
})
})
Promise.all(promises).then(results => {
//
const daysMap = {}
const baseDays = this.generateNextDays(10)
const baseDays = this.generateNextDays(10, startDate)
//
baseDays.forEach(day => {
@ -665,35 +728,14 @@ export default {
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
}
}
.task-no {
font-size: 13px;
font-weight: bold;
color: #409eff;
margin-bottom: 5px;
}
.task-supplier {
.task-line-text {
font-size: 12px;
color: #606266;
word-wrap: break-word;
word-break: break-all;
white-space: normal;
line-height: 1.5;
margin-bottom: 4px;
}
.task-address {
font-size: 10px;
color: #909399;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
i {
margin-right: 2px;
}
}
}
.empty-slot {
@ -733,6 +775,11 @@ export default {
}
/* 所有QC排程弹窗样式 */
.all-qc-query-form {
padding: 0 10px;
margin-bottom: 6px;
}
.all-qc-schedule-container {
max-height: 75vh;
overflow-y: auto;
@ -826,15 +873,6 @@ export default {
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.12);
}
.qc-name-tag {
font-size: 12px;
font-weight: bold;
color: #409eff;
margin-bottom: 4px;
padding-bottom: 3px;
border-bottom: 1px dashed #dcdfe6;
}
.task-list {
display: flex;
flex-direction: column;
@ -845,25 +883,10 @@ export default {
padding: 3px 5px;
background: #fff;
border-radius: 2px;
font-size: 10px;
color: #606266;
display: flex;
justify-content: space-between;
align-items: center;
gap: 4px;
.task-no-text {
font-weight: 500;
color: #303133;
flex-shrink: 0;
}
cursor: pointer;
.task-supplier-text {
color: #909399;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
&:hover {
background: #ecf5ff;
}
}
}

46
src/views/modules/inspection/myTodoList.vue

@ -22,8 +22,7 @@
:key="task.requestNo"
class="task-item"
@click="handleTaskClick(task, day.date)">
<div class="task-no">单号{{ task.requestNo }}</div>
<div class="task-supplier" :title="task.supplierName">{{ task.supplierName }}</div>
<div class="task-line-text" :title="buildTaskLineText(task)">{{ buildTaskLineText(task) }}</div>
<!-- <div v-if="task.inspectAddress" class="task-address" :title="task.inspectAddress">
<i class="el-icon-location"></i> {{ task.inspectAddress }}
</div> -->
@ -69,8 +68,11 @@ export default {
loadScheduleData () {
this.loading = true
const qcOperator = this.$store.state.user.name
const startDate = this.formatDate(new Date())
const site = this.$store.state.user.site
const qcDisplay = this.$store.state.user.userDisplay || this.$store.state.user.name
getScheduleView(qcOperator).then(({ data }) => {
getScheduleView(qcOperator, startDate, site).then(({ data }) => {
if (data.code === 0 && data.list) {
const days = this.generateNextDays(10)
const tasksByDate = {}
@ -85,7 +87,9 @@ export default {
if (!exists) {
tasksByDate[dateStr].push({
requestNo: task.requestNo,
poNo: task.poNo,
supplierName: task.supplierName,
qcDisplay: qcDisplay,
inspectAddress: task.inspectAddress,
planStartDate: task.planStartDate,
planEndDate: task.planEndDate
@ -136,6 +140,16 @@ export default {
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
getSupplierDisplayName (supplierName) {
const value = supplierName || ''
return value.length > 30 ? value.substring(0, 30) : value
},
buildTaskLineText (task) {
const displayName = task.qcDisplay || this.$store.state.user.userDisplay || this.$store.state.user.name
const poNo = task.poNo || ''
const supplierName = this.getSupplierDisplayName(task.supplierName)
return [displayName, poNo, supplierName].filter(item => item).join(' | ')
},
// -
handleTaskClick (task, date) {
@ -256,32 +270,14 @@ export default {
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
transform: translateY(-2px);
}
}
.task-no {
font-size: 13px;
font-weight: bold;
color: #409eff;
margin-bottom: 5px;
}
.task-supplier {
.task-line-text {
font-size: 12px;
color: #606266;
word-wrap: break-word;
word-break: break-all;
white-space: normal;
line-height: 1.4;
margin-bottom: 4px;
}
.task-address {
font-size: 11px;
color: #909399;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
i {
margin-right: 3px;
}
}
}
.empty-slot {

105
src/views/modules/qc/IQCFileTable.vue

@ -18,37 +18,53 @@ export default {
}
},
methods: {
getFileExt (row) {
const fromType = (row && row.fileType ? String(row.fileType) : '').trim()
if (fromType) {
return fromType.toLowerCase()
}
const fromSuffix = (row && row.fileSuffix ? String(row.fileSuffix) : '').trim()
if (fromSuffix) {
return fromSuffix.toLowerCase()
}
const fileName = row && row.fileName ? String(row.fileName) : ''
const lastDotIndex = fileName.lastIndexOf('.')
if (lastDotIndex >= 0 && lastDotIndex < fileName.length - 1) {
return fileName.substring(lastDotIndex + 1).toLowerCase()
}
return ''
},
getPreviewMimeType (ext) {
const image = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
if (image.includes(ext)) {
return 'image/' + ext
}
const video = ['mp4', 'avi', 'mov', 'wmv', 'flv']
if (video.includes(ext)) {
return 'video/' + ext
}
if (ext === 'txt') {
return 'text/plain'
}
if (ext === 'pdf') {
return 'application/pdf'
}
return ''
},
canPreview (row) {
const ext = this.getFileExt(row)
return !!this.getPreviewMimeType(ext)
},
emitFilePreviewed (row) {
this.$emit('file-previewed', row)
},
//
previewFile (row) {
//
let image = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
let type = ''
if (image.includes(row.fileType.toLowerCase())) {
type = 'image/' + row.fileType
}
let video = ['mp4', 'avi', 'mov', 'wmv', 'flv']
if (video.includes(row.fileType.toLowerCase())) {
type = 'video/' + row.fileType
}
let txt = ['txt']
if (txt.includes(row.fileType.toLowerCase())) {
type = 'text/plain'
}
let office = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx']
if (office.includes(row.fileType.toLowerCase())) {
this.$message.warning(`暂不支持预览${row.fileType.toLowerCase()}文件`)
return
}
let pdf = ['pdf']
if (pdf.includes(row.fileType.toLowerCase())) {
type = 'application/pdf'
}
if (type === ''){
this.$message.warning(`暂不支持预览${row.fileType.toLowerCase()}文件`)
const fileExt = this.getFileExt(row)
const type = this.getPreviewMimeType(fileExt)
if (type === '') {
this.$message.warning(`暂不支持预览${fileExt || '该类型'}文件`)
return;
}
downLoadObjectFile(row).then(({data}) => {
@ -63,31 +79,10 @@ export default {
//
previewFileMes (row) {
//
let image = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
let type = ''
if (image.includes(row.fileType.toLowerCase())) {
type = 'image/' + row.fileType
}
let video = ['mp4', 'avi', 'mov', 'wmv', 'flv']
if (video.includes(row.fileType.toLowerCase())) {
type = 'video/' + row.fileType
}
let txt = ['txt']
if (txt.includes(row.fileType.toLowerCase())) {
type = 'text/plain'
}
let office = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx']
if (office.includes(row.fileType.toLowerCase())) {
this.$message.warning(`暂不支持预览${row.fileType.toLowerCase()}文件`)
return
}
let pdf = ['pdf']
if (pdf.includes(row.fileType.toLowerCase())) {
type = 'application/pdf'
}
if (type === ''){
this.$message.warning(`暂不支持预览${row.fileType.toLowerCase()}文件`)
const fileExt = this.getFileExt(row)
const type = this.getPreviewMimeType(fileExt)
if (type === '') {
this.$message.warning(`暂不支持预览${fileExt || '该类型'}文件`)
return;
}
downLoadObjectFileMes(row).then(({data}) => {
@ -213,13 +208,19 @@ export default {
width="100"
label="操作">
<template slot-scope="scope">
<!-- <el-link v-if="scope.row.orderReftype !== 'mes'" style="cursor: pointer" @click="previewFile(scope.row)">预览</el-link>-->
<el-link
v-if="scope.row.orderReftype !== 'mes' && canPreview(scope.row)"
style="cursor: pointer"
@click="previewFile(scope.row)">预览</el-link>
<el-link v-if="scope.row.orderReftype !== 'mes'" style="cursor: pointer" @click="downloadFile(scope.row)">下载</el-link>
<el-link
v-if="scope.row.orderReftype !== 'mes' && scope.row.orderReftype !== 'PartSop' && scope.row.orderReftype !== 'PartFamilySop' && scope.row.orderReftype !== 'PartSkuSop'"
style="cursor: pointer"
@click="deleteFile(scope.row)">删除</el-link>
<!-- <el-link v-if="scope.row.orderReftype === 'mes'" style="cursor: pointer" @click="previewFileMes(scope.row)">预览</el-link>-->
<el-link
v-if="scope.row.orderReftype === 'mes' && canPreview(scope.row)"
style="cursor: pointer"
@click="previewFileMes(scope.row)">预览</el-link>
<el-link v-if="scope.row.orderReftype === 'mes'" style="cursor: pointer" @click="downloadFileMes(scope.row)">下载</el-link>
</template>
</el-table-column>

Loading…
Cancel
Save