This commit is contained in:
gtz
2022-11-07 08:45:49 +08:00
commit 4d1231adc2
1222 changed files with 194552 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
<template>
<div class="small-table" :style="{ width: width ? width + 'px' : '500px' }">
<el-button type="primary" size="mini" round style="margin-bottom: 8px;">{{ tableName }}</el-button>
<el-table
:data="renderData"
:header-cell-style="{ background: '#FAFAFA', color: '#606266', height: '40px' }"
border
fit
highlight-current-row
>
<!-- 序号列 -->
<el-table-column
v-if="showIndex"
prop="_pageIndex"
:label="'tableHeader.index' | i18nFilter"
width="70"
align="center"
fixed
/>
<!-- 其他配置列 -->
<el-table-column
v-for="item in tableConfig"
:key="item.prop"
v-bind="item"
:align="item.align ? item.align : 'left'"
:fixed="item.isFixed ? true : false"
>
<template slot-scope="scope">
<component
:is="item.subcomponent"
v-if="item.subcomponent"
:inject-data="{ ...scope.row, ...item }"
@emitData="emitData"
/>
<span v-else>{{ scope.row[item.prop] | commonFilter(item.filter) }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { isObject, isString } from 'lodash'
export default {
name: 'SmallTable',
filters: {
commonFilter: (source, filterType = a => a) => {
return filterType(source)
}
},
props: {
tableName: {
type: String,
default: '默认设备'
},
width: {
type: Number,
default: 350
},
tableData: {
type: Array,
required: true,
validator: val => val.filter(item => !isObject(item)).length === 0
},
tableConfig: {
type: Array,
required: true,
validator: val => val.filter(item => !isString(item.prop) || !isString(item.label)).length === 0
},
showIndex: {
type: Boolean,
default: true
}
},
data() {
return {}
},
computed: {
renderData() {
return this.tableData.map((item, index) => {
return {
...item,
// _pageIndex: (this.page - 1) * this.limit + index + 1
_pageIndex: index + 1
}
})
}
}
}
</script>
<style scoped>
.small-table {
margin-top: 12px;
margin-right: 12px;
}
.d {
background-color: #f5f7fa;
}
</style>

View File

@@ -0,0 +1,348 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 工艺信息追溯 - 查看工艺详情[新页面]
@remark: use drawer or new page
-->
<template>
<div class="craft-container">
<div class="craft-container__inner">
<!-- head form -->
<small-title :size="'sm'">基本信息</small-title>
<!-- 工单名称工艺名称产品名称产品规格 -->
<el-row style="padding: 8px 0;">
<head-form :form-config="headFormConfig" />
</el-row>
<small-title :size="'sm'">工艺流程展示</small-title>
<el-row>
<div class="process-demonstration">
<el-row class="legend" style="display: flex; margin: 8px 0 16px;;">
<div class="high" style="margin-right: 16px;">
<span
style="margin-right: 2px; display: inline-block; width: 24px; height: 12px; background-color: red; border-radius: 4px;"
/>
优先
</div>
<div class="low">
<span
style="margin-right: 2px; display: inline-block; width: 24px; height: 12px; background-color: blue; border-radius: 4px;"
/>
强制
</div>
</el-row>
<ProcedureBox v-for="procedure in procedureData" :key="procedure.id" :procedure="procedure" />
</div>
</el-row>
<el-row style="margin-top: 16px;">
<el-button type="success" @click="$router.go(-1)">{{ 'btn.back' | i18nFilter }}</el-button>
</el-row>
</div>
<div class="craft-container__inner" style="margin-top: 24px;">
<small-title :size="'sm'">设备运行参数</small-title>
<!-- 表格列表 -->
<div class="tables" style="display: flex; padding: 8px 0; width: 100%; overflow-x: scroll;">
<small-table
v-for="(item, index) in deviceParamsData"
:key="index"
:table-name="item.name"
:table-config="paramsTableProps"
:table-data="item.value"
/>
</div>
</div>
<div class="craft-container__inner" style="margin-top: 24px;">
<small-title :size="'sm'">设备物料</small-title>
<!-- 表格列表 -->
<div class="tables" style="display: flex; padding: 8px 0; width: 100%; overflow-x: scroll;">
<small-table
v-for="(item, index) in deviceMaterialsData"
:key="index"
:table-name="item.name"
:table-config="materialTableProps"
:table-data="item.value"
/>
</div>
</div>
</div>
</template>
<script>
import HeadForm from '@/components/basicData/HeadForm'
import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
import SmallTable from './SmallTable.vue'
import { craftDetail } from '@/api/quality-manage/retrospect'
import newBasicData from '@/filters/newBasicData'
import ProcedureBox from './procedureBox.vue'
// import BaseTable from '@/components/BaseTable'
// import Pagination from '@/components/Pagination'
// import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
// import { timeFormatter } from '@/filters'
const paramsTableProps = [
{
prop: 'name',
label: '参数名'
},
{
prop: 'runRange',
label: '运行范围',
filter: ({ min, max }) => `${min} ~ ${max}`
},
{
prop: 'unit',
label: '单位',
filter: newBasicData('1')
}
]
const materialTableProps = [
{
prop: 'materialsName',
label: '物料名称'
},
{
prop: 'quantity',
label: '数量'
},
{
prop: 'unit',
label: '单位',
filter: newBasicData('1')
}
]
const procedureData = [
{
id: 0,
procedureName: '工序1',
equipments: [
// { name: 'Eq-001', priority: 'high' },
// { name: 'Eq-002', priority: 'medium' },
// { name: 'Eq-001', priority: 'low' },
{ name: 'Eq-001', priority: '10' }, // 8-10: high
{ name: 'Eq-002', priority: '5' }, // 4-7: medium
{ name: 'Eq-003', priority: '1' } // 1-3: low
]
},
{
id: 1,
procedureName: '工序2',
equipments: [{ name: 'Eq-001', priority: '10' }, { name: 'Eq-002', priority: '5' }]
},
{
id: 2,
procedureName: '工序3',
equipments: [{ name: 'Eq-001', priority: '10' }, { name: 'Eq-002', priority: '1' }]
},
{
id: 3,
procedureName: '工序4',
equipments: [
{ name: 'Eq-001', priority: '7' },
{ name: 'Eq-002', priority: '5' },
{ name: 'Eq-003', priority: '1' }
]
},
{
id: 4,
procedureName: '工序5',
equipments: [
{ name: 'Eq-001', priority: '10' },
{ name: 'Eq-002', priority: '6' },
{ name: 'Eq-003', priority: '6' }
]
},
{
id: 5,
procedureName: '工序6',
equipments: [
{ name: 'Eq-001', priority: '10' },
{ name: 'Eq-002', priority: '5' },
{ name: 'Eq-003', priority: '1' }
]
},
{
id: 6,
procedureName: '工序7',
equipments: [{ name: 'Eq-001', priority: '8' }]
},
{
id: 7,
procedureName: '工序8',
equipments: [{ name: 'Eq-001', priority: '10' }, { name: 'Eq-001', priority: '1' }]
},
{
id: 8,
procedureName: '工序9',
equipments: [{ name: 'Eq-002', priority: '5' }]
},
{
id: 9,
procedureName: '工序10',
equipments: [
{ name: 'Eq-001', priority: '10' },
{ name: 'Eq-002', priority: '8' },
{ name: 'Eq-003', priority: '5' },
{ name: 'Eq-004', priority: '1' }
]
}
]
export default {
components: { HeadForm, SmallTitle, SmallTable, ProcedureBox },
data() {
return {
testId: '1526377040621187074', // 测试id这个id返回的数据值几乎是全的
visible: false,
listLoading: false,
paramsTableProps,
materialTableProps,
procedureData,
deviceParamsData: [], // 设备参数列表
deviceMaterialsData: [], // 设备物料列表
listQuery: {
current: 1,
size: 20
},
pageSizes: [5, 10, 15, 20],
dataForm: {
id: null
},
headFormConfig: [
{
// 输入过滤
// label: i18n.t('module.packingManage.PackingList.orderNo'),
// placeholder: this.$t('module.packingManage.PackingList.orderNo'),
type: 'input',
label: '工单名称',
placeholder: '工单名称',
disabled: true,
param: 'workOrderName',
defaultSelect: null
},
{
type: 'input',
label: '工艺名称',
placeholder: '工艺名称',
disabled: true,
param: 'processFlowName',
defaultSelect: null
},
{
type: 'input',
label: '产品名称',
placeholder: '产品名称',
disabled: true,
param: 'productName',
defaultSelect: null
},
{
type: 'input',
label: '产品规格',
placeholder: '产品规格',
disabled: true,
param: 'productSpecifications',
defaultSelect: null
}
]
}
},
created() {
this.init()
},
methods: {
init() {
// init form
this.dataForm.id = this.$route.params.id
console.log(this.dataForm.id)
// 有可能填充其他dataForm数据从外面
// 获取当前进度下的所有发货清单
craftDetail(this.testId).then(res => {
console.log('detail res: ', res)
this.$set(this.headFormConfig[0], 'defaultSelect', res.data.workOrderName)
this.$set(this.headFormConfig[1], 'defaultSelect', res.data.processFlowName)
this.$set(this.headFormConfig[2], 'defaultSelect', res.data.productName)
this.$set(this.headFormConfig[3], 'defaultSelect', res.data.productSpecifications)
if (res.data.deviceParameters) {
// 设置设备参数列表
this.deviceParamsData = res.data.deviceParameters
.filter(item => item.value.length > 0)
.map(item => {
// 如果设备参数的value数组不为空才展示到页面
return {
name: item.name,
value: item.value.map(attr => ({
name: attr.name,
runRange: { min: attr.min, max: attr.max },
unit: attr.unit
}))
}
})
} else {
this.deviceParamsData.splice(0)
}
if (res.data.deviceMaterials) {
// 设置设备物料列表
this.deviceMaterialsData = res.data.deviceMaterials
} else {
this.deviceMaterialsData.splice(0)
}
})
// create graphs
this.visible = true
},
close() {
this.visible = false
},
confirm() {
this.close()
},
handleTableEvents({ action, data }) {
switch (action) {
case 'view-cargo-detail':
this.viewCargoDetail(data)
}
},
viewCargoDetail(data) {
this.renderPayloadDetailDialog = true
this.$nextTick(() => {
console.log('before cargo detail: ', data)
this.$refs.payloadDetail.init({ ...data, orderName: this.dataForm.orderName })
})
}
}
}
</script>
<style scoped>
.craft-container__inner {
margin: 0 16px 0;
background-color: #fff;
border-radius: 4px;
padding: 16px;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2);
overflow: auto;
}
.process-demonstration {
/* height: 300px; */
margin-top: 8px;
padding: 18px 18px 0;
width: 100%;
background-color: #f9f9f9;
}
</style>

