gaoluyang
2 天以前 f49bfd6c085cbf28a25d9404f8dc5b74368b716a
src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -1,126 +1,101 @@
<template>
  <FormDialog v-model="visible"
              :title="computedTitle"
              :operation-type="operationType"
              width="800px"
              @confirm="sendForm"
              @cancel="handleCancel"
              @close="handleClose">
    <el-form :model="form"
             label-width="100px">
  <FormDialog
    v-model="visible"
    :title="id ? '编辑设备报修' : '新增设备报修'"
    width="800px"
    @confirm="sendForm"
    @cancel="handleCancel"
    @close="handleClose"
  >
    <el-form :model="form" label-width="100px">
      <el-row>
        <el-col :span="12">
          <el-form-item label="所属区域">
            <el-tree-select
              v-model="form.areaId"
              :data="areaOptions"
              :props="areaTreeProps"
              node-key="id"
              value-key="id"
              check-strictly
              clearable
              filterable
              placeholder="请选择所属区域"
              style="width: 100%"
              @change="handleAreaChange"
            />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="设备名称">
            <el-select v-model="form.deviceLedgerId"
                       @change="setDeviceModel"
                       filterable
                       :disabled="operationType === 'view'">
              <el-option v-for="(item, index) in deviceOptions"
                         :key="index"
                         :label="item.deviceName"
                         :value="item.id"></el-option>
            <el-select
              v-model="form.deviceLedgerIds"
              filterable
              clearable
              multiple
              collapse-tags
              collapse-tags-tooltip
              placeholder="请先选择区域,再选择设备"
              style="width: 100%"
              @change="setDeviceModels"
            >
              <el-option
                v-for="item in deviceOptions"
                :key="item.id"
                :label="item.deviceName"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="规格型号">
            <el-input v-model="form.deviceModel"
                      placeholder="请输入规格型号"
                      disabled />
            <el-input
              v-model="form.deviceModel"
              placeholder="自动带出规格型号"
              disabled
            />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="报修日期">
            <el-date-picker v-model="form.repairTime"
                            placeholder="请选择报修日期"
                            format="YYYY-MM-DD"
                            value-format="YYYY-MM-DD"
                            type="date"
                            clearable
                            style="width: 100%"
                            :disabled="operationType === 'view'" />
            <el-date-picker
              v-model="form.repairTime"
              placeholder="请选择报修日期"
              format="YYYY-MM-DD"
              value-format="YYYY-MM-DD"
              type="date"
              clearable
              style="width: 100%"
            />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="报修人">
            <el-input v-model="form.repairName"
                      placeholder="请输入报修人"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="报修报修项目">
            <el-input v-model="form.machineryCategory"
                      placeholder="请输入报修报修项目"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="12">
          <el-form-item label="维修人">
            <el-input v-model="form.maintenanceName"
                      placeholder="请输入维修人姓名"
                      :disabled="operationType === 'view'" />
            <el-input v-model="form.repairName" placeholder="请输入报修人" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="id">
        <el-col :span="12">
          <el-form-item label="报修状态">
            <el-select v-model="form.status"
                       disabled>
              <el-option label="待维修"
                         :value="0"></el-option>
              <el-option label="已验收"
                         :value="1"></el-option>
              <el-option label="失败"
                         :value="2"></el-option>
            <el-select v-model="form.status">
              <el-option label="待维修" :value="0" />
              <el-option label="完结" :value="1" />
              <el-option label="失败" :value="2" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <!-- 验收信息展示 -->
      <el-row v-if="id && (form.status === 1 || form.status === 3)">
        <el-col :span="12">
          <el-form-item label="验收人">
            <el-input v-model="form.acceptanceName"
                      disabled />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="验收时间">
            <el-input v-model="form.acceptanceTime"
                      disabled />
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="验收备注">
            <el-input v-model="form.acceptanceRemark"
                      type="textarea"
                      :rows="2"
                      disabled />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="故障现象">
            <el-input v-model="form.remark"
                      :rows="2"
                      type="textarea"
                      placeholder="请输入故障现象"
                      :disabled="operationType === 'view'" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="operationType !== 'view'"
              :gutter="30">
        <el-col :span="24">
          <el-form-item label="附件"
                        prop="attachmentIds">
            <FileUpload v-model:file-list="form.storageBlobDTOs"
                        :disabled="operationType === 'view'" />
            <el-input
              v-model="form.remark"
              :rows="2"
              type="textarea"
              placeholder="请输入故障现象"
            />
          </el-form-item>
        </el-col>
      </el-row>
@@ -129,140 +104,239 @@
</template>
<script setup>
  import FormDialog from "@/components/Dialog/FormDialog.vue";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
  import {
    addRepair,
    editRepair,
    getRepairById,
  } from "@/api/equipmentManagement/repair";
  import { ElMessage } from "element-plus";
  import dayjs from "dayjs";
  import useFormData from "@/hooks/useFormData";
  import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
  import useUserStore from "@/store/modules/user";
