feat: update production reporting workflows

This commit is contained in:
2026-07-07 17:30:12 +08:00
parent 1399b9a80a
commit c4a2f6e42e
24 changed files with 3713 additions and 35 deletions

View File

@@ -197,6 +197,12 @@
@click="getitemdata(scope.row.订单号)">查看</el-button>
</template>
</el-table-column>
<el-table-column align="center" label="历史工时" width="100">
<template slot-scope="scope">
<el-button type="text" size="mini"
@click="getWorkHour(scope.row.产品编码)">查看</el-button>
</template>
</el-table-column>
<el-table-column align="center" label="图纸" width="200">
<template slot-scope="scope">
<el-button v-if="scope.row.worker !=0"
@@ -372,6 +378,95 @@
</el-table>
</el-card>
</el-dialog>
<el-dialog :visible.sync="dialogcasual2" title="历史工时" center style="min-height: 300px;" width="1400px">
<el-card style="height: 550px">
<el-table
:data="itemdata"
:height="'55vh'"
border
size="mini"
style="margin-top: 20px; width: 95%;"
>
<el-table-column prop="taskDescription" label="任务描述" min-width="380" show-overflow-tooltip>
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level === 1 }">{{ scope.row.taskDescription || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="productionOrderNo" label="生产订单号" width="130" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.productionOrderNo || '' }}
</template>
</el-table-column>
<el-table-column prop="station" label="工位" width="110" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.station || '' }}
</template>
</el-table-column>
<el-table-column prop="reportWorkHours" label="报工工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.reportWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="auxiliaryWorkHours" label="辅助工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.auxiliaryWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="reportFinishQty" label="报工完成数" width="110" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.reportFinishQty || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="auxiliaryFinishQty" label="辅助完成数" width="110" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.auxiliaryFinishQty || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="totalWorkHours" label="合计工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.totalWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="clampingTime" label="装夹时间" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.clampingTime || '' }}
</template>
</el-table-column>
<el-table-column prop="programTime" label="程序时间" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.programTime || '' }}
</template>
</el-table-column>
<el-table-column prop="settlementReportPieceHours" label="结算报工单件工时" width="140" align="center">
<template slot-scope="scope">
{{ scope.row.settlementReportPieceHours || '' }}
</template>
</el-table-column>
<el-table-column prop="settlementAuxiliaryPieceHours" label="结算辅助单件工时" width="140" align="center">
<template slot-scope="scope">
{{ scope.row.settlementAuxiliaryPieceHours || '' }}
</template>
</el-table-column>
<el-table-column prop="operatorNames" label="操作人" width="180" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.operatorNames || '' }}
</template>
</el-table-column>
</el-table>
</el-card>
</el-dialog>
<!-- 图纸弹框 -->
<el-dialog :visible.sync="seeVisible" title="图纸" center width="1200px" overflow="scroll" >
<div id="el-dialog__body" style="min-height: 500px;"></div>
@@ -503,7 +598,8 @@ export default {
},
currentTime: "",
itemdata:[],
dialogcasual:false
dialogcasual:false,
dialogcasual2:false
}
},
computed: {
@@ -698,6 +794,25 @@ export default {
})
})
},
getWorkHour(item){
var param = []
this.dialogcasual2 = true
this.itemdata = []
param.push(["产品编码",item])
param.push(["合同号",''])
param.push(["订单号",''])
param.push(["工位",''])
param.push(["开始日期",''])
param.push(["结束日期",''])
param.push(["数据条数",100])
var Data = this.CreateData('11', '生产管理_结算工时_查询',param)
this.ExecDatabase(Data).then(response => {
response.data.forEach(element => {
if(element.Level == 2)
this.itemdata.push(element)
})
})
},
getCurrentTime() {
const now = new Date();
const year = now.getFullYear();

View File

@@ -180,6 +180,12 @@
@click="getitemdata(scope.row.订单号)">查看</el-button>
</template>
</el-table-column>
<el-table-column align="center" label="历史工时" width="100">
<template slot-scope="scope">
<el-button type="text" size="mini"
@click="getWorkHour(scope.row.产品编码)">查看</el-button>
</template>
</el-table-column>
<el-table-column align="center" prop="备注" label="备注" width="150" show-overflow-tooltip/>
<el-table-column align="center" prop="行文本备注" label="工艺备注" width="120" />
<el-table-column align="center" prop="任务概述" label="工艺说明" width="120" />
@@ -334,7 +340,95 @@
</el-table>
</el-card>
</el-dialog>
<el-dialog :visible.sync="dialogcasual2" title="历史工时" center style="min-height: 300px;" width="1400px">
<el-card style="height: 550px">
<el-table
:data="itemdata"
:height="'55vh'"
border
size="mini"
style="margin-top: 20px; width: 95%;"
>
<el-table-column prop="taskDescription" label="任务描述" min-width="380" show-overflow-tooltip>
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level === 1 }">{{ scope.row.taskDescription || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="productionOrderNo" label="生产订单号" width="130" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.productionOrderNo || '' }}
</template>
</el-table-column>
<el-table-column prop="station" label="工位" width="110" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.station || '' }}
</template>
</el-table-column>
<el-table-column prop="reportWorkHours" label="报工工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.reportWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="auxiliaryWorkHours" label="辅助工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.auxiliaryWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="reportFinishQty" label="报工完成数" width="110" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.reportFinishQty || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="auxiliaryFinishQty" label="辅助完成数" width="110" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.auxiliaryFinishQty || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="totalWorkHours" label="合计工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.totalWorkHours || '' }}</span>
</template>
</el-table-column>
<el-table-column prop="clampingTime" label="装夹时间" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.clampingTime || '' }}
</template>
</el-table-column>
<el-table-column prop="programTime" label="程序时间" width="100" align="center">
<template slot-scope="scope">
{{ scope.row.programTime || '' }}
</template>
</el-table-column>
<el-table-column prop="settlementReportPieceHours" label="结算报工单件工时" width="140" align="center">
<template slot-scope="scope">
{{ scope.row.settlementReportPieceHours || '' }}
</template>
</el-table-column>
<el-table-column prop="settlementAuxiliaryPieceHours" label="结算辅助单件工时" width="140" align="center">
<template slot-scope="scope">
{{ scope.row.settlementAuxiliaryPieceHours || '' }}
</template>
</el-table-column>
<el-table-column prop="operatorNames" label="操作人" width="180" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.operatorNames || '' }}
</template>
</el-table-column>
</el-table>
</el-card>
</el-dialog>
</div>
</template>
@@ -351,6 +445,7 @@ export default {
data() {
return {
dialogcasual:false,
dialogcasual2:false,
activeTab: 'form',
doneactiveTab: 'form',
orderNo: '',
@@ -613,6 +708,25 @@ export default {
})
})
},
getWorkHour(item){
var param = []
this.dialogcasual2 = true
this.itemdata = []
param.push(["产品编码",item])
param.push(["合同号",''])
param.push(["订单号",''])
param.push(["工位",''])
param.push(["开始日期",''])
param.push(["结束日期",''])
param.push(["数据条数",100])
var Data = this.CreateData('11', '生产管理_结算工时_查询',param)
this.ExecDatabase(Data).then(response => {
response.data.forEach(element => {
if(element.Level == 2)
this.itemdata.push(element)
})
})
},
getCurrentTime() {
const now = new Date();
const year = now.getFullYear();

View File

@@ -396,7 +396,12 @@ export default {
return this.getProcessBaseClass(process)
},
getRouteProcessName(process) {
return String(process.工序名称 || '')
const name = String(process.工序名称 || '')
const assignee = String(process.指派对象 || '')
if (!assignee || name.includes(`(${assignee})`) || name.includes(`${assignee}`)) {
return name
}
return `${name}(${assignee})`
},
escapeProcessHtml(value) {
return String(value == null ? '' : value)

View File

@@ -0,0 +1,281 @@
<template>
<div class="app-container design-check-page">
<el-card>
<div class="search-container" @keyup.enter="searchTable">
<span class="show-text">任务ID:</span>
<el-input v-model="searchForm.did" clearable size="small" style="width: 90px; margin-right: 8px" />
<span class="show-text">项目号:</span>
<el-input v-model="searchForm.projectNo" clearable size="small" style="width: 130px; margin-right: 8px" />
<span class="show-text">物料编码:</span>
<el-input v-model="searchForm.itemCode" clearable size="small" style="width: 170px; margin-right: 8px" />
<span class="show-text">操作人:</span>
<el-input v-model="searchForm.operator" clearable size="small" style="width: 120px; margin-right: 8px" />
<span class="show-text">开始日期:</span>
<el-date-picker v-model="searchForm.startDate" clearable type="date" value-format="yyyy-MM-dd" size="small" style="width: 140px; margin-right: 8px" />
<span class="show-text">结束日期:</span>
<el-date-picker v-model="searchForm.endDate" clearable type="date" value-format="yyyy-MM-dd" size="small" style="width: 140px; margin-right: 8px" />
<span class="show-text">校验状态:</span>
<el-select v-model="searchForm.checkStatus" size="small" style="width: 110px; margin-right: 8px">
<el-option label="未校验" value="未校验" />
<el-option label="已校验" value="已校验" />
<el-option label="全部" value="全部" />
</el-select>
<el-button :loading="loading" icon="el-icon-search" plain size="small" type="primary" @click="searchTable">查询</el-button>
<el-button :disabled="!multipleSelection.length" icon="el-icon-check" plain size="small" type="success" @click="batchValidate">批量校验</el-button>
</div>
<el-table
v-loading="loading"
:data="tableData"
border
height="74vh"
highlight-current-row
size="mini"
style="width: 100%; margin-top: 12px"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column align="center" fixed label="RID" prop="RID" width="70" />
<el-table-column align="center" fixed label="DID" prop="DID" width="70" />
<el-table-column align="center" label="校验状态" width="90">
<template slot-scope="scope">
<el-tag :type="scope.row.已校验 ? 'success' : 'info'" size="mini">{{ scope.row.校验状态 }}</el-tag>
</template>
</el-table-column>
<el-table-column align="left" label="项目号" prop="项目号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="物料编码" prop="物料编码" width="170" show-overflow-tooltip />
<el-table-column align="left" label="物料名称" prop="物料名称" width="180" show-overflow-tooltip />
<el-table-column align="left" label="图号" prop="图号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="任务描述" prop="任务描述" width="220" show-overflow-tooltip />
<el-table-column align="left" label="操作人" prop="操作人" width="110" show-overflow-tooltip />
<el-table-column align="center" label="开始时间" prop="开始时间" width="150" />
<el-table-column align="center" label="结束时间" prop="结束时间" width="150" />
<el-table-column align="right" label="工时(h)" prop="工时小时" width="90" />
<el-table-column align="left" label="校验人" prop="校验人" width="110" show-overflow-tooltip />
<el-table-column align="center" label="校验时间" prop="校验时间" width="150" />
<el-table-column align="left" label="备注" prop="备注" width="180" show-overflow-tooltip />
<el-table-column align="center" fixed="right" label="操作" width="90">
<template slot-scope="scope">
<el-button type="text" size="mini" :disabled="!!scope.row.已校验" @click="openValidate(scope.row)">
{{ scope.row.已校验 ? '已校验' : '校验' }}
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
title="设计工时校验"
width="620px"
center
:close-on-click-modal="false"
>
<el-form ref="checkForm" :model="formData" :rules="rules" label-width="110px" size="small">
<el-form-item label="RID">
<el-input v-model="formData.RID" disabled />
</el-form-item>
<el-form-item label="任务">
<el-input :value="`${formData.DID || ''} ${formData.任务描述 || ''}`" disabled />
</el-form-item>
<el-form-item label="操作人">
<el-input v-model="formData.操作人" disabled />
</el-form-item>
<el-form-item label="开始时间" prop="开始时间">
<el-date-picker v-model="formData.开始时间" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%" />
</el-form-item>
<el-form-item label="结束时间" prop="结束时间">
<el-date-picker v-model="formData.结束时间" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%" />
</el-form-item>
<el-form-item label="工时(h)">
<el-input :value="calculatedHours" disabled />
</el-form-item>
<el-form-item label="校验备注">
<el-input v-model="formData.备注" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitValidate">保存校验</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'DesignReportCheck',
data() {
return {
loading: false,
submitLoading: false,
dialogVisible: false,
tableData: [],
multipleSelection: [],
searchForm: {
did: '',
projectNo: '',
itemCode: '',
operator: '',
startDate: '',
endDate: '',
checkStatus: '未校验'
},
formData: {
RID: '',
DID: '',
任务描述: '',
操作人: '',
开始时间: '',
结束时间: '',
备注: ''
},
rules: {
开始时间: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
结束时间: [{ required: true, message: '请选择结束时间', trigger: 'change' }]
}
}
},
computed: {
calculatedHours() {
if (!this.formData.开始时间 || !this.formData.结束时间) return ''
const start = new Date(this.formData.开始时间)
const end = new Date(this.formData.结束时间)
const diff = end.getTime() - start.getTime()
if (Number.isNaN(diff) || diff <= 0) return ''
return (diff / 3600000).toFixed(2)
}
},
created() {
this.searchTable()
},
methods: {
buildSearchParams() {
return [
['DID', this.searchForm.did || 0],
['项目号', this.searchForm.projectNo || ''],
['物料编码', this.searchForm.itemCode || ''],
['操作人', this.searchForm.operator || ''],
['开始日期', this.searchForm.startDate || ''],
['结束日期', this.searchForm.endDate || ''],
['校验状态', this.searchForm.checkStatus || '全部']
]
},
async searchTable() {
this.loading = true
const data = this.CreateData('11', '设计报工_工时校验_查询', this.buildSearchParams())
try {
const response = await this.ExecDatabase(data)
this.tableData = response.data || []
} catch (error) {
console.error('设计工时校验查询失败:', error)
this.$message.error('查询失败')
} finally {
this.loading = false
}
},
handleSelectionChange(selection) {
this.multipleSelection = selection
},
openValidate(row) {
this.formData = {
RID: row.RID,
DID: row.DID,
任务描述: row.任务描述,
操作人: row.操作人,
开始时间: row.开始时间 || '',
结束时间: row.结束时间 || '',
备注: row.备注 || ''
}
this.dialogVisible = true
this.$nextTick(() => this.$refs.checkForm && this.$refs.checkForm.clearValidate())
},
submitValidate() {
this.$refs.checkForm.validate(async valid => {
if (!valid) return
if (new Date(this.formData.结束时间) <= new Date(this.formData.开始时间)) {
this.$message.error('结束时间必须大于开始时间')
return
}
this.submitLoading = true
const params = [
['RID', this.formData.RID],
['开始时间', this.formData.开始时间],
['结束时间', this.formData.结束时间],
['校验人ID', this.currentUserId()],
['校验人', this.currentUserName()],
['校验备注', this.formData.备注 || '']
]
const data = this.CreateData('12', '设计报工_工时校验_保存', params)
try {
const response = await this.ExecDatabase(data)
const result = this.getResult(response)
if (String(result.result) === '1') {
this.$message.success(result.message || '校验成功')
this.dialogVisible = false
this.searchTable()
} else {
this.$message.error(result.message || '校验失败')
}
} catch (error) {
console.error('设计工时校验保存失败:', error)
this.$message.error('校验失败')
} finally {
this.submitLoading = false
}
})
},
batchValidate() {
const rows = this.multipleSelection.filter(row => !row.已校验 && row.开始时间 && row.结束时间)
if (!rows.length) {
this.$message.warning('请选择未校验且已有结束时间的记录')
return
}
this.$confirm(`确定批量校验 ${rows.length} 条设计报工记录吗?`, '提示', { type: 'warning' })
.then(async () => {
const params = [
['RIDs', rows.map(row => row.RID).join(',')],
['校验人ID', this.currentUserId()],
['校验人', this.currentUserName()]
]
const data = this.CreateData('12', '设计报工_工时校验_批量保存', params)
const response = await this.ExecDatabase(data)
const result = this.getResult(response)
if (String(result.result) === '1') {
this.$message.success(result.message || '批量校验成功')
this.searchTable()
} else {
this.$message.error(result.message || '批量校验失败')
}
})
.catch(() => {})
},
getResult(response) {
const data = response && response.data
if (Array.isArray(data)) return data[0] || {}
if (data && Array.isArray(data.result)) return data.result[0] || {}
return data || {}
},
currentUserId() {
return (this.$store && this.$store.getters && this.$store.getters.id) || ''
},
currentUserName() {
return (this.$store && this.$store.getters && this.$store.getters.name) || ''
}
}
}
</script>
<style scoped>
.design-check-page {
padding: 12px;
}
.search-container {
line-height: 34px;
}
.show-text {
margin-right: 4px;
}
</style>

View File

@@ -0,0 +1,192 @@
<template>
<div class="app-container design-hours-report-page">
<el-card>
<div class="search-container" @keyup.enter="searchTable">
<span class="show-text">开始日期:</span>
<el-date-picker
v-model="searchForm.startDate"
clearable
type="date"
value-format="yyyy-MM-dd"
size="small"
style="width: 140px; margin-right: 8px"
/>
<span class="show-text">结束日期:</span>
<el-date-picker
v-model="searchForm.endDate"
clearable
type="date"
value-format="yyyy-MM-dd"
size="small"
style="width: 140px; margin-right: 8px"
/>
<span class="show-text">操作人:</span>
<el-input v-model="searchForm.operator" clearable size="small" style="width: 120px; margin-right: 8px" />
<span class="show-text">项目号:</span>
<el-input v-model="searchForm.projectNo" clearable size="small" style="width: 130px; margin-right: 8px" />
<span class="show-text">物料编码:</span>
<el-input v-model="searchForm.itemCode" clearable size="small" style="width: 170px; margin-right: 8px" />
<span class="show-text">任务ID:</span>
<el-input v-model="searchForm.did" clearable size="small" style="width: 90px; margin-right: 8px" />
<el-button :loading="loading" icon="el-icon-search" plain size="small" type="primary" @click="searchTable">查询</el-button>
</div>
<el-table
v-loading="loading"
:data="tableData"
border
default-expand-all
height="74vh"
row-key="id"
:tree-props="{ children: 'children' }"
size="mini"
style="width: 100%; margin-top: 12px"
>
<el-table-column label="操作人 / 日期 / 任务" min-width="260" show-overflow-tooltip>
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.Level <= 2 }">{{ getTreeTitle(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="工作日期" prop="工作日期" width="110" />
<el-table-column align="center" label="RID" prop="RID" width="70" />
<el-table-column align="center" label="DID" prop="DID" width="70" />
<el-table-column align="left" label="项目号" prop="项目号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="物料编码" prop="物料编码" width="170" show-overflow-tooltip />
<el-table-column align="left" label="物料名称" prop="物料名称" width="180" show-overflow-tooltip />
<el-table-column align="left" label="图号" prop="图号" width="120" show-overflow-tooltip />
<el-table-column align="center" label="报工次数" prop="报工次数" width="90" />
<el-table-column align="right" label="工时(h)" prop="工时小时" width="90">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.Level <= 2 }">{{ formatHours(scope.row.工时小时) }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="开始时间" prop="开始时间" width="150" />
<el-table-column align="center" label="结束时间" prop="结束时间" width="150" />
<el-table-column align="center" label="校验状态" prop="校验状态" width="90" />
<el-table-column align="left" label="备注" prop="备注" min-width="160" show-overflow-tooltip />
</el-table>
<div class="summary-footer">
<span>总工时<strong>{{ totalHours }}</strong> 小时</span>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'DesignReportHoursReport',
data() {
return {
loading: false,
tableData: [],
searchForm: {
startDate: '',
endDate: '',
operator: '',
projectNo: '',
itemCode: '',
did: ''
}
}
},
computed: {
totalHours() {
const total = this.tableData.reduce((sum, row) => sum + (Number(row.工时小时) || 0), 0)
return total.toFixed(2)
}
},
created() {
this.searchTable()
},
methods: {
buildSearchParams() {
return [
['开始日期', this.searchForm.startDate || ''],
['结束日期', this.searchForm.endDate || ''],
['操作人', this.searchForm.operator || ''],
['项目号', this.searchForm.projectNo || ''],
['物料编码', this.searchForm.itemCode || ''],
['DID', this.searchForm.did || 0]
]
},
async searchTable() {
this.loading = true
const data = this.CreateData('11', '设计报工_工时报表_作业者工时_查询', this.buildSearchParams())
try {
const response = await this.ExecDatabase(data)
this.tableData = this.buildTree(response.data || [])
} catch (error) {
console.error('设计工时报表查询失败:', error)
this.$message.error('查询失败')
} finally {
this.loading = false
}
},
buildTree(rows) {
const personMap = new Map()
const dateMap = new Map()
rows.forEach(row => {
if (row.Level === 1) {
personMap.set(row.id, { ...row, children: [] })
}
})
rows.forEach(row => {
if (row.Level === 2) {
const item = { ...row, children: [] }
dateMap.set(row.id, item)
const parent = personMap.get(row.parentId)
if (parent) parent.children.push(item)
}
})
rows.forEach(row => {
if (row.Level === 3) {
const parent = dateMap.get(row.parentId)
if (parent) parent.children.push({ ...row })
}
})
return Array.from(personMap.values())
},
getTreeTitle(row) {
if (row.Level === 1) return row.操作人 || '未填写操作人'
if (row.Level === 2) return row.工作日期 ? `日期 ${row.工作日期}` : '未填写日期'
return row.任务描述 || `${row.DID || ''}`
},
formatHours(value) {
if (value === null || value === undefined || value === '') return ''
const numberValue = Number(value)
if (Number.isNaN(numberValue)) return ''
return numberValue.toFixed(2)
}
}
}
</script>
<style scoped>
.design-hours-report-page {
padding: 12px;
}
.search-container {
line-height: 34px;
}
.show-text {
margin-right: 4px;
}
.bold-text {
font-weight: 600;
}
.summary-footer {
height: 36px;
line-height: 36px;
text-align: right;
color: #303133;
}
</style>