View File

@@ -0,0 +1,111 @@
<template>
<div class="procedure-box" style="display: inline-block;">
<div class="procedure-container">
<div class="procedure">
<h3 class="procedure__name">工序: {{ procedure.procedureName }}</h3>
<ul class="procedure__equipment-list">
<li
v-for="(equipment, index) in procedure.equipments"
:key="index"
:class="calcPriorityClass(equipment.priority)"
>
设备名称: {{ equipment.name }}
</li>
</ul>
</div>
<!-- eslint-disable-next-line -->
<img :src="jianTouSvg" style="margin: 0 8px;" alt="jiantou" />
</div>
</div>
</template>
<script>
import jianTouSvg from '@/assets/img/jiantou.svg'
export default {
name: 'ProcedureBox',
props: {
procedure: {
type: Object,
required: true,
validator: obj => obj.procedureName && obj.equipments
}
},
data() {
return { jianTouSvg }
},
methods: {
calcPriorityClass(priority) {
priority = +priority
return {
'priority-low': priority > 0 && priority <= 3,
'priority-medium': priority > 3 && priority <= 7,
'priority-high': priority > 7 && priority <= 10
}
}
}
}
</script>
<style scoped>
.procedure-container {
display: flex;
align-items: center;
margin: 8px 0 24px 8px;
}
.procedure-box:last-child img {
/* background-color: red; */
display: none;
}
.procedure {
width: 245px;
height: 150px;
border-radius: 4px;
padding: 12px;
background-color: #fff;
box-shadow: 0 6px 17px 0 rgb(0 0 0 / 8%);
display: flex;
flex-direction: column;
transition: box-shadow 0.2s ease-out;
cursor: pointer;
}
.procedure:hover {
box-shadow: 1px 4px 18px 0 rgba(0, 0, 0, 0.2);
}
.procedure__name {
text-align: center;
font-size: 18px;
margin: 8px 0;
}
.procedure__equipment-list {
flex: 1 auto;
overflow-y: scroll;
margin: 0;
padding: 0;
}
.procedure__equipment-list li {
list-style: none;
text-align: center;
margin: 6px 0;
cursor: pointer;
}
.procedure__equipment-list li:hover {
cursor: pointer;
}
.priority-low {
color: rgb(194, 194, 194);
}
.priority-medium {
color: rgb(67, 117, 255);
}
.priority-high {
color: rgb(255, 92, 92);
}
</style>

View File

