From cfba74a9db1b77f8e0b5f52fe15c8a1c4bfcaa76 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 16 四月 2026 13:01:19 +0800
Subject: [PATCH] 种形式想 1.工艺路线编辑的时候可以多选产品

---
 src/views/productionManagement/productionOrder/index.vue |  799 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 645 insertions(+), 154 deletions(-)

diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 87ca041..686d397 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -1,182 +1,673 @@
 <template>
-	<div class="app-container">
-		<div class="search_form">
-			<div>
-				<span class="search_title">瀹㈡埛鍚嶇О锛�</span>
-				<el-input
-					v-model="searchForm.customerName"
-					style="width: 240px"
-					placeholder="璇疯緭鍏�"
-					@change="handleQuery"
-					clearable
-					prefix-icon="Search"
-				/>
-				<span class="search_title ml10">椤圭洰鍚嶇О锛�</span>
-				<el-input
-					v-model="searchForm.customerName"
-					style="width: 240px"
-					placeholder="璇疯緭鍏�"
-					@change="handleQuery"
-					clearable
-					prefix-icon="Search"
-				/>
-				<span class="search_title ml10">褰曞叆鏃ユ湡锛�</span>
-				<el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-												placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
-				<el-button type="primary" @click="handleQuery" style="margin-left: 10px"
-				>鎼滅储</el-button
-				>
-			</div>
-			<div>
-				<el-button @click="handleOut">瀵煎嚭</el-button>
-			</div>
-		</div>
-		<div class="table_list">
-			<PIMTable
-				rowKey="id"
-				:column="tableColumn"
-				:tableData="tableData"
-				:page="page"
-				:tableLoading="tableLoading"
-				@pagination="pagination"
-			></PIMTable>
-		</div>
-	</div>
+  <div class="app-container">
+    <div class="search_form">
+      <el-form :model="searchForm" :inline="true">
+        <el-form-item label="瀹㈡埛鍚嶇О">
+          <el-input
+            v-model="searchForm.customerName"
+            placeholder="璇疯緭鍏�"
+            clearable
+            :prefix-icon="Search"
+            style="width: 160px;"
+            @change="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="閿�鍞悎鍚屽彿">
+          <el-input
+            v-model="searchForm.salesContractNo"
+            placeholder="璇疯緭鍏�"
+            clearable
+            :prefix-icon="Search"
+            style="width: 160px;"
+            @change="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="浜у搧鍚嶇О">
+          <el-input
+            v-model="searchForm.productCategory"
+            placeholder="璇疯緭鍏�"
+            clearable
+            :prefix-icon="Search"
+            style="width: 160px;"
+            @change="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="瑙勬牸鍨嬪彿">
+          <el-input
+            v-model="searchForm.specificationModel"
+            placeholder="璇疯緭鍏�"
+            clearable
+            :prefix-icon="Search"
+            style="width: 160px;"
+            @change="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery">鏌ヨ</el-button>
+        </el-form-item>
+      </el-form>
+      <div>
+        <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>
+        <el-button type="danger" @click="handleDelete">鍒犻櫎</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+      </div>
+    </div>
+
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :tableLoading="tableLoading"
+        :row-class-name="tableRowClassName"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        @pagination="pagination"
+      >
+        <template #completionStatus="{ row }">
+          <el-progress
+            :percentage="toProgressPercentage(row?.completionStatus)"
+            :color="progressColor(toProgressPercentage(row?.completionStatus))"
+            :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
+          />
+        </template>
+      </PIMTable>
+    </div>
+
+    <el-dialog
+      v-model="bindRouteDialogVisible"
+      title="缁戝畾宸ヨ壓璺嚎"
+      width="700px"
+    >
+      <el-form label-width="90px">
+        <el-form-item label="宸ヨ壓璺嚎">
+          <el-select
+            v-model="bindForm.routeId"
+            placeholder="璇烽�夋嫨宸ヨ壓璺嚎"
+            style="width: 100%;"
+            :loading="bindRouteLoading"
+            @change="handleBindRouteChange"
+          >
+            <el-option
+              v-for="item in routeOptions"
+              :key="item.id"
+              :label="item.processRouteCode || ''"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item v-if="bindProcessList.length" label="鎶ュ伐浜哄憳">
+          <div class="process-user-list">
+            <div
+              v-for="(item, index) in bindProcessList"
+              :key="item.id || `${item.processId}-${index}`"
+              class="process-user-item"
+            >
+              <div class="process-user-header">
+                <div class="process-user-name">
+                  {{ item.name || item.processName || item.no || `宸ュ簭${index + 1}` }}
+                </div>
+                <el-button
+                  type="danger"
+                  link
+                  class="process-user-remove"
+                  @click="removeBindProcessItem(index)"
+                >
+                  鍒犻櫎
+                </el-button>
+              </div>
+              <el-select
+                v-model="bindForm.processUserList[index].userIds"
+                class="process-user-select"
+                placeholder="璇烽�夋嫨鎶ュ伐浜哄憳"
+                filterable
+                clearable
+                multiple
+                collapse-tags
+                collapse-tags-tooltip
+                :max-collapse-tags="3"
+                @change="handleBindProcessUserChange(index, $event)"
+              >
+                <el-option
+                  v-for="user in userOptions"
+                  :key="user.userId"
+                  :label="user.nickName"
+                  :value="user.userId"
+                />
+              </el-select>
+            </div>
+          </div>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button
+            type="primary"
+            :loading="bindRouteSaving"
+            @click="handleBindRouteConfirm"
+          >
+            纭
+          </el-button>
+          <el-button @click="bindRouteDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <new-product-order
+      v-if="isShowNewModal"
+      v-model:visible="isShowNewModal"
+      @completed="handleQuery"
+    />
+  </div>
 </template>
 
 <script setup>
