index.vue 9.99 KB
<script setup lang="ts">
  import { List, Card, Button, PaginationProps, Popover, Slider, Tooltip } from 'ant-design-vue';
  import {
    ReloadOutlined,
    AppstoreOutlined,
    EyeOutlined,
    EditOutlined,
    EllipsisOutlined,
  } from '@ant-design/icons-vue';
  import { computed, onMounted, reactive, ref, unref } from 'vue';
  import { OrganizationIdTree, useResetOrganizationTree } from '../../common/organizationIdTree';
  import {
    deleteConfigurationCenter,
    getPage,
  } from '/@/api/configuration/center/configurationCenter';
  import { ConfigurationCenterItemsModal } from '/@/api/configuration/center/model/configurationCenterModal';
  import { PageWrapper } from '/@/components/Page';
  import { Dropdown } from '/@/components/Dropdown';
  import { BasicForm, useForm } from '/@/components/Form';
  import { ConfigurationPermission, searchFormSchema } from './center.data';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { Authority } from '/@/components/Authority';
  import { isDevMode } from '/@/utils/env';
  import ConfigurationCenterDrawer from './ConfigurationCenterDrawer.vue';
  import { useDrawer } from '/@/components/Drawer';
  import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';
  import { getBoundingClientRect } from '/@/utils/domUtils';
  import configurationSrc from '/@/assets/icons/configuration.svg';
  import { cloneDeep } from 'lodash';
  import { usePermission } from '/@/hooks/web/usePermission';
  import { useGlobSetting } from '/@/hooks/setting';

  const listColumn = ref(5);

  const { createMessage } = useMessage();

  const organizationId = ref<Nullable<number>>(null);

  const pagination = reactive<PaginationProps>({
    size: 'small',
    showTotal: (total: number) => `共 ${total} 条数据`,
    current: 1,
    onChange: (page: number) => {
      pagination.current = page;
      getListData();
    },
  });

  const loading = ref(false);

  const dataSource = ref<ConfigurationCenterItemsModal[]>([]);

  const [registerForm, { getFieldsValue }] = useForm({
    schemas: searchFormSchema,
    showAdvancedButton: true,
    labelWidth: 100,
    compact: true,
    resetFunc: () => {
      resetFn();
      organizationId.value = null;
      return getListData();
    },
    submitFunc: async () => {
      const value = getFieldsValue();
      getListData(value);
    },
  });

  async function getListData(value: Recordable = {}) {
    try {
      loading.value = true;
      const pageSize = 4 * unref(listColumn);
      const { items, total } = await getPage({
        organizationId: unref(organizationId),
        ...value,
        page: pagination.current!,
        pageSize,
      });
      dataSource.value = items;
      pagination.total = total;
      pagination.pageSize = pageSize;
    } catch (error) {
    } finally {
      loading.value = false;
    }
  }

  onMounted(() => {
    getListData();
  });

  const searchInfo = reactive<Recordable>({});
  const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  const handleSelect = (orgId: number) => {
    organizationId.value = orgId;
    getListData();
  };

  const [registerDrawer, { openDrawer }] = useDrawer();

  const { hasPermission } = usePermission();

  const getPreviewFlag = computed(() => {
    return hasPermission(ConfigurationPermission.PREVIEW);
  });

  const getDesignFlag = computed(() => {
    return hasPermission(ConfigurationPermission.DESIGN);
  });

  const handleCreateOrUpdate = (record?: ConfigurationCenterItemsModal) => {
    if (record) {
      openDrawer(true, {
        isUpdate: true,
        record: cloneDeep(record),
      });
    } else {
      openDrawer(true, {
        isUpdate: false,
      });
    }
  };

  const { configurationPrefix } = useGlobSetting();
  const isDev = isDevMode();

  const handlePreview = (record: ConfigurationCenterItemsModal) => {
    if (!unref(getPreviewFlag)) return;
    window.open(
      `${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}&lightbox=1`
    );
  };

  const handleDesign = (record: ConfigurationCenterItemsModal) => {
    if (!unref(getDesignFlag)) return;
    window.open(`${configurationPrefix}/${isDev ? '?dev=1&' : '?'}configurationId=${record!.id}`);
  };

  const { createSyncConfirm } = useSyncConfirm();
  const handleDelete = async (record: ConfigurationCenterItemsModal) => {
    try {
      await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' });
      await deleteConfigurationCenter([record.id]);
      createMessage.success('删除成功');
      await getListData();
    } catch (error) {}
  };

  const listEl = ref<Nullable<ComponentElRef>>(null);

  onMounted(() => {
    const clientHeight = document.documentElement.clientHeight;
    const rect = getBoundingClientRect(unref(listEl)!.$el!) as DOMRect;
    // margin-top 24 height 24
    const paginationHeight = 24 + 24 + 8;
    // list pading top 8 maring-top 8 extra slot 56
    const listContainerMarginBottom = 8 + 8 + 56;
    const listContainerHeight =
      clientHeight - rect.top - paginationHeight - listContainerMarginBottom;
    const listContainerEl = (unref(listEl)!.$el as HTMLElement).querySelector(
      '.ant-spin-container'
    ) as HTMLElement;
    listContainerEl &&
      (listContainerEl.style.height = listContainerHeight + 'px') &&
      (listContainerEl.style.overflowY = 'auto') &&
      (listContainerEl.style.overflowX = 'hidden');
  });
