src/views/environmentAccess/accessManagement/index.vue
@@ -1,347 +1,242 @@
<template>
  <div class="app-container">
    <el-form :model="filters" :inline="true">
      <el-form-item label="门禁名称">
        <el-input
          v-model="filters.name"
          style="width: 240px"
          placeholder="请输入门禁名称"
          clearable
          :prefix-icon="Search"
          @change="getTableData"
        />
      </el-form-item>
      <el-form-item label="门禁状态">
        <el-select
          v-model="filters.status"
          style="width: 240px"
          placeholder="请选择门禁状态"
          clearable
          @change="getTableData"
        >
          <el-option label="正常" value="1"></el-option>
          <el-option label="异常" value="0"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="区域">
        <el-input
          v-model="filters.area"
          style="width: 240px"
          placeholder="请输入区域"
          clearable
          :prefix-icon="Search"
          @change="getTableData"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="getTableData">搜索</el-button>
        <el-button @click="resetFilters">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
      <div class="actions">
        <div></div>
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
      <el-tab-pane label="进出厂车辆" name="1" />
      <el-tab-pane label="厂内车辆使用" name="2" />
      <el-tab-pane label="非道路移动机械" name="3" />
      <el-tab-pane label="设备故障" name="defect" />
    </el-tabs>
    <!-- 车辆/机械 -->
    <template v-if="activeTab !== 'defect'">
      <div class="search_form">
        <div>
          <el-button type="primary" @click="add" icon="Plus"> 新增 </el-button>
          <el-button type="danger" icon="Delete" :disabled="multipleList.length <= 0" @click="batchDelete">批量删除</el-button>
          <span class="search_title">车牌/机械编号:</span>
          <el-input v-model="searchForm.plateNo" style="width: 200px" placeholder="请输入" clearable @change="handleQuery" />
          <span class="search_title ml10">使用人:</span>
          <el-input v-model="searchForm.driverName" style="width: 160px" placeholder="请输入" clearable @change="handleQuery" />
          <span class="search_title ml10">时间:</span>
          <el-date-picker v-model="searchForm.dateRange" type="daterange" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
            start-placeholder="开始" end-placeholder="结束" clearable @change="changeRange" />
          <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        </div>
        <div>
          <el-button type="primary" @click="openForm('add')">新增</el-button>
          <el-button type="danger" plain @click="handleDelete">删除</el-button>
        </div>
      </div>
      <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
      </PIMTable>
    </div>
    <!-- 新增编辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px">
      <el-form :model="formData" label-width="100px">
        <el-form-item label="门禁名称" required>
          <el-input v-model="formData.name" placeholder="请输入门禁名称"></el-input>
        </el-form-item>
        <el-form-item label="区域" required>
          <el-input v-model="formData.area" placeholder="请输入区域"></el-input>
        </el-form-item>
        <el-form-item label="位置" required>
          <el-input v-model="formData.location" placeholder="请输入具体位置"></el-input>
        </el-form-item>
        <el-form-item label="状态" required>
          <el-select v-model="formData.status" placeholder="请选择状态">
            <el-option label="正常" value="1"></el-option>
            <el-option label="异常" value="0"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="formData.description" type="textarea" rows="3" placeholder="请输入描述信息"></el-input>
        </el-form-item>
      <div class="table_list">
        <PIMTable rowKey="id" :column="vehicleColumns" :tableData="tableData" :page="page" :isSelection="true"
          @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"></PIMTable>
      </div>
    </template>
    <!-- 设备故障 -->
    <template v-else>
      <div class="search_form">
        <div>
          <span class="search_title">设备台账ID:</span>
          <el-input v-model="defectSearch.deviceLedgerId" style="width: 200px" placeholder="请输入" clearable @change="handleQuery" />
          <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button>
        </div>
        <div>
          <el-button type="primary" @click="openDefect('add')">新增</el-button>
          <el-button type="danger" plain @click="handleDelete">删除</el-button>
        </div>
      </div>
      <div class="table_list">
        <PIMTable rowKey="id" :column="defectColumns" :tableData="tableData" :page="page" :isSelection="true"
          @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"></PIMTable>
      </div>
    </template>
    <!-- 车辆弹窗 -->
    <el-dialog v-model="dialogVisible" :title="operationType === 'add' ? '新增' : '编辑'" width="60%" @close="closeDia">
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12"><el-form-item label="车牌/机械编号:" prop="plateNo"><el-input v-model="form.plateNo" placeholder="请输入" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="车辆/机械型号:" prop="vehicleModel"><el-input v-model="form.vehicleModel" placeholder="请输入" /></el-form-item></el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12"><el-form-item label="使用人:" prop="driverName"><el-input v-model="form.driverName" placeholder="请输入" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="联系电话:" prop="driverPhone"><el-input v-model="form.driverPhone" placeholder="请输入" /></el-form-item></el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12"><el-form-item label="用途:" prop="usePurpose"><el-input v-model="form.usePurpose" placeholder="请输入" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="时间:" prop="occurTime">
            <el-date-picker v-model="form.occurTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="请选择" style="width:100%" />
          </el-form-item></el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12" v-if="activeTab === '1'"><el-form-item label="方向:" prop="direction">
            <el-select v-model="form.direction" placeholder="请选择" style="width:100%">
              <el-option label="进厂" :value="1" /><el-option label="出厂" :value="0" />
            </el-select>
          </el-form-item></el-col>
          <el-col :span="12"><el-form-item label="状态:" prop="status"><el-input v-model="form.status" placeholder="请输入" /></el-form-item></el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24"><el-form-item label="备注:" prop="remark"><el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" /></el-form-item></el-col>
        </el-row>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="saveData">确定</el-button>
        </span>
        <el-button type="primary" @click="submitForm">确认</el-button>
        <el-button @click="closeDia">取消</el-button>
      </template>
    </el-dialog>
    <!-- 设备故障弹窗 -->
    <el-dialog v-model="defectVisible" :title="defectType === 'add' ? '新增设备故障' : '编辑设备故障'" width="50%">
      <el-form :model="defectForm" label-width="140px" label-position="top">
        <el-form-item label="设备台账ID:"><el-input-number v-model="defectForm.deviceLedgerId" :min="0" style="width:100%" /></el-form-item>
        <el-form-item label="缺陷描述:"><el-input v-model="defectForm.defectDescription" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="defectForm.status" style="width:100%">
            <el-option label="未消除" value="0" /><el-option label="已消除" value="1" />
          </el-select>
        </el-form-item>
        <el-form-item label="消除时间:"><el-date-picker v-model="defectForm.eliminateTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width:100%" /></el-form-item>
      </el-form>
      <template #footer>
        <el-button type="primary" @click="submitDefect">确认</el-button>
        <el-button @click="defectVisible = false">取消</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue';
