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

620 lines
17 KiB
JavaScript
Raw Permalink Normal View History

2024-06-20 11:26:44 +08:00
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;