Browse Source

增加资源库

黄琪勇 1 month ago
parent
commit
be92443b2e

+ 25 - 0
src/types/slides.ts

@@ -635,6 +635,30 @@ export interface PPTCloudCoachElement extends PPTBaseElement {
   title: string
 }
 
+/**
+ * 音频播放器控件
+ *
+ * type: elf
+ *
+ * subtype: elf-enjoy
+ *
+ * sid: 音频id
+ *
+ * title:音频名称
+ */
+export interface PPTEnjoyElement extends PPTBaseElement {
+  type: "elf"
+  subtype: "elf-enjoy"
+  sid: string
+  title: string
+  src: string
+  enjoyList: {
+    id: string
+    title: string
+    src: string
+  }[]
+}
+
 export type PPTElement =
   | PPTTextElement
   | PPTImageElement
@@ -646,6 +670,7 @@ export type PPTElement =
   | PPTVideoElement
   | PPTAudioElement
   | PPTCloudCoachElement
+  | PPTEnjoyElement
 
 export type AnimationType = "in" | "out" | "attention"
 export type AnimationTrigger = "click" | "meantime" | "auto"

+ 2 - 0
src/views/components/element/enjoyElement/resourcesList/index.ts

@@ -0,0 +1,2 @@
+import resourcesList from "./resourcesList.vue"
+export default resourcesList

+ 832 - 0
src/views/components/element/enjoyElement/resourcesList/resourcesList.vue