</script>

<template>
  <PageWrapper dense contentFullHeight contentClass="flex">
    <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" />
    <section class="flex-auto p-4 w-3/4 xl:w-4/5 w-full configuration-list">
      <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4">
        <BasicForm @register="registerForm" />
      </div>
      <List
        ref="listEl"
        :loading="loading"
        class="flex-auto bg-light-50 dark:bg-dark-900 !p-2 !mt-4"
        position="bottom"
        :pagination="pagination"
        :data-source="dataSource"
        :grid="{ gutter: 4, column: listColumn }"
      >
        <template #header>
          <div class="flex gap-3 justify-end">
            <Authority :value="ConfigurationPermission.CREATE">
              <Button type="primary" @click="handleCreateOrUpdate()">新增组态</Button>
            </Authority>
            <Popover :trigger="['hover']">
              <template #content>
                <div class="w-50">
                  <div>每行显示数量</div>
                  <Slider
                    v-model:value="listColumn"
                    :max="12"
                    :min="4"
                    :marks="{ 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 }"
                    @change="getListData"
                  />
                </div>
              </template>
              <Button type="primary">
                <AppstoreOutlined />
              </Button>
            </Popover>
            <Tooltip title="刷新">
              <Button type="primary" @click="getListData">
                <ReloadOutlined @click="getListData" />
              </Button>
            </Tooltip>
          </div>
        </template>
        <template #renderItem="{ item }">
          <List.Item>
            <Card hoverable>
              <template #cover>
                <div class="h-full w-full !flex justify-center items-center text-center">
                  <img
                    class="w-full h-36"
                    alt="example"
                    :src="item.thumbnail || configurationSrc"
                    @click="handlePreview(item)"
                  />
                </div>
              </template>
              <template class="ant-card-actions" #actions>
                <Tooltip title="预览">
                  <EyeOutlined
                    :class="getPreviewFlag ? '' : '!cursor-not-allowed !text-gray-200'"
                    key="setting"
                    @click="handlePreview(item)"
                  />
                </Tooltip>
                <Tooltip title="设计">
                  <EditOutlined
                    :class="getDesignFlag ? '' : '!cursor-not-allowed !text-gray-200'"
                    key="edit"
                    @click="handleDesign(item)"
                  />
                </Tooltip>
                <Dropdown
                  :dropMenuList="[
                    {
                      text: '编辑',
                      auth: ConfigurationPermission.UPDATE,
                      icon: 'clarity:note-edit-line',
                      event: '',
                      onClick: handleCreateOrUpdate.bind(null, item),
                    },
                    {
                      text: '删除',
                      auth: ConfigurationPermission.DELETE,
                      icon: 'ant-design:delete-outlined',
                      color: 'error',
                      event: '',
                      onClick: handleDelete.bind(null, item),
                    },
                  ]"
                  :trigger="['hover']"
                >
                  <EllipsisOutlined key="ellipsis" />
                </Dropdown>
              </template>
              <Card.Meta>
                <template #title>
                  <span class="truncate">{{ item.name }}</span>
                </template>
                <template #description>
                  <div class="truncate h-11">
                    <div class="truncate">{{ item.organizationDTO.name }}</div>
                    <div class="truncate">{{ item.remark || '' }} </div>
                  </div>
                </template>
              </Card.Meta>
            </Card>
          </List.Item>
        </template>
      </List>
    </section>
    <ConfigurationCenterDrawer @register="registerDrawer" @success="getListData" />
  </PageWrapper>
</template>

<style lang="less" scoped>
  .configuration-list:deep(.ant-list-header) {
    border-bottom: none !important;
  }

  .configuration-list:deep(.ant-list-pagination) {
    height: 24px;
  }

  .configuration-list:deep(.ant-list-empty-text) {
    @apply w-full h-full flex justify-center items-center;
  }
</style>