View File

@@ -0,0 +1,202 @@
<template>
<div class="app-container design-report-page">
<el-card>
<div class="search-container" @keyup.enter="searchTable">
<span class="show-text">任务ID:</span>
<el-input v-model="searchForm.did" clearable size="small" style="width: 90px; margin-right: 8px" />
<span class="show-text">项目号:</span>
<el-input v-model="searchForm.projectNo" clearable size="small" style="width: 130px; margin-right: 8px" />
<span class="show-text">物料编码:</span>
<el-input v-model="searchForm.itemCode" clearable size="small" style="width: 170px; margin-right: 8px" />
<span class="show-text">图号:</span>
<el-input v-model="searchForm.drawingNo" clearable size="small" style="width: 120px; margin-right: 8px" />
<span class="show-text">父件编码:</span>
<el-input v-model="searchForm.parentItemCode" clearable size="small" style="width: 170px; margin-right: 8px" />
<span class="show-text">状态:</span>
<el-select v-model="searchForm.status" clearable size="small" style="width: 110px; margin-right: 8px">
<el-option label="全部" value="全部" />
<el-option label="待开始" value="待开始" />
<el-option label="执行中" value="执行中" />
<el-option label="已结束" value="已结束" />
<el-option label="已完成" value="已完成" />
</el-select>
<el-button :loading="loading" icon="el-icon-search" plain size="small" type="primary" @click="searchTable">查询</el-button>
</div>
<el-table
v-loading="loading"
:data="tableData"
border
height="74vh"
highlight-current-row
size="mini"
style="width: 100%; margin-top: 12px"
>
<el-table-column align="center" fixed label="DID" prop="DID" width="70" />
<el-table-column align="center" fixed label="状态" prop="单据状态" width="90">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.单据状态)" size="mini">{{ scope.row.单据状态 }}</el-tag>
</template>
</el-table-column>
<el-table-column align="left" label="项目号" prop="项目号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="物料编码" prop="物料编码" width="170" show-overflow-tooltip />
<el-table-column align="left" label="物料名称" prop="物料名称" width="180" show-overflow-tooltip />
<el-table-column align="left" label="图号" prop="图号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="任务描述" prop="任务描述" width="220" show-overflow-tooltip />
<el-table-column align="left" label="指派对象" prop="指派对象" width="180" show-overflow-tooltip />
<el-table-column align="center" label="预计开始" prop="预计开始时间" width="150" />
<el-table-column align="center" label="预计结束" prop="预计结束时间" width="150" />
<el-table-column align="center" label="报工次数" prop="报工次数" width="90" />
<el-table-column align="center" label="未结束" prop="未结束报工数" width="80" />
<el-table-column align="center" label="最后开始" prop="最后开始时间" width="150" />
<el-table-column align="center" label="最后结束" prop="最后结束时间" width="150" />
<el-table-column align="left" label="设计要求" prop="设计要求" width="220" show-overflow-tooltip />
<el-table-column align="center" fixed="right" label="操作" width="180">
<template slot-scope="scope">
<el-button type="text" size="mini" :disabled="!canStart(scope.row)" @click="startTask(scope.row)">开始</el-button>
<el-button type="text" size="mini" :disabled="!canEnd(scope.row)" @click="endTask(scope.row)">结束</el-button>
<el-button type="text" size="mini" :disabled="!canComplete(scope.row)" @click="completeTask(scope.row)">完成</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
name: 'DesignReportWork',
data() {
return {
loading: false,
actionLoading: false,
tableData: [],
searchForm: {
did: '',
projectNo: '',
itemCode: '',
drawingNo: '',
parentItemCode: '',
status: ''
}
}
},
created() {
this.searchTable()
},
methods: {
buildSearchParams() {
return [
['DID', this.searchForm.did || 0],
['项目号', this.searchForm.projectNo || ''],
['物料编码', this.searchForm.itemCode || ''],
['图号', this.searchForm.drawingNo || ''],
['关联父件物料编码', this.searchForm.parentItemCode || ''],
['预计开始时间_Start', ''],
['预计开始时间_End', ''],
['预计结束时间_Start', ''],
['预计结束时间_End', ''],
['单据状态', this.searchForm.status || '']
]
},
async searchTable() {
this.loading = true
const data = this.CreateData('11', '设计报工_任务_查询', this.buildSearchParams())
try {
const response = await this.ExecDatabase(data)
this.tableData = response.data || []
} catch (error) {
console.error('设计报工任务查询失败:', error)
this.$message.error('查询失败')
} finally {
this.loading = false
}
},
canStart(row) {
return row.单据状态 !== '已完成' && Number(row.未结束报工数 || 0) === 0
},
canEnd(row) {
return row.单据状态 !== '已完成' && Number(row.未结束报工数 || 0) > 0
},
canComplete(row) {
return row.单据状态 !== '已完成' && Number(row.未结束报工数 || 0) === 0 && Number(row.报工次数 || 0) > 0
},
startTask(row) {
this.runAction('设计报工_任务_开始', [
['DID', row.DID],
['操作人ID', this.currentUserId()],
['操作人', this.currentUserName()]
], '开始成功')
},
endTask(row) {
this.runAction('设计报工_任务_结束', [
['DID', row.DID],
['操作人ID', this.currentUserId()],
['操作人', this.currentUserName()]
], '结束成功')
},
completeTask(row) {
this.$confirm(`确定完成设计任务 DID ${row.DID} 吗?`, '提示', { type: 'warning' })
.then(() => {
this.runAction('设计报工_任务_完成', [
['DID', row.DID],
['操作人', this.currentUserName()]
], '完成成功')
})
.catch(() => {})
},
async runAction(procedure, params, defaultMessage) {
if (this.actionLoading) return
this.actionLoading = true
const data = this.CreateData('12', procedure, params)
try {
const response = await this.ExecDatabase(data)
const result = this.getResult(response)
if (String(result.result) === '1') {
this.$message.success(result.message || defaultMessage)
this.searchTable()
} else {
this.$message.error(result.message || '操作失败')
}
} catch (error) {
console.error(`${procedure}失败:`, error)
this.$message.error('操作失败')
} finally {
this.actionLoading = false
}
},
getResult(response) {
const data = response && response.data
if (Array.isArray(data)) return data[0] || {}
if (data && Array.isArray(data.result)) return data.result[0] || {}
return data || {}
},
currentUserId() {
return (this.$store && this.$store.getters && this.$store.getters.id) || ''
},
currentUserName() {
return (this.$store && this.$store.getters && this.$store.getters.name) || ''
},
getStatusType(status) {
if (status === '已完成') return 'success'
if (status === '执行中') return 'warning'
if (status === '已结束') return 'primary'
return 'info'
}
}
}
</script>
<style scoped>
.design-report-page {
padding: 12px;
}
.search-container {
line-height: 34px;
}
.show-text {
margin-right: 4px;
}
</style>