import { Search, Plus, Delete } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import dayjs from 'dayjs';
import { Search } from "@element-plus/icons-vue";
import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue";
import { ElMessageBox } from "element-plus";
import {
  listVehicle, addVehicle, updateVehicle, deleteVehicle,
  listDefect, addDefect, updateDefect, deleteDefect,
} from "@/api/environmentAccess/accessVehicle.js";
// 定义假数据
const mockData = [
  { id: 1, name: '东门门禁', area: '生产区', location: '东门入口', status: '1', lastUpdate: '2025-12-30 08:30:00', description: '主要用于员工上下班通行' },
  { id: 2, name: '西门门禁', area: '仓储区', location: '西门入口', status: '1', lastUpdate: '2025-12-30 09:15:00', description: '主要用于物流车辆通行' },
  { id: 3, name: '南门门禁', area: '办公区', location: '南门入口', status: '0', lastUpdate: '2025-12-30 10:20:00', description: '主要用于访客通行,当前故障' },
  { id: 4, name: '北门门禁', area: '生产区', location: '北门入口', status: '1', lastUpdate: '2025-12-30 11:45:00', description: '主要用于原材料运输车辆通行' },
  { id: 5, name: '中控室门禁', area: '中控区', location: '中控室门口', status: '1', lastUpdate: '2025-12-30 13:20:00', description: '仅限授权人员进入' },
];
const { proxy } = getCurrentInstance();
const activeTab = ref("1");
// 响应式数据
const filters = reactive({
  name: '',
  status: '',
  area: ''
});
const dirText = (d) => (d == 1 ? "进厂" : d == 0 ? "出厂" : "");
const defectStatusText = (s) => (s == 0 ? "未消除" : s == 1 ? "已消除" : (s ?? ""));
const dataList = ref([]);
const pagination = reactive({
  currentPage: 1,
  pageSize: 10,
  total: 0
});
const vehicleColumns = ref([
  { label: "车牌/机械编号", prop: "plateNo" },
  { label: "车辆/机械型号", prop: "vehicleModel" },
  { label: "使用人", prop: "driverName" },
  { label: "联系电话", prop: "driverPhone", width: 140 },
  { label: "用途", prop: "usePurpose" },
  { label: "时间", prop: "occurTime", width: 170 },
  { label: "方向", prop: "direction", width: 80, dataType: "tag", formatData: (p) => dirText(p), formatType: () => "primary" },
  { label: "状态", prop: "status", width: 90 },
  { label: "备注", prop: "remark", showOverflowTooltip: true },
  {
    dataType: "action", label: "操作", align: "center", fixed: "right", width: 100,
    operation: [{ name: "编辑", type: "text", clickFun: (row) => openForm("edit", row) }],
  },
]);
const multipleList = ref([]);
const defectColumns = ref([
  { label: "设备台账ID", prop: "deviceLedgerId", width: 120 },
  { label: "缺陷描述", prop: "defectDescription", showOverflowTooltip: true },
  { label: "状态", prop: "status", width: 100, dataType: "tag", formatData: (p) => defectStatusText(p), formatType: (p) => (p == 1 ? "success" : "danger") },
  { label: "消除时间", prop: "eliminateTime", width: 170 },
  { label: "创建时间", prop: "createTime", width: 170 },
  {
    dataType: "action", label: "操作", align: "center", fixed: "right", width: 100,
    operation: [{ name: "编辑", type: "text", clickFun: (row) => openDefect("edit", row) }],
  },
]);
const data = reactive({ searchForm: { plateNo: "", driverName: "", dateRange: [], entryDateStart: "", entryDateEnd: "" } });
const { searchForm } = toRefs(data);
const defectSearch = ref({ deviceLedgerId: "" });
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({ current: 1, size: 100, total: 0 });
// 车辆弹窗
const dialogVisible = ref(false);
const dialogTitle = ref('新增门禁');
const formData = reactive({
  id: '',
  name: '',
  area: '',
  location: '',
  status: '1',
  description: ''
});
const operationType = ref("add");
const formRef = ref();
const form = ref({});
const rules = { plateNo: [{ required: true, message: "请输入车牌/机械编号", trigger: "blur" }] };
// 表格列配置
const columns = [
  {
    label: '门禁名称',
    align: 'center',
    prop: 'name',
  },
  {
    label: '区域',
    align: 'center',
    prop: 'area',
  },
  {
    label: '位置',
    align: 'center',
    prop: 'location',
  },
  {
    label: '状态',
    align: 'center',
    prop: 'status',
    formatter: (row) => {
      return row.status === '1' ? '<el-tag type="success">正常</el-tag>' : '<el-tag type="danger">异常</el-tag>';
    }
  },
  {
    label: '最后更新',
    align: 'center',
    prop: 'lastUpdate',
  },
  {
    label: '描述',
    align: 'center',
    prop: 'description',
  },
  {
    dataType: 'action',
    label: '操作',
    align: 'center',
    fixed: 'right',
    width: 140,
    operation: [
      {
        name: '编辑',
        type: 'text',
        clickFun: (row) => {
          edit(row);
        },
      },
      {
        name: '删除',
        type: 'text',
        clickFun: (row) => {
          deleteRow(row.id);
        },
      },
    ],
  },
];
// 故障弹窗
const defectVisible = ref(false);
const defectType = ref("add");
const defectForm = ref({});
// 过滤后的数据
const filteredData = computed(() => {
  return mockData.filter(item => {
    const nameMatch = !filters.name || item.name.includes(filters.name);
    const statusMatch = !filters.status || item.status === filters.status;
    const areaMatch = !filters.area || item.area.includes(filters.area);
    return nameMatch && statusMatch && areaMatch;
  });
});
// 获取表格数据
const getTableData = () => {
  pagination.total = filteredData.value.length;
  const start = (pagination.currentPage - 1) * pagination.pageSize;
  const end = start + pagination.pageSize;
  dataList.value = filteredData.value.slice(start, end);
const changeRange = (v) => {
  searchForm.value.entryDateStart = v?.[0] || "";
  searchForm.value.entryDateEnd = v?.[1] || "";
  getList();
};
const handleTabChange = () => { page.current = 1; getList(); };
const handleQuery = () => { page.current = 1; getList(); };
const pagination = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); };
const handleSelectionChange = (s) => { selectedRows.value = s; };
// 重置过滤器
const resetFilters = () => {
  filters.name = '';
  filters.status = '';
  filters.area = '';
  pagination.currentPage = 1;
  getTableData();
};
// 分页变化
const changePage = ({ page, limit }) => {
  pagination.currentPage = page;
  pagination.pageSize = limit;
  getTableData();
};
// 多选处理
const handleSelectionChange = (selectionList) => {
  multipleList.value = selectionList;
};
// 新增
const add = () => {
  dialogTitle.value = '新增门禁';
  formData.id = '';
  formData.name = '';
  formData.area = '';
  formData.location = '';
  formData.status = '1';
  formData.description = '';
  dialogVisible.value = true;
};
// 编辑
const edit = (row) => {
  dialogTitle.value = '编辑门禁';
  formData.id = row.id;
  formData.name = row.name;
  formData.area = row.area;
  formData.location = row.location;
  formData.status = row.status;
  formData.description = row.description;
  dialogVisible.value = true;
};
// 保存数据
const saveData = () => {
  if (!formData.name || !formData.area || !formData.location) {
    ElMessage.warning('请填写必填字段');
    return;
  }
  const currentTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
  if (formData.id) {
    // 编辑
    const index = mockData.findIndex(item => item.id === formData.id);
    if (index !== -1) {
      mockData[index] = {
        ...formData,
        lastUpdate: currentTime
      };
      ElMessage.success('编辑成功');
    }
const getList = () => {
  tableLoading.value = true;
  if (activeTab.value === "defect") {
    listDefect({ ...defectSearch.value, ...page }).then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
      page.total = res.data.total;
    }).catch(() => { tableLoading.value = false; });
  } else {
    // 新增
    const newId = Math.max(...mockData.map(item => item.id), 0) + 1;
    mockData.unshift({
      ...formData,
      id: newId,
      lastUpdate: currentTime
    });
    ElMessage.success('新增成功');
    const p = { ...searchForm.value, vehicleType: Number(activeTab.value), ...page };
    delete p.dateRange;
    listVehicle(p).then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
      page.total = res.data.total;
    }).catch(() => { tableLoading.value = false; });
  }
  dialogVisible.value = false;
  getTableData();
};
// 删除
const deleteRow = (id) => {
  ElMessageBox.confirm('此操作将永久删除该门禁记录, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    const index = mockData.findIndex(item => item.id === id);
    if (index !== -1) {
      mockData.splice(index, 1);
      ElMessage.success('删除成功');
      getTableData();
    }
  }).catch(() => {});
