Ver Fonte

公共数据源管理对接ing

threethousanddream há 2 semanas atrás
pai
commit
2ddcd64955
5 ficheiros alterados com 352 adições e 15 exclusões
  1. 1 1
      package.json
  2. 16 0
      src/api/ds.js
  3. 19 0
      src/utils/index.js
  4. 306 0
      src/views/system/components/FileUpload.vue
  5. 10 14
      src/views/system/dsDetail.vue

+ 1 - 1
package.json

@@ -26,7 +26,7 @@
     "echarts": "^5.4.2",
     "echarts-gl": "^2.0.9",
     "echarts-wordcloud": "^2.1.0",
-    "element-plus": "^2.7.7",
+    "element-plus": "^2.2.26",
     "file-saver": "^2.0.5",
     "js-cookie": "3.0.1",
     "js-table2excel": "^1.0.3",

+ 16 - 0
src/api/ds.js

@@ -20,3 +20,19 @@ export const categoryList = params => request.get(bigdataPrefix + '/tablecategor
 export const categoryDel = params => request.post(bigdataPrefix + '/tablecategory/remove', {}, {params});
 export const categorySave = data => request.post(bigdataPrefix + '/tablecategory/submit', data);
 export const categoryUpdate = data => request.post(bigdataPrefix + '/tablecategory/update', data);
+
+export const tableFileUpload = data => request({
+  url: bigdataPrefix + '/cube/file/uploadToDs',
+  method: 'post',
+  data,
+  headers: {'Content-Type': 'multipart/form-data'},
+});
+
+export const getDatasourceDetail = params => {
+  if (!params.id) return;
+  return request({
+    url: bigdataPrefix + '/report/reportdatasource/detail',
+    method: 'get',
+    params,
+  });
+};

+ 19 - 0
src/utils/index.js

@@ -108,4 +108,23 @@ export function objectToParam(params) {
     }
   }
   return paramsUrl.toString()
+}
+export function dateFormat(date, fmt = 'YYYY-mm-dd HH:MM:SS') {
+  let ret;
+  const opt = {
+    'Y+': date.getFullYear().toString(), // 年
+    'm+': (date.getMonth() + 1).toString(), // 月
+    'd+': date.getDate().toString(), // 日
+    'H+': date.getHours().toString(), // 时
+    'M+': date.getMinutes().toString(), // 分
+    'S+': date.getSeconds().toString(), // 秒
+    // 有其他格式化字符需求可以继续添加,必须转化成字符串
+  };
+  for (let k in opt) {
+    ret = new RegExp('(' + k + ')').exec(fmt);
+    if (ret) {
+      fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'));
+    }
+  }
+  return fmt;
 }

+ 306 - 0
src/views/system/components/FileUpload.vue