View File

@@ -0,0 +1,578 @@
<template>
<div class="app-container design-task-page">
<el-card>
<div class="search-container" @keyup.enter="searchTable">
<span class="show-text">任务ID:</span>
<el-input v-model="searchForm.did" clearable size="small" style="width: 90px; margin-right: 8px" />
<span class="show-text">项目号:</span>
<el-select
v-model="searchForm.projectNo"
clearable
filterable
remote
:remote-method="queryProjects"
size="small"
style="width: 150px; margin-right: 8px"
>
<el-option v-for="item in projectOptions" :key="item.项目号" :label="item.项目号" :value="item.项目号" />
</el-select>
<span class="show-text">物料编码:</span>
<el-select
v-model="searchForm.itemCode"
clearable
filterable
remote
:remote-method="queryMaterialOptions"
size="small"
style="width: 190px; margin-right: 8px"
>
<el-option
v-for="item in materialOptions"
:key="item.物料编码"
:label="formatMaterialLabel(item)"
:value="item.物料编码"
/>
</el-select>
<span class="show-text">图号:</span>
<el-input v-model="searchForm.drawingNo" clearable size="small" style="width: 120px; margin-right: 8px" />
<span class="show-text">父件编码:</span>
<el-select
v-model="searchForm.parentItemCode"
clearable
filterable
remote
:remote-method="queryParentMaterialOptions"
size="small"
style="width: 190px; margin-right: 8px"
>
<el-option
v-for="item in parentMaterialOptions"
:key="item.物料编码"
:label="formatMaterialLabel(item)"
:value="item.物料编码"
/>
</el-select>
<span class="show-text">状态:</span>
<el-select v-model="searchForm.status" clearable size="small" style="width: 110px; margin-right: 8px">
<el-option label="全部" value="全部" />
<el-option label="待开始" value="待开始" />
<el-option label="执行中" value="执行中" />
<el-option label="已结束" value="已结束" />
<el-option label="已完成" value="已完成" />
</el-select>
<br>
<span class="show-text">预计开始:</span>
<el-date-picker
v-model="searchForm.planStartFrom"
clearable
size="small"
type="date"
value-format="yyyy-MM-dd"
style="width: 140px; margin-right: 4px"
/>
<span class="date-separator"></span>
<el-date-picker
v-model="searchForm.planStartTo"
clearable
size="small"
type="date"
value-format="yyyy-MM-dd"
style="width: 140px; margin-right: 8px"
/>
<span class="show-text">预计结束:</span>
<el-date-picker
v-model="searchForm.planEndFrom"
clearable
size="small"
type="date"
value-format="yyyy-MM-dd"
style="width: 140px; margin-right: 4px"
/>
<span class="date-separator"></span>
<el-date-picker
v-model="searchForm.planEndTo"
clearable
size="small"
type="date"
value-format="yyyy-MM-dd"
style="width: 140px; margin-right: 8px"
/>
<el-button :loading="loading" icon="el-icon-search" plain size="small" type="primary" @click="searchTable">查询</el-button>
<el-button icon="el-icon-plus" plain size="small" type="success" @click="openAdd">新建</el-button>
</div>
<el-table
v-loading="loading"
:data="tableData"
border
height="70vh"
highlight-current-row
size="mini"
style="width: 100%; margin-top: 12px"
>
<el-table-column align="center" fixed label="DID" prop="DID" width="70" />
<el-table-column align="center" fixed label="状态" prop="单据状态" width="90">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.单据状态)" size="mini">{{ scope.row.单据状态 }}</el-tag>
</template>
</el-table-column>
<el-table-column align="left" label="项目号" prop="项目号" width="120" show-overflow-tooltip />
<el-table-column align="left" label="物料编码" prop="物料编码" width="170" show-overflow-tooltip />
<el-table-column align="left" label="物料名称" prop="物料名称" width="180" show-overflow-tooltip />
<el-table-column align="left" label="图号" prop="图号" width="130" show-overflow-tooltip />
<el-table-column align="left" label="任务描述" prop="任务描述" width="220" show-overflow-tooltip />
<el-table-column align="left" label="父件物料编码" prop="关联父件物料编码" width="160" show-overflow-tooltip />
<el-table-column align="left" label="设计要求" prop="设计要求" width="220" show-overflow-tooltip />
<el-table-column align="left" label="研发立项号" prop="研发立项号" width="130" show-overflow-tooltip />
<el-table-column align="left" label="研发目的" prop="研发目的" width="200" show-overflow-tooltip />
<el-table-column align="left" label="指派对象" prop="指派对象" width="180" show-overflow-tooltip />
<el-table-column align="center" label="预计开始" prop="预计开始时间" width="150" />
<el-table-column align="center" label="预计结束" prop="预计结束时间" width="150" />
<el-table-column align="center" label="报工次数" prop="报工次数" width="90" />
<el-table-column align="center" label="未结束" prop="未结束报工数" width="80" />
<el-table-column align="center" label="创建日期" prop="创建日期" width="150" />
<el-table-column align="left" label="创建人" prop="创建人" width="110" show-overflow-tooltip />
<el-table-column align="left" label="备注" prop="备注" width="180" show-overflow-tooltip />
<el-table-column align="center" fixed="right" label="操作" width="130">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openEdit(scope.row)">编辑</el-button>
<el-button type="text" size="mini" class="danger-action" @click="deleteTask(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="isEdit ? '编辑设计任务' : '新建设计任务'"
width="860px"
center
:close-on-click-modal="false"
>
<el-form ref="taskForm" :model="formData" :rules="rules" label-width="130px" size="small">
<el-row :gutter="12">
<el-col v-if="isEdit" :span="12">
<el-form-item label="DID">
<el-input v-model="formData.DID" disabled />
</el-form-item>
</el-col>
<el-col v-if="isEdit" :span="12">
<el-form-item label="创建日期">
<el-input v-model="formData.创建日期" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目号">
<el-select
v-model="formData.项目号"
allow-create
clearable
filterable
remote
default-first-option
:remote-method="queryProjects"
style="width: 100%"
>
<el-option v-for="item in projectOptions" :key="item.项目号" :label="item.项目号" :value="item.项目号" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料编码" prop="物料编码">
<el-select
v-model="formData.物料编码"
clearable
filterable
remote
:remote-method="queryMaterialOptions"
style="width: 100%"
@change="handleMaterialChange"
>
<el-option
v-for="item in materialOptions"
:key="item.物料编码"
:label="formatMaterialLabel(item)"
:value="item.物料编码"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料名称">
<el-input v-model="formData.物料名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="图号">
<el-input v-model="formData.图号" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="任务描述" prop="任务描述">
<el-input v-model="formData.任务描述" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="父件物料编码">
<el-select
v-model="formData.关联父件物料编码"
clearable
filterable
remote
:remote-method="queryParentMaterialOptions"
style="width: 100%"
@change="handleParentMaterialChange"
>
<el-option
v-for="item in parentMaterialOptions"
:key="item.物料编码"
:label="formatMaterialLabel(item)"
:value="item.物料编码"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="父件物料名称">
<el-input v-model="formData.关联父件物料名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="研发立项号">
<el-input v-model="formData.研发立项号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="研发目的">
<el-input v-model="formData.研发目的" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="指派对象" prop="assigneeIds">
<el-select
v-model="formData.assigneeIds"
clearable
filterable
multiple
remote
:remote-method="queryPersonnel"
style="width: 100%"
@change="handleAssigneeChange"
>
<el-option
v-for="item in personnelOptions"
:key="item.人员编号"
:label="formatPersonLabel(item)"
:value="item.人员编号"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预计开始时间">
<el-date-picker v-model="formData.预计开始时间" type="date" value-format="yyyy-MM-dd" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预计结束时间">
<el-date-picker v-model="formData.预计结束时间" type="date" value-format="yyyy-MM-dd" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="设计要求">
<el-input v-model="formData.设计要求" type="textarea" :rows="3" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="formData.备注" type="textarea" :rows="2" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitForm">保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'DesignReportTask',
data() {
return {
loading: false,
submitLoading: false,
dialogVisible: false,
isEdit: false,
tableData: [],
projectOptions: [],
materialOptions: [],
parentMaterialOptions: [],
personnelOptions: [],
searchForm: {
did: '',
projectNo: '',
itemCode: '',
drawingNo: '',
parentItemCode: '',
planStartFrom: '',
planStartTo: '',
planEndFrom: '',
planEndTo: '',
status: ''
},
formData: this.getEmptyForm(),
rules: {
物料编码: [{ required: true, message: '请选择物料编码', trigger: 'change' }],
任务描述: [{ required: true, message: '请输入任务描述', trigger: 'blur' }],
assigneeIds: [{ type: 'array', required: true, message: '请选择指派对象', trigger: 'change' }]
}
}
},
created() {
this.queryProjects('')
this.queryPersonnel('')
this.searchTable()
},
methods: {
getEmptyForm() {
return {
DID: '',
项目号: '',
物料编码: '',
物料名称: '',
图号: '',
任务描述: '',
关联父件物料编码: '',
关联父件物料名称: '',
设计要求: '',
研发立项号: '',
研发目的: '',
指派对象ID: '',
指派对象: '',
assigneeIds: [],
预计开始时间: '',
预计结束时间: '',
创建日期: '',
备注: ''
}
},
buildSearchParams() {
return [
['DID', this.searchForm.did || 0],
['项目号', this.searchForm.projectNo || ''],
['物料编码', this.searchForm.itemCode || ''],
['图号', this.searchForm.drawingNo || ''],
['关联父件物料编码', this.searchForm.parentItemCode || ''],
['预计开始时间_Start', this.searchForm.planStartFrom || ''],
['预计开始时间_End', this.searchForm.planStartTo || ''],
['预计结束时间_Start', this.searchForm.planEndFrom || ''],
['预计结束时间_End', this.searchForm.planEndTo || ''],
['单据状态', this.searchForm.status || '']
]
},
async searchTable() {
this.loading = true
const data = this.CreateData('11', '设计报工_任务_查询', this.buildSearchParams())
try {
const response = await this.ExecDatabase(data)
this.tableData = response.data || []
} catch (error) {
console.error('设计任务查询失败:', error)
this.$message.error('查询失败')
} finally {
this.loading = false
}
},
openAdd() {
this.isEdit = false
this.formData = this.getEmptyForm()
this.dialogVisible = true
this.$nextTick(() => this.$refs.taskForm && this.$refs.taskForm.clearValidate())
},
openEdit(row) {
this.isEdit = true
const assigneeIds = row.指派对象ID ? String(row.指派对象ID).split(',').filter(Boolean) : []
this.formData = {
...this.getEmptyForm(),
...row,
assigneeIds,
预计开始时间: this.toDate(row.预计开始时间),
预计结束时间: this.toDate(row.预计结束时间)
}
if (row.指派对象ID || row.指派对象) {
const ids = assigneeIds
const names = row.指派对象 ? String(row.指派对象).split(',') : []
ids.forEach((id, index) => {
if (!this.personnelOptions.some(item => item.人员编号 === id)) {
this.personnelOptions.push({ 人员编号: id, 人员姓名: names[index] || id })
}
})
}
this.dialogVisible = true
this.$nextTick(() => this.$refs.taskForm && this.$refs.taskForm.clearValidate())
},
submitForm() {
this.$refs.taskForm.validate(async valid => {
if (!valid) return
this.submitLoading = true
const procedure = this.isEdit ? '设计报工_任务_编辑' : '设计报工_任务_新增'
const params = this.buildSaveParams()
const data = this.CreateData('12', procedure, params)
try {
const response = await this.ExecDatabase(data)
const result = this.getResult(response)
if (String(result.result) === '1') {
this.$message.success(result.message || '保存成功')
this.dialogVisible = false
this.searchTable()
} else {
this.$message.error(result.message || '保存失败')
}
} catch (error) {
console.error('设计任务保存失败:', error)
this.$message.error('保存失败')
} finally {
this.submitLoading = false
}
})
},
buildSaveParams() {
const params = []
if (this.isEdit) params.push(['DID', this.formData.DID || 0])
params.push(['项目号', this.formData.项目号 || ''])
params.push(['物料编码', this.formData.物料编码 || ''])
params.push(['物料名称', this.formData.物料名称 || ''])
params.push(['图号', this.formData.图号 || ''])
params.push(['任务描述', this.formData.任务描述 || ''])
params.push(['关联父件物料编码', this.formData.关联父件物料编码 || ''])
params.push(['关联父件物料名称', this.formData.关联父件物料名称 || ''])
params.push(['设计要求', this.formData.设计要求 || ''])
params.push(['研发立项号', this.formData.研发立项号 || ''])
params.push(['研发目的', this.formData.研发目的 || ''])
params.push(['指派对象ID', this.formData.指派对象ID || ''])
params.push(['指派对象', this.formData.指派对象 || ''])
params.push(['预计开始时间', this.formData.预计开始时间 || ''])
params.push(['预计结束时间', this.formData.预计结束时间 || ''])
params.push([this.isEdit ? '最后编辑人' : '创建人', this.currentUserName()])
params.push(['备注', this.formData.备注 || ''])
return params
},
deleteTask(row) {
this.$confirm(`确定删除设计任务 DID ${row.DID} 吗?已有报工记录的任务不能删除。`, '提示', { type: 'warning' })
.then(async () => {
const data = this.CreateData('12', '设计报工_任务_删除', [['DID', row.DID]])
const response = await this.ExecDatabase(data)
const result = this.getResult(response)
if (String(result.result) === '1') {
this.$message.success(result.message || '删除成功')
this.searchTable()
} else {
this.$message.error(result.message || '删除失败')
}
})
.catch(() => {})
},
async queryProjects(query) {
const data = this.CreateData('11', '设计报工_项目查询', [['过滤', query || '']])
try {
const response = await this.ExecDatabase(data)
this.projectOptions = response.data || []
} catch (error) {
this.projectOptions = []
}
},
async queryMaterialOptions(query) {
const data = this.CreateData('11', '设计报工_物料查询', [['过滤', query || '']])
try {
const response = await this.ExecDatabase(data)
this.materialOptions = response.data || []
} catch (error) {
this.materialOptions = []
}
},
async queryParentMaterialOptions(query) {
const data = this.CreateData('11', '设计报工_物料查询', [['过滤', query || '']])
try {
const response = await this.ExecDatabase(data)
this.parentMaterialOptions = response.data || []
} catch (error) {
this.parentMaterialOptions = []
}
},
async queryPersonnel(query) {
const data = this.CreateData('11', '设计报工_人员查询', [['过滤', query || '']])
try {
const response = await this.ExecDatabase(data)
this.personnelOptions = response.data || []
} catch (error) {
this.personnelOptions = []
}
},
handleMaterialChange(value) {
const selected = this.materialOptions.find(item => item.物料编码 === value)
this.formData.物料名称 = selected ? selected.物料名称 : ''
},
handleParentMaterialChange(value) {
const selected = this.parentMaterialOptions.find(item => item.物料编码 === value)
this.formData.关联父件物料名称 = selected ? selected.物料名称 : ''
},
handleAssigneeChange(values) {
const selected = this.personnelOptions.filter(item => values.includes(item.人员编号))
this.formData.指派对象ID = values.join(',')
this.formData.指派对象 = selected.map(item => item.人员姓名).join(',')
},
formatMaterialLabel(item) {
return item.物料名称 ? `${item.物料编码} | ${item.物料名称}` : item.物料编码
},
formatPersonLabel(item) {
return item.账号 ? `${item.人员姓名} | ${item.账号}` : item.人员姓名
},
getResult(response) {
const data = response && response.data
if (Array.isArray(data)) return data[0] || {}
if (data && Array.isArray(data.result)) return data.result[0] || {}
return data || {}
},
toDate(value) {
if (!value) return ''
return String(value).split(' ')[0]
},
currentUserName() {
return (this.$store && this.$store.getters && this.$store.getters.name) || ''
},
getStatusType(status) {
if (status === '已完成') return 'success'
if (status === '执行中') return 'warning'
if (status === '已结束') return 'primary'
return 'info'
}
}
}
</script>
<style scoped>
.design-task-page {
padding: 12px;
}
.search-container {
line-height: 34px;
}
.show-text {
margin-right: 4px;
}
.date-separator {
margin-right: 4px;
color: #606266;
}
.danger-action {
color: #f56c6c;
}
</style>