@@ -0,0 +1,832 @@
+<template>
+  <div class="resourcesList">
+    <div class="headCon">
+      <div class="headLeft">
+        <img class="tipImg" src="@/views/Editor/CanvasTool/imgs/zyk.png" alt="" />
+        <div class="title">资源库</div>
+      </div>
+      <div class="headright">
+        <img @click="emits('close')" class="closeBtn" src="../../cloudCoachElement/cloudCoachList/imgs/close.png" alt="" />
+      </div>
+    </div>
+    <div class="content">
+      <div class="tabTools">
+        <div class="tabCon">
+          <div
+            class="tab"
+            @click="handleTabChange(item.value)"
+            :class="{ active: item.value === queryData.sourceType }"
+            v-for="item in tabData"
+            :key="item.value"
+          >
+            {{ item.label }}
+          </div>
+        </div>
+        <div></div>
+      </div>
+      <div class="typeTools">
+        <div class="typeTabCon"></div>
+        <div class="query">
+          <Input :placeholder="'请输入搜索关键词'" v-model:value="queryData.name" @enter="handleQuery">
+            <template #prefix>
+              <img class="img" src="../../cloudCoachElement/cloudCoachList/imgs/query.png" alt="" />
+            </template>
+            <template #suffix>
+              <div class="queryBtn" @click="handleQuery">搜索</div>
+            </template>
+          </Input>
+        </div>
+      </div>
+      <div class="musicListCon">
+        <div class="queryFrom" :class="{ isExpandAct: !isExpand }">
+          <div v-show="queryData.sourceType === 2" class="queryFromList">
+            <div class="tit">教程:</div>
+            <div class="queryFromCon">
+              <div
+                v-for="item in musicTagList"
+                :key="item.id"
+                @click="handleMusicTagChange(item.id)"
+                :class="['queryTip', queryData.bookVersionId === item.id && 'active']"
+              >
+                {{ item.name }}
+              </div>
+            </div>
+          </div>
+          <div v-show="queryData.sourceType !== 3" class="queryFromList">
+            <div class="tit">场景:</div>
+            <div class="queryFromCon">
+              <div
+                v-for="item in audioPlayTypesOption"
+                :key="item.value"
+                @click="handleAudioPlayTypesChange(item.value)"
+                :class="['queryTip', queryData.audioPlayTypes === item.value && 'active']"
+              >
+                {{ item.text }}
+              </div>
+            </div>
+          </div>
+          <div v-show="queryData.audioPlayTypes !== 'SING'" class="queryFromList">
+            <div class="tit">乐器:</div>
+            <div class="queryFromCon">
+              <template v-for="item in subjectList">
+                <div
+                  :class="['queryTip', queryData.subject.id === item.instruments[0].id && 'active']"
+                  @click="handleSubjectChange(item.instruments[0])"
+                  v-if="item.instruments.length === 1"
+                  :key="item.id"
+                >
+                  {{ item.instruments[0].name }}
+                </div>
+                <Popover v-model:value="item.isExpand" trigger="mouseenter" v-else :offset="-4" :key="item.id + '_'">
+                  <template #content>
+                    <PopoverMenuItem
+                      @click="
+                        () => {
+                          item.isExpand = false
+                          handleSubjectChange(row)
+                        }
+                      "
+                      v-for="row in item.instruments"
+                      :key="row.id"
+                      :active="row.id === queryData.subject.id"
+                      >{{ row.name }}</PopoverMenuItem
+                    >
+                  </template>
+                  <div class="queryTip" :class="{ hoverActive: isActiveSubjectPop(item) }">
+                    <div>{{ isActiveSubjectPop(item) ? queryData.subject.name : item.name }}</div>
+                    <img src="../../cloudCoachElement/cloudCoachList/imgs/jt.png" alt="" />
+                  </div>
+                </Popover>
+              </template>
+            </div>
+          </div>
+        </div>
+        <div v-show="queryData.sourceType === 2" @click="isExpand = !isExpand" class="isExpand" :class="{ active: isExpand }">
+          <div>{{ isExpand ? "收起" : "展开" }}</div>
+          <img src="../../cloudCoachElement/cloudCoachList/imgs/jiao.png" alt="" />
+        </div>
+        <div class="musicListConBox" v-loading="loading">
+          <div class="musicList" :class="{ empty: !musicList.length && !loading }">
+            <div class="musicListBox" v-if="musicList.length && !loading">
+              <div class="musicCon" v-for="item in musicList" :key="item.id">
+                <div class="musicLeft">
+                  <div class="iconCon">
+                    <img class="icon" :src="item.titleImg" alt="" />
+                    <img v-if="item.sourceFrom === 'PLATFORM'" class="jxImg" src="../../cloudCoachElement/cloudCoachList/imgs/jx.png" alt="" />
+                  </div>
+                  <div class="musicInfo">
+                    <EllipsisScroll class="musicTit" :title="item.highName || ''" />
+                    <div class="info">
+                      <div class="hotInfo" v-if="item.usedNum">
+                        <img src="../../cloudCoachElement/cloudCoachList/imgs/hot.png" alt="" />
+                        <div>{{ formatNumber(item.usedNum) }}</div>
+                      </div>
+                      <div class="play" v-if="item.audioPlayTypes?.includes('SING')">演唱</div>
+                      <div class="sing" v-if="item.audioPlayTypes?.includes('PLAY')">演奏</div>
+                      <div class="musicUserName">
+                        <EllipsisScroll :title="item.composer || ''" />
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="musicRight">
+                  <img
+                    v-if="queryParams.fromType !== 'PLATFORM'"
+                    class="sc"
+                    @click="handleFavorite(item)"
+                    :src="item.favoriteFlag ? scActImg : scImg"
+                    alt=""
+                  />
+                  <div class="addBtn" @click="handleAddMusic(item.id, item.name)">添加</div>
+                </div>
+              </div>
+            </div>
+            <Empty v-if="!musicList.length && !loading" />
+          </div>
+          <div class="pagination" v-show="musicList.length">
+            <el-pagination layout="prev, pager, next" :default-page-size="21" @current-change="handleCurrentChange" :total="queryData.total" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ElLoading, ElPagination } from "element-plus"
+import Input from "@/components/Input.vue"
+import Popover from "@/components/Popover.vue"
+import PopoverMenuItem from "@/components/PopoverMenuItem.vue"
+import Empty from "@/components/Empty"
+import EllipsisScroll from "@/components/ellipsisScroll"
+import { reactive, ref } from "vue"
+import { getMaterialQueryPage, getSubjectListApi, getMusicTagTreeApi, favoriteApi } from "@/api/pptOperate"
+import { httpAjax } from "@/plugins/httpAjax"
+import queryParams from "@/queryParams"
+import scActImg from "../../cloudCoachElement/cloudCoachList/imgs/scAct.png"
+import scImg from "../../cloudCoachElement/cloudCoachList/imgs/sc.png"
+import { CODE_ERR_CANCELED } from "@/libs/auth"
+
+const emits = defineEmits<{
+  (event: "update", id: string, name: string): void
+  (event: "close"): void
+}>()
+
+function handleAddMusic(id: string, name: string) {
+  emits("update", id, name)
+  emits("close")
+}
+
+const tabData =
+  queryParams.fromType === "PLATFORM"
+    ? [
+        {
+          label: "共享资源",
+          value: 2
+        }
+      ]
+    : [
+        {
+          label: "相关资源",
+          value: 5
+        },
+        {
+          label: "共享资源",
+          value: 2
+        },
+        {
+          label: "我的资源",
+          value: 3
+        },
+        {
+          label: "我的收藏",
+          value: 4
+        }
+      ]
+// 场景
+const audioPlayTypesOption = [
+  { text: "全部", value: "" },
+  { text: "演唱", value: "SING" },
+  { text: "演奏", value: "PLAY" },
+  { text: "演唱+演奏", value: "PLAY,SING" }
+]
+// 教程
+const musicTagList = ref<any[]>([])
+// 乐器
+const subjectList = ref<any[]>([])
+
+const queryData = reactive({
+  page: 1,
+  rows: 21,
+  total: 0,
+  sourceType: tabData[0].value,
+  name: "",
+  bookVersionId: "",
+  audioPlayTypes: "",
+  subject: {
+    id: "",
+    name: ""
+  }
+})
+
+const musicList = ref<any[]>([])
+const loading = ref(true)
+const vLoading = ElLoading.directive
+const isExpand = ref(true)
+
+getQueryList()
+function getQueryList() {
+  Promise.all([httpAjax(getSubjectListApi), httpAjax(getMusicTagTreeApi)]).then(res => {
+    const [subjectListRes, musicTagTreeRes] = res
+    if (subjectListRes.code === 200) {
+      subjectList.value = subjectListRes.data.map((item: any) => {
+        return item.instruments.length > 1 ? Object.assign(item, { isExpand: ref(false) }) : item
+      })
+      // 赋默认值
+      handleSubjectDefault()
+    }
+    if (musicTagTreeRes.code === 200) {
+      musicTagList.value = [
+        { id: "", name: "全部" },
+        ...musicTagTreeRes.data.map((item: any) => {
+          return {
+            id: item.id,
+            name: item.name
+          }
+        })
+      ]
+    }
+    handleQuery()
+  })
+}
+function handleSubjectDefault() {
+  if (subjectList.value.length > 0) {
+    const instruments = subjectList.value.reduce((arr, item) => {
+      arr.push(...item.instruments)
+      return arr
+    }, [])
+    const instrumentId = queryParams.instrumentId
+    // 有id 就用id,没有就默认第一个
+    const instrumentObj = instrumentId
+      ? instruments.find((i: any) => {
+          return i.id === instrumentId
+        })
+      : instruments[0]
+    if (instrumentObj) {
+      queryData.subject.id = instrumentObj.id
+      queryData.subject.name = instrumentObj.name
+    }
+  }
+}
+function clearQueryData() {
+  queryData.page = 1
+  queryData.rows = 21
+  queryData.total = 0
+  queryData.sourceType = 5
+  queryData.name = ""
+  queryData.bookVersionId = ""
+  queryData.audioPlayTypes = ""
+  queryData.subject = {
+    id: "",
+    name: ""
+  }
+  handleSubjectDefault()
+}
+function handleTabChange(sourceType: number) {
+  clearQueryData()
+  isExpand.value = true
+  queryData.sourceType = sourceType
+  handleQuery()
+}
+function handleMusicTagChange(id: string) {
+  queryData.bookVersionId = id
+  handleQuery()
+}
+function handleAudioPlayTypesChange(value: string) {
+  queryData.audioPlayTypes = value
+  handleQuery()
+}
+function handleSubjectChange(item: any) {
+  queryData.subject.id = item.id
+  queryData.subject.name = item.name
+  handleQuery()
+}
+function isActiveSubjectPop(item: any) {
+  return item.instruments.some((i: any) => {
+    return i.id === queryData.subject.id
+  })
+}
+
+function handleCurrentChange(e: number) {
+  queryData.page = e
+  handleGetQuery()
+}
+function handleQuery() {
+  queryData.page = 1
+  queryData.rows = 21
+  handleGetQuery()
+}
+
+let controller: AbortController
+function handleGetQuery() {
+  loading.value = true
+  let { sourceType, subject, audioPlayTypes, name, page, rows, bookVersionId } = queryData
+  let musicalInstrumentId = subject.id
+  const audioPlayTypesParams = audioPlayTypes ? audioPlayTypes.split(",") : []
+  let params: any
+  // 相关资源
+  if (sourceType === 5) {
+    if (audioPlayTypesParams[0] === "SING") {
+      musicalInstrumentId = ""
+    }
+    params = {
+      name,
+      type: "MUSIC",
+      sourceType,
+      musicalInstrumentId,
+      enableFlag: true,
+      page,
+      rows,
+      audioPlayTypes: audioPlayTypesParams,
+      lessonCoursewareKnowledgeId: queryParams.lessonCoursewareKnowledgeId
+    }
+  }
+  if (sourceType === 2) {
+    if (audioPlayTypesParams[0] === "SING") {
+      musicalInstrumentId = ""
+    }
+    params = {
+      name,
+      type: "MUSIC",
+      sourceType,
+      musicalInstrumentId,
+      enableFlag: true,
+      page,
+      rows,
+      audioPlayTypes: audioPlayTypesParams,
+      lessonCoursewareKnowledgeId: queryParams.lessonCoursewareKnowledgeId,
+      bookVersionId
+    }
+  }
+  if (sourceType === 3) {
+    params = {
+      name,
+      type: "MUSIC",
+      sourceType,
+      musicalInstrumentId,
+      enableFlag: true,
+      page,
+      rows
+    }
+  }
+  if (sourceType === 4) {
+    if (audioPlayTypesParams[0] === "SING") {
+      musicalInstrumentId = ""
+    }
+    params = {
+      name,
+      type: "MUSIC",
+      sourceType,
+      musicalInstrumentId,
+      enableFlag: true,
+      page,
+      rows,
+      audioPlayTypes: audioPlayTypesParams
+    }
+  }
+  if (controller) {
+    controller.abort()
+  }
+  controller = new AbortController()
+  httpAjax(getMaterialQueryPage, params, controller).then(res => {
+    // 自己关闭的时候不取消加载
+    if (res.code === CODE_ERR_CANCELED) {
+      return
+    }
+    if (res.code === 200) {
+      musicList.value = res.data.rows.map((item: any) => {
+        item.highName = highlightedText(item.name, queryData.name)
+        return item
+      })
+      queryData.total = res.data.total
+    }
+    loading.value = false
+  })
+}
+
+function handleFavorite(item: any) {
+  httpAjax(favoriteApi, {
+    favoriteFlag: item.favoriteFlag ? 0 : 1,
+    materialId: item.id,
+    type: "MUSIC"
+  }).then(res => {
+    if (res.code === 200) {
+      item.favoriteFlag = !item.favoriteFlag
+    }
+  })
+}
+function formatNumber(num: number) {
+  return num >= 10000 ? (num / 10000).toFixed(1).replace(/\.0$/, "") + "万" : num.toString()
+}
+const highlightedText = (text: string, query: string) => {
+  if (!text) {
+    return ""
+  }
+  if (!query) {
+    return text
+  }
+  const regex = new RegExp(`(${query})`, "gi")
+  return text.replace(regex, '<span class="highlighted">$1</span>')
+}
+</script>
+
+<style lang="scss" scoped>
+.resourcesList {
+  width: 100%;
+  height: 100%;
+  .headCon {
+    width: 100%;
+    height: 64px;
+    border-bottom: 1px solid #eaeaea;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .headLeft {
+      margin-left: 30px;
+      display: flex;
+      align-items: center;
+      .tipImg {
+        width: 24px;
+        height: 24px;
+      }
+      .title {
+        font-weight: 600;
+        font-size: 18px;
+        color: #131415;
+        margin-left: 8px;
+      }
+    }
+    .headright {
+      margin-right: 30px;
+      display: flex;
+      align-items: center;
+      .closeBtn {
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        &:hover {
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+  .content {
+    width: 100%;
+    height: calc(100% - 64px);
+    .tabTools {
+      height: 72px;
+      width: 100%;
+      padding: 18px 30px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .tabCon {
+        display: flex;
+        .tab {
+          margin-right: 32px;
+          font-weight: 400;
+          font-size: 16px;
+          color: #8b8d98;
+          line-height: 22px;
+          cursor: pointer;
+          &:hover {
+            opacity: 0.8;
+          }
+          &:last-child {
+            margin-right: 0;
+          }
+          &.active {
+            font-weight: 600;
+            color: #131415;
+            position: relative;
+            &::after {
+              content: "";
+              position: absolute;
+              width: 100%;
+              height: 10px;
+              background: linear-gradient(90deg, #77bbff 0%, rgba(163, 231, 255, 0.22) 100%);
+              bottom: 0;
+              left: 0;
+              z-index: -1;
+            }
+          }
+        }
+      }
+    }
+    .typeTools {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      .typeTabCon{
+
+      }
+      .query {
+        width: 400px;
+        height: 36px;
+        &::v-deep(.input) {
+          align-items: center;
+          padding: 0 3px 0 12px;
+          border-radius: 18px;
+          height: 100%;
+          &:not(.disabled):hover,
+          &.focused {
+            .img {
+              opacity: 1;
+            }
+            .queryBtn {
+              opacity: 1;
+            }
+          }
+          input {
+            font-size: 14px;
+          }
+          .img {
+            width: 16px;
+            height: 16px;
+            opacity: 0.4;
+          }
+          .queryBtn {
+            width: 60px;
+            height: 30px;
+            background: #198cfe;
+            border-radius: 16px;
+            font-weight: 500;
+            font-size: 14px;
+            color: #ffffff;
+            line-height: 30px;
+            text-align: center;
+            opacity: 0.4;
+            cursor: pointer;
+            &:hover {
+              opacity: 0.8 !important;
+            }
+          }
+        }
+      }
+    }
+    .musicListCon {
+      width: 100%;
+      height: calc(100% - 72px);
+      display: flex;
+      flex-direction: column;
+      .queryFrom {
+        &.isExpandAct {
+          height: 42px;
+          overflow: hidden;
+        }
+        flex-shrink: 0;
+        padding: 0 30px;
+        .queryFromList {
+          display: flex;
+          margin-bottom: 4px;
+          .tit {
+            flex-shrink: 0;
+            font-weight: 500;
+            font-size: 14px;
+            color: #131415;
+            line-height: 32px;
+            margin-right: 16px;
+          }
+          .queryFromCon {
+            display: flex;
+            flex-wrap: wrap;
+            .queryTip {
+              margin: 0 16px 12px 0;
+              font-weight: 400;
+              font-size: 14px;
+              color: rgba(0, 0, 0, 0.6);
+              line-height: 20px;
+              padding: 6px 16px;
+              background: #f5f6fa;
+              border-radius: 6px;
+              cursor: pointer;
+              display: flex;
+              align-items: center;
+              & > img {
+                width: 7px;
+                height: 4px;
+                margin-left: 6px;
+              }
+              &.active,
+              &:hover {
+                background: #d2ecff;
+                color: rgba(0, 0, 0, 1);
+                > img {
+                  transform: rotate(180deg);
+                }
+              }
+              &.hoverActive {
+                background: #d2ecff;
+                color: rgba(0, 0, 0, 1);
+              }
+            }
+          }
+        }
+      }
+      .isExpand {
+        flex-shrink: 0;
+        margin-bottom: 12px;
+        cursor: pointer;
+        display: flex;
+        justify-content: center;
+        font-weight: 400;
+        font-size: 14px;
+        color: #198cfe;
+        line-height: 20px;
+        align-items: center;
+        &:hover {
+          opacity: 0.8;
+        }
+        &.active > img {
+          transform: rotate(0deg);
+        }
+        & > img {
+          transform: rotate(180deg);
+          margin-left: 4px;
+          width: 10px;
+          height: 10px;
+        }
+      }
+      .musicListConBox {
+        flex-grow: 1;
+        overflow: hidden;
+        .musicList {
+          padding: 4px 0;
+          height: calc(100% - 60px);
+          overflow: auto;
+          &.empty {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+          }
+          .musicListBox {
+            width: calc(100% + 24px);
+            margin-left: -24px;
+            display: flex;
+            flex-wrap: wrap;
+            padding: 0 30px;
+            .musicCon {
+              margin-bottom: 24px;
+              width: calc(33.3333% - 24px);
+              margin-left: 24px;
+              padding: 16px;
+              background: #f5f6fa;
+              border-radius: 12px;
+              display: flex;
+              justify-content: space-between;
+              align-items: center;
+              height: 102px;
+              &:nth-last-child(-n + 3) {
+                margin-bottom: 0;
+              }
+              &:hover {
+                outline: 2px solid #198cfe;
+              }
+              .musicLeft {
+                display: flex;
+                align-items: center;
+                margin-right: 14px;
+                overflow: hidden;
+                .iconCon {
+                  position: relative;
+                  .icon {
+                    width: 70px;
+                    height: 70px;
+                    border-radius: 8px;
+                  }
+                  .jxImg {
+                    position: absolute;
+                    left: 0;
+                    top: 0;
+                    width: 34px;
+                    height: 16px;
+                  }
+                }
+                .musicInfo {
+                  margin-left: 12px;
+                  overflow: hidden;
+                  .musicTit {
+                    font-weight: 600;
+                    font-size: 15px;
+                    color: #131415;
+                    line-height: 21px;
+                    &::v-deep(.highlighted) {
+                      color: $themeColor;
+                    }
+                  }
+                  .info {
+                    margin-top: 13px;
+                    display: flex;
+                    align-items: center;
+                    .hotInfo {
+                      margin-right: 4px;
+                      padding: 0 4px;
+                      background: #fff3f3;
+                      border-radius: 3px;
+                      border: 1px solid rgba(254, 67, 67, 0.5);
+                      display: flex;
+                      align-items: center;
+                      justify-content: center;
+                      flex-shrink: 0;
+                      line-height: 16px;
+                      & > img {
+                        width: 10px;
+                        height: 12px;
+                      }
+                      & > div {
+                        margin-left: 2px;
+                        font-weight: 400;
+                        font-size: 12px;
+                        color: #fe4343;
+                      }
+                    }
+                    .play {
+                      margin-right: 4px;
+                      flex-shrink: 0;
+                      padding: 0 4px;
+                      background: #ffffff;
+                      border-radius: 3px;
+                      border: 1px solid rgba(243, 130, 26, 0.5);
+                      font-weight: 400;
+                      font-size: 12px;
+                      color: #f3821a;
+                      line-height: 16px;
+                      text-align: center;
+                    }
+                    .sing {
+                      margin-right: 4px;
+                      flex-shrink: 0;
+                      padding: 0 4px;
+                      background: #ffffff;
+                      border-radius: 3px;
+                      border: 1px solid rgba(21, 178, 253, 0.5);
+                      font-weight: 400;
+                      font-size: 12px;
+                      color: #00adff;
+                      line-height: 16px;
+                      text-align: center;
+                    }
+                    .musicUserName {
+                      overflow: hidden;
+                      font-weight: 400;
+                      font-size: 13px;
+                      color: #777777;
+                      line-height: 16px;
+                    }
+                  }
+                }
+              }
+              .musicRight {
+                flex-shrink: 0;
+                display: flex;
+                align-items: center;
+                .sc {
+                  width: 26px;
+                  height: 26px;
+                  cursor: pointer;
+                  &:hover {
+                    opacity: 0.8;
+                  }
+                }
+                .addBtn {
+                  margin-left: 12px;
+                  width: 54px;
+                  height: 26px;
+                  background: #198cfe;
+                  border-radius: 4px;
+                  font-weight: 600;
+                  font-size: 13px;
+                  color: #ffffff;
+                  line-height: 26px;
+                  text-align: center;
+                  cursor: pointer;
+                  &:hover {
+                    opacity: 0.8;
+                  }
+                }
+              }
+            }
+          }
+        }
+        .pagination {
+          padding: 0 30px;
+          display: flex;
+          justify-content: flex-end;
+          align-items: center;
+          height: 60px;
+        }
+      }
+    }
+  }
+}
+</style>