啊鑫
3 天以前 52c82b4f021814fc1cbe49b70871757a9001458a
添加实验室检测模块功能

- 新增Laboratory模块List页面和详情页面
- 实现分页查询实验室检测数据
- 支持检验结果录入(合格/不合格)
- 添加API文档和页面路由配置
- 支持点击跳转和数据刷新功能
已添加3个文件
已修改1个文件
1232 ■■■■■ 文件已修改
MES_Laboratory_API_Documentation.md 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/Laboratory/Laboratory.vue 438 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/QC/Laboratory/List.vue 663 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MES_Laboratory_API_Documentation.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
# MES实验室检测数据API接口文档
## 1. ä¿å­˜å®žéªŒå®¤æ£€æµ‹æ•°æ®
**请求地址:** `POST /api/MesLaboratory/saveLaboratory`
**请求参数:**
```json
{
  "createUser": "string",  // åˆ›å»ºäºº
  "orderNo": "string"      // å·¥å•号
}
```
**返回数据:**
```json
{
  "status": 0,
  "message": "OK",
  "data": {
    "result": true  // æ“ä½œæ˜¯å¦æˆåŠŸ
  }
}
```
---
## 2. åˆ†é¡µæŸ¥è¯¢å®žéªŒå®¤æ£€æµ‹æ•°æ®
**请求地址:** `POST /api/MesLaboratory/GetPage`
**请求参数:**
```json
{
  "pageIndex": 1,     // é¡µç 
  "limit": 10,        // æ¯é¡µè®°å½•æ•°
  "id": "string"      // è®°å½•ID(可选)
}
```
**返回数据:**
```json
{
  "status": 0,
  "message": "OK",
  "data": {
    "tbBillList": [
      {
        "billNo": "string",           // å·¥å•号
        "lineNo": "string",           // ç”Ÿäº§çº¿ä½“编码
        "itemId": 1001,               // ç‰©æ–™ID
        "itemNo": "string",           // ç‰©æ–™ç¼–码
        "itemName": "string",         // ç‰©æ–™åç§°
        "itemModel": "string",        // ç‰©æ–™è§„æ ¼
        "departmentId": 1,            // ç”Ÿäº§è½¦é—´ID
        "departmentCode": "string",   // ç”Ÿäº§è½¦é—´ç¼–码
        "saleOrderNoc": "string",     // é”€å”®è®¢å•号
        "inspectionResult": "string", // æ£€éªŒç»“æžœ
        "createTime": "2024-01-01 12:00:00",  // åˆ›å»ºæ—¶é—´
        "createUser": "string",         // åˆ›å»ºäºº
        "inspectionTime": "2024-01-01 12:00:00",  // æ£€éªŒæ—¶é—´
        "inspectionUser": "string"      // æ£€éªŒäºº
      }
    ],
    "totalCount": 100  // æ€»è®°å½•æ•°
  }
}
```
---
## 3. å½•入检验结果
**请求地址:** `POST /api/MesLaboratory/UpdateInspectionResult`
**请求参数:**
```json
{
  "id": 1,                        // è®°å½•ID(必填)
  "inspectionResult": "string",   // æ£€éªŒç»“果(可选)
  "inspectionBy": "string"        // æ£€éªŒäººï¼ˆå¯é€‰ï¼‰
}
```
**返回数据:**
```json
{
  "status": 0,
  "message": "OK",
  "data": {
    "result": true  // æ“ä½œæ˜¯å¦æˆåŠŸ
  }
}
```
---
## é€šç”¨è¯´æ˜Ž
### å“åº”状态码
- `status: 0` - æ“ä½œæˆåŠŸ
- `status: 1` - æ“ä½œå¤±è´¥
### é”™è¯¯å“åº”格式
```json
{
  "status": 1,
  "message": "错误信息",
  "data": null
}
```
### æ³¨æ„äº‹é¡¹
1. æ‰€æœ‰æŽ¥å£å‡ä½¿ç”¨POST方法
2. è¯·æ±‚头需设置 `Content-Type: application/json`
3. æ—¥æœŸæ—¶é—´æ ¼å¼ä¸º `yyyy-MM-dd HH:mm:ss`
4. UpdateInspectionResult接口会自动设置检验时间为当前时间
pages.json
@@ -420,6 +420,20 @@
            {
                "navigationBarTitleText" : "检验详情"
            }
        },
        {
            "path" : "pages/QC/Laboratory/Laboratory",
            "style" :
            {
                "navigationBarTitleText" : "实验室送检"
            }
        },
        {
            "path" : "pages/QC/Laboratory/List",
            "style" :
            {
                "navigationBarTitleText" : "实验室送检"
            }
        }
        // {
        //     "path": "pages/Device/Spotcheck",
