13404089107
2 天以前 993e5fd593398926af72af660cb5ed6aba8e4e2b
culture/src/views/strain-library/production-cell-library/index.vue
@@ -2,36 +2,80 @@
  <div class="list">
    <el-card class="header-box">
      <div class="box-title">
        <img src="@/assets/public/notice.png" class="header-icon">
        <span>【菌种源保藏出/入细胞库登记表】说明</span>
        <el-button type="text" class="view-more" @click="handleViewMore">查看全部 >></el-button>
        <img src="@/assets/public/notice.png" class="header-icon" />
        <span>菌种源保藏出/入细胞库登记表说明</span>
        <el-button type="text" class="view-more" @click="handleViewMore"
          >查看全部 >></el-button
        >
      </div>
      <div class="header-content" :class="{ 'collapsed': true }">
        <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p>
        <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p>
        <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p>
        <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p>
      <div class="header-content" :class="{ collapsed: true }">
        <p>
          1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3
          条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2
          是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3
          是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。
          2.
          菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1
          原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3
          生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1
          细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在
          24 年 9 月 19
          接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1
          传代编码方式演例:祖代:DD-O-240919-01
          传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2
          编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2
          细胞库说明:3.2.1
          直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2
          从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3
          主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4.
          菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 a-01、a-02
          等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2
          接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。
        </p>
      </div>
      <!-- 查看全部弹窗 -->
      <el-dialog
        title="菌种源保藏出/入生产细胞库登记表说明"
        title="菌种源保藏出/入细胞库登记表说明"
        :visible.sync="dialogVisible"
        width="50%"
        class="view-all-dialog"
      >
        <div class="dialog-content">
          <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p>
          <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p>
          <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p>
          <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p>
          <p>
            1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3
            条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2
            是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3
            是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。2.
            菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1
            原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3
            生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1
            细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在
            24 年 9 月 19
            接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1
            传代编码方式演例:祖代:DD-O-240919-01
            传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2
            编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2
            细胞库说明:3.2.1
            直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2
            从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3
            主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4.
            菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用
            a-01、a-02 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2
            接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。
          </p>
        </div>
      </el-dialog>
    </el-card>
    <!-- Table -->
    <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange">
    <TableCustom
      :queryForm="queryForm"
      :tableData="tableData"
      :total="total"
      @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange"
    >
      <template #search>
        <el-form :model="form" label-width="auto" inline>
          <el-form-item label="菌种编号:">
@@ -40,15 +84,13 @@
          <el-form-item label="菌种名称:">
            <el-input v-model="form.strainName" placeholder="请输入"></el-input>
          </el-form-item>
          <el-form-item label="状态:">
          <el-form-item v-if="roleType == 4" label="状态:">
            <el-select v-model="form.status" placeholder="请选择">
              <el-option label="全部" value=""></el-option>
              <el-option
                v-for="item in statusOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value">
              </el-option>
              <el-option label="已出库" value="1"></el-option>
              <el-option label="出库待确认" value="2"></el-option>
              <el-option label="已入库" value="3"></el-option>
              <el-option label="入库待确认" value="4"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item class="search-btn-box">
