From 012aa7fd84c4de6216f5be6e8a05ed52f7fdf429 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 09 十二月 2025 13:16:28 +0800
Subject: [PATCH] 1.海川开心-给admin开放所有可编辑,删除的权限。

---
 src/views/productionManagement/productionDispatching/index.vue |  531 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 450 insertions(+), 81 deletions(-)

diff --git a/src/views/productionManagement/productionDispatching/index.vue b/src/views/productionManagement/productionDispatching/index.vue
index 70a3de9..e58e87e 100644
--- a/src/views/productionManagement/productionDispatching/index.vue
+++ b/src/views/productionManagement/productionDispatching/index.vue
@@ -1,5 +1,32 @@
 <template>
 	<div class="app-container">
+		<!-- 鐐掓満1-4 灞曠ず锛堟�婚噺 / 姝e湪鐢熶骇閲� / 绌轰綑閲忥級 -->
+		<div class="machines-grid">
+			<div v-for="machine in machines" :key="machine.id" class="machine-card">
+				<div class="machine-title">{{ machine.name }}</div>
+				<div class="machine-metrics">
+				<div class="machine-control">
+					<span>鎬婚噺(kg)锛�</span>
+					<el-input-number v-model="machineData[machine.name].workLoad" :min="0" :step="1" size="small" />
+				</div>
+				<div><span> 棰勮鎶曞叆閲�(kg)锛�</span><span>{{ machineData[machine.name].currentWorkLoad }}</span></div>
+				<div><span>绌轰綑宸ヤ綔閲�(kg)锛�</span><span>{{ machineData[machine.name].vacant }}</span></div>
+			</div>
+			</div>
+			<div class="save-button-container">
+				<div class="loss-rate-container">
+					<span class="loss-rate-label">鎹熻�楃巼(%)锛�</span>
+					<el-select v-model="rate" placeholder="璇烽�夋嫨鎹熻�楃巼" style="width: 120px" size="small">
+						<el-option label="6" :value="6" />
+						<el-option label="7" :value="7" />
+						<el-option label="8" :value="8" />
+						<el-option label="9" :value="9" />
+						<el-option label="10" :value="10" />
+					</el-select>
+				</div>
+				<el-button type="primary" @click="saveMachineTotals" size="small">淇濆瓨璁剧疆</el-button>
+			</div>
+		</div>
 		<div class="search_form">
 			<div>
 				<span class="search_title">瀹㈡埛鍚嶇О锛�</span>
@@ -11,25 +38,31 @@
 					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-input-->
+<!--					v-model="searchForm.projectName"-->
+<!--					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
-				>
+										placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
+				<el-checkbox
+					style="margin-left: 10px"
+					v-model="searchForm.status"
+					label="涓嶆樉绀哄緟鎺掓暟閲�0"
+					@change="handleQuery"
+				/>
+				<el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
 			</div>
 			<div>
-				<el-button type="primary" @click="openForm('add')">鐢熶骇娲惧伐</el-button>
-			</div>
+			<el-button type="primary" @click="openForm('add')">鐢熶骇娲惧伐</el-button>
+			<el-button type="success" @click="openAutoDispatch">鑷姩娲惧伐</el-button>
+			<el-button @click="handleOut">瀵煎嚭</el-button>
+		</div>
 		</div>
 		<div class="table_list">
 			<PIMTable
@@ -45,79 +78,89 @@
 			></PIMTable>
 		</div>
 		<form-dia ref="formDia" @close="handleQuery"></form-dia>
+		<auto-dispatch-dia ref="autoDispatchDia" @close="handleQuery"></auto-dispatch-dia>
 	</div>
 </template>
 
 <script setup>
-import {onMounted, ref} from "vue";
+import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick, computed, watch} from "vue";
 import FormDia from "@/views/productionManagement/productionDispatching/components/formDia.vue";
-import {staffJoinDel, staffJoinListPage} from "@/api/personnelManagement/onboarding.js";
-import {ElMessageBox} from "element-plus";
+import AutoDispatchDia from "@/views/productionManagement/productionDispatching/components/autoDispatchDia.vue";
 import dayjs from "dayjs";