import { nextTick, ref, unref } from "vue";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import FormDialog from "@/components/Dialog/FormDialog.vue";
import useFormData from "@/hooks/useFormData";
import useUserStore from "@/store/modules/user";
import {
  addRepair,
  editRepair,
  getRepairById,
} from "@/api/equipmentManagement/repair";
import {
  getDeviceAreaTree,
  getDeviceAreaTreeWithDevices,
} from "@/api/equipmentManagement/deviceArea";
  defineOptions({
    name: "设备报修弹窗",
  });
defineOptions({
  name: "设备报修弹窗",
});
  const emits = defineEmits(["ok"]);
const emits = defineEmits(["ok"]);
  const id = ref();
  const visible = ref(false);
  const loading = ref(false);
  const operationType = ref(""); // add, edit, view
const id = ref();
const visible = ref(false);
const loading = ref(false);
const userStore = useUserStore();
const areaOptions = ref([]);
const deviceOptions = ref([]);
const areaTreeProps = {
  label: "areaName",
  children: "children",
};
  const computedTitle = computed(() => {
    if (operationType.value === "add") return "新增设备报修";
    if (operationType.value === "edit") return "编辑设备报修";
    if (operationType.value === "view") return "设备报修详情";
    return "";
  });
const { form, resetForm } = useFormData({
  areaId: undefined,
  deviceLedgerId: undefined,
  deviceLedgerIds: [],
  deviceLedgerIdsStr: undefined,
  deviceName: undefined,
  deviceModel: undefined,
  repairTime: dayjs().format("YYYY-MM-DD"),
  repairName: userStore.nickName,
  remark: undefined,
  status: 0,
});
  const userStore = useUserStore();
  const deviceOptions = ref([]);
  const fileList = ref([]);
const loadAreaTree = async () => {
  const { data } = await getDeviceAreaTree();
  areaOptions.value = Array.isArray(data) ? data : [];
};
  const loadDeviceName = async () => {
    const { data } = await getDeviceLedger();
    deviceOptions.value = data;
  };
const normalizeIdList = (value) => {
  if (Array.isArray(value)) {
    return value
      .map((item) => Number(item))
      .filter((item) => Number.isFinite(item));
  }
  if (typeof value === "string") {
    return value
      .split(",")
      .map((item) => Number(item.trim()))
      .filter((item) => Number.isFinite(item));
  }
  if (value !== undefined && value !== null && value !== "") {
    const numericValue = Number(value);
    return Number.isFinite(numericValue) ? [numericValue] : [];
  }
  return [];
};
  const { form, resetForm } = useFormData({
    deviceLedgerId: undefined, // 设备Id
    deviceName: undefined, // 设备名称
    deviceModel: undefined, // 规格型号
    repairTime: dayjs().format("YYYY-MM-DD"), // 报修日期,默认当天
    repairName: userStore.nickName, // 报修人
    remark: undefined, // 故障现象
    status: 0, // 报修状态
    machineryCategory: undefined,
    storageBlobDTOs: [],
    maintenanceName: undefined, // 维修人
  });
const getNodeDevices = (node) => {
  const candidates = [
    node?.deviceList,
    node?.devices,
    node?.deviceLedgerList,
    node?.deviceLedgers,
    node?.ledgerList,
    node?.ledgers,
  ];
  return candidates.find((item) => Array.isArray(item)) || [];
};
  const setDeviceModel = deviceId => {
    const option = deviceOptions.value.find(item => item.id === deviceId);
    form.deviceModel = option.deviceModel;
  };
