rtgk-screen-web/components/client/PackagingOperation/index.js

620 lines
17 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, {
useCallback,
useRef,
useReducer,
useEffect,
useState,
useMemo,
} from "react";
import { message } from "antd";
import moment from "moment";
import Decimal from "decimal.js"
import Row from "../../../components/screen/Row";
import { FormItem } from "../FormItem";
import { Button } from "../Button";
import {
ModelSetting,
ModelBreak,
ModelOverproductionBatch,
ModelFinish,
ModelOverPrint,
} from "./ModalClient";
import { logo } from "./logo";
import { request } from "../utils";
import {
useEquipKey,
useSetting,
useMetaInfo,
useWsInfo,
useUser,
isDev,
} from "./hooks";
const headerHeight = 56;
/**
* url获取token
* 获取用户信息
* 获取权限信息
*
* url获取ip
* ip - 设置信息
* 设置信息 - 产品信息
* 设置信息 - socket 重量信息
*
* 任务状态:
* 无任务 待包装 包装中 中断 包装完成
*/
function formReducer(state, action) {
let { type, value } = action;
// console.log("action", action);
if (type === "FROM_INIT") return value;
if (type === "FROM_CHANGE") return Object.assign({}, state, value);
return state;
}
function PackagingOperation(props) {
const ModelSettingRef = useRef();
const ModelBreakRef = useRef();
const ModelOverproductionBatchRef = useRef();
const ModelFinishRef = useRef();
const [isEdit, setIsEdit] = useState(false);
const { equipKey, getEquipKey } = useEquipKey();
const { settingData, getSettingData } = useSetting(equipKey);
const [metaInfo, getMetaInfo] = useMetaInfo(settingData?.equipCode);
const [wsData] = useWsInfo(settingData?.equipCode, isEdit);
const [user, getUser] = useUser();
// 页面表单变化
const [form, dispatch] = useReducer(formReducer, {});
const onFormChange = useCallback((type, value) => {
dispatch({ type: "FROM_CHANGE", value: { [type]: value } });
}, []);
// 更新当前登录用户
useEffect(() => {
dispatch({ type: "FROM_CHANGE", value: { userName: user?.userName } });
}, [user]);
// 初始化表单
useEffect(() => {
dispatch({ type: "FROM_INIT", value: metaInfo });
getUser();
}, [metaInfo, getUser]);
// ws更新表单
useEffect(() => {
let { czzl, fczl } = wsData || {};
dispatch({ type: "FROM_CHANGE", value: { czzl, fczl } });
}, [wsData]);
// 更新净重
const netWeight = useMemo(() => {
let { bagWeight } = settingData;
let { fczl } = form;
if (isNaN(parseFloat(fczl))) return "";
if (isNaN(parseFloat(bagWeight))) return "";
let res = Decimal(fczl).sub(Decimal(bagWeight)).toNumber();
if (isNaN(res)) return "";
return res;
}, [form, settingData]);
// 更新持续时长
const [durationTime, setDurationTime] = useState(0);
useEffect(() => {
let getTime = () => {
let {
startTime,
status,
recoverDate,
interruptDate,
intrptDuration = 0,
} = metaInfo;
// console.log("metaInfo", metaInfo, {startTime, status, recoverDate, interruptDate, intrptDuration })
/**
* 无任务 “”
* 待包装 “”
* 包装中 currentDate - startTime - intrptDuration
* 中断 interruptDate - startTime - intrptDuration
* 包装完成 endTime - startTime - intrptDuration
*/
if (["no_job", "TO_BE_PACKAGED"].includes(status)) return "";
let dif = new Date(startTime).getTime() + intrptDuration * 1000;
if (status === "IN_PACKAGING") return new Date().getTime() - dif;
if (status === "INTERRUPT")
return new Date(interruptDate).getTime() - dif;
if (status === "PACKAGING_COMPLETED")
return new Date(endTime).getTime() - dif;
};
let timmer;
let run = () => {
setDurationTime(getTime());
timmer = setTimeout(() => {
run();
}, 1000);
};
run();
return () => {
clearTimeout(timmer);
};
}, [metaInfo]);
const durationTimeStr = useMemo(() => {
let time = moment.duration(durationTime);
let res = "";
let sec = time.seconds();
let min = time.minutes();
let hor = time.hours();
let day = time.days();
let m = time.months();
let y = time.years();
let flag = false;
let arr = [y, m, day, hor, min, sec];
let unt = ["年", "月", "日", "时", "分", "秒"];
arr.forEach((val, index) => {
if (val) {
flag = true;
res += val + unt[index];
} else if (flag) {
res += 0 + unt[index];
}
});
return res;
}, [durationTime]);
// 包装袋数
const [realBagNo, setRealBagNo] = useState(1);
useEffect(() => {
let { bagNo, outBagNo, outBatch } = form;
let res = 0;
if (outBatch) {
res = parseFloat(outBagNo) + 1;
} else {
res = parseFloat(bagNo) + 1;
}
setRealBagNo(isNaN(res) ? 0 : res);
}, [form.bagNo, form.outBagNo, form.outBatch]);
// 设备状态
const equipStatus = useMemo(() => {
if (form.status === "no_job") return "无任务";
if (form.status === "INTERRUPT") return "中断";
if (form.status === "TO_BE_PACKAGED") return "待包装";
if (form.status === "IN_PACKAGING") return "包装中";
if (form.status === "PACKAGING_COMPLETED") return "包装完成";
return "-";
}, [form.status]);
// 按钮启用禁用
const btnEnable = useMemo(() => {
/**
* 超产批号
* 设置 - 权限
* 历史记录 - 非无任务
* 开始 - 待包装
* 打印 - 包装中
* 结束 - 包装中 中断
* 中断 - 包装中
* 编辑 - 权限 包装中
* 编辑完成 - 权限 包装中
*/
return {
overPro: true,
setting: true,
history: ["中断", "待包装", "包装中", "包装完成"].includes(equipStatus),
start: ["待包装"].includes(equipStatus),
print: ["包装中"].includes(equipStatus),
finish: ["包装中", "中断"].includes(equipStatus),
break: ["包装中"].includes(equipStatus),
edit: ["包装中"].includes(equipStatus),
};
}, [equipStatus]);
// 退出
const handleCancel = useCallback(() => {
window.parent.postMessage({ type: "logOut" }, window.config.mesHost);
}, []);
// 设置
const handleSetting = useCallback(() => {
if (equipKey) {
let settingRes = Object.assign({}, settingData || {}, { equipKey });
ModelSettingRef.current.show(settingRes, getSettingData);
}
}, [equipKey, getSettingData, settingData]);
// 超产批号
const handleOverproduct = useCallback(() => {
ModelOverproductionBatchRef.current.show(
metaInfo.workOrderCode,
(outBatch) => {
onFormChange("outBatch", outBatch);
}
);
}, [metaInfo.workOrderCode, onFormChange]);
// 历史记录
const handleHistory = useCallback(() => {
window.parent.postMessage(
{ type: "history", data: metaInfo },
window.config.mesHost
);
}, [metaInfo]);
// 开始
const handleStart = useCallback(() => {
if (metaInfo.gid)
return new Promise((resolve, reject) => {
request({
url: `${window.config.mesUrl}/prodexec/prodexec/packageEquipment/startPack`,
bodys: { gid: metaInfo.gid },
})
.then((res) => {
if (res.success) {
message.success("开始成功!");
getMetaInfo();
}
})
.finally(() => {
resolve();
});
});
}, [metaInfo.gid, getMetaInfo]);
// 打印
const ModelOverPrintRef = useRef();
const [isGT, setIsGT] = useState(false)
const handlePrint = useCallback((GT, callback) => {
if (GT === undefined) GT = isGT;
let { gid: recordGid } = metaInfo;
let { gid: setInfoGid, bagWeight } = settingData;
let {
fczl,
czzl,
outBatch,
materialCode,
productLevel,
startTime,
materialName,
workOrderCode,
} = form;
// collectValue 页面可见数据 除自定义字段外的 对象json 字符串
let collectValue = {
materialCode,
productLevel,
startTime,
materialName,
workOrderCode,
czzl,
fczl,
bagWeight,
yetWeight: netWeight,
bagNo: realBagNo,
};
let data = {
recordGid,
mark: GT? "GT": undefined,
fczl,
bagNo: realBagNo,
setInfoGid,
yetWeight: netWeight,
outBatch,
collectValue: JSON.stringify(collectValue),
};
if (recordGid)
return new Promise((resolve, reject) => {
request({
url: `${window.config.mesUrl}/prodexec/prodexec/packageEquipment/print`,
bodys: data,
})
.then((res) => {
// if (isDev) {
// if (res.message.indexOf('打印命令发送失败') > -1) {
// res = {
// success: false,
// data: "GT",
// message: "message text"
// }
// }
// }
if (res && res.success) {
message.success("打印成功!");
setRealBagNo(parseFloat(realBagNo) + 1);
} else {
if (res?.data === "GT") {
ModelOverPrintRef.current.show(res.message, (close) => {
setIsGT(true);
return handlePrint(true, close);
})
}else message.error(res?.message);
}
})
.finally(() => {
resolve();
callback && callback();
});
});
}, [metaInfo, settingData, form, netWeight, realBagNo, isGT]);
// 结束
const handleFinish = useCallback(() => {
ModelFinishRef.current.show({ gid: metaInfo.gid }, getMetaInfo);
}, [metaInfo.gid, getMetaInfo]);
// 中断
const handleBreak = useCallback(() => {
ModelBreakRef.current.show({ gid: metaInfo.gid }, getMetaInfo);
}, [metaInfo.gid, getMetaInfo]);
// 编辑
const handleEdit = useCallback(() => {
// console.log("handleEdit");
if (isEdit) {
setIsEdit(false);
} else {
setIsEdit(true);
}
}, [isEdit]);
return (
<div className="client-content">
<div className="client-content-header">
<div className="logo-box">
<img src={logo} alt="logo" className="logo-img" />
</div>
<div className="btn-box">
<div className="btn link-btn" onClick={handleCancel}>
退出
</div>
</div>
</div>
<div className="client-content-body">
<div className="card">
<div className="card-header">
<span className="title">产品信息</span>
<div className="extra">
<Button
title="超产批号"
ghost
onClick={handleOverproduct}
enable={btnEnable.overPro}
/>
<ModelOverproductionBatch ref={ModelOverproductionBatchRef} />
<Button
title="设置"
ghost
ruleCode="set_pack_info"
onClick={handleSetting}
enable={btnEnable.setting}
/>
<ModelSetting ref={ModelSettingRef} />
</div>
</div>
<div className="card-body">
<div className="statu-box">{equipStatus}</div>
<div className="statu-content">
<Row gutter={32}>
<Row.Col span={8}>
<FormItem value={form.materialCode} title={"产品编码"} />
</Row.Col>
<Row.Col span={8}>
<FormItem value={form.productLevel} title={"产品型号"} />
</Row.Col>
<Row.Col span={8}>
<FormItem value={form.startTime} title={"开始时间"} />
</Row.Col>
<Row.Col span={8}>
<FormItem value={form.materialName} title={"产品名称"} />
</Row.Col>
<Row.Col span={8}>
<FormItem value={form.workOrderCode} title={"产品批次号"} />
</Row.Col>
<Row.Col span={8}>
<FormItem value={durationTimeStr} title={"持续时长"} />
</Row.Col>
</Row>
</div>
</div>
</div>
<div className="card">
<div className="card-header">
<span className="title">生产信息</span>
<div className="extra">
<Button
title="历史记录"
ghost={true}
onClick={handleHistory}
enable={btnEnable.history}
/>
</div>
</div>
<div className="card-body">
<Row gutter={32}>
<Row.Col span={8}>
<FormItem
value={form.czzl}
title={"毛重吨包/KG"}
horizontal={false}
type="number"
readonly={!isEdit}
onChange={(val) => onFormChange("czzl", val)}
/>
</Row.Col>
<Row.Col span={8}>
<FormItem
value={form.fczl}
title={"复称重量吨包/KG"}
horizontal={false}
type="number"
readonly={!isEdit}
onChange={(val) => onFormChange("fczl", val)}
/>
</Row.Col>
<Row.Col span={8}>
<FormItem
value={form.userName}
title={"复称人"}
horizontal={false}
/>
</Row.Col>
<Row.Col span={8}>
<FormItem
value={settingData.bagWeight}
title={"包装袋重量/KG"}
horizontal={false}
/>
</Row.Col>
<Row.Col span={8}>
<FormItem
value={netWeight}
title={"净重/KG"}
horizontal={false}
/>
</Row.Col>
<Row.Col span={8}>
<FormItem
value={realBagNo}
title={"包装袋数"}
horizontal={false}
type="number"
readonly={false}
min={1}
onChange={(val) => setRealBagNo(val)}
/>
</Row.Col>
</Row>
</div>
</div>
</div>
<div className="client-content-footer">
<Button
title="开始"
type="success"
size="large"
ruleCode="startPack"
onClick={handleStart}
enable={btnEnable.start}
/>
<Button
title="确认打印"
size="large"
ruleCode="print_pack"
onClick={handlePrint}
enable={btnEnable.print}
/>
<ModelOverPrint ref={ModelOverPrintRef}/>
<Button
title="结束"
type="danger"
size="large"
ruleCode="end_pack"
enable={btnEnable.finish}
onClick={handleFinish}
/>
<ModelFinish ref={ModelFinishRef} />
<Button
title="中断"
type="warning"
size="large"
ruleCode="interrupt_pack"
enable={btnEnable.break}
onClick={handleBreak}
/>
<ModelBreak ref={ModelBreakRef} />
<Button
title={!isEdit ? "编辑" : "编辑完成"}
type="info"
size="large"
ruleCode="eidt_fczl"
onClick={handleEdit}
enable={btnEnable.edit}
/>
</div>
<style jsx>{`
.client-content {
display: flex;
flex-direction: column;
height: 100vh;
}
.client-content-header {
height: ${headerHeight}px;
padding: 0 16px;
background: #272f3e;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
}
.logo-box {
float: left;
line-height: ${headerHeight}px;
}
.logo-img {
width: 175px;
height: 28px;
display: inline-block;
}
.btn-box {
float: right;
}
.btn.link-btn {
display: inline-block;
line-height: ${headerHeight}px;
padding: 0 24px;
color: white;
font-size: 20px;
cursor: pointer;
}
.client-content-footer {
background: white;
height: 96px;
text-align: center;
padding: 20px 0;
}
.client-content-body {
background: rgb(243, 243, 243);
flex: 1;
overflow: auto;
padding: 18px 16px 0;
}
.card {
background: #ffffff;
border-radius: 4px;
margin-bottom: 16px;
padding: 24px 32px;
}
.card-header {
overflow: hidden;
}
.card-header .title {
font-size: 28px;
color: #000000 85%;
}
.card-header .extra {
float: right;
}
.card-body {
padding: 20px 0;
overflow: hidden;
}
.statu-box {
height: 112px;
width: 112px;
background: #fff7e8;
border: 1px solid #f16704;
border-radius: 6px;
line-height: 112px;
font-size: 24px;
text-align: center;
color: #faab0c;
float: left;
}
.statu-content {
margin-left: ${112 + 32}px;
}
`}</style>
</div>
);
}
export default PackagingOperation;