pages/QC/Laboratory/Laboratory.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,438 @@
<template>
  <view class="container">
    <!-- é¡µé¢æ ‡é¢˜ -->
    <view class="page-header">
      <view class="header-title">实验室检测详情</view>
    </view>
    <!-- åŠ è½½çŠ¶æ€ -->
    <view v-if="loading" class="loading-container">
      <uni-load-more status="loading" />
    </view>
    <!-- æ•°æ®å±•示 -->
    <view v-else-if="data" class="content">
      <view class="card">
        <view class="card-header">
          <view class="header-info">
            <view class="info-item">
              <label class="info-label">工单号:</label>
              <text class="info-value">{{ data.billNo }}</text>
            </view>
          </view>
        </view>
        <view class="card-body">
          <view class="info-group">
            <view class="info-row">
              <view class="info-item">
                <label class="info-label">创建时间:</label>
                <text class="info-value">{{ data.createTime }}</text>
              </view>
              <view class="info-item">
                <label class="info-label">创建人:</label>
                <text class="info-value">{{ data.createUser }}</text>
              </view>
            </view>
            <view class="info-row">
              <view class="info-item">
                <label class="info-label">生产线编码:</label>
                <text class="info-value">{{ data.lineNo }}</text>
              </view>
              <view class="info-item">
                <label class="info-label">物料编码:</label>
                <text class="info-value">{{ data.itemNo }}</text>
              </view>
            </view>
            <view class="info-row full-width">
              <view class="info-item">
                <label class="info-label">物料名称:</label>
                <text class="info-value">{{ data.itemName }}</text>
              </view>
            </view>
            <view class="info-row full-width">
              <view class="info-item">
                <label class="info-label">物料规格:</label>
                <text class="info-value">{{ data.itemModel }}</text>
              </view>
            </view>
            <view class="info-row">
              <view class="info-item">
                <label class="info-label">生产车间编码:</label>
                <text class="info-value">{{ data.departmentCode }}</text>
              </view>
              <view class="info-item">
                <label class="info-label">生产车间ID:</label>
                <text class="info-value">{{ data.departmentId }}</text>
              </view>
            </view>
            <view class="info-row full-width">
              <view class="info-item">
                <label class="info-label">销售订单号:</label>
                <text class="info-value">{{ data.saleOrderNoc }}</text>
              </view>
            </view>
            <view class="info-row">
              <view class="info-item">
                <label class="info-label">检验时间:</label>
                <text class="info-value">{{ data.inspectionTime }}</text>
              </view>
              <view class="info-item">
                <label class="info-label">检验人:</label>
                <text class="info-value">{{ data.inspectionUser }}</text>
              </view>
            </view>
            <view class="info-row">
              <view class="info-item status-item">
                <label class="info-label">检验结果:</label>
                <view class="result-container">
                  <!-- æ˜¾ç¤ºå½“前检验结果 -->
                  <text v-if="data.inspectionResult" class="status-badge" :class="data.inspectionResult === '合格' ? 'success' : 'danger'">
                    {{ data.inspectionResult }}
                  </text>
                  <text v-else class="status-badge pending">
                    å¾…检验
                  </text>
                  <!-- å½•å…¥/重新录入按钮 -->
                  <button v-if="!showResultInput" class="input-btn" @click="showResultInput = true">
                    {{ data.inspectionResult ? '重新录入' : '录入结果' }}
                  </button>
                  <!-- æ£€éªŒç»“果选择按钮 -->
                  <view v-if="showResultInput" class="result-input-container">
                    <button class="result-btn qualified" @click="updateInspectionResult('合格')" :disabled="updating">
                      åˆæ ¼
                    </button>
                    <button class="result-btn unqualified" @click="updateInspectionResult('不合格')" :disabled="updating">
                      ä¸åˆæ ¼
                    </button>
                    <button class="result-btn cancel" @click="showResultInput = false" :disabled="updating">
                      å–消
                    </button>
                  </view>
                </view>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
    <!-- ç©ºçŠ¶æ€ -->
    <view v-else class="empty-state">
      <view class="empty-icon">📋</view>
      <view class="empty-text">暂无数据</view>
    </view>
  </view>
