From 91c82965b2d987452ca276e3a03b48c8dcda2ae9 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 19 八月 2026 11:47:26 +0800
Subject: [PATCH] config(env): 更新生产环境配置和公司名称

---
 src/views/mes/pro/batch/modules/form.vue |  281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 281 insertions(+), 0 deletions(-)

diff --git a/src/views/mes/pro/batch/modules/form.vue b/src/views/mes/pro/batch/modules/form.vue
new file mode 100644
index 0000000..2e45243
--- /dev/null
+++ b/src/views/mes/pro/batch/modules/form.vue
@@ -0,0 +1,281 @@
+<script lang="ts" setup>
+  import type { FormType } from "../data";
+
+  import type { VxeTableGridOptions } from "#/adapter/vxe-table";
+  import type { MesProBatchApi } from "#/api/mes/pro/batch";
+  import type { SystemUserApi } from "#/api/system/user";
+
+  import { computed, nextTick, ref } from "vue";
+
+  import { useVbenModal } from "@vben/common-ui";
+  import { DICT_TYPE } from "@vben/constants";
+  import { getDictOptions } from "@vben/hooks";
+
+  import { Button, Input, message, Select } from "ant-design-vue";
+
+  import { useVbenForm } from "#/adapter/form";
+  import { TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
+  import { createBatch, getBatch, updateBatch } from "#/api/mes/pro/batch";
+  import { $t } from "#/locales";
+  import { UserSelect } from "#/views/system/user/components";
+
+  import {
+    useFormSchema,
+    useWorkerEditGridColumns,
+    useWorkerReadGridColumns,
+  } from "../data";
+
+  defineOptions({ name: "MesProBatchForm" });
+
+  const emit = defineEmits(["success"]);
+
+  const formType = ref<FormType>("create");
+  const formData = ref<MesProBatchApi.Batch>();
+
+  const isEditable = computed(() =>
+    ["create", "update"].includes(formType.value)
+  );
+
+  const getTitle = computed(() => {
+    switch (formType.value) {
+      case "detail": {
+        return $t("ui.actionTitle.view", ["鐢熶骇鎵规"]);
+      }
+      case "update": {
+        return $t("ui.actionTitle.edit", ["鐢熶骇鎵规"]);
+      }
+      default: {
+        return $t("ui.actionTitle.create", ["鐢熶骇鎵规"]);
+      }
+    }
+  });
+
+  const [Form, formApi] = useVbenForm({
+    commonConfig: {
+      componentProps: {
+        class: "w-full",
+      },
+      formItemClass: "col-span-1",
+      labelWidth: 110,
+    },
+    layout: "horizontal",
+    schema: [],
+    showDefaultActions: false,
+    wrapperClass: "grid-cols-3",
+  });
+
+  // ========== 鐢熶骇浜哄憳閰嶇疆瀛愯〃 ==========
+  const [WorkerGrid, workerGridApi] = useVbenVxeGrid({
+    gridOptions: {
+      autoResize: true,
+      border: true,
+      columns: useWorkerEditGridColumns(),
+      minHeight: 160,
+      pagerConfig: { enabled: false },
+      rowConfig: { isHover: true, keyField: "_rowKey" },
+      showOverflow: true,
+      toolbarConfig: { enabled: false },
+    } as VxeTableGridOptions<MesProBatchApi.BatchWorker>,
+  });
+
+  /** 鏂板琛岀殑涓存椂琛屽彿锛堣礋鏁拌嚜澧烇紝閬垮厤涓� loadData 鐨� index 鍐茬獊锛� */
+  let workerRowSeq = 0;
+
+  /** 娣诲姞浜哄憳琛� */
+  function handleAddWorker() {
+    workerGridApi.grid.insertAt({ _rowKey: -(++workerRowSeq) }, -1);
+  }
+
+  /** 鍒犻櫎浜哄憳琛� */
+  function handleDeleteWorker(row: MesProBatchApi.BatchWorker) {
+    workerGridApi.grid.remove(row);
+  }
+
+  /** 浜哄憳閫夋嫨缂栧彿鍙樺寲锛堝崟閫夊満鏅笅鍙栫涓�涓�硷級 */
+  function handleWorkerUserIdChange(
+    value: number | number[] | undefined,
+    row: MesProBatchApi.BatchWorker
+  ) {
+    row.userId = Array.isArray(value) ? value[0] : value;
+  }
+
+  /** 浜哄憳閫夋嫨鍙樺寲鏃惰褰曞鍚嶏紙渚夸簬鏍¢獙鎻愮ず锛� */
+  function handleWorkerUserChange(
+    user: SystemUserApi.User | SystemUserApi.User[] | undefined,
+    row: MesProBatchApi.BatchWorker
+  ) {
+    row.userName = Array.isArray(user) ? user[0]?.nickname : user?.nickname;
+  }
+
+  /** 宀椾綅绫诲瀷瀛楀吀閫夐」 */
+  const workerTypeOptions = computed(() =>
+    getDictOptions(DICT_TYPE.MES_PRO_BATCH_WORKER_TYPE, "number").map(
+      (item) => ({ label: item.label, value: item.value as number })
+    )
+  );
+
+  /** 鏍¢獙骞惰幏鍙栦汉鍛橀厤缃垪琛� */
+  async function getValidWorkers(): Promise<
+    MesProBatchApi.BatchWorker[] | undefined
+  > {
+    // getData() 鍙繑鍥� loadData 鍔犺浇鐨勬暟鎹紱insertAt 鎻掑叆鐨勮闇�閫氳繃
+    // getInsertRecords() 鑾峰彇锛屽苟鎺掗櫎 getRemoveRecords() 涓凡鍒犻櫎鐨勮
+    const data = workerGridApi.grid.getData() as Array<
+      MesProBatchApi.BatchWorker & { _rowKey?: number }
+    >;
+    const removeRecords = workerGridApi.grid.getRemoveRecords() as Array<
+      MesProBatchApi.BatchWorker & { _rowKey?: number }
+    >;
+    const insertRecords = workerGridApi.grid.getInsertRecords() as Array<
+      MesProBatchApi.BatchWorker & { _rowKey?: number }
+    >;
+    const rows = [
+      ...data.filter(
+        (row) => !removeRecords.some((removed) => removed._rowKey === row._rowKey)
+      ),
+      ...insertRecords,
+    ].map(({ _rowKey, ...rest }) => rest);
+    if (rows.length === 0) {
+      message.warning("璇疯嚦灏戦厤缃竴鍚嶇敓浜т汉鍛�");
+      return undefined;
+    }
+    for (const [index, row] of rows.entries()) {
+      if (!row.userId) {
+        message.warning(`璇烽�夋嫨绗� ${index + 1} 琛岀殑鐢熶骇浜哄憳`);
+        return undefined;
+      }
+      if (!row.workerType) {
+        message.warning(`璇烽�夋嫨绗� ${index + 1} 琛岀殑宀椾綅绫诲瀷`);
+        return undefined;
+      }
+    }
+    return rows;
+  }
+
+  /** 绛夊緟浜哄憳瀛愯〃 grid 鎸傝浇瀹屾垚锛堝脊绐楁墦寮�鐬棿 onOpenChange 鍐呴儴琛ㄦ牸鍙兘灏氭湭鎸傝浇锛� */
+  async function waitWorkerGridReady(): Promise<void> {
+    await nextTick();
+    for (let i = 0; i < 100; i++) {
+      if (typeof workerGridApi.grid?.loadData === "function") {
+        return;
+      }
+      await new Promise((resolve) => setTimeout(resolve, 30));
+    }
+  }
+
+  const [Modal, modalApi] = useVbenModal({
+    showCancelButton: false, // 鑷畾涔夊彇娑�/鍏抽棴鎸夐挳锛岀鐢ㄩ粯璁ゅ彇娑堟寜閽伩鍏嶉噸澶�
+    async onConfirm() {
+      if (!isEditable.value) {
+        await modalApi.close();
+        return;
+      }
+      const { valid } = await formApi.validate();
+      if (!valid) return;
+      const workers = await getValidWorkers();
+      if (!workers) return;
+      modalApi.lock();
+      try {
+        const data = (await formApi.getValues()) as MesProBatchApi.Batch;
+        if (formData.value?.id) {
+          await updateBatch({ ...data, id: formData.value.id, workers });
+        } else {
+          await createBatch({ ...data, workers });
+        }
+        message.success($t("ui.actionMessage.operationSuccess"));
+        emit("success");
+        await modalApi.close();
+      } finally {
+        modalApi.unlock();
+      }
+    },
+    async onOpenChange(isOpen: boolean) {
+      if (!isOpen) {
+        formData.value = undefined;
+        return;
+      }
+      const data = modalApi.getData<{ formType: FormType; id?: number }>();
+      formType.value = data.formType;
+      formApi.setState({ schema: useFormSchema(formType.value) });
+      // 鏍规嵁琛ㄥ崟鎬佸垏鎹汉鍛樺瓙琛ㄥ垪
+      workerGridApi.setGridOptions({
+        columns: isEditable.value
+          ? useWorkerEditGridColumns()
+          : useWorkerReadGridColumns(),
+      });
+      if (data?.id) {
+        modalApi.lock();
+        try {
+          formData.value = await getBatch(data.id);
+          await formApi.setValues(formData.value);
+          const workers = (formData.value.workers ?? []).map(
+            (worker, index) => ({ ...worker, _rowKey: worker.id ?? index })
+          );
+          await waitWorkerGridReady();
+          await workerGridApi.grid.loadData(workers);
+        } finally {
+          modalApi.unlock();
+        }
+      } else {
+        await waitWorkerGridReady();
+        await workerGridApi.grid.loadData([]);
+      }
+    },
+  });
+</script>
+
+<template>
+  <Modal :title="getTitle"
+         class="w-3/5"
+         content-class="!max-h-[80vh] overflow-y-auto">
+    <Form class="mx-4" />
+    <div class="mx-4 mb-4">
+      <div class="mb-2 flex items-center justify-between">
+        <span class="font-medium">鐢熶骇浜哄憳閰嶇疆</span>
+        <Button v-if="isEditable" size="small" type="primary" @click="handleAddWorker">
+          娣诲姞浜哄憳
+        </Button>
+      </div>
+      <WorkerGrid>
+        <template #userId="{ row }">
+          <UserSelect
+            :model-value="row.userId"
+            placeholder="璇烽�夋嫨鐢熶骇浜哄憳"
+            @update:model-value="handleWorkerUserIdChange($event, row)"
+            @change="handleWorkerUserChange($event, row)"
+          />
+        </template>
+        <template #workerType="{ row }">
+          <Select
+            v-model:value="row.workerType"
+            :options="workerTypeOptions"
+            class="w-full"
+            placeholder="璇烽�夋嫨宀椾綅绫诲瀷"
+          />
+        </template>
+        <template #remark="{ row }">
+          <Input v-model:value="row.remark" placeholder="璇疯緭鍏ュ娉�" />
+        </template>
+        <template #actions="{ row }">
+          <TableAction
+            :actions="[
+              {
+                label: $t('common.delete'),
+                type: 'link',
+                danger: true,
+                onClick: handleDeleteWorker.bind(null, row),
+              },
+            ]"
+          />
+        </template>
+      </WorkerGrid>
+    </div>
+    <template #append-footer>
+      <div class="flex gap-2">
+        <Button @click="modalApi.close()">
+          {{ isEditable ? '鍙栨秷' : '鍏抽棴' }}
+        </Button>
+      </div>
+    </template>
+  </Modal>
+</template>

--
Gitblit v1.9.3