feat(生产排产): 新增车间、班组、排产管理模块并联动工单报工;修复空path菜单导致的路由注册报错
已修改4个文件
已添加6个文件
1359 ■■■■■ 文件已修改
index.html 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionScheduling/scheduling.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionScheduling/team.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionScheduling/workshop.js 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrderManagement/index.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionScheduling/schedulingManage/index.vue 462 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionScheduling/teamManage/index.vue 375 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionScheduling/workshopManage/index.vue 308 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html
@@ -11,9 +11,9 @@
    <link rel="icon" href="/favicon.ico" />
    <title>%VITE_APP_TITLE%</title>
    <!-- é«˜å¾·åœ°å›¾API -->
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
    <script type="text/javascript" defer src="https://webapi.amap.com/maps?v=2.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
    <!-- é«˜å¾·åœ°å›¾æœç´¢æ’ä»¶ -->
    <script type="text/javascript" src="https://webapi.amap.com/loca?v=2.0.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
    <script type="text/javascript" defer src="https://webapi.amap.com/loca?v=2.0.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
    <!--[if lt IE 11
      ]><script>
        window.location.href = "/html/ie.html";
src/api/productionScheduling/scheduling.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
// ç”Ÿäº§æŽ’班接口
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function listPage(query) {
  return request({
    url: "/productionScheduling/page",
    method: "get",
    params: query,
  });
}
// æŸ¥è¯¢ç­ç»„今日排班
export function today(teamId) {
  return request({
    url: "/productionScheduling/today",
    method: "get",
    params: { teamId },
  });
}
export function add(data) {
  return request({
    url: "/productionScheduling",
    method: "post",
    data: data,
  });
}
export function update(data) {
  return request({
    url: "/productionScheduling",
    method: "put",
    data: data,
  });
}
export function del(ids) {
  return request({
    url: `/productionScheduling/${ids}`,
    method: "delete",
  });
}
src/api/productionScheduling/team.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
// ç­ç»„管理接口
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function listPage(query) {
  return request({
    url: "/productionTeam/page",
    method: "get",
    params: query,
  });
}
// æŸ¥è¯¢å…¨éƒ¨ç­ç»„(下拉用,可按车间过滤)
export function listAll(workshopId) {
  return request({
    url: "/productionTeam/listAll",
    method: "get",
    params: { workshopId },
  });
}
export function add(data) {
  return request({
    url: "/productionTeam",
    method: "post",
    data: data,
  });
}
export function update(data) {
  return request({
    url: "/productionTeam",
    method: "put",
    data: data,
  });
}
export function del(ids) {
  return request({
    url: `/productionTeam/${ids}`,
    method: "delete",
  });
}
src/api/productionScheduling/workshop.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
// è½¦é—´ç®¡ç†æŽ¥å£
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function listPage(query) {
  return request({
    url: "/workshop/page",
    method: "get",
    params: query,
  });
}
// æŸ¥è¯¢å…¨éƒ¨è½¦é—´ï¼ˆä¸‹æ‹‰ç”¨ï¼‰
export function listAll() {
  return request({
    url: "/workshop/listAll",
    method: "get",
  });
}
export function add(data) {
  return request({
    url: "/workshop",
    method: "post",
    data: data,
  });
}
export function update(data) {
  return request({
    url: "/workshop",
    method: "put",
    data: data,
  });
}
export function del(ids) {
  return request({
    url: `/workshop/${ids}`,
    method: "delete",
  });
}
src/permission.js
@@ -36,7 +36,8 @@
          usePermissionStore().generateRoutes().then(accessRoutes => {
            // æ ¹æ®roles权限生成可访问的路由表
            accessRoutes.forEach(route => {
              if (!isHttp(route.path)) {
              // åŽç«¯èœå•数据缺失 path æ—¶ï¼ˆå¦‚ä»…å¡« https:// çš„内链菜单)跳过,避免 addRoute æŠ›é”™å¡æ­»æ•´ä¸ªç™»å½•流程
              if (route.path && !isHttp(route.path)) {
                router.addRoute(route) // åŠ¨æ€æ·»åŠ å¯è®¿é—®è·¯ç”±è¡¨
              }
            })
src/store/modules/permission.js
@@ -36,9 +36,10 @@
        return new Promise(resolve => {
          // å‘后端请求路由数据
          getRouters().then(res => {
            const sdata = JSON.parse(JSON.stringify(res.data))
            const rdata = JSON.parse(JSON.stringify(res.data))
            const defaultData = JSON.parse(JSON.stringify(res.data))
            const data = filterBadRoutes(JSON.parse(JSON.stringify(res.data)))
            const sdata = JSON.parse(JSON.stringify(data))
            const rdata = JSON.parse(JSON.stringify(data))
            const defaultData = JSON.parse(JSON.stringify(data))
            const sidebarRoutes = filterAsyncRouter(sdata)
            const rewriteRoutes = filterAsyncRouter(rdata, false, true)
            const defaultRoutes = filterAsyncRouter(defaultData)
@@ -55,6 +56,19 @@
    }
  })
// å‰”除后端返回的无 path èœå•(如地址只填 https:// çš„内链菜单),避免 addRoute ä¸Žä¾§è¾¹æ æ¸²æŸ“报错
function filterBadRoutes(routes) {
  return routes.filter(route => {
    if (!route.path) {
      return false
    }
    if (route.children && route.children.length) {
      route.children = filterBadRoutes(route.children)
    }
    return true
  })
}
// éåŽ†åŽå°ä¼ æ¥çš„è·¯ç”±å­—ç¬¦ä¸²ï¼Œè½¬æ¢ä¸ºç»„ä»¶å¯¹è±¡
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
  return asyncRouterMap.filter(route => {
src/views/productionManagement/workOrderManagement/index.vue
@@ -142,17 +142,21 @@
                    @input="handleScrapQtyInput" />
        </el-form-item>
        <el-form-item label="班组信息">
          <el-select v-model="reportForm.userId"
          <el-select v-model="reportForm.teamId"
                     style="width: 300px"
                     placeholder="请选择班组信息"
                     clearable
                     filterable
                     @change="handleUserChange">
            <el-option v-for="user in userOptions"
                       :key="user.userId"
                       :label="user.nickName"
                       :value="user.userId" />
                     @change="handleTeamChange">
            <el-option v-for="team in teamOptions"
                       :key="team.id"
                       :label="team.teamName"
                       :value="team.id" />
          </el-select>
          <div v-if="teamScheduleText"
               style="width: 300px; margin-top: 5px; color: #909399; font-size: 12px; line-height: 1.5;">
            {{ teamScheduleText }}
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
@@ -172,12 +176,15 @@
  import { onMounted, ref, nextTick } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  import { useDict } from "@/utils/dict.js";
  import {
    productWorkOrderPage,
    addProductMain,
    downProductWorkOrder,
  } from "@/api/productionManagement/workOrder.js";
  import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
  import { getUserProfile } from "@/api/system/user.js";
  import { listAll as teamListAll } from "@/api/productionScheduling/team.js";
  import { today as getTeamToday } from "@/api/productionScheduling/scheduling.js";
  import QRCode from "qrcode";
  import { getCurrentInstance, reactive, toRefs } from "vue";
  import FilesDia from "./components/filesDia.vue";
@@ -292,7 +299,9 @@
  const reportDialogVisible = ref(false);
  const workOrderFilesRef = ref(null);
  const reportFormRef = ref(null);
  const userOptions = ref([]);
  const teamOptions = ref([]);
  const teamScheduleText = ref("");
  const { shift_type, schedule_status } = useDict("shift_type", "schedule_status");
  const reportForm = reactive({
    planQuantity: 0,
    quantity: null,
@@ -302,6 +311,7 @@
    reportWork: "",
    productProcessRouteItemId: "",
    userId: "",
    teamId: null,
    productMainId: null,
  });
@@ -529,6 +539,8 @@
    reportForm.productMainId = row.productMainId;
    reportForm.scrapQty =
      row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
    reportForm.teamId = null;
    teamScheduleText.value = "";
    nextTick(() => {
      reportFormRef.value?.clearValidate();
    });
@@ -629,18 +641,33 @@
    });
  };
  const handleUserChange = val => {
    const user = userOptions.value.find(item => item.userId === val);
    reportForm.userName = user ? user.nickName : "";
  const handleTeamChange = val => {
    teamScheduleText.value = "";
    if (!val) return;
    // é€‰ä¸­ç­ç»„后,报工人默认为班组长
    const team = teamOptions.value.find(item => item.id === val);
    if (team && team.leaderUserId) {
      reportForm.userId = team.leaderUserId;
      reportForm.userName = team.leaderName;
    }
    // å±•示该班组今日排班信息
    getTeamToday(val).then(res => {
      const schedule = res.data;
      if (schedule && schedule.shiftType !== null && schedule.shiftType !== undefined) {
        const shift = shift_type.value.find(item => item.value === String(schedule.shiftType));
        const status = schedule_status.value.find(item => item.value === String(schedule.status));
        teamScheduleText.value = `今日排班:${shift ? shift.label : ""}${status ? "(" + status.label + ")" : ""}`;
      } else {
        teamScheduleText.value = "今日未排班";
      }
    });
  };
  onMounted(() => {
    getList();
    // èŽ·å–ç”¨æˆ·åˆ—è¡¨
    userListNoPageByTenantId().then(res => {
      if (res.code === 200) {
        userOptions.value = res.data;
      }
    // èŽ·å–ç­ç»„åˆ—è¡¨
    teamListAll().then(res => {
      teamOptions.value = res.data || [];
    });
  });
</script>
src/views/productionScheduling/schedulingManage/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,462 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
        <el-form-item label="工作日期:">
          <el-date-picker v-model="searchForm.dateRange"
                          type="daterange"
                          range-separator="至"
                          start-placeholder="开始日期"
                          end-placeholder="结束日期"
                          format="YYYY-MM-DD"
                          value-format="YYYY-MM-DD"
                          style="width: 260px;"
                          @change="handleQuery" />
        </el-form-item>
        <el-form-item label="所属车间:">
          <el-select v-model="searchForm.workshopId"
                     placeholder="请选择"
                     clearable
                     style="width: 180px;"
                     @change="handleSearchWorkshopChange">
            <el-option v-for="item in workshopOptions"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="班组:">
          <el-select v-model="searchForm.teamId"
                     placeholder="请选择"
                     clearable
                     style="width: 180px;"
                     @change="handleQuery">
            <el-option v-for="item in searchTeamOptions"
                       :key="item.id"
                       :label="item.teamName"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="searchForm.status"
                     placeholder="请选择"
                     clearable
                     style="width: 140px;"
                     @change="handleQuery">
            <el-option v-for="item in schedule_status"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <div style="text-align: right"
           class="mb10">
        <el-button type="primary"
                   @click="showNewModal">新增排班</el-button>
        <el-button type="danger"
                   plain
                   :disabled="selectedRows.length === 0"
                   @click="handleDelete">删除排班</el-button>
      </div>
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                :tableLoading="tableLoading"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        <template #shiftType="{ row }">
          <el-tag :type="shiftTag(row.shiftType)">
            {{ shiftLabel(row.shiftType) }}
          </el-tag>
        </template>
        <template #status="{ row }">
          <el-tag :type="statusTag(row.status)">
            {{ statusLabel(row.status) }}
          </el-tag>
        </template>
      </PIMTable>
    </div>
    <!-- æ–°å¢ž/编辑弹窗 -->
    <el-dialog v-model="dialogVisible"
               :title="form.id ? '编辑排班' : '新增排班'"
               width="600px">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="100px">
        <el-form-item label="工作日期"
                      prop="workDate">
          <el-date-picker v-model="form.workDate"
                          type="date"
                          placeholder="请选择工作日期"
                          format="YYYY-MM-DD"
                          value-format="YYYY-MM-DD"
                          style="width: 100%;" />
        </el-form-item>
        <el-form-item label="班次"
                      prop="shiftType">
          <el-select v-model="form.shiftType"
                     placeholder="请选择班次"
                     style="width: 100%;">
            <el-option v-for="item in shift_type"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="所属车间"
                      prop="workshopId">
          <el-select v-model="form.workshopId"
                     placeholder="请选择所属车间"
                     style="width: 100%;"
                     @change="handleFormWorkshopChange">
            <el-option v-for="item in workshopOptions"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="班组"
                      prop="teamId">
          <el-select v-model="form.teamId"
                     placeholder="请选择班组"
                     style="width: 100%;">
            <el-option v-for="item in formTeamOptions"
                       :key="item.id"
                       :label="item.teamName"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态"
                      prop="status">
          <el-select v-model="form.status"
                     placeholder="请选择状态"
                     style="width: 100%;">
            <el-option v-for="item in schedule_status"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="form.remark"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入备注"
                    maxlength="500" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     @click="handleSubmit">确定</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
  import {
    onMounted,
    ref,
    reactive,
    computed,
    getCurrentInstance,
  } from "vue";
  import dayjs from "dayjs";
  import { useDict } from "@/utils/dict.js";
  import {
    listPage,
    add,
    update,
    del,
  } from "@/api/productionScheduling/scheduling.js";
  import { listAll as workshopListAll } from "@/api/productionScheduling/workshop.js";
  import { listAll as teamListAll } from "@/api/productionScheduling/team.js";
  const { proxy } = getCurrentInstance();
  // å­—å…¸
  const { shift_type, schedule_status } = useDict("shift_type", "schedule_status");
  const findDictItem = (dict, val) => {
    return dict.value.find(item => item.value === String(val));
  };
  const shiftLabel = val => {
    const item = findDictItem(shift_type, val);
    return item ? item.label : val;
  };
  const shiftTag = val => {
    const item = findDictItem(shift_type, val);
    return item ? item.elTagType : "info";
  };
  const statusLabel = val => {
    const item = findDictItem(schedule_status, val);
    return item ? item.label : val;
  };
  const statusTag = val => {
    const item = findDictItem(schedule_status, val);
    return item ? item.elTagType : "info";
  };
  const tableColumn = ref([
    {
      label: "工作日期",
      prop: "workDate",
      width: "120",
    },
    {
      label: "班次",
      prop: "shiftType",
      dataType: "slot",
      slot: "shiftType",
      width: "100",
    },
    {
      label: "所属车间",
      prop: "workshopName",
      width: "140",
    },
    {
      label: "班组",
      prop: "teamName",
      width: "140",
    },
    {
      label: "状态",
      prop: "status",
      dataType: "slot",
      slot: "status",
      width: "100",
    },
    {
      label: "备注",
      prop: "remark",
    },
    {
      label: "更新时间",
      prop: "updateTime",
      width: "160",
    },
    {
      dataType: "action",
      label: "操作",
      align: "center",
      fixed: "right",
      width: 100,
      operation: [
        {
          name: "编辑",
          type: "text",
          clickFun: row => {
            showEditModal(row);
          },
        },
      ],
    },
  ]);
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const dialogVisible = ref(false);
  const formRef = ref(null);
  const workshopOptions = ref([]);
  const allTeams = ref([]);
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
  const data = reactive({
    searchForm: {
      dateRange: [],
      workshopId: null,
      teamId: null,
      status: null,
    },
  });
  const { searchForm } = data;
  const form = reactive({
    id: null,
    workDate: "",
    shiftType: "",
    workshopId: null,
    teamId: null,
    status: "1",
    remark: "",
  });
  const rules = {
    workDate: [{ required: true, message: "请选择工作日期", trigger: "change" }],
    shiftType: [{ required: true, message: "请选择班次", trigger: "change" }],
    workshopId: [{ required: true, message: "请选择所属车间", trigger: "change" }],
    teamId: [{ required: true, message: "请选择班组", trigger: "change" }],
  };
  // æœç´¢ç­ç»„下拉:按所选车间联动
  const searchTeamOptions = computed(() => {
    if (searchForm.workshopId) {
      return allTeams.value.filter(item => item.workshopId === searchForm.workshopId);
    }
    return allTeams.value;
  });
  // å¼¹çª—班组下拉:按所选车间联动
  const formTeamOptions = computed(() => {
    if (form.workshopId) {
      return allTeams.value.filter(item => item.workshopId === form.workshopId);
    }
    return allTeams.value;
  });
  /** æœç´¢æŒ‰é’®æ“ä½œ */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const handleSearchWorkshopChange = () => {
    searchForm.teamId = null;
    handleQuery();
  };
  const handleFormWorkshopChange = () => {
    form.teamId = null;
  };
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const getList = () => {
    tableLoading.value = true;
    const { dateRange, ...rest } = searchForm;
    const params = {
      ...rest,
      ...(dateRange && dateRange.length === 2
        ? { startDate: dateRange[0], endDate: dateRange[1] }
        : {}),
      ...page,
    };
    listPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(() => {
        tableLoading.value = false;
      });
  };
  // è¡¨æ ¼é€‰æ‹©æ•°æ®
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  const resetForm = () => {
    form.id = null;
    form.workDate = dayjs().format("YYYY-MM-DD");
    form.shiftType = "";
    form.workshopId = null;
    form.teamId = null;
    form.status = "1";
    form.remark = "";
  };
  // æ‰“开新增弹框
  const showNewModal = () => {
    resetForm();
    dialogVisible.value = true;
  };
  const showEditModal = row => {
    resetForm();
    form.id = row.id;
    form.workDate = row.workDate;
    form.shiftType = row.shiftType !== null && row.shiftType !== undefined ? String(row.shiftType) : "";
    form.workshopId = row.workshopId;
    form.teamId = row.teamId;
    form.status = row.status !== null && row.status !== undefined ? String(row.status) : "1";
    form.remark = row.remark;
    dialogVisible.value = true;
  };
  const handleSubmit = () => {
    formRef.value.validate(valid => {
      if (!valid) return;
      const payload = {
        id: form.id,
        workDate: form.workDate,
        shiftType: form.shiftType !== "" ? Number(form.shiftType) : null,
        workshopId: form.workshopId,
        teamId: form.teamId,
        status: form.status !== "" ? Number(form.status) : null,
        remark: form.remark,
      };
      const request = payload.id ? update(payload) : add(payload);
      request.then(() => {
        proxy.$modal.msgSuccess(payload.id ? "修改成功" : "新增成功");
        dialogVisible.value = false;
        getList();
      });
    });
  };
  // æ‰¹é‡åˆ é™¤
  const handleDelete = () => {
    const rows = selectedRows.value;
    const ids = rows.map(item => item.id);
    const firstDesc = `${rows[0].workDate} ${rows[0].teamName || ""}`;
    proxy.$modal
      .confirm(
        `是否确认删除"${firstDesc}"${rows.length > 1 ? `等${rows.length}条数据` : ""}?`
      )
      .then(function () {
        return del(ids.join(","));
      })
      .then(() => {
        getList();
        proxy.$modal.msgSuccess("删除成功");
      })
      .catch(() => {});
  };
  const getWorkshopOptions = () => {
    workshopListAll().then(res => {
      workshopOptions.value = res.data || [];
    });
  };
  const getTeamOptions = () => {
    teamListAll().then(res => {
      allTeams.value = res.data || [];
    });
  };
  onMounted(() => {
    getList();
    getWorkshopOptions();
    getTeamOptions();
  });
</script>
<style scoped></style>
src/views/productionScheduling/teamManage/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,375 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
        <el-form-item label="班组名称:">
          <el-input v-model="searchForm.teamName"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 200px;"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="所属车间:">
          <el-select v-model="searchForm.workshopId"
                     placeholder="请选择"
                     clearable
                     style="width: 200px;"
                     @change="handleQuery">
            <el-option v-for="item in workshopOptions"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="searchForm.status"
                     placeholder="请选择"
                     clearable
                     style="width: 160px;"
                     @change="handleQuery">
            <el-option v-for="item in statusOptions"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <div style="text-align: right"
           class="mb10">
        <el-button type="primary"
                   @click="showNewModal">新增班组</el-button>
        <el-button type="danger"
                   plain
                   :disabled="selectedRows.length === 0"
                   @click="handleDelete">删除班组</el-button>
      </div>
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                :tableLoading="tableLoading"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        <template #status="{ row }">
          <el-tag :type="row.status === 0 ? 'success' : 'info'">
            {{ row.status === 0 ? "启用" : "停用" }}
          </el-tag>
        </template>
      </PIMTable>
    </div>
    <!-- æ–°å¢ž/编辑弹窗 -->
    <el-dialog v-model="dialogVisible"
               :title="form.id ? '编辑班组' : '新增班组'"
               width="600px">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="100px">
        <el-form-item label="班组名称"
                      prop="teamName">
          <el-input v-model="form.teamName"
                    placeholder="请输入班组名称"
                    maxlength="100" />
        </el-form-item>
        <el-form-item label="班组编码"
                      prop="teamCode">
          <el-input v-model="form.teamCode"
                    placeholder="请输入班组编码"
                    maxlength="50" />
        </el-form-item>
        <el-form-item label="所属车间"
                      prop="workshopId">
          <el-select v-model="form.workshopId"
                     placeholder="请选择所属车间"
                     style="width: 100%;">
            <el-option v-for="item in workshopOptions"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="班组长"
                      prop="leaderUserId">
          <el-select v-model="form.leaderUserId"
                     placeholder="请选择班组长"
                     clearable
                     filterable
                     style="width: 100%;"
                     @change="handleLeaderChange">
            <el-option v-for="item in userOptions"
                       :key="item.userId"
                       :label="item.nickName"
                       :value="item.userId" />
          </el-select>
        </el-form-item>
        <el-form-item label="联系电话"
                      prop="contactPhone">
          <el-input v-model="form.contactPhone"
                    placeholder="请输入联系电话"
                    maxlength="20" />
        </el-form-item>
        <el-form-item label="状态"
                      prop="status">
          <el-radio-group v-model="form.status">
            <el-radio v-for="item in statusOptions"
                      :key="item.value"
                      :value="item.value">{{ item.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="form.remark"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入备注"
                    maxlength="500" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     @click="handleSubmit">确定</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
  import { onMounted, ref, reactive, getCurrentInstance } from "vue";
  import {
    listPage,
    add,
    update,
    del,
  } from "@/api/productionScheduling/team.js";
  import { listAll as workshopListAll } from "@/api/productionScheduling/workshop.js";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
  const { proxy } = getCurrentInstance();
  const statusOptions = [
    { label: "启用", value: 0 },
    { label: "停用", value: 1 },
  ];
  const tableColumn = ref([
    {
      label: "班组名称",
      prop: "teamName",
    },
    {
      label: "班组编码",
      prop: "teamCode",
      width: "120",
    },
    {
      label: "所属车间",
      prop: "workshopName",
      width: "140",
    },
    {
      label: "班组长",
      prop: "leaderName",
      width: "100",
    },
    {
      label: "联系电话",
      prop: "contactPhone",
      width: "140",
    },
    {
      label: "状态",
      prop: "status",
      dataType: "slot",
      slot: "status",
      width: "90",
    },
    {
      label: "备注",
      prop: "remark",
    },
    {
      label: "更新时间",
      prop: "updateTime",
      width: "160",
    },
    {
      dataType: "action",
      label: "操作",
      align: "center",
      fixed: "right",
      width: 100,
      operation: [
        {
          name: "编辑",
          type: "text",
          clickFun: row => {
            showEditModal(row);
          },
        },
      ],
    },
  ]);
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const dialogVisible = ref(false);
  const formRef = ref(null);
  const workshopOptions = ref([]);
  const userOptions = ref([]);
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
  const data = reactive({
    searchForm: {
      teamName: "",
      workshopId: null,
      status: null,
    },
  });
  const { searchForm } = data;
  const form = reactive({
    id: null,
    teamName: "",
    teamCode: "",
    workshopId: null,
    leaderUserId: null,
    leaderName: "",
    contactPhone: "",
    status: 0,
    remark: "",
  });
  const rules = {
    teamName: [{ required: true, message: "请输入班组名称", trigger: "blur" }],
    workshopId: [{ required: true, message: "请选择所属车间", trigger: "change" }],
  };
  /** æœç´¢æŒ‰é’®æ“ä½œ */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm, ...page };
    listPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(() => {
        tableLoading.value = false;
      });
  };
  // è¡¨æ ¼é€‰æ‹©æ•°æ®
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  const resetForm = () => {
    form.id = null;
    form.teamName = "";
    form.teamCode = "";
    form.workshopId = null;
    form.leaderUserId = null;
    form.leaderName = "";
    form.contactPhone = "";
    form.status = 0;
    form.remark = "";
  };
  // æ‰“开新增弹框
  const showNewModal = () => {
    resetForm();
    dialogVisible.value = true;
  };
  const showEditModal = row => {
    resetForm();
    Object.assign(form, JSON.parse(JSON.stringify(row)));
    dialogVisible.value = true;
  };
  const handleLeaderChange = val => {
    const user = userOptions.value.find(item => item.userId === val);
    form.leaderName = user ? user.nickName : "";
  };
  const handleSubmit = () => {
    formRef.value.validate(valid => {
      if (!valid) return;
      const request = form.id ? update(form) : add(form);
      request.then(() => {
        proxy.$modal.msgSuccess(form.id ? "修改成功" : "新增成功");
        dialogVisible.value = false;
        getList();
      });
    });
  };
  // æ‰¹é‡åˆ é™¤
  const handleDelete = () => {
    const names = selectedRows.value.map(item => item.teamName);
    const ids = selectedRows.value.map(item => item.id);
    proxy.$modal
      .confirm(
        `是否确认删除班组"${names[0]}"${names.length > 1 ? `等${names.length}条数据` : ""}?`
      )
      .then(function () {
        return del(ids.join(","));
      })
      .then(() => {
        getList();
        proxy.$modal.msgSuccess("删除成功");
      })
      .catch(() => {});
  };
  const getWorkshopOptions = () => {
    workshopListAll().then(res => {
      workshopOptions.value = res.data || [];
    });
  };
  const getUserOptions = () => {
    userListNoPageByTenantId().then(res => {
      if (res.code === 200) {
        userOptions.value = res.data;
      }
    });
  };
  onMounted(() => {
    getList();
    getWorkshopOptions();
    getUserOptions();
  });
</script>
<style scoped></style>
src/views/productionScheduling/workshopManage/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,308 @@
<template>
  <div class="app-container">
    <div class="search_form">
      <el-form :model="searchForm"
               :inline="true">
        <el-form-item label="车间名称:">
          <el-input v-model="searchForm.name"
                    placeholder="请输入"
                    clearable
                    prefix-icon="Search"
                    style="width: 200px;"
                    @change="handleQuery" />
        </el-form-item>
        <el-form-item label="状态:">
          <el-select v-model="searchForm.status"
                     placeholder="请选择"
                     clearable
                     style="width: 160px;"
                     @change="handleQuery">
            <el-option v-for="item in statusOptions"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <div style="text-align: right"
           class="mb10">
        <el-button type="primary"
                   @click="showNewModal">新增车间</el-button>
        <el-button type="danger"
                   plain
                   :disabled="selectedRows.length === 0"
                   @click="handleDelete">删除车间</el-button>
      </div>
      <PIMTable rowKey="id"
                :column="tableColumn"
                :tableData="tableData"
                :page="page"
                :isSelection="true"
                :tableLoading="tableLoading"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        <template #status="{ row }">
          <el-tag :type="row.status === 0 ? 'success' : 'info'">
            {{ row.status === 0 ? "启用" : "停用" }}
          </el-tag>
        </template>
      </PIMTable>
    </div>
    <!-- æ–°å¢ž/编辑弹窗 -->
    <el-dialog v-model="dialogVisible"
               :title="form.id ? '编辑车间' : '新增车间'"
               width="600px">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="100px">
        <el-form-item label="车间名称"
                      prop="name">
          <el-input v-model="form.name"
                    placeholder="请输入车间名称"
                    maxlength="100" />
        </el-form-item>
        <el-form-item label="车间编码"
                      prop="code">
          <el-input v-model="form.code"
                    placeholder="请输入车间编码"
                    maxlength="50" />
        </el-form-item>
        <el-form-item label="负责人"
                      prop="principal">
          <el-input v-model="form.principal"
                    placeholder="请输入负责人"
                    maxlength="50" />
        </el-form-item>
        <el-form-item label="联系电话"
                      prop="contactPhone">
          <el-input v-model="form.contactPhone"
                    placeholder="请输入联系电话"
                    maxlength="20" />
        </el-form-item>
        <el-form-item label="状态"
                      prop="status">
          <el-radio-group v-model="form.status">
            <el-radio v-for="item in statusOptions"
                      :key="item.value"
                      :value="item.value">{{ item.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="form.remark"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入备注"
                    maxlength="500" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     @click="handleSubmit">确定</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
  import { onMounted, ref, reactive, getCurrentInstance } from "vue";
  import {
    listPage,
    add,
    update,
    del,
  } from "@/api/productionScheduling/workshop.js";
  const { proxy } = getCurrentInstance();
  const statusOptions = [
    { label: "启用", value: 0 },
    { label: "停用", value: 1 },
  ];
  const tableColumn = ref([
    {
      label: "车间名称",
      prop: "name",
    },
    {
      label: "车间编码",
      prop: "code",
      width: "120",
    },
    {
      label: "负责人",
      prop: "principal",
      width: "100",
    },
    {
      label: "联系电话",
      prop: "contactPhone",
      width: "140",
    },
    {
      label: "状态",
      prop: "status",
      dataType: "slot",
      slot: "status",
      width: "90",
    },
    {
      label: "备注",
      prop: "remark",
    },
    {
      label: "更新时间",
      prop: "updateTime",
      width: "160",
    },
    {
      dataType: "action",
      label: "操作",
      align: "center",
      fixed: "right",
      width: 100,
      operation: [
        {
          name: "编辑",
          type: "text",
          clickFun: row => {
            showEditModal(row);
          },
        },
      ],
    },
  ]);
  const tableData = ref([]);
  const selectedRows = ref([]);
  const tableLoading = ref(false);
  const dialogVisible = ref(false);
  const formRef = ref(null);
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
  const data = reactive({
    searchForm: {
      name: "",
      status: null,
    },
  });
  const { searchForm } = data;
  const form = reactive({
    id: null,
    name: "",
    code: "",
    principal: "",
    contactPhone: "",
    status: 0,
    remark: "",
  });
  const rules = {
    name: [{ required: true, message: "请输入车间名称", trigger: "blur" }],
  };
  /** æœç´¢æŒ‰é’®æ“ä½œ */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm, ...page };
    listPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(() => {
        tableLoading.value = false;
      });
  };
  // è¡¨æ ¼é€‰æ‹©æ•°æ®
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  const resetForm = () => {
    form.id = null;
    form.name = "";
    form.code = "";
    form.principal = "";
    form.contactPhone = "";
    form.status = 0;
    form.remark = "";
  };
  // æ‰“开新增弹框
  const showNewModal = () => {
    resetForm();
    dialogVisible.value = true;
  };
  const showEditModal = row => {
    resetForm();
    Object.assign(form, JSON.parse(JSON.stringify(row)));
    dialogVisible.value = true;
  };
  const handleSubmit = () => {
    formRef.value.validate(valid => {
      if (!valid) return;
      const request = form.id ? update(form) : add(form);
      request.then(() => {
        proxy.$modal.msgSuccess(form.id ? "修改成功" : "新增成功");
        dialogVisible.value = false;
        getList();
      });
    });
  };
  // æ‰¹é‡åˆ é™¤
  const handleDelete = () => {
    const names = selectedRows.value.map(item => item.name);
    const ids = selectedRows.value.map(item => item.id);
    proxy.$modal
      .confirm(
        `是否确认删除车间"${names[0]}"${names.length > 1 ? `等${names.length}条数据` : ""}?`
      )
      .then(function () {
        return del(ids.join(","));
      })
      .then(() => {
        getList();
        proxy.$modal.msgSuccess("删除成功");
      })
      .catch(() => {});
  };
  onMounted(() => {
    getList();
  });
</script>
<style scoped></style>