</template>
<script>
export default {
  data() {
    return {
      data: null,
      loading: false,
      itemId: null,
      showResultInput: false,
      updating: false
    }
  },
  onLoad(options) {
    this.itemId = options.id;
    if (this.itemId) {
      this.loadData();
    }
  },
  methods: {
    loadData() {
      this.loading = true;
      const requestData = {
        pageIndex: 1,
        limit: 1,
        id: this.itemId
      };
      this.$post({
        url: "/MesLaboratory/GetPage",
        data: requestData
      }).then(res => {
        if (res.data && res.data.tbBillList && res.data.tbBillList.length > 0) {
          this.data = res.data.tbBillList[0];
        } else {
          this.data = null;
          this.$showMessage('未找到相关数据');
        }
      }).catch(err => {
        console.error('获取实验室详情失败:', err);
        this.$showMessage('获取数据失败,请重试');
      }).finally(() => {
        this.loading = false;
      });
    },
    updateInspectionResult(result) {
      this.updating = true;
      const requestData = {
        id: this.itemId,
        inspectionResult: result,
        inspectionBy: this.$loginInfo.account
      };
      this.$post({
        url: "/MesLaboratory/UpdateInspectionResult",
        data: requestData
      }).then(res => {
        if (res.status === 0 && res.data.result) {
          this.$showMessage(`检验结果已录入:${result}`);
          this.showResultInput = false;
          // å½•入成功后刷新页面数据
          this.loadData();
        } else {
          this.$showMessage('录入失败,请重试');
        }
      }).catch(err => {
        console.error('录入检验结果失败:', err);
        this.$showMessage('录入失败,请重试');
      }).finally(() => {
        this.updating = false;
      });
    }
  }
}
</script>
<style lang="scss">
.container {
  padding: 20px;
  background-color: #f8f9fa;
  min-height: 100vh;
}
.page-header {
  margin-bottom: 20px;
  text-align: center;
}
.header-title {
  font-size: 20px;
  font-weight: 600;
  color: #303133;
}
.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}
.content {
  width: 100%;
}
.card {
  background-color: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
  overflow: hidden;
}
.card-header {
  background: linear-gradient(145deg, #f0f9ff, #e0f2fe);
  border-left: 4px solid #409EFF;
  padding: 20px;
}
.header-info {
  display: flex;
  align-items: center;
}
.card-body {
  padding: 20px;
}
.info-group {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.info-row {
  display: flex;
  gap: 20px;
  &.full-width {
    flex-direction: column;
  }
}
.info-item {
  display: flex;
  align-items: center;
  flex: 1;
  min-width: 0;
  &.status-item {
    align-items: center;
    gap: 10px;
  }
}
.info-label {
  font-size: 14px;
  color: #606266;
  font-weight: 500;
  min-width: 100px;
  flex-shrink: 0;
}
.info-value {
  font-size: 14px;
  color: #303133;
  flex: 1;
  word-break: break-all;
}
.status-badge {
  display: inline-block;
  padding: 6px 12px;
  font-size: 14px;
  border-radius: 20px;
  font-weight: 500;
  &.success {
    background-color: #e6f7ed;
    color: #36b37e;
    border: 1px solid #d1fae5;
  }
  &.danger {
    background-color: #ffefef;
    color: #ff4d4f;
    border: 1px solid #fee2e2;
  }
  &.pending {
    background-color: #f5f5f5;
    color: #999;
    border: 1px solid #e5e5e5;
  }
}
.result-container {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.input-btn {
  padding: 6px 12px;
  font-size: 14px;
  border-radius: 6px;
  border: 1px solid #409EFF;
  background-color: #fff;
  color: #409EFF;
  cursor: pointer;
  transition: all 0.2s;
  &:hover {
    background-color: #409EFF;
    color: #fff;
  }
  &:active {
    transform: scale(0.95);
  }
}
.result-input-container {
  display: flex;
  gap: 8px;
  align-items: center;
}
.result-btn {
  padding: 6px 12px;
  font-size: 14px;
  border-radius: 6px;
  border: 1px solid;
  cursor: pointer;
  transition: all 0.2s;
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
  &.qualified {
    background-color: #e6f7ed;
    color: #36b37e;
    border-color: #36b37e;
    &:hover:not(:disabled) {
      background-color: #36b37e;
      color: #fff;
    }
  }
  &.unqualified {
    background-color: #ffefef;
    color: #ff4d4f;
    border-color: #ff4d4f;
    &:hover:not(:disabled) {
      background-color: #ff4d4f;
      color: #fff;
    }
  }
  &.cancel {
    background-color: #f5f5f5;
    color: #666;
    border-color: #ccc;
    &:hover:not(:disabled) {
      background-color: #ccc;
      color: #fff;
    }
  }
  &:active:not(:disabled) {
    transform: scale(0.95);
  }
}
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
  color: #909399;
}
.empty-icon {
  font-size: 64px;
  margin-bottom: 24px;
  color: #c0c4cc;
}
.empty-text {
  font-size: 16px;
  font-weight: 500;
}
</style>
pages/QC/Laboratory/List.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,663 @@
<template>
  <view class="container">
    <!-- åˆ·æ–°é¡µé¢åŽçš„顶部提示框 -->
    <view class="tips" :class="{ 'tips-ani': tipShow }">
      <view class="tips-icon">✓</view>
      <view class="tips-text">刷新成功</view>
    </view>
    <view class="newsTab">
      <uni-segmented-control
        :current="current"
        :values="items"
        @clickItem="onClickItem"
        style-type="button"
        active-color="#409EFF"
        class="segmented-control fixed-tabs"
      ></uni-segmented-control>
      <view class="content">
        <view v-show="current===0">
          <!-- åŸºäºŽ uni-list çš„页面布局 -->
          <view v-if="data.length === 0" class="empty-state">
            <view class="empty-icon">📝</view>
            <view class="empty-text">暂无检验记录</view>
          </view>
          <uni-list v-else>
            <!-- åˆ—表项 -->
            <uni-list-item
              style="margin-top: 15px;"
              class="list-item enhanced-list"
              direction="column"
              v-for="item in data"
              :key="item.billNo"
              :to="'Laboratory?id=' + (item.id || '')"
            >
              <!-- é€šè¿‡header插槽定义列表的标题 -->
              <template v-slot:header>
                <view class="card-header pending-header">
                  <view class="form-group">
                    <label class="form-label">工单号:</label>
                    <input class="form-input order-no" disabled="true" type="text" v-model="item.billNo"/>
                  </view>
                </view>
              </template>
              <!-- é€šè¿‡body插槽定义列表内容显示 -->
              <template v-slot:body>
                <view class="card-body pending-body">
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">创建时间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.createTime"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">创建人:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.createUser"/>
                      </view>
                    </view>
                  </view>
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">生产线:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.lineNo"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">物料编码:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.itemNo"/>
                      </view>
                    </view>
                  </view>
                  <!-- äº§å“åç§°å•独一行 -->
                  <view class="form-group">
                    <label class="form-label">产品名称:</label>
                    <input class="form-input" disabled="true" type="text" v-model="item.itemName"/>
                  </view>
                  <!-- äº§å“è§„格单独一行 -->
                  <view class="form-group">
                    <label class="form-label">产品规格:</label>
                    <input class="form-input" disabled="true" type="text" v-model="item.itemModel"/>
                  </view>
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">生产车间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.departmentCode"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">销售订单:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.saleOrderNoc"/>
                      </view>
                    </view>
                  </view>
                  <view class="row status-row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">检验时间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.inspectionTime"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group status-group">
                        <label class="form-label lab">检验结果:</label>
                        <span class="status-tag" :class="item.inspectionResult === '合格' ? 'success' : 'danger'">
                          {{ item.inspectionResult || '待检验' }}
                        </span>
                      </view>
                    </view>
                  </view>
                  <view class="row">
                    <view class="col-100">
                      <view class="form-group">
                        <label class="form-label lab">检验人:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.inspectionUser"/>
                      </view>
                    </view>
                  </view>
                </view>
              </template>
            </uni-list-item>
          </uni-list>
        </view>
        <view v-show="current===1">
          <view v-if="data.length === 0" class="empty-state">
            <view class="empty-icon">📁</view>
            <view class="empty-text">暂无已完成的检验记录</view>
          </view>
          <uni-list v-else>
            <!-- å·²å®Œæˆåˆ—表项样式 -->
            <uni-list-item
              style="margin-top: 15px;"
              class="list-item enhanced-list"
              direction="column"
              v-for="item in data"
              :key="item.billNo"
              :to="'Laboratory?id=' + (item.id || '')"
            >
              <!-- é€šè¿‡header插槽定义列表的标题 -->
              <template v-slot:header>
                <view class="card-header submitted-header">
                  <view class="form-group">
                    <label class="form-label">工单号:</label>
                    <input class="form-input order-no" disabled="true" type="text" v-model="item.billNo"/>
                  </view>
                </view>
              </template>
              <!-- é€šè¿‡body插槽定义列表内容显示 -->
              <template v-slot:body>
                <view class="card-body submitted-body">
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">创建时间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.createTime"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">创建人:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.createUser"/>
                      </view>
                    </view>
                  </view>
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">生产线:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.lineNo"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">物料编码:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.itemNo"/>
                      </view>
                    </view>
                  </view>
                  <!-- äº§å“åç§°å•独一行 -->
                  <view class="form-group">
                    <label class="form-label">产品名称:</label>
                    <input class="form-input" disabled="true" type="text" v-model="item.itemName"/>
                  </view>
                  <!-- äº§å“è§„格单独一行 -->
                  <view class="form-group">
                    <label class="form-label">产品规格:</label>
                    <input class="form-input" disabled="true" type="text" v-model="item.itemModel"/>
                  </view>
                  <view class="row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">生产车间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.departmentCode"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">销售订单:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.saleOrderNoc"/>
                      </view>
                    </view>
                  </view>
                  <view class="row status-row">
                    <view class="col-50">
                      <view class="form-group">
                        <label class="form-label lab">检验时间:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.inspectionTime"/>
                      </view>
                    </view>
                    <view class="col-50">
                      <view class="form-group status-group">
                        <label class="form-label lab">检验结果:</label>
                        <span class="status-tag submitted-tag" :class="item.inspectionResult === '合格' ? 'success' : 'danger'">
                          {{ item.inspectionResult || '待检验' }}
                        </span>
                      </view>
                    </view>
                  </view>
                  <view class="row">
                    <view class="col-100">
                      <view class="form-group">
                        <label class="form-label lab">检验人:</label>
                        <input class="form-input" disabled="true" type="text" v-model="item.inspectionUser"/>
                      </view>
                    </view>
                  </view>
                </view>
              </template>
            </uni-list-item>
          </uni-list>
        </view>
      </view>
    </view>
    <!-- åŠ è½½æ›´å¤šç»„ä»¶ -->
    <view v-if="isLoading || noData" class="load-more-container">
      <uni-load-more :status="options.status" />
    </view>
  </view>
</template>
<script>
export default {
  components: {},
  data() {
    return {
      items: ['检验记录'],
      current: 0,
      data: [],
      tipShow: false,
      // åˆ†é¡µå‚æ•°
      pageIndex: 1,
      limit: 20,
      totalPage: 0,
      totalCount: 0,
      noData: false,
      isLoading: false,
      // åŠ è½½æ›´å¤šç»„ä»¶çŠ¶æ€
      options: {
        status: 'more'
      }
    };
  },
  onLoad() {
    this.init();
  },
  methods: {
    init() {
      this.loadData();
    },
    loadData() {
      if (this.isLoading) return;
      this.isLoading = true;
      let userName = this.$loginInfo.account;
      // æž„造请求参数
      let requestData = {
        pageIndex: this.pageIndex,
        limit: this.limit
      };
      // æ ¹æ®å½“前标签页添加筛选条件
      if (this.current === 1) {
        // å·²å®Œæˆ - æœ‰æ£€éªŒç»“果的记录
        requestData.hasInspectionResult = true;
      }
      this.$post({
        url: "/MesLaboratory/GetPage",
        data: requestData
      }).then(res => {
        if (this.pageIndex === 1) {
          // å¦‚果是第一页,直接覆盖原数据
          this.data = res.data.tbBillList || [];
        } else {
          if (res.data.tbBillList && res.data.tbBillList.length > 0) {
            // å¦‚果是下一页,追加新数据
            this.data = [...this.data, ...res.data.tbBillList];
          }
        }
        this.totalCount = res.data.totalCount || 0;
        this.totalPage = Math.ceil(this.totalCount / this.limit);
        this.noData = this.pageIndex >= this.totalPage;
        this.isLoading = false;
        // æ›´æ–°åŠ è½½æ›´å¤šçŠ¶æ€
        this.options.status = this.noData ? 'noMore' : 'more';
      }).catch(err => {
        console.error('获取实验室数据失败:', err);
        this.isLoading = false;
        this.options.status = 'fail';
        this.$showMessage('获取数据失败,请重试');
      });
    },
    viewDetail(item) {
      // è·³è½¬åˆ°Laboratory.vue页面
      uni.navigateTo({
        url: `Laboratory?id=${item.id || ''}`
      });
    },
    onClickItem(index) {
      if (this.current !== index.currentIndex) {
        this.current = index.currentIndex;
        this.data = [];
        this.pageIndex = 1;
        this.init();
      }
    }
  },
  /**
   * ä¸‹æ‹‰åˆ·æ–°å›žè°ƒå‡½æ•°
   */
  onPullDownRefresh() {
    this.pageIndex = 1;
    this.init();
    this.tipShow = true;
    uni.stopPullDownRefresh();
    setTimeout(() => {
      this.tipShow = false;
    }, 1000);
  },
  /**
   * ä¸Šæ‹‰åŠ è½½å›žè°ƒå‡½æ•°
   */
  onReachBottom() {
    if (this.noData || this.isLoading) return;
    this.isLoading = true;
    this.pageIndex++;
    this.init();
  },
  onShow() {
    // æ¯æ¬¡è¿›å…¥é¡µé¢éƒ½ä¼šæ‰§è¡Œçš„æ–¹æ³•
    // this.init();
  }
};
</script>
<style lang="scss">
@import '@/common/uni-ui.scss';
/* å…¨å±€æ ·å¼ */
page {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  background-color: #f8f9fa;
  min-height: 100%;
  height: auto;
  padding-bottom: 80px;
}
.container {
  padding: 0;
  background-color: #f8f9fa;
}
/* é¡¶éƒ¨æç¤ºæ¡† */
.tips {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #3a86ff;
  font-size: 14px;
  line-height: 40px;
  background-color: #e6f7ff;
  height: 0;
  opacity: 0;
  transform: translateY(-100%);
  transition: all 0.3s ease;
  z-index: 1000;
  box-shadow: 0 2px 10px rgba(64, 158, 255, 0.2);
}
.tips-ani {
  transform: translateY(0);
  height: 40px;
  opacity: 1;
}
.tips-icon {
  margin-right: 8px;
  font-size: 18px;
  font-weight: bold;
}
/* å›ºå®šæ ‡ç­¾é¡µæ ·å¼ */
.fixed-tabs {
  background-color: #fff;
  border-bottom: 2px solid #409EFF;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  position: sticky;
  top: 0;
  z-index: 999;
}
/* åˆ†æ®µæŽ§ä»¶æŒ‰é’®æ ·å¼å¢žå¼º */
.uni-segmented-control__button {
  font-weight: 500;
  font-size: 16px;
  color: #606266;
  transition: all 0.2s;
}
.uni-segmented-control__button--active {
  color: #409EFF;
  border-bottom: 2px solid #409EFF;
  background-color: transparent;
  font-weight: 600;
}
/* å†…容区域 */
.content {
  width: 100%;
  padding: 15px;
  box-sizing: border-box;
  margin-top: 10px;
}
/* å¡ç‰‡æ ·å¼ */
.card-header, .card-body {
  border-radius: 12px;
  padding: 18px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}
.card-header {
  margin-bottom: 10px;
  display: flex;
  align-items: center;
}
.card-body {
  margin-bottom: 15px;
}
/* æœªå®ŒæˆçŠ¶æ€å¡ç‰‡æ ·å¼ */
.pending-header {
  background: linear-gradient(145deg, #f0f9ff, #e0f2fe);
  border-left: 4px solid #409EFF;
}
.pending-body {
  background-color: #f0f9ff;
}
/* å·²å®ŒæˆçŠ¶æ€å¡ç‰‡æ ·å¼ */
.submitted-header {
  background: linear-gradient(145deg, #f6f6f6, #e9e9e9);
  border-left: 4px solid #909399;
}
.submitted-body {
  background-color: #f6f6f6;
}
/* è¡¨å•样式 */
.form-group {
  display: flex;
  align-items: flex-start;
  margin-bottom: 18px;
}
.form-label {
  margin-bottom: 0;
  padding: 6px 10px;
  font-size: 14px;
  width: 100px;
  color: #606266;
  flex-shrink: 0;
  font-weight: 500;
}
.form-label.lab {
  color: #303133;
  font-weight: 600;
}
.form-input {
  flex: 1;
  margin-bottom: 0;
  padding: 10px 14px;
  font-size: 14px;
  background-color: rgba(255, 255, 255, 0.7);
  border: 1px solid #dcdfe6;
  border-radius: 8px;
  color: #303133;
  transition: all 0.2s;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.form-input:active {
  transform: scale(0.99);
}
/* å·¥å•号底色 */
.order-no {
  background-color: #e6f7ff;
  border-color: #bfdbfe;
  font-weight: 500;
}
/* è¡Œå’Œåˆ—布局 */
.row {
  display: flex;
  margin-bottom: 18px;
}
.status-row {
  border-top: 1px dashed #dcdfe6;
  padding-top: 12px;
  margin-top: 12px;
}
.col-50 {
  flex: 1;
  margin-right: 18px;
}
.col-50:last-child {
  margin-right: 0;
}
.col-100 {
  flex: 1;
}
/* çŠ¶æ€æ ‡ç­¾ */
.status-group {
  align-items: center;
}
.status-tag {
  display: inline-block;
  padding: 6px 12px;
  font-size: 14px;
  border-radius: 20px;
  margin-left: 12px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.status-tag.success {
  background-color: #e6f7ed;
  color: #36b37e;
  border: 1px solid #d1fae5;
}
.status-tag.danger {
  background-color: #ffefef;
  color: #ff4d4f;
  border: 1px solid #fee2e2;
}
.submitted-tag {
  background-color: rgba(144, 147, 153, 0.1);
  color: #909399;
}
/* ç©ºçŠ¶æ€ */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
  color: #909399;
}
.empty-icon {
  font-size: 64px;
  margin-bottom: 24px;
  color: #c0c4cc;
}
.empty-text {
  font-size: 16px;
  font-weight: 500;
}
/* åŠ è½½æ›´å¤šå®¹å™¨ */
.load-more-container {
  padding: 30px 0;
  text-align: center;
}
/* åˆ—表项动画 */
.enhanced-list {
  transition: all 0.3s ease;
  border-radius: 12px;
  overflow: hidden;
}
.enhanced-list:active {
  transform: translateY(2px);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.enhanced-list:hover {
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}
</style>