| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- <template>
- <view class="page">
- <scroll-view scroll-y="true" class="detail">
- <view class="form-content">
- <uni-forms
- ref="maintenanceFormRef"
- labelWidth="140px"
- :modelValue="mainWorkOrder"
- :rules="mainWorkOrderRules"
- >
- <!-- 工单名称 -->
- <uni-forms-item
- class="form-item"
- :label="$t('workOrder.workOrderName')"
- name="name"
- :required="true"
- >
- <uni-easyinput
- style="text-align: right"
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- v-model="mainWorkOrder.name"
- :placeholder="$t('operation.PleaseFillIn')"
- />
- </uni-forms-item>
- <!-- 工单编号 -->
- <!-- <uni-forms-item class="form-item" :label="$t('workOrder.workOrderNumber')" name="orderNumber"
- :required="false">
- <uni-easyinput style="text-align: right" :inputBorder="false" :clearable="true"
- :disabled="true" :styles="{disableColor:'transparent'}" v-model="mainWorkOrder.orderNumber"
- :placeholder="$t('operation.PleaseFillIn')" />
- </uni-forms-item> -->
- <!-- 保养类型 -->
- <uni-forms-item
- class="form-item"
- :label="$t('maintenanceWorkOrder.maintenanceType')"
- name="outsourcingFlag"
- :required="false"
- >
- <uni-data-select
- :clear="false"
- v-model="mainWorkOrder.outsourcingFlag"
- :localdata="outsourcingFlagRange"
- >
- </uni-data-select>
- </uni-forms-item>
- <!-- 实际保养开始时间 -->
- <uni-forms-item
- class="form-item"
- :label="$t('maintenanceWorkOrder.actualMaintenanceStartTime')"
- name="actualStartTime"
- :required="true"
- >
- <uni-datetime-picker
- :end="dateMax"
- type="datetime"
- :border="false"
- returnType="timestamp"
- :placeholder="$t('operation.PleaseSelect')"
- :style="{
- color: mainWorkOrder.actualStartTime ? '#333' : '#999',
- 'font-size': mainWorkOrder.actualStartTime
- ? '14px !important'
- : 'inherit !important',
- }"
- v-model="mainWorkOrder.actualStartTime"
- >
- </uni-datetime-picker>
- </uni-forms-item>
- <!-- return-type="timestamp" -->
- <!-- 实际保养结束时间 -->
- <uni-forms-item
- class="form-item"
- :label="$t('maintenanceWorkOrder.actualEndTime')"
- name="actualEndTime"
- :required="true"
- >
- <uni-datetime-picker
- :end="dateMax"
- type="datetime"
- :border="false"
- returnType="timestamp"
- :placeholder="$t('operation.PleaseSelect')"
- :style="{
- color: mainWorkOrder.actualEndTime ? '#333' : '#999',
- 'font-size': mainWorkOrder.actualEndTime
- ? '14px !important'
- : 'inherit !important',
- }"
- v-model="mainWorkOrder.actualEndTime"
- >
- </uni-datetime-picker>
- </uni-forms-item>
- <!-- 保养费用 -->
- <uni-forms-item
- class="form-item"
- :label="$t('maintenanceWorkOrder.maintenanceCost')"
- name="cost"
- :required="false"
- >
- <uni-easyinput
- style="text-align: right"
- :inputBorder="false"
- :clearable="true"
- type="digit"
- :styles="{ disableColor: 'transparent' }"
- v-model="mainWorkOrder.cost"
- :disabled="true"
- />
- </uni-forms-item>
- <!-- 其他费用 -->
- <uni-forms-item
- class="form-item"
- :label="$t('maintenanceWorkOrder.otherCost')"
- :required="false"
- name="otherCost"
- >
- <uni-easyinput
- style="text-align: right"
- :inputBorder="false"
- :clearable="true"
- type="digit"
- :styles="{ disableColor: '#fff' }"
- v-model="mainWorkOrder.otherCost"
- :placeholder="$t('operation.PleaseFillIn')"
- />
- </uni-forms-item>
- <!-- 备注 -->
- <uni-forms-item
- class="form-item"
- :label="$t('operation.remark')"
- :required="false"
- name="remark"
- >
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- v-model="mainWorkOrder.remark"
- :placeholder="$t('operation.PleaseFillIn')"
- />
- </uni-forms-item>
- </uni-forms>
- <!-- 新增设备 -->
- <uni-row class="form-item flex-row align-center">
- <uni-col :span="8">
- <button
- class="add-btn"
- size="mini"
- type="primary"
- @click="onAddDevice()"
- >
- <uni-icons type="plusempty" color="white"></uni-icons>
- {{ $t("workOrder.addDevice") }}
- </button>
- </uni-col>
- </uni-row>
- <view class="device-section" v-for="bom in mainWorkOrderBom">
- <!-- 设备编码 -->
- <view class="item-module">
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{ $t("device.deviceCode") }}:</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.deviceCode }}</span>
- </view>
- </view>
- <view class="module-border"> </view>
- </view>
- <!-- 设备名称 -->
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{ $t("device.deviceName") }}:</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.deviceName }}</span>
- </view>
- </view>
- <!-- 累计运行时间 -->
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{
- $t("maintenanceWorkOrder.accumulatedRunningTime")
- }}(h):</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.totalRunTime }}</span>
- </view>
- </view>
- <!-- 累计运行里程 -->
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{
- $t("maintenanceWorkOrder.accumulatedRunningMileage")
- }}(km):</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.totalMileage }}</span>
- </view>
- </view>
- <!-- 保养项 -->
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{ $t("maintenanceWorkOrder.maintenanceItems") }}:</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.name }}</span>
- </view>
- </view>
- <!-- 物料数量 -->
- <view class="item-content flex-row align-center justify-between">
- <view class="item-title">
- <span class="item-title-width"
- >{{ $t("workOrder.materialCount") }}:</span
- >
- </view>
- <view class="item-title">
- <span>{{ bom.materialCount }}</span>
- </view>
- </view>
- <!-- 操作按钮 -->
- <view class="item-opera flex-row justify-end">
- <!-- 删除 -->
- <button type="primary" :plain="true" @click="onDelete(bom)">
- {{ $t("operation.delete") }}
- </button>
- <!-- 选择物料 -->
- <button type="primary" :plain="true" @click="onMaterialChoose(bom)">
- {{ $t("workOrder.selectMaterial") }}
- </button>
- <!-- 物料详情 -->
- <button
- type="primary"
- :plain="false"
- @click="onMaterialView(bom)"
- v-if="bom.materialSelected"
- >
- {{ $t("workOrder.materialDetails") }}
- </button>
- </view>
- </view>
- </view>
- </scroll-view>
- <button
- class="submit-btn"
- type="primary"
- @click="formSubmit(maintenanceFormRef)"
- >
- {{ $t("operation.submit") }}
- </button>
- </view>
- <deviceMultiple
- ref="deviceMultipleRef"
- @multiple-devide-submit="onChooseDevice"
- />
- <materialsChoose
- ref="materialsChooseRef"
- :deviceId="addMateriaItem.id"
- :materialItem="addMateriaItem"
- @material-submit="materialSubmit"
- />
- <materials-view ref="materialsViewRef" />
- </template>
- <script setup>
- import { onLoad, onReady, onBackPress } from "@dcloudio/uni-app";
- import {
- reactive,
- ref,
- onMounted,
- onBeforeUnmount,
- nextTick,
- getCurrentInstance,
- } from "vue";
- import { getUserDeptInfo } from "@/api";
- import { getDeviceAssociateBomList, saveMaintenance } from "@/api/maintenance";
- import { getDeptId, getUserId } from "@/utils/auth";
- import dayjs from "dayjs";
- import deviceMultiple from "@/components/device/multiple.vue";
- import materialsChoose from "@/components/materials/choose.vue";
- import materialsView from "@/components/materials/view.vue";
- import { useDataDictStore } from "@/store/modules/dataDict";
- const { getDataDictList } = useDataDictStore();
- const dict = getDataDictList("pms_main_work_order_process_mode");
- // 遍历dict,新增text字段 值为label
- dict.forEach((item) => {
- item.text = item.label;
- });
- console.log("resultDict", dict);
- // 引用全局变量$t
- const { appContext } = getCurrentInstance();
- const t = appContext.config.globalProperties.$t;
- const outsourcingFlagRange = ref([
- {
- value: 0,
- text: t("maintenanceWorkOrder.maintenanceTypeIn"),
- },
- // {
- // value: 1,
- // text: t("maintenanceWorkOrder.maintenanceTypeOut"),
- // },
- ]);
- // 获取当前时间
- const now = dayjs().format("YYYY-MM-DD HH:mm:ss");
- const dateMax = ref(now);
- // 获取当前用户部门信息
- const deptInfo = ref({});
- onMounted(() => {
- // 获取当前用户部门信息
- getUserDeptInfo({ id: getDeptId() }).then((res) => {
- deptInfo.value = res.data;
- // 给mainWorkOrder.name赋值
- mainWorkOrder.value.name =
- deptInfo.value.name +
- "-" +
- dayjs().format("YYYY-MM-DD") +
- t("maintenanceWorkOrder.title");
- // 给mainWorkOrder.deptId赋值
- mainWorkOrder.value.deptId = deptInfo.value.id;
- });
- });
- const mainWorkOrder = ref({
- // id: getRandomNumber(),
- name: "", // 工单名称
- orderNumber: "", // 工单编号
- outsourcingFlag: 0, // 保养类型(是否委外 0否 1是)
- actualStartTime: "", // 实际开始时间
- actualEndTime: "", // 实际结束时间
- remark: "", // 备注
- cost: "", // 保养费用
- otherCost: "", // 其他费用
- type: 2, //工单类型(1计划生成 2临时新建),
- deptId: "", // 部门id"
- responsiblePerson: getUserId(), // 负责人
- });
- const deviceMultipleRef = ref(null);
- const selectedDevices = ref([]);
- const onAddDevice = () => {
- deviceMultipleRef.value.open();
- };
- const onChooseDevice = (data) => {
- console.log("onChooseDevice", data);
- selectedDevices.value = data;
- onDeviceBomList();
- };
- // 保养工单明细
- const mainWorkOrderBom = ref([]);
- const onDeviceBomList = () => {
- const ids = selectedDevices.value.map((item) => item.id);
- console.log("onDeviceBomList-ids", ids);
- getDeviceAssociateBomList({
- deviceIds: ids.join(","),
- bomFlag: "b", // 维修时选择 物料 传值 w 保养时选择 物料 传值 b
- }).then((res) => {
- console.log("getDeviceAssociateBomList", res.data);
- // 如果返回的data为空,则提示没有可选择的保养项
- if (!res.data.length) {
- uni.showToast({
- title: t("maintenanceWorkOrder.noMaintenanceItems"),
- icon: "none",
- });
- return;
- }
- /**
- * 重新生成工单名称
- * 格式:deviceCode - deviceName - currentDate 保养工单
- * 首先提取出已经获取到的所有设备保养项集合中的第1个保养项对象的属性 deviceCode deviceName
- * 然后拼接上 currentDate 保养工单
- * 最后赋值给mainWorkOrder.name
- */
- // 查找res.data中第一个存在deviceCode和deviceName属性的对象
- const device = res.data.find((item) => item.deviceCode && item.deviceName);
- console.log("🚀 ~ onDeviceBomList ~ device:", device);
- if (device) {
- mainWorkOrder.value.name =
- device.deviceCode +
- " - " +
- device.deviceName +
- " - " +
- dayjs().format("YYYY-MM-DD") +
- t("maintenanceWorkOrder.title");
- }
- // 遍历res.data,如果bomNodeId不存在于mainWorkOrderBom中,则添加到mainWorkOrderBom中,并将是否选择物料设为false
- res.data.forEach((bom) => {
- if (
- !mainWorkOrderBom.value.some(
- (item) => item.bomNodeId === bom.bomNodeId && item.id === bom.id
- )
- ) {
- mainWorkOrderBom.value.push({
- ...bom,
- deviceId: bom.id,
- materialCount: 0, // 物料数量
- workOrderBomOnlyKey: bom.id + "_" + bom.bomNodeId, //手动拼接列表中的唯一标识
- materialSelected: false, //手动添加是否选择物料标识
- });
- }
- });
- console.log(
- "getDeviceAssociateBomList- mainWorkOrderBom",
- mainWorkOrderBom.value
- );
- });
- };
- // 物料选择
- const materialsChooseRef = ref(null);
- const addMateriaItem = ref({});
- const onMaterialChoose = (item) => {
- console.log("onMaterialChoose", item);
- addMateriaItem.value = item;
- materialsChooseRef.value.open(item);
- };
- // 保养工单 - 物料
- const mainWorkOrderMaterials = ref([]);
- const materialSubmit = (material) => {
- console.log("material - submit", material);
- // 判断mainWorkOrderMaterials中是否存在相同chooseKey和workOrderBomOnlyKey的物料,如果存在,则更新数量,如果不存在,则添加
- const index = mainWorkOrderMaterials.value.findIndex(
- (item) =>
- item.chooseKey === material.chooseKey &&
- item.workOrderBomOnlyKey == material.workOrderBomOnlyKey
- );
- if (index !== -1) {
- mainWorkOrderMaterials.value[index].quantity =
- parseFloat(mainWorkOrderMaterials.value[index].quantity) +
- parseFloat(material.quantity);
- } else {
- mainWorkOrderMaterials.value.push({
- ...material,
- });
- // 修改是否选择物料
- mainWorkOrderBom.value.forEach((bom) => {
- if (bom.workOrderBomOnlyKey === material.workOrderBomOnlyKey) {
- bom.materialSelected = true;
- }
- });
- }
- // 根据workOrderBomOnlyKey计算所选物料的数量 赋值给mainWorkOrderBom.materialCount
- mainWorkOrderBom.value.forEach((bom) => {
- bom.materialCount = mainWorkOrderMaterials.value
- .filter((item) => item.workOrderBomOnlyKey === bom.workOrderBomOnlyKey)
- .reduce((total, item) => {
- return parseFloat(total) + parseFloat(item.quantity);
- }, 0);
- });
- // 计算保养费用
- mainWorkOrder.value.cost = mainWorkOrderMaterials.value.reduce(
- (total, item) => {
- return (
- parseFloat(total) +
- parseFloat(item.quantity) * parseFloat(item.unitPrice)
- );
- },
- 0
- );
- // mainWorkOrder.value.cost保留两位小数
- mainWorkOrder.value.cost = mainWorkOrder.value.cost.toFixed(2);
- console.log("mainWorkOrderMaterials", mainWorkOrderMaterials.value);
- };
- const materialsViewRef = ref(null);
- const onMaterialView = (item) => {
- console.log("onMaterialView", item);
- // 筛选mainWorkOrderMaterials中相同workOrderBomOnlyKey的物料
- const materials = mainWorkOrderMaterials.value.filter(
- (material) => material.workOrderBomOnlyKey === item.workOrderBomOnlyKey
- );
- console.log("onMaterialView-materials", materials);
- // uni.$emit('material-view', materials)
- uni.navigateTo({
- url: "/pages/material/view",
- success: () => {
- setTimeout(() => {
- uni.$emit("material-view", materials);
- }, 300); // 延迟300ms,根据实际情况调整
- },
- });
- // materialsViewRef.value.openDrawer()
- };
- const onDelete = (item) => {
- console.log("onDelete", item);
- // 删除对应保养项以及对应保养项添加的物料
- mainWorkOrderBom.value = mainWorkOrderBom.value.filter(
- (bom) => bom.workOrderBomOnlyKey !== item.workOrderBomOnlyKey
- );
- mainWorkOrderMaterials.value = mainWorkOrderMaterials.value.filter(
- (material) => material.workOrderBomOnlyKey !== item.workOrderBomOnlyKey
- );
- };
- const maintenanceFormRef = ref(null);
- const mainWorkOrderRules = ref({
- name: {
- rules: [
- {
- required: true,
- errorMessage: t("operation.PleaseFillIn"),
- },
- ],
- },
- actualStartTime: {
- rules: [
- {
- required: true,
- errorMessage:
- t("operation.PleaseSelect") +
- t("maintenanceWorkOrder.actualMaintenanceStartTime"),
- },
- ],
- },
- actualEndTime: {
- rules: [
- {
- required: true,
- errorMessage:
- t("operation.PleaseSelect") + t("maintenanceWorkOrder.actualEndTime"),
- },
- ],
- },
- });
- const formSubmit = async (formEl) => {
- if (!formEl) return;
- await formEl
- .validate()
- .then((res) => {
- console.log("success", res);
- // 判断mainWorkOrder.value中的实际保养结束时间是否大于实际保养开始时间
- if (
- mainWorkOrder.value.actualEndTime &&
- mainWorkOrder.value.actualStartTime &&
- mainWorkOrder.value.actualEndTime < mainWorkOrder.value.actualStartTime
- ) {
- uni.showToast({
- title: t("maintenanceWorkOrder.timeNotBeEarlier"),
- icon: "none",
- });
- mainWorkOrder.value.actualEndTime = "";
- return;
- }
- // 判断是否存在保养明细
- if (mainWorkOrderBom.value.length === 0) {
- uni.showToast({
- title: t("maintenanceWorkOrder.bomEmpty"),
- icon: "none",
- });
- return;
- }
- // 判断是否所有保养项都已选择物料
- const unselectedBoms = mainWorkOrderBom.value.filter(
- (bom) => !bom.materialSelected
- );
- if (unselectedBoms.length > 0) {
- let message = "";
- if (unselectedBoms.length <= 1) {
- // 少于等于1个时全部显示
- message = unselectedBoms
- .map((bom) => `【${bom.deviceCode}-${bom.name}】${t("maintenanceWorkOrder.materialUnselected")}`)
- .join("\n");
- } else {
- // 超过1个时显示前1个加省略
- const firstThree = unselectedBoms
- .slice(0, 1)
- .map((bom) => `【${bom.deviceCode}-${bom.name}】`)
- .join("\n");
- message = `${firstThree}\n...${t("maintenanceWorkOrder.unselectedMaintenanceItems")}`;
- }
- uni.showToast({
- title: message,
- icon: "none",
- duration: 3000, // 延长显示时间以便用户阅读
- mask: true,
- });
- return;
- }
- // 提取数据处理逻辑为独立函数 - 使用对象解构赋值代替 delete 操作,避免修改原始数据
- const processBomData = (bomItems) => {
- return bomItems.map((item) => {
- const {
- id,
- materialCount,
- workOrderBomOnlyKey,
- materialSelected,
- ...rest
- } = item;
- return rest;
- });
- };
- const processMaterialData = (materialItems) => {
- return materialItems.map((item) => {
- const { chooseKey, workOrderBomOnlyKey, ...rest } = item;
- return {
- ...rest,
- };
- });
- };
- // 删除mainWorkOrderBom.value中的workOrderBomOnlyKey与materialSelected
- const orderBom = processBomData([...mainWorkOrderBom.value]);
- console.log("orderBom", orderBom);
- // 删除mainWorkOrderMaterials.value中的chooseKey与workOrderBomOnlyKey
- const orderMaterials = processMaterialData([
- ...mainWorkOrderMaterials.value,
- ]);
- saveMaintenance({
- mainWorkOrder: mainWorkOrder.value,
- mainWorkOrderBom: orderBom,
- mainWorkOrderMaterials: orderMaterials,
- })
- .then((res) => {
- console.log("saveMaintenance", res);
- if (res.code == 0) {
- uni.showToast({
- title: t("operation.success"),
- icon: "success",
- });
- uni.navigateBack();
- } else {
- uni.showToast({
- title: res.msg,
- icon: "none",
- });
- }
- })
- .catch((err) => {
- console.log("err", err);
- });
- })
- .catch((err) => {
- console.log("err", err);
- });
- };
- onLoad(() => {
- console.log("onLoad");
- });
- onReady(() => {
- // 设置自定义表单校验规则,必须在节点渲染完毕后执行
- // this.$refs.customForm.setRules(this.customRules)
- });
- </script>
- <style lang="scss" scoped>
- @import "@/style/work-order-detail.scss";
- </style>
|