src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,17 +1,50 @@
<template>
  <div>
    <el-dialog :title="operationType === 'add' ? '新增巡检任务' : '编辑巡检任务'"
               v-model="dialogVisitable" width="800px" @close="cancel">
      <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
    <el-dialog
      v-model="dialogVisitable"
      :title="operationType === 'add' ? '新增巡检任务' : '编辑巡检任务'"
      width="800px"
      @close="cancel"
    >
      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="任务名称" prop="taskName">
              <el-input v-model="form.taskName" placeholder="请输入任务名称" maxlength="30" />
            <el-form-item label="所属区域" prop="areaId">
              <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="地点" prop="inspectionLocation">
              <el-input v-model="form.inspectionLocation" placeholder="请输入地点" maxlength="30" />
            <el-form-item label="设备名称" prop="deviceLedgerIds">
              <el-select
                v-model="form.deviceLedgerIds"
                multiple
                collapse-tags
                collapse-tags-tooltip
                clearable
                filterable
                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-row>
@@ -19,10 +52,26 @@
          <el-col :span="12">
            <el-form-item label="巡检人" prop="inspector">
              <el-select v-model="form.inspector" placeholder="请选择" multiple clearable>
                <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
                <el-option
                  v-for="item in userList"
                  :key="item.userId"
                  :label="item.nickName"
                  :value="item.userId"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="规格型号">
              <el-input
                v-model="form.deviceModel"
                placeholder="自动带出规格型号"
                disabled
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="备注" prop="remarks">
              <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" />
@@ -33,55 +82,64 @@
          <el-col :span="12">
            <el-form-item label="任务频率" prop="frequencyType">
              <el-select v-model="form.frequencyType" placeholder="请选择" clearable>
                <el-option label="每日" value="DAILY"/>
                <el-option label="每周" value="WEEKLY"/>
                <el-option label="每月" value="MONTHLY"/>
                <el-option label="季度" value="QUARTERLY"/>
                <el-option label="每日" value="DAILY" />
                <el-option label="每周" value="WEEKLY" />
                <el-option label="每月" value="MONTHLY" />
                <el-option label="每年" value="YEARLY" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
          <el-col :span="12" v-if="form.frequencyType === 'DAILY'">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-time-picker v-model="form.frequencyDetail" placeholder="选择时间" format="HH:mm"
                              value-format="HH:mm" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%">
                <el-option label="周一" value="MON"/>
                <el-option label="周二" value="TUE"/>
                <el-option label="周三" value="WED"/>
                <el-option label="周四" value="THU"/>
                <el-option label="周五" value="FRI"/>
                <el-option label="周六" value="SAT"/>
                <el-option label="周日" value="SUN"/>
              </el-select>
              <el-time-picker v-model="form.time" placeholder="选择时间" format="HH:mm"
                              value-format="HH:mm"  style="width: 50%"/>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="DD,HH:mm"
                  value-format="DD,HH:mm"
              <el-time-picker
                v-model="form.frequencyDetail"
                placeholder="选择时间"
                format="HH:mm"
                value-format="HH:mm"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
          <el-col :span="12" v-if="form.frequencyType === 'WEEKLY'">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%">
                <el-option label="周一" value="MON" />
                <el-option label="周二" value="TUE" />
                <el-option label="周三" value="WED" />
                <el-option label="周四" value="THU" />
                <el-option label="周五" value="FRI" />
                <el-option label="周六" value="SAT" />
                <el-option label="周日" value="SUN" />
              </el-select>
              <el-time-picker
                v-model="form.time"
                placeholder="选择时间"
                format="HH:mm"
                value-format="HH:mm"
                style="width: 50%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'MONTHLY'">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="MM,DD,HH:mm"
                  value-format="MM,DD,HH:mm"
                v-model="form.frequencyDetail"
                type="datetime"
                clearable
                placeholder="选择开始日期"
                format="DD,HH:mm"
                value-format="DD,HH:mm"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'YEARLY'">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                v-model="form.frequencyDetail"
                type="datetime"
                clearable
                placeholder="选择开始日期"
                format="MM,DD,HH:mm"
                value-format="MM,DD,HH:mm"
              />
            </el-form-item>
          </el-col>
