From bf0d5e47a21816c440a2850299c8af60d58d1f25 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 05 三月 2026 16:41:24 +0800
Subject: [PATCH] lims模块

---
 src/api/lims/realtimeMonitor.js                  |   46 
 src/api/lims/dataInterface.js                    |   46 
 src/api/lims/sample.js                           |   46 
 src/api/lims/experiment.js                       |   46 
 src/views/lims/dataInterfaceManagement/index.vue |  479 +++++++++
 src/views/lims/dataCollection/index.vue          |  561 +++++++++++
 src/views/lims/experimentManagement/index.vue    |  526 ++++++++++
 src/views/lims/realtimeMonitor/index.vue         |  582 +++++++++++
 src/api/lims/dataCollection.js                   |   46 
 src/views/lims/sampleManagement/index.vue        |  539 +++++++++++
 10 files changed, 2,917 insertions(+), 0 deletions(-)

diff --git a/src/api/lims/dataCollection.js b/src/api/lims/dataCollection.js
new file mode 100644
index 0000000..595d20f
--- /dev/null
+++ b/src/api/lims/dataCollection.js
@@ -0,0 +1,46 @@
+// 鏁版嵁閲囬泦涓庡鐞嗛〉闈㈡帴鍙�
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ鏁版嵁閲囬泦
+export function listDataCollection(query) {
+    return request({
+        url: '/lims/dataCollection/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鏌ヨ鏁版嵁閲囬泦璇︾粏
+export function getDataCollection(id) {
+    return request({
+        url: '/lims/dataCollection/' + id,
+        method: 'get'
+    })
+}
+
+// 鏂板鏁版嵁閲囬泦
+export function addDataCollection(data) {
+    return request({
+        url: '/lims/dataCollection/add',
+        method: 'post',
+        data: data
+    })
+}
+
+// 淇敼鏁版嵁閲囬泦
+export function updateDataCollection(data) {
+    return request({
+        url: '/lims/dataCollection/update',
+        method: 'post',
+        data: data
+    })
+}
+
+// 鍒犻櫎鏁版嵁閲囬泦
+export function delDataCollection(ids) {
+    return request({
+        url: '/lims/dataCollection/delete',
+        method: 'delete',
+        data: ids
+    })
+}
diff --git a/src/api/lims/dataInterface.js b/src/api/lims/dataInterface.js
new file mode 100644
index 0000000..ff20ba6
--- /dev/null
+++ b/src/api/lims/dataInterface.js
@@ -0,0 +1,46 @@
+// 鏁版嵁鎺ュ彛绠$悊椤甸潰鎺ュ彛
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ鏁版嵁鎺ュ彛
+export function listDataInterface(query) {
+    return request({
+        url: '/lims/dataInterface/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鏌ヨ鏁版嵁鎺ュ彛璇︾粏
+export function getDataInterface(id) {
+    return request({
+        url: '/lims/dataInterface/' + id,
+        method: 'get'
+    })
+}
+
+// 鏂板鏁版嵁鎺ュ彛
+export function addDataInterface(data) {
+    return request({
+        url: '/lims/dataInterface/add',
+        method: 'post',
+        data: data
+    })
+}
+
+// 淇敼鏁版嵁鎺ュ彛
+export function updateDataInterface(data) {
+    return request({
+        url: '/lims/dataInterface/update',
+        method: 'post',
+        data: data
+    })
+}
+
+// 鍒犻櫎鏁版嵁鎺ュ彛
+export function delDataInterface(ids) {
+    return request({
+        url: '/lims/dataInterface/delete',
+        method: 'delete',
+        data: ids
+    })
+}
diff --git a/src/api/lims/experiment.js b/src/api/lims/experiment.js
new file mode 100644
index 0000000..bf3224f
--- /dev/null
+++ b/src/api/lims/experiment.js
@@ -0,0 +1,46 @@
+// 瀹為獙绠$悊椤甸潰鎺ュ彛
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ瀹為獙
+export function listExperiment(query) {
+    return request({
+        url: '/lims/experiment/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鏌ヨ瀹為獙璇︾粏
+export function getExperiment(id) {
+    return request({
+        url: '/lims/experiment/' + id,
+        method: 'get'
+    })
+}
+
+// 鏂板瀹為獙
+export function addExperiment(data) {
+    return request({
+        url: '/lims/experiment/add',
+        method: 'post',
+        data: data
+    })
+}
+
+// 淇敼瀹為獙
+export function updateExperiment(data) {
+    return request({
+        url: '/lims/experiment/update',
+        method: 'post',
+        data: data
+    })
+}
+
+// 鍒犻櫎瀹為獙
+export function delExperiment(ids) {
+    return request({
+        url: '/lims/experiment/delete',
+        method: 'delete',
+        data: ids
+    })
+}
diff --git a/src/api/lims/realtimeMonitor.js b/src/api/lims/realtimeMonitor.js
new file mode 100644
index 0000000..303fb68
--- /dev/null
+++ b/src/api/lims/realtimeMonitor.js
@@ -0,0 +1,46 @@
+// 瀹炴椂鐩戞帶涓庨璀﹂〉闈㈡帴鍙�
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ鐩戞帶鏁版嵁
+export function listRealtimeMonitor(query) {
+    return request({
+        url: '/lims/realtimeMonitor/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鏌ヨ鐩戞帶鏁版嵁璇︾粏
+export function getRealtimeMonitor(id) {
+    return request({
+        url: '/lims/realtimeMonitor/' + id,
+        method: 'get'
+    })
+}
+
+// 鏂板鐩戞帶鏁版嵁
+export function addRealtimeMonitor(data) {
+    return request({
+        url: '/lims/realtimeMonitor/add',
+        method: 'post',
+        data: data
+    })
+}
+
+// 淇敼鐩戞帶鏁版嵁
+export function updateRealtimeMonitor(data) {
+    return request({
+        url: '/lims/realtimeMonitor/update',
+        method: 'post',
+        data: data
+    })
+}
+
+// 鍒犻櫎鐩戞帶鏁版嵁
+export function delRealtimeMonitor(ids) {
+    return request({
+        url: '/lims/realtimeMonitor/delete',
+        method: 'delete',
+        data: ids
+    })
+}
diff --git a/src/api/lims/sample.js b/src/api/lims/sample.js
new file mode 100644
index 0000000..2a221c4
--- /dev/null
+++ b/src/api/lims/sample.js
@@ -0,0 +1,46 @@
+// 鏍峰搧绠$悊椤甸潰鎺ュ彛
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ鏍峰搧
+export function listSample(query) {
+    return request({
+        url: '/lims/sample/listPage',
+        method: 'get',
+        params: query
+    })
+}
+
+// 鏌ヨ鏍峰搧璇︾粏
+export function getSample(id) {
+    return request({
+        url: '/lims/sample/' + id,
+        method: 'get'
+    })
+}
+
+// 鏂板鏍峰搧
+export function addSample(data) {
+    return request({
+        url: '/lims/sample/add',
+        method: 'post',
+        data: data
+    })
+}
+
+// 淇敼鏍峰搧
+export function updateSample(data) {
+    return request({
+        url: '/lims/sample/update',
+        method: 'post',
+        data: data
+    })
+}
+
+// 鍒犻櫎鏍峰搧
+export function delSample(ids) {
+    return request({
+        url: '/lims/sample/delete',
+        method: 'delete',
+        data: ids
+    })
+}
diff --git a/src/views/lims/dataCollection/index.vue b/src/views/lims/dataCollection/index.vue
new file mode 100644
index 0000000..02e8a5e
--- /dev/null
+++ b/src/views/lims/dataCollection/index.vue
@@ -0,0 +1,561 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">閲囬泦缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.collectionCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+          :prefix-icon="Search"
+        />
+        <span class="search_title" style="margin-left: 20px">璁惧鍚嶇О锛�</span>
+        <el-input
+          v-model="searchForm.deviceName"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+        />
+        <span class="search_title" style="margin-left: 20px">閲囬泦鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.collectionStatus"
+          style="width: 150px"
+          placeholder="璇烽�夋嫨"
+          clearable
+          @change="handleQuery"
+        >
+          <el-option label="閲囬泦涓�" value="collecting" />
+          <el-option label="澶勭悊涓�" value="processing" />
+          <el-option label="宸插畬鎴�" value="completed" />
+          <el-option label="澶辫触" value="failed" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板閲囬泦</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <el-dialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板鏁版嵁閲囬泦' : '缂栬緫鏁版嵁閲囬泦'"
+      width="70%"
+      @close="closeDia"
+    >
+      <el-form
+        :model="form"
+        label-width="140px"
+        label-position="top"
+        :rules="rules"
+        ref="formRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閲囬泦缂栧彿锛�" prop="collectionCode">
+              <el-input
+                v-model="form.collectionCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁惧鍚嶇О锛�" prop="deviceName">
+              <el-input
+                v-model="form.deviceName"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="璁惧缂栧彿锛�" prop="deviceCode">
+              <el-input
+                v-model="form.deviceCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏁版嵁绫诲瀷锛�" prop="dataType">
+              <el-select
+                v-model="form.dataType"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="娓╁害" value="temperature" />
+                <el-option label="婀垮害" value="humidity" />
+                <el-option label="鍘嬪姏" value="pressure" />
+                <el-option label="娴侀噺" value="flow" />
+                <el-option label="娴撳害" value="concentration" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閲囬泦鏁板�硷細" prop="collectionValue">
+              <el-input
+                v-model="form.collectionValue"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁¢噺鍗曚綅锛�" prop="unit">
+              <el-select
+                v-model="form.unit"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鎽勬皬搴�(掳C)" value="celsius" />
+                <el-option label="鐧惧垎姣�(%)" value="percent" />
+                <el-option label="甯曟柉鍗�(Pa)" value="pa" />
+                <el-option label="鍗�/鍒嗛挓(L/min)" value="lmin" />
+                <el-option label="姣厠/鍗�(mg/L)" value="mgl" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="閲囬泦鏃堕棿锛�" prop="collectionTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.collectionTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm:ss"
+                type="datetime"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閲囬泦鐘舵�侊細" prop="collectionStatus">
+              <el-select
+                v-model="form.collectionStatus"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="閲囬泦涓�" value="collecting" />
+                <el-option label="澶勭悊涓�" value="processing" />
+                <el-option label="宸插畬鎴�" value="completed" />
+                <el-option label="澶辫触" value="failed" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏁版嵁璐ㄩ噺锛�" prop="dataQuality">
+              <el-select
+                v-model="form.dataQuality"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鍚堟牸" value="qualified" />
+                <el-option label="寮傚父" value="abnormal" />
+                <el-option label="寰呮牎楠�" value="pending" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="澶勭悊鏂瑰紡锛�" prop="processMethod">
+              <el-select
+                v-model="form.processMethod"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鑷姩娓呮礂" value="autoClean" />
+                <el-option label="浜哄伐鏍¢獙" value="manualVerify" />
+                <el-option label="鏁版嵁杞崲" value="dataTransform" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="鍘熷鏁版嵁锛�" prop="rawData">
+              <el-input
+                v-model="form.rawData"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶勭悊鍚庢暟鎹細" prop="processedData">
+              <el-input
+                v-model="form.processedData"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input
+                v-model="form.remark"
+                type="textarea"
+                :rows="2"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細" prop="maintainer">
+              <el-select
+                v-model="form.maintainer"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.nickName"
+                  :label="item.nickName"
+                  :value="item.nickName"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.maintenanceTime"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              />
+            </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="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addDataCollection,
+  delDataCollection,
+  getDataCollection,
+  listDataCollection,
+  updateDataCollection,
+} from "@/api/lims/dataCollection.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+  {
+    label: "閲囬泦缂栧彿",
+    prop: "collectionCode",
+    width: 150,
+  },
+  {
+    label: "璁惧鍚嶇О",
+    prop: "deviceName",
+    width: 180,
+  },
+  {
+    label: "璁惧缂栧彿",
+    prop: "deviceCode",
+    width: 150,
+  },
+  {
+    label: "鏁版嵁绫诲瀷",
+    prop: "dataType",
+    width: 120,
+  },
+  {
+    label: "閲囬泦鏁板��",
+    prop: "collectionValue",
+    width: 120,
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
+    width: 80,
+  },
+  {
+    label: "閲囬泦鏃堕棿",
+    prop: "collectionTime",
+    width: 180,
+  },
+  {
+    label: "閲囬泦鐘舵��",
+    prop: "collectionStatus",
+    width: 100,
+  },
+  {
+    label: "鏁版嵁璐ㄩ噺",
+    prop: "dataQuality",
+    width: 100,
+  },
+  {
+    label: "澶勭悊鏂瑰紡",
+    prop: "processMethod",
+    width: 120,
+  },
+  {
+    label: "缁存姢浜�",
+    prop: "maintainer",
+  },
+  {
+    label: "缁存姢鏃堕棿",
+    prop: "maintenanceTime",
+    width: 100,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.maintainer !== userStore.nickName
+        }
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    collectionCode: "",
+    deviceName: "",
+    collectionStatus: "",
+  },
+  form: {
+    collectionCode: "",
+    deviceName: "",
+    deviceCode: "",
+    dataType: "",
+    collectionValue: "",
+    unit: "",
+    collectionTime: "",
+    collectionStatus: "collecting",
+    dataQuality: "",
+    processMethod: "",
+    rawData: "",
+    processedData: "",
+    remark: "",
+    maintainer: "",
+    maintenanceTime: "",
+  },
+  rules: {
+    collectionCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    deviceName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    deviceCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    dataType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    collectionValue: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    unit: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    collectionTime: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    collectionStatus: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    dataQuality: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    processMethod: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+    maintenanceTime: [
+      { required: false, message: "璇烽�夋嫨", trigger: "change" },
+    ],
+  },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  listDataCollection({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
+};
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+const openForm = (type, row) => {
+  operationType.value = type;
+  form.value = {};
+  form.value.maintainer = userStore.nickName;
+  form.value.collectionStatus = "collecting";
+  form.value.maintenanceTime = getCurrentDate();
+  userListNoPage().then((res) => {
+    userList.value = res.data;
+  });
+  if (type === "edit") {
+    getDataCollection(row.id).then((res) => {
+      form.value = { ...res.data };
+    });
+  }
+  dialogFormVisible.value = true;
+};
+const submitForm = () => {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitEdit();
+      } else {
+        submitAdd();
+      }
+    }
+  });
+};
+const submitAdd = () => {
+  addDataCollection(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+const submitEdit = () => {
+  updateDataCollection(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/lims/dataCollection/export", {}, "鏁版嵁閲囬泦涓庡鐞�.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delDataCollection(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0");
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss"></style>
diff --git a/src/views/lims/dataInterfaceManagement/index.vue b/src/views/lims/dataInterfaceManagement/index.vue
new file mode 100644
index 0000000..803310e
--- /dev/null
+++ b/src/views/lims/dataInterfaceManagement/index.vue
@@ -0,0 +1,479 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">鎺ュ彛鍚嶇О锛�</span>
+        <el-input
+          v-model="searchForm.interfaceName"
+          style="width: 240px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+          :prefix-icon="Search"
+        />
+        <span class="search_title" style="margin-left: 20px">璁惧绫诲瀷锛�</span>
+        <el-select
+          v-model="searchForm.deviceType"
+          style="width: 200px"
+          placeholder="璇烽�夋嫨"
+          clearable
+          @change="handleQuery"
+        >
+          <el-option label="浠櫒浠〃" value="instrument" />
+          <el-option label="杞欢绯荤粺" value="software" />
+          <el-option label="浼犳劅鍣�" value="sensor" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板鎺ュ彛</el-button>
+        <!-- <el-button @click="handleOut">瀵煎嚭</el-button> -->
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <el-dialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板鏁版嵁鎺ュ彛' : '缂栬緫鏁版嵁鎺ュ彛'"
+      width="70%"
+      @close="closeDia"
+    >
+      <el-form
+        :model="form"
+        label-width="140px"
+        label-position="top"
+        :rules="rules"
+        ref="formRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鎺ュ彛鍚嶇О锛�" prop="interfaceName">
+              <el-input
+                v-model="form.interfaceName"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎺ュ彛缂栫爜锛�" prop="interfaceCode">
+              <el-input
+                v-model="form.interfaceCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="璁惧绫诲瀷锛�" prop="deviceType">
+              <el-select
+                v-model="form.deviceType"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="浠櫒浠〃" value="instrument" />
+                <el-option label="杞欢绯荤粺" value="software" />
+                <el-option label="浼犳劅鍣�" value="sensor" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁惧鍚嶇О锛�" prop="deviceName">
+              <el-input
+                v-model="form.deviceName"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="杩炴帴鍗忚锛�" prop="protocol">
+              <el-select
+                v-model="form.protocol"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="HTTP" value="http" />
+                <el-option label="TCP" value="tcp" />
+                <el-option label="MQTT" value="mqtt" />
+                <el-option label="Modbus" value="modbus" />
+                <el-option label="OPC UA" value="opcua" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="杩炴帴鍦板潃锛�" prop="connectionUrl">
+              <el-input
+                v-model="form.connectionUrl"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="绔彛鍙凤細" prop="port">
+              <el-input
+                v-model="form.port"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎺ュ彛鐘舵�侊細" prop="status">
+              <el-radio-group v-model="form.status">
+                <el-radio label="1">鍚敤</el-radio>
+                <el-radio label="0">绂佺敤</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="鎺ュ彛鎻忚堪锛�" prop="description">
+              <el-input
+                v-model="form.description"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細" prop="maintainer">
+              <el-select
+                v-model="form.maintainer"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.nickName"
+                  :label="item.nickName"
+                  :value="item.nickName"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.maintenanceTime"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              />
+            </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="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addDataInterface,
+  delDataInterface,
+  getDataInterface,
+  listDataInterface,
+  updateDataInterface,
+} from "@/api/lims/dataInterface.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+  {
+    label: "鎺ュ彛鍚嶇О",
+    prop: "interfaceName",
+    width: 200,
+  },
+  {
+    label: "鎺ュ彛缂栫爜",
+    prop: "interfaceCode",
+    width: 150,
+  },
+  {
+    label: "璁惧绫诲瀷",
+    prop: "deviceType",
+    width: 120,
+  },
+  {
+    label: "璁惧鍚嶇О",
+    prop: "deviceName",
+    width: 180,
+  },
+  {
+    label: "杩炴帴鍗忚",
+    prop: "protocol",
+    width: 120,
+  },
+  {
+    label: "杩炴帴鍦板潃",
+    prop: "connectionUrl",
+    width: 220,
+  },
+  {
+    label: "绔彛鍙�",
+    prop: "port",
+    width: 100,
+  },
+  {
+    label: "鎺ュ彛鐘舵��",
+    prop: "status",
+    width: 100,
+  },
+  {
+    label: "缁存姢浜�",
+    prop: "maintainer",
+  },
+  {
+    label: "缁存姢鏃堕棿",
+    prop: "maintenanceTime",
+    width: 100,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.maintainer !== userStore.nickName
+        }
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+// 鏁版嵁鎺ュ彛琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    interfaceName: "",
+    deviceType: "",
+  },
+  form: {
+    interfaceName: "",
+    interfaceCode: "",
+    deviceType: "",
+    deviceName: "",
+    protocol: "",
+    connectionUrl: "",
+    port: "",
+    status: "1",
+    description: "",
+    maintainer: "",
+    maintenanceTime: "",
+  },
+  rules: {
+    interfaceName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    interfaceCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    deviceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    deviceName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    protocol: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    connectionUrl: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    port: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    status: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+    maintenanceTime: [
+      { required: false, message: "璇烽�夋嫨", trigger: "change" },
+    ],
+  },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  listDataInterface({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+  operationType.value = type;
+  form.value = {};
+  form.value.maintainer = userStore.nickName;
+  form.value.status = "1";
+  form.value.maintenanceTime = getCurrentDate();
+  userListNoPage().then((res) => {
+    userList.value = res.data;
+  });
+  if (type === "edit") {
+    getDataInterface(row.id).then((res) => {
+      form.value = { ...res.data };
+    });
+  }
+  dialogFormVisible.value = true;
+};
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitEdit();
+      } else {
+        submitAdd();
+      }
+    }
+  });
+};
+// 鎻愪氦鏂板
+const submitAdd = () => {
+  addDataInterface(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鎻愪氦淇敼
+const submitEdit = () => {
+  updateDataInterface(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/lims/dataInterface/export", {}, "鏁版嵁鎺ュ彛绠$悊.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+    const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delDataInterface(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0");
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss"></style>
diff --git a/src/views/lims/experimentManagement/index.vue b/src/views/lims/experimentManagement/index.vue
new file mode 100644
index 0000000..01d743b
--- /dev/null
+++ b/src/views/lims/experimentManagement/index.vue
@@ -0,0 +1,526 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">瀹為獙缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.experimentCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+          :prefix-icon="Search"
+        />
+        <span class="search_title" style="margin-left: 20px">瀹為獙鍚嶇О锛�</span>
+        <el-input
+          v-model="searchForm.experimentName"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+        />
+        <span class="search_title" style="margin-left: 20px">瀹為獙鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.experimentStatus"
+          style="width: 150px"
+          placeholder="璇烽�夋嫨"
+          clearable
+          @change="handleQuery"
+        >
+          <el-option label="璁″垝涓�" value="planned" />
+          <el-option label="杩涜涓�" value="inProgress" />
+          <el-option label="宸插畬鎴�" value="completed" />
+          <el-option label="宸插彇娑�" value="cancelled" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板瀹為獙</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <el-dialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板瀹為獙' : '缂栬緫瀹為獙'"
+      width="70%"
+      @close="closeDia"
+    >
+      <el-form
+        :model="form"
+        label-width="140px"
+        label-position="top"
+        :rules="rules"
+        ref="formRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="瀹為獙缂栧彿锛�" prop="experimentCode">
+              <el-input
+                v-model="form.experimentCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀹為獙鍚嶇О锛�" prop="experimentName">
+              <el-input
+                v-model="form.experimentName"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="瀹為獙绫诲瀷锛�" prop="experimentType">
+              <el-select
+                v-model="form.experimentType"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鍖栧鍒嗘瀽" value="chemicalAnalysis" />
+                <el-option label="鐗╃悊娴嬭瘯" value="physicalTest" />
+                <el-option label="寰敓鐗╂娴�" value="microbialTest" />
+                <el-option label="鎬ц兘娴嬭瘯" value="performanceTest" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀹為獙鏍囧噯锛�" prop="experimentStandard">
+              <el-input
+                v-model="form.experimentStandard"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="璁″垝寮�濮嬫棩鏈燂細" prop="planStartDate">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.planStartDate"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁″垝缁撴潫鏃ユ湡锛�" prop="planEndDate">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.planEndDate"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="瀹為獙璐熻矗浜猴細" prop="responsiblePerson">
+              <el-input
+                v-model="form.responsiblePerson"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀹為獙鐘舵�侊細" prop="experimentStatus">
+              <el-select
+                v-model="form.experimentStatus"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="璁″垝涓�" value="planned" />
+                <el-option label="杩涜涓�" value="inProgress" />
+                <el-option label="宸插畬鎴�" value="completed" />
+                <el-option label="宸插彇娑�" value="cancelled" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="瀹為獙鐩殑锛�" prop="experimentPurpose">
+              <el-input
+                v-model="form.experimentPurpose"
+                type="textarea"
+                :rows="2"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="瀹為獙杩囩▼锛�" prop="experimentProcess">
+              <el-input
+                v-model="form.experimentProcess"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="瀹為獙缁撴灉锛�" prop="experimentResult">
+              <el-input
+                v-model="form.experimentResult"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細" prop="maintainer">
+              <el-select
+                v-model="form.maintainer"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.nickName"
+                  :label="item.nickName"
+                  :value="item.nickName"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.maintenanceTime"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              />
+            </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="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addExperiment,
+  delExperiment,
+  getExperiment,
+  listExperiment,
+  updateExperiment,
+} from "@/api/lims/experiment.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+  {
+    label: "瀹為獙缂栧彿",
+    prop: "experimentCode",
+    width: 150,
+  },
+  {
+    label: "瀹為獙鍚嶇О",
+    prop: "experimentName",
+    width: 180,
+  },
+  {
+    label: "瀹為獙绫诲瀷",
+    prop: "experimentType",
+    width: 120,
+  },
+  {
+    label: "瀹為獙鏍囧噯",
+    prop: "experimentStandard",
+    width: 150,
+  },
+  {
+    label: "璁″垝寮�濮嬫棩鏈�",
+    prop: "planStartDate",
+    width: 120,
+  },
+  {
+    label: "璁″垝缁撴潫鏃ユ湡",
+    prop: "planEndDate",
+    width: 120,
+  },
+  {
+    label: "瀹為獙璐熻矗浜�",
+    prop: "responsiblePerson",
+    width: 120,
+  },
+  {
+    label: "瀹為獙鐘舵��",
+    prop: "experimentStatus",
+    width: 100,
+  },
+  {
+    label: "缁存姢浜�",
+    prop: "maintainer",
+  },
+  {
+    label: "缁存姢鏃堕棿",
+    prop: "maintenanceTime",
+    width: 100,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.maintainer !== userStore.nickName
+        }
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+// 瀹為獙琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    experimentCode: "",
+    experimentName: "",
+    experimentStatus: "",
+  },
+  form: {
+    experimentCode: "",
+    experimentName: "",
+    experimentType: "",
+    experimentStandard: "",
+    planStartDate: "",
+    planEndDate: "",
+    responsiblePerson: "",
+    experimentStatus: "planned",
+    experimentPurpose: "",
+    experimentProcess: "",
+    experimentResult: "",
+    maintainer: "",
+    maintenanceTime: "",
+  },
+  rules: {
+    experimentCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    experimentName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    experimentType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    experimentStandard: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    planStartDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    planEndDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    responsiblePerson: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    experimentStatus: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+    maintenanceTime: [
+      { required: false, message: "璇烽�夋嫨", trigger: "change" },
+    ],
+  },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  listExperiment({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+  operationType.value = type;
+  form.value = {};
+  form.value.maintainer = userStore.nickName;
+  form.value.experimentStatus = "planned";
+  form.value.maintenanceTime = getCurrentDate();
+  userListNoPage().then((res) => {
+    userList.value = res.data;
+  });
+  if (type === "edit") {
+    getExperiment(row.id).then((res) => {
+      form.value = { ...res.data };
+    });
+  }
+  dialogFormVisible.value = true;
+};
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitEdit();
+      } else {
+        submitAdd();
+      }
+    }
+  });
+};
+// 鎻愪氦鏂板
+const submitAdd = () => {
+  addExperiment(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鎻愪氦淇敼
+const submitEdit = () => {
+  updateExperiment(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/lims/experiment/export", {}, "瀹為獙绠$悊.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+    const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delExperiment(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0");
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss"></style>
diff --git a/src/views/lims/realtimeMonitor/index.vue b/src/views/lims/realtimeMonitor/index.vue
new file mode 100644
index 0000000..658db2c
--- /dev/null
+++ b/src/views/lims/realtimeMonitor/index.vue
@@ -0,0 +1,582 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">鐩戞帶缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.monitorCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+          :prefix-icon="Search"
+        />
+        <span class="search_title" style="margin-left: 20px">鐩戞帶瀵硅薄锛�</span>
+        <el-input
+          v-model="searchForm.monitorTarget"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+        />
+        <span class="search_title" style="margin-left: 20px">棰勮鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.alertStatus"
+          style="width: 150px"
+          placeholder="璇烽�夋嫨"
+          clearable
+          @change="handleQuery"
+        >
+          <el-option label="姝e父" value="normal" />
+          <el-option label="棰勮" value="warning" />
+          <el-option label="鍛婅" value="alert" />
+          <el-option label="宸插鐞�" value="resolved" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板鐩戞帶</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <el-dialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板瀹炴椂鐩戞帶' : '缂栬緫瀹炴椂鐩戞帶'"
+      width="70%"
+      @close="closeDia"
+    >
+      <el-form
+        :model="form"
+        label-width="140px"
+        label-position="top"
+        :rules="rules"
+        ref="formRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鐩戞帶缂栧彿锛�" prop="monitorCode">
+              <el-input
+                v-model="form.monitorCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐩戞帶瀵硅薄锛�" prop="monitorTarget">
+              <el-input
+                v-model="form.monitorTarget"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鐩戞帶绫诲瀷锛�" prop="monitorType">
+              <el-select
+                v-model="form.monitorType"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="娓╁害鐩戞帶" value="temperature" />
+                <el-option label="婀垮害鐩戞帶" value="humidity" />
+                <el-option label="鍘嬪姏鐩戞帶" value="pressure" />
+                <el-option label="璁惧鐘舵��" value="equipment" />
+                <el-option label="瀹為獙杩囩▼" value="experiment" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐩戞帶鎸囨爣锛�" prop="monitorIndicator">
+              <el-input
+                v-model="form.monitorIndicator"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="褰撳墠鏁板�硷細" prop="currentValue">
+              <el-input
+                v-model="form.currentValue"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁¢噺鍗曚綅锛�" prop="unit">
+              <el-select
+                v-model="form.unit"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鎽勬皬搴�(掳C)" value="celsius" />
+                <el-option label="鐧惧垎姣�(%)" value="percent" />
+                <el-option label="甯曟柉鍗�(Pa)" value="pa" />
+                <el-option label="杞�/鍒嗛挓(rpm)" value="rpm" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="涓婇檺闃堝�硷細" prop="upperLimit">
+              <el-input
+                v-model="form.upperLimit"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓嬮檺闃堝�硷細" prop="lowerLimit">
+              <el-input
+                v-model="form.lowerLimit"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="棰勮鐘舵�侊細" prop="alertStatus">
+              <el-select
+                v-model="form.alertStatus"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="姝e父" value="normal" />
+                <el-option label="棰勮" value="warning" />
+                <el-option label="鍛婅" value="alert" />
+                <el-option label="宸插鐞�" value="resolved" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="棰勮绾у埆锛�" prop="alertLevel">
+              <el-select
+                v-model="form.alertLevel"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="涓�鑸�" value="low" />
+                <el-option label="閲嶈" value="medium" />
+                <el-option label="绱ф��" value="high" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鐩戞帶鏃堕棿锛�" prop="monitorTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.monitorTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                format="YYYY-MM-DD HH:mm:ss"
+                type="datetime"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="澶勭悊浜猴細" prop="handler">
+              <el-input
+                v-model="form.handler"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="棰勮鎻忚堪锛�" prop="alertDescription">
+              <el-input
+                v-model="form.alertDescription"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶勭悊鎺柦锛�" prop="handleMeasure">
+              <el-input
+                v-model="form.handleMeasure"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input
+                v-model="form.remark"
+                type="textarea"
+                :rows="2"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細" prop="maintainer">
+              <el-select
+                v-model="form.maintainer"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.nickName"
+                  :label="item.nickName"
+                  :value="item.nickName"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.maintenanceTime"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              />
+            </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="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addRealtimeMonitor,
+  delRealtimeMonitor,
+  getRealtimeMonitor,
+  listRealtimeMonitor,
+  updateRealtimeMonitor,
+} from "@/api/lims/realtimeMonitor.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+  {
+    label: "鐩戞帶缂栧彿",
+    prop: "monitorCode",
+    width: 150,
+  },
+  {
+    label: "鐩戞帶瀵硅薄",
+    prop: "monitorTarget",
+    width: 180,
+  },
+  {
+    label: "鐩戞帶绫诲瀷",
+    prop: "monitorType",
+    width: 120,
+  },
+  {
+    label: "鐩戞帶鎸囨爣",
+    prop: "monitorIndicator",
+    width: 150,
+  },
+  {
+    label: "褰撳墠鏁板��",
+    prop: "currentValue",
+    width: 100,
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
+    width: 80,
+  },
+  {
+    label: "涓婇檺闃堝��",
+    prop: "upperLimit",
+    width: 100,
+  },
+  {
+    label: "涓嬮檺闃堝��",
+    prop: "lowerLimit",
+    width: 100,
+  },
+  {
+    label: "棰勮鐘舵��",
+    prop: "alertStatus",
+    width: 100,
+  },
+  {
+    label: "棰勮绾у埆",
+    prop: "alertLevel",
+    width: 100,
+  },
+  {
+    label: "鐩戞帶鏃堕棿",
+    prop: "monitorTime",
+    width: 180,
+  },
+  {
+    label: "缁存姢浜�",
+    prop: "maintainer",
+  },
+  {
+    label: "缁存姢鏃堕棿",
+    prop: "maintenanceTime",
+    width: 100,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.maintainer !== userStore.nickName
+        }
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    monitorCode: "",
+    monitorTarget: "",
+    alertStatus: "",
+  },
+  form: {
+    monitorCode: "",
+    monitorTarget: "",
+    monitorType: "",
+    monitorIndicator: "",
+    currentValue: "",
+    unit: "",
+    upperLimit: "",
+    lowerLimit: "",
+    alertStatus: "normal",
+    alertLevel: "",
+    monitorTime: "",
+    alertDescription: "",
+    handler: "",
+    handleMeasure: "",
+    remark: "",
+    maintainer: "",
+    maintenanceTime: "",
+  },
+  rules: {
+    monitorCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    monitorTarget: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    monitorType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    monitorIndicator: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    currentValue: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    unit: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    upperLimit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    lowerLimit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    alertStatus: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    monitorTime: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+    maintenanceTime: [
+      { required: false, message: "璇烽�夋嫨", trigger: "change" },
+    ],
+  },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  listRealtimeMonitor({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
+};
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+const openForm = (type, row) => {
+  operationType.value = type;
+  form.value = {};
+  form.value.maintainer = userStore.nickName;
+  form.value.alertStatus = "normal";
+  form.value.maintenanceTime = getCurrentDate();
+  userListNoPage().then((res) => {
+    userList.value = res.data;
+  });
+  if (type === "edit") {
+    getRealtimeMonitor(row.id).then((res) => {
+      form.value = { ...res.data };
+    });
+  }
+  dialogFormVisible.value = true;
+};
+const submitForm = () => {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitEdit();
+      } else {
+        submitAdd();
+      }
+    }
+  });
+};
+const submitAdd = () => {
+  addRealtimeMonitor(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+const submitEdit = () => {
+  updateRealtimeMonitor(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/lims/realtimeMonitor/export", {}, "瀹炴椂鐩戞帶涓庨璀�.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delRealtimeMonitor(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0");
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss"></style>
diff --git a/src/views/lims/sampleManagement/index.vue b/src/views/lims/sampleManagement/index.vue
new file mode 100644
index 0000000..8004754
--- /dev/null
+++ b/src/views/lims/sampleManagement/index.vue
@@ -0,0 +1,539 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title">鏍峰搧缂栧彿锛�</span>
+        <el-input
+          v-model="searchForm.sampleCode"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+          :prefix-icon="Search"
+        />
+        <span class="search_title" style="margin-left: 20px">鏍峰搧鍚嶇О锛�</span>
+        <el-input
+          v-model="searchForm.sampleName"
+          style="width: 200px"
+          placeholder="璇疯緭鍏�"
+          @change="handleQuery"
+          clearable
+        />
+        <span class="search_title" style="margin-left: 20px">鏍峰搧鐘舵�侊細</span>
+        <el-select
+          v-model="searchForm.sampleStatus"
+          style="width: 150px"
+          placeholder="璇烽�夋嫨"
+          clearable
+          @change="handleQuery"
+        >
+          <el-option label="鍦ㄥ簱" value="inStock" />
+          <el-option label="鍑哄簱" value="outStock" />
+          <el-option label="妫�娴嬩腑" value="testing" />
+          <el-option label="宸查攢姣�" value="destroyed" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
+          >鎼滅储</el-button
+        >
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板鏍峰搧</el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+      ></PIMTable>
+    </div>
+    <el-dialog
+      v-model="dialogFormVisible"
+      :title="operationType === 'add' ? '鏂板鏍峰搧' : '缂栬緫鏍峰搧'"
+      width="70%"
+      @close="closeDia"
+    >
+      <el-form
+        :model="form"
+        label-width="140px"
+        label-position="top"
+        :rules="rules"
+        ref="formRef"
+      >
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧缂栧彿锛�" prop="sampleCode">
+              <el-input
+                v-model="form.sampleCode"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧鍚嶇О锛�" prop="sampleName">
+              <el-input
+                v-model="form.sampleName"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧绫诲瀷锛�" prop="sampleType">
+              <el-select
+                v-model="form.sampleType"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鍘熸枡" value="rawMaterial" />
+                <el-option label="鍗婃垚鍝�" value="semiFinished" />
+                <el-option label="鎴愬搧" value="finishedProduct" />
+                <el-option label="鐣欐牱" value="retainedSample" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧瑙勬牸锛�" prop="specification">
+              <el-input
+                v-model="form.specification"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鍏ュ簱鏃ユ湡锛�" prop="inStockDate">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.inStockDate"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瀛樺偍浣嶇疆锛�" prop="storageLocation">
+              <el-input
+                v-model="form.storageLocation"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧鏁伴噺锛�" prop="quantity">
+              <el-input
+                v-model="form.quantity"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璁¢噺鍗曚綅锛�" prop="unit">
+              <el-select
+                v-model="form.unit"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鍏�(g)" value="g" />
+                <el-option label="鍗冨厠(kg)" value="kg" />
+                <el-option label="姣崌(ml)" value="ml" />
+                <el-option label="鍗�(L)" value="L" />
+                <el-option label="涓�" value="piece" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="鏍峰搧鐘舵�侊細" prop="sampleStatus">
+              <el-select
+                v-model="form.sampleStatus"
+                placeholder="璇烽�夋嫨"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="鍦ㄥ簱" value="inStock" />
+                <el-option label="鍑哄簱" value="outStock" />
+                <el-option label="妫�娴嬩腑" value="testing" />
+                <el-option label="宸查攢姣�" value="destroyed" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏈夋晥鏈熻嚦锛�" prop="validityDate">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.validityDate"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="24">
+            <el-form-item label="澶囨敞锛�" prop="remark">
+              <el-input
+                v-model="form.remark"
+                type="textarea"
+                :rows="3"
+                placeholder="璇疯緭鍏�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="缁存姢浜猴細" prop="maintainer">
+              <el-select
+                v-model="form.maintainer"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.nickName"
+                  :label="item.nickName"
+                  :value="item.nickName"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+              <el-date-picker
+                style="width: 100%"
+                v-model="form.maintenanceTime"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                type="date"
+                placeholder="璇烽�夋嫨"
+                clearable
+                disabled
+              />
+            </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="closeDia">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import {
+  addSample,
+  delSample,
+  getSample,
+  listSample,
+  updateSample,
+} from "@/api/lims/sample.js";
+import { ElMessageBox } from "element-plus";
+import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user";
+const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
+
+const tableColumn = ref([
+  {
+    label: "鏍峰搧缂栧彿",
+    prop: "sampleCode",
+    width: 150,
+  },
+  {
+    label: "鏍峰搧鍚嶇О",
+    prop: "sampleName",
+    width: 180,
+  },
+  {
+    label: "鏍峰搧绫诲瀷",
+    prop: "sampleType",
+    width: 120,
+  },
+  {
+    label: "鏍峰搧瑙勬牸",
+    prop: "specification",
+    width: 150,
+  },
+  {
+    label: "鍏ュ簱鏃ユ湡",
+    prop: "inStockDate",
+    width: 120,
+  },
+  {
+    label: "瀛樺偍浣嶇疆",
+    prop: "storageLocation",
+    width: 150,
+  },
+  {
+    label: "鏁伴噺",
+    prop: "quantity",
+    width: 100,
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
+    width: 80,
+  },
+  {
+    label: "鏍峰搧鐘舵��",
+    prop: "sampleStatus",
+    width: 100,
+  },
+  {
+    label: "鏈夋晥鏈熻嚦",
+    prop: "validityDate",
+    width: 120,
+  },
+  {
+    label: "缁存姢浜�",
+    prop: "maintainer",
+  },
+  {
+    label: "缁存姢鏃堕棿",
+    prop: "maintenanceTime",
+    width: 100,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: 'right',
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        },
+        disabled: (row) => {
+          return row.maintainer !== userStore.nickName
+        }
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const selectedRows = ref([]);
+const userList = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+// 鏍峰搧琛ㄥ崟寮规鏁版嵁
+const operationType = ref("");
+const dialogFormVisible = ref(false);
+const data = reactive({
+  searchForm: {
+    sampleCode: "",
+    sampleName: "",
+    sampleStatus: "",
+  },
+  form: {
+    sampleCode: "",
+    sampleName: "",
+    sampleType: "",
+    specification: "",
+    inStockDate: "",
+    storageLocation: "",
+    quantity: "",
+    unit: "",
+    sampleStatus: "inStock",
+    validityDate: "",
+    remark: "",
+    maintainer: "",
+    maintenanceTime: "",
+  },
+  rules: {
+    sampleCode: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    sampleName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    sampleType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    specification: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    inStockDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    storageLocation: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+    unit: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    sampleStatus: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    validityDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+    maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+    maintenanceTime: [
+      { required: false, message: "璇烽�夋嫨", trigger: "change" },
+    ],
+  },
+});
+const { searchForm, form, rules } = toRefs(data);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  listSample({ ...searchForm.value, ...page }).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records;
+    page.total = res.data.total;
+  });
+};
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+  operationType.value = type;
+  form.value = {};
+  form.value.maintainer = userStore.nickName;
+  form.value.sampleStatus = "inStock";
+  form.value.maintenanceTime = getCurrentDate();
+  userListNoPage().then((res) => {
+    userList.value = res.data;
+  });
+  if (type === "edit") {
+    getSample(row.id).then((res) => {
+      form.value = { ...res.data };
+    });
+  }
+  dialogFormVisible.value = true;
+};
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  proxy.$refs["formRef"].validate((valid) => {
+    if (valid) {
+      if (operationType.value === "edit") {
+        submitEdit();
+      } else {
+        submitAdd();
+      }
+    }
+  });
+};
+// 鎻愪氦鏂板
+const submitAdd = () => {
+  addSample(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鎻愪氦淇敼
+const submitEdit = () => {
+  updateSample(form.value).then((res) => {
+    proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+    closeDia();
+    getList();
+  });
+};
+// 鍏抽棴寮规
+const closeDia = () => {
+  proxy.resetForm("formRef");
+  dialogFormVisible.value = false;
+};
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      proxy.download("/lims/sample/export", {}, "鏍峰搧绠$悊.xlsx");
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+// 鍒犻櫎
+const handleDelete = () => {
+  let ids = [];
+  if (selectedRows.value.length > 0) {
+    // 妫�鏌ユ槸鍚︽湁浠栦汉缁存姢鐨勬暟鎹�
+    const unauthorizedData = selectedRows.value.filter(item => item.maintainer !== userStore.nickName);
+    if (unauthorizedData.length > 0) {
+      proxy.$modal.msgWarning("涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�");
+      return;
+    }
+    ids = selectedRows.value.map((item) => item.id);
+  } else {
+    proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+    return;
+  }
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+    .then(() => {
+      tableLoading.value = true;
+      delSample(ids)
+        .then((res) => {
+          proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+          getList();
+        })
+        .finally(() => {
+          tableLoading.value = false;
+        });
+    })
+    .catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+};
+
+// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+function getCurrentDate() {
+  const today = new Date();
+  const year = today.getFullYear();
+  const month = String(today.getMonth() + 1).padStart(2, "0");
+  const day = String(today.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss"></style>

--
Gitblit v1.9.3