index.vue 7.31 KB
<script lang="ts" setup>
  import { Button, Card, Switch, Tooltip } from 'ant-design-vue';
  import {
    CloudSyncOutlined,
    PlayCircleOutlined,
    QuestionCircleOutlined,
  } from '@ant-design/icons-vue';
  import { Authority } from '/@/components/Authority';
  import { TaskRecordType } from '/@/api/task/model';
  import { StateEnum, TaskTargetNameEnum, TaskTypeEnum } from '../../config';
  import { TaskTypeNameEnum, PermissionEnum } from '../../config';
  import AuthDropDown from '/@/components/Widget/AuthDropDown.vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { cancelTask, deleteTask, updateState } from '/@/api/task';
  import { computed } from '@vue/reactivity';
  import { unref } from 'vue';
  import { ref } from 'vue';
  import { dateUtil } from '/@/utils/dateUtil';
  import { DEFAULT_DATE_FORMAT } from '/@/views/visual/board/detail/config/util';

  enum DropMenuEvent {
    DELETE = 'DELETE',
    EDIT = 'EDIT',
  }

  const props = withDefaults(
    defineProps<{
      record: TaskRecordType;
      reload: Fn;
      deviceTaskCardMode?: boolean;
      tbDeviceId?: string;
    }>(),
    {
      deviceTaskCardMode: false,
    }
  );

  const emit = defineEmits(['edit', 'runTask']);

  const loading = ref(false);

  const { createMessage } = useMessage();

  const getRecord = computed(() => {
    return props.record;
  });

  const getCancelState = computed(() => {
    return !!(
      unref(getRecord).tkDeviceTaskCenter && unref(getRecord).tkDeviceTaskCenter?.allowState
    );
  });

  const handleDelete = async () => {
    try {
      await deleteTask([unref(getRecord).id]);
      createMessage.success('删除成功');
      props.reload?.();
    } catch (error) {}
  };

  const handleSwitchState = async () => {
    try {
      loading.value = true;
      await updateState(
        unref(getRecord).id,
        !unref(getRecord).state ? StateEnum.ENABLE : StateEnum.CLOSE
      );
      createMessage.success('更新状态成功');
      props.reload?.();
    } catch (error) {
      throw error;
    } finally {
      loading.value = false;
    }
  };

  const handleCancelTask = async () => {
    try {
      if (!props.tbDeviceId) return;
      loading.value = true;
      await cancelTask({
        id: unref(getRecord).id,
        tbDeviceId: props.tbDeviceId,
        allow: !unref(getCancelState),
      });
      createMessage.success('设置成功');
      props.reload?.();
    } catch (error) {
      throw error;
    } finally {
      loading.value = false;
    }
  };

  const getTwoDateDiff = (date: number, now = dateUtil()) => {
    const unitList = [
      { radix: null, unitName: '年', unit: 'year' },
      { radix: 11, unitName: '月', unit: 'month' },
      { radix: 30, unitName: '日', unit: 'day' },
      { radix: 23, unitName: '时', unit: 'hour' },
      { radix: 59, unitName: '分', unit: 'minute' },
      { radix: 59, unitName: '秒', unit: 'second' },
    ];

    for (let i = unitList.length - 1; i >= 0; i--) {
      const { unit, radix, unitName } = unitList[i];
      const lastDate = dateUtil(date);
      const diffValue = now.diff(lastDate, unit as any);
      if (!radix || diffValue <= radix) {
        return { value: diffValue, unit, unitName };
      }
    }
  };

  const getLastExecuteTime = computed(() => {
    if (!unref(getRecord).lastExecuteTime) return;
    return getTwoDateDiff(unref(getRecord).lastExecuteTime!);
  });

  const handleRunTask = () => {
    emit('runTask', unref(getRecord));
  };
</script>