+import {schedulingListPage, schedulingList, addSpeculatTrading, updateSpeculatTrading, getLossRate, addLossRate, updateLossRate} from "@/api/productionManagement/productionOrder.js";
+import { ElMessageBox } from "element-plus";
 
 const data = reactive({
 	searchForm: {
-		staffName: "",
-		entryDate: [
-			dayjs().format("YYYY-MM-DD"),
-			dayjs().add(1, "day").format("YYYY-MM-DD"),
-		], // 褰曞叆鏃ユ湡
+		customerName: "",
+		projectName: "",
+		status: "",
+		entryDate: [dayjs().format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD")], // 褰曞叆鏃ユ湡锛岄粯璁ゅ綋澶�
 		entryDateStart: dayjs().format("YYYY-MM-DD"),
-		entryDateEnd: dayjs().add(1, "day").format("YYYY-MM-DD"),
+		entryDateEnd: dayjs().format("YYYY-MM-DD"),
 	},
 });
 const { searchForm } = toRefs(data);
 const tableColumn = ref([
 	{
-		label: "褰曞叆鏃ユ湡",
-		prop: "staffNo",
-	},
-	{
 		label: "鍚堝悓鍙�",
-		prop: "staffName",
+		prop: "salesContractNo",
+		width: 220,
 	},
-	{
-		label: "瀹㈡埛鍚堝悓鍙�",
-		prop: "addressPhone",
-		width: 250,
-	},
+	// {
+	// 	label: "瀹㈡埛鍚堝悓鍙�",
+	// 	prop: "customerContractNo",
+	// 	width: 250,
+	// },
 	{
 		label: "瀹㈡埛鍚嶇О",
-		prop: "contactPerson",
+		prop: "customerName",
+		width: 250,
 	},
-	{
-		label: "椤圭洰鍚嶇О",
-		prop: "contactPhone",
-		width:150
-	},
+	// {
+	// 	label: "椤圭洰鍚嶇О",
+	// 	prop: "projectName",
+	// 	width:300
+	// },
 	{
 		label: "浜у搧澶х被",
-		prop: "basicBankAccount",
-		width: 220,
+		prop: "productCategory",
+		width: 160,
 	},
 	{
 		label: "瑙勬牸鍨嬪彿",
-		prop: "bankAccount",
+		prop: "specificationModel",
+		width: 120,
+	},
+	{
+		label: "缁戝畾鏈哄櫒",
+		prop: "speculativeTradingName",
 		width: 220,
 	},
 	{
 		label: "鍗曚綅",
-		prop: "bankCode",
-		width:220
+		prop: "unit",
+		width:90
+	},
+	{
+		label: "褰曞叆鏃ユ湡",
+		prop: "entryDate",
+		width: 120,
 	},
 	{
 		label: "鏁伴噺",
-		prop: "maintainer",
+		prop: "quantity",
 	},
 	{
 		label: "鎺掍骇鏁伴噺",
-		prop: "maintenanceTime",
+		prop: "schedulingNum",
 		width: 100,
 	},
 	{
 		label: "寰呮帓鏁伴噺",
-		prop: "maintenanceTime",
+		prop: "pendingQuantity",
 		width: 100,
+		fixed: 'right',
 	},
 ]);
 const tableData = ref([]);
@@ -129,7 +172,140 @@
 	total: 0,
 });
 const formDia = ref()
+const autoDispatchDia = ref()
 const { proxy } = getCurrentInstance()
