zhongshujie
2025-06-11 588feedaac26559b59cfc7400e992a0af7cc48ee
Merge branch 'master' of http://182.92.203.7:2001/r/testbookLayout
1个文件已修改
16个文件已添加
2442 ■■■■■ 已修改文件
src/App.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/0018-01.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/0018-02.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/0018_03.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/0019_01.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/0021-01.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/feiye.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/fengdi.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/fengmian.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/icon/heart-check.png 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/icon/heart.png 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/images/top.png 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/assets/main.less 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/view/components/chapter001.vue 788 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/view/components/header.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/view/components/index.vue 953 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/books/foodSensoryInspection/view/index.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue
@@ -84,6 +84,7 @@
    >
    </hotelEnglishTrainingBrochure2nd>
    <hydraulicTransmission v-if="activeBook.name == 'hydraulicTransmission'"></hydraulicTransmission>
    <foodSensoryInspection v-if="activeBook.name == 'foodSensoryInspection'"></foodSensoryInspection>
    <MMVRTCMP v-if="activeBook.name == 'MMVRTCMP'"></MMVRTCMP>
  </div>
</template>
@@ -165,6 +166,8 @@
      import("./books/hotelEnglishTrainingBrochure2nd/view/index.vue"),
    hydraulicTransmission: () =>
      import("./books/hydraulicTransmission/view/index.vue"),
    foodSensoryInspection: () =>
      import("./books/foodSensoryInspection/view/index.vue"),
    MMVRTCMP: () => import("./books/MMVRTCMP/view/index.vue"),
  },
  data() {
@@ -227,6 +230,7 @@
      // aviationPassengerTransport6th  // 民航旅客运输第6版(旅游社)
      // hotelEnglishTrainingBrochure2nd // 酒店英语实训活页教程(第2版)(旅游社)
      // hydraulicTransmission           // 机械传动 (哈工大)
      // foodSensoryInspection         //食品感官检验技术
      // MMVRTCMP // 视觉手册
      // console.log("debugger", process.env);
      this.activeBook = await this.config.getBookConfig(
src/books/foodSensoryInspection/assets/images/0018-01.jpg
src/books/foodSensoryInspection/assets/images/0018-02.jpg
src/books/foodSensoryInspection/assets/images/0018_03.jpg
src/books/foodSensoryInspection/assets/images/0019_01.jpg
src/books/foodSensoryInspection/assets/images/0021-01.jpg
src/books/foodSensoryInspection/assets/images/feiye.jpg
src/books/foodSensoryInspection/assets/images/fengdi.jpg
src/books/foodSensoryInspection/assets/images/fengmian.jpg
src/books/foodSensoryInspection/assets/images/icon/heart-check.png
src/books/foodSensoryInspection/assets/images/icon/heart.png
src/books/foodSensoryInspection/assets/images/top.png
src/books/foodSensoryInspection/assets/main.less
New file
@@ -0,0 +1,444 @@
.foodSensoryInspection {
    width: 100%;
    height: 100%;
    // 自定义内容
    .page-box {
        box-sizing: border-box;
        min-height: 980px;
        margin-bottom: 20px;
        box-shadow: 0 3px 6px 1px #00000029;
        background-color: #fff;
        position: relative;
    }
    p {
        font-family: "宋体";
        margin-top: 0.2em;
        margin-bottom: 0.2em !important;
        text-indent: 2em;
        line-height: 30px;
        text-align: justify;
    }
    .fz-11 {
        font-size: 11px !important;
    }
    .fz-13 {
        font-size: 13px !important;
    }
    .fz-14 {
        font-size: 14px !important;
    }
    .fz-15 {
        line-height: 26px;
        font-size: 15px !important;
    }
    .img-0 {
        width: 100%;
    }
    .img-20 {
        width: 20%;
    }
    .img-70 {
        width: 70%;
    }
    .td-0 {
        text-indent: 0em !important;
    }
    .openImgBox {
        margin: 20px 0 !important;
    }
    .block {
        font-size: 18px;
        font-family: "KAITI";
        .bold {
            font-family: '黑体';
            font-weight: bold;
        }
    }
    .block1 {
        font-size: 16px;
        font-family: "FangSong";
    }
    .block2 {
        line-height: 20px;
        color: #333;
    }
    .block3 {
        font-family: '黑体';
    }
    .center {
        text-align: center;
        margin-left: 0%;
        margin-right: 0%;
        text-indent: 0em;
    }
    .right-info {
        font-family: "KAITI";
        text-align: right;
    }
    .page-box:nth-child(even) .bodystyle {
        font-family: 'FZLTXIHJW';
        text-align: justify;
        margin: 0 15% 0 13%;
        padding-bottom: 80px;
        line-height: 30px;
        padding: 14% 0 12%;
    }
    .page-box:nth-child(odd) .bodystyle {
        font-family: 'FZLTXIHJW';
        text-align: justify;
        margin: 0 13% 0 15%;
        padding-bottom: 80px;
        line-height: 30px;
        padding: 14% 0 12% 0;
    }
    .mainColor {
        color: #F48131;
    }
    .hr {
        height: 1px;
        width: 83%;
        border-top: 1px dotted #4E78EB;
    }
    .pageHeader {
        height: 100px;
        position: absolute;
        .f-right {
            color: #333;
            position: absolute;
            bottom: 8%;
            right: 10%;
            font-family: "youyuan";
        }
        span {
            margin: 0 20px;
        }
    }
    .titleBox {
        margin-bottom: 100px;
    }
    .firstTitle {
        font-family: '黑体';
        font-size: 1.6em !important;
    }
    .secondTitle {
        font-family: '仿宋';
    }
    h1 {
        font-family: '宋体';
        line-height: 2em;
        font-weight: bold;
        font-size: 1.8em;
        margin: 0;
        text-indent: 0em;
    }
    h2 {
        font-family: 'youyuan';
        font-weight: 500;
        font-size: 1.6em;
        text-indent: 2em;
    }
    h3 {
        font-family: 'youyuan';
        font-weight: 500;
        font-size: 1.2em;
        text-indent: 2em;
    }
    .mr-20 {
        margin-right: 20px;
    }
    .bold {
        font-weight: bold;
    }
    .img-rights {
        width: 350px;
        float: right;
        height: auto;
        margin: auto;
        margin-left: 18px;
    }
    .bk {
        margin-left: 2em;
        width: 80%;
        padding: 10px;
        color: #F48131;
        border: 2px dotted #F48131;
    }
    .pdf-view {
        min-width: 160px;
        flex: 1;
        span {
            cursor: pointer;
        }
        span:hover {
            color: #F48131;
            text-decoration: underline;
        }
    }
    .textarea-box {
        width: 88%;
        margin-left: 2em;
        overflow: auto;
        word-break: break-all;
        resize: none;
        border: 1px solid #666;
        border-radius: 5px;
        background-color: rgba(255, 255, 255, 0);
        outline-color: #F48131
    }
    .input-box {
        border: none;
        border-bottom: 1px solid #333;
        background-color: rgba(255, 255, 255, 0);
        outline: none;
    }
 //视频
    .video-box {
        margin: 20px 0 20px 0;
        border: 1px solid #F48131;
        padding: 2% 2%;
    }
    .videoname {
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 12px;
    }
    .collect-btn {
        cursor: pointer;
        width: 18px;
        height: 18px;
        margin-left: 10px;
        margin-top: 0.8%;
    }
}
.pdfModal {
    width: 100%;
    height: 90vh;
    .pdfBox-component {
        width: 100%;
        height: 100%;
        position: relative;
        .preview {
            width: 100%;
            height: 100%;
            .imageBox {
                height: calc(100% - 30px);
                overflow-x: hidden;
                overflow-y: auto;
                background: #ccc;
                box-sizing: border-box;
            }
            .imageBox:hover {
                cursor: zoom-in !important;
            }
            ::v-deep .el-dialog__header {
                background-color: rgba(0, 0, 0, 0.8);
                .header_title {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    color: #fff;
                    font-weight: 900;
                    font-size: 16px;
                    font-family: 'FZLTXIHJW';
                    span:nth-child(2):hover {
                        cursor: pointer;
                    }
                }
                ::v-deep .el-dialog__title,
                ::v-deep .el-dialog__headerbtn .el-dialog__close {
                    color: #fff;
                    font-weight: 900;
                    font-size: 16px;
                    font-family: 'FZLTXIHJW';
                }
            }
            .bottom_tool {
                height: 30px;
                background-color: rgba(0, 0, 0, 0.8);
                display: flex;
                justify-content: flex-end;
                align-items: center;
                svg {
                    margin-right: 15px;
                    fill: #d1d1d1;
                }
                svg:hover {
                    fill: #fff;
                    cursor: pointer;
                }
            }
        }
        .notBox {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: calc(100% - 30px);
            min-height: 300px;
        }
    }
}
.custom-dialog {
    overflow: hidden !important;
    .el-dialog__body {
        padding: 0;
    }
    .el-dialog__header {
        background-color: rgba(0, 0, 0, 0.8);
        .header_title {
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: #fff;
            font-weight: 900;
            font-size: 16px;
            font-family: 'FZLTXIHJW';
            span:nth-child(2):hover {
                cursor: pointer;
            }
        }
        .el-dialog__title,
        .el-dialog__headerbtn .el-dialog__close {
            color: #fff;
            font-weight: 900;
            font-size: 16px;
            font-family: 'FZLTXIHJW';
        }
    }
}
.header_title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    // color: #fff;
    font-weight: 900;
    font-size: 16px;
    font-family: 'FZLTXIHJW';
    span:nth-child(2):hover {
        cursor: pointer;
    }
}
/* 媒体查询做基础响应式布局 */
@media screen and (max-width: 1024px) {
    .pdfModal {
        width: 100%;
        height: 80vh;
    }
    h1 {
        font-size: 1.1em;
    }
    .custom-dialog {
        .el-dialog {
            width: 90vw !important;
        }
    }
    .span-box {
        display: inline-block;
        width: 8px;
        height: 8px;
        background-color: #FAAD70;
    }
    .span-text {
        font-size: 16px;
        font-weight: 100;
        padding: 0em 0.15em 0em 0.3em;
    }
}
@media screen and (max-width: 800px) {
    .pdfModal {
        width: 100%;
        height: 60vh;
    }
    .custom-dialog {
        .el-dialog {
            width: 90vw !important;
        }
    }
}
src/books/foodSensoryInspection/view/components/chapter001.vue
New file
@@ -0,0 +1,788 @@
<template>
  <div class="chapter" num="2">
    <!-- P1 -->
    <div class="page-box" page="7">
      <div v-if="showPageList.indexOf(7) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">
            <span>项目一</span>食品感官检验的岗前培训<span>1</span>
          </div>
        </div>
        <div class="bodystyle">
          <div class="titleBox">
            <h1 class="firstTitle mainColor">项目一</h1>
            <h1 class="mainColor">食品感官检验的岗前培训</h1>
          </div>
          <p class="mainColor bold">【案例导入】</p>
          <p class="center block3">“舌尖上的天宫”,口味个性化的航天食品</p>
          <p class="block">
            “民以食为天”,从“神五”到“神十五”,中国航天食品经历了巨大的变迁,个性化的航天食品代表着科技结晶。我国一些关键核心技术实现突破,战略性新兴产业发展壮大,载人航天、探月探火、深海深地探测等取得重大成果,进入创新型国家行列。中国航天食品自从1968年开始进行先期研究,到现在已经有百种以上。由于在失重环境中,航天员体液上涌,鼻腔充血,导致味觉神经钝化,唾液分泌发生变化,感官分析专家根据航天员生活所处的特殊环境,结合航天员在太空的口味和消化吸收能力,以及特殊进食方式,经过多次的品尝、打分、评议,并定期对食品质量在外观、质地、风味、口感、可接受程度等各方面进行感官评价,研制了120余种营养均衡、品种丰富、口感良好、长保质期的航天食品,如鱼香肉丝、宫保鸡丁、黑椒牛柳等以咸辣酸甜的口味的食品为航天员开胃助食。
          </p>
          <p class="block">
            从“神五”到“神十五”铸梦太空,个性化的航天食品快速发展,广大食品科技工作者在祖国大地上树立起了一座座科技创新的丰碑,展现出服务人民的爱国精神,勇攀高峰、敢为人先的创新精神,以及追求真理、严谨治学的求实精神和精益求精的工匠精神。随着食品领域科技的发展,航天食品会更加安全、营养、丰富,与中国航天事业一路茁壮成长壮大,并坚定不移的为人民将神舟太空的各种食品高新技术推广到生活中。
          </p>
          <p class="block3">思考问题:</p>
          <p>1.航天食品具有哪些特点?食品感官检验技术有哪些重要的意义?</p>
          <textarea
            v-model="questionData.askAbout.one"
            placeholder="请输入内容"
            rows="4"
            class="fz-15 textarea-box"
            @change="setBookQuestion"
          ></textarea>
          <p>
            2.作为一名感官检验从业人员,应具备哪些职业素养、专业知识和能力?
          </p>
          <textarea
            v-model="questionData.askAbout.two"
            placeholder="请输入内容"
            rows="4"
            class="fz-15 textarea-box"
            @change="setBookQuestion"
          ></textarea>
        </div>
      </div>
    </div>
    <!-- P2 -->
    <div class="page-box" page="8">
      <div v-if="showPageList.indexOf(8) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">食品感官检验技术<span>2</span></div>
        </div>
        <div class="bodystyle">
          <h2><span class="mr-20">任务1</span>食品感官检验的基础知识</h2>
          <p class="mainColor bold">【学习目标】</p>
          <p class="block3">知识目标</p>
          <p class="block">
            1.掌握食品感官检验技术的概念,以及在食品工业中的重要意义;
          </p>
          <p class="block">2.了解国内外食品感官检验的发展现状与趋势;</p>
          <p class="block">3.熟悉食品感官检验技术的国家标准。</p>
          <p class="block3">能力目标</p>
          <p class="block">
            1.会按照食品感官检验四项基本活动开展感官检验活动;
          </p>
          <p class="block">
            2.能查阅资料,归纳当今我国食品感官检验技术发展的研究与广泛应用;
          </p>
          <p class="block">
            3.能准确读懂并领会感官分析实验室人员的岗位职责和能力。
          </p>
          <p class="block3">素养目标</p>
          <p class="block">
            1.培养科学严谨、爱岗敬业、遵纪守法、诚实守信的精神与良好的职业道德;
          </p>
          <p class="block">
            2.树立食品质量与安全意识和职业生涯规划意识,增强专业自豪感、职业使命感和社会责任感;
          </p>
          <p class="block">3.培养学生善于思考、获取信息和自主探究的能力。</p>
          <p class="mainColor bold">【工作任务】</p>
          <p class="content">
            北京某食品企业,为了生产优质、安全,让消费者放心的乳制品,需要对新入职的职工进行食品感官检验技术培训,为上岗就业做好准备。
          </p>
          <p class="mainColor bold">【任务分析】</p>
          <div class="img-rights">
            <div class="video-box">
              <p class="center text td-0">
                <video
                  :src="videoPathOne"
                  webkit-playsinline="true"
                  x-webkit-airplay="true"
                  playsinline="true"
                  x5-video-orientation="h5"
                  x5-video-player-fullscreen="true"
                  x5-playsinline=""
                  controls
                  controlslist="nodownload"
                  class="img-0 video"
                ></video>
              </p>
              <p class="center videoname">
                <span>视频:职教“体验官”之我是“食品检验检测员”</span>
                <el-tooltip
                  class="item"
                  effect="dark"
                  :content="
                    chapterData.isCollectVideo ? '点击取消' : '点击收藏'
                  "
                  placement="top-start"
                >
                  <img
                    :src="
                      collectResourceList.findIndex(
                        (item) => item.id == '0ef987e8737e8a90c8e0678a1a14ece4'
                      ) > -1
                        ? collectCheck
                        : collectImg
                    "
                    alt=""
                    class="collect-btn"
                    @click="handleCollect('video-01')"
                  />
                </el-tooltip>
              </p>
            </div>
          </div>
          <p class="content">
            乳制品行业已成为我国现代食品制造业的优秀代表,并逐渐步入由规模效益转向价值竞争的新阶段。乳制品企业为了保证乳品的质量安全,给消费者提供营养、健康、安全、美味的产品,在安全控制、新产品开发、产品质量改进等方面加大了力度,乳制品的感官检验技术也日益成熟。本任务是对新入职的职工进行食品感官检验技术培训。依据国家标准开展相关培训:GB/T
            23470.1-2009《感官分析 感官分析实验室人员一般导则 第1部分:实验室人员职责》;GB/T
            23470.2-2009《感官分析 感官分析实验室人员一般导则 第2部分:评价小组组长的聘用和培训》。
          </p>
          <p class="mainColor bold">【思维导图】</p>
          <p class="openImgBox center">
            <img class="img-70" src="../../assets/images/0018-02.jpg" alt="" />
          </p>
          <p class="td-0">
            <img class="img-20" src="../../assets/images/0018_03.jpg" alt="" />
          </p>
          <h3>一、食品感官检验的概念及基本活动</h3>
          <p class="block">1.食品感官检验的概念</p>
          <p class="block1">
            推进健康中国建设。人民健康是民族昌盛和国家强盛的重要标志。把保障人民
          </p>
        </div>
      </div>
    </div>
    <!-- P3 -->
    <div class="page-box" page="9">
      <div v-if="showPageList.indexOf(9) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">
            <span>项目一</span>食品感官检验的岗前培训<span>3</span>
          </div>
        </div>
        <div class="bodystyle">
          <p class="td-0 block1">
            健康放在优先发展的战略位置,完善人民健康促进政策。必须坚持在发展中保障和改善民生,鼓励共同奋斗创造美好生活,不断实现人民对美好生活的向往。
          </p>
          <p class="block1">
            ——2022年10月16日,习近平在中国共产党第二十次全国代表大会上的报告
          </p>
          <p>
            中国食品工业朝着安全、营养、美味、便捷的方向发展。人民对美好生活的向往,给食品行业带来了新的机遇和挑战。未来食品发展的方向是风味健康双导向,即未来食品需要同时满足人们对美味和健康的需求。食品感官检验(Food
            Sensory
            Test)也被称为食品感官分析,是现代食品科学中最具特色的学科之一,是用于唤起、测量、分析和解释。这是目前比较经典且被广泛接受和认可的关于食品感官检验的定义。它是通过视觉、嗅觉、触觉、味觉和听觉而感知食品及其他物质特征的一门科学,是集心理学、生理学、统计学和其他科学发展起来的学科,在食品安全、质量管理、新产品开发、市场预测等方面具有重要的指导意义。
          </p>
          <p>
            食品感官检验是系统研究人类感官与食物相互作用形式与规律的一门学科,其核心的表现形式是食品感官品质,基本的科学方法是感官分析。在产品研发、质量控制、风味营销和质量安全监督检验等方面的强大作用,使其迅速成为现代食品科学技术及食品产业发展的重要技术支撑。感官评价包括一系列精确测定人对食品的反应技术,把对品牌中存在的偏见效应和一些其他信息对消费者感觉的影响降到最低;同时它试图解析食品本身的感官特性,并向产品开发者、食品科学家和管理人员提供关于其产品感官性质的重要而有价值的信息。
          </p>
          <p class="block">2.食品感官检验四项基本活动</p>
          <p>
            (1)唤起:“调试仪器”。在品评的整个过程中,使用恰当的品评表和提示语,唤醒品评人员的某种注意力,从而得到相对应的噪声影响最小的感知。
          </p>
          <p>
            (2)测量:“采集数据”。感官分析是一门定量的科学,通过采集数据,在产品性质和人的感知之间建立合理的、特定的联系。感官方法主要来自行为学研究的方法,是通过观察来测量人的反应的方式。
          </p>
          <p>
            (3)分析:“数据分析”。适当的数据分析是感官检验的重要部分,通常使用的是实验设计和数理统计分析的有效组合,以便使各种复杂的影响因素最小化,体现出品评结果的科学可靠性。因此,需要用统计学来对数据进行分析,才有可能得出较为合理的结论,也可借助计算机和感官分析软件来完成。
          </p>
          <p>
            (4)解释:“结论解释”。感官分析专家不仅仅只是为了得到实验结果,而是必须针对结果给出科学的解释和合理的措施,在基于数据、分析和实验结果的基础上进行合理判断,包括研究的背景、所采用的方法、实验的局限性和可靠性,以此指导进一步的研究和对策。
          </p>
          <p class="td-0">
            <img class="img-20" src="../../assets/images/0019_01.jpg" alt="" />
          </p>
          <p class="center block3">
            感官分析实验室人员的岗位职责和能力包括哪些?
          </p>
          <p class="block">
            食品感官检验是在科学、有效的组织下进行的实验活动。依据GB/T23470.1-2009/ISO
            13300-1:2006《感官分析实验室人员一般导则 第1部分:实验室人员职责》,感官分析实验室人员分为感官分析实验室管理人员、感官分析师和(或)评价小组组长、评价小组技术员,其岗位的划分主要取决于其所行使的职责。其中:
          </p>
          <p class="block">
            1.感官分析实验室管理人员:感官分析实验室中高层或中层管理人员,负责行政管理和经济预算。(1)应具备良好的组织和策划能力、行政能力,掌握商业和环境知识,与产品的生产、包装、储藏以及分发等相关
          </p>
        </div>
      </div>
    </div>
    <!-- P4 -->
    <div class="page-box" page="10">
      <div v-if="showPageList.indexOf(10) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">食品感官检验技术<span>4</span></div>
        </div>
        <div class="bodystyle">
          <p class="td-0 block">
            技术知识等管理能力,科研和技术能力以及感官分析能力;(2)善于内部沟通与外部联络与沟通,具有良好的语言和文字表达能力、人际交往能力;(3)了解团队合作并能激发团队活力的能力。
          </p>
          <p class="block">
            2.感官分析师和(或)评价小组组长:感官分析实验室中履行专业技术职能的人员,负责监管一个或若干评价小组组长,设计和实施感官研究,分析和解释感官分析数据等。应具备组织管理、科研能力、感官检验和领导决策4种能力。(1)组织管理能力主要是指组织策划能力、行政能力及具备必要的商业和环境知识;(2)科研能力要求具备相关产品、技术、专业和统计学的知识背景;(3)感官检验能力要求具备感官分析理论与方法学知识,以及担任过评价小组组长或评价小组技术员的实践工作经验;(4)领导能力包括团队合作、人际沟通、决策判断及激发小组成员积极性的能力。
          </p>
          <p class="block">
            3.评价小组技术员:感官检验过程中协助评价小组组长或感官分析师进行具体操作的人员,负责感官检验前的样品制备到检验后的后续工作(如废弃物的安全处理)等。(1)应具备感官分析理论和方法学知识,产品研发和配方设计知识,以及生产和包装的技术知识;(2)实验室操作规程和实验安全常识和食品卫生知识;(3)安排和实施感官检验的理论知识,能够遵守操作规程,具有良好的记录能力;(4)具有良好的职业道德,可靠并具有责任感,有工作热情;(5)具备交流能力、语言和文字表达能力、人际交往能力、应变能力,具有较好的团队合作精神和交往沟通能力。
          </p>
          <h3>二、食品感官检验的重要性</h3>
          <p>
            食品的感官检验是人类和动物最原始的自我保护本能,从神农尝百草,到现代人类日常生活中以看、闻、尝、摸等动作决定食品的品质状况,我们每天都在做着每一件食品的感官检查,其依赖的是个人经验的积累与传承。那么,食品质量感官鉴别能否真实、准确地反映客观事物的本质,除了与人体感觉器官的健全程度和灵敏程度有关外,还与人们对客观事物的认识能力有直接的关系。
          </p>
          <p class="block">1.没有任何仪器能完全代替人的感官评价</p>
          <p>
            食品感官检验有着理化分析和微生物检验所不能替代的优越性,产品质量的感官标准已经成为质量控制体系的一个重要组成部分。在食品的质量和卫生标准中,第一项内容是感官检验,在判断食品的质量时,感官指标往往具有否决性,即如果某一食品感官指标不合格,则不必进行其他的理化分析和微生物检验,直接判定该食品为不合格产品。另外,目前没有仪器可以替代人的大脑进行感官评价。
          </p>
          <p class="block">2.食品的感官消费接受性是产品市场成功的首要条件</p>
          <p>
            感官检验是食品行业必不可少的质量检验手段,为质量控制提供了信息,降低了生产过程中的风险。在现代,食品感官分析更多地被应用于食品开发商在考虑商业利益和战略决策方面,例如消费群体的偏爱调查、工艺或原材料的改变是否对产品带来质量影响的调查。一种新产品的推出是否会受到更多消费者喜欢的调查等。一项功能完善的感官检验计划对一个公司确保市场竞争力是很重要的,是产品市场成功的首要条件。
          </p>
          <p class="block">3.感官检验渗透在食品企业运行的各个环节</p>
          <p>
            感官检验提供了人们对产品由于配料、工艺、包装或货架期的改变而感知存在
          </p>
        </div>
      </div>
    </div>
    <!-- P5 -->
    <div class="page-box" page="11">
      <div v-if="showPageList.indexOf(11) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">
            <span>项目一</span>食品感官检验的岗前培训<span>5</span>
          </div>
        </div>
        <div class="bodystyle">
          <p class="td-0">
            差异的有用信息。感官评价部门与新产品开发部门间的相互影响非常大,直接对质量控制、市场研究和包装,以及间接对整个公司的其他部门提供信息。如图1-1所示,食品感官检验技术在食品企业运行的各个环节如新产品研发、工艺改进、市场调研与预测、品质检验、质量控制等都得到了广泛应用。
          </p>
          <p class="openImgBox center">
            <img src="../../assets/images/0021-01.jpg" class="img-70" alt="" />
          </p>
          <p class="center bold">图1-1 食品感官检验技术的广泛应用</p>
          <p>
            感官信息降低了产品开发和满足消费者需要的战略决策的风险。对于食品公司而言,在满足消费者期望以及确保更大可能的市场成功方面,一项功能完备的感官检验实施计划将不可或缺,感官检验的结果直接与感官质量相关。
          </p>
          <p class="block">4.从简单的品评走向科学的感官检验是必然趋势</p>
          <p>
            现代感官评价是一种科学的测定方法,从实验室环境布置和要求、评价员的选择与培训、实验方案的设计,结果的分析与处理都依靠科学的感官评价标准。感官品评技术在食品工业中的应用,随着差别检验、差异类别检验、描述分析等感官品评方法的不断完善而日益科学化、完备化,是新产品研制、保障食品感官质量的重要手段。目前一些大型的食品加工企业、香精香料公司,如NESTLE、DANONE、北京稻香村食品公司、中粮集团等都拥有自己的感官品评实验室和感官品评小组,主要对本公司产品的感官特性进行分析和评价。例如在新产品开发过程中要进行从头到尾的测试和跟踪。包括:(1)新产品的感官特性的设计;(2)产品即将投放市场的最后测试;(3)产品制造过程中感官特性的控制;(4)产品投放市场后满足感的跟踪。
          </p>
          <p>
            近年来,我国一些大型食品加工企业也逐渐意识到食品感官品评技术的重要性,并将该技术运用到食品生产和质量控制过程中。相关管理部门还先后出台了关于茶叶、葡萄酒、乳制品等方面的感官品评国家标准和行业标准,在行业内也涌现出了一批具有较高水平的品酒师、咖啡师、品茶师、乳品评鉴师等。
          </p>
          <h3>三、食品感官检验的发展与趋势</h3>
          <p class="block">1.国外食品感官检验的发展</p>
          <p>
            感官科学技术的发展,主要经历了三个阶段,一是从管理者品评起步;二是专业感官品评小组品评成主体,多学科交叉与应用,感官评价活动标准化;三是感官分析与理化分析相结合,仪器测量辅助感官评价。国外食品感官检验已呈现出人机结合,智能感官渐成主流;市场消费需求和消费意向的感官分析技术与感官营销两大主要方面的发展态势。
          </p>
          <p>
            感官评价始于20世纪初,随着食品工业的快速发展,感官评价科学迅速发展起
          </p>
        </div>
      </div>
    </div>
    <!-- P6 -->
    <div class="page-box" page="12">
      <div v-if="showPageList.indexOf(12) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">食品感官检验技术<span>6</span></div>
        </div>
        <div class="bodystyle">
          <p class="td-0">
            来。20世纪40年代,美国食品与容器研究所以系统化方式收集士兵们对食品接受程度的数据,目的就是为了保证有营养的军需食品更好吃,能被军人接受。许多科学家也开始思索如何收集人们对物品的感官反应及形成这些反应的生理现象。
          </p>
          <p>
            整个感官检验技术真正起飞始于20世纪六七十年代,主要诱因是食品加工工业的快速发展。在期间各种评价方法、标记方法、评价观念、评价结果的表现方式等不断被提出、讨论与验证,并在此基础上出现了专家型品评员。到了80年代,感官检验技术开始蓬勃发展,越来越多的企业成立感官评价部门,各大学成立研究单位并纳入高等教育课程。美国标准检验(ASTM)方法也制订了感官品鉴实施标准(Committee
            E-18)。90年代之后,由于国际商业活动频繁以及全球化的影响,感官评价活动频繁,感官评价开始进行国际交流讨论,跨国文化与人种对感官反应的影响。
          </p>
          <p>
            进入21世纪,感官评价已在各国发展迅速,在美国,各大食品公司(可口可乐、雀巢、芬美意等)都已拥有各自庞大的感官评价部门,各大学的食品科学系皆设立了感官品鉴研究课程及项目,业界甚至出现了很多感官品鉴的专业顾问公司,为中小企业提供品鉴服务。
          </p>
          <p class="block">2.国内感官检验的发展</p>
          <p>(1)食品感官检验技术国家标准</p>
          <p>
            我国现代感官分析始于20世纪40年代,至今已经历了80多年的发展,逐步形成了一支较为完善和规范化的学科。随着电子技术、生物技术、仿生技术的发展,感官分析的应用结果处理更方便、更快速,它必将得到进一步的完善和提高。自1988年起,我国相继制订并颁布了感官分析方法的国家标准,并在不断的修订和更新,包括:GB/T
            10220-2012《感官分析方法 总论》、GB/T
            10221-2021《感官分析 术语》、GB/T
            16291.1-2012《感官分析 选拔、培训与管理评价员一般导则第1部分:优选评价员》、GB/T
            16291.2-2012《感官分析 选拔、培训与管理评价员一般导则第2部分:专家评价员》、GB/T
            13868-2009《建立感官分析实验室的一般导则》、GB/T
            12311-2012《感官分析方法三点检验》、GB/T
            17321-2012《感官分析方法 二、三点检验》、GB/T
            12310-2012《感官分析 成对比较检验》、GB/T
            12315-2008《感官分析 方法学 排序法》、GB/T
            39558-2020《感官分析 方法学“A”-“非A”检验》、GB/T
            12312-2012《感官分析 味觉敏感度的测定方法》、GB/T
            15549-1995《感官分析 方法学检测和识别气味方面评价员的入门和培训》、GB/T
            16860-1997《感官分析方法 质地剖面检验》、GB/T
            12313-1997《感官分析方法 风味剖面检验》、GB/T
            16861-1997《感官分析 通过多元分析方法鉴定和选择用于建立感官剖面的描述词》、GB/T
            29605-2013《感官分析 食品感官质量控制导则》、GB/T
            29604-2013《感官分析 建立感官特性参比样的一般导则》、GB/T
            25006-2010《感官分析包装材料引起食品风味改变的评价方法》。
          </p>
          <p>
            这些国家标准一般都是参照采用或等效采用相关的国际标准(ISO系列),并对国际标准进行了修改和完善,使得国际标准更加本土化,具有较高的权威性和可比性,成为感官分析的法律法规依据。经过不断的发展及修订,至今国际标准化组织已颁布了33项感官分析标准,其中感官分析方法标准的数量最多,共21项,占感官分析标准总数的64%。
          </p>
          <p>(2)食品感官科学技术的研究与应用</p>
          <p>
            从整体而言,我国食品感官科学技术的研究与应用分为三个阶段:一是以满足
          </p>
        </div>
      </div>
    </div>
    <!-- P7 -->
    <div class="page-box" page="13">
      <div v-if="showPageList.indexOf(13) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">
            <span>项目一</span>食品感官检验的岗前培训<span>7</span>
          </div>
        </div>
        <div class="bodystyle">
          <p class="td-0">
            食品工业质量管理、市场营销、新产品开发为目的,提高传统感官品评方法的科学化程度;二是结合我国的特点进行系统的感官品质研究,尤其是对一些传统食品,如白酒、茶叶、馒头、米饭等的感官评价与仪器分析数据的相关性进行的的系统研究,截至目前已积累了较丰富的科学数据;三是站在学科发展前沿,在感官评价信息管理系统、智能感官分析方法与设备研究方面参与国际竞争。
          </p>
          <p>
            从1975年起开始有学者研究香气和组织的评价。20世纪90年代后,“感官评价”被大量地应用在食品科学的研究中,目前在国内的应用有:①评估餐饮业的清洗效果(以目视法进行);②生鲜产品,如肉品、水产品、蛋品、乳品等;③中药药材;④香水材料;⑤嗜好性产品,如酒、茶叶;⑥育种开发,如园艺产品、农畜产品;⑦环保检测(以目视及嗅觉进行);⑧纺织品;⑨设计学、媒体传播方面;⑩食品加工等方面。其中以食品方面的应用最多,研究食品感官评价方面的学术文章也在不断增加。
          </p>
          <p class="block">3.动态与趋势</p>
          <p>
            进入21世纪,伴随着信息科学、生命科学、仪器分析技术的发展,感官科学技术与多个学科交叉,表现为人机一体化、仪器智能化的发展趋势,呈现出与市场需求和消费者意向密切结合的多元化态势。
          </p>
          <p>(1)人机一体化发展,现代智能感官检验技术渐成主流</p>
          <p>
            采用现代仿生技术模拟哺乳动物的感官系统开发的电子鼻和电子舌设备,广泛应用于乳制品、肉制品、酒类等,电子舌采用人舌头味觉细胞工作原理相似的人工膜脂传感器技术,以客观数值的评价食品的甜味、苦味、涩味、酸味、咸味、鲜味等基本味觉感官指标。在日本许多品牌将商品本身的味觉雷达图谱印刷在食品外包装上,以方便消费者选购自己喜欢的口味。电子鼻应用于原料奶品质判断,火腿的成熟度判断,酒的风味识别等方面。针对色泽的仪器测定已经建立了与人的视觉之间良好的相关性,如美国农业部研制了柑桔比色仪,实现了仪器测定结果与原标准比色板的视觉比对相同的效果,成为官方的色泽评分方法。在食品的香气测定方面,气相色谱与质谱联机(GC-MS)已成为测定食品中挥发性成分的常见方法。人机结合的香气分析技术也取得了重大进展,如将气相色谱—质谱技术与人的嗅觉相结合的嗅探技术,被广泛用于研究人的嗅觉与香气成分之间的关系。
          </p>
          <p>(2)市场需求和消费者意向密切结合</p>
          <p>
            为了适应企业快速发展的需要,不断提高感官品评结果的准确性,研究人员开发出了各种先进的感官品评软件,并通过计算机系统完成问卷自动生成、在线调查、自动收集数据、数据及时分析和绘制图表等工作。还将结果储存在计算机内便于追踪评价员的表现。这些软件的使用极大地提高了感官品评的工作效率和结果的准确性,为产品品质的提升和企业的发展做出了重要贡献。目前使用较普遍的软件有加拿大
            Compusense公司的Compusease
            Five、法国Biosystemes公司的FIZZ、美国Sensory Computer
            Systems公司的SIM2000、荷兰Logic8公司的EyeQuestion、法国 ABT
            Informatique公司的Tastel,以及中国标准化研究院的“轻松感官分析软件”等。
          </p>
          <p>
            科技是第一生产力、人才是第一资源、创新是第一动力。食品感官科学作为食品科学学科,无论在理论建立、技术创新、前沿突破、工业应用等方面都取得了令人瞩目的成就。尤其近十几年来,我国食品感官科学的研究队伍得到快速的发展,
          </p>
        </div>
      </div>
    </div>
    <!-- P8 -->
    <div class="page-box" page="14">
      <div v-if="showPageList.indexOf(14) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">食品感官检验技术<span>8</span></div>
        </div>
        <div class="bodystyle">
          <p class="td-0">
            学科的整体水平得到了快速的提升,在智能感官分析、感官评价技术、风味化学、口腔行为等相关领域取得了一系列成果。实施食品安全战略,助力健康中国建设。食品生产企业也在不断寻求创新突破,通过感官分析智能化和风味数字化,利用科技赋能、风味描述打造产品差异化,丰富产品信息,将食品的品控从传统的理化、成分指标检测层面,拓展至消费者体验层面,强化对体验的品质控制,使食品更加适合人们的需求,保障人民生命健康,不断满足人民日益增长的美好生活需要。
          </p>
          <p class="mainColor bold">【知识拓展与链接】</p>
          <div class="bk">
            <div class="pdf-view">
              <span @click="toUrl(1)">感官检验——精密的‘生物检测器’</span>
            </div>
          </div>
          <p class="mainColor bold">【任务测试】</p>
          <p class="block3 bold">一、多选题</p>
          <p>
            1.感官检验是建立在多种理论综合的基础上的学科,主要与( )等学科密不可分。
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.one"
              :disabled="questionData.isComplete"
              value="A"
              id="1"
              v-model="questionData.projectData.one"
              @change="setBookQuestion"
            />A.心理学
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.one"
              :disabled="questionData.isComplete"
              value="B"
              id="1"
              v-model="questionData.projectData.one"
              @change="setBookQuestion"
            />B.生理学
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.one"
              :disabled="questionData.isComplete"
              value="C"
              id="1"
              v-model="questionData.projectData.one"
              @change="setBookQuestion"
            />C.统计学
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.one"
              :disabled="questionData.isComplete"
              value="D"
              id="1"
              v-model="questionData.projectData.one"
              @change="setBookQuestion"
            />D.社会学
          </p>
          <p>2.执行一个项目的感官检验,必须完成的任务有( )。</p>
          <p>
            <input
              type="checkbox"
              name="projectData.two"
              :disabled="questionData.isComplete"
              value="A"
              id="2"
              v-model="questionData.projectData.two"
              @change="setBookQuestion"
            />A.项目目标的确定,实验目标的确定
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.two"
              :disabled="questionData.isComplete"
              value="B"
              id="2"
              v-model="questionData.projectData.two"
              @change="setBookQuestion"
            />B.样品的筛选,实验设计
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.two"
              :disabled="questionData.isComplete"
              value="C"
              id="2"
              v-model="questionData.projectData.two"
              @change="setBookQuestion"
            />C.实验的实施,分析数据
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.two"
              :disabled="questionData.isComplete"
              value="D"
              id="2"
              v-model="questionData.projectData.two"
              @change="setBookQuestion"
            />D.解释结果得出结论
          </p>
          <p>3.以下属于现代感官分析仪器的是( )。</p>
          <p>
            <input
              type="checkbox"
              name="projectData.three"
              :disabled="questionData.isComplete"
              value="A"
              id="3"
              v-model="questionData.projectData.three"
              @change="setBookQuestion"
            />A.电子舌
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.three"
              :disabled="questionData.isComplete"
              value="B"
              id="3"
              v-model="questionData.projectData.three"
              @change="setBookQuestion"
            />B.电子鼻
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.three"
              :disabled="questionData.isComplete"
              value="C"
              id="3"
              v-model="questionData.projectData.three"
              @change="setBookQuestion"
            />C.液相色谱仪
          </p>
          <p>
            <input
              type="checkbox"
              name="projectData.three"
              :disabled="questionData.isComplete"
              value="D"
              id="3"
              v-model="questionData.projectData.three"
              @change="setBookQuestion"
            />D.色差计
          </p>
          <p class="block3 bold">二、填空题</p>
          <p>
            1.食品感官检验技术是通过<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.four"
              @change="setBookQuestion"
            />、<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.five"
              @change="setBookQuestion"
            />、<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.six"
              @change="setBookQuestion"
            />和<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.seven"
              @change="setBookQuestion"
            />而感知到食品及其物质的特征或性质的一种科学方法。
          </p>
          <p>
            2.食品感官检验包括<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.eight"
              @change="setBookQuestion"
            />、<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.nine"
              @change="setBookQuestion"
            />、<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.ten"
              @change="setBookQuestion"
            />和<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              autocomplete="off"
              v-model="questionData.projectData.eleven"
              @change="setBookQuestion"
            />四种活动。
          </p>
          <p>
            3.自1988年开始,我国制订和颁布实施了一系列食品感官分析方法的<input
              type="text"
              name="ball1"
              class="fz-16 input-box"
              style="width: 100px"
              v-model="questionData.projectData.twelve"
              @change="setBookQuestion"
            />,是参照等效的相关国际标准制订的,具有权威性和可比性,也是执行感官分析的法律依据。
          </p>
          <p class="block3 bold">三、简答题</p>
          <p>
            1.什么是食品感官检验技术?与理化检验相比较有什么不可替代的优势?
          </p>
          <textarea
            v-model="questionData.projectData.thirteen"
            placeholder="请输入内容"
            rows="4"
            class="fz-15 textarea-box"
            @change="setBookQuestion"
          ></textarea>
          <p>2.食品感官检验在食品企业有哪些广泛的应用?</p>
          <textarea
            v-model="questionData.projectData.fourteen"
            placeholder="请输入内容"
            rows="4"
            class="fz-15 textarea-box"
            @change="setBookQuestion"
          ></textarea>
          <p>
            3.我国在一些关键核心技术实现突破,战略性新兴产业发展壮大,进入创新型国家行列。请查阅文献资料,举例说明我国食品感官分析领域有哪些新技术,并探讨未来的发展趋势。
          </p>
          <textarea
            v-model="questionData.projectData.fifteen"
            placeholder="请输入内容"
            rows="4"
            class="fz-15 textarea-box"
            @change="setBookQuestion"
          ></textarea>
        </div>
      </div>
    </div>
    <preView
      :isClear="dialogVisible"
      :md5="p_md5"
      :pdfTitle="pdfTitle"
      ref="pdfDialogRef"
    ></preView>
  </div>
</template>
<script>
import { getResourcePath, uploadFilePath } from "@/assets/methods/resources";
import {
  getCollectResource,
  setCollectResource,
} from "@/assets/methods/resources";
import preView from "@/components/pdfview/index.vue";
import tool from "@/assets/js/toolClass.js";
export default {
  name: "chapterOne",
  props: {
    showPageList: {
      type: Array,
    },
  },
  components: {
    preView,
  },
  data() {
    return {
      collectImg: require("../../assets/images/icon/heart.png"),
      collectCheck: require("../../assets/images/icon/heart-check.png"),
      questionData: {
        isComplete: false,
        askAbout: {
          one: "",
          two: "",
        },
        projectData: {
          one: [],
          two: [],
          three: [],
          four: "",
          five: "",
          six: "",
          seven: "",
          eight: "",
          nine: "",
          ten: "",
          eleven: "",
          twelve: "",
          thirteen: "",
          fourteen: "",
          fifteen: "",
        },
      },
      videoPathOne: "",
      chapterData: {
        isCollectVideo: false,
      },
      collectResourceList: [],
      dialogVisible: false,
      pdfTitle: "",
      p_md5: "",
      pdfDialogRef: "",
      pdfMd5: {
        1: {
          md5: "7181ec12587d46113dfd910030d6e824",
          name: "感官检验——精密的‘生物检测器’",
        },
      },
    };
  },
  async mounted() {
    const bookQuestion = localStorage.getItem(
      "foodSensoryInspection-book-chapter01-question"
    );
    if (bookQuestion) {
      this.questionData = JSON.parse(bookQuestion);
    }
    this.getVidoePath();
    this.collectResourceList = await getCollectResource(
      this.config.activeBook.bookId
    );
  },
  methods: {
    setBookQuestion() {
      localStorage.setItem(
        "foodSensoryInspection-book-chapter01-question",
        JSON.stringify(this.questionData)
      );
    },
    async getVidoePath() {
      this.videoPathOne = await getResourcePath(
        "0ef987e8737e8a90c8e0678a1a14ece4"
      );
    },
    toUrl(val) {
      if (val) {
        this.dialogVisible = true;
        this.p_md5 = this.pdfMd5[val].md5;
        this.pdfTitle = this.pdfMd5[val].name;
        this.$refs.pdfDialogRef.openDialog();
      }
    },
    handleCollect(e) {
      if (e == "video-01") {
        this.handleCollectResource(
          "0ef987e8737e8a90c8e0678a1a14ece4",
          "0ef987e8737e8a90c8e0678a1a14ece4",
          "",
          "视频",
          "bits",
          "视频:职教“体验官”之我是“食品检验检测员”"
        );
        this.chapterData.isCollectVideo = !this.chapterData.isCollectVideo;
      }
    },
    //资源收藏事件
    // resourcePath  文件路径,
    // resourceType  文件类型
    // source        文件来源
    handleCollectResource(
      id,
      md5,
      resourcePath,
      resourceType,
      source,
      resourceName
    ) {
      let list = this.collectResourceList;
      if (list.findIndex((item) => item.id == id) > -1) {
        list = list.filter((item) => item.id != id);
      } else {
        list.push({
          id,
          md5,
          resourcePath,
          resourceType,
          source,
          resourceName,
        });
      }
      this.collectResourceList = list;
      setCollectResource(
        this.config.activeBook.bookId,
        this.collectResourceList
      );
    },
  },
};
</script>
<style lang="less" scoped></style>
src/books/foodSensoryInspection/view/components/header.vue
New file
@@ -0,0 +1,173 @@
<template>
  <div class="chapter" num="1">
    <!-- 封面 -->
    <div class="page-box mt-20" page="1" style="min-height: auto">
      <div v-if="showPageList.indexOf(1) > -1">
        <img class="img-0" alt="" src="../../assets/images/fengmian.jpg" />
      </div>
    </div>
    <!-- 扉页 -->
    <div class="page-box mt-20" page="2" style="min-height: auto">
      <div v-if="showPageList.indexOf(2) > -1">
        <img class="img-0" alt="" src="../../assets/images/feiye.jpg" />
      </div>
    </div>
    <!-- 介绍页面 -->
    <div class="page-box" page="3">
      <div v-if="showPageList.indexOf(3) > -1">
        <div style="margin: 0 auto; padding: 50% 40% 10% 10%;">
          <p class="fz-15"><b>图书在版编目(CIP)数据</b></p>
          <p class="fz-15 block2">
            食品感官检验技术/柳青主编.—北京:北京师范大学出版社,2025.1
          </p>
          <p class="fz-15 block2">("十四五"职业教育国家规划教材)</p>
          <p class="fz-15 block2">ISBN 978-7-303-25359-3</p>
          <p class="block2"><br /></p>
          <p class="fz-15 block2">
            Ⅰ.①食…  Ⅱ.①柳…  Ⅲ.①食品感官评价—高等<br/>职业教育-教材 Ⅳ.①TS207.3
          </p>
          <p class="block2"><br /></p>
          <p class="fz-15 block2">
            中国国家版本馆CIP数据核字(2019)第273865号
          </p>
          <hr />
          <p class="td-0 fz-14 block2">
            出版发行:北京师范大学出版社 https://www.bnupg.com
          </p>
          <p class="td-0 fz-14 block2">
                 北京市西城区新街口外大街12-3号
          </p>
          <p class="td-0 fz-14 block2">     邮政编码:100088</p>
          <p class="td-0 fz-14 block2">印  刷:河北品睿印刷有限公司</p>
          <p class="td-0 fz-14 block2">经  销:全国新华书店</p>
          <p class="td-0 fz-14 block2">开  本:787mm×1092mm 1/16</p>
          <p class="td-0 fz-14 block2">印  张:18.5</p>
          <p class="td-0 fz-14 block2">字  数:389千字</p>
          <p class="td-0 fz-14 block2">版 印 次:2025年1月第2版第8次印刷</p>
          <p class="td-0 fz-14 block2">定  价:47.00元</p>
          <hr />
          <p class="td-0 fz-15 block2">
            策划编辑:周光明      责任编辑:周光明
          </p>
          <p class="td-0 fz-15 block2">
            美术编辑:焦 丽      装帧设计:焦 丽
          </p>
          <p class="td-0 fz-15 block2">
            责任校对:陈 民      责任印制:赵 龙
          </p>
          <p ><br /></p>
          <p class="td-0 fz-16"><b>版权所有 侵权必究</b></p>
          <p class="td-0 block2 fz-13">读者服务电话:010-58806806</p>
          <p class="td-0 block2 fz-13">如发现印装质量问题,影响阅读,请联系印制管理部:010-58800608</p>
        </div>
      </div>
    </div>
    <!-- 编委会 -->
    <div class="page-box" page="4">
      <div v-if="showPageList.indexOf(4) > -1">
        <div class="bodystyle">
          <h1 class="firstTitle center">编委会</h1>
          <p class="block">
            <span class="bold">主 编</span> 柳 青 北京农业职业学院
          </p>
          <p class="block">
            <span class="bold">副主编</span> 包永华 浙江经贸职业技术学院
          </p>
          <p class="block">    谭龙飞 广州城市职业学院</p>
          <p class="block">    李群和 温州科技职业学院</p>
          <p class="block">
            <span class="bold">参 编</span> 张丽云 石家庄职业技术学院
          </p>
          <p class="block">    田文静 北京农业职业学院</p>
          <p class="block">    任龙梅 乌兰察布职业学院</p>
          <p class="block">    施 帅 江苏农牧科技职业学院</p>
          <p class="block">    周慧恒 湖南化工职业技术学院</p>
          <p class="block">    李 扬 北京艾森泰科科技有限责任公司</p>
          <p class="block">    李 宁 北京盈盛恒泰科技有限责任公司</p>
          <p class="block">
                卢 伟 柯尼卡美能达(中国)投资有限公司
          </p>
          <p class="block">
                陈 达 柯尼卡美能达(中国)投资有限公司
          </p>
        </div>
      </div>
    </div>
    <!-- 前言 -->
    <div class="page-box" page="5">
      <div v-if="showPageList.indexOf(5) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">前言</div>
        </div>
        <div class="bodystyle">
          <h1 class="center mainColor">前言</h1>
          <p class="block1">
            本教材是以习近平新时代中国特色社会主义思想为指导,深入学习贯彻党的二十大报告精神,“落实立德树人根本任务,培养德智体美劳全面发展的社会主义建设者和接班人”,根据《中华人民共和国职业教育法》和国务院《国家职业教育改革实施方案》(国发〔2019〕4号),紧贴新时代特点和食品领域新形势,产教融合特色鲜明,旨在承担保障人民对安全美味食品的追求,采用任务导向教学模式,与企业行业专家合作编写而成。坚持把培养中国特色社会主义建设者和接班人作为根本任务,紧紧围绕培养什么人、怎样培养人、为谁培养人,保障人民“舌尖上的安全”,不断满足人民对美好生活的向往。教材编写团队主持的教育部全国食品工业行指委“高职院校食品感官检验技术课程教学改革与实践”项目获省部级教学成果一等奖。主要特色如下:
          </p>
          <p class="block1">
            1.紧扣感官检验岗位职业能力要求,构建“岗课赛证创”课程体系
          </p>
          <p class="block1">
            教材立足食品安全战略要求,深入实施人才强国战略,培养造就大批德才兼备的高素质人才,以食品感官检验职业岗位需求为导向,对接感官分析国家标准、“1+X”粮农食品安全评价等级证书、检验技能大赛和“互联网+”大学生创新创业大赛,融合质构仪、电子舌、电子鼻分析等现代智能感官检验新技术,校企合作开发基于岗位的典型工作任务。课程内容架构遵循国家“感官分析师”职业能力培养规律并符合学生学习认知规律,紧扣食品行业的新技术、新工艺、新规范,以10个项目共37个企业真实的感官检验任务为主线,每个项目以“案例导入、工作任务、知识准备、方案设计与实施、评价与反馈”序化教材内容,充分体现以学生主体、教师为主导。实现职业素养培养与职业技能提升相融合,工作任务与岗位相融合,教材内容与感官分析国家标准、技能竞赛相融合,成绩考核与职业资格证书相融合。
          </p>
          <p class="block1">
            2.配套国家在线精品课程和国家教学资源库,为线上线下混合式教学奠定坚实基础
          </p>
          <p class="block1">
            本教材配套北京农业职业学院柳青教授主持的国家职业教育在线精品课程,网址:https://mooc.icve.com.cn/cms/courseDetails/index.htm?cid=spgbjn011lq441。并配套国家职业教育教学资源库3门课程资源(https://www.icve.com.cn):《食品感官检验技术》《食品感官分析技术》和《农产品感官分析技术》,目前选课人数1万余人。依托教育部食品安全示范性虚拟仿真实训基地,建设38GB、1300余项立体化数字资源,包括微课、视频、动画、感官分析虚拟仿真软件、VR、测试题、PPT等,充分满足学生个性化学习需求,为线上线下混合式教学奠定坚实基础。满足了广大师生、企业人员和社会学习者的学习需求,实现了在线学习与课堂实践的高度融合,全面激发学生的学习兴趣和潜能。同时教材封面贴有二维码,为各项目任务配套PPT、知识拓展和测试题等资源,书内也嵌入了二维码,方便学生直接扫码学习素材。
          </p>
          <p class="block1">3.落实立德树人根本任务,润物细无声融入课程思政</p>
          <p class="block1">
            为落实立德树人根本任务,深化三全育人改革,将思政元素落实到每个任务,使学生从风味角度严控食品品质,服务人民美好生活。例如在食品感官检验的岗前
          </p>
        </div>
      </div>
    </div>
    <div class="page-box" page="6">
      <div v-if="showPageList.indexOf(6) > -1">
        <div class="pageHeader">
          <img class="img-0" alt="" src="../../assets/images/top.png" />
          <div class="f-right">食品感官检验技术<span>2</span></div>
        </div>
        <div class="bodystyle">
          <p class="td-0 block1">培训任务中巧妙融入“舌尖上的天宫”,口味定制化的航天食品,弘扬爱国精神,引导广大人才爱党报国、敬业奉献、服务人民;在味觉与食品的味觉识别以“神农尝百草之滋味,水泉之甘苦”案例,培养学生实践出真知,养成勤学明辨和科学献身精神;将“葡萄美酒夜光杯,欲饮琵琶马上催”融入葡萄酒的排序检验任务中,引导学生坚守中华文化立场,弘扬中华民族优秀传统文化,树立“中国制造”葡萄酒的文化自信,培养精益求精的工匠精神;针对制假售假,劣质酒披高档“外衣”销售现象,利用现代智能感官分析技术精准检验以及在感官检验应用技能中融入创新让老醋飘“新香”案例,提升学生的综合职业能力,实现育训结合、德技并修的教学目标。</p>
          <p class="block1">4.产教融合特色鲜明,聚焦现代食品产业发展前沿</p>
          <p class="block1">
            教材聚焦食品产业发展的新需求,对接职业标准和感官检验岗位要求,以企业真实案例设计典型工作项目,秉持创新驱动发展战略,搭建虚拟现实感官分析平台,将教学过程与项目实战充分融为一体,体现“教、学、做”一体化,实现校企合作、工学结合的“无缝对接”。主要内容包括食品感官检验的岗前培训、食品感官检验条件的控制、样品的制备和呈送、食品感官评价员的选拔与培训、食品差别检验、食品排列检验、食品描述性分析检验、食品分级检验、现代智能食品感官分析和食品感官检验的应用技能。涵盖了果蔬制品、烘焙食品、乳制品、肉制品、水产品、酒类、饮料、茶叶、罐头等各类食品的感官检验方法,引领食品感官检验领域专业化、职业化人才培养,努力造就更多“卓越工程师、大国工匠、高技能人才”。
          </p>
          <p class="block1">
            本书由北京农业职业学院柳青担任主编并统稿,具体编写分工如下:柳青编写项目一(任务1、2)、项目五、项目九及附录;田文静编写项目一(任务3~任务5);张丽云编写项目二;李群和编写项目三、项目四;包永华编写项目六;谭龙飞编写项目七;施帅编写项目八;李扬、李宁、卢伟、陈达编写项目九(任务1~任务4);任龙梅编写项目十。
          </p>
          <p class="block1">
            本书在编写过程中,得到了国家职业教育教学资源库“智慧职教”课程平台、国内有关高校、中国标准化研究院、食品企业专家的大力支持,在此表示衷心的感谢。另外,书中引用和参考了众多专家的著作,在此一并表示感谢。
          </p>
          <p class="block1">
            本书既可作为食品检验及加工类等专业的教学用书,也可作为食品专业技术人员、管理人员和科研人员的参考书,对精细加工、医药等行业的产品评定和营销人员也具有一定的参考价值。
          </p>
          <p class="block1">
            鉴于编者水平有限,加之时间仓促,书中不足之处在所难免,恳请各位专家和读者提出宝贵意见和建议,以便修改和完善。
          </p>
          <p class="right-info">编者</p>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "pageHeader",
  props: {
    showPageList: {
      type: Array,
    },
  },
  data() {
    return {};
  },
};
</script>
<style lang="less" scoped>
</style>
src/books/foodSensoryInspection/view/components/index.vue
New file
@@ -0,0 +1,953 @@
<template>
  <div class="page-main" @scroll="throttledScrollHandler">
    <div class="page-content" :style="{
      fontSize: fontSize + 'px',
      transform: `scale(${pageZoom})`,
      transformOrigin: 'center top',
    }">
      <pageHeader v-if="showCatalogList.indexOf(1) > -1" :showPageList="loadPageList"></pageHeader>
      <chapterOne v-if="showCatalogList.indexOf(2) > -1" :showPageList="loadPageList"></chapterOne>
    </div>
  </div>
