| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 | <template>  <div class="videoDaysDetail">    <DialogCom title="录像详情" :visible.sync="isShow" width="1100px">      <el-descriptions        title="基础信息"        :column="2"        border        :label-style="labelStyle"        :contentStyle="content_style"        ><el-descriptions-item label="监控主机">{{          data.hostName        }}</el-descriptions-item>        <el-descriptions-item label="通道名称">{{          data.channelName        }}</el-descriptions-item>        <!-- <el-descriptions-item label="IP地址">{{          data.channelIp        }}</el-descriptions-item> -->      </el-descriptions>      <el-tabs type="border-card">        <el-tab-pane label="录像存储情况"><!--          <el-descriptions            title="录像存储天数"            :column="3"            border            :label-style="labelStyle"            :contentStyle="content_style"            v-if="data.storage == null || data.storage.planDays == null"          >            <el-descriptions-item label="存储状态"> 未知 </el-descriptions-item>          </el-descriptions>          <div v-else>            <el-descriptions              title="录像存储天数"              :column="3"              border              :label-style="labelStyle"              :contentStyle="content_style"            >              <el-descriptions-item label="计划存储"                >{{ data.storage.planDays }}天</el-descriptions-item              >              <el-descriptions-item label="实际存储"                >{{ data.storage.realDays }}天</el-descriptions-item              >              <el-descriptions-item label="最早录像存储日期">{{                data.storage.earliestTime                  ? dayjs(data.storage.earliestTime).format("YYYY年M月D日")                  : ""              }}</el-descriptions-item>            </el-descriptions>            <el-descriptions :column="1">              <el-descriptions-item label="存储状态">                <!–          <time-line></time-line>–>                <ul class="legend-box">                  <li>                    <i class="legend" style="background-color: green"></i>                    <span>录像完整</span>                  </li>                  <li>                    <i class="legend" style="background-color: orange"></i>                    <span>部分丢失</span>                  </li>                  <li>                    <i class="legend" style="background-color: red"></i>                    <span>全部丢失</span>                  </li>                  <li>                    <i class="legend" style="background-color: #cbd5e0"></i>                    <span>计划录像天数</span>                  </li>                </ul>              </el-descriptions-item>            </el-descriptions>            <div class="calendar-box">              <Calendar                :startDate="calenderStartDate"                :endDate="data.storage.lastTime"                :full="data.storage.fullDates"                :paritialLoss="data.storage.partialLossDates"                :allLoss="data.storage.allLostDates"                @select="onSelectDate"              ></Calendar>            </div>          </div>-->          <div style="height: 10px"></div>          <el-descriptions            title="录像完整性"            :column="3"            border            :label-style="labelStyle"            :contentStyle="content_style"            v-if="integrity == null || integrity.state == null"          >            <el-descriptions-item label="检测结果"> 未知 </el-descriptions-item>          </el-descriptions>          <div v-else>            <el-descriptions              title="录像完整性"              :column="3"              border              :label-style="labelStyle"              :contentStyle="content_style"            >              <el-descriptions-item label="检测结果">{{                getLabel(videoIntegrityState, integrity.state)              }}</el-descriptions-item>              <el-descriptions-item label="录像日期">{{                dayjs(integrity.recordDate).format("YYYY年M月D日")              }}</el-descriptions-item>              <el-descriptions-item label="丢失时长">{{                lostDurationText(integrity.loseDuration)              }}</el-descriptions-item>              <el-descriptions-item label="更新时间">{{                dayjs(integrity.updateTime).format("YYYY年M月D日H时m分")              }}</el-descriptions-item>            </el-descriptions>            <el-descriptions :column="1">              <el-descriptions-item label="丢失时段">                <!--          <time-line></time-line>-->                <ul class="legend-box">                  <li>                    <i class="legend" style="background-color: #00b2ff"></i>                    <span>计划时长</span>                  </li>                  <li>                    <i class="legend" style="background-color: #eaeaea"></i>                    <span>未计划时长</span>                  </li>                  <li>                    <i class="legend" style="background-color: green"></i>                    <span>有录像</span>                  </li>                  <li>                    <i class="legend" style="background-color: red"></i>                    <span>无录像</span>                  </li>                </ul>              </el-descriptions-item>            </el-descriptions>            <div class="time-line-box">              <!--        <div style="width: 100%;height: 20px;background-color: red; "></div>-->              <progress-bar                :timeCell="timeCells"                :lostData="lostData"              ></progress-bar>            </div>          </div>        </el-tab-pane>        <el-tab-pane label="实时录像质量">          <el-descriptions            title="实时录像质量"            :column="3"            border            :label-style="labelStyle"            :contentStyle="content_style"            v-if="data.quality == null || data.quality.quality == null"          >            <el-descriptions-item label="检测结果"> 未知 </el-descriptions-item>          </el-descriptions>          <div v-else>            <el-descriptions              title="实时录像质量"              :column="2"              border              :label-style="labelStyle"              :contentStyle="content_style"            >              <el-descriptions-item label="检测结果">{{                getLabel(videoDiagnosisState, data.quality.quality)              }}</el-descriptions-item>              <el-descriptions-item label="更新时间">{{                dayjs(data.quality.updateTime).format("YYYY年M月D日H时m分")              }}</el-descriptions-item>              <el-descriptions-item                label="诊断截图"                v-if="data.quality.quality == 1"              >                <div>                  <ul class="legend-box legend-box-quality">                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.signalLost"                        >视频信号</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.occlude"                        >遮挡</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.blurry"                        >模糊</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.colorCast"                        >偏色</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.snowflake"                        >雪花</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.stripe"                        >条纹</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.contrast"                        >对比度</el-tag                      >                    </li>                    <li>                      <el-tag                        size="small"                        type="danger"                        v-if="data.quality.brightness"                        >亮度</el-tag                      >                    </li>                  </ul>                  <div                    style="                      display: block;                      width: 300px;                      max-height: 300px;                      margin-top: 20px;                    "                  >                    <el-image                      :src="imgUrl(data.quality.image)"                      :preview-src-list="[imgUrl(data.quality.image)]"                    >                      <div slot="error" class="image-slot">                        <i class="el-icon-picture-outline"></i>                      </div>                    </el-image>                  </div>                </div>              </el-descriptions-item>            </el-descriptions>          </div>        </el-tab-pane>      </el-tabs>      <div slot="footer" class="dialog-footer" style="margin-top: 20px">        <el-button @click="onHide">关闭</el-button>      </div>    </DialogCom>  </div></template><script>import ProgressBar from "./ProgressBar";import Calendar from "./Calendar.vue";import dayjs from "dayjs";import { detail } from "@/api/iot/videoDiagnosis.js";import { getLabel } from "@/views/commonOption.js";import { integrity } from "@/api/iot/videoDiagnosis";export default {  components: { ProgressBar, Calendar },  data() {    return {      isShow: false,      data: {},      integrity: {},      id: null,      // playVideoObj: {}, //选中的正在播放的录像      timeCells: [], //录像时间块      lostData: [], //不存在视频的时间块      // start_timestamp: new Date().getTime() - 5 * 60 * 60 * 1000, //刻度轴开始时间      labelStyle: {        color: "#000",        "text-align": "center",        height: "40px",        width: "120px",        "word-break": "keep-all",      },      content_style: {        "text-align": "left",        "min-width": "250px",        "word-break": "break-all",      },    };  },  props: ["videoIntegrityState", "videoDaysState", "videoDiagnosisState"],  computed: {    calenderStartDate() {      if (this.data == null || this.data.storage == null) {        return new Date();      }      if (this.data.storage.earliestTime) {        return this.data.storage.earliestTime;      }      let d = dayjs().add(this.data.storage.planDays * -1 - 1, "day");      return d;    },  },  methods: {    dayjs,    getLabel,    async show(hostCode, channelCode) {      detail(hostCode, channelCode).then((r) => {        let data = r.data;        data.hostCode = hostCode;        data.channelCode = channelCode;        // this.data.storage.fullDates=["2024-02-15","2024-02-16","2024-02-17","2024-02-18","2024-02-19"]        // this.data.storage.partialLossDates=["2024-02-5","2024-02-6","2024-02-7","2024-02-8","2024-02-9"]        // this.data.storage.allLostDates=["2024-02-10","2024-02-11","2024-02-12","2024-02-13","2024-02-14"]        this.handleInterity(data.integrity);        this.data = data;        this.isShow = true;      });    },    getIntegrity(hostCode, channelCode, date) {      integrity(hostCode, channelCode, dayjs(date).format("YYYY-MM-DD")).then(        (r) => {          this.handleInterity(r.data);        }      );    },    handleInterity(integrity) {      this.integrity = integrity;      let timeCells = [];      let lostData = [];      if (integrity && integrity.recordDate) {        let recordDateStr = dayjs(integrity.recordDate).format("YYYY-MM-DD");        if (integrity.checks) {          timeCells = integrity.checks.map((d) => ({            beginTime: `${recordDateStr} ${d.st}`,            endTime: `${recordDateStr} ${d.et}`,          }));        }        if (integrity.losts) {          lostData = integrity.losts.map((d) => ({            beginTime: `${recordDateStr} ${d.st}`,            endTime: `${recordDateStr} ${d.et}`,          }));        }      }      this.timeCells = timeCells;      this.lostData = lostData;    },    onHide() {      this.isShow = false;      this.id = null;      this.integrity = {};      this.data = {};      (this.timeCells = []), //录像时间块        (this.lostData = []);    },    onSelectDate(date) {      this.getIntegrity(this.data.hostCode, this.data.channelCode, date);    },    lostDurationText(duration) {      if (!duration || duration == "0") {        return "未丢失";      }      let str = "";      let hour = Math.floor(duration / 60);      if (hour > 0) {        str += `${hour}小时`;      }      let minute = duration % 60;      if (minute > 0) {        str += `${minute}分`;      }      return str;    },    imgUrl(url) {      // 如果传入的是 base64 字符串,直接返回      if (url.startsWith('data:image')) {        return url;      }      // 否则,返回原来的 URL      return url;    }  },};</script><style lang="scss">.videoDaysDetail {  .block {    display: block;  }  .time-line {    margin-top: 10px;    margin-left: 80px;  }  .list-title {    font-size: 16px;    font-family: PingFangSC-Medium, PingFang SC;    font-weight: 500;    color: #181b1e;  }  .list-company {    font-size: 14px;    font-family: PingFangSC-Regular, PingFang SC;    font-weight: 400;    color: #2991ff;    margin-top: 15px;    margin-bottom: 15px;  }  .list-desc {    font-size: 14px;    font-family: PingFangSC-Regular, PingFang SC;    font-weight: 400;    color: #596878;  }  .el-tag--small {    margin-bottom: 10px;  }  .reTip {    display: block;    background: #f00;    border-radius: 50%;    width: 4px;    height: 4px;    top: -21px;    right: -26px;    position: relative;    z-index: 4;  }  //左侧时间  .time {    color: rgb(181 215 251);    position: absolute;    left: -35px;    top: -1px;    .year {      font-size: 14px;      font-family: PingFangSC-Regular, PingFang SC;      font-weight: 400;      color: #20354a;    }    .day {      font-size: 14px;      font-family: PingFangSC-Regular, PingFang SC;      font-weight: 400;      color: #596878;      text-align: center;      margin-top: 10px;    }  }  .legend-box {    display: flex;    flex-direction: row;    justify-content: flex-start;    align-items: center;    > li {      display: flex;      flex-direction: row;      justify-content: flex-start;      align-items: center;      margin-right: 20px;      i {        margin-right: 5px;      }    }  }  .legend-box-quality {    > li {      margin-right: 5px;    }  }  .time-line-box {    width: 100%;    padding: 0 80px 50px 80px;  }  .calendar-box {    width: 100%;    display: flex;    flex-wrap: wrap;    justify-content: space-between;    //>div{    //  width: 30%;    //}  }  .el-calendar-table .el-calendar-day {    padding: 5px;    height: auto;  }  .el-calendar__button-group {    display: none;  }  .legend {    display: block;    width: 14px;    height: 10px;    margin-right: 5px;  }}</style>
 |