Ver código fonte

feat:tablePlus数据源&选中行绑定

ananzhusen 10 meses atrás
pai
commit
b6a6808b2a

+ 1 - 0
index.html

@@ -54,6 +54,7 @@
     <script defer src="/js/marked.min.js"></script>
     <script defer src="/js/echarts.min.js"></script>
     <script defer src="/js/mycharts.js"></script>
+    <script defer src="/js/papaparse.min.js"></script>
     <script src="/js/rg.js"></script>
   </body>
 </html>

Diferenças do arquivo suprimidas por serem muito extensas
+ 6 - 0
public/js/papaparse.min.js


+ 26 - 16
src/services/excel.ts

@@ -2,7 +2,7 @@ import ExcelJS from 'exceljs';
 import { saveAs } from 'file-saver';
 import { MessagePlugin } from 'tdesign-vue-next';
 
-export async function importExcel(columns: any[]) {
+export async function importExcel(columns?: any[]) {
   return new Promise((resolve, reject) => {
     const input = document.createElement('input');
     input.type = 'file';
@@ -27,25 +27,35 @@ export async function importExcel(columns: any[]) {
             return;
           }
           let data: any = [];
-          let indexKeyMap: any = {};
-          worksheet.eachRow((row, rowNumber) => {
-            let _data: any = {};
-            row.eachCell((cell, colNumber) => {
-              if (rowNumber === 1) {
-                let _index = columns.findIndex(
-                  (item) => item.header === cell.value
-                );
-                if (_index !== -1) {
-                  indexKeyMap[colNumber] = columns[_index].key;
+          if(columns){
+            let indexKeyMap: any = {};
+            worksheet.eachRow((row, rowNumber) => {
+              let _data: any = {};
+              row.eachCell((cell, colNumber) => {
+                if (rowNumber === 1) {
+                  let _index = columns.findIndex(
+                    (item) => item.header === cell.value
+                  );
+                  if (_index !== -1) {
+                    indexKeyMap[colNumber] = columns[_index].key;
+                  }
+                } else {
+                  _data[indexKeyMap[colNumber]] = cell.value;
                 }
-              } else {
-                _data[indexKeyMap[colNumber]] = cell.value;
+              });
+              if (rowNumber !== 1) {
+                data.push(_data);
               }
             });
-            if (rowNumber !== 1) {
+          } else {
+            worksheet.eachRow((row, rowNumber) => {
+              let _data: any = [];
+              row.eachCell((cell, colNumber) => {
+                _data[colNumber-1] = cell.value;
+              });
               data.push(_data);
-            }
-          });
+            });
+          }
           resolve(data);
           MessagePlugin.success('导入成功!');
         };

+ 23 - 0
src/services/file.ts

@@ -1,4 +1,5 @@
 import axios from 'axios';
+import { MessagePlugin } from 'tdesign-vue-next';
 
 export async function upload(
   blob: Blob,
@@ -107,3 +108,25 @@ export function saveToBlob(img: HTMLImageElement): Blob {
   context.drawImage(img, 0, 0, canvas.width, canvas.height);
   return dataURLtoBlob(canvas.toDataURL());
 }
+
+export async function importCSV() {
+  return new Promise((resolve, reject) => {
+    const input = document.createElement('input');
+    input.type = 'file';
+    input.accept =
+      '.csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/zip';
+    input.onchange = (event) => {
+      const elem: any = event.target;
+      if (elem.files && elem.files[0].name.indexOf('.csv') > 0) {
+        //papaparse.js
+        globalThis.Papa.parse(elem.files[0], {
+          complete: function(results) {
+            resolve(results.data); // 输出二维数组
+          }
+        });
+        MessagePlugin.success('导入成功!');
+      }
+    };
+    input.click();
+  });
+}

+ 2 - 2
src/views/components/Custom.vue

@@ -293,7 +293,7 @@ const getPenData = (data: any) => {
         cell.value.textColor = undefined;
         cell.value.fontSize = undefined;
       }
-    } else if (props.pen.calculative.activeCol) {
+    } else if (props.pen.calculative.activeCol !== undefined) {
       cell.value.col = props.pen.calculative.activeCol;
       cell.value.row = undefined;
       let found = props.pen.styles.findIndex((item: any) => {
@@ -308,7 +308,7 @@ const getPenData = (data: any) => {
         cell.value.textColor = undefined;
         cell.value.fontSize = undefined;
       }
-    } else if (props.pen.calculative.activeRow) {
+    } else if (props.pen.calculative.activeRow !== undefined) {
       cell.value.col = undefined;
       cell.value.row = props.pen.calculative.activeRow;
 

+ 2 - 0
src/views/components/Network.vue

@@ -114,6 +114,7 @@
         /> -->
         <CodeEditor
           :json="true"
+          :language="'json'"
           v-model="modelValue.headers"
           class="mt-4"
           style="height: 50px"
@@ -132,6 +133,7 @@
         /> -->
         <CodeEditor
           :json="true"
+          :language="'json'"
           v-model="modelValue.body"
           class="mt-4"
           style="height: 50px"

+ 167 - 19
src/views/components/PenDatas.vue

@@ -141,11 +141,26 @@
       </t-collapse-panel> -->
 
       <t-collapse-panel value="3" header="数据">
+        <div class="form-item"  v-if="props.pen.name==='tablePlus'">
+          <label class="label">数据源</label>
+          <t-select
+            v-model="dataSource"
+            placeholder="请选择"
+            @change="getDataSource"
+          >
+            <t-option key="api" value="api"  label="API接口"/>
+            <t-option key="csv" value="csv"  label="CSV文件"/>
+            <t-option key="excel" value="excel"  label="从Excel导入"/>
+          </t-select>
+        </div>
         <div class="t-space-item" v-if="props.pen.name==='tablePlus'">
-          <div v-if="cell.col!==undefined&&cell.row!==undefined" class="flex between form-item  py-12">
-              <div style="line-height: 30px">
+          <div v-if="cell.row!==undefined" class="flex between form-item  py-12">
+              <div  v-if="cell.col!==undefined"  style="line-height: 30px">
                 当前选中单元格  (第{{ cell.row }}行,第{{ cell.col}}列)
               </div>
+              <div v-else style="line-height: 30px">
+                当前选中行  (第{{ cell.row }}行)
+              </div>
               <div>
                 <t-tooltip content="快捷绑定" placement="top">
                  <link-icon style="width: 13px;margin-right: 26px"class="hover ml-4" @click="onQuickBind()"/>
@@ -786,6 +801,50 @@
       {{ propsDialog.placeholder }}
     </div>
   </t-dialog>
+
+  <t-dialog
+    v-if="apiDialog.show"
+    :visible="true"
+    class="data-dialog"
+    header="API接口"
+    @close="apiDialog.show = false"
+    @confirm="onConfirmAPI"
+  >
+  <div class="form-item mt-8">
+      <label>http地址</label>
+      <t-input
+        placeholder="请输入(临时请求,不会保存)"
+        v-model="apiDialog.url"
+      />
+    </div>
+    <div class="form-item mt-8">
+        <label>请求方式</label>
+        <t-select v-model="apiDialog.method">
+          <t-option key="GET" value="GET" label="GET" />
+          <t-option key="POST" value="POST" label="POST" />
+        </t-select>
+      </div>
+      <div class="form-item mt-8">
+        <label>请求头</label>
+        <CodeEditor
+          :json="true"
+          :language="'json'"
+          v-model="apiDialog.headers"
+          class="mt-4"
+          style="height: 50px"
+        />
+      </div>
+      <div v-if="apiDialog.method === 'POST'" class="form-item mt-8">
+        <label>请求体</label>
+        <CodeEditor
+          :json="true"
+          :language="'json'"
+          v-model="apiDialog.body"
+          class="mt-4"
+          style="height: 50px"
+        />
+      </div>
+  </t-dialog>
 </template>
 
 <script lang="ts" setup>
@@ -815,6 +874,8 @@ import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
 import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
 import { EllipsisIcon, MoreIcon, LinkIcon, RelativityIcon, AddRectangleIcon, SearchIcon ,DeleteIcon, ArrowRightIcon, CloseIcon, ChevronLeftDoubleIcon, AddIcon, ViewListIcon } from 'tdesign-icons-vue-next';
 import { s8 } from '@/services/random';
+import { importExcel } from '@/services/excel';
+import { importCSV } from '@/services/file';
 
 const route = useRoute();
 const router = useRouter();
@@ -1897,6 +1958,9 @@ const getPenData = (e)=>{
     if(props.pen.calculative.activeCell){
       cell.value.col = props.pen.calculative.activeCell.col;
       cell.value.row = props.pen.calculative.activeCell.row;
+    }else if(props.pen.calculative.activeRow !== undefined){
+      cell.value.row = props.pen.calculative.activeRow;
+      cell.value.col = undefined;
     }else{
       cell.value.col = undefined;
       cell.value.row = undefined;
@@ -1905,26 +1969,109 @@ const getPenData = (e)=>{
 }
 
 const onQuickBind = ()=>{
-  if(cell.value.col !== undefined && cell.value.row !== undefined){
+  if(cell.value.row !== undefined){
     if(!props.pen.realTimes){
       props.pen.realTimes = [];
     }
-    let found = props.pen.realTimes.findIndex((item:any)=>{
-      return item.key === `data.${cell.value.row}.${cell.value.col}`;
-    });
-    if(found === -1){
-      props.pen.realTimes.push({
-        label: `第${cell.value.row}行,第${cell.value.col}列`,
-        key: `data.${cell.value.row}.${cell.value.col}`,
-        type: 'float',
+    if(cell.value.col !== undefined){
+      let found = props.pen.realTimes.findIndex((item:any)=>{
+        return item.key === `data.${cell.value.row}.${cell.value.col}`;
       });
-      onBind(props.pen.realTimes[props.pen.realTimes.length-1]);
+      if(found === -1){
+        props.pen.realTimes.push({
+          label: `第${cell.value.row}行,第${cell.value.col}列`,
+          key: `data.${cell.value.row}.${cell.value.col}`,
+          type: 'float',
+        });
+        onBind(props.pen.realTimes[props.pen.realTimes.length-1]);
+      }else{
+        onBind(props.pen.realTimes[found]);
+      }
     }else{
-      onBind(props.pen.realTimes[found]);
+      let found = props.pen.realTimes.findIndex((item:any)=>{
+        return item.key === `data.${cell.value.row}`;
+      });
+      if(found === -1){
+        props.pen.realTimes.push({
+          label: `第${cell.value.row}行`,
+          key: `data.${cell.value.row}`,
+          type: 'array',
+        });
+        onBind(props.pen.realTimes[props.pen.realTimes.length-1]);
+      }else{
+        onBind(props.pen.realTimes[found]);
+      }
     }
   }
 }
 
+const dataSource = ref('');
+
+const getDataSource = async (e) => {
+  dataSource.value = '';
+  if (e === 'excel') {
+    let data = await importExcel();
+    if (Array.isArray(data) && Array.isArray(data[0])) {
+      meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
+    } else {
+      MessagePlugin.warning("数据格式必需是二维数组");
+    }
+  } else if (e === 'csv') {
+    let data = await importCSV();
+    if (Array.isArray(data) && Array.isArray(data[0])) {
+      meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
+    } else {
+      MessagePlugin.warning("数据格式必需是二维数组");
+    }
+  } else if (e === 'api') {
+    apiDialog.show = true;
+  }
+}
+
+const apiDialog = reactive<any>({
+  show: false,
+});
+
+const onConfirmAPI = async () => {
+  if (!apiDialog.url) {
+    MessagePlugin.warning('请输入API地址');
+    return;
+  }
+  const res: Response = await fetch(apiDialog.url, {
+    headers: apiDialog.headers,
+    method: apiDialog.method || 'GET',
+    body: apiDialog.method === 'GET' ? undefined : JSON.stringify(apiDialog.body),
+  });
+  let data: any = JSON.parse(await res.text());
+  if (data.data) {
+    data = data.data;
+  }
+  if (data.list) {
+    data = data.list;
+  }
+
+  if (Array.isArray(data)) {
+    if (Array.isArray(data[0])) {
+    } else {
+      let _data = [];
+      data.forEach((item) => {
+        _data.push(Object.values(item));
+
+      })
+      data = _data;
+    }
+    if (Array.isArray(data) && Array.isArray(data[0])) {
+      meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
+      MessagePlugin.success("导入成功");
+    } else {
+      MessagePlugin.warning("数据格式必需是二维数组");
+    }
+    apiDialog.show = false;
+  } else {
+    MessagePlugin.warning("数据格式必需是数组类型");
+  }
+};
+
 onMounted(() => {
    meta2d.on('click',getPenData);
    getPenData({});
@@ -1974,12 +2121,13 @@ onUnmounted(() => {
     color: var(--color);
     font-weight: 700;
   }
-
-  .label {
-    width: fix-content;
-    font-size: 10px;
-    line-height: 28px;
-    color: var(--color-desc);
+  .real-times{
+    .label {
+      width: fix-content;
+      font-size: 10px;
+      line-height: 28px;
+      color: var(--color-desc);
+    }
   }
 
   .value {

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff