ExportBox.vue 7.43 KB
<template>
  <el-dialog :close-on-click-modal="false" :visible.sync="visible"
    class="NCC-dialog NCC-dialog_center export-dialog" lock-scroll width="650px">
    <div slot="title" class="dialog-title">
      <i class="el-icon-download"></i>
      <span>导出客户信息</span>
    </div>
    
    <div class="export-content">
      <el-form label-position="top" label-width="80px">
        <div class="section-card">
          <div class="section-header">
            <i class="el-icon-files"></i>
            <span>数据范围选择</span>
          </div>
          <el-form-item>
            <el-radio-group v-model="type" class="data-type-group">
              <el-radio :label="0" class="data-type-radio">
                <div class="radio-content">
                  <i class="el-icon-document"></i>
                  <div>
                    <div class="radio-title">当前页面数据</div>
                    <div class="radio-desc">仅导出当前页面显示的数据</div>
                  </div>
                </div>
              </el-radio>
              <el-radio :label="1" class="data-type-radio">
                <div class="radio-content">
                  <i class="el-icon-folder-opened"></i>
                  <div>
                    <div class="radio-title">全部页面数据</div>
                    <div class="radio-desc">导出所有符合条件的数据</div>
                  </div>
                </div>
              </el-radio>
            </el-radio-group>
          </el-form-item>
        </div>

        <div class="section-card">
          <div class="section-header">
            <i class="el-icon-menu"></i>
            <span>导出字段选择</span>
          </div>
          <el-form-item>
            <div class="field-selection">
              <div class="select-all-wrapper">
                <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll"
                  @change="handleCheckAllChange" class="select-all-checkbox">
                  <span class="select-all-text">全选字段</span>
                </el-checkbox>
                <span class="selected-count">已选择 {{columns.length}} / {{columnList.length}} 个字段</span>
              </div>
              <el-divider></el-divider>
              <el-checkbox-group v-model="columns" @change="handleCheckedChange" class="field-checkbox-group">
                <el-checkbox v-for="item in columnList" :label="item.prop" :key="item.prop" class="field-checkbox">
                  {{item.label}}
                </el-checkbox>
              </el-checkbox-group>
            </div>
          </el-form-item>
        </div>
      </el-form>
    </div>

    <span slot="footer" class="dialog-footer">
      <el-button @click="visible=false" size="medium">
        <i class="el-icon-close"></i>
        取 消
      </el-button>
      <el-button type="primary" @click="downLoad" size="medium" :loading="btnLoading">
        <i class="el-icon-download"></i>
        {{ btnLoading ? '导出中...' : '确认导出' }}
      </el-button>
    </span>
  </el-dialog>
</template>

<script>
export default {
  data() {
    return {
      visible: false,
      btnLoading: false,
      type: 0,
      columns: [],
      checkAll: true,
      isIndeterminate: false,
      columnList: []
    }
  },
  methods: {
    init(columnList) {
      this.visible = true
      this.columnList = columnList
      this.columns = columnList.map(o => o.prop)
    },
    handleCheckAllChange(val) {
      this.columns = val ? this.columnList.map(o => o.prop) : [];
      this.isIndeterminate = false;
    },
    handleCheckedChange(value) {
      let checkedCount = value.length;
      this.checkAll = checkedCount === this.columnList.length;
      this.isIndeterminate = checkedCount > 0 && checkedCount < this.columnList.length;
    },
    downLoad() {
      if (this.columns.length === 0) {
        this.$message.warning('请至少选择一个导出字段');
        return;
      }
      
      this.btnLoading = true;
      
      // 模拟导出过程
      setTimeout(() => {
        this.$emit('download', { dataType: this.type, selectKey: this.columns.join(',') });
        this.btnLoading = false;
        this.visible = false;
        this.$message.success('导出任务已提交,请稍后查看下载文件');
      }, 1000);
    }
  }
}
</script>
<style lang="scss" scoped>
.export-dialog {
  >>> .el-dialog__body {
    padding: 0 !important;
  }
  
  >>> .el-dialog__header {
    padding: 20px 20px 10px 20px;
    border-bottom: 1px solid #ebeef5;
  }
  
  >>> .el-dialog__footer {
    padding: 15px 20px 20px 20px;
    border-top: 1px solid #ebeef5;
    background: #fafafa;
  }
}

.dialog-title {
  display: flex;
  align-items: center;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  
  i {
    margin-right: 8px;
    font-size: 18px;
    color: #409EFF;
  }
}

.export-content {
  padding: 20px;
  max-height: 500px;
  overflow-y: auto;
}

.section-card {
  margin-bottom: 20px;
  border: 1px solid #ebeef5;
  border-radius: 8px;
  overflow: hidden;
  
  &:last-child {
    margin-bottom: 0;
  }
}

.section-header {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  background: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
  font-weight: 600;
  color: #606266;
  
  i {
    margin-right: 8px;
    color: #409EFF;
  }
}

.data-type-group {
  padding: 16px;
  
  .data-type-radio {
    display: block;
    margin-bottom: 12px;
    padding: 12px;
    border: 1px solid #dcdfe6;
    border-radius: 6px;
    transition: all 0.3s;
    
    &:last-child {
      margin-bottom: 0;
    }
    
    &:hover {
      border-color: #409EFF;
      background: #f0f9ff;
    }
    
    >>> .el-radio__input.is-checked + .el-radio__label {
      color: #409EFF;
    }
    
    >>> .el-radio__input.is-checked {
      .el-radio__inner {
        border-color: #409EFF;
        background: #409EFF;
      }
    }
  }
}

.radio-content {
  display: flex;
  align-items: center;
  margin-left: 20px;
  
  i {
    font-size: 20px;
    margin-right: 12px;
    color: #909399;
  }
  
  .radio-title {
    font-weight: 600;
    color: #303133;
    margin-bottom: 4px;
  }
  
  .radio-desc {
    font-size: 12px;
    color: #909399;
  }
}

.field-selection {
  padding: 16px;
}

.select-all-wrapper {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  
  .select-all-checkbox {
    >>> .el-checkbox__label {
      font-weight: 600;
      color: #303133;
    }
  }
  
  .selected-count {
    font-size: 12px;
    color: #909399;
    background: #f0f2f5;
    padding: 4px 8px;
    border-radius: 4px;
  }
}

.field-checkbox-group {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 8px;
  
  .field-checkbox {
    margin: 0;
    padding: 8px 12px;
    border: 1px solid #ebeef5;
    border-radius: 4px;
    transition: all 0.3s;
    
    &:hover {
      border-color: #c6e2ff;
      background: #f0f9ff;
    }
    
    >>> .el-checkbox__input.is-checked + .el-checkbox__label {
      color: #409EFF;
    }
    
    >>> .el-checkbox__label {
      font-size: 13px;
      padding-left: 8px;
    }
  }
}

.dialog-footer {
  text-align: right;
  
  .el-button {
    margin-left: 10px;
    
    i {
      margin-right: 4px;
    }
  }
}

>>> .el-divider {
  margin: 16px 0;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .field-checkbox-group {
    grid-template-columns: 1fr;
  }
  
  .select-all-wrapper {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
}
</style>