From 2dd434830299e781cd942ef5e6e938160dd12704 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 03 三月 2026 17:15:18 +0800
Subject: [PATCH] 原材料检验功能开发

---
 src/pages/qualityManagement/materialInspection/index.vue |  814 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 814 insertions(+), 0 deletions(-)

diff --git a/src/pages/qualityManagement/materialInspection/index.vue b/src/pages/qualityManagement/materialInspection/index.vue
new file mode 100644
index 0000000..c575493
--- /dev/null
+++ b/src/pages/qualityManagement/materialInspection/index.vue
@@ -0,0 +1,814 @@
+<template>
+  <view class="material-inspection-page">
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="鍘熸潗鏂欐楠�"
+                @back="goBack" />
+    <!-- 鎼滅储鍖哄煙 -->
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    placeholder="璇疯緭鍏ヤ緵搴斿晢鎼滅储"
+                    v-model="searchForm.supplier"
+                    @change="getList"
+                    clearable />
+        </view>
+        <!-- <view class="filter-button"
+              @click="showDatePicker">
+          <up-icon name="calendar"
+                   size="24"
+                   color="#999"></up-icon>
+        </view> -->
+        <view class="filter-button"
+              @click="getList">
+          <up-icon name="search"
+                   size="24"
+                   color="#999"></up-icon>
+        </view>
+      </view>
+      <!-- 鏃ユ湡閫夋嫨 -->
+      <!-- <view class="date-range"
+            v-if="searchForm.entryDate">
+        <text class="date-text">{{ searchForm.entryDate[0] }} 鑷� {{ searchForm.entryDate[1] }}</text>
+        <up-icon name="close"
+                 size="16"
+                 color="#999"
+                 @click="clearDateRange"></up-icon>
+      </view> -->
+    </view>
+    <!-- 缁熻淇℃伅鍗$墖 -->
+    <!-- <view class="stats-cards">
+      <view class="stat-card">
+        <text class="stat-number">{{ totalCount }}</text>
+        <text class="stat-label">鎬绘楠�</text>
+      </view>
+      <view class="stat-card">
+        <text class="stat-number">{{ submittedCount }}</text>
+        <text class="stat-label">宸叉彁浜�</text>
+      </view>
+      <view class="stat-card">
+        <text class="stat-number">{{ pendingCount }}</text>
+        <text class="stat-label">寰呮彁浜�</text>
+      </view>
+      <view class="stat-card">
+        <text class="stat-number">{{ qualifiedCount }}</text>
+        <text class="stat-label">宸插悎鏍�</text>
+      </view>
+    </view> -->
+    <!-- 妫�楠屽垪琛� -->
+    <view class="inspection-list"
+          v-if="inspectionList.length > 0">
+      <view v-for="(item, index) in inspectionList"
+            :key="index">
+        <view class="inspection-item"
+              @click="viewDetail(item)">
+          <view class="item-header">
+            <view class="item-left">
+              <!-- <view class="material-icon"
+                    :class="getStateClass(item.inspectState)">
+                <up-icon :name="getStateIcon(item.inspectState)"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view> -->
+              <view class="material-info">
+                <text class="material-name">{{ item.productName }}</text>
+                <text class="material-code">{{ item.model }}</text>
+              </view>
+            </view>
+            <view class="status-tags">
+              <u-tag :type="getTagType(item.checkResult)"
+                     size="mini"
+                     class="status-tag">
+                {{ item.checkResult }}
+              </u-tag>
+              <u-tag :type="getStateTagType(item.inspectState)"
+                     size="mini"
+                     class="status-tag">
+                {{ item.inspectState ? '宸叉彁浜�' : '鏈彁浜�' }}
+              </u-tag>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">妫�娴嬫棩鏈�</text>
+              <text class="detail-value">{{ formatDateTime(item.checkTime) || '-' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">閲囪喘璁㈠崟鍙�</text>
+              <text class="detail-value">{{ item.purchaseContractNo || '-' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">渚涘簲鍟�</text>
+              <text class="detail-value">{{ item.supplier || '-' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">妫�楠屽憳</text>
+              <text class="detail-value">{{ item.checkName || '-' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鏁伴噺</text>
+              <text class="detail-value">{{ item.quantity || 0 }} {{ item.unit || '' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">妫�娴嬪崟浣�</text>
+              <text class="detail-value">{{ item.checkCompany || '-' }}</text>
+            </view>
+          </view>
+          <!-- 鎿嶄綔鎸夐挳 -->
+          <view class="action-buttons">
+            <u-button type="primary"
+                      size="small"
+                      class="action-btn"
+                      :disabled="item.inspectState"
+                      @click.stop="startInspection(item)">
+              缂栬緫
+            </u-button>
+            <u-button type="info"
+                      size="small"
+                      class="action-btn"
+                      @click.stop="viewDetail(item)">
+              璇︽儏
+            </u-button>
+            <u-button type="success"
+                      size="small"
+                      class="action-btn"
+                      :disabled="item.inspectState"
+                      @click.stop="submitInspection(item)">
+              鎻愪氦
+            </u-button>
+          </view>
+          <view class="action-buttons">
+            <u-button type="info"
+                      size="small"
+                      class="action-btn"
+                      @click.stop="viewFileList(item)">
+              闄勪欢
+            </u-button>
+            <u-button type="warning"
+                      size="small"
+                      class="action-btn"
+                      :disabled="item.inspectState || item.checkName !== ''"
+                      @click.stop="assignInspector(item)">
+              鍒嗛厤妫�楠屽憳
+            </u-button>
+          </view>
+        </view>
+      </view>
+    </view>
+    <view v-else
+          class="no-data">
+      <up-empty mode="data"
+                text="鏆傛棤妫�楠屼换鍔�"></up-empty>
+    </view>
+    <!-- 鍒嗛〉缁勪欢 -->
+    <!-- 娴姩鏂板鎸夐挳 -->
+    <view class="fab-button"
+          @click="addInspection">
+      <up-icon name="plus"
+               size="24"
+               color="#ffffff"></up-icon>
+    </view>
+    <!-- 鏃ユ湡閫夋嫨鍣� -->
+    <up-popup v-model:show="showDate"
+              mode="date"
+              :start-year="2020"
+              :end-year="2030"
+              :range="true"
+              @confirm="confirmDate" />
+    <!-- 鍒嗛厤妫�楠屽憳寮圭獥 -->
+    <up-popup v-model:show="showAssignDialog"
+              mode="center"
+              round
+              style="width: 80%">
+      <view class="assign-dialog">
+        <view class="dialog-header">
+          <text class="dialog-title">鍒嗛厤妫�楠屽憳</text>
+          <up-icon name="close"
+                   size="20"
+                   color="#999"
+                   @click="showAssignDialog = false"></up-icon>
+        </view>
+        <view class="dialog-content">
+          <up-form-item label="妫�楠屽憳"
+                        prop="checkName"
+                        :label-width="60"
+                        required>
+            <up-input v-model="assignForm.checkName"
+                      placeholder="璇烽�夋嫨妫�楠屽憳"
+                      readonly />
+            <template #right>
+              <up-icon @click="showInspectorSheet = true"
+                       name="arrow-right" />
+            </template>
+          </up-form-item>
+        </view>
+        <view class="dialog-footer">
+          <u-button type="default"
+                    class="footer-btn"
+                    @click="showAssignDialog = false">
+            鍙栨秷
+          </u-button>
+          <u-button type="primary"
+                    class="footer-btn"
+                    @click="submitAssign">
+            纭畾
+          </u-button>
+        </view>
+      </view>
+    </up-popup>
+    <!-- 妫�楠屽憳閫夋嫨 -->
+    <up-action-sheet :show="showInspectorSheet"
+                     :actions="userSheetOptions"
+                     @select="selectInspector"
+                     title="閫夋嫨妫�楠屽憳" />
+  </view>
+</template>
+
+<script setup>
+  import { ref, computed, onMounted } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import PageHeader from "@/components/PageHeader.vue";
+  import dayjs from "dayjs";
+  import {
+    submitQualityInspect,
+    qualityInspectUpdate,
+    qualityInspectListPage,
+  } from "@/api/qualityManagement/materialInspection.js";
+  import { userListNoPage } from "@/api/system/user.js";
+
+  // 鏄剧ず鎻愮ず淇℃伅
+  const showToast = message => {
+    uni.showToast({
+      title: message,
+      icon: "none",
+    });
+  };
+
+  // 鎼滅储琛ㄥ崟
+  const searchForm = ref({
+    supplier: "",
+    entryDate: undefined,
+    entryDateStart: undefined,
+    entryDateEnd: undefined,
+  });
+
+  // 鏃ユ湡閫夋嫨鍣�
+  const showDate = ref(false);
+
+  // 鍒嗛厤妫�楠屽憳寮圭獥
+  const showAssignDialog = ref(false);
+  const showInspectorSheet = ref(false);
+  const assignForm = ref({
+    checkName: "",
+  });
+  const currentAssignRow = ref(null);
+
+  // 妫�楠屽垪琛ㄦ暟鎹�
+  const inspectionList = ref([]);
+
+  // 鍒嗛〉鏁版嵁
+  const page = ref({
+    current: -1,
+    size: -1,
+    total: 0,
+  });
+
+  // 鍔犺浇鐘舵��
+  const tableLoading = ref(false);
+
+  // 缁熻鏁版嵁
+  const totalCount = ref(0);
+  const submittedCount = ref(0);
+  const pendingCount = ref(0);
+  const qualifiedCount = ref(0);
+
+  // 妫�楠屽憳鍒楄〃
+  const userList = ref([]);
+
+  // ActionSheet閫夐」
+  const userSheetOptions = computed(() => {
+    return userList.value.map(item => ({
+      name: item.nickName,
+      value: item.nickName,
+    }));
+  });
+
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  // 鏍煎紡鍖栨棩鏈熸椂闂�
+  const formatDateTime = dateStr => {
+    if (!dateStr) return "";
+    return dayjs(dateStr).format("YYYY-MM-DD");
+  };
+
+  // 鑾峰彇鐘舵�佹牱寮�
+  const getStateClass = inspectState => {
+    return inspectState ? "state-submitted" : "state-pending";
+  };
+
+  // 鑾峰彇鐘舵�佸浘鏍�
+  const getStateIcon = inspectState => {
+    return inspectState ? "checkmark-circle" : "time";
+  };
+
+  // 鑾峰彇鏍囩绫诲瀷
+  const getTagType = checkResult => {
+    if (checkResult === "鍚堟牸") return "success";
+    if (checkResult === "涓嶅悎鏍�") return "error";
+    return "default";
+  };
+
+  // 鑾峰彇鐘舵�佹爣绛剧被鍨�
+  const getStateTagType = inspectState => {
+    return inspectState ? "success" : "warning";
+  };
+
+  // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+  const showDatePicker = () => {
+    showDate.value = true;
+  };
+
+  // 纭鏃ユ湡閫夋嫨
+  const confirmDate = e => {
+    searchForm.value.entryDate = e.value;
+    searchForm.value.entryDateStart = dayjs(e.value[0]).format("YYYY-MM-DD");
+    searchForm.value.entryDateEnd = dayjs(e.value[1]).format("YYYY-MM-DD");
+    getList();
+  };
+  const viewFileList = item => {
+    uni.setStorageSync("qualityInspectFileId", item.id);
+    uni.navigateTo({
+      url: "/pages/qualityManagement/materialInspection/fileList",
+    });
+  };
+
+  // 娓呴櫎鏃ユ湡鑼冨洿
+  const clearDateRange = () => {
+    searchForm.value.entryDate = undefined;
+    searchForm.value.entryDateStart = undefined;
+    searchForm.value.entryDateEnd = undefined;
+    getList();
+  };
+
+  // 鑾峰彇鐢ㄦ埛鍒楄〃
+  const getUserList = async () => {
+    try {
+      const userRes = await userListNoPage();
+      userList.value = userRes.data || [];
+    } catch (e) {
+      console.error("鍔犺浇妫�楠屽憳鍒楄〃澶辫触", e);
+      userList.value = [];
+    }
+  };
+
+  // 鏌ヨ鍒楄〃
+  const getList = () => {
+    tableLoading.value = true;
+    const params = { ...searchForm.value, ...page.value };
+    params.entryDate = undefined;
+    qualityInspectListPage({ ...params, inspectType: 0 })
+      .then(res => {
+        tableLoading.value = false;
+        inspectionList.value = res.data.records || [];
+        page.value.total = res.data.total || 0;
+        totalCount.value = res.data.total || 0;
+        submittedCount.value = inspectionList.value.filter(
+          item => item.inspectState
+        ).length;
+        pendingCount.value = inspectionList.value.filter(
+          item => !item.inspectState
+        ).length;
+        qualifiedCount.value = inspectionList.value.filter(
+          item => item.checkResult === "鍚堟牸"
+        ).length;
+      })
+      .catch(err => {
+        tableLoading.value = false;
+        console.error("鑾峰彇鍒楄〃澶辫触:", err);
+        showToast("鑾峰彇鍒楄〃澶辫触锛岃閲嶈瘯");
+      });
+  };
+
+  // 缂栬緫妫�楠�
+  const startInspection = item => {
+    if (!item) {
+      showToast("鍙傛暟閿欒");
+      return;
+    }
+    // 瀛樺偍瀹屾暣鐨勬楠屾暟鎹�
+    uni.setStorageSync("inspectionEditData", item);
+    // 璺宠浆鍒扮紪杈戦〉闈�
+    uni.navigateTo({
+      url: `/pages/qualityManagement/materialInspection/add?id=${item.id}&isEdit=true`,
+    });
+  };
+
+  // 鏌ョ湅璇︽儏
+  const viewDetail = item => {
+    if (!item) {
+      showToast("鍙傛暟閿欒");
+      return;
+    }
+    // 璺宠浆鍒拌鎯呴〉闈�
+    uni.navigateTo({
+      url: `/pages/qualityManagement/materialInspection/detail?id=${item.id}`,
+    });
+  };
+
+  // 鏂板妫�楠�
+  const addInspection = () => {
+    uni.navigateTo({
+      url: "/pages/qualityManagement/materialInspection/add",
+    });
+  };
+
+  // 鎻愪氦妫�楠�
+  const submitInspection = async item => {
+    if (!item) {
+      showToast("鍙傛暟閿欒");
+      return;
+    }
+    try {
+      const res = await submitQualityInspect({ id: item.id });
+      if (res.code === 200) {
+        showToast("鎻愪氦鎴愬姛");
+        setTimeout(() => {
+          getList();
+        }, 1000);
+      } else {
+        showToast("鎻愪氦澶辫触锛�" + (res.msg || "鏈煡閿欒"));
+      }
+    } catch (error) {
+      console.error("鎻愪氦澶辫触:", error);
+      showToast("鎻愪氦澶辫触锛岃閲嶈瘯");
+    }
+  };
+
+  // 鍒嗛厤妫�楠屽憳
+  const assignInspector = item => {
+    if (!item) {
+      showToast("鍙傛暟閿欒");
+      return;
+    }
+    currentAssignRow.value = item;
+    getUserList();
+    showAssignDialog.value = true;
+  };
+
+  // 閫夋嫨妫�楠屽憳
+  const selectInspector = e => {
+    assignForm.value.checkName = e.value;
+    showInspectorSheet.value = false;
+  };
+
+  // 鎻愪氦鍒嗛厤
+  const submitAssign = async () => {
+    if (!currentAssignRow.value || !assignForm.value.checkName) {
+      showToast("璇烽�夋嫨妫�楠屽憳");
+      return;
+    }
+    try {
+      const data = {
+        ...assignForm.value,
+        id: currentAssignRow.value.id,
+      };
+      const res = await qualityInspectUpdate(data);
+      if (res.code === 200) {
+        showToast("鍒嗛厤鎴愬姛");
+        showAssignDialog.value = false;
+        setTimeout(() => {
+          getList();
+        }, 1000);
+      } else {
+        showToast("鍒嗛厤澶辫触锛�" + (res.msg || "鏈煡閿欒"));
+      }
+    } catch (error) {
+      console.error("鍒嗛厤澶辫触:", error);
+      showToast("鍒嗛厤澶辫触锛岃閲嶈瘯");
+    }
+  };
+
+  // 澶勭悊鍒嗛〉
+  const handlePagination = obj => {
+    page.value.current = obj.current;
+    page.value.size = obj.size;
+    getList();
+  };
+
+  onMounted(() => {
+    getList();
+    getUserList();
+  });
+
+  onShow(() => {
+    getList();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "../../../styles/sales-common.scss";
+
+  .material-inspection-page {
+    min-height: 100vh;
+    background: #f8f9fa;
+    padding-bottom: 80px;
+  }
+
+  // 鎼滅储鍖哄煙
+  .search-section {
+    padding: 10px 15px;
+    background: #fff;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .search-bar {
+    display: flex;
+    align-items: center;
+    background: #f8f9fa;
+    border-radius: 20px;
+    padding: 0 15px;
+    height: 40px;
+  }
+
+  .search-input {
+    flex: 1;
+  }
+
+  .search-text {
+    background: transparent;
+    border: none;
+  }
+
+  .filter-button {
+    margin-left: 10px;
+    padding: 5px;
+  }
+
+  // 缁熻鍗$墖
+  .stats-cards {
+    display: flex;
+    padding: 15px;
+    gap: 10px;
+    background: #fff;
+    margin-bottom: 10px;
+  }
+
+  .stat-card {
+    flex: 1;
+    background: #2979ff;
+    border-radius: 12px;
+    padding: 15px;
+    text-align: center;
+    color: #fff;
+    box-shadow: 0 2px 8px rgba(41, 121, 255, 0.2);
+  }
+
+  .stat-number {
+    display: block;
+    font-size: 20px;
+    font-weight: 600;
+    margin-bottom: 5px;
+  }
+
+  .stat-label {
+    font-size: 12px;
+    opacity: 0.9;
+  }
+
+  // 妫�楠屽垪琛�
+  .inspection-list {
+    padding: 20px;
+  }
+
+  .inspection-item {
+    background: #ffffff;
+    border-radius: 12px;
+    margin-bottom: 16px;
+    overflow: hidden;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+    padding: 0 16px;
+
+    &:active {
+      transform: scale(0.98);
+      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+
+  .item-header {
+    padding: 16px 0;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .item-left {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .material-icon {
+    width: 24px;
+    height: 24px;
+    background: #2979ff;
+    border-radius: 4px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .state-pending {
+    background: #ff9900;
+  }
+
+  .state-submitted {
+    background: #52c41a;
+  }
+
+  .material-info {
+    flex: 1;
+  }
+
+  .material-name {
+    font-size: 14px;
+    color: #333;
+    font-weight: 500;
+  }
+
+  .material-code {
+    font-size: 12px;
+    color: #999;
+    margin-left: 8px;
+  }
+
+  .status-tags {
+    display: flex;
+    gap: 8px;
+  }
+
+  .status-tag {
+    margin: 0;
+  }
+
+  .date-range {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 10px;
+    padding: 8px 12px;
+    background: #f8f9fa;
+    border-radius: 8px;
+  }
+
+  .date-text {
+    font-size: 12px;
+    color: #666;
+  }
+
+  // 璇︽儏琛�
+  .item-details {
+    padding: 16px 0;
+  }
+
+  .detail-row {
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    margin-bottom: 8px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+
+  .detail-label {
+    font-size: 12px;
+    color: #777777;
+    min-width: 60px;
+  }
+
+  .detail-value {
+    font-size: 12px;
+    color: #000000;
+    text-align: right;
+    flex: 1;
+    margin-left: 16px;
+  }
+
+  // 鎿嶄綔鎸夐挳
+  .action-buttons {
+    display: flex;
+    gap: 12px;
+    padding: 0 0 16px 0;
+    justify-content: space-between;
+  }
+
+  .action-btn {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 8px;
+  }
+
+  // 绌虹姸鎬�
+  .no-data {
+    padding: 60px 20px;
+    text-align: center;
+  }
+
+  // 娴姩鎸夐挳
+  .fab-button {
+    position: fixed;
+    bottom: 20px;
+    right: 20px;
+    width: 56px;
+    height: 56px;
+    background: #2979ff;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0 4px 16px rgba(41, 121, 255, 0.3);
+    z-index: 1000;
+  }
+
+  // 鍒嗛厤妫�楠屽憳寮圭獥
+  .assign-dialog {
+    padding: 24px;
+    background: #ffffff;
+    border-radius: 12px;
+  }
+
+  .dialog-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 24px;
+    padding-bottom: 16px;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .dialog-title {
+    font-size: 18px;
+    font-weight: 600;
+    color: #303133;
+  }
+
+  .dialog-content {
+    margin-bottom: 24px;
+  }
+
+  .dialog-footer {
+    display: flex;
+    gap: 16px;
+    padding-top: 16px;
+    border-top: 1px solid #f0f0f0;
+  }
+
+  .footer-btn {
+    flex: 1;
+    height: 44px;
+    font-size: 16px;
+  }
+
+  // 杈撳叆妗嗘牱寮�
+  :deep(.up-input__inner) {
+    border-radius: 8px;
+    height: 44px;
+    font-size: 14px;
+  }
+
+  // 琛ㄥ崟椤规牱寮�
+  :deep(.up-form-item) {
+    margin-bottom: 0;
+  }
+
+  :deep(.up-form-item__label) {
+    font-size: 14px;
+    color: #606266;
+    margin-bottom: 8px;
+  }
+
+  // 鎸夐挳鏍峰紡
+  :deep(.up-button--primary) {
+    border-radius: 8px;
+  }
+
+  :deep(.up-button--default) {
+    border-radius: 8px;
+  }
+
+  // 鍒嗛〉缁勪欢
+  .pagination {
+    padding: 20px;
+    background: #fff;
+    margin-top: 10px;
+    display: flex;
+    justify-content: center;
+  }
+</style>

--
Gitblit v1.9.3