@@ -61,236 +103,207 @@
      <template #setting>
        <div class="tableTitle">
          <div class="flex a-center">
            <div class="title" :class="{ active: currentType === 'list' }"
              @click="handleTypeChange('list')">
              生产细胞列表</div>
            <div class="drafts" :class="{ active: currentType === 'draft' }"
              @click="handleTypeChange('draft')">
              草稿箱</div>
            <div
              class="title"
              :class="{ active: currentType === 'list' }"
              @click="handleTypeChange('list')"
            >
              生产细胞列表
            </div>
            <div
              class="drafts"
              :class="{ active: currentType === 'draft' }"
              @click="handleTypeChange('draft')"
            >
              草稿箱
            </div>
          </div>
          <div class="flex a-center">
            <el-button @click="handleAdd" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增生产细胞</el-button>
            <el-button @click="handleAdd" class="el-icon-plus" type="primary" style="margin-right: 12px;">批量新增</el-button>
          <div v-if="roleType == 4" class="flex a-center">
            <el-button
              @click="handleNewStrain"
              class="el-icon-plus"
              type="primary"
              style="margin-right: 12px"
              >新增生产细胞</el-button
            >
            <el-button
              @click="handleNewStrain"
              class="el-icon-plus"
              type="primary"
              >批量新增</el-button
            >
          </div>
        </div>
      </template>
      <template #table>
        <el-table-column type="selection" width="55" />
        <el-table-column prop="strainNo" label="菌种编号" width="150" />
        <el-table-column prop="strainName" label="菌种名称" width="180" />
        <el-table-column prop="source" label="菌种来源" width="150" />
        <el-table-column prop="preservationMethod" label="鉴定方法" width="120" />
        <el-table-column prop="storageLocation" label="特征描述" width="150" />
        <el-table-column prop="inventory" label="菌种保存方法" width="100" />
        <el-table-column prop="inventory" label="保存位置" width="100" />
        <el-table-column prop="inventory" label="库存余量" width="100" />
        <el-table-column prop="inventory" label="备注"  />
        <el-table-column prop="status" label="状态" width="100">
          <template slot-scope="scope">
            <el-tag :type="getStatusType(scope.row.status)">{{ scope.row.status }}</el-tag>
        <el-table-column prop="strainCode" label="菌种编号" />
        <el-table-column prop="strainName" label="菌种名称" />
        <el-table-column prop="strainSource" label="菌种来源" />
        <el-table-column prop="appraisalMethod" label="鉴定方法" />
        <el-table-column prop="features" label="特征描述" />
        <el-table-column prop="saveMethod" label="菌种保存方法" />
        <el-table-column prop="saveLocation" label="保藏位置" />
        <el-table-column prop="stock" label="库存余量" />
        <el-table-column prop="remark" label="备注" />
        <el-table-column
          v-if="currentType === 'list'"
          prop="status"
          label="当前状态"
        >
          <template #default="{ row }">
            <el-tag :type="getStatusType(row.status)">{{
              getStatusText(row.status)
            }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" fixed="right">
          <template slot-scope="scope">
            <el-button type="text" @click="handleView(scope.row)">详情</el-button>
            <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button type="text" @click="handleDelete(scope.row)" class="delete-btn">删除</el-button>
        <el-table-column label="操作" width="200">
          <template #default="{ row }">
            <el-button type="text" @click="handleDetail(row)">详情</el-button>
            <el-button v-if="row.status == 2 || row.status == 4" type="text" @click="handleEdit(row)">编辑</el-button>
            <el-button
              v-if="currentType === 'list'"
              type="text"
              @click="handleRecord(row)"
              >出入库记录</el-button
            >
            <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </template>
    </TableCustom>
    <!-- 删除确认对话框 -->
    <el-dialog
      title="确认删除"
      :visible.sync="deleteDialogVisible"
      width="30%">
      <div class="delete-dialog-content">
        <i class="el-icon-warning-outline warning-icon"></i>
        <span>确定要删除该菌种记录吗?删除后将无法恢复。</span>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="deleteDialogVisible = false">取消</el-button>
        <el-button type="danger" @click="confirmDelete">确定</el-button>
      </span>
    </el-dialog>
    <StrainDetail :visible.sync="detailVisible" :detail="currentDetail" />
  </div>
</template>
<script>
import StrainDetail from "../strain-library-manage/components/StrainDetail.vue";
import { getList, deleteStrainLibrary } from "../strain-library-manage/service";
export default {
  name: 'ProductionCellLibrary',
  name: "StrainLibraryManage",
  components: {
    StrainDetail,
  },
  data() {
    return {
      dialogVisible: false,
      currentType: 'list',
      currentType: "list",
      detailVisible: false,
      currentDetail: {},
      form: {
        strainNo: '',
        strainName: '',
        status: ''
        strainNo: "",
        strainName: "",
        status: "",
      },
      queryForm: {
        pageSize: 10,
        pageNum: 1
        pageNum: 1,
      },
      total: 100,
      loading: false,
      sourceOptions: [
        { value: '主细胞库', label: '主细胞库' },
        { value: '工作细胞库', label: '工作细胞库' },
        { value: '外部来源', label: '外部来源' }
      ],
      statusOptions: [
        { value: '正常', label: '正常' },
        { value: '缺货', label: '缺货' },
        { value: '异常', label: '异常' },
        { value: '已停用', label: '已停用' }
      ],
      total: 800,
      tableData: [],
      selectedRows: [],
      deleteDialogVisible: false,
      deleteRow: null
    }
      roleType: "",
    };
  },
  created() {
    this.fetchData();
  activated() {
    this.searchData();
    // 角色类型 1=超级管理员 2=审批人 3=工程师 4=实验员
    this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType;
  },
  methods: {
    handleDelete(row) {
      this.$confirm("确定删除该数据吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        deleteStrainLibrary({ id: row.id }).then((res) => {
            this.$message.success("删除成功");
            this.searchData();
        });
      });
    },
    handleRecord(row) {
      this.$router.push({
        path: `/strain-library/strain-library-manage/record?id=${row.id}`,
      });
    },
    handleNewStrain() {
      this.$router.push({ path: "/strain-library/production-cell-library/add" });
    },
    handleEdit(row) {
      this.$router.push({
        path: `/strain-library/production-cell-library/add?id=${row.id}`,
      });
    },
    handleDetail(row) {
      this.currentDetail = row;
      this.detailVisible = true;
    },
    handleViewMore() {
      this.dialogVisible = true;
    },
    resetForm() {
      this.form = {
        strainNo: '',
        strainName: '',
        status: ''
      }
      this.searchData()
        strainNo: "",
        strainName: "",
        status: "",
      };
      this.searchData();
    },
    searchData() {
      this.queryForm.pageNum = 1;
      this.fetchData();
    },
    // 获取数据
    fetchData() {
      this.loading = true;
      // 构建请求参数
      const params = {
        page: this.queryForm.pageNum,
        pageNum: this.queryForm.pageNum,
        pageSize: this.queryForm.pageSize,
        ...this.form
        strainCode: this.form.strainNo,
        strainName: this.form.strainName,
        isDraft: this.currentType === "draft" ? 1 : 0,
        status: this.form.status,
        type: 3,
      };
      // 模拟API请求
      setTimeout(() => {
        // 模拟数据,实际项目中应替换为真实API调用
        const mockData = [];
        for (let i = 1; i <= 10; i++) {
          mockData.push({
            id: `${i}`,
            strainNo: `PCLS-2023-${String(i).padStart(3, '0')}`,
            strainName: `枯草芽孢杆菌生产株${i}`,
            source: i % 3 === 0 ? '外部来源' : (i % 2 === 0 ? '工作细胞库' : '主细胞库'),
            preservationMethod: i % 2 === 0 ? '冻干保存' : '超低温冷冻保存',
            storageLocation: `A区-A-${100 + i}-冷藏柜`,
            inventory: 10 + i,
            status: i % 4 === 0 ? '异常' : (i % 3 === 0 ? '缺货' : (i % 2 === 0 ? '已停用' : '正常')),
            preparationDate: `2023-05-${String(i).padStart(2, '0')}`,
            expiryDate: `2024-05-${String(i).padStart(2, '0')}`
          });
        }
        this.tableData = mockData;
        this.total = 100; // 模拟总数
        this.loading = false;
      }, 500);
      getList(params)
        .then((res) => {
          if (res.code === 200) {
            this.tableData = res.data.records;
            this.total = res.data.total;
          }
        })
        .catch((err) => {
          this.$message.error("数据加载失败");
        });
    },
    // 状态标签类型
    getStatusType(status) {
      switch(status) {
        case '正常':
          return 'success';
        case '缺货':
          return 'warning';
        case '异常':
          return 'danger';
        case '已停用':
          return 'info';
        default:
          return 'info';
      }
    },
    handleCurrentChange(page) {
      this.queryForm.pageNum = page
      this.fetchData();
      this.queryForm.pageNum = page;
      this.searchData();
    },
    handleSizeChange(size) {
      this.queryForm.pageSize = size
      this.queryForm.pageNum = 1
      this.fetchData();
      this.queryForm.pageSize = size;
      this.searchData();
    },
    handleTypeChange(type) {
      this.currentType = type;
      this.fetchData();
      this.searchData();
    },
    // 表格多选
    handleSelectionChange(selection) {
      this.selectedRows = selection;
    getStatusType(status) {
      const types = {
        1: "warning",
        2: "warning",
        3: "success",
        4: "success",
      };
      return types[status] || "info";
    },
    // 新增菌种
    handleAdd() {
      this.$router.push('/strain-library/production-cell-library/add');
    getStatusText(status) {
      const texts = {
        1: "已出库",
        2: "出库待确认",
        3: "已入库",
        4: "入库待确认",
      };
      return texts[status] || "未知状态";
    },
    // 查看菌种详情
    handleView(row) {
      this.$router.push(`/strain-library/production-cell-library/record/${row.id}`);
    },
    // 编辑菌种
    handleEdit(row) {
      this.$router.push(`/strain-library/production-cell-library/edit/${row.id}`);
    },
    // 删除菌种
    handleDelete(row) {
      this.deleteRow = row;
      this.deleteDialogVisible = true;
    },
    // 确认删除
    confirmDelete() {
      if (!this.deleteRow) return;
      // 模拟API请求
      this.$message({
        type: 'success',
        message: `删除成功: ${this.deleteRow.strainNo} - ${this.deleteRow.strainName}`
      });
      // 移除本地数据
      const index = this.tableData.findIndex(item => item.id === this.deleteRow.id);
      if (index !== -1) {
        this.tableData.splice(index, 1);
      }
      this.deleteDialogVisible = false;
      this.deleteRow = null;
    },
    // 导出
    handleExport() {
      this.$message.info('生产细胞库菌种导出功能开发中');
      // 实际项目中应实现导出逻辑
    }
  }
}
  },
};
</script>
<style scoped lang="less">
@@ -320,7 +333,7 @@
    .view-more {
      position: absolute;
      right: 0;
      color: #049C9A;
      color: #049c9a;
    }
  }
