Xxuwei95etl 重构
e36f907e创建于 2025年12月4日历史提交
<template>
  <div class="query-panel" v-show="isExpanded">
    <ModelQuery ref="queryRef" :data="queryInfo" />
  </div>
  <div class="toggle-button-container">
    <div class="toggle-button-wrapper" @mouseenter="isHover = true" @mouseleave="isHover = false" @click="isExpanded = !isExpanded; isHover=false">
      <a-icon class="toggle-icon" v-if="!isHover" type="minus-outlined" style="font-size: 20px" />
      <a-icon class="toggle-icon" v-if="isHover && !isExpanded" type="down-outlined" style="font-size: 20px" />
      <a-icon class="toggle-icon" v-if="isHover && isExpanded" type="up-outlined" style="font-size: 20px" />
    </div>
  </div>
  <JVxeTable
    ref="tableRef"
    toolbar
    resizable
    maxHeight="600"
    :toolbarConfig="{ btn: [] }"
    :loading="loading"
    :columns="columns"
    :dataSource="dataSource"
    :pagination="!hidePagination && pagination"
    @pageChange="handlePageChange"
  >
    <template #toolbarSuffix>
      <a-button @click="fetchData(false)" style="float: right" preIcon="ant-design:search-outlined">查询</a-button>
      <a-button @click="copyQuery" style="float: right" preIcon="ant-design:copy-outlined">复制查询条件</a-button>
      <a-button :loading="loading" @click="outputData" style="float: right" preIcon="ant-design:export-outlined">导出数据</a-button>
    </template>
  </JVxeTable>
</template>

<script lang="ts" setup>
  import { watch, ref, unref, onMounted, reactive } from 'vue';
  import { JVxeTypes, JVxeColumn, JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
  import { queryData } from '../dataquery.api';
  import ModelQuery from './modelQuery.vue';
  import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { cloneObject } from '/@/utils';
  import { parseTableRecords } from '/@/utils/common_utils';
  import { useMethods } from '/@/hooks/system/useMethods';
  import { usePermission } from '@/hooks/web/usePermission';
  const { handleExportExcel } = useMethods();
  const { createMessage } = useMessage();
  const { clipboardRef, copiedRef } = useCopyToClipboard();
  const { hasPermission } = usePermission();
  const tableRef = ref<JVxeTableInstance>();
  const queryRef = ref(null);
  const props = defineProps({
    data: { type: Object, default: () => ({}) },
    rootTreeData: { type: Array, default: () => [] },
  });
  const isExpanded = ref<boolean>(true);
  const isHover = ref<boolean>(false);
  const loading = ref<boolean>(false);
  const model = ref<object>({}); // 模型数据
  const columns = ref<JVxeColumn[]>([]); // 字段列表
  const dataSource = ref<any[]>([]); // 数据列表
  const modelFields = ref<any[]>([]); // 模型字段列表
  const queryInfo = reactive({
    extract_rules: [], // 筛选规则列表
    search_type_list: [], // 高级查询列表
    fields: [], //  字段列表
  }); // 查询配置
  const pagination = reactive({
    current: 1,
    pageSize: 100,
    pageSizeOptions: ['100', '500', '1000', '2000', '5000', '10000'],
    total: 0,
  });
  const hidePagination = ref(false);
  // 初始化查询配置
  function initData() {
    columns.value = [];
    dataSource.value = [];
    // 重置查询配置到空状态,确保 modelQuery 能检测到变化
    Object.assign(queryInfo, {
      extract_rules: [],
      search_type_list: [],
      fields: [],
    });
    pagination.pageSize = 100;
    pagination.current = 1;
  }
  /** 获取值,忽略表单验证 */
  // 当分页参数变化时触发的事件
  async function handlePageChange(event) {
    console.log(event);
    // 重新赋值
    pagination.current = event.current;
    pagination.pageSize = event.pageSize;
    // 查询数据
    await fetchData(false);
  }
  // 导出excel
  async function outputData() {
    console.log(dataSource.value);
    handleExportExcel('数据导出结果_' + Date.now() + '.xlsx', dataSource.value);
  }
  // 获取查询结构
  async function genQuery(include_id = true) {
    const extract_info = cloneObject(queryRef.value.genQuery());
    extract_info['page'] = pagination.current;
    extract_info['pagesize'] = pagination.pageSize;
    if (include_id) {
      extract_info['id'] = model.value.id;
    }
    console.log('query', extract_info);
    return extract_info;
  }
  // 复制查询条件
  async function copyQuery() {
    // queryRef
    const extract_info = await genQuery(false);
    const value = unref(JSON.stringify(extract_info));
    if (!value) {
      createMessage.warning('请输入要复制的内容!');
      return;
    }
    clipboardRef.value = value;
    if (unref(copiedRef)) {
      createMessage.success('复制成功!');
    }
  }
  // 查询模型数据
  async function fetchData(is_init = false) {
    // queryRef
    const extract_info = await genQuery(true);
    loading.value = true;
    try {
      const res_data = await queryData(extract_info);
      if (res_data) {
        hidePagination.value = res_data.hasOwnProperty('pagination') && res_data.pagination === false;
        pagination.total = res_data.total;
        dataSource.value = parseTableRecords(res_data.records);
        // 重置字段列表
        let fields = res_data.fields;
        columns.value = [];
        for (let i in fields) {
          let field = fields[i];
          columns.value.push({
            title: field,
            key: field,
            type: JVxeTypes.normal,
            width: 240,
          });
        }
        if (is_init) {
          // 重置筛选规则列表, 高级查询列表
          // 使用 Object.assign 确保响应式更新
          Object.assign(queryInfo, {
            extract_rules: res_data.extract_rules || [],
            search_type_list: res_data.search_type_list || [],
            fields: res_data.fields || [],
          });
          console.log(7, queryInfo);
        }
      } else {
        console.log('error', res_data);
      }
    } catch (e) {
      console.log(e);
    } finally {
      loading.value = false;
    }
  }
  // 监听 data 变化
  onMounted(() => {
    watch(
      () => props.data,
      async () => {
        let record = unref(props.data);
        if (typeof record !== 'object') {
          record = {};
        }
        if (record.id) {
          model.value = record;
          modelFields.value = record.fields;
          await initData();
          await fetchData(true);
        }
      },
      { deep: true, immediate: true }
    );
  });
</script>

<style>
  .query-panel {
    min-height: 55px;
  }
  .toggle-button-container {
    text-align: center;
  }
  .toggle-button-wrapper {
    /* 初始样式 */
    display: inline-block;
    cursor: pointer;
    transition: all 0.3s ease;
  }

  .toggle-icon {
    font-size: 24px; /* 初始字体大小 */
  }

  .toggle-button-wrapper:hover .toggle-icon {
    /* 悬停时图标的样式 */
    font-size: 40px; /* 放大字体 */
    animation: pulse 1s infinite alternate; /* 应用动画 */
  }

  /* 定义动画 */
  @keyframes pulse {
    from {
      transform: scale(1);
    }
    to {
      transform: scale(1.1);
    }
  }
</style>