@@ -0,0 +1,328 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:42:50
@Description: 质量管理 - 质量追溯 - 工艺信息追溯
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
@emitFun="handleTableEvents"
>
<!-- <method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
</div>
</template>
<script>
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination'
// import SmallTitle from '@/components/BaseDrawer/components/SmallTitle'
import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
import { getCraftList, getWorkOrders } from '@/api/quality-manage/retrospect'
import newBasicData from '@/filters/newBasicData'
import { timeFormatter } from '@/filters'
// import moment from 'moment'
// import i18n from '@/lang'
// import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
// import { refineData } from '@/utils/helpers'
const topBtnConfig = [
{
type: 'add',
btnName: 'add'
}
]
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
// label: i18n.t('module.packingManage.PackingList.shelfId'),
prop: 'workOrderName',
label: '工单名称'
},
{
prop: 'workOrderCode',
label: '工单编码'
},
{
prop: 'workOrderStatus',
label: '工单状态'
},
{
prop: 'startTime',
filter: timeFormatter,
label: '开始时间'
},
{
prop: 'endTime',
filter: timeFormatter,
label: '结束时间'
},
{
prop: 'quantity',
label: '数量'
},
{
prop: 'unitId',
label: '单位',
filter: newBasicData('1')
},
{
prop: 'passRate',
label: '合格率'
},
{
prop: 'productName',
label: '产品名'
},
{
prop: 'processFlowName',
label: '工艺名称'
},
{
prop: '详情',
label: '详情',
subcomponent: commonBtn,
buttonContent: '查看工艺详情',
actionName: 'view-detail-action',
emitFullData: true
}
// {
// prop: 'endTime',
// label: '完成时间',
// filter: val => (val ? moment(val).format('YYYY-MM-DD') : '-')
// },
]
export default {
name: 'CraftRetrospect',
components: {
HeadForm,
BaseTable,
Pagination
},
data() {
return {
timePicker: '',
tableProps,
tableBtn,
topBtnConfig,
trueWidth: 200,
dataList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
// 输入过滤
// label: i18n.t('module.packingManage.PackingList.orderNo'),
// placeholder: this.$t('module.packingManage.PackingList.orderNo'),
type: 'autocomplete',
label: '工单名称',
placeholder: '工单名称',
param: 'workOrderName',
querySearch: (queryString, cb) => {
const workOrders = this.workOrderList
let result = queryString
? workOrders.filter(workOrder => workOrder.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
: workOrders
result = result.map(item => ({ value: item.name, workOrderName: item.name }))
cb(result)
}
},
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange',
valueFormat: 'yyyy-MM-dd', // 解决时间早一天问题
rangeSeparator: '-',
startPlaceholder: this.$t('module.orderManage.order.StartTime'),
endPlaceholder: this.$t('module.orderManage.order.EndTime'),
param: 'timeSlot'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {},
workOrderList: [],
fields: [
'id',
'startTime',
'endTime',
'passRate',
'productName',
'processFlowName',
'quantity',
'unitId',
'workOrderName',
'workOrderCode',
'workOrderStatus',
'productSpecifications'
]
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
this.init()
},
methods: {
handleTableEvents({ action, data }) {
let chosenAction = null
switch (action) {
case 'view-detail-action':
chosenAction = this.handleViewDetail
break
}
if (chosenAction) chosenAction(data)
},
handleViewDetail(data) {
this.addNew(data)
},
init() {
this.fetchList('workOrder').then(res => {
console.log('res', res)
if (res.data.records) {
this.workOrderList = res.data.records
} else {
this.workOrderList.splice(0)
}
})
this.getList()
},
fetchList(type) {
switch (type) {
case 'workOrder':
return getWorkOrders()
case 'craft-list': {
return getCraftList({
...this.listQuery,
workOrderName: this.headFormValue.workOrderName ? this.headFormValue.workOrderName : '',
startDate: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[0] : '',
endDate: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[1] : ''
})
}
}
},
getList() {
this.listLoading = true
this.fetchList('craft-list').then(response => {
if (response.data.records) {
this.dataList = response.data.records
} else {
this.dataList.splice(0)
}
this.total = response.data.total
this.listLoading = false
})
},
// handleClick(raw) {
// if (raw.type === 'delete') {
// this.$confirm(
// `${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.orderName}]?`,
// this.$t('module.basicData.visual.Tips'),
// {
// confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
// cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
// type: 'warning'
// }
// )
// .then(() => {
// del(raw.data.id).then(response => {
// this.$message({
// message: this.$t('module.basicData.visual.success'),
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getList()
// }
// })
// })
// })
// .catch(() => {})
// } else if (raw.type === 'edit') {
// // 编辑
// this.addNew({ deliveryId: raw.data.id, orderId: raw.data.orderId }, false)
// }
// },
btnClick(val) {
// 顶部搜索
this.headFormValue = val
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
// clickTopBtn(type) {
// if (type === 'add') {
// // 新增
// this.addNew(null, false)
// }
// },
addNew(data) {
this.$router.push({
name: 'craftDetail',
params: data
})
}
}
}
</script>

View File

@@ -0,0 +1,359 @@
<template>
<div class="custom-container">
<el-row :gutter="20" style="height: calc(100vh - 150px)">
<el-col :span="4">
<aside class="custom-container__common left-side-container">
<section class="left-side-container__title">
<span v-if="logoUrl" class="logo">
<img :src="logoUrl" alt="side container logo">
</span>
<span class="text-content">
{{ factoryName }}
</span>
</section>
<section class="left-side-container__content">
<!-- 导航栏 -->
<el-tree
class="custom-tree"
:icon-class="'el-icon-document-copy'"
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
/>
</section>
</aside>
</el-col>
<el-col :span="20">
<div class="custom-container__common right-side-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps && tableProps.length ? tableProps : [{ label: '', prop: '' }]"
:table-data="dataList"
:is-loading="listLoading"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
// 获取树形数据结构:
import { getEquipmentTree, getWorkOrders, equipParams } from '@/api/quality-manage/retrospect'
import BaseTable from '@/components/BaseTable'
// import Pagination from '@/components/Pagination'
import HeadForm from '@/components/basicData/HeadForm'
import testData from './parameter.test.data.js'
import moment from 'moment'
import writeXlsxFile from 'write-excel-file'
export default {
name: 'EquipmentRetrospectParameter',
components: { BaseTable, HeadForm },
data() {
return {
factoryName: 'xxx工厂',
logoUrl: require('../../../../assets/img/cnbm.png'),
treeData: null,
defaultProps: { label: 'label', children: 'children' },
tableProps: [],
trueWidth: 200,
dataList: [],
productLineList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
selectedEquipmentId: null,
headFormConfig: [
{
// 输入过滤
// label: i18n.t('module.packingManage.PackingList.orderNo'),
// placeholder: this.$t('module.packingManage.PackingList.orderNo'),
type: 'select',
label: '工单',
placeholder: '工单',
filterable: true,
param: 'workOrderId',
selectOptions: []
},
{
type: 'datePicker',
label: '时间段',
dateType: 'daterange',
// valueFormat: 'yyyy-MM-dd hh:mm:ss', // 解决时间早一天问题
rangeSeparator: '-',
// startPlaceholder: '开始日期',
// endPlaceholder: '结束日期',
startPlaceholder: this.$t('module.orderManage.order.StartTime'),
endPlaceholder: this.$t('module.orderManage.order.EndTime'),
param: 'timeSlot'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
},
{
type: 'button',
btnName: 'btn.export',
name: 'export',
color: 'success'
}
],
headFormValue: {},
testData
}
},
created() {
this.init()
this.fetchList('eq-tree').then(res => {
if (res.data) {
const eqTree = res.data[0] // 只会返回一条工厂数据
this.factoryName = eqTree.name
// 构造tree展示的结构
eqTree.pdlList.forEach(item => {
const treeItem = {}
treeItem.label = item.name
if (item.wsList.length) {
treeItem.children = []
item.wsList.forEach(workSection => {
const wsItem = {}
wsItem.label = workSection.name
if (workSection.eqList.length) {
wsItem.children = []
workSection.eqList.forEach(eq => {
const eqItem = {}
eqItem.label = eq.eqName
eqItem.id = eq.eqId
wsItem.children.push(eqItem)
})
}
treeItem.children.push(wsItem)
})
}
// 产线
this.productLineList.push(treeItem)
})
this.treeData = this.productLineList
}
})
this.fetchList('work-order').then(res => {
if (res.data.records) {
this.headFormConfig[0].selectOptions = res.data.records.map(item => ({ id: item.id, name: item.name }))
}
})
},
methods: {
init() {
this.productLineList.splice(0)
this.headFormConfig[0].selectOptions.splice(0)
this.factoryName = ''
// 设置静态props
this.resetTableProps()
},
fetchList(type) {
switch (type) {
case 'eq-tree':
return getEquipmentTree()
case 'work-order':
return getWorkOrders()
case 'eq-params': {
return equipParams({
...this.listQuery,
startTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[0] : '',
endTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[1] : '',
equipmentId: this.selectedEquipmentId,
workOrderId: this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
})
}
}
},
//
btnClick(val) {
this.headFormValue = val
if (this.headFormValue.btnName === 'search') {
this.getList('eq-params')
} else if (this.headFormValue.btnName === 'export') {
this.exportExcel()
}
},
resetTableProps() {
this.tableProps.splice(0)
this.tableProps = [
{
prop: 'equipmentName',
// label: i18n.t('module.packingManage.PackingList.shelfId'),
label: '设备名称',
fixed: true
}
]
},
getList() {
// 清除数据
this.dataList.splice(0)
// 清除原先的prop并设置静态props
this.resetTableProps()
// this.fetchList('eq-params').then(res => {})
setTimeout(() => {
// 创建动态列名
this.createDynamicProps(this.testData)
// 创建扁平化数据
this.flattenRes(JSON.parse(JSON.stringify(this.testData)))
// 加载数据
}, 3000)
},
// dynamic props
createDynamicProps(res) {
const names = res.data.nameData
if (names) {
// 如果数据结构正确
names
.filter(item => item.parentId === '0')
.map(item => item.name)
.forEach(name => {
this.tableProps.push({ label: name, prop: name })
})
return
}
console.log('createDynamicProps(): 数据结构不正确')
},
// 数据扁平化
flattenRes(res) {
// 注: parentId+tree+id+name 看情况叠加,一般是不会出现重复的prop,有可能多个设备有不同的参数,到时候可能就要求并集
const dataList = res.data.data
if (dataList && dataList.length > 0) {
// 如果数据结构正确
dataList.forEach(obj => {
obj.data.forEach(item => {
obj[item.dynamicName] =
item.dynamicName === 'time' ? moment(item.dynamicValue).format('YYYY-MM-DD HH:mm:ss') : item.dynamicValue
})
// 原地删除data数组
delete obj.data
})
this.dataList = dataList
}
},
async exportExcel() {
const data = []
if (this.dataList.length > 0) {
const HEADER_ROW = this.tableProps.map(item => ({ value: item.label }))
// table prop 里的 prop 是不全的,要补充
HEADER_ROW.unshift({ value: 'plc' })
HEADER_ROW.unshift({ value: '序号' })
data.push(HEADER_ROW)
this.dataList.forEach(obj => {
const DATA_ROW = []
for (const key in obj) {
DATA_ROW.push({ value: obj[key] })
}
data.push(DATA_ROW)
})
await writeXlsxFile(data, {
fileName: 'equipment_parameters_list.xlsx'
})
} else {
this.$message({
message: this.$t('module.basicData.visual.hints.searchFirst'),
type: 'error',
duration: 1500
})
}
},
handleNodeClick(data) {
if (data.id) {
this.selectedEquipmentId = data.id
}
}
}
}
</script>
<style lang="scss" scoped>
.custom-container {
height: calc(100vh - 134px);
margin: 0 16px 0;
}
.custom-container__common {
background-color: #fff;
padding: 0;
border-radius: 4px;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.2);
}
.left-side-container {
height: calc(100vh - 147px);
padding: 0;
background: #fafafa;
display: flex;
flex-direction: column;
.left-side-container__title {
display: flex;
align-items: center;
padding: 8px;
border-bottom: 1px solid rgba(204, 204, 204, 0.479);
.text-content {
font-size: 18px;
font-weight: 700;
}
}
.left-side-container__content {
flex: 1 1;
overflow-y: scroll;
}
}
.right-side-container {
height: calc(100vh - 147px);
padding: 16px;
}
.logo {
width: 36px;
height: 36px;
margin: 0 12px 0;
img {
width: 100%;
height: 100%;
}
}
.custom-tree >>> .el-tree-node {
padding: 0;
background-color: #fff;
}
.custom-tree >>> .el-tree-node__content {
height: 48px;
}
.custom-tree >>> .is-current {
border-left: 4px solid #0b58ff;
}
.custom-tree >>> .is-current .el-tree-node__content {
background: #fafafa;
}
</style>

View File

@@ -0,0 +1,191 @@
module.exports = {
code: 0,
data: {
data: [
{
data: [
{
id: 'SIMS1200time',
parentId: '0',
dynamicName: 'time',
dynamicValue: '2021-12-16T04:43:42.476500681Z'
},
{
id: 'SIMS1200DB3.0',
parentId: '0',
dynamicName: 'DB3.0',
dynamicValue: true
},
{
id: 'SIMS1200DB3.1',
parentId: '0',
dynamicName: 'DB3.1',
dynamicValue: 8
},
{
id: 'SIMS1200DB3.2',
parentId: '0',
dynamicName: 'DB3.2',
dynamicValue: 5
},
{
id: 'SIMS1200DB3.26',
parentId: '0',
dynamicName: 'DB3.26',
dynamicValue: -12.1
},
{
id: 'SIMS1200DB3.4',
parentId: '0',
dynamicName: 'DB3.4',
dynamicValue: 4294967296
},
{
id: 'SIMS1200DB3.830',
parentId: '0',
dynamicName: 'DB3.830',
dynamicValue: 'false, false'
}
],
id: '0',
plcName: 'SIMS1200',
equipmentName: '设备1'
},
{
data: [
{
id: 'SIMS1200time',
parentId: '1',
dynamicName: 'time',
dynamicValue: '2021-12-16T04:43:46.683355354Z'
},
{
id: 'SIMS1200DB3.0',
parentId: '1',
dynamicName: 'DB3.0',
dynamicValue: true
},
{
id: 'SIMS1200DB3.1',
parentId: '1',
dynamicName: 'DB3.1',
dynamicValue: 8
},
{
id: 'SIMS1200DB3.2',
parentId: '1',
dynamicName: 'DB3.2',
dynamicValue: 5
},
{
id: 'SIMS1200DB3.26',
parentId: '1',
dynamicName: 'DB3.26',
dynamicValue: -12.1
},
{
id: 'SIMS1200DB3.4',
parentId: '1',
dynamicName: 'DB3.4',
dynamicValue: 4294967296
},
{
id: 'SIMS1200DB3.830',
parentId: '1',
dynamicName: 'DB3.830',
dynamicValue: 'false, false'
}
],
id: '1',
plcName: 'SIMS1200',
equipmentName: '设备2'
}
],
nameData: [
{
name: 'time',
tree: 1,
id: 'SIMS1200time',
parentId: '0'
},
{
name: 'DB3.0',
tree: 1,
id: 'SIMS1200DB3.0',
parentId: '0'
},
{
name: 'DB3.1',
tree: 1,
id: 'SIMS1200DB3.1',
parentId: '0'
},
{
name: 'DB3.2',
tree: 1,
id: 'SIMS1200DB3.2',
parentId: '0'
},
{
name: 'DB3.26',
tree: 1,
id: 'SIMS1200DB3.26',
parentId: '0'
},
{
name: 'DB3.4',
tree: 1,
id: 'SIMS1200DB3.4',
parentId: '0'
},
{
name: 'DB3.830',
tree: 1,
id: 'SIMS1200DB3.830',
parentId: '0'
},
{
name: 'time',
tree: 1,
id: 'SIMS1200time',
parentId: '1'
},
{
name: 'DB3.0',
tree: 1,
id: 'SIMS1200DB3.0',
parentId: '1'
},
{
name: 'DB3.1',
tree: 1,
id: 'SIMS1200DB3.1',
parentId: '1'
},
{
name: 'DB3.2',
tree: 1,
id: 'SIMS1200DB3.2',
parentId: '1'
},
{
name: 'DB3.26',
tree: 1,
id: 'SIMS1200DB3.26',
parentId: '1'
},
{
name: 'DB3.4',
tree: 1,
id: 'SIMS1200DB3.4',
parentId: '1'
},
{
name: 'DB3.830',
tree: 1,
id: 'SIMS1200DB3.830',
parentId: '1'
}
]
}
}

View File

@@ -0,0 +1,7 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 设备参数追溯 - 右侧主体部分
-->

View File

@@ -0,0 +1,7 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 设备参数追溯 - 左侧树形选择部分
-->

View File

@@ -0,0 +1,76 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 设备参数追溯
-->
<template>
<el-container style="margin:30px">
<el-aside>
<!-- tips: el-tree -->
<!-- <side-tree v-if="menuList.length>0" :menu-list="menuList" @getOrganization="getOrganization" /> -->
</el-aside>
<el-main style="border:2px solid #E4E4E4;border-radius:10px;margin-left:10px">
<!-- 引入table相关组件 -->
<!-- <organization-manege v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getList" /> -->
</el-main>
</el-container>
</template>
<script>
// import sideTree from '../system-manage/sideTree'
// import organizationManege from '../system-manage/organizationManege'
// import { getOrgList } from '@/api/org'
export default {
// components: { sideTree, organizationManege },
data() {
return {
menuList: [],
addOrUpdateVisible: false,
organizationInfo: {},
defaultProps: {
children: 'children',
label: 'label'
},
listQuery: {
current: 1,
size: 500
}
}
},
created() {
this.getList()
},
methods: {
// async getList() {
// // edit here
// this.menuList.splice(0, this.menuList.length)
// const res = await getOrgList(this.listQuery)
// if (res.code === 0) {
// this.menuList = res.data.records
// }
// },
getOrganization(data) {
this.addNew(data.id)
},
// 新增 / 修改
addNew(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id)
})
}
}
}
</script>
<style scoped>
.el-container >>> .el-aside{
border:2px solid #E4E4E4;
border-radius:10px;
background-color: white;
min-height:550px;
width:30%;
padding-top:20px
}
</style>