@@ -343,8 +356,50 @@
  }
}
.search-btn-box {
  margin-left: auto;
.search-form {
  margin-bottom: 20px;
  background: #f5f7fa;
  padding: 24px;
  border-radius: 8px;
  .el-form-item {
    margin-right: 20px;
    margin-bottom: 0;
  }
  .el-button {
    margin-left: 10px;
  }
}
.action-buttons {
  margin-bottom: 20px;
  .el-button {
    margin-right: 10px;
  }
}
.tab-container {
  display: flex;
  margin-bottom: 20px;
  .tab {
    padding: 10px 30px;
    border: 1px solid #dcdfe6;
    border-bottom: none;
    border-radius: 8px 8px 0 0;
    cursor: pointer;
    margin-right: 10px;
    background: #f5f7fa;
    &.active {
      background: #fff;
      border-color: #049c9a;
      color: #049c9a;
      font-weight: bold;
    }
  }
}
.flex {
@@ -371,7 +426,6 @@
    line-height: 50px;
    width: 166px;
    text-align: center;
  }
  .drafts {
@@ -394,28 +448,15 @@
    background: #ffffff;
    border-radius: 8px 8px 0px 0px;
    border: 1px solid #049c9a;
  }
}
.delete-dialog-content {
  display: flex;
  align-items: center;
  padding: 20px 0;
  .warning-icon {
    font-size: 24px;
    color: #E6A23C;
    margin-right: 10px;
  }
}
.view-all-dialog {
  :deep(.el-dialog__header) {
    padding: 20px;
    border-bottom: 1px solid #EBEEF5;
    border-bottom: 1px solid #ebeef5;
    margin-right: 0;
    .el-dialog__title {
      font-size: 18px;
      font-weight: bold;
@@ -433,11 +474,11 @@
      p {
        margin: 12px 0;
        &:first-child {
          margin-top: 0;
        }
        &:last-child {
          margin-bottom: 0;
        }
@@ -445,8 +486,4 @@
    }
  }
}
.delete-btn {
  color: #F56C6C;
}
</style>
</style>