+
+// 鐐掓満鏁版嵁
+const machineData = reactive({
+	"鐐掓満1": { workLoad: 0, currentWorkLoad: 0, vacant: 0 },
+	"鐐掓満2": { workLoad: 0, currentWorkLoad: 0, vacant: 0 },
+	"鐐掓満3": { workLoad: 0, currentWorkLoad: 0, vacant: 0 },
+	"鐐掓満4": { workLoad: 0, currentWorkLoad: 0, vacant: 0 }
+})
+
+// 鐐掓満閰嶇疆鏁扮粍
+const machines = [
+	{ id: 1, name: '鐐掓満1' },
+	{ id: 2, name: '鐐掓満2' },
+	{ id: 3, name: '鐐掓満3' },
+	{ id: 4, name: '鐐掓満4' }
+]
+
+// 淇濆瓨鐐掓満鎬婚噺璁剧疆
+const saveMachineTotals = () => {
+	// 楠岃瘉鎹熻�楃巼鏄惁宸查�夋嫨
+	if (rate.value === null || rate.value === undefined || isNaN(rate.value)) {
+		proxy.$message.warning('璇烽�夋嫨鎹熻�楃巼');
+		return;
+	}
+	
+	// 鏋勯�犱繚瀛樻暟鎹暟缁勶紝浣跨敤machines鏁扮粍寰幆鏋勫缓
+	const saveData = machines.map(machine => {
+		const saveItem = {
+			name: machine.name, // 鐐掓満鍚嶇О
+			workLoad: machineData[machine.name].workLoad,  // 鎬婚噺
+			currentWorkLoad: machineData[machine.name].currentWorkLoad, //  棰勮鎶曞叆閲�
+			vacant: machineData[machine.name].vacant   // 绌轰綑閲�
+		};
+		
+		// 濡傛灉鏄慨鏀规搷浣滐紝闇�瑕佷紶閫抜d瀛楁
+		if (hasQueryData.value) {
+			const queryData = getMachineQueryData(machine.id);
+			if (queryData && queryData.id) {
+				saveItem.id = queryData.id;
+			}
+		}
+		
+		return saveItem;
+	});
+	
+	// 鏋勯�犳崯鑰楃巼鏁版嵁
+	const rateData = {
+		rate: rate.value
+	};
+	
+	// 濡傛灉鏈塈D锛岃鏄庢槸淇敼鎿嶄綔
+	if (rateId.value) {
+		rateData.id = rateId.value;
+	}
+	
+	// 鏍规嵁鏄惁鏈夋煡璇㈡暟鎹喅瀹氳皟鐢ㄦ柊澧炴帴鍙h繕鏄慨鏀规帴鍙�
+	const saveApi = hasQueryData.value ? updateSpeculatTrading : addSpeculatTrading;
+	const successMessage = hasQueryData.value ? '鐐掓満璁剧疆淇敼鎴愬姛' : '鐐掓満璁剧疆鏂板鎴愬姛';
+	
+	// 鏍规嵁鏄惁鏈塈D鍐冲畾璋冪敤鏂板鎺ュ彛杩樻槸淇敼鎺ュ彛
+	const rateApi = rateId.value ? updateLossRate : addLossRate;
+	const rateSuccessMessage = rateId.value ? '鎹熻�楃巼淇敼鎴愬姛' : '鎹熻�楃巼鏂板鎴愬姛';
+	
+	// 骞惰璋冪敤涓や釜鎺ュ彛
+	Promise.all([
+		saveApi(saveData),
+		rateApi(rateData)
+	]).then(([saveRes, rateRes]) => {
+		proxy.$message.success(successMessage);
+		proxy.$message.success(rateSuccessMessage);
+		
+		// 淇濆瓨鎴愬姛鍚庯紝璁剧疆hasQueryData涓簍rue锛屼笅娆′繚瀛樺皢璋冪敤淇敼鎺ュ彛
+		if (!hasQueryData.value) {
+			hasQueryData.value = true;
+		}
+		
+		// 濡傛灉杩斿洖浜咺D锛屼繚瀛樿捣鏉�
+		if (rateRes && rateRes.data && rateRes.data.id) {
+			rateId.value = rateRes.data.id;
+		}
+		
+		// 淇濆瓨鎴愬姛鍚庨噸鏂拌皟鐢ㄦ煡璇㈤〉闈�
+		getList();
+	}).catch(err => {
+		proxy.$message.error('淇濆瓨澶辫触');
+		console.error('淇濆瓨澶辫触:', err);
+	});
+}
+
+// 鑾峰彇鐐掓満鏌ヨ鏁版嵁
+const machineQueryData = ref([]);
+
+const getMachineQueryData = (machineId) => {
+	return machineQueryData.value.find(item => item.id === machineId);
+};
+
+const getMachineIndex = (item) => {
+	// 鍏煎澶氱瀛楁鍛藉悕锛岃繑鍥� 1-4 涔嬩竴锛屽惁鍒欒繑鍥� 0锛堟湭鐭ワ級
+	const candidates = [item.machineId, item.machineNo, item.machine, item.deviceNo, item.deviceId]
+	for (const v of candidates) {
+		if (v === undefined || v === null) continue
+		const n = Number(String(v).replace(/[^\d]/g, "")) // 鎶藉彇鏁板瓧
+		if ([1,2,3,4].includes(n)) return n
+	}
+	return 0
+}
+
+const computeTodaySummary = () => {
+	const todayStr = dayjs().format("YYYY-MM-DD")
+	
+	// 閲嶇疆鎵�鏈夌倰鏈烘暟鎹�
+	machines.forEach(machine => {
+		machineData[machine.name] = { workLoad: 0, currentWorkLoad: 0, vacant: 0 }
+	})
+	
+	tableData.value.forEach(item => {
+		// 浠呯粺璁″綋澶�
+		const isToday = dayjs(item.entryDate).format("YYYY-MM-DD") === todayStr
+		if (!isToday) return
+		
+		// 浣跨敤姝g‘鐨勫瓧娈靛悕锛歸orkLoad锛堢倰鏈哄伐浣滈噺锛�, currentWorkLoad锛堢倰鏈烘鍦ㄥ伐浣滈噺锛�
+		const workLoad = Number(item.workLoad) || 0
+		const currentWorkLoad = Number(item.currentWorkLoad) || 0
+		const machineName = item.speculativeTradingName || '鐐掓満1'
+		
+		if (machineData[machineName]) {
+			machineData[machineName].workLoad += workLoad
+			machineData[machineName].currentWorkLoad += currentWorkLoad
+			machineData[machineName].vacant = machineData[machineName].workLoad - machineData[machineName].currentWorkLoad
+		}
+	})
+}
 
 // 鏌ヨ鍒楄〃
 /** 鎼滅储鎸夐挳鎿嶄綔 */