View File

@@ -0,0 +1,452 @@
<template>
<el-dialog
:visible.sync="visible"
:title="$t('module.quality.inspection.restrospect.analysis')"
class="status-trend-dialog"
:class="{ 'show-full-class': showFull }"
@closed="close"
>
<template v-if="!showFull">
<!-- 里面要包含一个柱状图而且这个柱状图还要能通过对设备进行多选框来过滤 -->
<!-- 选定的图形地址https://echarts.apache.org/examples/zh/editor.html?c=bar-label-rotation -->
<el-row>
<el-col>
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane :label="$t('module.quality.inspection.restrospect.duration')" name="duration">
<div id="single-duration-bar" ref="single-duration-bar" style="width: 100%; height: 100%;">
<!-- 时长bar图 -->
</div>
</el-tab-pane>
<el-tab-pane :label="$t('module.quality.inspection.restrospect.ratio')" name="rate">
<div id="single-rate-pie" ref="single-rate-pie" style="width: 100%; height: 100%;">
<!-- 比例pie图 -->
</div>
</el-tab-pane>
<el-tab-pane :label="$t('module.quality.inspection.restrospect.value')" name="speed">
<div id="single-speed-chart" ref="single-speed-chart" style="width: 100%; height: 100%;">
<!-- 速度图 -->
</div>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</template>
<template v-else>
<!-- 展示所有设备对比图 -->
<el-row>
<el-col>
<div id="compare-chart" style="width: 100%;height: 500px;">
<!-- 总的对比图 -->
</div>
</el-col>
</el-row>
</template>
<el-row slot="footer">
<el-col>
<el-button type="primary" @click="close">{{ 'btn.cancel' | i18nFilter }}</el-button>
</el-col>
</el-row>
</el-dialog>
</template>
<script>
// imports
import echarts from 'echarts'
const labelOption = {
show: true,
position: 'top',
distance: 15,
align: 'center',
verticalAlign: 'middle',
formatter: '{c}%',
fontSize: 16, // 动态计算
color: '#000'
}
const barSeriesCommonConfig = {
type: 'bar',
barGap: 0,
barWidth: 30, // 动态计算
label: labelOption,
emphasis: {
focus: 'series'
}
}
const graphConfig = {
compareGraph: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['工作时长比率', '停机比率', '故障比率', '速度开动率']
},
xAxis: [
{
type: 'category',
axisTick: { show: false },
// 动态设置
// data: ['设备1', '设备2', '设备3', '设备4', '设备5']
data: []
}
],
yAxis: [
{
type: 'value',
axisLabel: {
formatter: '{value} %'
}
}
],
series: [
// 动态设置
// 模式:
// {
// name: '工作时长比率',
// ...barSeriesCommonConfig,
// data: [320, 332, 301, 334, 390]
// }
]
},
singleBarGraph: {
xAxis: {
type: 'category',
axisLabel: {
fontSize: 18
},
data: ['工作时长', '停机时长', '故障时长']
},
yAxis: {
type: 'value'
},
barWidth: 60,
series: [
{
// data: [120, 200, 150], // 需动态赋值
data: [],
type: 'bar',
label: {
show: true,
fontSize: 18,
formatter: '{c} 小时'
}
}
],
tooltip: {
show: true,
trigger: 'item'
}
},
singlePieGraph: {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'horizontal',
left: 'center',
bottom: 10
},
label: {
fontSize: 16,
formatter: '{b}\n{c}%'
},
series: [
{
name: '时长比例',
type: 'pie',
center: ['50%', '45%'],
width: '100%',
height: '100%',
radius: '60%',
data: [
// 需动态赋值
// { value: 40.79, name: '工作时长比例' },
// { value: 33.1, name: '停机比例' },
// { value: 55, name: '故障比例' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
},
singleSpeedGraph: {
title: {
// text: '实际加工速度 (约75%)', // 需动态设置
left: 'center',
bottom: 10,
textStyle: {
color: '#70a0a0', // 5c7780
fontWeight: 'lighter'
}
},
series: [
{
type: 'gauge',
progress: {
show: true,
width: 16
},
axisLine: {
lineStyle: {
width: 16
}
},
axisTick: {
show: false
},
splitLine: {
length: 10,
lineStyle: {
width: 1,
color: '#999'
}
},
axisLabel: {
distance: 25,
color: '#999',
fontSize: 12
},
anchor: {
show: true,
showAbove: true,
size: 25,
itemStyle: {
borderWidth: 10
}
},
title: {
show: false
},
detail: {
valueAnimation: true,
fontSize: 40,
offsetCenter: [0, '70%']
},
min: 0,
max: 1,
data: [
// 需动态赋值
// {
// value: 0.75
// }
]
}
]
}
}
export default {
name: 'StatusTrend',
props: {
showFull: {
type: Boolean,
default: false
}
},
data() {
return {
visible: false,
graphConfig,
labelOption,
barSeriesCommonConfig,
chart: null, // full chart
activeName: 'duration'
}
},
methods: {
init(data) {
if (this.showFull) {
// 各设备对比,此时 data 是列表
// 1. 准备数据
const eqCount = data.length
const MAX_WIDTH = 800 // 弹窗的宽度px
// 计算barWidth和fontSize
this.barSeriesCommonConfig.barWidth =
(MAX_WIDTH / eqCount - 20 * 2) / 4 /** 工作时长比率|停机比率|故障比率|速度开动率 */
this.labelOption.fontSize = Math.floor(this.barSeriesCommonConfig.barWidth / 4)
// this.labelOption.rich.nameStyle.fontSize = this.labelOption.fontSize
// console.log(this.barSeriesCommonConfig, this.labelOption)
// 设置series
this.graphConfig.compareGraph.xAxis[0].data.splice(0)
this.graphConfig.compareGraph.series.splice(0)
const workTimeArray = []
const stopTimeArray = []
const downTimeArray = []
const peEfficiencyArray = []
data.forEach(eq => {
this.graphConfig.compareGraph.xAxis[0].data.push(eq.eqName)
workTimeArray.push((eq.workRate * 100).toFixed(2))
stopTimeArray.push((eq.stopRate * 100).toFixed(2))
downTimeArray.push((eq.downRate * 100).toFixed(2))
peEfficiencyArray.push((eq.peEfficiency * 100).toFixed(2))
})
this.graphConfig.compareGraph.series.push({
name: '工作时长比率',
...this.barSeriesCommonConfig,
data: workTimeArray
})
this.graphConfig.compareGraph.series.push({
name: '停机比率',
...this.barSeriesCommonConfig,
data: stopTimeArray
})
this.graphConfig.compareGraph.series.push({
name: '故障比率',
...this.barSeriesCommonConfig,
data: downTimeArray
})
this.graphConfig.compareGraph.series.push({
name: '速度开动率',
...this.barSeriesCommonConfig,
data: peEfficiencyArray
})
// 2. 渲染图表
this.$nextTick(() => {
this.initChart('compare-chart')
})
} else {
this.activeName = 'duration'
// 单独设备,此时 data 是设备信息
// this.clearState()
// 1. 获取动态值
// duration[] 里的顺序是根据graphConfig里的对应图表配置定的
const duration = [data.workTime, data.stopTime, data.downTime]
const durationRate = [
{ value: data.workRate * 100, name: '工作时长比例' },
{ value: data.stopRate * 100, name: '停机比例' },
{ value: data.downRate * 100, name: '故障比例' }
]
const speedValue = [{ value: data.peEfficiency.toFixed(4) }]
// 2. 设置动态值
this.graphConfig.singleBarGraph.series[0].data = duration
this.graphConfig.singlePieGraph.series[0].data = durationRate
this.graphConfig.singleSpeedGraph.series[0].data = speedValue
this.graphConfig.singleSpeedGraph.title.text = `实际加工速度 (约 ${Math.ceil(
(data.peEfficiency * 100).toFixed(2)
)}%)`
// 3. 设置侦听器
this.$watch(
'activeName',
function(val, oldVal) {
if (val && val !== oldVal) {
let name = ''
switch (val) {
case 'duration':
name = 'single-duration-bar-chart'
break
case 'rate':
name = 'single-rate-pie-chart'
break
case 'speed':
name = 'single-speed-chart'
break
}
this.$nextTick(() => {
this.initChart(name)
})
}
},
{
immediate: true
}
)
}
this.visible = true
},
close() {
this.visible = false
if (this.showFull) {
setTimeout(() => {
this.$emit('clear-show-full-state') // 要求外面清除showFull状态
}, 1000)
}
// 清除状态
// this.clearState()
},
clearState() {
// console.log('clear-state')
this.graphConfig.singleBarGraph.series[0].data = [0, 0, 0]
this.graphConfig.singlePieGraph.series[0].data = [
{ value: 0, name: '工作时长比例' },
{ value: 0, name: '停机比例' },
{ value: 0, name: '故障比例' }
]
this.graphConfig.singleSpeedGraph.series[0].data = [{ value: 0 }]
this.graphConfig.singleSpeedGraph.title.text = ''
},
initChart(chartType) {
let chartId = ''
let chartOptions = null
switch (chartType) {
case 'single-duration-bar-chart':
chartId = 'single-duration-bar'
chartOptions = graphConfig.singleBarGraph
break
case 'single-rate-pie-chart':
chartId = 'single-rate-pie'
chartOptions = graphConfig.singlePieGraph
break
case 'single-speed-chart':
chartId = 'single-speed-chart'
chartOptions = graphConfig.singleSpeedGraph
break
case 'compare-chart':
chartId = 'compare-chart'
chartOptions = graphConfig.compareGraph
break
}
// console.log('创建图表 ===> ', chartId, chartOptions)
this.$nextTick(() => {
// 动态设置容器的宽高为 100%
this.chart = echarts.init(document.getElementById(chartId))
this.chart.setOption(chartOptions)
// this.chart.resize()
})
},
handleTabClick(data) {
// data 是一个 vue 组件实例
}
}
}
</script>
<style scoped>
.show-full-class >>> .el-dialog {
width: 80vw;
/* height: 70vh; */
min-width: 1000px;
/* min-height: 600px; */
}
.status-trend-dialog >>> .el-dialog .el-dialog__body {
padding: 20px;
}
.status-trend-dialog >>> .el-dialog .el-tab-pane {
width: 100%;
height: 300px;
background-color: #f5f5f5;
}
</style>

View File

@@ -0,0 +1,53 @@
module.exports = {
code: 0,
data: [
{
time: '2022-05-08T00:01:00',
factoryId: '1409788118381297666',
factoryName: '合肥新能源',
pdId: '1409788336610934786',
pdName: 'A线',
wsId: '1540159440866611201',
wsName: 'A预热',
eqId: '1540208600539242497',
eqCode: 'SB20220624000308',
eqName: 'A1预热机',
workTime: 69,
workRate: 0.47909677,
stopTime: 72.6,
stopRate: 0.50469035,
downTime: 2.3,
downRate: 0.01621285,
timeEfficiency: 0.9675153,
realYield: 0.72516286,
designYield: 1,
peEfficiency: 0.72516286,
oee: 0.70160615,
teep: 0.3475123
},
{
time: '2022-05-18T00:01:00',
factoryId: '1409788118381297111',
factoryName: '合肥新能源2',
pdId: '1409788336610933342',
pdName: 'B线',
wsId: '15401594408666112f3',
wsName: 'B预热',
eqId: '1540208600539242497',
eqCode: 'SB20220624000308',
eqName: 'B1预热机',
workTime: 33,
workRate: 0.3345,
stopTime: 72.11,
stopRate: 0.50035,
downTime: 11,
downRate: 0.33109,
timeEfficiency: 0.9675153,
realYield: 0.72516286,
designYield: 1,
peEfficiency: 0.889,
oee: 0.70160615,
teep: 0.3475123
}
]
}

View File

@@ -0,0 +1,378 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 设备状态追溯
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<p v-if="!dataList.length">{{ $t('module.basicData.visual.hints.selectWorkOrder') }}</p>
<base-table
v-else
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps ? tableProps : [{ label: '', prop: '' }]"
:table-data="dataList"
:is-loading="listLoading"
@emitFun="handleTableEvents"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<!-- <pagination
v-show="total > 0"
:total="total"
@pagination="getList()"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
/> -->
<status-trend
v-if="showGraph"
ref="addOrUpdate"
:show-full.sync="showGraphFull"
@clear-show-full-state="showGraphFull = false"
/>
</div>
</template>
<script>
import HeadForm from '@/components/basicData/HeadForm'
import { getWorkOrders, equipStatus } from '@/api/quality-manage/retrospect'
import BaseTable from '@/components/BaseTable/index-compound'
import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
// import testData from './status.test.data'
import writeXlsxFile from 'write-excel-file'
import StatusTrend from './status-trend.vue'
import { refineData } from '@/utils/helpers'
import i18n from '@/lang'
const tableProps = [
{
prop: 'eqName',
label: i18n.t('module.quality.inspection.restrospect.eqName')
// label: '设备名称'
},
{
// label: '有效时间(h)',
label: i18n.t('module.quality.inspection.restrospect.time.efficient'),
children: [
{
prop: 'workTime',
// label: '工作时长(小时)',
label: i18n.t('module.quality.inspection.restrospect.time.work'),
filter: val => `${val} ` + i18n.t('module.quality.inspection.restrospect.hour')
},
{
prop: 'workRate',
// label: '工作时长比率',
label: i18n.t('module.quality.inspection.restrospect.rate.work'),
filter: val => (val * 100).toFixed(2) + '%'
}
]
},
{
// label: '关机时间(h)',
label: i18n.t('module.quality.inspection.restrospect.time.off'),
children: [
{
prop: 'stopTime',
// label: '停机时长(小时)',
label: i18n.t('module.quality.inspection.restrospect.time.stop'),
filter: val => `${val} ` + i18n.t('module.quality.inspection.restrospect.hour')
},
{
prop: 'stopRate',
// label: '停机比率',
label: i18n.t('module.quality.inspection.restrospect.rate.stop'),
filter: val => (val * 100).toFixed(2) + '%'
}
]
},
{
// label: '中断损失',
label: i18n.t('module.quality.inspection.restrospect.lost'),
children: [
{
prop: 'downTime',
// label: '故障时长(小时)',
label: i18n.t('module.quality.inspection.restrospect.time.down'),
filter: val => `${val} 小时`
},
{
prop: 'downRate',
// label: '故障比率',
label: i18n.t('module.quality.inspection.restrospect.rate.down'),
filter: val => (val * 100).toFixed(2) + '%'
}
]
},
{
// label: '速度损失',
label: i18n.t('module.quality.inspection.restrospect.speedLost'),
children: [
{
prop: 'realYield',
// label: '实际加工速度',
label: i18n.t('module.quality.inspection.restrospect.speed.real'),
filter: val => `${val} /` + i18n.t('module.quality.inspection.restrospect.hour')
}, // 片/小时
{
prop: 'designYield',
// label: '理论加工速度',
label: i18n.t('module.quality.inspection.restrospect.speed.thero'),
filter: val => `${val} /` + i18n.t('module.quality.inspection.restrospect.hour')
},
{
prop: 'peEfficiency',
// label: '速度开动率',
label: i18n.t('module.quality.inspection.restrospect.speed.rate'),
filter: val => (val * 100).toFixed(2) + '%'
}
]
},
// {
// prop: 'goodRate',
// label: '良品率' // 暂时先隐藏
// },
{
// label: '操作',
label: i18n.t('module.quality.inspection.restrospect.operate'),
subcomponent: commonBtn,
emitFullData: true,
// buttonContent: '切换图形',
buttonContent: i18n.t('module.quality.inspection.restrospect.toggle'),
actionName: 'toggle-graph'
}
]
export default {
name: 'EquipmentStatusRetrospect',
components: {
HeadForm,
BaseTable,
StatusTrend
// Pagination
// MethodBtn
},
data() {
return {
timePicker: '',
tableProps,
// tableBtn,
// topBtnConfig,
trueWidth: 200,
dataList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
showGraph: false,
showGraphFull: false,
headFormConfig: [
{
type: 'select',
label: i18n.t('module.quality.inspection.orderNameHead'),
placeholder: this.$t('module.quality.inspection.orderName'),
// label: '工单名(必填)',
// placeholder: '工单名',
filterable: true,
param: 'workOrderId',
selectOptions: []
},
{
type: 'datePicker',
label: i18n.t('module.quality.inspection.deep.timerange'),
dateType: 'daterange',
// valueFormat: 'yyyy-MM-dd', // 解决时间早一天问题
rangeSeparator: '-',
startPlaceholder: i18n.t('module.quality.inspection.deep.startTime'),
endPlaceholder: i18n.t('module.quality.inspection.deep.endTime'),
param: 'timeSlot'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
},
{
type: 'button',
btnName: 'btn.export',
name: 'export',
color: 'success'
},
{
type: 'button',
btnName: i18n.t('module.quality.inspection.restrospect.analysis'),
name: 'analyze',
color: 'success'
}
],
headFormValue: {}
}
},
created() {
this.fetchList('work-order').then(res => {
// console.log('fetch list workorder: ', res)
if (res.data.records) {
this.headFormConfig[0].selectOptions = res.data.records.map(item => ({ id: item.id, name: item.name }))
}
})
// this.getList()
},
methods: {
handleTableEvents({ action, data }) {
let chosenAction = null
switch (action) {
case 'toggle-graph':
chosenAction = this.handleToggleGraph
break
}
if (chosenAction) chosenAction(false, data)
},
handleToggleGraph(showFull, data) {
if (showFull) {
this.showGraphFull = true
data = this.dataList // 如果是所有设备一起展示的话就拦截data改为dataList
}
this.showGraph = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(data)
})
},
fetchList(type) {
switch (type) {
case 'work-order':
return getWorkOrders()
case 'eq-status': {
// console.log('before request: ', {
// ...this.listQuery,
// startTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[0] : '',
// endTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[1] : '',
// equipmentId: this.selectedEquipmentId,
// workOrderId: this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
// })
return equipStatus({
...this.listQuery,
startTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[0] : '',
endTime: this.headFormValue.timeSlot ? this.headFormValue.timeSlot[1] : '',
equipmentId: this.selectedEquipmentId,
workOrderId: this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
})
}
}
},
getList() {
// this.listLoading = true
this.fetchList('eq-status').then(res => {
// console.log('eq-status --- res: ', res)
if (res.data) {
this.dataList = res.data
} else {
this.dataList.splice(0)
this.$message({
message: i18n.t('module.quality.inspection.hint.noData'),
type: 'info',
duration: 1500
})
}
})
// setTimeout(() => {
// this.dataList = testData.data
// console.log('data list: ', this.dataList)
// // this.listLoading = false
// }, 2000)
},
btnClick(val) {
// 顶部搜索
this.headFormValue = val
if (this.headFormValue.btnName === 'search') {
this.getList()
} else if (this.headFormValue.btnName === 'export') {
this.exportExcel()
} else if (this.headFormValue.btnName === 'analyze') {
this.handleToggleGraph(true, null)
}
},
async exportExcel() {
const data = []
const HEADER_ROW = []
function setRowItem(array) {
array.map(item => {
if (item.children) {
setRowItem(item.children)
} else {
HEADER_ROW.push({ value: item.label })
}
})
}
if (this.dataList.length > 0) {
setRowItem(this.tableProps)
HEADER_ROW.pop() // 把'操作'列pop掉
HEADER_ROW.unshift({ value: i18n.t('module.quality.inspection.restrospect.id') })
data.push(HEADER_ROW)
this.dataList.forEach((obj, index) => {
const DATA_ROW = []
const filterdData = refineData(obj, [
'eqName',
'workTime',
'workRate',
'stopTime',
'stopRate',
'downTime',
'downRate',
'realYield',
'designYield',
'peEfficiency'
])
DATA_ROW.push({ value: index + 1 }) // 序号从1开始
for (const key in filterdData) {
// 对比率类数据进行转换一下
if (
(key === 'workRate' || key === 'stopRate' || key === 'downRate' || key === 'peEfficiency') &&
filterdData[key]
) {
// console.log('in push : ', key, filterdData[key])
DATA_ROW.push({ value: filterdData[key] * 100 + '%' })
} else {
DATA_ROW.push({ value: filterdData[key] })
}
}
data.push(DATA_ROW)
})
await writeXlsxFile(data, {
fileName: 'equipment_status_list.xlsx'
})
} else {
this.$message({
message: this.$t('module.basicData.visual.hints.searchFirst'),
type: 'warning',
duration: 1500
})
}
}
}
}
</script>