const normalizeDevice = (item) => ({
  ...item,
  id: item.id ?? item.deviceLedgerId,
  deviceName: item.deviceName ?? item.name,
  deviceModel: item.deviceModel ?? item.model,
});
  const setForm = data => {
    form.deviceLedgerId = data.deviceLedgerId;
    form.deviceName = data.deviceName;
    form.deviceModel = data.deviceModel;
    form.repairTime = data.repairTime;
    form.repairName = data.repairName;
    form.remark = data.remark;
    form.status = data.status;
    form.machineryCategory = data.machineryCategory;
    form.storageBlobDTOs = data.storageBlobVOs || [];
    form.maintenanceName = data.maintenanceName;
    form.acceptanceName = data.acceptanceName;
    form.acceptanceTime = data.acceptanceTime;
    form.acceptanceRemark = data.acceptanceRemark;
  };
  const sendForm = async () => {
    loading.value = true;
    try {
      const { code } = id.value
        ? await editRepair({ id: unref(id), ...form })
        : await addRepair(form);
      if (code == 200) {
        ElMessage.success(`${id.value ? "编辑" : "新增"}报修成功`);
        visible.value = false;
        emits("ok");
      }
    } finally {
      loading.value = false;
const collectDevices = (node) => {
  const currentDevices = getNodeDevices(node).map(normalizeDevice);
  const childDevices = (node?.children || []).flatMap((child) =>
    collectDevices(child)
  );
  const deviceMap = new Map();
  [...currentDevices, ...childDevices].forEach((item) => {
    if (item?.id !== undefined && item?.id !== null) {
      deviceMap.set(Number(item.id), item);
    }
  };
  const handleCancel = () => {
    resetForm();
    visible.value = false;
  };
  const handleClose = () => {
    resetForm();
    visible.value = false;
  };
  const openAdd = async () => {
    id.value = undefined;
    operationType.value = "add";
    visible.value = true;
    fileList.value = [];
    await nextTick();
    await loadDeviceName();
  };
  const openEdit = async editId => {
    const { data } = await getRepairById(editId);
    id.value = editId;
    operationType.value = "edit";
    visible.value = true;
    await nextTick();
    await loadDeviceName();
    setForm(data);
  };
  const openView = async viewId => {
    const { data } = await getRepairById(viewId);
    id.value = viewId;
    operationType.value = "view";
    visible.value = true;
    await nextTick();
    await loadDeviceName();
    setForm(data);
  };
  defineExpose({
    openAdd,
    openEdit,
    openView,
  });
  return Array.from(deviceMap.values());
};
const findAreaNode = (nodes, areaId) => {
  for (const node of nodes || []) {
    if (Number(node.id) === Number(areaId)) {
      return node;
    }
    const target = findAreaNode(node.children, areaId);
    if (target) {
      return target;
    }
  }
  return null;
};
const loadDevicesByArea = async (areaId) => {
  if (!areaId) {
    deviceOptions.value = [];
    return;
  }
  const { data } = await getDeviceAreaTreeWithDevices();
  const treeData = Array.isArray(data) ? data : [];
  const currentNode = findAreaNode(treeData, areaId);
  deviceOptions.value = currentNode ? collectDevices(currentNode) : [];
};
const syncDeviceFields = (deviceIds) => {
  const selectedIds = normalizeIdList(deviceIds);
  const selectedDevices = selectedIds
    .map((deviceId) =>
      deviceOptions.value.find((item) => Number(item.id) === Number(deviceId))
    )
    .filter(Boolean);
  form.deviceLedgerIds = selectedIds;
  form.deviceLedgerId = selectedIds[0];
  form.deviceLedgerIdsStr = selectedIds.join(",");
  form.deviceName = selectedDevices
    .map((item) => item.deviceName)
    .filter(Boolean)
    .join(",");
  form.deviceModel = selectedDevices
    .map((item) => item.deviceModel || "-")
    .join(",");
};
const setDeviceModels = (deviceIds) => {
  syncDeviceFields(deviceIds);
};
const setForm = (data) => {
  form.areaId = data.areaId;
  form.deviceLedgerIds = normalizeIdList(
    data.deviceLedgerIds ?? data.deviceLedgerIdsStr ?? data.deviceLedgerId
  );
  form.deviceLedgerId = form.deviceLedgerIds[0];
  form.deviceLedgerIdsStr =
    data.deviceLedgerIdsStr ?? form.deviceLedgerIds.join(",");
  form.deviceName = data.deviceName;
  form.deviceModel = data.deviceModel;
  form.repairTime = data.repairTime;
  form.repairName = data.repairName;
  form.remark = data.remark;
  form.status = data.status;
};
const handleAreaChange = async (areaId) => {
  form.deviceLedgerId = undefined;
  form.deviceLedgerIds = [];
  form.deviceLedgerIdsStr = undefined;
  form.deviceName = undefined;
  form.deviceModel = undefined;
  await loadDevicesByArea(areaId);
};
const sendForm = async () => {
  loading.value = true;
  try {
    syncDeviceFields(form.deviceLedgerIds);
    const payload = {
      ...form,
      deviceLedgerId: form.deviceLedgerIds[0],
      deviceLedgerIds: [...form.deviceLedgerIds],
      deviceLedgerIdsStr: form.deviceLedgerIds.join(","),
      deviceModel: form.deviceModel || "-",
    };
    const { code } = id.value
      ? await editRepair({ id: unref(id), ...payload })
      : await addRepair(payload);
    if (code === 200) {
      ElMessage.success(`${id.value ? "编辑" : "新增"}报修成功`);
      visible.value = false;
      emits("ok");
    }
  } finally {
    loading.value = false;
  }
};
const handleCancel = () => {
  resetForm();
  visible.value = false;
};
const handleClose = () => {
  resetForm();
  visible.value = false;
};
const openAdd = async () => {
  id.value = undefined;
  visible.value = true;
  await nextTick();
  await loadAreaTree();
  deviceOptions.value = [];
};
const openEdit = async (editId) => {
  const { data } = await getRepairById(editId);
  id.value = editId;
  visible.value = true;
  await nextTick();
  await loadAreaTree();
  setForm(data);
  await loadDevicesByArea(form.areaId);
  syncDeviceFields(form.deviceLedgerIds);
};
defineExpose({
  openAdd,
  openEdit,
});
</script>
<style lang="scss" scoped></style>