@@ -137,13 +313,63 @@
 	page.current = 1;
 	getList();
 };
+
+// 鏄惁鏈夋煡璇㈡暟鎹�
+const hasQueryData = ref(false)
+// 鎹熻�楃巼
+const rate = ref(6)
+// 鎹熻�楃巼ID
+const rateId = ref(null)
+
+// 鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
+const getMachineProductionData = () => {
+	schedulingList().then((res) => {
+		// 澶勭悊鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
+		if (res.data && Array.isArray(res.data)) {
+			// 璁剧疆鏄惁鏈夋煡璇㈡暟鎹�
+			hasQueryData.value = res.data.length > 0
+			
+			// 淇濆瓨鏌ヨ鏁版嵁鍒癿achineQueryData
+			machineQueryData.value = res.data;
+			
+			// 閲嶇疆鎵�鏈夌倰鏈烘暟鎹�
+			machines.forEach(machine => {
+				machineData[machine.name] = { workLoad: 0, currentWorkLoad: 0, vacant: 0 }
+			});
+			
+			// 閬嶅巻鏁版嵁锛屾牴鎹煡璇㈣繑鍥炵殑鏁版嵁缁撴瀯澶勭悊
+			res.data.forEach(item => {
+				// 鏍规嵁name瀛楁纭畾鐐掓満
+				const machineName = item.name || '鐐掓満1';
+				
+				if (machineData[machineName]) {
+					// 濡傛灉鏌ヨ鏁版嵁涓湁workLoad锛屽垯鍒濆鍖栫倰鏈烘�婚噺
+					if (item.workLoad !== null && item.workLoad !== undefined) {
+						machineData[machineName].workLoad = Number(item.workLoad) || 0;
+					}
+					
+					// 濡傛灉鏌ヨ鏁版嵁涓湁currentWorkLoad锛屽垯璁剧疆姝e湪宸ヤ綔閲�
+					if (item.currentWorkLoad !== null && item.currentWorkLoad !== undefined) {
+						machineData[machineName].currentWorkLoad = Number(item.currentWorkLoad) || 0;
+					}
+					
+					// 璁$畻绌轰綑宸ヤ綔閲�
+					machineData[machineName].vacant = machineData[machineName].workLoad - machineData[machineName].currentWorkLoad;
+				}
+			});
+		}
+	}).catch(err => {
+		console.error('鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹け璐�:', err);
+	});
+};
+
 const changeDaterange = (value) => {
 	if (value) {
-		searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
-		searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+		searchForm.value.entryDateStart = value[0];
+		searchForm.value.entryDateEnd = value[1];
 	} else {
-		searchForm.entryDateStart = undefined;
-		searchForm.entryDateEnd = undefined;
+		searchForm.value.entryDateStart = undefined;
+		searchForm.value.entryDateEnd = undefined;
 	}
 	handleQuery();
 };
