From 1b475b840978b0b98c7cd29a00c87971513e3426 Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期五, 09 十月 2026 10:13:17 +0800
Subject: [PATCH] feat(生产排产): 新增车间、班组、排产管理模块并联动工单报工;修复空path菜单导致的路由注册报错
---
src/permission.js | 3
index.html | 4
src/views/productionScheduling/teamManage/index.vue | 375 ++++++++++++++++
src/views/productionScheduling/workshopManage/index.vue | 308 +++++++++++++
src/store/modules/permission.js | 20
src/views/productionScheduling/schedulingManage/index.vue | 462 ++++++++++++++++++++
src/api/productionScheduling/workshop.js | 42 +
src/api/productionScheduling/scheduling.js | 43 +
src/api/productionScheduling/team.js | 43 +
src/views/productionManagement/workOrderManagement/index.vue | 59 +
10 files changed, 1,337 insertions(+), 22 deletions(-)
diff --git a/index.html b/index.html
index 274352d..34df730 100644
--- a/index.html
+++ b/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";
diff --git a/src/api/productionScheduling/scheduling.js b/src/api/productionScheduling/scheduling.js
new file mode 100644
index 0000000..cf9a376
--- /dev/null
+++ b/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",
+ });
+}
diff --git a/src/api/productionScheduling/team.js b/src/api/productionScheduling/team.js
new file mode 100644
index 0000000..7c5f89f
--- /dev/null
+++ b/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",
+ });
+}
diff --git a/src/api/productionScheduling/workshop.js b/src/api/productionScheduling/workshop.js
new file mode 100644
index 0000000..74a57a2
--- /dev/null
+++ b/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",
+ });
+}
diff --git a/src/permission.js b/src/permission.js
index 9bf4a91..239fb67 100644
--- a/src/permission.js
+++ b/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) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
}
})
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
index 6a16d9d..30035e6 100644
--- a/src/store/modules/permission.js
+++ b/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 => {
diff --git a/src/views/productionManagement/workOrderManagement/index.vue b/src/views/productionManagement/workOrderManagement/index.vue
index 6def04c..822c2aa 100644
--- a/src/views/productionManagement/workOrderManagement/index.vue
+++ b/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>
diff --git a/src/views/productionScheduling/schedulingManage/index.vue b/src/views/productionScheduling/schedulingManage/index.vue
new file mode 100644
index 0000000..d21f8e0
--- /dev/null
+++ b/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>
diff --git a/src/views/productionScheduling/teamManage/index.vue b/src/views/productionScheduling/teamManage/index.vue
new file mode 100644
index 0000000..2eefe67
--- /dev/null
+++ b/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>
diff --git a/src/views/productionScheduling/workshopManage/index.vue b/src/views/productionScheduling/workshopManage/index.vue
new file mode 100644
index 0000000..c015514
--- /dev/null
+++ b/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="璇疯緭鍏ヨ礋璐d汉"
+ 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>
--
Gitblit v1.9.3