-import {onMounted, ref} from "vue";
-import {
-	listCustomer,
-} from "@/api/basicData/customerFile.js";
+import { defineAsyncComponent, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
 import { ElMessageBox } from "element-plus";
+import { Search } from "@element-plus/icons-vue";
 import dayjs from "dayjs";
+import { useRouter } from "vue-router";
+import {
+  bindingRoute,
+  delProductOrder,
+  listProcessRoute,
+  productOrderListPage,
+} from "@/api/productionManagement/productionOrder.js";
+import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
+import { processList } from "@/api/productionManagement/productionProcess.js";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import {findProcessRouteItemList} from "@/api/productionManagement/processRouteItem.js";
+
+const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
+
 const { proxy } = getCurrentInstance();
+const router = useRouter();
+const isShowNewModal = ref(false);
 
 const tableColumn = ref([
-	{
-		label: "褰曞叆鏃ユ湡",
-		prop: "customerName",
-		width: 120,
-	},
-	{
-		label: "鍚堝悓鍙�",
-		prop: "taxpayerIdentificationNumber",
-		width: 220,
-	},
-	{
-		label: "瀹㈡埛鍚堝悓鍙�",
-		prop: "addressPhone",
-		width: 250,
-	},
-	{
-		label: "瀹㈡埛鍚嶇О",
-		prop: "contactPerson",
-	},
-	{
-		label: "椤圭洰鍚嶇О",
-		prop: "contactPhone",
-		width:150
-	},
-	{
-		label: "浜у搧澶х被",
-		prop: "basicBankAccount",
-		width: 220,
-	},
-	{
-		label: "瑙勬牸鍨嬪彿",
-		prop: "bankAccount",
-		width: 220,
-	},
-	{
-		label: "鍗曚綅",
-		prop: "bankCode",
-		width:220
-	},
-	{
-		label: "鏁伴噺",
-		prop: "maintainer",
-	},
-	{
-		label: "鎺掍骇鏁伴噺",
-		prop: "maintenanceTime",
-		width: 100,
-	},
-	{
-		label: "瀹屽伐鏁伴噺",
-		prop: "maintenanceTime",
-		width: 100,
-	},
+  {
+    label: "鐢熶骇璁㈠崟鍙�",
+    prop: "npsNo",
+    width: "120px",
+  },
+  {
+    label: "閿�鍞悎鍚屽彿",
+    prop: "salesContractNo",
+    width: "150px",
+  },
+  {
+    label: "瀹㈡埛鍚嶇О",
+    prop: "customerName",
+    width: "200px",
+  },
+  {
+    label: "浜у搧鍚嶇О",
+    prop: "productCategory",
+    width: "120px",
+  },
+  {
+    label: "瑙勬牸鍨嬪彿",
+    prop: "specificationModel",
+    width: "120px",
+  },
+  {
+    label: "宸ヨ壓璺嚎缂栧彿",
+    prop: "processRouteCode",
+    width: "200px",
+  },
+  {
+    label: "闇�姹傛暟閲�",
+    prop: "quantity",
+  },
+  {
+    label: "瀹屾垚鏁伴噺",
+    prop: "completeQuantity",
+  },
+  {
+    dataType: "slot",
+    label: "瀹屾垚杩涘害",
+    prop: "completionStatus",
+    slot: "completionStatus",
+    width: 180,
+  },
+  {
+    label: "寮�濮嬫棩鏈�",
+    prop: "startTime",
+    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+    width: 120,
+  },
+  {
+    label: "缁撴潫鏃ユ湡",
+    prop: "endTime",
+    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+    width: 120,
+  },
+  {
+    label: "浜や粯鏃ユ湡",
+    prop: "deliveryDate",
+    formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+    width: 120,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: "right",
+    width: 200,
+    operation: [
+      {
+        name: "宸ヨ壓璺嚎",
+        type: "text",
+        clickFun: row => {
+          showRouteItemModal(row);
+        },
+      },
+      {
+        name: "缁戝畾宸ヨ壓璺嚎",
+        type: "text",
+        showHide: row => !row.processRouteCode,
+        clickFun: row => {
+          openBindRouteDialog(row);
+        },
+      },
+      {
+        name: "浜у搧缁撴瀯",
+        type: "text",
+        clickFun: row => {
+          showProductStructure(row);
+        },
+      },
+    ],
+  },
 ]);
+
 const tableData = ref([]);
 const tableLoading = ref(false);
 const page = reactive({
-	current: 1,
-	size: 100,
-	total: 0,
+  current: 1,
+  size: 100,
+  total: 0,
 });
+const selectedRows = ref([]);
 
 const data = reactive({
-	searchForm: {
-		customerName: "",
-		entryDate: [
-			dayjs().format("YYYY-MM-DD"),
-			dayjs().add(1, "day").format("YYYY-MM-DD"),
-		], // 褰曞叆鏃ユ湡
-		entryDateStart: dayjs().format("YYYY-MM-DD"),
-		entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"),
-	},
+  searchForm: {
+    customerName: "",
+    salesContractNo: "",
+    projectName: "",
+    productCategory: "",
+    specificationModel: "",
+  },
 });
 const { searchForm } = toRefs(data);
 
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
-	page.current = 1;
-	getList();
-};
-const pagination = (obj) => {
-	page.current = obj.page;
-	page.size = obj.limit;
-	getList();
-};
-const changeDaterange = (value) => {
-	if (value) {
-		searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
-		searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
-	} else {
-		searchForm.entryDateStart = undefined;
-		searchForm.entryDateEnd = undefined;
-	}
-	handleQuery();
-};
-const getList = () => {
-	tableLoading.value = true;
-	listCustomer({ ...searchForm.value, ...page }).then((res) => {
-		tableLoading.value = false;
-		tableData.value = res.records;
-		page.total = res.total;
-	});
+const toProgressPercentage = val => {
+  const n = Number(val);
+  if (!Number.isFinite(n) || n <= 0) return 0;
+  if (n >= 100) return 100;
+  return Math.round(n);
 };
 
-// 瀵煎嚭
+const progressColor = percentage => {
+  const p = toProgressPercentage(percentage);
+  if (p < 30) return "#f56c6c";
+  if (p < 50) return "#e6a23c";
+  if (p < 80) return "#409eff";
+  return "#67c23a";
+};
+
+const tableRowClassName = ({ row }) => {
+  if (!row.deliveryDate || row.isFh) return "";
+
+  const diff = row.deliveryDaysDiff;
+  if (diff === 15) return "yellow";
+  if (diff === 10) return "pink";
+  if (diff === 2) return "purple";
+  if (diff < 2) return "red";
+  return "";
+};
+
+const bindRouteDialogVisible = ref(false);
+const bindRouteLoading = ref(false);
+const bindRouteSaving = ref(false);
+const routeOptions = ref([]);
+const bindProcessList = ref([]);
+const userOptions = ref([]);
+const userLoading = ref(false);
+const bindForm = reactive({
+  orderId: null,
+  productId: null,
+  productModelId: null,
+  routeId: null,
+  processUserList: [],
+});
+
+const resetBindProcessUsers = () => {
+  bindProcessList.value = [];
+  bindForm.processUserList = [];
+};
+
+const ensureUserOptions = () => {
+  if (userOptions.value.length || userLoading.value) return;
+
+  userLoading.value = true;
+  userListNoPageByTenantId()
+    .then(res => {
+      userOptions.value = res.data || [];
+    })
+    .finally(() => {
+      userLoading.value = false;
+    });
+};
+
+const createBindProcessUserList = list =>
+  list.map(item => ({
+    processId: item.id,
+    processName: item.name || item.processName || item.no || "",
+    userIds: [],
+    userNames: "",
+  }));
+
+const buildBindProcessRouteItems = () =>
+  bindProcessList.value.map((item, index) => {
+    const processUser = bindForm.processUserList[index] || {};
+    return {
+      productOrderId: bindForm.orderId,
+      productRouteId: bindForm.routeId,
+      processId: item.id,
+      productModelId: bindForm.productModelId,
+      dragSort: item.dragSort ?? index + 1,
+      isQuality: item.isQuality ?? false,
+      reportUserIds: Array.isArray(processUser.userIds) ? processUser.userIds.join(",") : "",
+    };
+  });
+
+const fetchBindProcessList = async routeId => {
+  if (!routeId) {
+    resetBindProcessUsers();
+    return;
+  }
+
+  try {
+    const res = await findProcessRouteItemList({
+      routeId,
+			productModelId: bindForm.productModelId,
+    });
+    bindProcessList.value = res.data || [];
+    bindForm.processUserList = createBindProcessUserList(bindProcessList.value);
+    ensureUserOptions();
+  } catch (error) {
+    console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触", error);
+    proxy.$modal.msgError("鑾峰彇宸ュ簭鍒楄〃澶辫触");
+    resetBindProcessUsers();
+  }
+};
+
+const handleBindRouteChange = routeId => {
+  fetchBindProcessList(routeId);
+};
+
+const handleBindProcessUserChange = (index, userIds) => {
+  const selectedUsers = userOptions.value.filter(user => Array.isArray(userIds) && userIds.includes(user.userId));
+  bindForm.processUserList[index].userNames = selectedUsers.map(user => user.nickName).join(",");
+};
+
+const removeBindProcessItem = index => {
+  bindProcessList.value.splice(index, 1);
+  bindForm.processUserList.splice(index, 1);
+};
+
+const openBindRouteDialog = async row => {
+  bindForm.orderId = row.id;
+  bindForm.productId = row.id ?? null;
+  bindForm.productModelId = row.productModelId ?? null;
+  bindForm.routeId = null;
+  bindForm.processUserList = [];
+  bindRouteDialogVisible.value = true;
+  routeOptions.value = [];
+  resetBindProcessUsers();
+
+  if (!row.productModelId) {
+    proxy.$modal.msgWarning("褰撳墠璁㈠崟缂哄皯浜у搧鍨嬪彿锛屾棤娉曟煡璇㈠伐鑹鸿矾绾�");
+    bindRouteDialogVisible.value = false;
+    return;
+  }
+
+  bindRouteLoading.value = true;
+  try {
+    const res = await listProcessRoute({
+      productId: bindForm.productId,
+      productModelId: row.productModelId,
+    });
+    routeOptions.value = res.data || [];
+  } catch (error) {
+    console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触", error);
+    proxy.$modal.msgError("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触");
+  } finally {
+    bindRouteLoading.value = false;
+  }
+};
+
+const handleBindRouteConfirm = async () => {
+  if (!bindForm.routeId) {
+    proxy.$modal.msgWarning("璇烽�夋嫨宸ヨ壓璺嚎");
+    return;
+  }
+  if (!bindForm.processUserList.length) {
+    proxy.$modal.msgWarning("褰撳墠宸ヨ壓璺嚎涓嬫病鏈夊伐搴�");
+    return;
+  }
+  if (bindForm.processUserList.some(item => !Array.isArray(item.userIds) || item.userIds.length === 0)) {
+    proxy.$modal.msgWarning("璇蜂负姣忛亾宸ュ簭閫夋嫨鎶ュ伐浜哄憳");
+    return;
+  }
+
+  bindRouteSaving.value = true;
+  try {
+    await bindingRoute({
+      id: bindForm.orderId,
+      routeId: bindForm.routeId,
+      processRouteItems: buildBindProcessRouteItems(),
+      processUserList: bindForm.processUserList.map(item => ({
+        ...item,
+        userIds: item.userIds.join(","),
+      })),
+    });
+    proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
+    bindRouteDialogVisible.value = false;
+    getList();
+  } catch (error) {
+    console.error("缁戝畾宸ヨ壓璺嚎澶辫触", error);
+    proxy.$modal.msgError("缁戝畾宸ヨ壓璺嚎澶辫触");
+  } finally {
+    bindRouteSaving.value = false;
+  }
+};
+
+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.value, ...page };
+  params.entryDate = undefined;
+
+  productOrderListPage(params)
+    .then(res => {
+      tableData.value = res.data.records;
+      page.total = res.data.total;
+    })
+    .finally(() => {
+      tableLoading.value = false;
+    });
+};
+
+const showRouteItemModal = async row => {
+  const orderId = row.id;
+  try {
+    const res = await getOrderProcessRouteMain(orderId);
+    const detail = res.data || {};
+    if (!detail.id) {
+      proxy.$modal.msgWarning("鏈壘鍒板叧鑱旂殑宸ヨ壓璺嚎");
+      return;
+    }
+
+    router.push({
+      path: "/productionManagement/processRouteItem",
+      query: {
+        id: detail.id,
+        processRouteCode: detail.processRouteCode || "",
+        productName: detail.productName || "",
+        model: detail.model || "",
+        bomNo: detail.bomNo || "",
+        description: detail.description || "",
+        orderId,
+        type: "order",
+      },
+    });
+  } catch (error) {
+    console.error("鑾峰彇宸ヨ壓璺嚎淇℃伅澶辫触", error);
+    proxy.$modal.msgError("鑾峰彇宸ヨ壓璺嚎淇℃伅澶辫触");
+  }
+};
+
+const showProductStructure = row => {
+  router.push({
+    path: "/productionManagement/productStructureDetail",
+    query: {
+      id: row.id,
+      bomNo: row.bomNo || "",
+      productName: row.productCategory || "",
+      productModelName: row.specificationModel || "",
+      orderId: row.id,
+      type: "order",
+    },
+  });
+};
+
+const handleSelectionChange = selection => {
+  selectedRows.value = selection;
+};
+
+const handleDelete = () => {
+  if (!selectedRows.value.length) {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+
+  const ids = selectedRows.value.map(item => item.id);
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => delProductOrder(ids))
+    .then(() => {
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      getList();
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑堝垹闄�");
+    });
+};
+
 const handleOut = () => {
-	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-		confirmButtonText: "纭",
-		cancelButtonText: "鍙栨秷",
-		type: "warning",
-	})
-		.then(() => {
-			proxy.download("/basic/customer/export", {}, "瀹㈡埛妗f.xlsx");
-		})
-		.catch(() => {
-			proxy.$modal.msg("宸插彇娑�");
-		});
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/productOrder/export", { ...searchForm.value }, "鐢熶骇璁㈠崟.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑堝鍑�");
+    });
 };
 
 onMounted(() => {
-	getList();
+  getList();
 });
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.search_form {
+  align-items: start;
+}
+
+:deep(.yellow) {
+  background-color: #faf0de;
+}
+
+:deep(.pink) {
+  background-color: #fae1de;
+}
+
+:deep(.red) {
+  background-color: #f80202;
+}
+
+:deep(.purple) {
+  background-color: #f4defa;
+}
+
+.process-user-list {
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 14px;
+  padding: 14px;
+  border-radius: 12px;
+  background: #f7f9fc;
+  border: 1px solid #e8eef5;
+}
+
+.process-user-item {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr);
+  gap: 16px;
+  padding: 12px 14px;
+  border-radius: 10px;
+  background: #fff;
+  border: 1px solid #edf2f7;
+}
+
+.process-user-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+}
+
+.process-user-name {
+  color: #1f2d3d;
+  font-weight: 500;
+  line-height: 1.4;
+}
+
+.process-user-remove {
+  flex-shrink: 0;
+  padding: 0;
+}
+
+.process-user-select {
+  width: 100%;
+}
+
+@media (max-width: 768px) {
+  .process-user-item {
+    grid-template-columns: 1fr;
+    gap: 10px;
+  }
+}
+</style>

--
Gitblit v1.9.3