622 lines
17 KiB
Vue
622 lines
17 KiB
Vue
<script setup lang="ts">
|
||
import { toRaw, ref, computed } from 'vue'
|
||
import { formatDate } from '@/utils/index'
|
||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||
import { useLoginStore } from '@/stores/modules/login'
|
||
import { getTaskRepotPageAPI, getTaskDetailAPI, postOperateAPI } from '@/services/productionReport'
|
||
const popup = ref<UniHelper.UniPopupInstance>()
|
||
|
||
const userStore = useLoginStore()
|
||
const dictInfo = userStore?.dictInfo || []
|
||
const unitDictData = dictInfo.filter(e => e.dictType == 'heli_material_unit') || []
|
||
const userId = userStore.userInfo.userId
|
||
|
||
const isShowStart = computed(() => {
|
||
let flag = true
|
||
if (historyList.value.length) {
|
||
const obj = historyList.value[0]
|
||
if (!obj?.endTime) {
|
||
flag = false
|
||
}
|
||
}
|
||
return flag
|
||
})
|
||
const isShowEnd = computed(() => {
|
||
let flag = true
|
||
if (historyList.value.length) {
|
||
const obj = historyList.value[0]
|
||
if (obj?.endTime) {
|
||
flag = false
|
||
}
|
||
} else {
|
||
flag = false
|
||
}
|
||
return flag
|
||
})
|
||
const amount = ref(null)
|
||
const workTime = ref(null)
|
||
// 详情数据
|
||
const detailInfo = ref({})
|
||
let isLoading = ref(false)
|
||
const historyList = ref([])
|
||
const formObj = ref({})
|
||
// 历史明细
|
||
const getData = async () => {
|
||
// 发送请求
|
||
// isLoading.value = true
|
||
const params = {
|
||
pageNo: 1,
|
||
integerpageSize: 5,
|
||
owner: userId,
|
||
dispatchDetailId: detailInfo.value.id,
|
||
}
|
||
const data = await getTaskRepotPageAPI(params)
|
||
data.list.forEach((e) => {
|
||
e.startTimeStr = e.startTime && formatDate(e.startTime, 'YYYY-MM-DD HH:mm')
|
||
e.endTimeStr = e.endTime && formatDate(e.endTime, 'YYYY-MM-DD HH:mm')
|
||
// e.endTimeStr = '2025-01-13 00:00'
|
||
})
|
||
// if (data.list[0]) {
|
||
// formObj.value = data.list[0]
|
||
// const time = formObj.value.endTime - formObj.value.startTime //时间差秒
|
||
// console.log(time)
|
||
// const leave1 = time % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
|
||
// workTime.value = Math.floor(leave1 / (3600 * 1000))
|
||
// }
|
||
// if (data.list[0]) {
|
||
// // 将字符串转换为Date对象
|
||
// formObj.value = data.list[0]
|
||
// const endTime= new Date(formObj.value.endTimeStr);
|
||
// const startTime = new Date(formObj.value.startTimeStr);
|
||
|
||
// // 计算两个日期之间的毫秒差
|
||
// const timeDifferenceInMs = endTime - startTime;
|
||
|
||
// // 将毫秒差转换为小时
|
||
// const timeDifferenceInHours = timeDifferenceInMs / (3600 * 1000);
|
||
// const roundedTimeDifference = parseFloat(timeDifferenceInHours.toFixed(2));
|
||
// workTime.value = roundedTimeDifference;
|
||
// }
|
||
historyList.value = data.list
|
||
if(historyList.value!=null&&historyList.value.length>0){
|
||
var totalAmount = detailInfo.value.amount;
|
||
var beforeAmount = detailInfo.value.totalReportAmount
|
||
if(totalAmount >= beforeAmount){
|
||
amount.value = totalAmount - beforeAmount
|
||
}else{
|
||
amount.value = 0
|
||
}
|
||
|
||
}
|
||
|
||
isLoading.value = false
|
||
}
|
||
// 详情
|
||
const isOverBeforeProcedure = ref(true)
|
||
const getDetailData = async (id) => {
|
||
// 发送请求
|
||
// isLoading.value = true
|
||
const params = {
|
||
id,
|
||
}
|
||
const data = await getTaskDetailAPI(params)
|
||
if(data.beforeProcedureStatus == 0){
|
||
//如果上一道工序没结束
|
||
isOverBeforeProcedure.value = true;
|
||
}
|
||
data.startTime = formatDate(data.startTime, 'YYYY-MM-DD HH:mm');
|
||
data.endTime = formatDate(data.endTime, 'YYYY-MM-DD HH:mm'); // 去掉了末尾的空格
|
||
|
||
const endTime = new Date(data.endTime);
|
||
const startTime = new Date(data.startTime);
|
||
// // 计算两个日期之间的毫秒差
|
||
const timeDifferenceInMs = endTime - startTime;
|
||
// // 将毫秒差转换为小时
|
||
const timeDifferenceInHours = timeDifferenceInMs / (3600 * 1000);
|
||
const roundedTimeDifference = parseFloat(timeDifferenceInHours.toFixed(2));
|
||
workTime.value = roundedTimeDifference;
|
||
// 单位枚举
|
||
const lineObj = unitDictData.find((q) => q.value == data.unit) || {}
|
||
data.unit = lineObj.label
|
||
detailInfo.value = data || {}
|
||
isLoading.value = false
|
||
}
|
||
onLoad(async (options: any) => {
|
||
await getDetailData(options.id)
|
||
await getData()
|
||
const obj = historyList.value[0]
|
||
// 最新的报工是否完成
|
||
if (obj && obj?.workTime == null && obj.endTime) {
|
||
popup.value?.open()
|
||
}
|
||
})
|
||
|
||
// 生产完成
|
||
const handleComplate = async () => {
|
||
isLoading.value = true
|
||
const params = {
|
||
id: detailInfo.value?.id,
|
||
active: 'FINISH',
|
||
}
|
||
try {
|
||
const data = await postOperateAPI(params);
|
||
} catch (error) {
|
||
} finally {
|
||
isLoading.value = false;
|
||
}
|
||
const url = `/pages/productionReport/productionReport-detail?id=${detailInfo.value.id}`
|
||
uni.redirectTo({
|
||
url,
|
||
})
|
||
}
|
||
// 提交报工
|
||
const handleOk = async (active) => {
|
||
const params = {
|
||
id: detailInfo.value?.id,
|
||
active: 'SUBMIT',
|
||
amount: amount.value,
|
||
workTime: workTime.value,
|
||
}
|
||
const data = await postOperateAPI(params)
|
||
const url = `/pages/productionReport/productionReport-detail?id=${detailInfo.value.id}`
|
||
uni.redirectTo({
|
||
url,
|
||
})
|
||
}
|
||
// 开始生产
|
||
const handleStart = async () => {
|
||
const params = {
|
||
id: detailInfo.value.id,
|
||
active: 'START',
|
||
}
|
||
const data = await postOperateAPI(params)
|
||
const url = `/pages/productionReport/productionReport-detail?id=${detailInfo.value.id}`
|
||
uni.redirectTo({
|
||
url,
|
||
})
|
||
}
|
||
// 结束生产
|
||
const handleStop = async () => {
|
||
const params = {
|
||
id: detailInfo.value?.id,
|
||
active: 'END',
|
||
}
|
||
const data = await postOperateAPI(params)
|
||
const url = `/pages/productionReport/productionReport-detail?id=${detailInfo.value.id}`
|
||
uni.redirectTo({
|
||
url,
|
||
})
|
||
popup.value?.open()
|
||
}
|
||
</script>
|
||
<template>
|
||
<view>
|
||
<view v-if="isOverBeforeProcedure==true" class="data-detail">
|
||
<template v-if="!isLoading">
|
||
<view class="module">
|
||
<view class="module-info">
|
||
<view class="product-item">项目:{{ detailInfo.projectCode }} {{ detailInfo.projectName }}</view>
|
||
<image src="/static/images/productionReport-page.png" class="product-img" mode="scaleToFill"></image>
|
||
<view :class="[detailInfo.procedureStatus == 2 ? 'had' : 'unhad', 'product-status']">{{
|
||
detailInfo.procedureStatus == 2 ? '已完成' : '未完成' }}</view>
|
||
<view class="product-item">子项目:{{ detailInfo.projectSubCode || '' }} {{ ' ' + detailInfo.projectSubName }}
|
||
</view>
|
||
<view class="product-item">派工工序:{{ detailInfo.procedureName }}</view>
|
||
<view class="product-row">
|
||
<view class="row-item">
|
||
<view class="label">派工数量:</view>
|
||
<view class="val">{{ detailInfo.amount }}</view>
|
||
</view>
|
||
<view class="row-item">
|
||
<view class="label">总报工数量:</view>
|
||
<view class="val high-color">{{ detailInfo.totalReportAmount }}</view>
|
||
</view>
|
||
</view>
|
||
<view class="product-row">
|
||
<view class="row-item">
|
||
<view class="label">预计工时:</view>
|
||
<view class="val">{{ detailInfo.workTime }}</view>
|
||
</view>
|
||
<view class="row-item">
|
||
<view class="label">总报工工时:</view>
|
||
<view class="val high-color">{{ detailInfo.totalWorkTime }}</view>
|
||
</view>
|
||
</view>
|
||
<view class="product-item">预计生产日期:{{ detailInfo.startTime }} ~ {{ detailInfo.endTime }}</view>
|
||
<view class="finish" v-if="isShowStart && detailInfo.procedureStatus !== 2 && detailInfo.totalWorkTime"
|
||
@click="handleComplate">
|
||
<image class="complate-img" src="/static/images/productionReport-detail-complate.png" mode="scaleToFill" />
|
||
生产完成
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="module-list">
|
||
<view class="module-title">历史报工明细</view>
|
||
<view class="history-list">
|
||
<view class="no-data" v-if="!historyList.length">
|
||
无数据...
|
||
</view>
|
||
<template v-else>
|
||
<view class="item" v-for="(item, index) in historyList" :key="item.id">
|
||
<view class="product-item">生产开始时间:{{ item.startTimeStr }}</view>
|
||
<view class="product-item">生产结束时间:{{ item.endTimeStr }}</view>
|
||
<view class="product-row">
|
||
<view class="row-item">
|
||
<view class="label">报工工时:</view>
|
||
<view class="val high-color">{{ item.workTime }}</view>
|
||
</view>
|
||
<view class="row-item">
|
||
<view class="label">报工数量:</view>
|
||
<view class="val high-color">{{ item.amount }}</view>
|
||
</view>
|
||
</view>
|
||
<view class="tip-index">
|
||
<image src="/static/images/productionReport-detail-index.png" class="icon-status" mode="scaleToFit">
|
||
</image>
|
||
<view class="text">{{ historyList.length - index }}</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
<view class="action" v-if="detailInfo.procedureStatus !== 2">
|
||
<view class="action-item start" v-if="isShowStart" @click="handleStart">开始生产</view>
|
||
<view class="action-item stop" v-if="isShowEnd" @click="handleStop">结束生产</view>
|
||
<!-- <view class="action-item finish" v-if="isShowFinish" @click="handleComplate">生产完成</view> -->
|
||
</view>
|
||
</template>
|
||
<view class="loading-text" v-else>加载中..</view>
|
||
<uni-popup class="popup" ref="popup" :mask-click="false" type="bottom" background-color="#fff">
|
||
<view class="title">
|
||
<view class="text">填写信息</view>
|
||
<!-- <view class="close" @click="handleClose">X</view> -->
|
||
</view>
|
||
<view class="cont">
|
||
<view class="item">
|
||
<view class="label">开始生产时间:</view>
|
||
<view class="val">{{ detailInfo.startTime }}</view>
|
||
</view>
|
||
<view class="item">
|
||
<view class="label">结束生产时间:</view>
|
||
<view class="val">{{ detailInfo.endTime }}</view>
|
||
</view>
|
||
<view class="item">
|
||
<view class="label"><span class="star">*</span>本次报工工时:</view>
|
||
<uni-easyinput class="val" type="digit" v-model="amount" placeholder="请输入本次报工工时"></uni-easyinput>
|
||
<view class="unit">时</view>
|
||
</view>
|
||
<view class="item">
|
||
<view class="label"><span class="star">*</span>本次报工数量:</view>
|
||
<uni-easyinput class="val" type="number" v-model="workTime" placeholder="请输入本次报工数量"></uni-easyinput>
|
||
<view class="unit"> {{ detailInfo.unit }}</view>
|
||
</view>
|
||
</view>
|
||
<view class="ok" @click="handleOk">确定</view>
|
||
</uni-popup>
|
||
</view>
|
||
<view v-if="isOverBeforeProcedure==false">
|
||
<p>上一道工序尚未完工,请等待上一道工序完工后进行报工!</p>
|
||
</view>
|
||
</view>
|
||
|
||
</template>
|
||
<style lang="scss">
|
||
// 订单列表
|
||
.data-detail {
|
||
border-radius: 10rpx;
|
||
padding-bottom: 200rpx;
|
||
|
||
.module {
|
||
background: linear-gradient(178deg, #356899 7%, #356899 57%, #F4F6F9 94%);
|
||
padding: 20rpx;
|
||
|
||
.module-info {
|
||
padding: 20rpx 20rpx 80rpx;
|
||
border-radius: 10rpx;
|
||
min-height: 100rpx;
|
||
font-size: 28rpx;
|
||
border-bottom: 2rpx solid #F2F2F2;
|
||
background: linear-gradient(215deg, #C7D3E5 8%, rgba(222, 228, 236, 0) 13%), linear-gradient(162deg, #FFFFFF 25%, #E4EFFD 106%);
|
||
position: relative;
|
||
border-top-right-radius: 100rpx;
|
||
|
||
.product-img {
|
||
position: absolute;
|
||
right: 0rpx;
|
||
top: 0;
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
}
|
||
|
||
.product-status {
|
||
|
||
width: 140rpx;
|
||
border-radius: 10rpx;
|
||
text-align: center;
|
||
padding: 8rpx 12rpx;
|
||
|
||
&.had {
|
||
background: #E8FFEA;
|
||
color: #00B42A;
|
||
}
|
||
|
||
&.unhad {
|
||
background: #FFF7E8;
|
||
color: #FF7D00;
|
||
}
|
||
}
|
||
|
||
.product-item {
|
||
margin: 20rpx 0;
|
||
display: flex;
|
||
align-items: center;
|
||
color: #737D88
|
||
}
|
||
|
||
.product-row {
|
||
margin: 20rpx 0;
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
color: #737D88;
|
||
|
||
.row-item {
|
||
flex: 1;
|
||
|
||
.label {
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.val {
|
||
color: #1D2129;
|
||
|
||
&.high-color {
|
||
color: #00B42A
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
.finish {
|
||
position: absolute;
|
||
right: 40rpx;
|
||
bottom: 30rpx;
|
||
background: linear-gradient(142deg, #FEB34A 14%, #FE9B12 83%);
|
||
color: #fff;
|
||
width: 200rpx;
|
||
text-align: center;
|
||
padding: 10rpx;
|
||
border-radius: 31rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.complate-img {
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
margin-right: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.module-list {
|
||
padding: 20rpx 20rpx;
|
||
box-shadow: 0px 0px 8px 0px rgba(161, 161, 177, 0.12);
|
||
|
||
.module-title {
|
||
color: #0D0D26;
|
||
font-size: 36rpx;
|
||
margin: 20rpx 0;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.history-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
min-height: 200rpx;
|
||
justify-content: center;
|
||
padding: 0rpx 10rpx;
|
||
|
||
.item {
|
||
margin: 10rpx 0;
|
||
background: #EAEEF4;
|
||
font-size: 28rpx;
|
||
padding: 20rpx;
|
||
width: 100%;
|
||
border-radius: 10rpx;
|
||
color: #737D88;
|
||
position: relative;
|
||
|
||
.product-item {
|
||
margin: 10rpx 0;
|
||
|
||
.hight-color {
|
||
color: #00B42A;
|
||
}
|
||
}
|
||
|
||
.product-row {
|
||
margin: 20rpx 0;
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
color: #737D88;
|
||
|
||
.row-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: row;
|
||
|
||
.label {
|
||
margin-bottom: 10rpx;
|
||
|
||
&.high-color {
|
||
color: #00B42A
|
||
}
|
||
}
|
||
|
||
.val {
|
||
color: #1D2129;
|
||
|
||
&.high-color {
|
||
color: #00B42A
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
.tip-index {
|
||
position: absolute;
|
||
top: 0rpx;
|
||
right: 0rpx;
|
||
|
||
.icon-status {
|
||
width: 100rpx;
|
||
height: 72rpx;
|
||
z-index: 1;
|
||
}
|
||
|
||
.text {
|
||
color: #fff;
|
||
position: absolute;
|
||
top: 4rpx;
|
||
right: 30rpx;
|
||
z-index: 2;
|
||
}
|
||
}
|
||
}
|
||
|
||
.no-data {
|
||
font-size: 28rpx;
|
||
color: #444;
|
||
}
|
||
}
|
||
|
||
.table-cont {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.button {
|
||
color: #356899;
|
||
}
|
||
}
|
||
|
||
.action {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
position: fixed;
|
||
bottom: 0rpx;
|
||
border-radius: 18rpx;
|
||
padding: 30rpx 30rpx;
|
||
background: #FFFFFF;
|
||
margin: 0 auto;
|
||
width: 100vw;
|
||
box-shadow: 0px -4px 10px 0px rgba(121, 153, 183, 0.2);
|
||
|
||
.action-item {
|
||
width: 272rpx;
|
||
height: 86rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin: 0 20rpx;
|
||
font-size: 26rpx;
|
||
color: #fff;
|
||
width: 272rpx;
|
||
height: 86rpx;
|
||
border-radius: 24rpx;
|
||
|
||
&.start {
|
||
background: linear-gradient(157deg, #2EACE6 -3%, #356899 90%);
|
||
}
|
||
|
||
&.stop {
|
||
background: linear-gradient(167deg, #FEA97B -2%, #F75E40 87%);
|
||
}
|
||
|
||
&.finish {
|
||
background: linear-gradient(142deg, #FEB34A 14%, #FE9B12 83%);
|
||
}
|
||
}
|
||
}
|
||
|
||
.loading-text {
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
padding: 20rpx 0;
|
||
}
|
||
|
||
.popup {
|
||
.title {
|
||
line-height: 1;
|
||
padding: 40rpx;
|
||
font-size: 32rpx;
|
||
font-weight: normal;
|
||
border-bottom: 1rpx solid #ddd;
|
||
color: #444;
|
||
|
||
.close {
|
||
position: absolute;
|
||
right: 24rpx;
|
||
top: 40rpx;
|
||
height: 60rpx;
|
||
width: 60rpx;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
.cont {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin: 40rpx;
|
||
height: 50vh;
|
||
|
||
.item {
|
||
display: flex;
|
||
align-items: center;
|
||
margin: 20rpx 0;
|
||
color: #737D88;
|
||
width: 94%;
|
||
|
||
.label {
|
||
font-size: 32rpx;
|
||
width: 260rpx;
|
||
|
||
.star {
|
||
color: red
|
||
}
|
||
}
|
||
|
||
.val {
|
||
flex: 1;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.unit {
|
||
width: 100rpx;
|
||
margin-left: 4rpx;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.ok {
|
||
font-size: 32rpx;
|
||
margin: 20rpx auto 80rpx;
|
||
text-align: center;
|
||
width: 200rpx;
|
||
border-radius: 10rpx;
|
||
padding: 8rpx 0;
|
||
background-color: #3C8AF7;
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
</style>
|