View File

@@ -119,13 +119,13 @@
</el-table-column>
<el-table-column label="操作" align="center" width="400px" fixed="right">
<template slot-scope="scope">
<el-button
<el-button v-if="scope.row.单据状态 != '已取消'"
type="text"
size="mini"
style="margin-right: 5px; padding:0; width:auto"
@click="receive(scope.row)">发料
</el-button>
<el-button
<el-button v-if="scope.row.单据状态 != '已取消'"
type="text"
size="mini"
style="margin-right: 5px; padding:0; width:auto"

View File

@@ -82,6 +82,14 @@
type="primary"
@click="searchTable"
>查询</el-button>
<el-button
:disabled="loading || tableData.length === 0"
icon="el-icon-download"
plain
size="small"
type="success"
@click="exportToExcel"
>导出</el-button>
</div>
<el-table
@@ -146,6 +154,8 @@
</template>
<script>
import * as XLSX from 'xlsx'
export default {
name: 'ProductPassRateWorkstation',
data() {
@@ -194,6 +204,97 @@ export default {
this.loading = false
}
},
exportToExcel() {
if (this.tableData.length === 0) {
this.$message.warning('没有数据可导出')
return
}
try {
const columns = this.getExportColumns()
const exportRows = [
columns.map(column => column.label),
...this.buildExportRows(columns)
]
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.aoa_to_sheet(exportRows)
ws['!cols'] = columns.map(column => ({ wch: column.width }))
XLSX.utils.book_append_sheet(wb, ws, '产品合格率工位')
XLSX.writeFile(wb, `产品合格率工位_${this.formatDateForFileName(new Date())}.xlsx`)
this.$message.success('导出成功')
} catch (error) {
console.error('产品合格率导出失败:', error)
this.$message.error('导出失败')
}
},
getExportColumns() {
return [
{ label: '层级', prop: '层级', width: 10 },
{ label: '关闭日期', prop: '关闭日期', width: 12 },
{ label: '生产订单号', prop: '生产订单号', width: 14 },
{ label: '物料名称', prop: '物料名称', width: 32 },
{ label: '物料编码', prop: '物料编码', width: 24 },
{ label: '计划数量', prop: '计划数量', width: 12 },
{ label: '完成数量', prop: '完成数量', width: 12 },
{ label: '不良数量', prop: '不良数量', width: 12 },
{ label: '合格率', prop: '合格率', width: 12 },
{ label: '工序', prop: '工序', width: 16 },
{ label: '工序号', prop: '工序号', width: 10 },
{ label: '工位(指派对象)', prop: '工位', width: 18 },
{ label: '明细完工数量', prop: '明细完成数量', width: 14 },
{ label: '明细不良数量', prop: '明细不良数量', width: 14 },
{ label: '明细合格率', prop: '明细合格率', width: 12 },
{ label: '检验说明', prop: '检测说明', width: 32 }
]
},
buildExportRows(columns) {
const rows = []
this.tableData.forEach(row => {
rows.push(this.formatExportRow(this.buildMainExportRow(row), columns))
if (Array.isArray(row.children)) {
row.children.forEach(child => {
rows.push(this.formatExportRow(this.buildDetailExportRow(row, child), columns))
})
}
})
return rows
},
buildMainExportRow(row) {
return {
层级: '主表',
关闭日期: this.formatDate(row.关闭日期),
生产订单号: row.生产订单号,
物料名称: row.物料名称,
物料编码: row.物料编码,
计划数量: row.计划数量,
完成数量: row.完成数量,
不良数量: row.不良数量,
合格率: this.formatRate(row.合格率)
}
},
buildDetailExportRow(row, child) {
return {
层级: '明细',
关闭日期: this.formatDate(row.关闭日期),
生产订单号: row.生产订单号,
物料名称: row.物料名称,
物料编码: row.物料编码,
工序: child.工序,
工序号: child.工序号,
工位: child.工位,
明细完成数量: child.完成数量,
明细不良数量: child.不良数量,
明细合格率: this.formatRate(child.合格率),
检测说明: child.检测说明
}
},
formatExportRow(row, columns) {
return columns.map(column => this.normalizeExportValue(row[column.prop]))
},
normalizeExportValue(value) {
if (value === null || value === undefined) return ''
return value
},
parseDetails(value) {
if (!value) return []
try {
@@ -218,6 +319,10 @@ export default {
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
formatDateForFileName(date) {
const pad = value => String(value).padStart(2, '0')
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}_${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`
},
formatDate(value) {
if (!value) return ''
return String(value).split('T')[0].split(' ')[0]

View File

@@ -17,7 +17,8 @@
placeholder="选择开始日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 150px; margin-right: 10px" />
style="width: 150px; margin-right: 10px"
/>
<span class="show-text">结束日期:</span>
<el-date-picker
v-model="searchForm.endDate"
@@ -25,9 +26,11 @@
placeholder="选择结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 150px; margin-right: 10px" />
style="width: 150px; margin-right: 10px"
/>
<el-button :loading="loading" icon="el-icon-search" plain type="primary" @click="handleSearch">查询</el-button>
<el-button :disabled="loading || tableData.length === 0" icon="el-icon-download" plain type="success" @click="exportToExcel">导出</el-button>
</div>
<el-table
@@ -41,7 +44,9 @@
default-expand-all
class="custom-tree-table"
:row-class-name="tableRowClassName"
style="width: 100%">
style="width: 100%"
@expand-change="handleExpandChange"
>
<el-table-column prop="taskDescription" label="任务描述" min-width="380" show-overflow-tooltip>
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level === 1 }">{{ scope.row.taskDescription || '' }}</span>
@@ -66,7 +71,7 @@
</template>
</el-table-column>
<el-table-column prop="auxiliaryWorkHours" label="辅工时" width="100" align="center">
<el-table-column prop="auxiliaryWorkHours" label="辅工时" width="100" align="center">
<template slot-scope="scope">
<span :class="{ 'bold-text': scope.row.level <= 2 }">{{ scope.row.auxiliaryWorkHours || '' }}</span>
</template>
@@ -129,6 +134,8 @@
</template>
<script>
import * as XLSX from 'xlsx'
export default {
name: 'SettlementWorkhours',
data() {
@@ -144,7 +151,8 @@ export default {
},
loading: false,
tableHeight: '68vh',
tableData: []
tableData: [],
collapsedRowIds: []
}
},
computed: {
@@ -175,6 +183,73 @@ export default {
handleSearch() {
this.loadData()
},
exportToExcel() {
if (this.tableData.length === 0) {
this.$message.warning('没有数据可导出')
return
}
try {
const columns = this.getExportColumns()
const exportRows = [
columns.map(column => column.label),
...this.buildExportRows(columns),
[],
[`报工工时:${this.totals.reportWorkHours} 小时 | 主辅工时:${this.totals.auxiliaryWorkHours} 小时 | 合计工时:${this.totals.totalWorkHours} 小时`]
]
const wb = XLSX.utils.book_new()
const ws = XLSX.utils.aoa_to_sheet(exportRows)
ws['!cols'] = columns.map(column => ({ wch: column.width }))
XLSX.utils.book_append_sheet(wb, ws, '结算工时')
XLSX.writeFile(wb, `结算工时_${this.formatDateForFileName(new Date())}.xlsx`)
this.$message.success('导出成功')
} catch (error) {
console.error('导出失败:', error)
this.$message.error('导出失败')
}
},
getExportColumns() {
return [
{ label: '任务描述', prop: 'taskDescription', width: 52 },
{ label: '生产订单号', prop: 'productionOrderNo', width: 14 },
{ label: '工位', prop: 'station', width: 12 },
{ label: '报工工时', prop: 'reportWorkHours', width: 12 },
{ label: '辅助工时', prop: 'auxiliaryWorkHours', width: 12 },
{ label: '报工完成数', prop: 'reportFinishQty', width: 12 },
{ label: '辅助完成数', prop: 'auxiliaryFinishQty', width: 12 },
{ label: '合计工时', prop: 'totalWorkHours', width: 12 },
{ label: '装夹时间', prop: 'clampingTime', width: 12 },
{ label: '程序时间', prop: 'programTime', width: 12 },
{ label: '结算报工单件工时', prop: 'settlementReportPieceHours', width: 18 },
{ label: '结算辅助单件工时', prop: 'settlementAuxiliaryPieceHours', width: 18 },
{ label: '操作人', prop: 'operatorNames', width: 24 }
]
},
buildExportRows(columns) {
const rows = []
this.tableData.forEach(row => {
rows.push(this.formatExportRow(row, columns))
if (Array.isArray(row.children) && this.isRowExpanded(row)) {
row.children.forEach(child => {
rows.push(this.formatExportRow(child, columns))
})
}
})
return rows
},
formatExportRow(row, columns) {
return columns.map(column => {
if (column.prop === 'taskDescription') {
const indent = row.level === 2 ? ' ' : ''
return `${indent}${row.taskDescription || ''}`
}
return row[column.prop] || ''
})
},
formatDateForFileName(date) {
const pad = value => String(value).padStart(2, '0')
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}_${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`
},
loadData() {
this.loading = true
const param = [
@@ -188,6 +263,7 @@ export default {
]
const Data = this.CreateData('11', '生产管理_结算工时_查询', param)
this.ExecDatabase(Data).then(res => {
this.collapsedRowIds = []
this.tableData = this.buildTree(res.data || [])
this.loading = false
}).catch(() => {
@@ -250,6 +326,22 @@ export default {
tableRowClassName({ row }) {
if (row.level === 1) return 'material-row'
return ''
},
handleExpandChange(row, expanded) {
if (row.level !== 1) return
const isExpanded = Array.isArray(expanded)
? expanded.some(item => item.id === row.id)
: expanded
if (isExpanded) {
this.collapsedRowIds = this.collapsedRowIds.filter(id => id !== row.id)
return
}
if (!this.collapsedRowIds.includes(row.id)) {
this.collapsedRowIds.push(row.id)
}
},
isRowExpanded(row) {
return !this.collapsedRowIds.includes(row.id)
}
}
}

View File

@@ -833,7 +833,6 @@ export default {
"QueryPath": "$crossjoin(PurchaseOrders,PurchaseOrders/DocumentLines)",
"QueryOption": "$expand=PurchaseOrders($select=DocEntry, DocNum,CardCode,CardName),PurchaseOrders/DocumentLines($select=ItemCode,LineNum,Price,U_WWOworID,U_WWOrstHS,LineStatus)&$filter=PurchaseOrders/DocEntry eq PurchaseOrders/DocumentLines/DocEntry and PurchaseOrders/DocumentLines/U_WWOworID eq "+this.receiveCheckData.计划号+""
})
if (result.success) {
if(result.data.value.length>0){
let processed = false;
@@ -842,9 +841,9 @@ export default {
console.log(this.receiveCheckData.工序名称)
console.log(element['PurchaseOrders/DocumentLines'].U_WWOrstHS)
console.log(element['PurchaseOrders/DocumentLines'].LineStatus)
console.log(this.receiveCheckData.工序名称 == element['PurchaseOrders/DocumentLines'].U_WWOrstHS & element['PurchaseOrders/DocumentLines'].LineStatus == 'O')
// console.log(this.receiveCheckData.合格数 <= element['PurchaseOrders/DocumentLines'].RemainingOpenQuantity)
if( this.receiveCheckData.工序名称 == element['PurchaseOrders/DocumentLines'].U_WWOrstHS && element['PurchaseOrders/DocumentLines'].LineStatus == 'O' ){
if( this.receiveCheckData.工序名称 == element['PurchaseOrders/DocumentLines'].U_WWOrstHS && element['PurchaseOrders/DocumentLines'].LineStatus == 'O'){
var CardCode = element.PurchaseOrders.CardCode
var CardName = element.PurchaseOrders.Cardname
var DocEntry = element.PurchaseOrders.DocEntry
@@ -927,6 +926,7 @@ export default {
this.$message.error("收检操作失败: " + (error.message || '未知错误'));
} finally {
// 无论成功或失败,都要重置提交状态
console.log(111)
this.submitLoading = false;
}
},