View File

@@ -0,0 +1,254 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 物料信息追溯 - 查看详情
-->
<template>
<el-drawer :visible.sync="visible" :show-close="false" :wrapper-closable="false" class="drawer" size="60%">
<small-title slot="title" :no-padding="true">
<!-- {{ isdetail ? 'btn.detail' : isedit ? 'btn.edit' : 'btn.add' | i18nFilter }} -->
{{ $t('module.quality.inspection.material.detail') }}
</small-title>
<div class="content">
<div class="visual-part">
<!-- form -->
<el-row>
<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
<el-row :gutter="20">
<!-- 工单名称 -->
<el-col :span="8">
<el-form-item :label="$t('module.quality.inspection.orderName')" prop="workOrderName">
<el-input
v-model="dataForm.workOrderName"
disabled
:label="$t('module.quality.inspection.orderName')"
:placeholder="$t('module.quality.inspection.orderName')"
/>
</el-form-item>
</el-col>
<!-- 物料名称 -->
<el-col :span="8">
<el-form-item :label="$t('module.quality.inspection.material.name')" prop="materialName">
<el-input
v-model="dataForm.materialName"
disabled
:label="$t('module.quality.inspection.material.name')"
:placeholder="$t('module.quality.inspection.material.name')"
/>
</el-form-item>
</el-col>
<!-- 物料编码 -->
<el-col :span="8">
<el-form-item :label="$t('module.quality.inspection.material.code')" prop="materialCode">
<el-input
v-model="dataForm.materialCode"
disabled
:label="$t('module.quality.inspection.material.code')"
:placeholder="$t('module.quality.inspection.material.code')"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-row>
<small-title style="margin-top: 16px; padding-left: 8px;">
{{ $t('module.quality.inspection.detailList') }}
</small-title>
<div class="attr-list">
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
:page-sizes="pageSizes"
@pagination="getList()"
/>
</div>
</div>
<div style="position: absolute; bottom: 24px; right: 24px;">
<el-button @click="close">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="confirm">{{ 'btn.confirm' | i18nFilter }}</el-button>
</div>
</div>
</el-drawer>
</template>
<script>
import BaseTable from '@/components/BaseTable'
import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
import Pagination from '@/components/Pagination'
import newBasicData from '@/filters/newBasicData'
import { timeFormatter } from '@/filters'
import { getMaterialConsumeDetail } from '@/api/quality-manage/retrospect'
import i18n from '@/lang'
const tableProps = [
// {
// prop: 'materialDate',
// label: i18n.t('module.quality.inspection.materialDate')
// // label: '批次号'
// },
{
prop: 'useTime',
label: i18n.t('module.quality.inspection.rawMaterial.applyTime'),
// label: '开始使用时间',
filter: timeFormatter
},
{
prop: 'user',
label: i18n.t('module.quality.inspection.material.user')
// label: '使用人'
},
{
prop: 'quantity',
label: i18n.t('module.quality.inspection.material.quantity')
// label: '数量'
},
{
prop: 'unit',
label: i18n.t('module.quality.inspection.unit'),
// label: '单位',
filter: newBasicData('1')
},
{
prop: 'remark',
label: i18n.t('module.quality.inspection.remark')
// label: '说明'
}
]
export default {
components: { BaseTable, SmallTitle, Pagination },
data() {
return {
visible: false,
listLoading: false,
tableProps,
listQuery: {
current: 1,
size: 5
},
total: 0,
pageSizes: [5, 10, 15, 20],
dataForm: {
workOrderName: '',
materialName: null,
materialCode: ''
},
dataFormRules: {},
dataList: [],
currentWorkOrderId: null
}
},
methods: {
init(data) {
this.total = 0
this.dataList.splice(0)
this.dataForm = {
workOrderName: '',
materialName: null,
materialCode: ''
}
this.currentWorkOrderId = data.workOrderId || null
this.currentMaterialId = data.materialId || null
this.getList()
this.visible = true
},
getList() {
getMaterialConsumeDetail({
...this.listQuery,
workOrderId: this.currentWorkOrderId,
materialId: this.currentMaterialId
}).then(res => {
if (res.data) {
// 填充表头
const { workOrderName, name, code } = res.data
this.dataForm.workOrderName = workOrderName
this.dataForm.materialName = name
this.dataForm.materialCode = code
if (res.data.detVos && res.data.detVos.records) {
// 获得列表数据
this.dataList = res.data.detVos.records
this.total = res.data.detVos.total
} else {
this.dataList.splice(0)
this.total = 0
}
} else {
this.dataForm = {
workOrderName: '',
materialName: '',
materialCode: ''
}
this.dataList.splice(0)
this.total = 0
}
})
},
close() {
this.visible = false
},
confirm() {
this.close()
}
}
}
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 30px;
}
.drawer >>> .content {
padding: 0 24px 30px;
display: flex;
flex-direction: column;
height: 100%;
}
.drawer >>> .visual-part {
flex: 1 auto;
max-height: 76vh;
overflow: hidden;
overflow-y: scroll;
padding-right: 10px; /* 调整滚动条样式 */
}
.drawer >>> .el-form,
.drawer >>> .attr-list {
padding: 0 16px;
}
</style>