@@ -154,13 +380,44 @@
 };
 const getList = () => {
 	tableLoading.value = true;
-	staffJoinListPage({...page, ...searchForm.value}).then(res => {
+	// 鏋勯�犱竴涓柊鐨勫璞★紝涓嶅寘鍚玡ntryDate瀛楁
+	const params = { ...searchForm.value, ...page };
+	params.entryDate = undefined
+	schedulingListPage(params).then((res) => {
 		tableLoading.value = false;
-		tableData.value = res.data.records
+		// 澶勭悊姣忔潯鏁版嵁锛屽鍔爌endingQuantity瀛楁
+		tableData.value = res.data.records.map(item => ({
+			...item,
+			pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0)
+		}));
 		page.total = res.data.total;
-	}).catch(err => {
+		computeTodaySummary()
+		
+		// 鍚屾椂鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
+		getMachineProductionData();
+		// 鑾峰彇鎹熻�楃巼鏁版嵁
+		getLossRateData();
+	}).catch(() => {
 		tableLoading.value = false;
 	})
+};
+
+// 鑾峰彇鎹熻�楃巼鏁版嵁
+const getLossRateData = () => {
+	getLossRate().then((res) => {
+		const data = res.data || res;
+		if (data && data.rate !== undefined && data.rate !== null) {
+			rate.value = Number(data.rate); // 纭繚杞崲涓烘暟瀛�
+			rateId.value = data.id || null;
+		} else {
+			rate.value = 6;
+			rateId.value = null;
+		}
+	}).catch(err => {
+		console.error('鑾峰彇鎹熻�楃巼鏁版嵁澶辫触:', err);
+		rate.value = 6;
+		rateId.value = null;
+	});
 };
 // 琛ㄦ牸閫夋嫨鏁版嵁
 const handleSelectionChange = (selection) => {
@@ -168,44 +425,40 @@
 };
 
 // 鎵撳紑寮规
-const openForm = (type, row) => {
+const openForm = (type) => {
 	if (selectedRows.value.length !== 1) {
 		proxy.$message.error("璇烽�夋嫨涓�鏉℃暟鎹�");
 		return;
 	}
-	if (selectedRows.value[0].unPaymentAmountTotal == 0) {
-		proxy.$message.warning("鏃犻渶鍐嶄粯娆�");
+	if (selectedRows.value[0].pendingQuantity == 0) {
+		proxy.$message.warning("鏃犻渶鍐嶆淳宸�");
 		return;
 	}
 	nextTick(() => {
-		formDia.value?.openDialog(type, row)
+		formDia.value?.openDialog(type, selectedRows.value[0])
 	})
 };
 
-// 鍒犻櫎
-const handleDelete = () => {
-	let ids = [];
-	if (selectedRows.value.length > 0) {
-		ids = selectedRows.value.map((item) => item.id);
-	} else {
-		proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+// 鎵撳紑鑷姩娲惧伐寮规
+const openAutoDispatch = () => {
+	if (selectedRows.value.length === 0) {
+		proxy.$message.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
 		return;
 	}
-	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
-		confirmButtonText: "纭",
-		cancelButtonText: "鍙栨秷",
-		type: "warning",
+	
+	// 杩囨护鎺夊緟鎺掍骇鏁伴噺涓�0鐨勬暟鎹�
+	const validRows = selectedRows.value.filter(row => row.pendingQuantity > 0);
+	
+	if (validRows.length === 0) {
+		proxy.$message.warning("閫変腑鐨勬暟鎹棤闇�娲惧伐");
+		return;
+	}
+	
+	nextTick(() => {
+		autoDispatchDia.value?.openDialog('auto', validRows)
 	})
-		.then(() => {
-			staffJoinDel(ids).then((res) => {
-				proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-				getList();
-			});
-		})
-		.catch(() => {
-			proxy.$modal.msg("宸插彇娑�");
-		});
 };
+
 // 瀵煎嚭
 const handleOut = () => {
 	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
@@ -214,15 +467,131 @@
 		type: "warning",
 	})
 		.then(() => {
-			proxy.download("/staff/staffJoinLeaveRecord/export", {staffState: 1}, "浜哄憳鍏ヨ亴.xlsx");
+			proxy.download("/salesLedger/scheduling/exportOne", {}, "鐢熶骇娲惧伐.xlsx");
 		})
 		.catch(() => {
 			proxy.$modal.msg("宸插彇娑�");
 		});
 };
+
 onMounted(() => {
 	getList();
+	getLossRateData();
 });
 </script>
 
-<style scoped></style>
+<style scoped>
+.summary-bar{
+	display: flex;
+	gap: 16px;
+	margin: 10px 0 16px 0;
+}
+.summary-item{
+	background: #f5f7fa;
+	border: 1px solid #ebeef5;
+	border-radius: 6px;
+	padding: 10px 16px;
+	min-width: 160px;
+}
+.summary-label{
+	color: #909399;
+	font-size: 12px;
+	margin-bottom: 6px;
+}
+.summary-value{
+	color: #303133;
+	font-size: 20px;
+	font-weight: 600;
+}
+.summary-control{
+	display: flex;
+	align-items: center;
+	height: 28px;
+}
+.machines-grid{
+	display: grid;
+	grid-template-columns: repeat(4, 1fr);
+	gap: 16px;
+	margin-bottom: 20px;
+	padding: 16px;
+	background: #f8f9fa;
+	border-radius: 8px;
+	border: 1px solid #e9ecef;
+}
+.machine-card{
+	border: 1px solid #dee2e6;
+	border-radius: 8px;
+	padding: 16px;
+	background: #fff;
+	box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+	transition: all 0.3s ease;
+}
+.machine-card:hover{
+	transform: translateY(-2px);
+	box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+}
+.machine-title{
+	font-weight: 600;
+	font-size: 16px;
+	margin-bottom: 12px;
+	color: #2c3e50;
+	text-align: center;
+	padding-bottom: 8px;
+	border-bottom: 2px solid #3498db;
+}
+.machine-metrics{
+	display: flex;
+	flex-direction: column;
+	gap: 10px;
+	color: #495057;
+}
+.machine-control{
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	gap: 8px;
+	padding: 8px 0;
+	border-bottom: 1px solid #f1f3f4;
+}
+.machine-control span{
+	font-size: 14px;
+	white-space: nowrap;
+	color: #6c757d;
+	font-weight: 500;
+}
+.machine-metrics > div:not(.machine-control) {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding: 4px 0;
+	font-size: 14px;
+}
+.machine-metrics > div:not(.machine-control) span:first-child {
+	color: #6c757d;
+}
+.machine-metrics > div:not(.machine-control) span:last-child {
+	font-weight: 600;
+	color: #2c3e50;
+}
+.save-button-container{
+	grid-column: 1 / -1;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	gap: 16px;
+	margin-top: 16px;
+	padding-top: 16px;
+	border-top: 1px solid #e9ecef;
+}
+.loss-rate-container{
+	display: flex;
+	align-items: center;
+	gap: 8px;
+}
+.loss-rate-label{
+	font-size: 14px;
+	color: #6c757d;
+	font-weight: 500;
+	white-space: nowrap;
+}
+</style>

--
Gitblit v1.9.3