From 8b1397cf60e69bcc3222a6862e72efc3f95483b0 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期一, 11 五月 2026 14:18:48 +0800
Subject: [PATCH] 生产班组

---
 src/api/productionManagement/productionTeam.js          |   53 ++++++
 src/views/productionManagement/productionTeam/index.vue |  382 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 435 insertions(+), 0 deletions(-)

diff --git a/src/api/productionManagement/productionTeam.js b/src/api/productionManagement/productionTeam.js
new file mode 100644
index 0000000..3dd0947
--- /dev/null
+++ b/src/api/productionManagement/productionTeam.js
@@ -0,0 +1,53 @@
+import request from "@/utils/request";
+
+// 鍒涘缓鐝粍
+export function createTeam(data) {
+    return request({
+        url: "/production_team",
+        method: "post",
+        data: data,
+    });
+}
+
+// 鏇存柊鐝粍
+export function updateTeam(data) {
+    return request({
+        url: "/production_team",
+        method: "put",
+        data: data,
+    });
+}
+
+// 鍒犻櫎鐝粍
+export function deleteTeam(id) {
+    return request({
+        url: "/production_team/" + id,
+        method: "delete",
+    });
+}
+
+// 鏌ヨ鐝粍璇︽儏
+export function getTeamDetail(id) {
+    return request({
+        url: "/production_team/" + id,
+        method: "get",
+    });
+}
+
+// 鏌ヨ鐝粍鍒楄〃
+export function getTeamList(query) {
+    return request({
+        url: "/production_team/list",
+        method: "get",
+        params: query,
+    });
+}
+
+// 鍒嗛〉鏌ヨ鐝粍鍒楄〃
+export function getTeamListPage(query) {
+    return request({
+        url: "/production_team/listPage",
+        method: "get",
+        params: query,
+    });
+}
diff --git a/src/views/productionManagement/productionTeam/index.vue b/src/views/productionManagement/productionTeam/index.vue
new file mode 100644
index 0000000..b3fdcf9
--- /dev/null
+++ b/src/views/productionManagement/productionTeam/index.vue
@@ -0,0 +1,382 @@
+<template>
+  <div class="app-container">
+    <!-- 鎼滅储琛ㄥ崟 -->
+    <div class="search_form">
+      <div class="search-row">
+        <div class="search-left">
+          <div class="search-item">
+            <span class="search_title">鐝粍鍚嶇О锛�</span>
+            <el-input v-model="searchForm.teamName"
+                      style="width: 240px"
+                      placeholder="璇疯緭鍏�"
+                      @change="handleQuery"
+                      clearable
+                      prefix-icon="Search" />
+          </div>
+          <div class="search-item">
+            <el-button type="primary"
+                       @click="handleQuery">鎼滅储</el-button>
+          </div>
+        </div>
+        <div class="search-right">
+          <el-button type="primary"
+                     @click="handleAdd">鏂板</el-button>
+          <el-button type="danger"
+                     plain
+                     :disabled="!selectedIds.length"
+                     @click="handleBatchDelete">鍒犻櫎</el-button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 琛ㄦ牸鏁版嵁 -->
+    <div class="table_list">
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :tableLoading="tableLoading"
+                @pagination="pagination"
+                :isSelection="true"
+                @selection-change="handleSelectionChange">
+        <template #members="{ row }">
+          <el-tag
+              v-for="member in getNonLeaderMembers(row)"
+              :key="member.userId"
+              type="info"
+              size="small"
+              style="margin-right: 4px"
+          >{{ member.nickName }}</el-tag>
+          <span v-if="!getNonLeaderMembers(row).length" class="text-gray">鏆傛棤鎴愬憳</span>
+        </template>
+      </PIMTable>
+    </div>
+
+    <!-- 娣诲姞鎴栦慨鏀圭彮缁勫璇濇 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="teamRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="鐝粍鍚嶇О" prop="teamName">
+          <el-input v-model="form.teamName" placeholder="璇疯緭鍏ョ彮缁勫悕绉�" />
+        </el-form-item>
+        <el-form-item label="鐝粍闀�" prop="leaderId">
+          <el-select
+              v-model="form.leaderId"
+              placeholder="璇烽�夋嫨鐝粍闀�"
+              style="width: 100%"
+              clearable
+              filterable
+          >
+            <el-option
+                v-for="user in userList"
+                :key="user.userId"
+                :label="user.nickName"
+                :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鐝粍鎴愬憳" prop="memberIds">
+          <el-select
+              v-model="form.memberIds"
+              placeholder="璇烽�夋嫨鐝粍鎴愬憳锛堜笉鍖呭惈鐝粍闀匡級"
+              style="width: 100%"
+              multiple
+              clearable
+              filterable
+          >
+            <el-option
+                v-for="user in availableMembers"
+                :key="user.userId"
+                :label="user.nickName"
+                :value="user.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="ProductionTeam">
+import { ref, reactive, toRefs, onMounted, computed, watch } from "vue";
+import {
+  createTeam,
+  updateTeam,
+  deleteTeam,
+  getTeamDetail,
+  getTeamListPage,
+} from "@/api/productionManagement/productionTeam.js";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+
+const { proxy } = getCurrentInstance();
+
+const tableColumn = ref([
+  {
+    label: "鐝粍鍚嶇О",
+    prop: "teamName",
+    width: "150",
+  },
+  {
+    label: "鐝粍闀�",
+    prop: "leaderName",
+    width: "120",
+  },
+  {
+    label: "鐝粍鎴愬憳",
+    dataType: "slot",
+    slot: "members",
+  },
+  {
+    label: "鍒涘缓鏃ユ湡",
+    prop: "createTime",
+    width: "180",
+  },
+  {
+    label: "澶囨敞",
+    prop: "remark",
+  },
+  {
+    label: "鎿嶄綔",
+    width: "180",
+    align: "center",
+    dataType: "action",
+    fixed: "right",
+    operation: [
+      {
+        name: "缂栬緫",
+        clickFun: (row) => {
+          handleUpdate(row);
+        },
+      },
+      {
+        name: "鍒犻櫎",
+        clickFun: (row) => {
+          handleDelete(row);
+        },
+      },
+    ],
+  },
+]);
+
+const tableData = ref([]);
+const tableLoading = ref(false);
+const open = ref(false);
+const title = ref("");
+const userList = ref([]);
+const selectedIds = ref([]);
+
+// 鍙�夋嫨鐨勬垚鍛樺垪琛紙鎺掗櫎鐝粍闀匡級
+const availableMembers = computed(() => {
+  if (!form.value.leaderId) {
+    return userList.value;
+  }
+  return userList.value.filter(user => user.userId !== form.value.leaderId);
+});
+
+const page = reactive({
+  current: 1,
+  size: 10,
+  total: 0,
+});
+
+const data = reactive({
+  form: {},
+  searchForm: {
+    teamName: "",
+  },
+  rules: {
+    teamName: [{ required: true, message: "鐝粍鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }],
+    leaderId: [{ required: true, message: "璇烽�夋嫨鐝粍闀�", trigger: "blur" }],
+  },
+});
+
+const { searchForm, form, rules } = toRefs(data);
+
+/** 鏌ヨ鐝粍鍒楄〃 */
+function getList() {
+  tableLoading.value = true;
+  const params = { ...searchForm.value, ...page };
+  getTeamListPage(params).then((response) => {
+    tableData.value = response.data?.records || response.data || [];
+    page.total = response.data?.total || (response.data?.length || 0);
+    tableLoading.value = false;
+  }).catch(() => {
+    tableLoading.value = false;
+  });
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+  page.current = 1;
+  getList();
+}
+
+/** 鍒嗛〉鎿嶄綔 */
+function pagination(obj) {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+  proxy.$modal.confirm(`鏄惁纭鍒犻櫎鐝粍"${row.teamName}"?`).then(function () {
+    return deleteTeam(row.id);
+  }).then(() => {
+    getList();
+    proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+/** 鎵归噺鍒犻櫎 */
+function handleBatchDelete() {
+  if (!selectedIds.value.length) {
+    proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鐝粍");
+    return;
+  }
+  proxy.$modal.confirm(`鏄惁纭鍒犻櫎閫変腑鐨�${selectedIds.value.length}涓彮缁�?`).then(function () {
+    // 鎵归噺鍒犻櫎锛屼緷娆″垹闄ゆ瘡涓狪D
+    const deletePromises = selectedIds.value.map(id => deleteTeam(id));
+    return Promise.all(deletePromises);
+  }).then(() => {
+    getList();
+    selectedIds.value = [];
+    proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+/** 澶氶�夋閫変腑鏁版嵁 */
+function handleSelectionChange(selection) {
+  selectedIds.value = selection.map((item) => item.id);
+}
+
+/** 鑾峰彇闈炵彮缁勯暱鐨勬垚鍛樺垪琛� */
+function getNonLeaderMembers(row) {
+  if (!row.members || !row.leaderId) {
+    return row.members || [];
+  }
+  return row.members.filter(m => m.userId !== row.leaderId);
+}
+
+/** 鑾峰彇鐢ㄦ埛鍒楄〃 */
+function getUserList() {
+  userListNoPageByTenantId().then((response) => {
+    if (response.code === 200) {
+      userList.value = response.data || [];
+    }
+  });
+}
+
+/** 閲嶇疆琛ㄥ崟 */
+function reset() {
+  form.value = {
+    id: undefined,
+    teamName: undefined,
+    leaderId: undefined,
+    memberIds: [],
+    remark: undefined,
+  };
+  proxy.resetForm("teamRef");
+}
+
+/** 娣诲姞鐝粍 */
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "娣诲姞鐝粍";
+}
+
+/** 淇敼鐝粍 */
+function handleUpdate(row) {
+  reset();
+  getTeamDetail(row.id).then((response) => {
+    form.value = response.data;
+    // 杩囨护鎺夌彮缁勯暱锛屽彧淇濈暀鏅�氭垚鍛�
+    form.value.memberIds = response.data.members
+      .filter(m => m.userId !== response.data.leaderId)
+      .map((m) => m.userId);
+    open.value = true;
+  });
+  title.value = "淇敼鐝粍";
+}
+
+// 鐩戝惉鐝粍闀垮彉鍖栵紝鑷姩浠庢垚鍛樺垪琛ㄤ腑绉婚櫎鐝粍闀�
+watch(() => form.value.leaderId, (newLeaderId, oldLeaderId) => {
+  if (newLeaderId && form.value.memberIds) {
+    form.value.memberIds = form.value.memberIds.filter(id => id !== newLeaderId);
+  }
+});
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+  proxy.$refs["teamRef"].validate((valid) => {
+    if (valid) {
+      const submitData = {
+        id: form.value.id,
+        teamName: form.value.teamName,
+        leaderId: form.value.leaderId,
+        memberIds: form.value.memberIds || [],
+        remark: form.value.remark,
+      };
+      if (form.value.id != undefined) {
+        updateTeam(submitData).then((response) => {
+          proxy.$modal.msgSuccess("淇敼鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      } else {
+        createTeam(submitData).then((response) => {
+          proxy.$modal.msgSuccess("鏂板鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 鍙栨秷鎸夐挳 */
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+onMounted(() => {
+  getList();
+  getUserList();
+});
+</script>
+
+<style scoped lang="scss">
+.search_form {
+  margin-bottom: 20px;
+  .search-row {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+  }
+  .search-left {
+    display: flex;
+    gap: 20px;
+    align-items: center;
+    .search-item {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+    }
+  }
+  .search-right {
+    display: flex;
+    gap: 10px;
+  }
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3