View File

@@ -0,0 +1,247 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 物料信息追溯
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<p v-if="!dataList.length">{{ $t('module.basicData.visual.hints.selectWorkOrder') }}</p>
<base-table
v-else
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
@emitFun="handleTableEvents"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<material-detail v-if="addOrUpdateVisible" ref="addOrUpdate" />
</div>
</template>
<script>
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination'
import HeadForm from '@/components/basicData/HeadForm'
import newBasicData from '@/filters/newBasicData'
import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
import MaterialDetail from './components/detail.vue'
import i18n from '@/lang'
import { getMaterialConsumeList, getWorkOrders } from '@/api/quality-manage/retrospect'
const tableProps = [
{
prop: 'name',
label: i18n.t('module.quality.inspection.material.name')
// label: '物料名称'
},
{
prop: 'prescribedUsage',
label: i18n.t('module.quality.inspection.material.usage')
// label: '规定使用数量'
},
{
prop: 'actualUsage',
label: i18n.t('module.quality.inspection.material.actualuse')
// label: '实际使用'
},
{
prop: 'unit',
label: i18n.t('module.quality.inspection.unit'),
// label: '单位',
filter: newBasicData('1')
},
{
prop: '详情',
label: i18n.t('module.quality.inspection.detail'),
// label: '详情',
subcomponent: commonBtn,
buttonContent: i18n.t('module.quality.inspection.viewDetail'),
// buttonContent: '查看详情',
actionName: 'view-detail-action',
emitFullData: true
}
]
export default {
name: 'MaterialRetrospect',
components: {
HeadForm,
BaseTable,
MaterialDetail,
Pagination
},
data() {
return {
// tableBtn,
// topBtnConfig,
tableProps,
trueWidth: 200,
dataList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
// 输入过滤
label: i18n.t('module.quality.inspection.orderNameHead'),
placeholder: this.$t('module.quality.inspection.orderName'),
type: 'select',
// label: '工单名称(必填)',
// placeholder: '工单名称',
filterable: true,
param: 'workOrderId'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {},
workOrderList: []
}
},
created() {
this.init()
},
methods: {
init() {
this.prepareHeadFormData()
},
prepareHeadFormData() {
this.fetchList('workOrder').then(res => {
if (res.data.records) {
this.workOrderList = res.data.records
} else {
this.workOrderList.splice(0)
}
this.setHeadForm('workOrderId', 'selectOptions', this.workOrderList)
})
},
setHeadForm(field, property, value) {
const idx = this.headFormConfig.findIndex(item => item.param === field)
this.$set(this.headFormConfig[idx], property, value)
},
handleTableEvents({ action, data }) {
let chosenAction = null
switch (action) {
case 'view-detail-action':
chosenAction = this.handleViewDetail
break
}
if (chosenAction) chosenAction(data)
},
handleViewDetail(data) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(data)
})
},
btnClick(val) {
// 顶部搜索
this.headFormValue = val
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
fetchList(type) {
switch (type) {
case 'workOrder':
return getWorkOrders()
case 'dataList': {
const id = this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
return getMaterialConsumeList({ ...this.listQuery, id })
}
}
},
getList() {
// this.listLoading = true
this.fetchList('dataList').then(res => {
if (res.data.records) {
this.dataList = res.data.records
} else {
this.dataList.splice(0)
this.$message({
message: this.$t('module.quality.inspection.hint.noData'),
type: 'error',
duration: 1500
})
}
this.total = res.data.total
// this.listLoading = false
})
}
// handleClick(raw) {
// if (raw.type === 'delete') {
// this.$confirm(
// `${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.orderName}]?`,
// this.$t('module.basicData.visual.Tips'),
// {
// confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
// cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
// type: 'warning'
// }
// )
// .then(() => {
// del(raw.data.id).then(response => {
// this.$message({
// message: this.$t('module.basicData.visual.success'),
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getList()
// }
// })
// })
// })
// .catch(() => {})
// } else if (raw.type === 'edit') {
// // 编辑
// this.addNew(raw.data.id)
// }
// },
// clickTopBtn(type) {
// if (type === 'add') {
// // 新增
// this.addNew()
// }
// },
// addNew(id) {
// this.addOrUpdateVisible = true
// this.$nextTick(() => {
// this.$refs.addOrUpdate.init(id)
// })
// }
}
}
</script>