@@ -0,0 +1,306 @@
+<template>
+  <el-dialog
+    :direction="direction || 'rtl'"
+    width="900px"
+    :model-value="show"
+    :wrapperClosable="false"
+    class="upload-drawer dataset-file-upload"
+    title="上传文件"
+    v-bind="$attrs"
+    @close="onClose"
+  >
+    <div
+      v-loading="uploadLoading"
+      element-loading-spinner="el-icon-loading"
+      element-loading-text="上传中"
+      style="padding: 0 20px; overflow: auto"
+    >
+      <el-form label-width="80px" size="small">
+        <el-form-item label="上传文件" required>
+          <el-upload
+            ref="upload"
+            :action="fileUploadUrl + '/bi-api/cube/file/structure'"
+            :before-upload="beforeUpload"
+            :data="{ columnNameType: fileForm.columnNameType }"
+            :headers="fileUploadHeaders"
+            :on-success="uploadSuccess"
+            class="upload" :limit="1"
+            :on-remove="onRemove"
+          >
+            <el-button size="small" type="primary" @click.prevent="handleClick" ref="uploadBtn">点击上传</el-button>
+          </el-upload>
+          <div class="tips ml-10" style="font-size: 12px; color: rgba(160, 160, 160, 1);margin-left: 3px;">
+            <el-icon>
+              <InfoFilled/>
+            </el-icon>
+            单文件上传,支持 xlsx、xls、csv 格式文件,默认选择第一个sheet
+          </div>
+        </el-form-item>
+        <el-form-item label="物理表名" required>
+          <el-input v-model="fileForm.tableName" :maxlength="30" placeholder="请使用英文/数字/下划线"></el-input>
+          <div class="tips ml-10" style="font-size: 12px; color: rgba(160, 160, 160, 1)">
+            <el-icon>
+              <InfoFilled/>
+            </el-icon>
+            物理表名字段:由英文,数字,下划线组成,字母开头
+          </div>
+        </el-form-item>
+        <el-form-item label="备注表名" required>
+          <el-input v-model="fileForm.tableComment"></el-input>
+        </el-form-item>
+        <el-form-item label="选择分类">
+          <el-select v-model="fileForm.classifyId">
+            <el-option :value="0" label="全部"></el-option>
+            <el-option
+              v-for="(item, i) of systemStore.state.tableCategoryList"
+              :key="i"
+              :label="item.categoryName"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="物理字段创建类型" label-width="112">
+          <el-radio @change="getTableColumnList" v-model="columnNameType" label="pinyinAllColumnName">全拼</el-radio>
+          <el-radio @change="getTableColumnList" v-model="columnNameType" label="pinyinFirstLetterColumnName">
+            拼音首字母
+          </el-radio>
+          <el-radio @change="getTableColumnList" v-model="columnNameType" label="systemColumnName">系统默认</el-radio>
+          <div class="tips" style="font-size: 12px; color: rgba(160, 160, 160, 1)">
+            <i class="el-icon-info"></i>
+            文件上传后,创建的物理表名和字段名将会按照此配置创建
+          </div>
+        </el-form-item>
+        <el-form-item label="字段大小写转换" label-width="100">
+          <el-radio @change="getTableColumnList" v-model="isCase" label="xiaoxie">小写</el-radio>
+          <el-radio @change="getTableColumnList" v-model="isCase" label="daxie">大写</el-radio>
+        </el-form-item>
+        <div style="font-size: 14px; margin-bottom: 20px; display: flex">字段配置</div>
+      </el-form>
+      <el-table :data="fileForm.tableColumnList" size="default">
+        <el-table-column label="原始字段">
+          <template v-slot="{ row }">
+            <el-input v-model="row.comment" size="small"></el-input>
+          </template>
+        </el-table-column>
+        <el-table-column label="物理字段">
+          <template v-slot="{ row }">
+            <el-input v-model="row.columnName" size="small" :maxlength="30" :show-word-limit="isOracle"></el-input>
+          </template>
+        </el-table-column>
+        <el-table-column label="数据类型">
+          <template v-slot="{ row }">
+            <el-select v-model="row.columnType" size="small" @change="changeString(row)">
+              <el-option label="整形" value="INT"></el-option>
+              <el-option label="数字" value="NUMBER"></el-option>
+              <el-option label="日期" value="DATETIME"></el-option>
+              <el-option label="字符串" value="STRING"></el-option>
+              <el-option label="长字符串" value="LARGE_STRING"></el-option>
+              <el-option label="长整数" value="BIGINT"></el-option>
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column label="字段长度">
+          <template v-slot="{ row }">
+            <el-input-number
+              :value="row.columnSize || 255" min="0" size="small" style="width: 120px"
+              v-model="row.columnSize" v-if="row.columnType === 'STRING' || row.columnType === 'NUMBER'"
+            ></el-input-number>
+          </template>
+        </el-table-column>
+        <el-table-column label="字段位数" width="200">
+          <template #header>
+            <div style="display: flex; align-items: center; gap: 10px">
+              字段位数:
+              <el-input
+                v-model="decimalDigits" @change="changeDecimalDigits" style="width: 70px"
+                size="small" placeholder="批量设置"
+              />
+            </div>
+          </template>
+          <template v-slot="{ row }">
+            <el-input-number
+              size="small" min="0" :value="row.decimalDigits || 4" style="width: 120px"
+              v-model="row.decimalDigits" v-if="row.columnType === 'NUMBER'"
+            ></el-input-number>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="dialog-btns">
+      <el-button size="default" @click="$emit('closeDrawer')">取消</el-button>
+      <el-button size="default" type="primary" @click="onUploadConfirm">确定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import {getToken} from '@/utils/auth';
+import {dateFormat} from "/@/utils";
+import {tableFileUpload, getDatasourceDetail} from '@/api/ds';
+import useSystemStore from "/@/stores/modules/system";
+import {ElMessage, ElMessageBox, ElLoading} from "element-plus";
+
+export default {
+  props: ['show', 'direction', 'datasourceId', "categoryId",],
+  data() {
+    return {
+      fileUploadUrl: window._CONFIG.APIHead,
+      fileUploadHeaders: {Authorization: getToken()},
+      fileForm: {file: null, tableName: '', tableComment: '', tableColumnList: [], dsId: 0, classifyId: 0},
+      uploadLoading: false,
+      isOracle: false,
+      decimalDigits: '',
+      columnNameType: 'pinyinAllColumnName',
+      isCase: 'xiaoxie',
+    };
+  },
+  computed: {
+    ...mapStores(useSystemStore),
+  },
+  watch: {
+    show(val) {
+      this.fileForm.classifyId = this.categoryId
+      if (!val) {
+        this.fileForm = {...this.fileForm, file: null, tableName: '', tableComment: '', tableColumnList: []};
+        try {
+          this.$refs.upload.clearFiles();
+        } catch (e) {
+          console.log(e)
+        }
+      }
+    },
+  },
+  created() {
+    getDatasourceDetail({id: this.datasourceId}).then(res => {
+      if (res.data.dsTypeSyl === 'oracle') {
+        this.isOracle = true;
+      }
+    });
+  },
+  methods: {
+    onClose() {
+      this.$emit('closeDrawer')
+    },
+    handleClick(event) {
+      if (this.fileForm.file) {
+        event.preventDefault()
+        event.stopPropagation()
+        ElMessageBox.confirm('确定覆盖当前文件?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          this.$refs.upload.clearFiles()
+          this.onRemove()
+          this.$refs.uploadBtn.$el.click()
+        }).catch(() => {
+        })
+      }
+    },
+    // 文件上传确认提交
+    onUploadConfirm() {
+      if (!this.fileForm.file) {
+        return ElMessage({type: 'error', message: '请上传文件'});
+      }
+      if (!this.fileForm.tableName) {
+        return ElMessage({type: 'error', message: '请填写表名'});
+      }
+      if (!this.fileForm.tableComment) {
+        return ElMessage({type: 'error', message: '请填写表注释名'});
+      }
+      if (!/^[a-zA-Z][_\d\w]*$/g.test(this.fileForm.tableName)) {
+        return ElMessage({type: 'error', message: '请检查表名拼写'});
+      }
+      if (this.datasourceId) {
+        this.fileForm.dsId = this.datasourceId;
+      }
+      let data = {...this.fileForm};
+      delete data.tableColumnList;
+      let formData = new FormData();
+      Object.keys(data).forEach(k => formData.append(k, data[k]));
+      formData.append('tableColumnList', JSON.stringify(this.fileForm.tableColumnList));
+      this.uploadLoading = true;
+      tableFileUpload(formData).then(res => {
+        if (res.code === 200) {
+          ElMessage({type: 'success', message: '上传成功'});
+          this.$emit('closeDrawer')
+        } else {
+          ElMessage({type: 'error', message: res.msg});
+        }
+      }).finally(() => (this.uploadLoading = false));
+    },
+    // 文件上传成功后
+    uploadSuccess(response, file) {
+      if (response.code === 200) {
+        this.structure = response.data
+        this.fileForm.file = file.raw;
+        this.getTableColumnList();
+        this.fileForm.tableComment = file.name.split('.')[0];
+        this.fileForm.tableName = 'file_table_' + dateFormat(new Date(), 'YYYYmmdd_HHMMSS');
+      } else {
+        ElMessage({type: 'error', message: response.msg || '服务器错误'});
+      }
+    },
+    onRemove() {
+      this.fileForm.file = null
+      this.fileForm.tableComment = ''
+      this.fileForm.tableName = ''
+      this.fileForm.tableColumnList = []
+    },
+    getTableColumnList() {
+      this.fileForm.tableColumnList = this.structure.map(i => {
+        i.columnName = i[this.columnNameType];
+        i.columnName = this.isCase === 'xiaoxie' ? i.columnName.toLowerCase() : i.columnName.toUpperCase();
+        i.columnSize = i.columnSize || 255;
+        i.decimalDigits = i.decimalDigits || 4;
+        return i;
+      });
+    },
+    // excel文件上传校验
+    beforeUpload(file) {
+      let nameArr = file.name.split('.');
+      if (!['xlsx', 'xls', 'csv'].includes(nameArr[nameArr.length - 1])) {
+        ElMessage({type: 'error', message: '请检查文件格式'});
+        return false;
+      } else {
+        return true;
+      }
+    },
+    changeDecimalDigits(val) {
+      this.fileForm.tableColumnList = this.fileForm.tableColumnList.map(i => ({...i, decimalDigits: val || 4}));
+    },
+    changeString(row) {
+      if (row.columnType === 'NUMBER') {
+        row.columnSize = 20;
+      } else {
+        row.columnSize = 255;
+      }
+    },
+  },
+};
+</script>
+<style lang="scss">
+.dataset-file-upload {
+  max-height: 80% !important;
+  display: flex;
+  flex-direction: column;
+  .el-dialog__header {
+    flex: 0 0 56px;
+    margin: 0;
+  }
+  .el-dialog__body {
+    flex: 1;
+    overflow-y: auto;
+  }
+  .upload {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    .el-upload-list__item {
+      margin-top: 0;
+    }
+    .el-upload-list {
+      flex: 1;
+    }
+  }
+}
+</style>