<template>
  <Card hoverable class="card-container !rounded">
    <div v-if="!deviceTaskCardMode" class="flex justify-end mb-4">
      <AuthDropDown
        @click.stop
        :trigger="['hover']"
        :drop-menu-list="[
          {
            text: '编辑',
            event: DropMenuEvent.DELETE,
            disabled: !!getRecord.state,
            icon: 'ant-design:edit-outlined',
            auth: PermissionEnum.UPDATE,
            onClick: emit.bind(null, 'edit', getRecord),
          },
          {
            text: '删除',
            event: DropMenuEvent.DELETE,
            icon: 'ant-design:delete-outlined',
            auth: PermissionEnum.DELETE,
            popconfirm: {
              title: '是否确认删除操作?',
              onConfirm: handleDelete.bind(null),
            },
          },
        ]"
      />
    </div>
    <div class="flex text-base font-medium justify-between mb-2">
      <Tooltip :title="getRecord.name" placement="topLeft">
        <div class="truncate max-w-48">{{ getRecord.name }}</div>
      </Tooltip>
      <span
        v-if="deviceTaskCardMode"
        class="text-xs w-12 leading-6 text-right"
        :class="getRecord.state === StateEnum.ENABLE ? 'text-green-500' : 'text-red-500'"
      >
        {{ getRecord.state === StateEnum.ENABLE ? '已启用' : '未启用' }}
      </span>
      <Authority :value="PermissionEnum.START_TASK">
        <Switch
          v-if="!deviceTaskCardMode"
          :checked="getRecord.state === StateEnum.ENABLE"
          :loading="loading"
          size="small"
          @click="handleSwitchState"
        />
      </Authority>
    </div>
    <div class="flex gap-2 items-center">
      <div
        class="rounded flex justify-center items-center w-6 h-6"
        :class="
          getRecord.executeContent.type === TaskTypeEnum.MODBUS_RTU
            ? ' bg-blue-400'
            : 'bg-green-400'
        "
      >
        <CloudSyncOutlined class="svg:fill-light-50" />
      </div>
      <div class="text-gray-400 truncate">
        <span>{{ TaskTypeNameEnum[getRecord.executeContent.type] }}</span>
        <span class="mx-1">-</span>
        <span>{{ TaskTargetNameEnum[getRecord.targetType] }}</span>
      </div>
    </div>
    <div class="mt-4 flex justify-between items-center gap-3">
      <Authority :value="PermissionEnum.EXECUTE">
        <Button size="small" @click="handleRunTask">
          <div class="text-xs px-1">
            <PlayCircleOutlined class="mr-1" />
            <span>运行任务</span>
          </div>
        </Button>
      </Authority>
      <Tooltip
        v-if="getLastExecuteTime"
        overlay-class-name="task-last-execute-time-tooltip"
        placement="topLeft"
        :title="`最后运行时间: ${dateUtil(getRecord.lastExecuteTime).format(DEFAULT_DATE_FORMAT)}`"
      >
        <div class="text-gray-400 text-xs truncate">
          <span class="mr-2">间隔时间重复</span>
          <span>{{
            getLastExecuteTime.value
              ? `${getLastExecuteTime.value}${getLastExecuteTime.unitName}前`
              : '刚刚'
          }}</span>
        </div>
      </Tooltip>
    </div>

    <Authority :value="PermissionEnum.ALLOW">
      <section
        v-if="deviceTaskCardMode"
        class="border-t mt-4 pt-2 text-sm border-gray-100 flex justify-between text-gray-400"
      >
        <div>
          <span>允许该设备</span>
          <Tooltip title="设置是否允许当前设备定时执行任务。该选项不影响手动执行任务。">
            <QuestionCircleOutlined class="ml-1" />
          </Tooltip>
        </div>
        <div>
          <Switch
            size="small"
            :loading="loading"
            :checked="getCancelState"
            @click="handleCancelTask"
          />
        </div>
      </section>
    </Authority>
  </Card>
</template>

<style>
  .task-last-execute-time-tooltip {
    max-width: 300px;
  }
</style>