View File

@@ -0,0 +1,233 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 原片原料信息追溯
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<p v-if="!dataList.length">{{ $t('module.basicData.visual.hints.selectWorkOrder') }}</p>
<base-table
v-else
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
</div>
</template>
<script>
import BaseTable from '@/components/BaseTable'
import HeadForm from '@/components/basicData/HeadForm'
import newBasicData from '@/filters/newBasicData'
import { getWorkOrders, raw } from '@/api/quality-manage/retrospect'
import Pagination from '@/components/Pagination'
import { timeFormatter } from '@/filters'
import i18n from '@/lang'
// import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
const tableProps = [
{
prop: 'dateName', // 批次
label: i18n.t('module.quality.inspection.rawMaterial.name')
// label: '原片/原料'
},
{
prop: 'createTime',
// label: '开始使用时间',
label: i18n.t('module.quality.inspection.rawMaterial.applyTime'),
filter: timeFormatter
},
{
prop: 'operator',
// label: '操作员'
label: i18n.t('module.quality.inspection.rawMaterial.operator')
},
{
prop: 'quantity',
// label: '数量'
label: i18n.t('module.quality.inspection.rawMaterial.quantity')
},
{
prop: 'unitCode', // 数据字典
// label: '单位',
label: i18n.t('module.quality.inspection.unit'),
filter: newBasicData('1')
},
{
prop: 'specification', // 数据字典
label: i18n.t('module.quality.inspection.rawMaterial.spec'),
// label: '规格',
filter: newBasicData('1528564570336985090')
},
{
prop: 'explanation',
label: i18n.t('module.quality.inspection.explain')
// label: '说明'
}
]
export default {
name: 'RawMaterialRetrospect',
components: {
HeadForm,
BaseTable,
Pagination
},
data() {
return {
// tableBtn,
// topBtnConfig,
tableProps,
trueWidth: 200,
dataList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
// 输入过滤
type: 'select',
// label: i18n.t('module.packingManage.PackingList.orderNo'),
// placeholder: this.$t('module.packingManage.PackingList.orderNo'),
label: this.$t('module.quality.inspection.orderNameHead'),
placeholder: this.$t('module.basicData.visual.hints.selectWorkOrder'),
param: 'workOrderId'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {},
workOrderList: []
}
},
created() {
this.init()
},
methods: {
init() {
this.fetchList('workOrder').then(res => {
if (res.data.records) {
this.workOrderList = res.data.records
} else {
this.workOrderList.splice(0)
}
this.setHeadForm('workOrderId', 'selectOptions', this.workOrderList)
})
},
setHeadForm(field, property, value) {
const idx = this.headFormConfig.findIndex(item => item.param === field)
this.$set(this.headFormConfig[idx], property, value)
},
btnClick(val) {
// 顶部搜索
this.headFormValue = val
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
fetchList(type) {
// 相对来说底层的代码
switch (type) {
case 'workOrder':
return getWorkOrders()
case 'dataList': {
// workOrderId 必填
const workOrderId = this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
return raw({ ...this.listQuery, workOrderId })
}
}
},
getList() {
// this.listLoading = true
this.fetchList('dataList').then(res => {
if (res.data.records) {
this.dataList = res.data.records
} else {
this.dataList.splice(0)
this.$message({
message: this.$t('module.quality.inspection.hint.noData'),
type: 'info',
duration: 1500
})
}
this.total = res.data.total
// this.listLoading = false
})
}
// handleClick(raw) {
// if (raw.type === 'delete') {
// this.$confirm(
// `${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.orderName}]?`,
// this.$t('module.basicData.visual.Tips'),
// {
// confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
// cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
// type: 'warning'
// }
// )
// .then(() => {
// del(raw.data.id).then(response => {
// this.$message({
// message: this.$t('module.basicData.visual.success'),
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getList()
// }
// })
// })
// })
// .catch(() => {})
// } else if (raw.type === 'edit') {
// // 编辑
// this.addNew(raw.data.id)
// }
// },
// clickTopBtn(type) {
// if (type === 'add') {
// // 新增
// this.addNew()
// }
// },
// addNew(id) {
// this.addOrUpdateVisible = true
// this.$nextTick(() => {
// this.$refs.addOrUpdate.init(id)
// })
// }
}
}
</script>

View File

@@ -0,0 +1,228 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 执行班组管理 - 查看详情
-->
<template>
<el-drawer :visible.sync="visible" :show-close="false" :wrapper-closable="false" class="drawer" size="60%">
<small-title slot="title" :no-padding="true">
<!-- {{ isdetail ? 'btn.detail' : isedit ? 'btn.edit' : 'btn.add' | i18nFilter }} -->
{{ $t('module.quality.inspection.team.detail') }}
</small-title>
<div class="content">
<div class="visual-part">
<!-- form -->
<el-row>
<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
<el-row :gutter="20">
<!-- 工单名称 -->
<el-col :span="6">
<el-form-item :label="$t('module.quality.inspection.orderName')" prop="workOrderName">
<el-input
v-model="dataForm.workOrderName"
disabled
:label="$t('module.quality.inspection.orderName')"
:placeholder="$t('module.quality.inspection.orderName')"
/>
</el-form-item>
</el-col>
<!-- 班组名称 -->
<el-col :span="6">
<el-form-item :label="$t('module.quality.inspection.team.name')" prop="teamName">
<el-input
v-model="dataForm.teamName"
disabled
:label="$t('module.quality.inspection.team.name')"
:placeholder="''"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-row>
<small-title style="margin-top: 16px; padding-left: 8px;">
{{ $t('module.quality.inspection.detailList') }}
</small-title>
<div class="attr-list">
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
:page-sizes="pageSizes"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
:page-sizes="[5, 10, 15, 20]"
@pagination="getList()"
/>
</div>
</div>
<div style="position: absolute; bottom: 24px; right: 24px;">
<el-button @click="close">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="confirm">{{ 'btn.confirm' | i18nFilter }}</el-button>
</div>
</div>
</el-drawer>
</template>
<script>
import BaseTable from '@/components/BaseTable'
import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
import Pagination from '@/components/Pagination'
import i18n from '@/lang'
import { timeFormatter } from '@/filters'
import { getTeamDetail } from '@/api/quality-manage/retrospect'
const tableProps = [
{
prop: 'startTime',
label: i18n.t('module.quality.inspection.launchTime'),
// label: '开始时间',
filter: timeFormatter
},
{
prop: 'endTime',
label: i18n.t('module.quality.inspection.terminateTime'),
// label: '结束时间',
filter: timeFormatter
},
{
prop: 'personNum',
label: i18n.t('module.quality.inspection.team.num')
// label: '人数'
},
{
prop: 'workDuration',
label: i18n.t('module.quality.inspection.restrospect.time.work'),
// label: '工作时长(h)',
filter: val => val + ' ' + i18n.t('module.quality.inspection.restrospect.hour')
}
]
export default {
name: 'TeamRetrospectDetail',
components: { BaseTable, SmallTitle, Pagination },
data() {
return {
visible: false,
listLoading: false,
tableProps,
listQuery: {
current: 1,
size: 5
},
listQueryExtra: {
teamId: null,
workOrderId: null
},
total: 0,
pageSizes: [5, 10, 15, 20],
dataForm: {
id: null,
workOrderName: '',
teamName: ''
},
dataFormRules: {},
dataList: []
}
},
methods: {
init(data) {
this.listQueryExtra = {
teamId: null,
workOrderId: null
}
// 设置头部表单的工单名称和班组名称
this.dataForm.workOrderName = data.workOrderName
this.dataForm.teamName = data.teamName
// 设置查询条件里的工单id
this.listQueryExtra.workOrderId = data.workOrderId
// 设置查询条件里的 teamId
this.listQueryExtra.teamId = data.teamId
this.getList()
this.visible = true
},
getList() {
const queryCondition = { ...this.listQuery }
if (this.listQueryExtra.teamId) queryCondition.teamId = this.listQueryExtra.teamId
if (this.listQueryExtra.workOrderId) queryCondition.workOrderId = this.listQueryExtra.workOrderId
getTeamDetail(queryCondition).then(res => {
if (res.data.records && res.data.records.length > 0) {
this.dataList = res.data.records
} else {
this.dataList.splice(0)
this.total = 0
this.listQuery = {
current: 1,
size: 5
}
}
// 注意此处的接口也没有分页处理
this.total = res.data.total
// this.total = res.data.total
})
},
close() {
this.visible = false
},
confirm() {
this.close()
}
}
}
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 30px;
}
.drawer >>> .content {
padding: 0 24px 30px;
display: flex;
flex-direction: column;
height: 100%;
}
.drawer >>> .visual-part {
flex: 1 auto;
max-height: 76vh;
overflow: hidden;
overflow-y: scroll;
padding-right: 10px; /* 调整滚动条样式 */
}
.drawer >>> .el-form,
.drawer >>> .attr-list {
padding: 0 16px;
}
</style>