+ 10 - 14
src/views/system/dsDetail.vue

@@ -93,17 +93,14 @@
       </el-table>
     </el-dialog>
     <UploadBox v-if="uploadBoxVisible" ref="UploadBox" @UploadChange="UploadChange"/>
-    <!-- 文件上传抽屉 -->
-    <!--    <dataset-file-upload-->
-    <!--      ref="upload"-->
-    <!--      v-model="showUpload"-->
-    <!--      :datasource-id="datasourceId"-->
-    <!--      direction="btt"-->
-    <!--      size="900px"-->
-    <!--      @closeDrawer="closeDrawer"-->
-    <!--      :category-id="nowCategoryId"-->
-    <!--      :showCategory="true"-->
-    <!--    ></dataset-file-upload>-->
+    <FileUpload
+      ref="upload"
+      :show="showUpload"
+      :datasource-id="datasourceId"
+      @closeDrawer="closeDrawer"
+      :category-id="nowCategoryId"
+      :showCategory="true"
+    ></FileUpload>
   </div>
 </template>
 <script>
@@ -113,11 +110,10 @@ import TableCategory from './components/TableCategory.vue';
 import {Plus, QuestionFilled} from "@element-plus/icons-vue";
 import useSystemStore from '@/stores/modules/system'
 import UploadBox from './components/UploadBox.vue';
-// import DatasetFileUpload from '@/views/newbi/dataset/comps/datasetFileUpload.vue';
+import FileUpload from './components/FileUpload.vue'
 
 export default {
-  // components: {DatasetFileUpload, UploadBox, TableCategory},
-  components: {TableCategory, UploadBox},
+  components: {TableCategory, UploadBox, FileUpload},
   data() {
     return {
       datasourceId: 0,