DigitalDashBoard.vue 6.44 KB
<script lang="ts" setup>
  import { computed, onMounted, onUnmounted, ref, unref } from 'vue';
  import { Space, Tooltip } from 'ant-design-vue';
  import {
    DigitalComponentDefaultConfig,
    DigitalDashBoardLayout,
    DigitalDashBoardValue,
  } from './digitalDashBoard.config';
  import { dateUtil } from '/@/utils/dateUtil';
  import {
    fontSize,
    RadioRecord,
    DEFAULT_DATE_FORMAT,
    DEFAULT_RADIO_RECORD,
    DEFAULT_ANIMATION_INTERVAL,
  } from '../../detail/config/util';
  import { isNaN } from 'lodash';

  const props = withDefaults(
    defineProps<{
      layout?: DigitalDashBoardLayout;
      value?: DigitalDashBoardValue;
      radio?: RadioRecord;
      random?: boolean;
    }>(),
    {
      value: () => ({}),
      layout: () => ({ max: 5, keepNumber: 2 }),
    }
  );

  const changeValue = ref(0);

  const getPropsValue = computed(() => {
    return { value: unref(changeValue), ...DigitalComponentDefaultConfig, ...props.value };
  });

  const integerPart = computed(() => {
    let { value = 0 } = unref(getPropsValue);
    const { max = 5 } = props.layout;
    if (isNaN(value)) value = 0;
    let _value = Number(value).toFixed(2).split('.')[0];
    if (_value.length < max) _value = _value.padStart(5, '0');
    if (_value.length > max) _value = ''.padStart(5, '9');

    return _value;
  });

  const decimalPart = computed(() => {
    let { value = 0 } = unref(getPropsValue);
    const { keepNumber = 2 } = props.layout;
    if (isNaN(value)) value = 0;
    let _value = Number(value)?.toFixed(2).split('.')[1];
    if (_value.length < keepNumber) _value = _value.padStart(5, '0');

    if (_value.length > keepNumber) _value = ''.padStart(5, '0');

    return _value;
  });

  const getRadio = computed(() => {
    // const { radio } = props.radio || DEFAULT_RADIO_RECORD;
    // return radio;
    return props.radio || DEFAULT_RADIO_RECORD;
  });

  let timeout: Nullable<number> = null;

  const handleRandom = () => {
    const newValue = Math.floor(Math.random() * 100);
    changeValue.value = newValue;
  };

  const getScale = computed(() => {
    const { width } = props.radio || DEFAULT_RADIO_RECORD;
    return width / 360 > 1 ? 1 : width / 360;
  });

  onMounted(() => {
    if (props.random)
      timeout = setInterval(handleRandom, DEFAULT_ANIMATION_INTERVAL) as unknown as number;
  });

  onUnmounted(() => {
    clearInterval(timeout as number);
    timeout = null;
  });
</script>

<template>
  <section class="w-full h-full">
    <div class="flex flex-col w-full h-full">
      <div class="flex-1 flex justify-center items-center">
        <div class="flex px-4 items-center" :style="{ transform: `scale(${getScale})` }">
          <Space
            justify="end"
            class="justify-end"
            :size="4"
            :style="{
              backgroundColor: '#585357',
              padding: fontSize({ radioRecord: getRadio, basic: 10 }),
            }"
          >
            <div
              v-for="number in integerPart"
              :key="number"
              class="digital-wrapper__int"
              :style="{
                color: getPropsValue.fontColor,
                fontSize: fontSize({ radioRecord: getRadio, basic: 20, max: 20 }),
                padding: fontSize({ radioRecord: getRadio, basic: 5 }),
              }"
            >
              <div class="digital-text__int p-1 text-light-50"> {{ number }}</div>
            </div>
          </Space>
          <div
            class="m-0.5 rounded-1/2"
            style="background-color: #333; width: 6px; height: 6px; align-self: flex-end"
          >
          </div>
          <Space
            justify="end"
            class="justify-end"
            :size="4"
            :style="{
              backgroundColor: '#b74940',
              padding: fontSize({ radioRecord: getRadio, basic: 10 }),
            }"
          >
            <div
              v-for="number in decimalPart"
              :key="number"
              class="digital-wrapper__float"
              :style="{
                color: getPropsValue.fontColor,
                fontSize: fontSize({ radioRecord: getRadio, basic: 20, max: 20 }),
                padding: fontSize({ radioRecord: getRadio, basic: 5 }),
              }"
            >
              <div class="digital-text__float p-1 text-light-50">
                {{ number }}
              </div>
            </div>
          </Space>
          <div
            class="px-1 font-bold"
            :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 18, max: 18 }) }"
          >
            {{ getPropsValue.unit }}
          </div>
        </div>
      </div>

      <div
        class="text-center truncate"
        :style="{ fontSize: fontSize({ radioRecord: getRadio, basic: 18 }) }"
      >
        <span>{{ props.value.name || '电表' }}</span>
      </div>

      <div
        class="text-center text-xs p-5"
        :style="{
          fontSize: fontSize({ radioRecord: getRadio, basic: 12, max: 16 }),
          color: '#999',
        }"
      >
        <Tooltip
          placement="top"
          :title="
            props.value?.updateTime
              ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
              : '暂无更新时间'
          "
        >
          <div class="truncate">
            <span class="mr-1">更新时间:</span>
            <span>
              {{
                props.value?.updateTime
                  ? dateUtil(props?.value?.updateTime).format(DEFAULT_DATE_FORMAT)
                  : '暂无更新时间'
              }}
            </span>
          </div>
        </Tooltip>
      </div>
    </div>
    <div></div>
  </section>
</template>

<style scoped lang="less">
  .digital-wrapper__int {
    border-radius: 1px;
    box-shadow: inset 0 1px 3px 0 rgba(0, 0, 0, 0.7);
    background: url('/@/assets/images/digital-wrapper-bg-int.png') 0 -1px no-repeat;
    padding: 5px;
    background-size: 100% 100%;
  }

  .digital-text_int {
    display: inline-block;
    overflow-wrap: break-word;
    color: rgba(255, 255, 255, 1);
    white-space: nowrap;
    text-align: center;
  }

  .digital-wrapper__float {
    border-radius: 1px;
    box-shadow: inset 0 1px 3px 0 rgba(112, 22, 15, 1);
    background: url('/@/assets/images/digital-wrapper-bg-float.png') 0 -1px no-repeat;
    padding: 5px;
    background-size: 100% 100%;
  }

  .digital-text_float {
    display: inline-block;
    overflow-wrap: break-word;
    color: rgba(255, 255, 255, 1);
    white-space: nowrap;
    text-align: center;
  }
</style>