</template>
<script>
import Vue from "vue";
import pageHeader from "./header.vue";
import chapterOne from "./chapter001.vue";
import NoteIcon from "@/assets/images/biji.png";
import getQuestionList from "@/assets/methods/examination";
import _ from "lodash";
import Swiper from "swiper/bundle";
import "swiper/swiper-bundle.css";
import Viewer from "viewerjs";
import "viewerjs/dist/viewer.css";
export default {
  name: "pageContent",
  data() {
    return {
      catalogLength: 2, // 总章节数
      showCatalogList: [], // 显示的章节
      loadThreshold: 300, // 触发加载阈值
      throttleThreshold: 100, // 节流阈值
      previousScrollTop: 0,
      throttledScrollHandler: null,
      observer: null,
      loadPageObserver: null,
      loadPageList: [],
      questionDataMap: {},
      renderSignMap: {},
      highlightData: null,
      audioPath: "",
      currentTime: null,
      videoList: [],
    };
  },
  computed: {
    fontSize() {
      this.transformDom(this.$store.state.qiankun.fontSize);
      return this.$store.state.qiankun.fontSize
        ? this.$store.state.qiankun.fontSize
        : 16;
    },
    pageZoom() {
      return this.$store.state.qiankun.scale
        ? this.$store.state.qiankun.scale / 100
        : 1;
    },
  },
  watch: {
    showCatalogList: {
      handler(newVal, oldVal) {
        if (
          this.$store.state.qiankun &&
          this.$store.state.qiankun.catalogChange
        ) {
          // 调用父层方法
          this.$store.state.qiankun.catalogChange({
            showCatalogList: newVal,
          });
        }
        // 启动页码观察
        setTimeout(() => {
          this.initObservation();
          this.initThemeColor();
        }, 500);
      },
    },
    loadPageList: {
      handler(newVal, oldVal) {
        setTimeout(() => {
          this.transformDom(this.$store.state.qiankun.fontSize);
          this.initSwiper();
          this.initViewer();
          this.closeAudio();
          this.closeVideo();
        }, 200);
      },
    },
    pageZoom: {
      handler(newVal, oldVal) {
        const scrollBox = (
          this.container ? this.container : document
        ).querySelector(".page-main");
        scrollBox.scrollTop = (scrollBox.scrollTop / oldVal) * newVal;
      },
    },
  },
  mounted() {
    // 默认加载章节
    this.showCatalogList = [1];
    // 滚动监听节流
    this.throttledScrollHandler = _.throttle(
      this.scrollFun,
      this.throttleThreshold,
      { leading: true, trailing: false }
    );
    // 定义子层方法
    if (this.setGlobalState) {
      // 提供页面跳转功能
      this.setGlobalState({
        gotoPage: (catalog, page) => {
          this.gotoPage(catalog, page);
        },
        // 渲染笔记、高亮、划线
        renderSign: (type, data) => {
          // 因为调整为页面懒加载,所以渲染标记也需要按照页面进行处理,先储存数据,页面加载完成再渲染对应的标记;
          this.handelSignData(type, data);
          // this.renderSign(type, data);
        },
        // 删除笔记、高亮、划线
        delSign: (data) => {
          this.delSign(data);
        },
        // 全文检索
        searchBookByKeyword: (keyword) => {
          return this.searchTextByPage(keyword);
        },
        // 跳转检索结果位置
        jumpSearchItem: (data) => {
          this.searchItemLocation(data);
        },
      });
    }
    // 创建一个新的 Intersection Observer 实例,用于观察目标元素和执行相应的回调函数。
    // new IntersectionObserver(callback, options):使用之前定义的 callback 回调函数和 options 配置选项来初始化 Intersection Observer 实例。
    this.observer = new IntersectionObserver(this.pageChangeCallback, {
      root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
      rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
      threshold: 0.5, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    this.loadPageObserver = new IntersectionObserver(this.loadPageCallback, {
      root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
      rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
      threshold: 0, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    // 启动页码观察
    setTimeout(() => {
      this.initObservation();
      this.initThemeColor();
    }, 500);
    // 测试页面跳转
    setTimeout(() => {
      // this.gotoPage(11, 290);
      //   setTimeout(() => {
      //     this.renderSign("Highlight", {
      //       id: "2ACA9359",
      //       txt: "题一学习主题一 运动",
      //       page: "10",
      //       type: "Highlight",
      //       color: "#F5E12A"
      //     });
      // setTimeout(() => {
      //   this.delSign({
      //     ids: ["2ACA9359"]
      //   });
      // }, 2000);
    }, 500);
    // const pageDom = (this.container ? this.container : document)
    //   .querySelector("#app")
    //   .querySelectorAll(".page-box");
    // 检索
    // console.log(this.searchTextByPage("保护内脏器官"), "searchTextByPage");
    // 检索跳转
    // this.searchItemLocation({
    //   catalog: 2,
    //   page: 10,
    //   txt: " 运动系统是由骨、骨连结和骨骼肌三部分组成的。全身的骨通过骨连结组成人体骨骼(见图1-1)。骨骼是人体的支架,具有保护内脏器官、供肌肉附着和作为肌肉运动的杠杆等作用。在神经系统的支配下,肌肉收缩牵动所附着的骨绕着关节转动,使身体产生各种动作。所以,运动系统具有运动、支持和保护等功能,幼年时期的骨骼还具有造血功能。 ",
    //   txtIndex: 57
    // });
    // }, 500);
  },
  methods: {
    // setZoom1() {
    //   let scale = this.$store.state.qiankun.scale + 10;
    //   const scrollBox = (
    //     this.container ? this.container : document
    //   ).querySelector(".page-main");
    //   this.$store.commit("setZoom", scale);
    // },
    // setZoom2() {
    //   let scale = this.$store.state.qiankun.scale - 10;
    //   const scrollBox = (
    //     this.container ? this.container : document
    //   ).querySelector(".page-main");
    //   this.$store.commit("setZoom", scale);
    // },
    // 滚动监听
    scrollFun(event) {
      this.handleVideoPicture();
      // 判断向上滚动还是向下滚动
      if (event.target.scrollTop > this.previousScrollTop) {
        this.getAduio();
        // 向下
        const currentScrollTop =
          event.target.scrollTop + event.target.offsetHeight;
        if (
          currentScrollTop >=
          event.target.scrollHeight - this.loadThreshold
        ) {
          console.log(1);
          // 到达阈值
          if (
            this.showCatalogList[this.showCatalogList.length - 1] <
            this.catalogLength
          ) {
            // 加载下一章
            this.showCatalogList.push(
              this.showCatalogList[this.showCatalogList.length - 1] + 1
            );
            if (this.showCatalogList.length > 3) {
              // 超过三章隐藏顶部一章
              this.showCatalogList.shift();
            }
          }
        }
      } else if (event.target.scrollTop < this.previousScrollTop) {
        this.handleAudio();
        // 向上
        const currentScrollTop = event.target.scrollTop;
        if (currentScrollTop <= this.loadThreshold) {
          // 到达阈值
          if (this.showCatalogList[0] > 0) {
            // 加载上一章
            this.showCatalogList.unshift(this.showCatalogList[0] - 1);
            if (this.showCatalogList.length > 3) {
              // 超过三章隐藏底部一章
              this.showCatalogList.pop();
            }
          }
        }
      }
      // showCatalogList 当前显示的三个章节,watch监听传递给主应用
      // 更新上一次滚动的位置
      this.previousScrollTop = event.target.scrollTop;
    },
    // 章节、页面跳转
    gotoPage(catalog, page) {
      if (catalog >= 0 && catalog <= this.catalogLength) {
        // 处理渲染章节
        if (catalog == 0) {
          this.showCatalogList = [0, 1];
        } else if (catalog == this.catalogLength) {
          this.showCatalogList = [
            this.catalogLength - 2,
            this.catalogLength - 1,
            this.catalogLength,
          ];
        } else {
          this.showCatalogList = [catalog - 1, catalog, catalog + 1];
        }
        setTimeout(() => {
          // 跳转页码
          const pageDom = (
            this.container ? this.container : document
          ).querySelector(`[page="${page}"]`);
          if (pageDom) {
            pageDom.scrollIntoView();
          } else {
            console.log("页码错误!");
          }
        }, 500);
      } else {
        console.log("章节错误!");
      }
    },
    // 处理标记数据
    handelSignData(type, data) {
      if (this.loadPageList.indexOf(Number(data.page)) > -1) {
        // 立即渲染
        this.renderSign(type, data);
      }
      // 储存数据
      if (!this.renderSignMap[type]) this.renderSignMap[type] = {};
      if (!this.renderSignMap[type][data.page])
        this.renderSignMap[type][data.page] = [];
      this.renderSignMap[type][data.page].push(data);
    },
    // 渲染标记
    renderSign(type, data) {
      // 父层设置禁止渲染标记时不再进行渲染
      if (this.$store.state.qiankun.disableSign) {
        return false;
      }
      const existence = (
        this.container ? this.container : document
      ).querySelector(`[dataid="${data.id}"]`);
      // 去重
      if (!existence) {
        const pageDom = (
          this.container ? this.container : document
        ).querySelector(`[page="${data.page}"]`);
        // 创建 createTreeWalker 迭代器,用于遍历文本节点,保存到一个数组
        const treeWalker = document.createTreeWalker(
          pageDom,
          NodeFilter.SHOW_TEXT
        );
        const allTextNodes = [];
        let currentNode = treeWalker.nextNode();
        while (currentNode) {
          allTextNodes.push(currentNode);
          currentNode = treeWalker.nextNode();
        }
        for (let i = 0; i < allTextNodes.length; i++) {
          const textDom = allTextNodes[i];
          if (textDom.textContent.indexOf(data.txt) > -1) {
            let reg = new RegExp(`${data.txt}`, "ig");
            switch (type) {
              case "Highlight":
                // 高亮
                textDom.parentNode.innerHTML =
                  textDom.parentNode.innerHTML.replace(
                    reg,
                    `<span datatype="Highlight" dataid="${data.id}" style="background: ${data.color};" class="highLight" onclick="signClick('Highlight','${data.id}','${data.chapterNum}')">${data.txt}</span>`
                  );
                break;
              case "Dashing":
                // 划线
                textDom.parentNode.innerHTML =
                  textDom.parentNode.innerHTML.replace(
                    reg,
                    `<span datatype="Dashing" dataid="${data.id}" style="text-decoration-color:${data.color};" class="underline" onclick="signClick('Dashing','${data.id}','${data.chapterNum}')">${data.txt}</span>`
                  );
                break;
              case "Note":
                // 笔记
                textDom.parentNode.innerHTML =
                  textDom.parentNode.innerHTML.replace(
                    reg,
                    `<span datatype="Note" dataid="${data.id}" style="border-bottom-color:${data.color}" class="notesline" onclick="signClick('Note','${data.id}','${data.chapterNum}')" onmouseover="noteHover('Note','${data.id}','${data.chapterNum}')" onmouseout="noteOut('Note')">${data.txt}<img src="${NoteIcon}"/></span>`
                  );
                break;
            }
          }
        }
      }
    },
    // 删除标记渲染
    delSign({ ids, type }) {
      if (ids && ids.length) {
        for (let i = 0; i < ids.length; i++) {
          const id = ids[i];
          const dom = (
            this.container ? this.container : document
          ).querySelector(`[dataid="${id}"]`);
          dom.parentNode.innerHTML = dom.parentNode.innerHTML.replace(
            dom.outerHTML,
            dom.outerText
          );
        }
      }
      if (type) {
        const doms = (
          this.container ? this.container : document
        ).querySelectorAll(`[datatype="${type}"]`);
        for (let i = 0; i < doms.length; i++) {
          const dom = doms[i];
          dom.parentNode.innerHTML = dom.parentNode.innerHTML.replace(
            dom.outerHTML,
            dom.outerText
          );
        }
      }
    },
    initObservation() {
      const sections = (
        this.container ? this.container : document
      ).querySelectorAll(".page-box");
      sections.forEach((section) => {
        if (this.config.activeBook && this.config.activeBook.tryPageCount) {
          const page = section.getAttribute("page");
          if (Number(page) > this.config.activeBook.tryPageCount) {
            let chapterDom = this.getParentWithClass(section, "chapter");
            const chapterNum = chapterDom.getAttribute("num");
            this.catalogLength = Number(chapterNum) - 1;
            section.remove();
            return false;
          }
        }
        // observer 观察每个元素,以便在它们进入或离开视窗时触发回调函数。
        const isObserver = section.getAttribute("observer");
        const isLoadObserver = section.getAttribute("loadObserver");
        if (!isObserver) {
          this.observer.observe(section);
          section.setAttribute("observer", "1");
        }
        if (!isLoadObserver) {
          this.loadPageObserver.observe(section);
          section.setAttribute("loadObserver", "1");
        }
      });
    },
    initThemeColor() {
      // 获取各种需要主题色的节点
      const colorDom = (
        this.container ? this.container : document
      ).querySelectorAll(".theme-color");
      const backgroundColorDom = (
        this.container ? this.container : document
      ).querySelectorAll(".theme-back");
      const borderColorDom = (
        this.container ? this.container : document
      ).querySelectorAll(".theme-border");
      // 获取配置的主题色
      const bookThemeColor =
        this.config.activeBook && this.config.activeBook.bookThemeColor
          ? this.config.activeBook.bookThemeColor
          : null;
      const chapterThemeColor =
        this.config.activeBook && this.config.activeBook.chapterThemeColor
          ? this.config.activeBook.chapterThemeColor
          : null;
      const pageThemeColor =
        this.config.activeBook && this.config.activeBook.pageThemeColor
          ? this.config.activeBook.pageThemeColor
          : null;
      colorDom.forEach((domItem) => {
        // 获取章节、页码
        let pageDom = this.getParentWithClass(domItem, "page-box");
        let chapterDom = this.getParentWithClass(domItem, "chapter");
        let page, chapterNum;
        if (pageDom) page = pageDom.getAttribute("page");
        if (chapterDom) chapterNum = chapterDom.getAttribute("num");
        // 向上匹配主题色
        const themeColor =
          page && pageThemeColor && pageThemeColor[page]
            ? pageThemeColor[page]
            : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum]
              ? chapterThemeColor[chapterNum]
              : bookThemeColor;
        if (themeColor) {
          domItem.style.color = themeColor;
        }
      });
      backgroundColorDom.forEach((domItem) => {
        // 获取章节、页码
        let pageDom = this.getParentWithClass(domItem, "page-box");
        let chapterDom = this.getParentWithClass(domItem, "chapter");
        let page, chapterNum;
        if (pageDom) page = pageDom.getAttribute("page");
        if (chapterDom) chapterNum = chapterDom.getAttribute("num");
        // 向上匹配主题色
        const themeColor =
          page && pageThemeColor && pageThemeColor[page]
            ? pageThemeColor[page]
            : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum]
              ? chapterThemeColor[chapterNum]
              : bookThemeColor;
        if (themeColor) {
          domItem.style.backgroundColor = themeColor;
        }
      });
      borderColorDom.forEach((domItem) => {
        // 获取章节、页码
        let pageDom = this.getParentWithClass(domItem, "page-box");
        let chapterDom = this.getParentWithClass(domItem, "chapter");
        let page, chapterNum;
        if (pageDom) page = pageDom.getAttribute("page");
        if (chapterDom) chapterNum = chapterDom.getAttribute("num");
        // 向上匹配主题色
        const themeColor =
          page && pageThemeColor && pageThemeColor[page]
            ? pageThemeColor[page]
            : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum]
              ? chapterThemeColor[chapterNum]
              : bookThemeColor;
        if (themeColor) {
          domItem.style.borderColor = themeColor;
        }
      });
    },
    getParentWithClass(element, className) {
      while (element.parentElement) {
        element = element.parentElement;
        if (element.classList.contains(className)) {
          return element;
        }
      }
    },
    pageChangeCallback(entries, observer) {
      //entries:代表观察到的目标元素的集合。 observer:代表观察者对象。
      entries.forEach((entry) => {
        //entry.isIntersecting:检查当前目标元素是否与根元素相交。
        if (entry.isIntersecting) {
          const target = entry.target;
          //entry.target:获取当前目标元素
          const page = target.getAttribute("page");
          const catalogDom = this.tool.getParentNodeByClassName(
            target,
            "chapter"
          );
          const catalog = catalogDom.getAttribute("num");
          let text = null;
          if (target.querySelector("p")) {
            text = target.querySelector("p").textContent.substring(0, 50);
          }
          // 返回页码和章节信息
          if (this.$store.state.qiankun && this.$store.state.qiankun.pageChange)
            this.$store.state.qiankun.pageChange({
              page: page,
              catalog: catalog,
              text,
            });
          // const sections = Array.from(document.querySelectorAll(".section"));
          //sections:获取所有具有 .section 类名的元素,并转换为数组。
          // let index = sections.findIndex((section) => section === target) + 1;
          //index:查找当前目标元素在 sections 数组中的索引,并加 1,用于确定当前页码。
        }
      });
    },
    loadPageCallback(entries, observer) {
      entries.forEach(async (entry) => {
        if (entry.isIntersecting) {
          const target = entry.target;
          const page = target.getAttribute("page");
          if (this.loadPageList.indexOf(Number(page)) == -1) {
            const catalogDom = this.tool.getParentNodeByClassName(
              target,
              "chapter"
            );
            // 添加页码
            this.loadPageList.push(Number(page));
            const catalog = catalogDom.getAttribute("num");
            // if (!this.questionDataMap[page]) {
            //   if (testData && testData[catalog]) {
            //     if (testData[catalog][page]) {
            //       if (Array.isArray(testData[catalog][page])) {
            //         const datas = await getQuestionList(
            //           page,
            //           testData[catalog][page],
            //           this.config.activeBook
            //         );
            //         this.$set(this.questionDataMap,page,datas)
            //       } else {
            //         const obj = {};
            //         for (let key in testData[catalog][page]) {
            //           obj[key] = await getQuestionList(
            //             [],
            //             testData[catalog][page][key],
            //             this.config.activeBook
            //           );
            //         }
            //         this.$set(this.questionDataMap,page,obj)
            //         // this.questionDataMap[page] = obj;
            //       }
            //     }
            //   }
            // }
            // 渲染这一页的标记
            for (const key in this.renderSignMap) {
              if (this.renderSignMap[key][page]) {
                this.renderSignMap[key][page].forEach((item) => {
                  this.renderSign(key, item);
                });
              }
            }
            // 处理高亮
            if (this.highlightData) {
              // 高亮行
              setTimeout(() => {
                // 获取页面所有text节点
                const pageTextList = document.createTreeWalker(
                  target,
                  NodeFilter.SHOW_TEXT
                );
                // 匹配关键字
                const allPageTextNodes = [];
                let currentNode = pageTextList.nextNode();
                while (currentNode) {
                  allPageTextNodes.push(currentNode);
                  currentNode = pageTextList.nextNode();
                }
                for (let i = 0; i < allPageTextNodes.length; i++) {
                  const textDom = allPageTextNodes[i];
                  let txtIndex = textDom.textContent.indexOf(
                    this.highlightData.txt
                  );
                  if (txtIndex > -1) {
                    textDom.parentNode.style.transition =
                      "background-color 0.8s";
                    textDom.parentNode.scrollIntoView();
                    textDom.parentNode.style.backgroundColor = "#79bbf0";
                    setTimeout(() => {
                      textDom.parentNode.style.backgroundColor = "";
                    }, 1000);
                  }
                }
              }, 100);
            }
            if (this.loadPageList.length > 5) {
              // 超过5页
              this.loadPageList.shift();
            }
          }
        }
      });
    },
    initSwiper() {
      const doms = (
        this.container ? this.container : document
      ).querySelectorAll(".swiper-img");
      for (let i = 0; i < doms.length; i++) {
        const dom = doms[i];
        new Swiper(dom, {
          loop: false, // 无缝
          autoplay: {
            //自动开始
            delay: 3000, //时间间隔
            disableOnInteraction: false, //*手动操作轮播图后不会暂停*
          },
          paginationClickable: true,
          slidesPerView: 1, // 一组三个
          spaceBetween: 30, // 间隔
          // 如果需要前进后退按钮
          navigation: {
            nextEl: dom.querySelector(".swiper-button-next"),
            prevEl: dom.querySelector(".swiper-button-prev"),
          },
          // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
          // observer: true,
          // observeParents: true
          // // 如果需要分页器
          // pagination: {
          //   el: (this.container ? this.container : document).querySelector(
          //     ".swiper-pagination"
          //   ),
          //   clickable: true // 分页器可以点击
          // }
        });
      }
      const pptDoms = (
        this.container ? this.container : document
      ).querySelectorAll(".swiper_ppt");
      for (let i = 0; i < pptDoms.length; i++) {
        const dom = pptDoms[i];
        new Swiper(dom, {
          loop: false, // 无缝
          autoplay: false,
          paginationClickable: true,
          slidesPerView: 1, // 一组三个
          spaceBetween: 30, // 间隔
          // 如果需要前进后退按钮
          navigation: {
            nextEl: dom.querySelector(".swiper-button-next"),
            prevEl: dom.querySelector(".swiper-button-prev"),
          },
          // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
          observer: true,
          observeParents: true,
          on: {
            init: (value) => {
              let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数)
              let totalPages = value.slides.length; // 获取总页数
              var paginationInfoEl = dom.querySelector(".pageBox");
              if (paginationInfoEl)
                paginationInfoEl.textContent = currentPage + "/" + totalPages;
            },
            slideChange: (value) => {
              let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数)
              let totalPages = value.slides.length; // 获取总页数
              var paginationInfoEl = dom.querySelector(".pageBox");
              if (paginationInfoEl)
                paginationInfoEl.textContent = currentPage + "/" + totalPages;
            },
          },
        });
      }
    },
    initViewer() {
      const doms = (
        this.container ? this.container : document
      ).querySelectorAll(".openImgBox");
      for (let i = 0; i < doms.length; i++) {
        const dom = doms[i];
        new Viewer(dom, {
          container: this.container
            ? this.container.querySelector("#app")
            : "body",
          navbar: true, // 显示导航栏
          toolbar: true, // 显示工具栏
          title: true, // 显示标题
        });
      }
    },
    // 根据关键字全文检索
    searchTextByPage(keyword) {
      const searchResult = [];
      let catalogIndex = 0;
      // 所有章节组件(每本书制作时单独配置)
      const pageData = {
        pageHeader,
        chapterOne,
      };
      // 遍历所有章节文件
      for (const key in pageData) {
        catalogIndex++;
        let pageComponent, pageExample;
        // 先渲染一次当前章节文件(这时页面的内容为空),获取页码信息
        pageComponent = Vue.extend(pageData[key]);
        pageExample = new pageComponent({
          propsData: {
            showPageList: [],
            questionData: {},
            isSearch: true,
          },
        });
        pageExample.$mount(
          (this.container ? this.container : document).querySelector(
            "#searchContent"
          )
        );
        // 获取页码
        const pageDom = (this.container ? this.container : document)
          .querySelector("#searchDomBox")
          .querySelectorAll(".page-box");
        const pages = [];
        for (let i = 0; i < pageDom.length; i++) {
          const pageDomItem = pageDom[i];
          pages.push(Number(pageDomItem.getAttribute("page")));
        }
        // 获取页面结束,卸载销毁
        pageExample.$destroy();
        (this.container ? this.container : document).querySelector(
          "#searchDomBox"
        ).innerHTML = '<div id="searchContent"></div>';
        // 遍历页码
        if (pages.length) {
          for (let i = 0; i < pages.length; i++) {
            const pageNum = pages[i];
            // 动态渲染对应章节的页码
            pageComponent = Vue.extend(pageData[key]);
            pageExample = new pageComponent({
              propsData: {
                showPageList: [pageNum],
                questionData: {},
                isSearch: true,
              },
            });
            pageExample.$mount(
              (this.container ? this.container : document).querySelector(
                "#searchContent"
              )
            );
            // 获取对应页面dom
            const thisPageDom = (this.container ? this.container : document)
              .querySelector("#searchDomBox")
              .querySelector(`[page="${pageNum}"]`);
            if (thisPageDom) {
              // 获取页面所有text节点
              const pageTextList = document.createTreeWalker(
                thisPageDom,
                NodeFilter.SHOW_TEXT
              );
              // 匹配关键字
              const allPageTextNodes = [];
              let currentNode = pageTextList.nextNode();
              while (currentNode) {
                allPageTextNodes.push(currentNode);
                currentNode = pageTextList.nextNode();
              }
              for (let i = 0; i < allPageTextNodes.length; i++) {
                const textDom = allPageTextNodes[i];
                let txtIndex = textDom.textContent.indexOf(keyword);
                if (txtIndex > -1) {
                  // 记录关键字所在页码、章节以及匹配到的段落
                  searchResult.push({
                    page: pageNum,
                    catalog: catalogIndex,
                    txt: textDom.textContent,
                    txtIndex: txtIndex,
                  });
                }
              }
              // 结束,卸载销毁
              pageExample.$destroy();
              (this.container ? this.container : document).querySelector(
                "#searchDomBox"
              ).innerHTML = '<div id="searchContent"></div>';
            }
          }
        }
      }
      // 输出搜索结果
      console.log(searchResult);
      return searchResult;
    },
    // 根据检索结果跳转对应位置并高亮
    searchItemLocation(data) {
      // 记录高亮信息
      this.highlightData = data;
      // 跳转
      this.gotoPage(data.catalog, data.page, () => { });
    },
    // 页面向下滚动,音频小窗播放功能
    getAduio() {
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      allVideo = Array.from(allVideo);
      this.videoList = allVideo;
      if (allVideo.length) {
        // 查找播放状态的最后一条音频
        const playAudio = allVideo
          .reverse()
          .find((item) => item.paused == false);
        if (playAudio) {
          const bottomGap = playAudio.getBoundingClientRect().bottom;
          if (bottomGap < 0) {
            playAudio.pause();
            this.audioPath = playAudio.src;
            this.currentTime = playAudio.currentTime;
          }
        }
      }
    },
    // 页面向上滚动,音频小窗回收
    handleAudio() {
      if (!this.audioPath) return false;
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      allVideo = Array.from(allVideo);
      if (allVideo.length) {
        //查找与小窗播放音频同源的页面audio DOM
        const playAudio = allVideo.find((item) => item.src == this.audioPath);
        if (playAudio) {
          const bottomGap = playAudio.getBoundingClientRect().bottom;
          if (bottomGap >= 0) {
            if (this.$refs.audioPlayer) {
              const playerState = this.$refs.audioPlayer.getVideoPlayer();
              this.audioPath = "";
              playAudio.currentTime = playerState.currentTime;
              if (!playerState.paused) playAudio.play();
            }
          }
        }
      }
    },
    // 关闭mini video
    closeMiniAudio() {
      this.audioPath = "";
    },
    // 点击音频播放,关闭其他音频
    closeAudio() {
      let allAudio = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      for (let index = 0; index < allAudio.length; index++) {
        const item = allAudio[index];
        item.addEventListener("play", () => {
          const audioList = Array.from(allAudio);
          for (let cindex = 0; cindex < audioList.length; cindex++) {
            const citem = audioList[cindex];
            if (citem.currentSrc != item.src) {
              citem.pause();
            }
          }
          this.closeMiniAudio();
        });
      }
    },
    // 点击视频关闭其他
    closeVideo() {
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".video");
      for (let index = 0; index < allVideo.length; index++) {
        const item = allVideo[index];
        item.addEventListener("playing", (item) => {
          const path = item.srcElement.src;
          const videoList = Array.from(allVideo);
          for (let cindex = 0; cindex < videoList.length; cindex++) {
            const citem = videoList[cindex];
            if (citem.currentSrc != path && path) {
              citem.pause();
            }
          }
        });
      }
    },
    // 视频小窗
    handleVideoPicture() {
      let doms = (this.container ? this.container : document).querySelectorAll(
        ".video"
      );
      doms = Array.from(doms);
      if (!doms.length) return false;
      const playVudio = doms.reverse().find((item) => item.paused == false);
      if (playVudio) {
        const bottomGap = playVudio.getBoundingClientRect().bottom;
        const topGap = playVudio.getBoundingClientRect().top;
        if (bottomGap < 0 || topGap > window.innerHeight) {
          try {
            if (playVudio.readyState) playVudio.requestPictureInPicture();
          } catch (error) {
            console.log(error, "小窗错误error");
          }
        }
      }
    },
    //其他类名下字体大小变化
    transformDom(fs) {
      if (!fs) return;
      let doms = (this.container ? this.container : document).querySelectorAll(
        ".block"
      );
      if (!doms.length) return;
      for (let index = 0; index < doms.length; index++) {
        const dom = doms[index];
        dom.style.fontSize = fs + "px";
      }
    },
  },
  components: {
    pageHeader,
    chapterOne,
  },
};
</script>
<style lang="less" scoped>
.page-main {
  width: 100% !important;
  height: 100% !important;
  overflow: auto;
  .page-content {
    max-width: 816px;
    min-width: 375px;
    margin: 0 auto;
    padding-bottom: 100px;
  }
}
</style>
src/books/foodSensoryInspection/view/index.vue
New file
@@ -0,0 +1,80 @@
<template>
    <div class="foodSensoryInspection" @mouseup="handleMouseUp">
      <pageContent></pageContent>
    </div>
  </template>
  <script>
  import pageContent from "./components/index.vue";
  export default {
    name: "foodSensoryInspection",
    components: {
      pageContent,
    },
    computed: {
      fontSize() {
        return this.$store.state.qiankun.fontSize;
      },
      pageZoom() {
        return this.$store.state.qiankun.scale / 100;
      },
    },
    methods: {
      getParentWithClass(element, className) {
        while (element.parentElement) {
          element = element.parentElement;
          if (element.classList.contains(className)) {
            return element;
          }
        }
      },
      handleMouseUp(e) {
        const selection = (
          this.container ? this.container : window
        ).getSelection();
        const txt = selection.toString();
        if (selection.type != "none" && txt) {
          let node = selection.anchorNode.parentNode;
          let pageHtml = this.getParentWithClass(
            selection.anchorNode,
            "page-box"
          );
          let chapterDom = this.getParentWithClass(
            selection.anchorNode,
            "chapter"
          );
          let chapterNum;
          if (chapterDom) chapterNum = chapterDom.getAttribute("num");
          if (pageHtml) {
            const page = pageHtml.getAttribute("page");
            // 监听选中文本事件,并触发父层方法
            if (this.$store.state.qiankun.windowSelection) {
              this.$store.state.qiankun.windowSelection({
                chapterNum,
                txt,
                page,
                x: e.x,
                y: e.y,
              });
            }
          }
        } else {
          if (this.$store.state.qiankun.windowSelection) {
            this.$store.state.qiankun.windowSelection({
              chapterNum: "",
              txt: "",
              page: "",
              x: e.x,
              y: e.y,
            });
          }
        }
      },
    },
  };
  </script>
  <style lang="less">
  @import "../assets/main.less";
  </style>