@@ -89,8 +147,8 @@
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancel">取消</el-button>
          <el-button type="primary" @click="submitForm">保存</el-button>
          <el-button @click="cancel">取消</el-button>
        </div>
      </template>
    </el-dialog>
@@ -98,77 +156,308 @@
</template>
<script setup>
import {reactive, ref} from "vue";
import useUserStore from '@/store/modules/user'
import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js";
import {userListAll} from "@/api/publicApi/index.js";
import { getCurrentInstance, reactive, ref, toRefs } from "vue";
import useUserStore from "@/store/modules/user";
import { addOrEditTimingTask } from "@/api/inspectionManagement/index.js";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import {
  getDeviceAreaTree,
  getDeviceAreaTreeWithDevices,
} from "@/api/equipmentManagement/deviceArea";
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const emit = defineEmits(["closeDia"]);
const userStore = useUserStore();
const dialogVisitable = ref(false);
const operationType = ref('add');
const operationType = ref("add");
const areaOptions = ref([]);
const deviceOptions = ref([]);
const userList = ref([]);
const areaTreeProps = {
  label: "areaName",
  children: "children",
};
const data = reactive({
  form: {
    taskName: '',
    inspectionLocation: '',
    inspector: '',
    inspectorIds: '',
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
    areaId: undefined,
    taskId: undefined,
    taskIds: [],
    taskIdsStr: undefined,
    deviceLedgerIds: [],
    deviceLedgerIdsStr: undefined,
    taskName: undefined,
    deviceModel: undefined,
    inspector: [],
    inspectorIds: "",
    remarks: "",
    frequencyType: "",
    frequencyDetail: "",
    week: "",
    time: "",
  },
  rules: {
    taskName: [{ required: true, message: "请输入任务名称", trigger: "blur" },],
    inspectionLocation: [{ required: true, message: "请输入地点", trigger: "blur" },],
    inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" },],
    areaId: [{ required: true, message: "请选择所属区域", trigger: "change" }],
    deviceLedgerIds: [{ required: true, message: "请选择设备", trigger: "change" }],
    inspector: [{ required: true, message: "请选择巡检人", trigger: "change" }],
    frequencyType: [{ required: true, message: "请选择任务频率", trigger: "change" }],
    frequencyDetail: [
      {
        required: true,
        trigger: "change",
        validator: (rule, value, callback) => {
          if (!form.value.frequencyType) {
            callback();
            return;
          }
          if (form.value.frequencyType === "WEEKLY") {
            if (!form.value.week || !form.value.time) {
              callback(new Error("请选择日期和时间"));
            } else {
              callback();
            }
            return;
          }
          if (!value) {
            callback(new Error("请选择日期"));
            return;
          }
          callback();
        },
      },
    ],
  },
});
const { form, rules } = toRefs(data);
const loadAreaTree = async () => {
  const { data } = await getDeviceAreaTree();
  areaOptions.value = Array.isArray(data) ? data : [];
};
const normalizeIdList = (value) => {
  if (Array.isArray(value)) {
    return value
      .map((item) => Number(item))
      .filter((item) => Number.isFinite(item));
  }
})
const { form, rules } = toRefs(data)
const userList = ref([])
// 打开弹框
const openDialog = async (type, row) => {
  dialogVisitable.value = true
  userListAll().then(res => {
    userList.value = res.data
  })
  if (type === 'edit') {
    form.value = {...row}
    form.value.inspector = form.value.inspectorIds.split(',').map(Number)
  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 cancel = () => {
  proxy.resetForm("formRef")
  dialogVisitable.value = false
  emit('closeDia')
}
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 submitForm = () => {
  proxy.$refs["formRef"].validate(async valid => {
    if (valid) {
      form.value.inspectorIds = form.value.inspector.join(',')
         delete form.value.inspector
      if (form.value.frequencyType === 'WEEKLY') {
        let frequencyDetail = ''
        frequencyDetail = form.value.week + ',' + form.value.time
        form.value.frequencyDetail = frequencyDetail
      }
      let res = await userStore.getInfo()
      form.value.registrantId = res.user.userId
      addOrEditTimingTask(form.value).then(() => {
        cancel()
        proxy.$modal.msgSuccess('提交成功')
      })
const normalizeDevice = (item) => ({
  ...item,
  id: item.id ?? item.deviceLedgerId,
  deviceName: item.deviceName ?? item.name,
  deviceModel: item.deviceModel ?? item.model,
});
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);
    }
  })
}
defineExpose({ openDialog })
  });
  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.value.deviceLedgerIds = selectedIds;
  form.value.deviceLedgerIdsStr = selectedIds.join(",");
  form.value.taskIds = [...selectedIds];
  form.value.taskIdsStr = selectedIds.join(",");
  form.value.taskId = selectedIds[0];
  form.value.taskName = selectedDevices
    .map((item) => item.deviceName)
    .filter(Boolean)
    .join(",");
  form.value.deviceModel = selectedDevices
    .map((item) => item.deviceModel || "-")
    .join(",");
};
const setDeviceModels = (deviceIds) => {
  syncDeviceFields(deviceIds);
};
const handleAreaChange = async (areaId) => {
  form.value.taskId = undefined;
  form.value.taskIds = [];
  form.value.taskIdsStr = undefined;
  form.value.deviceLedgerIds = [];
  form.value.deviceLedgerIdsStr = undefined;
  form.value.taskName = undefined;
  form.value.deviceModel = undefined;
  await loadDevicesByArea(areaId);
};
const resetForm = () => {
  if (proxy.$refs.formRef) {
    proxy.$refs.formRef.resetFields();
  }
  form.value = {
    areaId: undefined,
    taskId: undefined,
    taskIds: [],
    taskIdsStr: undefined,
    deviceLedgerIds: [],
    deviceLedgerIdsStr: undefined,
    taskName: undefined,
    deviceModel: undefined,
    inspector: [],
    inspectorIds: "",
    remarks: "",
    frequencyType: "",
    frequencyDetail: "",
    week: "",
    time: "",
  };
};
const openDialog = async (type, row) => {
  dialogVisitable.value = true;
  operationType.value = type;
  resetForm();
  userListNoPageByTenantId().then((res) => {
    userList.value = res.data;
  });
  await loadAreaTree();
  if (type === "edit" && row) {
    form.value = {
      ...form.value,
      ...row,
      inspector: row.inspectorIds
        ? String(row.inspectorIds)
            .split(",")
            .map((item) => Number(item))
            .filter((item) => Number.isFinite(item))
        : [],
    };
    form.value.deviceLedgerIds = normalizeIdList(
      row.deviceLedgerIds ??
        row.deviceLedgerIdsStr ??
        row.taskIds ??
        row.taskIdsStr ??
        row.taskId
    );
    form.value.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(",");
    form.value.taskIds = [...form.value.deviceLedgerIds];
    form.value.taskIdsStr = form.value.deviceLedgerIds.join(",");
    form.value.taskId = form.value.deviceLedgerIds[0];
    if (form.value.areaId) {
      await loadDevicesByArea(form.value.areaId);
      syncDeviceFields(form.value.deviceLedgerIds);
    }
  }
};
const cancel = () => {
  resetForm();
  dialogVisitable.value = false;
  emit("closeDia");
};
const submitForm = () => {
  proxy.$refs.formRef.validate(async (valid) => {
    if (!valid) {
      return;
    }
    try {
      syncDeviceFields(form.value.deviceLedgerIds);
      const payload = { ...form.value };
      payload.inspectorIds = Array.isArray(form.value.inspector)
        ? form.value.inspector.join(",")
        : "";
      delete payload.inspector;
      if (payload.frequencyType === "WEEKLY") {
        payload.frequencyDetail = `${payload.week},${payload.time}`;
      }
      const userInfo = await userStore.getInfo();
      payload.registrantId = userInfo.user.userId;
      payload.taskId = form.value.deviceLedgerIds[0];
      payload.taskIds = [...form.value.deviceLedgerIds];
      payload.taskIdsStr = form.value.deviceLedgerIds.join(",");
      payload.deviceLedgerIds = [...form.value.deviceLedgerIds];
      payload.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(",");
      payload.taskName = form.value.taskName;
      payload.deviceModel = form.value.deviceModel || "-";
      await addOrEditTimingTask(payload);
      cancel();
      proxy.$modal.msgSuccess("提交成功");
    } catch (error) {
      proxy.$modal.msgError("提交失败,请重试");
    }
  });
};
defineExpose({ openDialog });
</script>
<style scoped>
</style>
<style scoped></style>