View File

@@ -0,0 +1,267 @@
<!--
@Author: lb
@Date: 2022-05-27 11:00:00
@LastEditors: lb
@LastEditTime: 2022-05-27 11:00:00
@Description: 质量管理 - 质量追溯 - 执行班组管理
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<p v-if="!dataList.length">{{ $t('module.basicData.visual.hints.selectWorkOrder') }}</p>
<base-table
v-else
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="dataList"
:is-loading="listLoading"
@emitFun="handleTableEvents"
>
<!-- <method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" /> -->
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<team-detail v-if="addOrUpdateVisible" ref="addOrUpdate" />
<!-- <team-detail v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="xx" /> -->
</div>
</template>
<script>
import BaseTable from '@/components/BaseTable'
import HeadForm from '@/components/basicData/HeadForm'
import Pagination from '@/components/Pagination'
import commonBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
import TeamDetail from './components/detail.vue'
import { getTeamList, getWorkOrders } from '@/api/quality-manage/retrospect'
import i18n from '@/lang'
const tableProps = [
{
prop: 'teamName',
label: i18n.t('module.quality.inspection.team.name')
// label: '班组名称'
},
{
prop: 'teamLeader',
label: i18n.t('module.quality.inspection.team.leader')
// label: '班组长'
},
{
prop: 'personNum',
label: i18n.t('module.quality.inspection.team.num')
// label: '人数'
},
{
prop: 'count',
label: i18n.t('module.quality.inspection.team.cnt')
// label: '上班次数'
},
{
prop: '详情',
label: i18n.t('module.quality.inspection.detail'),
// label: '详情',
subcomponent: commonBtn,
buttonContent: i18n.t('module.quality.inspection.viewDetail'),
// buttonContent: '查看详情',
actionName: 'view-detail-action',
emitFullData: true
}
]
export default {
name: 'TeamRetrospect',
components: {
HeadForm,
BaseTable,
TeamDetail,
Pagination
},
data() {
return {
// tableBtn,
// topBtnConfig,
tableProps,
trueWidth: 200,
dataList: [],
total: 0,
listLoading: false,
addOrUpdateVisible: false,
listQuery: {
current: 1,
size: 20
},
currentOrderName: '',
headFormConfig: [
{
// 输入过滤
label: i18n.t('module.quality.inspection.orderNameHead'),
placeholder: this.$t('module.quality.inspection.orderName'),
type: 'select',
// label: '工单名称(必填)',
// placeholder: '工单名称',
filterable: true,
param: 'workOrderId'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {},
workOrderList: []
}
},
created() {
this.init()
},
methods: {
init() {
this.currentOrderName = ''
this.prepareHeadFormData()
},
prepareHeadFormData() {
this.fetchList('workOrder').then(res => {
if (res.data.records) {
this.workOrderList = res.data.records
} else {
this.workOrderList.splice(0)
}
this.setHeadForm('workOrderId', 'selectOptions', this.workOrderList)
})
},
setHeadForm(field, property, value) {
const idx = this.headFormConfig.findIndex(item => item.param === field)
this.$set(this.headFormConfig[idx], property, value)
},
handleTableEvents({ action, data }) {
let chosenAction = null
switch (action) {
case 'view-detail-action':
chosenAction = this.handleViewDetail
break
}
if (chosenAction) chosenAction(data)
},
handleViewDetail(data) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init({ ...data, workOrderName: this.currentOrderName })
})
},
btnClick(val) {
// 顶部搜索
this.headFormValue = val
// 在本地利用条件找到工单名称
if (val.workOrderId) {
const workOrder = this.workOrderList.find(item => item.id.toString() === val.workOrderId.toString())
if (workOrder) {
this.currentOrderName = workOrder.name
} else {
this.currentOrderName = ''
}
}
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
fetchList(type) {
switch (type) {
case 'workOrder':
return getWorkOrders()
}
},
getList() {
// this.listLoading = true
const workOrderId = this.headFormValue.workOrderId ? this.headFormValue.workOrderId : null
if (!workOrderId) {
this.$message({
message: this.$t('module.quality.inspection.hint.noWorkOrder'),
type: 'warning',
duration: 1500
})
return
}
getTeamList({ ...this.listQuery, workOrderId }).then(res => {
if (res.data.length > 0) {
this.dataList = res.data
} else {
this.dataList.splice(0)
this.$message({
message: this.$t('module.quality.inspection.hint.noData'),
type: 'info',
duration: 1500
})
}
this.total = res.data.length
// this.total = res.data.total
// this.listLoading = false
})
}
// handleClick(raw) {
// if (raw.type === 'delete') {
// this.$confirm(
// `${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.orderName}]?`,
// this.$t('module.basicData.visual.Tips'),
// {
// confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
// cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
// type: 'warning'
// }
// )
// .then(() => {
// del(raw.data.id).then(response => {
// this.$message({
// message: this.$t('module.basicData.visual.success'),
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getList()
// }
// })
// })
// })
// .catch(() => {})
// } else if (raw.type === 'edit') {
// // 编辑
// this.addNew(raw.data.id)
// }
// },
// clickTopBtn(type) {
// if (type === 'add') {
// // 新增
// this.addNew()
// }
// },
// addNew(id) {
// this.addOrUpdateVisible = true
// this.$nextTick(() => {
// this.$refs.addOrUpdate.init(id)
// })
// }
}
}
</script>