index.vue 3.84 KB
<script lang="ts" setup>
  import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
  import { option } from './config';
  import { SvgIcon } from '/@/components/Icon';
  import { Switch } from 'ant-design-vue';
  import { computed, ref } from 'vue';
  import { useComponentScale } from '../../../hook/useComponentScale';
  import { unref } from 'vue';
  import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
  import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  import { useDataFetch } from '../../../hook/socket/useSocket';
  import { useModal } from '/@/components/Modal';
  import PasswordModal from '../component/PasswordModal.vue';
  import { useCommandDelivery } from '../../../hook/useCommandDelivery';
  import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';

  const props = defineProps<{
    config: ComponentPropsConfigType<typeof option>;
  }>();

  const checked = ref(false);

  const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();

  const getDesign = computed(() => {
    const { option, persetOption } = props.config;
    const { componentInfo, attribute, deviceProfileId, attributeRename, commandType } = option;
    const {
      icon: presetIcon,
      iconColor: presetIconColor,
      fontSize: persetFontSize,
      password: persetPassword,
    } = persetOption || {};
    const { icon, iconColor, fontSize, password } = componentInfo || {};

    const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
    return {
      icon: icon ?? presetIcon,
      iconColor: iconColor || presetIconColor,
      attribute: attributeRename || tsl?.functionName || attribute,
      fontSize: fontSize || persetFontSize || 14,
      password: password || persetPassword,
      commandType,
    };
  });

  const { loading, doCommandDeliver } = useCommandDelivery();

  const handleChange = async () => {
    if (unref(getDesign).password) {
      openModal(true, { password: unref(getDesign).password });
      checked.value = !unref(checked);
      return;
    }
    handleSendCommand();
  };

  const handleSendCommand = async () => {
    if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
    const { option } = props.config || {};
    const result = await doCommandDeliver(option, Number(unref(checked)));
    if (!result) checked.value = !unref(checked);
  };

  const updateFn: DataFetchUpdateFn = (message, attribute) => {
    const { data = {} } = message;
    const [latest] = data[attribute] || [];
    const [_, value] = latest;
    checked.value = isNaN(value as unknown as number) ? false : !!Number(value);
  };

  useDataFetch(props, updateFn);
  const { getScale, getRatio } = useComponentScale(props);

  const [registerModal, { openModal }] = useModal();
</script>

<template>
  <main class="w-full h-full flex flex-col justify-center">
    <DeviceName :config="config" class="text-center" />
    <main class="w-full h-full flex justify-around items-center" :style="getScale">
      <div class="flex flex-col justify-center items-center">
        <SvgIcon
          :name="getDesign.icon"
          prefix="iconfont"
          :style="{ color: getDesign.iconColor }"
          :size="getRatio ? getRatio * 60 : 60"
        />
        <span
          class="mt-3 truncate text-gray-500 text-center"
          :style="{
            fontSize: (getRatio ? getRatio * getDesign.fontSize : getDesign.fontSize) + 'px',
          }"
        >
          {{ getDesign.attribute || '属性' }}
        </span>
      </div>
      <Switch
        :style="{ transform: ` scale(${getRatio})` }"
        v-model:checked="checked"
        :loading="loading"
        @change="handleChange"
      />
    </main>
    <PasswordModal @register="registerModal" @success="handleSendCommand" />
  </main>
</template>