const openForm = (type, row) => {
  operationType.value = type;
  form.value = type === "add" ? { vehicleType: Number(activeTab.value) } : { ...row };
  dialogVisible.value = true;
};
const closeDia = () => { proxy.resetForm("formRef"); dialogVisible.value = false; };
const submitForm = () => {
  formRef.value.validate((valid) => {
    if (!valid) return;
    form.value.vehicleType = Number(activeTab.value);
    const p = operationType.value === "add" ? addVehicle(form.value) : updateVehicle(form.value);
    p.then(() => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); });
  });
};
// 批量删除
const batchDelete = () => {
  if (multipleList.value.length === 0) {
    ElMessage.warning('请选择要删除的数据');
    return;
  }
  ElMessageBox.confirm('此操作将永久删除所选门禁记录, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    const ids = multipleList.value.map(item => item.id);
    mockData.forEach((item, index) => {
      if (ids.includes(item.id)) {
        mockData.splice(index, 1);
      }
    });
    ElMessage.success('删除成功');
    getTableData();
    multipleList.value = [];
  }).catch(() => {});
const openDefect = (type, row) => {
  defectType.value = type;
  defectForm.value = type === "add" ? { status: "0" } : { ...row };
  defectVisible.value = true;
};
const submitDefect = () => {
  const p = defectType.value === "add" ? addDefect(defectForm.value) : updateDefect(defectForm.value);
  p.then(() => { proxy.$modal.msgSuccess("提交成功"); defectVisible.value = false; getList(); });
};
// 初始化数据
onMounted(() => {
  getTableData();
});
const handleDelete = () => {
  if (!selectedRows.value.length) { proxy.$modal.msgWarning("请选择数据"); return; }
  const ids = selectedRows.value.map((i) => i.id);
  ElMessageBox.confirm("是否确认删除?", "删除", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning" })
    .then(() => {
      const p = activeTab.value === "defect" ? deleteDefect(ids) : deleteVehicle(ids);
      p.then(() => { proxy.$modal.msgSuccess("删除成功"); getList(); });
    }).catch(() => {});
};
onMounted(() => { getList(); });
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
<style scoped lang="scss">
.ml10 { margin-left: 10px; }
.table_list { margin-top: unset; }
</style>