From d51e4238adb806e6f5f9c20f20efc215532142d3 Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期四, 05 二月 2026 17:24:00 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New' into dev_New

---
 src/views/inventoryManagement/vehicleFuelManagement/index.vue   |  556 ++++++++++
 src/views/personnelManagement/attendanceCheckin/index.vue       |  469 ++++++++
 src/views/equipmentManagement/attendanceManagement/index.vue    |  403 +++++++
 src/views/inventoryManagement/transportTaskManagement/index.vue |  692 ++++++++++++
 src/views/inventoryManagement/vehicleManagement/index.vue       |  581 ++++++++++
 src/views/qualityManagement/afterSalesTraceability/index.vue    |  595 ++++++++++
 6 files changed, 3,296 insertions(+), 0 deletions(-)

diff --git a/src/views/equipmentManagement/attendanceManagement/index.vue b/src/views/equipmentManagement/attendanceManagement/index.vue
new file mode 100644
index 0000000..a346d0b
--- /dev/null
+++ b/src/views/equipmentManagement/attendanceManagement/index.vue
@@ -0,0 +1,403 @@
+<template>
+  <div class="app-container">
+    <!-- 鏈嶅姟璇勪环姒傝锛氭ā鎷熷憳宸ヤ笟缁╄瘎鍒� -->
+    <el-row :gutter="16" class="mb16">
+      <el-col :span="8">
+        <el-card shadow="never">
+          <div class="kpi-title">鏈湀骞冲潎璇勫垎</div>
+          <div class="kpi-value">
+            {{ overallAvgScore.toFixed(1) }}
+            <span class="kpi-unit">鍒�</span>
+          </div>
+          <el-rate v-model="overallAvgScore" disabled show-score score-template="{value} / 5" />
+        </el-card>
+      </el-col>
+      <el-col :span="8">
+        <el-card shadow="never">
+          <div class="kpi-title">宸茶瘎浠风淮淇伐鍗�</div>
+          <div class="kpi-value">
+            {{ ratedCount }}
+            <span class="kpi-unit">鍗�</span>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="8">
+        <el-card shadow="never">
+          <div class="kpi-title">寰呰瘎浠风淮淇伐鍗�</div>
+          <div class="kpi-value kpi-warning">
+            {{ pendingCount }}
+            <span class="kpi-unit">鍗�</span>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 鏌ヨ鏉′欢锛氱鐞嗗憳鎸夊伐绋嬪笀 / 瀹㈡埛 / 鏃堕棿杩芥函璇勪环 -->
+    <div class="search_form">
+      <div>
+        <span class="search_title">缁翠慨宸ョ▼甯堬細</span>
+        <el-input
+          v-model="searchForm.engineerName"
+          placeholder="璇疯緭鍏ュ伐绋嬪笀濮撳悕"
+          style="width: 180px"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">瀹㈡埛鍚嶇О锛�</span>
+        <el-input
+          v-model="searchForm.customerName"
+          placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+          style="width: 180px"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">瀹屾垚鏃堕棿锛�</span>
+        <el-date-picker
+          v-model="searchForm.dateRange"
+          type="daterange"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          clearable
+        />
+
+        <span class="search_title ml10">璇勪环鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.status"
+          placeholder="璇烽�夋嫨"
+          style="width: 140px"
+          clearable
+        >
+          <el-option label="寰呰瘎浠�" value="pending" />
+          <el-option label="宸茶瘎浠�" value="rated" />
+        </el-select>
+
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+        <el-button @click="resetSearch">閲嶇疆</el-button>
+      </div>
+      <div>
+        <el-button icon="Download" @click="handleExport">
+          瀵煎嚭璇勪环缁熻
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 缁翠慨璇勪环鍒楄〃锛氭ā鎷熲�滅淮淇畬鎴愬悗瑙﹀彂璇勪环鈥濆満鏅� -->
+    <div class="table_list">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%"
+        height="calc(100vh - 24em)"
+        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+      >
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column prop="orderNo" label="缁翠慨宸ュ崟鍙�" width="160" show-overflow-tooltip />
+        <el-table-column prop="deviceName" label="璁惧鍚嶇О" width="160" show-overflow-tooltip />
+        <el-table-column prop="customerName" label="瀹㈡埛鍚嶇О" width="180" show-overflow-tooltip />
+        <el-table-column prop="engineerName" label="缁翠慨宸ョ▼甯�" width="120" />
+        <el-table-column prop="completeTime" label="缁翠慨瀹屾垚鏃堕棿" width="180" />
+        <el-table-column prop="score" label="鏄熺骇璇勫垎" width="140" align="center">
+          <template #default="scope">
+            <el-rate v-if="scope.row.score" v-model="scope.row.score" disabled />
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="璇勪环鐘舵��" width="100" align="center">
+          <template #default="scope">
+            <el-tag
+              :type="scope.row.status === 'rated' ? 'success' : 'warning'"
+              size="small"
+            >
+              {{ scope.row.status === 'rated' ? '宸茶瘎浠�' : '寰呰瘎浠�' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="feedback" label="瀹㈡埛鍙嶉" show-overflow-tooltip />
+        <el-table-column label="鎿嶄綔" width="160" align="center" fixed="right">
+          <template #default="scope">
+            <el-button
+              v-if="scope.row.status === 'pending'"
+              type="primary"
+              link
+              size="small"
+              @click="openEvaluate(scope.row)"
+            >
+              鍘昏瘎浠�
+            </el-button>
+            <el-button
+              v-else
+              type="primary"
+              link
+              size="small"
+              @click="openEvaluate(scope.row)"
+            >
+              鏌ョ湅 / 淇敼璇勪环
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 璇勪环寮规锛氭ā鎷熲�滅淮淇畬鎴愬悗寮瑰嚭瀹㈡埛绔瘎浠封�� -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="520px"
+      destroy-on-close
+    >
+      <div class="dialog-order-info" v-if="currentOrder">
+        <div>缁翠慨宸ュ崟锛歿{ currentOrder.orderNo }}</div>
+        <div>璁惧鍚嶇О锛歿{ currentOrder.deviceName }}</div>
+        <div>缁翠慨宸ョ▼甯堬細{{ currentOrder.engineerName }}</div>
+      </div>
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="100px"
+      >
+        <el-form-item label="鏄熺骇璇勫垎锛�" prop="score">
+          <el-rate v-model="form.score" :max="5" />
+        </el-form-item>
+        <el-form-item label="鏂囧瓧鍙嶉锛�" prop="feedback">
+          <el-input
+            v-model="form.feedback"
+            type="textarea"
+            :rows="4"
+            placeholder="璇峰~鍐欏鏈缁翠慨鏈嶅姟鐨勮瘎浠凤紝濡傚搷搴旈�熷害銆佷笓涓氱▼搴︺�佹矡閫氫綋楠岀瓑"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="handleSubmit">鎻� 浜� 璇� 浠�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from "vue";
+import { ElMessage } from "element-plus";
+
+// 妯℃嫙缁翠慨宸ュ崟 + 瀹㈡埛璇勪环鏁版嵁
+const rawOrders = ref([
+  {
+    id: 1,
+    orderNo: "WX-2024-1201-001",
+    deviceName: "绌哄帇鏈� A1 鍙�",
+    customerName: "鍗庡崡鐢靛瓙绉戞妧鏈夐檺鍏徃",
+    engineerName: "鐜嬪笀鍌�",
+    completeTime: "2024-12-01 10:30:00",
+    completeDate: "2024-12-01",
+    status: "rated",
+    score: 5,
+    feedback: "缁翠慨闈炲父涓撲笟锛屽搷搴旈�熷害蹇紝鐜板満瑙i噴涔熷緢娓呮櫚锛屾弧鎰忋��",
+  },
+  {
+    id: 2,
+    orderNo: "WX-2024-1201-002",
+    deviceName: "娉ㄥ鏈� B3 鍙�",
+    customerName: "鍗庝笢绮惧瘑鍒堕�犳湁闄愬叕鍙�",
+    engineerName: "鏉庡笀鍌�",
+    completeTime: "2024-12-01 15:20:00",
+    completeDate: "2024-12-01",
+    status: "rated",
+    score: 4,
+    feedback: "鏁翠綋杩樹笉閿欙紝灏辨槸鍒板満鏃堕棿绋嶅井闀夸簡涓�鐐癸紝甯屾湜鍚庨潰鑳藉啀蹇竴浜涖��",
+  },
+  {
+    id: 3,
+    orderNo: "WX-2024-1202-003",
+    deviceName: "鐒婃帴鏈哄櫒浜� C2 鍙�",
+    customerName: "瑗垮崡鏂拌兘婧愮鎶�鑲′唤",
+    engineerName: "寮犲笀鍌�",
+    completeTime: "2024-12-02 11:05:00",
+    completeDate: "2024-12-02",
+    status: "pending",
+    score: null,
+    feedback: "",
+  },
+  {
+    id: 4,
+    orderNo: "WX-2024-1203-005",
+    deviceName: "娴嬭瘯鍙� D1 鍙�",
+    customerName: "鍖楁柟姹借溅闆堕儴浠舵湁闄愬叕鍙�",
+    engineerName: "鐜嬪笀鍌�",
+    completeTime: "2024-12-03 09:50:00",
+    completeDate: "2024-12-03",
+    status: "pending",
+    score: null,
+    feedback: "",
+  },
+]);
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  engineerName: "",
+  customerName: "",
+  dateRange: [],
+  status: "",
+});
+
+// 鍒楄〃鏁版嵁
+const tableData = ref([...rawOrders.value]);
+
+// 缁熻锛氭暣浣撹瘎鍒嗐�佸凡璇勪环 / 寰呰瘎浠锋暟閲�
+const ratedOrders = computed(() =>
+  rawOrders.value.filter((o) => o.status === "rated" && o.score)
+);
+
+const overallAvgScore = computed(() => {
+  if (!ratedOrders.value.length) return 0;
+  const sum = ratedOrders.value.reduce((acc, cur) => acc + (cur.score || 0), 0);
+  return sum / ratedOrders.value.length;
+});
+
+const ratedCount = computed(() => ratedOrders.value.length);
+const pendingCount = computed(
+  () => rawOrders.value.filter((o) => o.status === "pending").length
+);
+
+// 鏌ヨ / 閲嶇疆
+const recomputeTable = () => {
+  const list = rawOrders.value.filter((item) => {
+    if (
+      searchForm.engineerName &&
+      !item.engineerName.includes(searchForm.engineerName.trim())
+    ) {
+      return false;
+    }
+    if (
+      searchForm.customerName &&
+      !item.customerName.includes(searchForm.customerName.trim())
+    ) {
+      return false;
+    }
+    if (searchForm.status && item.status !== searchForm.status) {
+      return false;
+    }
+    if (Array.isArray(searchForm.dateRange) && searchForm.dateRange.length === 2) {
+      const [start, end] = searchForm.dateRange;
+      if (item.completeDate < start || item.completeDate > end) {
+        return false;
+      }
+    }
+    return true;
+  });
+  tableData.value = list;
+};
+
+const handleQuery = () => {
+  recomputeTable();
+};
+
+const resetSearch = () => {
+  searchForm.engineerName = "";
+  searchForm.customerName = "";
+  searchForm.dateRange = [];
+  searchForm.status = "";
+  recomputeTable();
+};
+
+// 瀵煎嚭锛堟紨绀猴級
+const handleExport = () => {
+  ElMessage.success("褰撳墠涓烘紨绀洪〉闈紝璇勪环瀵煎嚭鍔熻兘鏈鎺ュ疄闄呮帴鍙�");
+};
+
+// 璇勪环寮规
+const dialogVisible = ref(false);
+const dialogTitle = ref("缁翠慨鏈嶅姟璇勪环");
+const currentOrder = ref(null);
+const formRef = ref(null);
+const form = reactive({
+  score: 0,
+  feedback: "",
+});
+
+const rules = {
+  score: [{ required: true, message: "璇烽�夋嫨鏄熺骇璇勫垎", trigger: "change" }],
+  feedback: [{ required: true, message: "璇峰~鍐欐枃瀛楀弽棣�", trigger: "blur" }],
+};
+
+// 鎵撳紑璇勪环锛氭ā鎷熲�滅淮淇畬鎴愮‘璁ゅ悗寮瑰嚭璇勪环寮规鈥�
+const openEvaluate = (row) => {
+  currentOrder.value = row;
+  dialogTitle.value =
+    row.status === "pending" ? "缁翠慨鏈嶅姟璇勪环" : "鏌ョ湅 / 淇敼璇勪环";
+  form.score = row.score || 0;
+  form.feedback = row.feedback || "";
+  dialogVisible.value = true;
+};
+
+// 鎻愪氦璇勪环锛氬悓姝ュ埌鏈湴鈥滃憳宸ヤ笟缁╃粺璁♀��
+const handleSubmit = () => {
+  if (!formRef.value) return;
+  formRef.value.validate((valid) => {
+    if (!valid || !currentOrder.value) return;
+
+    const target = rawOrders.value.find((o) => o.id === currentOrder.value.id);
+    if (target) {
+      target.score = form.score;
+      target.feedback = form.feedback;
+      target.status = "rated";
+    }
+
+    ElMessage.success("璇勪环鎻愪氦鎴愬姛锛屽凡鍚屾鑷冲憳宸ヤ笟缁╃粺璁�");
+    dialogVisible.value = false;
+    recomputeTable();
+  });
+};
+
+// 鍒濆鍖栧垪琛�
+recomputeTable();
+</script>
+
+<style scoped lang="scss">
+.mb16 {
+  margin-bottom: 16px;
+}
+
+.kpi-title {
+  font-size: 13px;
+  color: #909399;
+}
+
+.kpi-value {
+  margin-top: 6px;
+  font-size: 24px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.kpi-unit {
+  font-size: 12px;
+  margin-left: 4px;
+  color: #909399;
+}
+
+.kpi-warning {
+  color: #e6a23c;
+}
+
+.dialog-order-info {
+  margin-bottom: 12px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.8;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>
+
diff --git a/src/views/inventoryManagement/transportTaskManagement/index.vue b/src/views/inventoryManagement/transportTaskManagement/index.vue
new file mode 100644
index 0000000..1feb54b
--- /dev/null
+++ b/src/views/inventoryManagement/transportTaskManagement/index.vue
@@ -0,0 +1,692 @@
+<template>
+  <div class="app-container">
+    <!-- 缁熻姒傝 -->
+    <el-row :gutter="16" style="margin-bottom: 16px">
+      <el-col :span="6">
+        <el-card shadow="never">
+          <div>鎬讳换鍔℃暟</div>
+          <div style="font-size: 22px; font-weight: 600; margin-top: 4px">
+            {{ totalTasks }}
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card shadow="never">
+          <div>杩涜涓换鍔�</div>
+          <div style="font-size: 22px; font-weight: 600; margin-top: 4px">
+            {{ runningTasks }}
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card shadow="never">
+          <div>宸插畬鎴愪换鍔�</div>
+          <div style="font-size: 22px; font-weight: 600; margin-top: 4px">
+            {{ finishedTasks }}
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card shadow="never">
+          <div>瀹屾垚鐜�</div>
+          <div style="font-size: 22px; font-weight: 600; margin-top: 4px">
+            {{ completionRate }}%
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 鏌ヨ鏉′欢 -->
+    <div class="search_form">
+      <div>
+        <span class="search_title">浠诲姟缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.taskNo"
+          style="width: 200px"
+          placeholder="璇疯緭鍏ヤ换鍔$紪鍙�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">杞﹁締缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.vehicleCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏ヨ溅杈嗙紪鍙�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">浠诲姟鏃ユ湡锛�</span>
+        <el-date-picker
+          v-model="searchForm.dateRange"
+          type="daterange"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          clearable
+          @change="handleQuery"
+        />
+
+        <span class="search_title ml10">鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.status"
+          style="width: 140px"
+          placeholder="璇烽�夋嫨浠诲姟鐘舵��"
+          clearable
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+        <el-button @click="resetSearch">閲嶇疆</el-button>
+      </div>
+      <div>
+        <el-button type="primary" icon="Plus" @click="openAdd">
+          鏂板缓杩愯緭浠诲姟
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 琛ㄦ牸 -->
+    <div class="table_list">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%"
+        height="calc(100vh - 22em)"
+        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+        :row-class-name="tableRowClassName"
+      >
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column
+          prop="taskNo"
+          label="浠诲姟缂栧彿"
+          width="150"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="outboundOrderNo"
+          label="鍑哄簱璁㈠崟鍙�"
+          width="180"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="vehicleCode"
+          label="杞﹁締缂栧彿"
+          width="130"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="plateNumber"
+          label="杞︾墝鍙风爜"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="driverName"
+          label="鍙告満"
+          width="100"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="loadAddress"
+          label="瑁呰揣鍦扮偣"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="deliveryAddress"
+          label="閫佽揣鍦扮偣"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="loadTime"
+          label="瑁呰揣鏃堕棿"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="deliveryTime"
+          label="閫佽揣鏃堕棿"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="signTime"
+          label="绛炬敹鏃堕棿"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column label="鐘舵��" width="110" align="center">
+          <template #default="scope">
+            <el-tag :type="statusTagType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="杩涘害" width="150" align="center">
+          <template #default="scope">
+            <el-progress
+              :percentage="scope.row.progress"
+              :status="scope.row.status === '宸插畬鎴�' ? 'success' : undefined"
+              :stroke-width="12"
+              :show-text="false"
+            />
+            <div style="font-size: 12px; margin-top: 4px">
+              {{ scope.row.progress }}%
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" fixed="right" width="160" align="center">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              link
+              size="small"
+              @click="openEdit(scope.row)"
+            >
+              缂栬緫
+            </el-button>
+            <el-button
+              type="danger"
+              link
+              size="small"
+              @click="removeRow(scope.row)"
+            >
+              鍒犻櫎
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="780px"
+      destroy-on-close
+    >
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="110px"
+        label-position="right"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浠诲姟缂栧彿锛�" prop="taskNo">
+              <el-input
+                v-model="form.taskNo"
+                placeholder="璇疯緭鍏ヤ换鍔$紪鍙�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍑哄簱璁㈠崟鍙凤細" prop="outboundOrderNo">
+              <el-input
+                v-model="form.outboundOrderNo"
+                placeholder="璇疯緭鍏ュ叧鑱斿嚭搴撹鍗曞彿"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="杞﹁締缂栧彿锛�" prop="vehicleCode">
+              <el-input
+                v-model="form.vehicleCode"
+                placeholder="璇疯緭鍏ヨ溅杈嗙紪鍙�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="杞︾墝鍙风爜锛�" prop="plateNumber">
+              <el-input
+                v-model="form.plateNumber"
+                placeholder="璇疯緭鍏ヨ溅鐗屽彿鐮�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍙告満锛�" prop="driverName">
+              <el-input
+                v-model="form.driverName"
+                placeholder="璇疯緭鍏ュ徃鏈哄鍚�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍙告満鐢佃瘽锛�" prop="driverPhone">
+              <el-input
+                v-model="form.driverPhone"
+                placeholder="璇疯緭鍏ュ徃鏈鸿仈绯荤數璇�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="瑁呰揣鍦扮偣锛�" prop="loadAddress">
+              <el-input
+                v-model="form.loadAddress"
+                placeholder="璇疯緭鍏ヨ璐у湴鐐�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閫佽揣鍦扮偣锛�" prop="deliveryAddress">
+              <el-input
+                v-model="form.deliveryAddress"
+                placeholder="璇疯緭鍏ラ�佽揣鍦扮偣"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="瑁呰揣鏃堕棿锛�" prop="loadTime">
+              <el-date-picker
+                v-model="form.loadTime"
+                type="datetime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm"
+                placeholder="璇烽�夋嫨瑁呰揣鏃堕棿"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="閫佽揣鏃堕棿锛�" prop="deliveryTime">
+              <el-date-picker
+                v-model="form.deliveryTime"
+                type="datetime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm"
+                placeholder="璇烽�夋嫨閫佽揣鏃堕棿"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="绛炬敹鏃堕棿锛�" prop="signTime">
+              <el-date-picker
+                v-model="form.signTime"
+                type="datetime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm"
+                placeholder="璇烽�夋嫨绛炬敹鏃堕棿"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鐘舵�侊細" prop="status">
+              <el-select v-model="form.status" placeholder="璇烽�夋嫨浠诲姟鐘舵��">
+                <el-option
+                  v-for="item in statusOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁″垝鏃ユ湡锛�" prop="planDate">
+              <el-date-picker
+                v-model="form.planDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨璁″垝鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleCancel">鍙� 娑�</el-button>
+          <el-button type="primary" @click="handleSubmit">淇� 瀛�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+// 妯℃嫙杩愯緭浠诲姟鏁版嵁
+const rawTasks = ref([
+  {
+    id: 1,
+    taskNo: "T2024-1201-001",
+    outboundOrderNo: "OUT-2024-1201-1001",
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    driverName: "寮犲笀鍌�",
+    driverPhone: "13800000001",
+    loadAddress: "娣卞湷浠撳簱A鍖�",
+    deliveryAddress: "骞垮窞瀹㈡埛涓�閮�",
+    planDate: "2024-12-01",
+    loadTime: "2024-12-01 09:00:00",
+    deliveryTime: "2024-12-01 14:30:00",
+    signTime: "2024-12-01 15:00:00",
+    status: "宸插畬鎴�",
+  },
+  {
+    id: 2,
+    taskNo: "T2024-1201-002",
+    outboundOrderNo: "OUT-2024-1201-1002",
+    vehicleCode: "CL-202402",
+    plateNumber: "绮67890",
+    driverName: "鏉庡笀鍌�",
+    driverPhone: "13800000002",
+    loadAddress: "娣卞湷浠撳簱B鍖�",
+    deliveryAddress: "涓滆帪瀹㈡埛浜岄儴",
+    planDate: "2024-12-01",
+    loadTime: "2024-12-01 10:00:00",
+    deliveryTime: "2024-12-01 13:00:00",
+    signTime: "",
+    status: "杩愯緭涓�",
+  },
+  {
+    id: 3,
+    taskNo: "T2024-1202-001",
+    outboundOrderNo: "OUT-2024-1202-1003",
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    driverName: "寮犲笀鍌�",
+    driverPhone: "13800000001",
+    loadAddress: "娣卞湷浠撳簱A鍖�",
+    deliveryAddress: "浣涘北瀹㈡埛涓夐儴",
+    planDate: "2024-12-02",
+    loadTime: "2024-12-02 08:30:00",
+    deliveryTime: "",
+    signTime: "",
+    status: "寰呭彂杞�",
+  },
+  {
+    id: 4,
+    taskNo: "T2024-1203-001",
+    outboundOrderNo: "OUT-2024-1203-1004",
+    vehicleCode: "CL-202403",
+    plateNumber: "绮11223",
+    driverName: "鐜嬪笀鍌�",
+    driverPhone: "13800000003",
+    loadAddress: "娣卞湷浠撳簱C鍖�",
+    deliveryAddress: "鎯犲窞瀹㈡埛鍥涢儴",
+    planDate: "2024-12-03",
+    loadTime: "",
+    deliveryTime: "",
+    signTime: "",
+    status: "鏈紑濮�",
+  },
+]);
+
+// 鐘舵�佹灇涓�
+const statusOptions = [
+  { label: "鏈紑濮�", value: "鏈紑濮�" },
+  { label: "寰呭彂杞�", value: "寰呭彂杞�" },
+  { label: "杩愯緭涓�", value: "杩愯緭涓�" },
+  { label: "寰呯鏀�", value: "寰呯鏀�" },
+  { label: "宸插畬鎴�", value: "宸插畬鎴�" },
+];
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  taskNo: "",
+  vehicleCode: "",
+  dateRange: [],
+  status: "",
+});
+
+// 琛ㄦ牸鏁版嵁锛堝甫杩涘害绛夎绠楀瓧娈碉級
+const tableData = ref([]);
+
+// 缁熻
+const totalTasks = computed(() => rawTasks.value.length);
+const finishedTasks = computed(
+  () => rawTasks.value.filter((t) => t.status === "宸插畬鎴�").length
+);
+const runningTasks = computed(
+  () =>
+    rawTasks.value.filter((t) =>
+      ["寰呭彂杞�", "杩愯緭涓�", "寰呯鏀�"].includes(t.status)
+    ).length
+);
+const completionRate = computed(() => {
+  if (!totalTasks.value) return 0;
+  return Math.round((finishedTasks.value / totalTasks.value) * 100);
+});
+
+// 璁$畻鍗曟潯浠诲姟杩涘害
+const computeProgress = (task) => {
+  if (task.status === "宸插畬鎴�" || task.signTime) return 100;
+  if (task.status === "寰呯鏀�" || task.deliveryTime) return 80;
+  if (task.status === "杩愯緭涓�") return 60;
+  if (task.status === "寰呭彂杞�" || task.loadTime) return 30;
+  if (task.status === "鏈紑濮�") return 0;
+  return 0;
+};
+
+// 鐘舵�� tag 鏍峰紡
+const statusTagType = (status) => {
+  if (status === "宸插畬鎴�") return "success";
+  if (status === "杩愯緭涓�") return "warning";
+  if (status === "寰呯鏀�" || status === "寰呭彂杞�") return "info";
+  return "default";
+};
+
+// 閲嶇畻琛ㄦ牸鏁版嵁
+const recomputeTable = () => {
+  const filtered = rawTasks.value
+    .filter((t) => {
+      if (searchForm.taskNo && !t.taskNo.includes(searchForm.taskNo.trim())) {
+        return false;
+      }
+      if (
+        searchForm.vehicleCode &&
+        !t.vehicleCode.includes(searchForm.vehicleCode.trim())
+      ) {
+        return false;
+      }
+      if (searchForm.status && t.status !== searchForm.status) {
+        return false;
+      }
+      if (Array.isArray(searchForm.dateRange) && searchForm.dateRange.length === 2) {
+        const [start, end] = searchForm.dateRange;
+        if (!t.planDate || t.planDate < start || t.planDate > end) {
+          return false;
+        }
+      }
+      return true;
+    })
+    .map((t) => ({
+      ...t,
+      progress: computeProgress(t),
+    }));
+
+  tableData.value = filtered;
+};
+
+// 鏌ヨ
+const handleQuery = () => {
+  recomputeTable();
+};
+
+const resetSearch = () => {
+  searchForm.taskNo = "";
+  searchForm.vehicleCode = "";
+  searchForm.dateRange = [];
+  searchForm.status = "";
+  recomputeTable();
+};
+
+// 琛屾牱寮�
+const tableRowClassName = ({ row }) => {
+  if (row.status === "宸插畬鎴�") {
+    return "row-finished";
+  }
+  if (row.status === "杩愯緭涓�") {
+    return "row-running";
+  }
+  return "";
+};
+
+// 寮圭獥 & 琛ㄥ崟
+const dialogVisible = ref(false);
+const dialogTitle = ref("鏂板缓杩愯緭浠诲姟");
+const isEdit = ref(false);
+const formRef = ref(null);
+const form = reactive({
+  id: null,
+  taskNo: "",
+  outboundOrderNo: "",
+  vehicleCode: "",
+  plateNumber: "",
+  driverName: "",
+  driverPhone: "",
+  loadAddress: "",
+  deliveryAddress: "",
+  planDate: "",
+  loadTime: "",
+  deliveryTime: "",
+  signTime: "",
+  status: "鏈紑濮�",
+});
+
+const rules = {
+  taskNo: [{ required: true, message: "璇疯緭鍏ヤ换鍔$紪鍙�", trigger: "blur" }],
+  outboundOrderNo: [
+    { required: true, message: "璇疯緭鍏ュ嚭搴撹鍗曞彿", trigger: "blur" },
+  ],
+  vehicleCode: [{ required: true, message: "璇疯緭鍏ヨ溅杈嗙紪鍙�", trigger: "blur" }],
+  plateNumber: [{ required: true, message: "璇疯緭鍏ヨ溅鐗屽彿鐮�", trigger: "blur" }],
+  driverName: [{ required: true, message: "璇疯緭鍏ュ徃鏈哄鍚�", trigger: "blur" }],
+  loadAddress: [{ required: true, message: "璇疯緭鍏ヨ璐у湴鐐�", trigger: "blur" }],
+  deliveryAddress: [
+    { required: true, message: "璇疯緭鍏ラ�佽揣鍦扮偣", trigger: "blur" },
+  ],
+  planDate: [{ required: true, message: "璇烽�夋嫨璁″垝鏃ユ湡", trigger: "change" }],
+};
+
+// 鏂板缓
+const openAdd = () => {
+  dialogTitle.value = "鏂板缓杩愯緭浠诲姟";
+  isEdit.value = false;
+  Object.assign(form, {
+    id: null,
+    taskNo: "",
+    outboundOrderNo: "",
+    vehicleCode: "",
+    plateNumber: "",
+    driverName: "",
+    driverPhone: "",
+    loadAddress: "",
+    deliveryAddress: "",
+    planDate: "",
+    loadTime: "",
+    deliveryTime: "",
+    signTime: "",
+    status: "鏈紑濮�",
+  });
+  dialogVisible.value = true;
+};
+
+// 缂栬緫
+const openEdit = (row) => {
+  dialogTitle.value = "缂栬緫杩愯緭浠诲姟";
+  isEdit.value = true;
+  Object.assign(form, row);
+  dialogVisible.value = true;
+};
+
+// 淇濆瓨
+const handleSubmit = () => {
+  if (!formRef.value) return;
+  formRef.value.validate((valid) => {
+    if (!valid) return;
+
+    if (isEdit.value) {
+      const index = rawTasks.value.findIndex((t) => t.id === form.id);
+      if (index !== -1) {
+        rawTasks.value[index] = { ...form };
+      }
+      ElMessage.success("杩愯緭浠诲姟宸叉洿鏂�");
+    } else {
+      const newId = rawTasks.value.length
+        ? Math.max(...rawTasks.value.map((t) => t.id)) + 1
+        : 1;
+      rawTasks.value.push({ ...form, id: newId });
+      ElMessage.success("杩愯緭浠诲姟宸叉柊澧�");
+    }
+    dialogVisible.value = false;
+    recomputeTable();
+  });
+};
+
+const handleCancel = () => {
+  dialogVisible.value = false;
+};
+
+// 鍒犻櫎
+const removeRow = (row) => {
+  ElMessageBox.confirm("鏄惁纭鍒犻櫎璇ヨ繍杈撲换鍔★紵", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      rawTasks.value = rawTasks.value.filter((t) => t.id !== row.id);
+      recomputeTable();
+      ElMessage.success("鍒犻櫎鎴愬姛");
+    })
+    .catch(() => {});
+};
+
+onMounted(() => {
+  recomputeTable();
+});
+</script>
+
+<style scoped lang="scss">
+.dialog-footer {
+  text-align: right;
+}
+
+::v-deep(.row-finished) {
+  background-color: #f6ffed;
+}
+
+::v-deep(.row-running) {
+  background-color: #fffbe6;
+}
+</style>
+
diff --git a/src/views/inventoryManagement/vehicleFuelManagement/index.vue b/src/views/inventoryManagement/vehicleFuelManagement/index.vue
new file mode 100644
index 0000000..8579cba
--- /dev/null
+++ b/src/views/inventoryManagement/vehicleFuelManagement/index.vue
@@ -0,0 +1,556 @@
+<template>
+  <div class="app-container">
+    <!-- 鏌ヨ鏉′欢 -->
+    <div class="search_form">
+      <div>
+        <span class="search_title">杞﹁締缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.vehicleCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏ヨ溅杈嗙紪鍙�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">鍔犳补鏃堕棿锛�</span>
+        <el-date-picker
+          v-model="searchForm.dateRange"
+          type="daterange"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          clearable
+          @change="handleQuery"
+        />
+
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+        <el-button @click="resetSearch">閲嶇疆</el-button>
+      </div>
+      <div>
+        <el-button type="primary" icon="Plus" @click="openAdd">
+          鏂板鍔犳补璁板綍
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 琛ㄦ牸 -->
+    <div class="table_list">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%"
+        height="calc(100vh - 18.5em)"
+        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+        :row-class-name="tableRowClassName"
+      >
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column
+          prop="vehicleCode"
+          label="杞﹁締缂栧彿"
+          width="130"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="plateNumber"
+          label="杞︾墝鍙风爜"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="fuelDate"
+          label="鍔犳补鏃ユ湡"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="gunNo"
+          label="娌规灙鍙�"
+          width="90"
+          align="center"
+        />
+        <el-table-column
+          prop="amount"
+          label="閲戦(鍏�)"
+          width="100"
+          align="right"
+        >
+          <template #default="scope">
+            <span>{{ scope.row.amount?.toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="liters"
+          label="鍗囨暟(L)"
+          width="90"
+          align="right"
+        >
+          <template #default="scope">
+            <span>{{ scope.row.liters?.toFixed(2) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="startMileage"
+          label="璧峰閲岀▼(km)"
+          width="120"
+          align="right"
+        />
+        <el-table-column
+          prop="endMileage"
+          label="缁撴潫閲岀▼(km)"
+          width="120"
+          align="right"
+        />
+        <el-table-column
+          prop="distance"
+          label="琛岄┒閲岀▼(km)"
+          width="120"
+          align="right"
+        />
+        <el-table-column
+          prop="fuelConsumption"
+          label="娌硅��(L/100km)"
+          width="130"
+          align="center"
+        >
+          <template #default="scope">
+            <span
+              :style="scope.row.isAbnormal ? 'color:#F56C6C;font-weight:600;' : ''"
+            >
+              {{ scope.row.fuelConsumption != null ? scope.row.fuelConsumption.toFixed(2) : '-' }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="avgConsumption"
+          label="杞﹁締骞冲潎娌硅��"
+          width="130"
+          align="center"
+        >
+          <template #default="scope">
+            <span>
+              {{ scope.row.avgConsumption != null ? scope.row.avgConsumption.toFixed(2) : '-' }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="寮傚父棰勮" width="100" align="center">
+          <template #default="scope">
+            <el-tag v-if="scope.row.isAbnormal" type="danger" size="small">
+              寮傚父
+            </el-tag>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" fixed="right" width="140" align="center">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              link
+              size="small"
+              @click="openEdit(scope.row)"
+            >
+              缂栬緫
+            </el-button>
+            <el-button
+              type="danger"
+              link
+              size="small"
+              @click="removeRow(scope.row)"
+            >
+              鍒犻櫎
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="640px"
+      destroy-on-close
+    >
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="110px"
+        label-position="right"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="杞﹁締缂栧彿锛�" prop="vehicleCode">
+              <el-input
+                v-model="form.vehicleCode"
+                placeholder="璇疯緭鍏ヨ溅杈嗙紪鍙�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="杞︾墝鍙风爜锛�" prop="plateNumber">
+              <el-input
+                v-model="form.plateNumber"
+                placeholder="璇疯緭鍏ヨ溅鐗屽彿鐮�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍔犳补鏃ユ湡锛�" prop="fuelDate">
+              <el-date-picker
+                v-model="form.fuelDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨鍔犳补鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="娌规灙鍙凤細" prop="gunNo">
+              <el-input
+                v-model="form.gunNo"
+                placeholder="璇疯緭鍏ユ补鏋彿"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="閲戦(鍏�)锛�" prop="amount">
+              <el-input-number
+                v-model="form.amount"
+                :min="0"
+                :step="0.01"
+                :precision="2"
+                placeholder="璇疯緭鍏ラ噾棰�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍗囨暟(L)锛�" prop="liters">
+              <el-input-number
+                v-model="form.liters"
+                :min="0"
+                :step="0.01"
+                :precision="2"
+                placeholder="璇疯緭鍏ュ崌鏁�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璧峰閲岀▼(km)锛�" prop="startMileage">
+              <el-input-number
+                v-model="form.startMileage"
+                :min="0"
+                :step="1"
+                placeholder="璇疯緭鍏ヨ捣濮嬮噷绋�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁撴潫閲岀▼(km)锛�" prop="endMileage">
+              <el-input-number
+                v-model="form.endMileage"
+                :min="0"
+                :step="1"
+                placeholder="璇疯緭鍏ョ粨鏉熼噷绋�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleCancel">鍙� 娑�</el-button>
+          <el-button type="primary" @click="handleSubmit">淇� 瀛�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+// 妯℃嫙鍔犳补璁板綍鏁版嵁
+const rawRecords = ref([
+  {
+    id: 1,
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    fuelDate: "2024-12-01",
+    gunNo: "01",
+    amount: 500,
+    liters: 70,
+    startMileage: 12000,
+    endMileage: 12600,
+  },
+  {
+    id: 2,
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    fuelDate: "2024-12-15",
+    gunNo: "02",
+    amount: 520,
+    liters: 72,
+    startMileage: 12600,
+    endMileage: 13250,
+  },
+  {
+    id: 3,
+    vehicleCode: "CL-202402",
+    plateNumber: "绮67890",
+    fuelDate: "2024-12-05",
+    gunNo: "03",
+    amount: 430,
+    liters: 60,
+    startMileage: 8000,
+    endMileage: 8520,
+  },
+  {
+    id: 4,
+    vehicleCode: "CL-202402",
+    plateNumber: "绮67890",
+    fuelDate: "2024-12-20",
+    gunNo: "01",
+    amount: 450,
+    liters: 63,
+    startMileage: 8520,
+    endMileage: 9000,
+  },
+  {
+    id: 5,
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    fuelDate: "2025-01-05",
+    gunNo: "01",
+    amount: 700,
+    liters: 90,
+    startMileage: 13250,
+    endMileage: 13600, // 鏄庢樉寮傚父娌硅��
+  },
+]);
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  vehicleCode: "",
+  dateRange: [],
+});
+
+// 琛ㄦ牸鏁版嵁锛堝寘鍚绠楀瓧娈碉級
+const tableData = ref([]);
+
+// 寮圭獥 & 琛ㄥ崟
+const dialogVisible = ref(false);
+const dialogTitle = ref("鏂板鍔犳补璁板綍");
+const isEdit = ref(false);
+const formRef = ref(null);
+const form = reactive({
+  id: null,
+  vehicleCode: "",
+  plateNumber: "",
+  fuelDate: "",
+  gunNo: "",
+  amount: null,
+  liters: null,
+  startMileage: null,
+  endMileage: null,
+});
+
+const rules = {
+  vehicleCode: [{ required: true, message: "璇疯緭鍏ヨ溅杈嗙紪鍙�", trigger: "blur" }],
+  plateNumber: [{ required: true, message: "璇疯緭鍏ヨ溅鐗屽彿鐮�", trigger: "blur" }],
+  fuelDate: [{ required: true, message: "璇烽�夋嫨鍔犳补鏃ユ湡", trigger: "change" }],
+  gunNo: [{ required: true, message: "璇疯緭鍏ユ补鏋彿", trigger: "blur" }],
+  amount: [{ required: true, message: "璇疯緭鍏ラ噾棰�", trigger: "blur" }],
+  liters: [{ required: true, message: "璇疯緭鍏ュ崌鏁�", trigger: "blur" }],
+  startMileage: [{ required: true, message: "璇疯緭鍏ヨ捣濮嬮噷绋�", trigger: "blur" }],
+  endMileage: [{ required: true, message: "璇疯緭鍏ョ粨鏉熼噷绋�", trigger: "blur" }],
+};
+
+// 閲嶆柊璁$畻娌硅�椼�佸钩鍧囨补鑰楀拰寮傚父棰勮
+const recomputeTable = () => {
+  const records = rawRecords.value;
+
+  // 1. 鍏堟寜杞﹁締缁熻骞冲潎娌硅��
+  const stats = {};
+  records.forEach((r) => {
+    const distance = r.endMileage - r.startMileage;
+    if (distance <= 0 || !r.liters) return;
+    const cons = (r.liters / distance) * 100; // L/100km
+    if (!stats[r.vehicleCode]) {
+      stats[r.vehicleCode] = { totalCons: 0, count: 0 };
+    }
+    stats[r.vehicleCode].totalCons += cons;
+    stats[r.vehicleCode].count += 1;
+  });
+
+  const avgMap = {};
+  Object.keys(stats).forEach((key) => {
+    avgMap[key] = stats[key].totalCons / stats[key].count;
+  });
+
+  // 2. 鎸夌瓫閫夋潯浠惰繃婊ゅ苟琛ュ厖璁$畻瀛楁
+  const filtered = records
+    .filter((r) => {
+      if (
+        searchForm.vehicleCode &&
+        !r.vehicleCode.includes(searchForm.vehicleCode.trim())
+      ) {
+        return false;
+      }
+      if (Array.isArray(searchForm.dateRange) && searchForm.dateRange.length === 2) {
+        const [start, end] = searchForm.dateRange;
+        if (r.fuelDate < start || r.fuelDate > end) {
+          return false;
+        }
+      }
+      return true;
+    })
+    .map((r) => {
+      const distance = r.endMileage - r.startMileage;
+      const fuelConsumption =
+        distance > 0 && r.liters
+          ? (r.liters / distance) * 100
+          : null;
+      const avgConsumption =
+        avgMap[r.vehicleCode] != null ? avgMap[r.vehicleCode] : null;
+      const isAbnormal =
+        avgConsumption != null &&
+        fuelConsumption != null &&
+        fuelConsumption > avgConsumption * 1.2;
+
+      return {
+        ...r,
+        distance,
+        fuelConsumption,
+        avgConsumption,
+        isAbnormal,
+      };
+    });
+
+  tableData.value = filtered;
+};
+
+// 鏌ヨ
+const handleQuery = () => {
+  recomputeTable();
+};
+
+const resetSearch = () => {
+  searchForm.vehicleCode = "";
+  searchForm.dateRange = [];
+  recomputeTable();
+};
+
+// 琛屾牱寮忥紙寮傚父楂樹寒锛�
+const tableRowClassName = ({ row }) => {
+  if (row.isAbnormal) {
+    return "row-abnormal";
+  }
+  return "";
+};
+
+// 鏂板
+const openAdd = () => {
+  dialogTitle.value = "鏂板鍔犳补璁板綍";
+  isEdit.value = false;
+  Object.assign(form, {
+    id: null,
+    vehicleCode: "",
+    plateNumber: "",
+    fuelDate: "",
+    gunNo: "",
+    amount: null,
+    liters: null,
+    startMileage: null,
+    endMileage: null,
+  });
+  dialogVisible.value = true;
+};
+
+// 缂栬緫
+const openEdit = (row) => {
+  dialogTitle.value = "缂栬緫鍔犳补璁板綍";
+  isEdit.value = true;
+  Object.assign(form, row);
+  dialogVisible.value = true;
+};
+
+// 淇濆瓨
+const handleSubmit = () => {
+  if (!formRef.value) return;
+  formRef.value.validate((valid) => {
+    if (!valid) return;
+
+    if (form.endMileage <= form.startMileage) {
+      ElMessage.warning("缁撴潫閲岀▼蹇呴』澶т簬璧峰閲岀▼");
+      return;
+    }
+
+    if (isEdit.value) {
+      const index = rawRecords.value.findIndex((r) => r.id === form.id);
+      if (index !== -1) {
+        rawRecords.value[index] = { ...form };
+      }
+      ElMessage.success("鍔犳补璁板綍宸叉洿鏂�");
+    } else {
+      const newId = rawRecords.value.length
+        ? Math.max(...rawRecords.value.map((r) => r.id)) + 1
+        : 1;
+      rawRecords.value.push({ ...form, id: newId });
+      ElMessage.success("鍔犳补璁板綍宸叉柊澧�");
+    }
+    dialogVisible.value = false;
+    recomputeTable();
+  });
+};
+
+const handleCancel = () => {
+  dialogVisible.value = false;
+};
+
+// 鍒犻櫎
+const removeRow = (row) => {
+  ElMessageBox.confirm("鏄惁纭鍒犻櫎璇ュ姞娌硅褰曪紵", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      rawRecords.value = rawRecords.value.filter((r) => r.id !== row.id);
+      recomputeTable();
+      ElMessage.success("鍒犻櫎鎴愬姛");
+    })
+    .catch(() => {});
+};
+
+onMounted(() => {
+  recomputeTable();
+});
+</script>
+
+<style scoped lang="scss">
+.dialog-footer {
+  text-align: right;
+}
+
+::v-deep(.row-abnormal) {
+  background-color: #fff5f5;
+}
+</style>
+
diff --git a/src/views/inventoryManagement/vehicleManagement/index.vue b/src/views/inventoryManagement/vehicleManagement/index.vue
new file mode 100644
index 0000000..1e383c6
--- /dev/null
+++ b/src/views/inventoryManagement/vehicleManagement/index.vue
@@ -0,0 +1,581 @@
+<template>
+  <div class="app-container">
+    <!-- 鏌ヨ鏉′欢 -->
+    <div class="search_form">
+      <div>
+        <span class="search_title">杞︾墝鍙风爜锛�</span>
+        <el-input
+          v-model="searchForm.plateNumber"
+          style="width: 180px"
+          placeholder="璇疯緭鍏ヨ溅鐗屽彿鐮�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+
+        <span class="search_title ml10">杞﹁締绫诲瀷锛�</span>
+        <el-select
+          v-model="searchForm.vehicleType"
+          style="width: 160px"
+          placeholder="璇烽�夋嫨杞﹁締绫诲瀷"
+          clearable
+        >
+          <el-option
+            v-for="item in vehicleTypeOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+        <span class="search_title ml10">鎵�灞為儴闂細</span>
+        <el-select
+          v-model="searchForm.department"
+          style="width: 160px"
+          placeholder="璇烽�夋嫨鎵�灞為儴闂�"
+          clearable
+        >
+          <el-option
+            v-for="item in departmentOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+        <span class="search_title ml10">鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.status"
+          style="width: 140px"
+          placeholder="璇烽�夋嫨鐘舵��"
+          clearable
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+        <span class="search_title ml10">褰掓。鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.archived"
+          style="width: 140px"
+          placeholder="璇烽�夋嫨褰掓。鐘舵��"
+          clearable
+        >
+          <el-option label="鏈綊妗�" value="false" />
+          <el-option label="宸插綊妗�" value="true" />
+        </el-select>
+
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+        <el-button @click="resetSearch">閲嶇疆</el-button>
+      </div>
+      <div>
+        <el-button type="primary" icon="Plus" @click="openAdd">鏂板杞﹁締</el-button>
+      </div>
+    </div>
+
+    <!-- 琛ㄦ牸 -->
+    <div class="table_list">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%"
+        height="calc(100vh - 18.5em)"
+        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+      >
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column
+          prop="vehicleCode"
+          label="杞﹁締缂栧彿"
+          width="140"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="plateNumber"
+          label="杞︾墝鍙风爜"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="vehicleType"
+          label="杞﹁締绫诲瀷"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="department"
+          label="鎵�灞為儴闂�"
+          width="140"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="purchaseDate"
+          label="璐疆鏃ユ湡"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="licenseNumber"
+          label="琛岄┒璇佺紪鍙�"
+          width="160"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="licenseIssueDate"
+          label="鍙戣瘉鏃ユ湡"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="licenseExpireDate"
+          label="鍒版湡鏃ユ湡"
+          width="120"
+          show-overflow-tooltip
+        />
+        <el-table-column label="鐘舵��" width="100" align="center">
+          <template #default="scope">
+            <el-tag :type="statusTagType(scope.row.status)">
+              {{ scope.row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="褰掓。鐘舵��" width="100" align="center">
+          <template #default="scope">
+            <el-tag :type="scope.row.archived ? 'info' : 'success'">
+              {{ scope.row.archived ? '宸插綊妗�' : '鏈綊妗�' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" fixed="right" width="220" align="center">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              link
+              size="small"
+              @click="openEdit(scope.row)"
+            >
+              缂栬緫
+            </el-button>
+            <el-button
+              type="warning"
+              link
+              size="small"
+              :disabled="scope.row.archived"
+              @click="archiveRow(scope.row)"
+            >
+              褰掓。
+            </el-button>
+            <el-button
+              type="danger"
+              link
+              size="small"
+              @click="removeRow(scope.row)"
+            >
+              鍒犻櫎
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="600px"
+      destroy-on-close
+    >
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="100px"
+        label-position="right"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="杞﹁締缂栧彿锛�" prop="vehicleCode">
+              <el-input v-model="form.vehicleCode" placeholder="璇疯緭鍏ヨ溅杈嗙紪鍙�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="杞︾墝鍙风爜锛�" prop="plateNumber">
+              <el-input v-model="form.plateNumber" placeholder="璇疯緭鍏ヨ溅鐗屽彿鐮�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="杞﹁締绫诲瀷锛�" prop="vehicleType">
+              <el-select
+                v-model="form.vehicleType"
+                placeholder="璇烽�夋嫨杞﹁締绫诲瀷"
+                clearable
+              >
+                <el-option
+                  v-for="item in vehicleTypeOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎵�灞為儴闂細" prop="department">
+              <el-select
+                v-model="form.department"
+                placeholder="璇烽�夋嫨鎵�灞為儴闂�"
+                clearable
+              >
+                <el-option
+                  v-for="item in departmentOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="璐疆鏃ユ湡锛�" prop="purchaseDate">
+              <el-date-picker
+                v-model="form.purchaseDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨璐疆鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵�侊細" prop="status">
+              <el-select v-model="form.status" placeholder="璇烽�夋嫨鐘舵��">
+                <el-option
+                  v-for="item in statusOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="琛岄┒璇佺紪鍙凤細" prop="licenseNumber">
+              <el-input
+                v-model="form.licenseNumber"
+                placeholder="璇疯緭鍏ヨ椹惰瘉缂栧彿"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍙戣瘉鏃ユ湡锛�" prop="licenseIssueDate">
+              <el-date-picker
+                v-model="form.licenseIssueDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨鍙戣瘉鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="鍒版湡鏃ユ湡锛�" prop="licenseExpireDate">
+              <el-date-picker
+                v-model="form.licenseExpireDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨鍒版湡鏃ユ湡"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="handleCancel">鍙� 娑�</el-button>
+          <el-button type="primary" @click="handleSubmit">淇� 瀛�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+
+// 妯℃嫙杞﹁締鍩虹鏁版嵁
+const allVehicles = ref([
+  {
+    id: 1,
+    vehicleCode: "CL-202401",
+    plateNumber: "绮12345",
+    vehicleType: "鍘㈠紡璐ц溅",
+    department: "鐗╂祦涓�閮�",
+    purchaseDate: "2022-03-15",
+    licenseNumber: "4401-2022-0001",
+    licenseIssueDate: "2022-03-10",
+    licenseExpireDate: "2026-03-10",
+    status: "鍦ㄧ敤",
+    archived: false,
+  },
+  {
+    id: 2,
+    vehicleCode: "CL-202402",
+    plateNumber: "绮67890",
+    vehicleType: "鍐疯棌杞�",
+    department: "鐗╂祦浜岄儴",
+    purchaseDate: "2021-08-01",
+    licenseNumber: "4401-2021-0123",
+    licenseIssueDate: "2021-07-28",
+    licenseExpireDate: "2025-07-28",
+    status: "缁翠慨",
+    archived: false,
+  },
+  {
+    id: 3,
+    vehicleCode: "CL-202403",
+    plateNumber: "绮11223",
+    vehicleType: "鐗靛紩杞�",
+    department: "椤圭洰杩愯緭閮�",
+    purchaseDate: "2020-05-20",
+    licenseNumber: "4401-2020-0456",
+    licenseIssueDate: "2020-05-18",
+    licenseExpireDate: "2024-05-18",
+    status: "闂茬疆",
+    archived: false,
+  },
+  {
+    id: 4,
+    vehicleCode: "CL-202404",
+    plateNumber: "绮33445",
+    vehicleType: "鍘㈠紡璐ц溅",
+    department: "璧勪骇绠$悊閮�",
+    purchaseDate: "2019-11-11",
+    licenseNumber: "4401-2019-0789",
+    licenseIssueDate: "2019-11-08",
+    licenseExpireDate: "2023-11-08",
+    status: "鍦ㄧ敤",
+    archived: true,
+  },
+]);
+
+// 涓嬫媺鏋氫妇
+const vehicleTypeOptions = [
+  { label: "鍘㈠紡璐ц溅", value: "鍘㈠紡璐ц溅" },
+  { label: "鍐疯棌杞�", value: "鍐疯棌杞�" },
+  { label: "鐗靛紩杞�", value: "鐗靛紩杞�" },
+  { label: "鍏朵粬", value: "鍏朵粬" },
+];
+
+const departmentOptions = [
+  { label: "鐗╂祦涓�閮�", value: "鐗╂祦涓�閮�" },
+  { label: "鐗╂祦浜岄儴", value: "鐗╂祦浜岄儴" },
+  { label: "椤圭洰杩愯緭閮�", value: "椤圭洰杩愯緭閮�" },
+  { label: "璧勪骇绠$悊閮�", value: "璧勪骇绠$悊閮�" },
+];
+
+const statusOptions = [
+  { label: "鍦ㄧ敤", value: "鍦ㄧ敤" },
+  { label: "闂茬疆", value: "闂茬疆" },
+  { label: "缁翠慨", value: "缁翠慨" },
+];
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  plateNumber: "",
+  vehicleType: "",
+  department: "",
+  status: "",
+  archived: "",
+});
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([...allVehicles.value]);
+
+// 寮圭獥 & 琛ㄥ崟
+const dialogVisible = ref(false);
+const dialogTitle = ref("鏂板杞﹁締");
+const isEdit = ref(false);
+const formRef = ref(null);
+const form = reactive({
+  id: null,
+  vehicleCode: "",
+  plateNumber: "",
+  vehicleType: "",
+  department: "",
+  purchaseDate: "",
+  licenseNumber: "",
+  licenseIssueDate: "",
+  licenseExpireDate: "",
+  status: "鍦ㄧ敤",
+  archived: false,
+});
+
+const rules = {
+  vehicleCode: [{ required: true, message: "璇疯緭鍏ヨ溅杈嗙紪鍙�", trigger: "blur" }],
+  plateNumber: [{ required: true, message: "璇疯緭鍏ヨ溅鐗屽彿鐮�", trigger: "blur" }],
+  vehicleType: [{ required: true, message: "璇烽�夋嫨杞﹁締绫诲瀷", trigger: "change" }],
+  department: [{ required: true, message: "璇烽�夋嫨鎵�灞為儴闂�", trigger: "change" }],
+  purchaseDate: [{ required: true, message: "璇烽�夋嫨璐疆鏃ユ湡", trigger: "change" }],
+  status: [{ required: true, message: "璇烽�夋嫨鐘舵��", trigger: "change" }],
+  licenseNumber: [{ required: true, message: "璇疯緭鍏ヨ椹惰瘉缂栧彿", trigger: "blur" }],
+  licenseIssueDate: [{ required: true, message: "璇烽�夋嫨鍙戣瘉鏃ユ湡", trigger: "change" }],
+};
+
+// 鏌ヨ
+const handleQuery = () => {
+  tableData.value = allVehicles.value.filter((item) => {
+    if (
+      searchForm.plateNumber &&
+      !item.plateNumber.includes(searchForm.plateNumber.trim())
+    ) {
+      return false;
+    }
+    if (searchForm.vehicleType && item.vehicleType !== searchForm.vehicleType) {
+      return false;
+    }
+    if (searchForm.department && item.department !== searchForm.department) {
+      return false;
+    }
+    if (searchForm.status && item.status !== searchForm.status) {
+      return false;
+    }
+    if (searchForm.archived !== "") {
+      const targetArchived = searchForm.archived === "true";
+      if (item.archived !== targetArchived) return false;
+    }
+    return true;
+  });
+};
+
+const resetSearch = () => {
+  searchForm.plateNumber = "";
+  searchForm.vehicleType = "";
+  searchForm.department = "";
+  searchForm.status = "";
+  searchForm.archived = "";
+  handleQuery();
+};
+
+// 鏂板
+const openAdd = () => {
+  dialogTitle.value = "鏂板杞﹁締";
+  isEdit.value = false;
+  Object.assign(form, {
+    id: null,
+    vehicleCode: "",
+    plateNumber: "",
+    vehicleType: "",
+    department: "",
+    purchaseDate: "",
+    licenseInfo: "",
+    status: "鍦ㄧ敤",
+    archived: false,
+  });
+  dialogVisible.value = true;
+};
+
+// 缂栬緫
+const openEdit = (row) => {
+  dialogTitle.value = "缂栬緫杞﹁締";
+  isEdit.value = true;
+  Object.assign(form, row);
+  dialogVisible.value = true;
+};
+
+// 淇濆瓨
+const handleSubmit = () => {
+  if (!formRef.value) return;
+  formRef.value.validate((valid) => {
+    if (!valid) return;
+    if (isEdit.value) {
+      const index = allVehicles.value.findIndex((v) => v.id === form.id);
+      if (index !== -1) {
+        allVehicles.value[index] = { ...form };
+      }
+      ElMessage.success("杞﹁締淇℃伅宸叉洿鏂�");
+    } else {
+      const newId = allVehicles.value.length
+        ? Math.max(...allVehicles.value.map((v) => v.id)) + 1
+        : 1;
+      allVehicles.value.push({ ...form, id: newId });
+      ElMessage.success("杞﹁締淇℃伅宸叉柊澧�");
+    }
+    dialogVisible.value = false;
+    handleQuery();
+  });
+};
+
+const handleCancel = () => {
+  dialogVisible.value = false;
+};
+
+// 褰掓。
+const archiveRow = (row) => {
+  if (row.archived) return;
+  ElMessageBox.confirm(
+    "鏄惁纭灏嗚杞﹁締褰掓。锛熷綊妗e悗浠呬繚鐣欐煡璇紝涓嶅啀鍙備笌杩愯緭浠诲姟鍒嗛厤銆�",
+    "褰掓。鎻愮ず",
+    {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(() => {
+      row.archived = true;
+      if (row.status === "鍦ㄧ敤") {
+        row.status = "闂茬疆";
+      }
+      ElMessage.success("杞﹁締宸插綊妗�");
+      handleQuery();
+    })
+    .catch(() => {});
+};
+
+// 鍒犻櫎
+const removeRow = (row) => {
+  ElMessageBox.confirm("鏄惁纭鍒犻櫎璇ヨ溅杈嗗熀纭�淇℃伅锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      allVehicles.value = allVehicles.value.filter((v) => v.id !== row.id);
+      handleQuery();
+      ElMessage.success("鍒犻櫎鎴愬姛");
+    })
+    .catch(() => {});
+};
+
+// 鐘舵�佹牱寮�
+const statusTagType = (status) => {
+  if (status === "鍦ㄧ敤") return "success";
+  if (status === "闂茬疆") return "info";
+  if (status === "缁翠慨") return "warning";
+  return "default";
+};
+</script>
+
+<style scoped lang="scss">
+.dialog-footer {
+  text-align: right;
+}
+</style>
+
diff --git a/src/views/personnelManagement/attendanceCheckin/index.vue b/src/views/personnelManagement/attendanceCheckin/index.vue
new file mode 100644
index 0000000..bcfdb00
--- /dev/null
+++ b/src/views/personnelManagement/attendanceCheckin/index.vue
@@ -0,0 +1,469 @@
+<template>
+  <div class="app-container">
+    <!-- 鍛樺伐鎵撳崱鍖� -->
+    <el-card shadow="never" class="mb16">
+      <div class="attendance-header">
+        <div>
+          <div class="title">鎵撳崱绛惧埌</div>
+          <div class="sub-title">鏀寔涓�閿墦鍗★紝鑷姩璁板綍涓婁笅鐝椂闂�</div>
+        </div>
+        <div class="attendance-actions">
+          <div class="time-block">
+            <div class="label">褰撳墠鏃堕棿</div>
+            <div class="value">{{ nowTime }}</div>
+          </div>
+          <el-button type="primary" size="large" @click="handleCheckInOut">
+            {{ checkInOutText }}
+          </el-button>
+        </div>
+      </div>
+      <el-descriptions border :column="4" class="mt10">
+        <el-descriptions-item label="鍛樺伐濮撳悕">
+          {{ currentUser.name }}
+        </el-descriptions-item>
+        <el-descriptions-item label="宸ュ彿">
+          {{ currentUser.no }}
+        </el-descriptions-item>
+        <el-descriptions-item label="鎵�灞為儴闂�">
+          {{ currentUser.dept }}
+        </el-descriptions-item>
+        <el-descriptions-item label="浠婃棩鐘舵��">
+          <el-tag :type="todayStatusTag" size="small">
+            {{ todayStatusText }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="涓婄彮鏃堕棿">
+          {{ todayRecord?.checkInTime || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="涓嬬彮鏃堕棿">
+          {{ todayRecord?.checkOutTime || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="宸ユ椂(灏忔椂)">
+          {{ todayRecord?.workHours ?? '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="寮傚父鏍囪">
+          <span v-if="todayRecord?.status === 'normal'">-</span>
+          <el-tag v-else type="danger" size="small">
+            {{ todayRecord?.statusText }}
+          </el-tag>
+        </el-descriptions-item>
+      </el-descriptions>
+    </el-card>
+
+    <!-- 鏌ヨ鏉′欢锛堢鐞嗗憳鑰冨嫟鏃ユ姤锛� -->
+    <div class="search_form">
+      <div>
+        <span class="search_title">閮ㄩ棬锛�</span>
+        <el-select
+          v-model="searchForm.dept"
+          placeholder="璇烽�夋嫨閮ㄩ棬"
+          style="width: 180px"
+          clearable
+        >
+          <el-option
+            v-for="item in deptOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+        <span class="search_title ml10">鏃ユ湡锛�</span>
+        <el-date-picker
+          v-model="searchForm.date"
+          type="date"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          placeholder="璇烽�夋嫨鏃ユ湡"
+          clearable
+        />
+
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+        <el-button @click="resetSearch">閲嶇疆</el-button>
+      </div>
+      <div>
+        <el-button icon="Download" @click="handleExport">
+          瀵煎嚭鑰冨嫟鏃ユ姤
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 鑰冨嫟鏃ユ姤琛ㄦ牸 -->
+    <div class="table_list">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%"
+        height="calc(100vh - 24em)"
+        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+        :row-class-name="rowClassName"
+      >
+        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
+        <el-table-column
+          prop="date"
+          label="鏃ユ湡"
+          width="120"
+        />
+        <el-table-column
+          prop="dept"
+          label="閮ㄩ棬"
+          width="140"
+        />
+        <el-table-column
+          prop="name"
+          label="濮撳悕"
+          width="120"
+        />
+        <el-table-column
+          prop="no"
+          label="宸ュ彿"
+          width="120"
+        />
+        <el-table-column
+          prop="checkInTime"
+          label="涓婄彮鏃堕棿"
+          width="140"
+        />
+        <el-table-column
+          prop="checkOutTime"
+          label="涓嬬彮鏃堕棿"
+          width="140"
+        />
+        <el-table-column
+          prop="workHours"
+          label="宸ユ椂(灏忔椂)"
+          width="110"
+          align="center"
+        />
+        <el-table-column
+          prop="statusText"
+          label="鑰冨嫟鐘舵��"
+          width="120"
+          align="center"
+        >
+          <template #default="scope">
+            <el-tag
+              v-if="scope.row.status === 'normal'"
+              type="success"
+              size="small"
+            >
+              姝e父
+            </el-tag>
+            <el-tag
+              v-else
+              type="danger"
+              size="small"
+            >
+              {{ scope.row.statusText }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="remark"
+          label="澶囨敞"
+          show-overflow-tooltip
+        />
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
+import { ElMessage } from "element-plus";
+
+// 妯℃嫙褰撳墠鐧诲綍鍛樺伐
+const currentUser = reactive({
+  id: 1,
+  name: "寮犱笁",
+  no: "E10001",
+  dept: "鐢熶骇涓�閮�",
+});
+
+// 閮ㄩ棬閫夐」
+const deptOptions = [
+  { label: "鐢熶骇涓�閮�", value: "鐢熶骇涓�閮�" },
+  { label: "鐢熶骇浜岄儴", value: "鐢熶骇浜岄儴" },
+  { label: "璁惧缁存姢閮�", value: "璁惧缁存姢閮�" },
+  { label: "璐ㄦ閮�", value: "璐ㄦ閮�" },
+];
+
+// 妯℃嫙鑰冨嫟鍘熷鏁版嵁
+const rawAttendance = ref([
+  {
+    id: 1,
+    date: "2024-12-01",
+    userId: 1,
+    name: "寮犱笁",
+    no: "E10001",
+    dept: "鐢熶骇涓�閮�",
+    checkInTime: "08:58",
+    checkOutTime: "18:10",
+    workHours: 9.2,
+    status: "normal",
+    statusText: "姝e父",
+    remark: "",
+  },
+  {
+    id: 2,
+    date: "2024-12-01",
+    userId: 2,
+    name: "鏉庡洓",
+    no: "E10002",
+    dept: "鐢熶骇涓�閮�",
+    checkInTime: "09:15",
+    checkOutTime: "18:05",
+    workHours: 8.8,
+    status: "late",
+    statusText: "杩熷埌",
+    remark: "鍥犱氦閫氭嫢鍫佃繜鍒�",
+  },
+  {
+    id: 3,
+    date: "2024-12-01",
+    userId: 3,
+    name: "鐜嬩簲",
+    no: "E20001",
+    dept: "璁惧缁存姢閮�",
+    checkInTime: "08:50",
+    checkOutTime: "17:20",
+    workHours: 8.5,
+    status: "early",
+    statusText: "鏃╅��",
+    remark: "澶栧嚭澶勭悊绱ф�ユ晠闅�",
+  },
+  {
+    id: 4,
+    date: "2024-12-02",
+    userId: 1,
+    name: "寮犱笁",
+    no: "E10001",
+    dept: "鐢熶骇涓�閮�",
+    checkInTime: "08:45",
+    checkOutTime: "18:30",
+    workHours: 9.7,
+    status: "normal",
+    statusText: "姝e父",
+    remark: "鍔犵彮0.5灏忔椂",
+  },
+]);
+
+// 鏌ヨ琛ㄥ崟
+const searchForm = reactive({
+  dept: "",
+  date: "",
+});
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([]);
+
+// 褰撳墠鏃堕棿灞曠ず
+const nowTime = ref("");
+let timer = null;
+
+const updateNowTime = () => {
+  const now = new Date();
+  const Y = now.getFullYear();
+  const M = String(now.getMonth() + 1).padStart(2, "0");
+  const D = String(now.getDate()).padStart(2, "0");
+  const h = String(now.getHours()).padStart(2, "0");
+  const m = String(now.getMinutes()).padStart(2, "0");
+  const s = String(now.getSeconds()).padStart(2, "0");
+  nowTime.value = `${Y}-${M}-${D} ${h}:${m}:${s}`;
+};
+
+// 浠婃棩鏃ユ湡
+const todayStr = computed(() => nowTime.value.slice(0, 10));
+
+// 褰撴棩褰撳墠鍛樺伐鑰冨嫟璁板綍
+const todayRecord = computed(() =>
+  rawAttendance.value.find(
+    (item) =>
+      item.userId === currentUser.id && item.date === todayStr.value
+  )
+);
+
+// 鎵撳崱鎸夐挳鏂囨湰
+const checkInOutText = computed(() => {
+  if (!todayRecord.value || !todayRecord.value.checkInTime) {
+    return "涓婄彮鎵撳崱";
+  }
+  if (!todayRecord.value.checkOutTime) {
+    return "涓嬬彮鎵撳崱";
+  }
+  return "浠婃棩宸叉墦鍗″畬鎴�";
+});
+
+// 浠婃棩鐘舵�佸睍绀�
+const todayStatusTag = computed(() => {
+  if (!todayRecord.value) return "info";
+  if (todayRecord.value.status === "normal") return "success";
+  return "danger";
+});
+
+const todayStatusText = computed(() => {
+  if (!todayRecord.value) return "鏈墦鍗�";
+  return todayRecord.value.statusText || "姝e父";
+});
+
+// 琛屾牱寮忥細寮傚父楂樹寒
+const rowClassName = ({ row }) => {
+  if (row.status === "late" || row.status === "early") {
+    return "row-abnormal";
+  }
+  return "";
+};
+
+// 鏌ヨ
+const recomputeTable = () => {
+  const list = rawAttendance.value.filter((item) => {
+    if (searchForm.dept && item.dept !== searchForm.dept) {
+      return false;
+    }
+    if (searchForm.date && item.date !== searchForm.date) {
+      return false;
+    }
+    return true;
+  });
+  tableData.value = list;
+};
+
+const handleQuery = () => {
+  recomputeTable();
+};
+
+const resetSearch = () => {
+  searchForm.dept = "";
+  searchForm.date = "";
+  recomputeTable();
+};
+
+// 瀵煎嚭锛堟紨绀猴級
+const handleExport = () => {
+  ElMessage.success("褰撳墠涓烘紨绀洪〉闈紝瀵煎嚭鍔熻兘鏈鎺ュ疄闄呮帴鍙�");
+};
+
+// 鎵撳崱閫昏緫锛堜粎鍓嶇妯℃嫙锛�
+const handleCheckInOut = () => {
+  const [dateStr, timeStr] = nowTime.value.split(" ");
+  if (!dateStr || !timeStr) return;
+
+  // 涓婄彮鎵撳崱
+  if (!todayRecord.value) {
+    const newId = rawAttendance.value.length
+      ? Math.max(...rawAttendance.value.map((i) => i.id)) + 1
+      : 1;
+    const status =
+      timeStr > "09:00:00" ? "late" : "normal";
+    const statusText = status === "late" ? "杩熷埌" : "姝e父";
+    rawAttendance.value.push({
+      id: newId,
+      date: dateStr,
+      userId: currentUser.id,
+      name: currentUser.name,
+      no: currentUser.no,
+      dept: currentUser.dept,
+      checkInTime: timeStr.slice(0, 5),
+      checkOutTime: "",
+      workHours: null,
+      status,
+      statusText,
+      remark: "",
+    });
+    ElMessage.success("涓婄彮鎵撳崱鎴愬姛");
+  } else if (!todayRecord.value.checkOutTime) {
+    // 涓嬬彮鎵撳崱
+    todayRecord.value.checkOutTime = timeStr.slice(0, 5);
+    // 绠�鍗曟寜 9:00-18:00 璁$畻宸ユ椂
+    const start = todayRecord.value.checkInTime || "09:00";
+    const [sh, sm] = start.split(":").map((v) => parseInt(v, 10));
+    const [eh, em] = todayRecord.value.checkOutTime
+      .split(":")
+      .map((v) => parseInt(v, 10));
+    const diff = (eh * 60 + em - (sh * 60 + sm)) / 60;
+    todayRecord.value.workHours = Number(Math.max(diff, 0).toFixed(1));
+
+    // 鏃╅��鍒ゆ柇锛�18:00 鍓嶇寮�瑙嗕负鏃╅��锛堝彧绀烘剰锛�
+    if (timeStr < "18:00:00") {
+      todayRecord.value.status = "early";
+      todayRecord.value.statusText = "鏃╅��";
+    } else if (todayRecord.value.status === "normal") {
+      todayRecord.value.statusText = "姝e父";
+    }
+    ElMessage.success("涓嬬彮鎵撳崱鎴愬姛");
+  } else {
+    ElMessage.info("浠婃棩宸插畬鎴愪笂涓嬬彮鎵撳崱");
+  }
+
+  recomputeTable();
+};
+
+onMounted(() => {
+  updateNowTime();
+  timer = setInterval(updateNowTime, 1000);
+  // 榛樿灞曠ず褰撳ぉ鏁版嵁
+  const today = new Date();
+  const Y = today.getFullYear();
+  const M = String(today.getMonth() + 1).padStart(2, "0");
+  const D = String(today.getDate()).padStart(2, "0");
+  searchForm.date = `${Y}-${M}-${D}`;
+  recomputeTable();
+});
+
+onBeforeUnmount(() => {
+  if (timer) {
+    clearInterval(timer);
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.mb16 {
+  margin-bottom: 16px;
+}
+
+.attendance-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.attendance-header .title {
+  font-size: 18px;
+  font-weight: 600;
+  margin-bottom: 4px;
+}
+
+.attendance-header .sub-title {
+  font-size: 13px;
+  color: #909399;
+}
+
+.attendance-actions {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+}
+
+.time-block {
+  text-align: right;
+}
+
+.time-block .label {
+  font-size: 12px;
+  color: #909399;
+}
+
+.time-block .value {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+::v-deep(.row-abnormal) {
+  background-color: #fff5f5;
+}
+</style>
+
diff --git a/src/views/qualityManagement/afterSalesTraceability/index.vue b/src/views/qualityManagement/afterSalesTraceability/index.vue
new file mode 100644
index 0000000..8cd4856
--- /dev/null
+++ b/src/views/qualityManagement/afterSalesTraceability/index.vue
@@ -0,0 +1,595 @@
+<template>
+  <div class="app-container">
+    <!-- 鏌ヨ鏉′欢 -->
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      :inline="true"
+      v-show="showSearch"
+      label-width="90px"
+    >
+      <el-form-item label="浜у搧鍨嬪彿" prop="productModel">
+        <el-input
+          v-model="queryParams.productModel"
+          placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+        <el-input
+          v-model="queryParams.customerName"
+          placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍙嶉鏃堕棿" prop="feedbackRange">
+        <el-date-picker
+          v-model="queryParams.feedbackRange"
+          type="daterange"
+          range-separator="鑷�"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          value-format="YYYY-MM-DD"
+          format="YYYY-MM-DD"
+          clearable
+        />
+      </el-form-item>
+      <el-form-item label="澶勭悊鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="璇烽�夋嫨澶勭悊鐘舵��"
+          clearable
+        >
+          <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" icon="Search" @click="handleQuery">
+          鎼滅储
+        </el-button>
+        <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 鎿嶄綔鍖� -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="3">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+        >
+          鏂板鍞悗璐ㄩ噺璁板綍
+        </el-button>
+      </el-col>
+      <el-col :span="3">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+        >
+          淇敼
+        </el-button>
+      </el-col>
+      <el-col :span="3">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+        >
+          鍒犻櫎
+        </el-button>
+      </el-col>
+      <el-col :span="3">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+        >
+          瀵煎嚭
+        </el-button>
+      </el-col>
+      <right-toolbar
+        v-model:showSearch="showSearch"
+        @queryTable="getList"
+      />
+    </el-row>
+
+    <!-- 鏁版嵁琛� -->
+    <el-table
+      v-loading="loading"
+      :data="afterSalesList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="搴忓彿" type="index" width="55" align="center" />
+      <el-table-column label="閿�鍞悎鍚屽彿" prop="contractNo" width="160" />
+      <el-table-column label="浜у搧缂栧彿" prop="productCode" width="140" />
+      <el-table-column label="浜у搧鍨嬪彿" prop="productModel" width="140" />
+      <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" width="160" />
+      <el-table-column label="鑱旂郴鏂瑰紡" prop="contact" width="140" />
+      <el-table-column label="鍙嶉鏃堕棿" prop="feedbackTime" width="160">
+        <template #default="scope">
+          <span>{{ scope.row.feedbackTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="闂鎻忚堪" prop="problemDesc" show-overflow-tooltip />
+      <el-table-column label="缁翠慨鎯呭喌" prop="repairInfo" show-overflow-tooltip />
+      <el-table-column label="澶勭悊缁撴灉" prop="result" show-overflow-tooltip />
+      <el-table-column label="澶勭悊鐘舵��" prop="status" width="120" align="center">
+        <template #default="scope">
+          <dict-tag
+            :options="statusOptions"
+            :value="scope.row.status"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width" width="160" fixed="right">
+        <template #default="scope">
+          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(scope.row)">
+            淇敼
+          </el-button>
+          <el-button size="small" type="text" icon="Delete" @click="handleDelete(scope.row)">
+            鍒犻櫎
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 鏂板/淇敼寮圭獥 -->
+    <el-dialog
+      :title="title"
+      v-model="open"
+      width="900px"
+      append-to-body
+    >
+      <el-form
+        ref="formRef"
+        :model="form"
+        :rules="rules"
+        label-width="110px"
+      >
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="閿�鍞悎鍚屽彿" prop="contractNo">
+              <el-input
+                v-model="form.contractNo"
+                placeholder="璇烽�夋嫨鍏宠仈閿�鍞悎鍚屽彿"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浜у搧缂栧彿" prop="productCode">
+              <el-input
+                v-model="form.productCode"
+                placeholder="璇烽�夋嫨鍏宠仈浜у搧缂栧彿"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="浜у搧鍨嬪彿" prop="productModel">
+              <el-input
+                v-model="form.productModel"
+                placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀹㈡埛鍚嶇О" prop="customerName">
+              <el-input
+                v-model="form.customerName"
+                placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴鏂瑰紡" prop="contact">
+              <el-input
+                v-model="form.contact"
+                placeholder="璇疯緭鍏ュ鎴疯仈绯绘柟寮�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍙嶉鏃堕棿" prop="feedbackTime">
+              <el-date-picker
+                v-model="form.feedbackTime"
+                type="datetime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm"
+                placeholder="璇烽�夋嫨鍙嶉鏃堕棿"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="瀹㈡埛鍙嶉闂" prop="problemDesc">
+              <el-input
+                v-model="form.problemDesc"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯缁嗚褰曞鎴峰弽棣堥棶棰樸�佺幇璞℃弿杩扮瓑淇℃伅"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="缁翠慨鎯呭喌" prop="repairInfo">
+              <el-input
+                v-model="form.repairInfo"
+                type="textarea"
+                :rows="2"
+                placeholder="璁板綍缁翠慨杩囩▼銆佷娇鐢ㄥ浠躲�佽繑淇鏁扮瓑"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="澶勭悊缁撴灉" prop="result">
+              <el-input
+                v-model="form.result"
+                type="textarea"
+                :rows="2"
+                placeholder="璁板綍鏈�缁堝鐞嗙粨鏋滐紝濡傛洿鎹€�侀��璐с�佸崌绾х瓑"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="澶勭悊鐘舵��" prop="status">
+              <el-select
+                v-model="form.status"
+                placeholder="璇烽�夋嫨澶勭悊鐘舵��"
+              >
+                <el-option
+                  v-for="item in statusOptions"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="澶囨敞" prop="remark">
+              <el-input
+                v-model="form.remark"
+                type="textarea"
+                :rows="2"
+                placeholder="鍙褰曞悗缁窡韪剰瑙併�佸鐩樼粨璁虹瓑"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </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="AfterSalesTraceability">
+import { ref, reactive, onMounted } from "vue";
+import { ElMessageBox } from "element-plus";
+
+const { proxy } = getCurrentInstance();
+
+// 鐘舵�佸瓧鍏�
+const statusOptions = ref([
+  { label: "寰呭鐞�", value: "0" },
+  { label: "澶勭悊涓�", value: "1" },
+  { label: "宸插畬鎴�", value: "2" },
+  { label: "宸插叧闂�", value: "3" },
+]);
+
+// 妯℃嫙鍞悗璐ㄩ噺鏁版嵁
+const afterSalesList = ref([
+  {
+    id: 1,
+    contractNo: "SC-2024-001",
+    productCode: "P-10001",
+    productModel: "XG-500A",
+    customerName: "鍗庡崡鐢靛瓙绉戞妧鏈夐檺鍏徃",
+    contact: "寮犲伐 / 13800000001",
+    feedbackTime: "2024-12-01 10:23:00",
+    problemDesc: "浣跨敤涓変釜鏈堝悗鍑虹幇闂存瓏鎬ф帀鐢碉紝褰卞搷浜х嚎绋冲畾杩愯銆�",
+    repairInfo: "瀹夋帓宸ョ▼甯堜笂闂ㄦ淇紝鏇存崲鐢垫簮妯″潡骞跺姞鍥烘帴绾跨瀛愩��",
+    result: "鏇存崲鐢垫簮鎬绘垚锛屾仮澶嶆甯镐娇鐢紝寤鸿瀹㈡埛澧炲姞UPS淇濇姢銆�",
+    status: "2",
+    remark: "鍒楀叆閲嶇偣璺熻釜瀹㈡埛锛屽悗缁瀵熶竴涓搴︺��",
+  },
+  {
+    id: 2,
+    contractNo: "SC-2024-015",
+    productCode: "P-10045",
+    productModel: "XG-500B",
+    customerName: "鍗庝笢绮惧瘑鍒堕�犳湁闄愬叕鍙�",
+    contact: "鏉庡伐 / 13800000002",
+    feedbackTime: "2024-12-05 15:40:00",
+    problemDesc: "閮ㄥ垎鎵规鍑虹幇澶栧3鍒姳锛屽鎴锋姇璇夊瑙傝川閲忎笉杈炬爣銆�",
+    repairInfo: "涓庣敓浜х幇鍦烘牳鏌ワ紝纭鏉ユ枡鎼繍鍙婂寘瑁呯幆鑺傚瓨鍦ㄧ纰伴闄┿��",
+    result: "瀵归棶棰樻壒娆¢噸鏂拌繑宸ワ紝琛ュ彂鑹搧锛屽苟浼樺寲鍖呰闃叉姢鏂规銆�",
+    status: "1",
+    remark: "闇�璺熻釜鍚庣画鎵规鎶曡瘔鐜囧彉鍖栥��",
+  },
+  {
+    id: 3,
+    contractNo: "SC-2024-032",
+    productCode: "P-10110",
+    productModel: "XG-600C",
+    customerName: "瑗垮崡鏂拌兘婧愮鎶�鑲′唤",
+    contact: "鐜嬪伐 / 13800000003",
+    feedbackTime: "2024-11-28 09:15:00",
+    problemDesc: "鐜板満璋冭瘯鏃跺彂鐜版帴鍙d笉鍏煎锛岄渶瑕侀�傞厤瀹㈡埛鏃х増绯荤粺銆�",
+    repairInfo: "杩滅▼鎶�鏈敮鎸�+鐜板満宸ョ▼甯堣仈鍚堟帓鏌ワ紝鎻愪緵杩囨浮閫傞厤鏂规銆�",
+    result: "閫氳繃鏇存崲鎺ユ彃浠跺苟鍗囩骇鍥轰欢鐗堟湰瑙e喅銆�",
+    status: "0",
+    remark: "寤鸿涓嬫鍚堝悓鍓嶇疆娌熼�氭帴鍙h鏍笺��",
+  },
+]);
+
+const open = ref(false);
+const loading = ref(false);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(3);
+const title = ref("鏂板鍞悗璐ㄩ噺璁板綍");
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productModel: null,
+    customerName: null,
+    feedbackRange: [],
+    status: null,
+  },
+  rules: {
+    contractNo: [
+      { required: true, message: "閿�鍞悎鍚屽彿涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    productCode: [
+      { required: true, message: "浜у搧缂栧彿涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    productModel: [
+      { required: true, message: "浜у搧鍨嬪彿涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    customerName: [
+      { required: true, message: "瀹㈡埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    contact: [
+      { required: true, message: "鑱旂郴鏂瑰紡涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    feedbackTime: [
+      { required: true, message: "鍙嶉鏃堕棿涓嶈兘涓虹┖", trigger: "change" },
+    ],
+    problemDesc: [
+      { required: true, message: "瀹㈡埛鍙嶉闂涓嶈兘涓虹┖", trigger: "blur" },
+    ],
+    status: [
+      { required: true, message: "澶勭悊鐘舵�佷笉鑳戒负绌�", trigger: "change" },
+    ],
+  },
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃锛堜粎鍓嶇绛涢�夛紝涓嶈皟鎺ュ彛锛�
+function getList() {
+  loading.value = true;
+  const list = afterSalesList.value.filter((item) => {
+    if (
+      queryParams.value.productModel &&
+      !item.productModel
+        ?.toLowerCase()
+        .includes(queryParams.value.productModel.toLowerCase())
+    ) {
+      return false;
+    }
+    if (
+      queryParams.value.customerName &&
+      !item.customerName
+        ?.toLowerCase()
+        .includes(queryParams.value.customerName.toLowerCase())
+    ) {
+      return false;
+    }
+    if (queryParams.value.status && item.status !== queryParams.value.status) {
+      return false;
+    }
+    if (
+      Array.isArray(queryParams.value.feedbackRange) &&
+      queryParams.value.feedbackRange.length === 2
+    ) {
+      const [start, end] = queryParams.value.feedbackRange;
+      const dateStr = item.feedbackTime?.slice(0, 10);
+      if (dateStr < start || dateStr > end) {
+        return false;
+      }
+    }
+    return true;
+  });
+  total.value = list.length;
+  // 姝ゅ鏈仛鍒嗛〉锛屼粎妯℃嫙鍏ㄩ噺灞曠ず
+  afterSalesList.value = list;
+  loading.value = false;
+}
+
+// 鍙栨秷
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+  form.value = {
+    id: null,
+    contractNo: null,
+    productCode: null,
+    productModel: null,
+    customerName: null,
+    contact: null,
+    feedbackTime: null,
+    problemDesc: null,
+    repairInfo: null,
+    result: null,
+    status: "0",
+    remark: null,
+  };
+  proxy.resetForm("formRef");
+}
+
+// 鎼滅储
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+// 閲嶇疆
+function resetQuery() {
+  proxy.resetForm("queryForm");
+  queryParams.value.feedbackRange = [];
+  handleQuery();
+}
+
+// 澶氶��
+function handleSelectionChange(selection) {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+}
+
+// 鏂板
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "鏂板鍞悗璐ㄩ噺璁板綍";
+}
+
+// 淇敼
+function handleUpdate(row) {
+  reset();
+  const current = row || afterSalesList.value.find((item) => item.id === ids.value[0]);
+  if (current) {
+    form.value = { ...current };
+    open.value = true;
+    title.value = "淇敼鍞悗璐ㄩ噺璁板綍";
+  }
+}
+
+// 鎻愪氦
+function submitForm() {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (form.value.id != null) {
+        // 淇敼锛氭浛鎹㈡湰鍦版ā鎷熸暟鎹�
+        const index = afterSalesList.value.findIndex(
+          (item) => item.id === form.value.id
+        );
+        if (index !== -1) {
+          afterSalesList.value.splice(index, 1, { ...form.value });
+        }
+        proxy.$modal.msgSuccess("淇敼鎴愬姛");
+      } else {
+        // 鏂板锛氭彃鍏ユ湰鍦版ā鎷熸暟鎹�
+        const newId =
+          afterSalesList.value.length > 0
+            ? Math.max(...afterSalesList.value.map((i) => i.id)) + 1
+            : 1;
+        afterSalesList.value.push({ ...form.value, id: newId });
+        proxy.$modal.msgSuccess("鏂板鎴愬姛");
+      }
+      open.value = false;
+      getList();
+    }
+  });
+}
+
+// 鍒犻櫎
+function handleDelete(row) {
+  const deleteIds = row?.id ? [row.id] : ids.value;
+  if (!deleteIds || deleteIds.length === 0) {
+    proxy.$modal.msgWarning("璇峰厛閫夋嫨瑕佸垹闄ょ殑璁板綍");
+    return;
+  }
+  ElMessageBox.confirm(
+    '鏄惁纭鍒犻櫎閫変腑鐨勫敭鍚庤川閲忚褰曪紵',
+    "璀﹀憡",
+    {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }
+  )
+    .then(() => {
+      // 鍓嶇鍒犻櫎鏈湴妯℃嫙鏁版嵁
+      afterSalesList.value = afterSalesList.value.filter(
+        (item) => !deleteIds.includes(item.id)
+      );
+      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      getList();
+    })
+    .catch(() => {});
+}
+
+// 瀵煎嚭
+function handleExport() {
+  proxy.$modal.msgSuccess("瀵煎嚭鍔熻兘涓烘紨绀哄姛鑳斤紝褰撳墠鏈鎺ュ疄闄呭鍑烘帴鍙�");
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped>
+.mb8 {
+  margin-bottom: 8px;
+}
+.dialog-footer {
+  text-align: right;
+}
+</style>
+

--
Gitblit v1.9.3