Browse Source

feat:conflict

ananzhusen 4 tháng trước cách đây
mục cha
commit
4ed936db61

+ 11 - 9
src/views/components/Graphics.vue

@@ -43,7 +43,8 @@
           </template>
           </template>
         </div>
         </div>
       </div>
       </div>
-      <Data v-if="activeAssets === 'data'"  :group="activedGroup" />
+      <!-- <Data v-if="activeAssets === 'data'"  :group="activedGroup" /> -->
+      <DataSource v-if="activeAssets === 'data'"  :group="activedGroup" />
       <Structure v-else-if="activeAssets === 'structure'" :group="activedGroup"/>
       <Structure v-else-if="activeAssets === 'structure'" :group="activedGroup"/>
       <template v-else>
       <template v-else>
       <div class="list" :class="groupType ? 'two-columns' : ''">
       <div class="list" :class="groupType ? 'two-columns' : ''">
@@ -443,7 +444,8 @@ import {
   WifiIcon
   WifiIcon
 } from 'tdesign-icons-vue-next';
 } from 'tdesign-icons-vue-next';
 import { getNetJsDiagram } from '@/services/material';
 import { getNetJsDiagram } from '@/services/material';
-import Data from './Data.vue';
+// import Data from './Data.vue';
+import DataSource from './DataSource.vue';
 import Structure from './Structure.vue';
 import Structure from './Structure.vue';
 import { useDot } from '@/services/common';
 import { useDot } from '@/services/common';
 import { getToken  } from '@le5le/auth-token';
 import { getToken  } from '@le5le/auth-token';
@@ -546,14 +548,14 @@ const userGroups = [
 const dataGroups = [
 const dataGroups = [
   {
   {
     icon: 'data',
     icon: 'data',
-    name: '数据源',
-    key: '',
-  },
-  {
-    icon: 'install',
-    name: '属性',
+    name: '数据',
     key: '',
     key: '',
   },
   },
+  // {
+  //   icon: 'install',
+  //   name: '属性',
+  //   key: '',
+  // },
   {
   {
     icon: 'code',
     icon: 'code',
     name: '解析',
     name: '解析',
@@ -627,7 +629,7 @@ const assetsChange = (value) => {
     activedGroup.value = userLastName;
     activedGroup.value = userLastName;
   }else if(value === 'data'){
   }else if(value === 'data'){
     groups = dataGroups;
     groups = dataGroups;
-    activedGroup.value = '数据';
+    activedGroup.value = '数据';
   }else if(value === 'structure'){
   }else if(value === 'structure'){
     groups = structureGroups;
     groups = structureGroups;
     activedGroup.value = '图层';
     activedGroup.value = '图层';

+ 21 - 1
src/views/components/Header.vue

@@ -199,7 +199,7 @@
             </div>
             </div>
           </a>
           </a>
         </t-dropdown-item>
         </t-dropdown-item>
-        <t-dropdown-item>
+        <t-dropdown-item  divider="true">
           <a @click="onToggleAnchor">
           <a @click="onToggleAnchor">
             <div
             <div
               class="flex"
               class="flex"
@@ -210,6 +210,14 @@
             </div>
             </div>
           </a>
           </a>
         </t-dropdown-item>
         </t-dropdown-item>
+        <t-dropdown-item>
+          <a @click="onChangeMock">
+            <div class="flex middle">
+              开启全局数据模拟 <span class="flex-grow"></span>
+              <check-icon v-show="data.enableMock" />
+            </div>
+          </a>
+        </t-dropdown-item>
       </t-dropdown-menu>
       </t-dropdown-menu>
     </t-dropdown>
     </t-dropdown>
     <t-dropdown
     <t-dropdown
@@ -3019,6 +3027,18 @@ const nosaveNewfile = ()=>{
   newFile();
   newFile();
   newFileDialog.value.show = false;
   newFileDialog.value.show = false;
 }
 }
+
+const onChangeMock = () => {
+  // @ts-ignore
+  data.enableMock = !data.enableMock;
+  meta2d.store.data.enableMock = data.enableMock;
+  if (data.enableMock) {
+    meta2d.startDataMock();
+  } else {
+    meta2d.stopDataMock();
+  }
+};
+
 </script>
 </script>
 <style lang="postcss" scoped>
 <style lang="postcss" scoped>
 .app-header {
 .app-header {

+ 400 - 88
src/views/components/PenDatas.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div class="props">
   <div class="props">
     <t-collapse
     <t-collapse
-      :defaultValue="['1', '2', '3', '7']"
+      :defaultValue="['1', '2', '3','4', '7']"
       expandIconPlacement="right"
       expandIconPlacement="right"
       :borderless="true"
       :borderless="true"
     >
     >
@@ -173,14 +173,18 @@
           </div>
           </div>
         </t-space>
         </t-space>
       </t-collapse-panel> -->
       </t-collapse-panel> -->
-
-      <t-collapse-panel value="3" :header="$t('数据')">
-        <div class="form-item" v-if="props.pen.name==='tablePlus'">
-          <label class="label">{{$t('数据源')}}</label>
-          <t-select v-model="dataSource" @change="getDataSource" :placeholder="$t('请选择')">
-            <t-option key="api" value="api" :label="$t('API接口')"></t-option>
-            <t-option key="csv" value="csv" :label="$t('CSV文件')"></t-option>
-            <t-option key="excel" value="excel" :label="$t('从Excel导入')"></t-option>
+      <t-collapse-panel value="4" header="设置" v-if="props.pen.name==='tablePlus'">
+        <div class="form-item py-8">
+          <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-option key="sql" value="sql"  label="SQL数据库"/>
           </t-select>
           </t-select>
         </div>
         </div>
         <div class="t-space-item" v-if="props.pen.name==='tablePlus'">
         <div class="t-space-item" v-if="props.pen.name==='tablePlus'">
@@ -197,14 +201,61 @@
                 </t-tooltip>
                 </t-tooltip>
               </div>
               </div>
           </div>
           </div>
+        <div class="form-item py-8" v-if="props.pen.dbid">
+          <label>自动保存 
+            <t-tooltip content="编辑表格后会自动保存到sql数据库" placement="top">
+              <HelpCircleIcon style="font-size: 12px" class="ml-2"/>
+            </t-tooltip>
+          </label>
+          <t-switch size="small" style="margin:8px 8px" v-model="props.pen.autoSave" />
         </div>
         </div>
+        <div class="form-item py-8">
+          <label>可编辑
+            <t-tooltip content="表格可以在运行时被编辑" placement="top">
+              <HelpCircleIcon style="font-size: 12px" class="ml-2"/>
+            </t-tooltip>
+          </label>
+          <t-switch size="small" style="margin:8px 8px" v-model="props.pen.input" />
+        </div>
+        <div class="form-item py-8" v-if="props.pen.columns?.length">
+          <label>不可编辑列</label>
+          <t-select
+            @change="changeColumns"
+            v-model="props.pen.notEdit"
+            :options="props.pen.columns.map(item=>{return {key:item.colKey,value:item.text}})"
+            multiple
+          />
+        </div>
+        </div>
+      </t-collapse-panel>
+      <t-collapse-panel value="3" header="数据">
         <div class="t-space-item">
         <div class="t-space-item">
           <div class="form-item  py-12">
           <div class="form-item  py-12">
               <label style="width: 76px">{{$t('关联设备')}}</label>
               <label style="width: 76px">{{$t('关联设备')}}</label>
               <t-input class="w-full" v-model="props.pen.deviceId" @change="changeValue('deviceId')" :placeholder="$t('设备ID')"></t-input>
               <t-input class="w-full" v-model="props.pen.deviceId" @change="changeValue('deviceId')" :placeholder="$t('设备ID')"></t-input>
           </div>
           </div>
         </div>
         </div>
-        <div class="real-times" v-if="props.pen.realTimes && props.pen.realTimes.length||pen.children?.length">
+        <template  v-if="props.pen.name==='tablePlus'">
+        <div class="t-space-item">
+          <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()"/>
+                </t-tooltip>
+              </div>
+          </div>
+        </div>
+        </template>
+        <div
+          class="real-times"
+          v-if="props.pen.realTimes && props.pen.realTimes.length||pen.children?.length"
+        >
           <div class="grid head">
           <div class="grid head">
             <div class="title">{{$t('数据名')}}</div>
             <div class="title">{{$t('数据名')}}</div>
             <div class="title">{{$t('值')}}</div>
             <div class="title">{{$t('值')}}</div>
@@ -273,11 +324,19 @@
                 </t-badge>
                 </t-badge>
               </t-tooltip> -->
               </t-tooltip> -->
                 <t-dropdown
                 <t-dropdown
-                  :options="triggerOptions"
                   @click="addTrigger(item, $event, i)"
                   @click="addTrigger(item, $event, i)"
                   :minColumnWidth="120"
                   :minColumnWidth="120"
                 >
                 >
                   <ViewListIcon class="hover"/>
                   <ViewListIcon class="hover"/>
+                  <template #dropdown>
+                    <t-dropdown-menu >
+                      <t-dropdown-item v-for="(option) in triggerOptions" :value="option.value">
+                        {{ option.content  }}
+                        <t-divider v-if="option.divider"></t-divider>
+                        <check-icon class="ml-16" v-show="option.value === 'mock' && item.enableMock" />
+                      </t-dropdown-item> 
+                    </t-dropdown-menu>
+                  </template>
                 </t-dropdown>
                 </t-dropdown>
             </div>
             </div>
             <!-- <div class="actions">
             <!-- <div class="actions">
@@ -319,7 +378,7 @@
         </div>
         </div>
         <div v-if="props.pen.children?.length" class="c-titile">
         <div v-if="props.pen.children?.length" class="c-titile">
           <t-tooltip :content="$t('ctrl+shift+点击,可选中子图元')">
           <t-tooltip :content="$t('ctrl+shift+点击,可选中子图元')">
-            {{$t('图元')}}
+            {{$t('图元结构')}}
           </t-tooltip>
           </t-tooltip>
         </div>
         </div>
         <template v-for="(cPen) in childrenPens">
         <template v-for="(cPen) in childrenPens">
@@ -474,47 +533,53 @@
     :top="70"
     :top="70"
     :width="700"
     :width="700"
   >
   >
-    <t-tabs :defaultValue="1">
-      <t-tab-panel :value="1" :destroy-on-hide="false" style="height: 420px" :label="$t('绑定变量')">
-        <div class="form-item mt-12">
-          <label>{{$t('当前绑定')}}:</label>
-          <div class="label" v-if="dataBindDialog.data.bind?.id">
-            <t-tooltip :content="dataBindDialog.data.bind?.id">
-              <t-tag class="mr-8 mb-8" closable @close="onRemoveBind()">
-                {{ dataBindDialog.data.bind?.label }}
-              </t-tag>
-            </t-tooltip>
-          </div>
-          <div class="label gray" v-else>{{$t('无')}}</div>
-        </div>
+    <div class="form-item" style="height: 32px;">
+      <label>当前绑定:</label>
+      <div class="label" v-if="dataBindDialog.data.bind?.id">
+        <t-tooltip :content="dataBindDialog.data.bind?.id">
+          <t-tag class="mr-8 mb-8" closable @close="onRemoveBind()">
+            {{ dataBindDialog.data.bind?.label }}
+          </t-tag>
+        </t-tooltip>
+      </div>
+      <div class="label gray" v-else>无</div>
+    </div>
+    <div class="input-search mb-8 mt-8" style="padding:0px;">
+      <div class="btn" style="left:10px">
+        <img style="margin-top: 7px" src="/img/icon_search_gray.svg" />
+      </div>
+      <t-input
+        style="height: 32px;"
+        v-model="bindSearch"
+        @change="onSearchBind"
+        @enter="onSearchBind"
+        placeholder="搜索绑定变量"
+      />
+    </div>
+    <t-tree 
+      style="height:420px;overflow:auto; scrollbar-width: thin;" 
+      v-model="dataBindDialog.selectedIds" 
+      :activeMultiple="false" 
+      :data="bindTreeData"
+      :expand-level="1"
+      :checkable="true" 
+      :checkStrictly="false" 
+      allow-fold-node-on-filter
+      :filter="bindFilter"
+      @change="doBind"
+    />
+
+    <!-- 
         <div class="form-item flex middle mt-8">
         <div class="form-item flex middle mt-8">
-          <!-- <t-input
-            v-if="dataBindDialog.url"
-            v-model="dataBindDialog.device"
-            placeholder="设备"
-            style="width: 200px"
-          />
-          <t-select
-            v-else
-            class="mr-16"
-            style="width: 200px"
-            v-model="dataBindDialog.device"
-            clearable
-            placeholder="设备"
-            @change="getDataset"
+          <t-input
+            style="width:250px;"
+            placeholder="搜索"
+            v-model="dataBindDialog.input"
+            @change="onSearchDataset"
+            @enter="onSearchDataset"
           >
           >
-            <t-option
-              v-for="(item, i) in dataBindDialog.devices"
-              :key="item"
-              :value="item"
-              :label="item"
-            />
-          </t-select> -->
-
-          <t-input style="width:250px;" v-model="dataBindDialog.input" @change="onSearchDataset" @enter="onSearchDataset" :placeholder="$t('搜索')">
             <template #suffixIcon>
             <template #suffixIcon>
               <search-icon class="hover" @click="onSearchDataset"/>
               <search-icon class="hover" @click="onSearchDataset"/>
-              <!-- <t-icon name="search" class="hover" @click="onSearchDataset" /> -->
             </template>
             </template>
           </t-input>
           </t-input>
         </div>
         </div>
@@ -534,43 +599,59 @@
           :max-height="270"
           :max-height="270"
         >
         >
         </t-table>
         </t-table>
-      </t-tab-panel>
-      <t-tab-panel :value="2" :destroy-on-hide="false" style="height: 420px" :label="$t('本地调试')">
-        <div class="form-item mt-20">
-          <label>{{$t('模拟值')}}:</label>
-          <t-input v-model="dataBindDialog.data.mock"></t-input>
-        </div>
-        <div class="form-item mt-20">
-          <label>{{$t('类型')}}:</label>
-          <t-select class="w-full" :options="typeOptions" v-model="dataBindDialog.data.type" :placeholder="$t('字符串')"></t-select>
-        </div>
-        <div class="form-item mt-12">
-          <label>{{$t('开启')}}:</label>
-          <t-switch class="mt-8" size="small" v-model="dataBindDialog.data.enableMock"></t-switch>
-        </div>
-        <h6 class="desc mt-20">{{$t('模拟值说明')}}</h6>
-        <ul class="desc mt-4">
-          <li class="mt-4">
-            <label class="inline" style="width: 80px">{{$t('固定值')}}:</label>
-            {{$t('直接填写')}},{{$t('例如')}}:10
-          </li>
-          <li class="mt-4">
-            <label class="inline" style="width: 80px">{{$t('随机值')}}:</label>
-            {{$t('值')}}1,{{$t('值')}}2,...。{{$t('例如')}}:1,2,3,4,5
-          </li>
-          <li class="mt-4">
-            <label class="inline" style="width: 80px">{{$t('范围数字')}}:</label>
-            {{$t('最小值')}}-{{$t('最大值')}}。{{$t('例如')}}:0-1.0 {{$t('或')}} 0-100
-          </li>
-          <li class="mt-4">
-            <label class="inline" style="width: 80px">{{$t('随机字符串')}}:</label>
-            [{{$t('长度')}}]。{{$t('例如')}}:[8]
-          </li>
-        </ul>
-      </t-tab-panel>
-    </t-tabs>
+      -->
+  </t-dialog>
+  <t-dialog
+    v-if="dataMockDialog.show"
+    :visible="true"
+    class="data-link-dialog"
+    header="本地调试"
+    @close="dataMockDialog.show = false;"
+    @confirm="dataMockDialog.show = false;"
+    :top="70"
+    :width="700"
+  >
+    <div class="form-item mt-20">
+      <label>模拟值:</label>
+      <t-input v-model="dataMockDialog.data.mock" />
+    </div>
+    <div class="form-item mt-20">
+      <label>类型:</label>
+      <t-select
+        class="w-full"
+        :options="typeOptions"
+        v-model="dataMockDialog.data.type"
+        placeholder="字符串"
+      />
+    </div>
+    <div class="form-item mt-12">
+      <label>开启:</label>
+      <t-switch
+        class="mt-8"
+        size="small"
+        v-model="dataMockDialog.data.enableMock"
+      />
+    </div>
+    <h6 class="desc mt-20" style="font-size: 13px;">模拟值说明</h6>
+    <ul class="desc mt-4" style="list-style-type: none;">
+      <li class="mt-4">
+        <label class="inline" style="width: 80px">固定值:</label>
+        直接填写,例如:10
+      </li>
+      <li class="mt-4">
+        <label class="inline" style="width: 80px">随机值:</label>
+        值1,值2,...。例如:1,2,3,4,5
+      </li>
+      <li class="mt-4">
+        <label class="inline" style="width: 80px">范围数字:</label>
+        最小值-最大值。例如:0-1.0 或 0-100
+      </li>
+      <li class="mt-4">
+        <label class="inline" style="width: 80px">随机字符串:</label>
+        [长度]。例如:[8]
+      </li>
+    </ul>
   </t-dialog>
   </t-dialog>
-
   <t-dialog
   <t-dialog
     v-if="triggersDialog.show"
     v-if="triggersDialog.show"
     :visible="true"
     :visible="true"
@@ -778,6 +859,51 @@
         <CodeEditor :json="true" :language="'json'" v-model="apiDialog.body" class="mt-4" style="height: 50px"></CodeEditor>
         <CodeEditor :json="true" :language="'json'" v-model="apiDialog.body" class="mt-4" style="height: 50px"></CodeEditor>
       </div>
       </div>
   </t-dialog>
   </t-dialog>
+  <t-dialog
+    v-if="sqlDialog.show"
+    :visible="true"
+    class="data-link-dialog"
+    header="绑定sql数据源"
+    @close="sqlDialog.show = false;"
+    @confirm="sqlConnect"
+    :top="70"
+    :width="700"
+  >
+    <div class="form-item  py-12">
+        <label style="width: 76px">SQL数据源</label>
+        <t-select v-model="sqlDialog.dbid" placeholder="请选择数据源" >
+          <t-option v-for="sql in sqlList " @click="sqlChange(sql)" :key="sql.id" :value="sql.id" :label="sql.name+'('+sql.dbType+')'" />
+        </t-select>
+    </div>
+    <div class="form-item mt-8">
+        <label>sql语句</label>
+        <CodeEditor
+          :json="false"
+          :language="'sql'"
+          v-model="sqlDialog.sql"
+          class="mt-4"
+          style="height: 100px"
+        />
+    </div>
+    <div class="form-item mt-8">
+        <label>第几页</label>
+        <t-input-number
+          v-model="sqlDialog.current"
+          theme="normal"
+          :min="1"
+          placeholder="默认1"
+        />
+    </div>
+    <div class="form-item mt-8">
+        <label>每页数量</label>
+        <t-input-number
+          v-model="sqlDialog.pageSize"
+          theme="normal"
+          placeholder="20"
+          :min="1"
+        />
+    </div>
+  </t-dialog>
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
@@ -805,10 +931,11 @@ import Actions from './Actions.vue';
 import { useSelection } from '@/services/selections';
 import { useSelection } from '@/services/selections';
 import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
 import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
 import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
 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 { EllipsisIcon, MoreIcon, LinkIcon, RelativityIcon, AddRectangleIcon, SearchIcon ,DeleteIcon, ArrowRightIcon, CloseIcon, ChevronLeftDoubleIcon, AddIcon, ViewListIcon, CheckIcon, HelpCircleIcon } from 'tdesign-icons-vue-next';
 import { s8 } from '@/services/random';
 import { s8 } from '@/services/random';
 import { importExcel } from '@/services/excel';
 import { importExcel } from '@/services/excel';
 import { importCSV } from '@/services/file';
 import { importCSV } from '@/services/file';
+import { getDevices, getDeviceProperties,getSqlSourceList, doSqlCode } from '@/services/iot';
 
 
 const route = useRoute();
 const route = useRoute();
 const router = useRouter();
 const router = useRouter();
@@ -913,6 +1040,11 @@ const dataBindDialog = reactive<any>({
   data: undefined,
   data: undefined,
 });
 });
 
 
+const dataMockDialog = reactive<any>({
+  show: false,
+  data: undefined,
+});
+
 const ojbectDialog = reactive<any>({
 const ojbectDialog = reactive<any>({
   show: false,
   show: false,
   data: undefined,
   data: undefined,
@@ -1161,9 +1293,84 @@ const onBind = (item: any) => {
     dataBindDialog.selectedIds.push(item.bind.id);
     dataBindDialog.selectedIds.push(item.bind.id);
   }
   }
   dataBindDialog.show = true;
   dataBindDialog.show = true;
-  getDataset();
+  // getDataset();
+  // getIotTree();
+  // getSqlTree();
+  getBindTreeData();
+};
+
+const bindTreeData = ref<any>([]);
+
+const getBindTreeData = ()=>{
+  let data = [];
+  const iotTree = meta2d.store.data.iot?.tree || [];
+  if(iotTree.length){
+    iotTree.forEach((item:any)=>{
+      item.checkable = false;
+    });
+    data.push({
+      label: '物联网平台',
+      value: 'iot',
+      checkable: false,
+      children: iotTree,
+    });
+  }
+  const sqlTree = meta2d.store.data.sqls || [];
+  if(sqlTree.length){
+    data.push({
+      label: 'sql数据源',
+      value: 'sql',
+      checkable: false,
+      children: sqlTree,
+    });
+  }
+  const networks = meta2d.store.data.networks || [];
+  if(networks.length){
+    networks.forEach((item:any)=>{
+      item.checkable = false;
+    });
+    data.push({
+      label: 'MQTT',
+      value: 'network',
+      checkable: false,
+      children:  meta2d.store.data.networks.filter((item)=>item.protocol==='mqtt'),
+    });
+    data.push({
+      label: 'Websocket',
+      value: 'network',
+      checkable: false,
+      children:  meta2d.store.data.networks.filter((item)=>item.protocol==='websocket'),
+    });
+    data.push({
+      label: 'HTTP',
+      value: 'network',
+      checkable: false,
+      children:  meta2d.store.data.networks.filter((item)=>item.protocol==='http'),
+    });
+  }
+  bindTreeData.value = data;
+}
+
+const bindSearch = ref('');
+const bindFilter = ref(null);
+const onSearchBind = () => {
+  bindFilter.value = bindSearch.value ? (node) => { return node.data.label?.indexOf(bindSearch.value) >= 0|| node.data.value?.indexOf(bindSearch.value) >= 0 }: null;
 };
 };
 
 
+const bindValue = ref('');
+
+const doBind = (value:any,context:any)=>{
+  // bindValue.value = [context.node.value];
+  dataBindDialog.selectedIds = [context.node.value];
+  dataBindDialog.data.bind = {
+    id: context.node.value,
+    label: context.node.data._label|| context.node.data.label,
+    class: context.node.data.class,
+    token: context.node.data.token,
+  }
+  meta2d.initBinds();
+}
+
 const onSearchDataset = () => {
 const onSearchDataset = () => {
   debounce(getDataset, 300);
   debounce(getDataset, 300);
 };
 };
@@ -1171,6 +1378,7 @@ const onSearchDataset = () => {
 const getDataset = async () => {
 const getDataset = async () => {
   // @ts-ignore
   // @ts-ignore
   const data: Meta2dBackData = meta2d.data();
   const data: Meta2dBackData = meta2d.data();
+  dataBindDialog.sqls = data.sqls;
   if (!data.dataset) {
   if (!data.dataset) {
     return;
     return;
   }
   }
@@ -1690,6 +1898,10 @@ const triggerOptions = computed(() => {
       content: $t('条件动画'),
       content: $t('条件动画'),
       divider: true
       divider: true
     },
     },
+    {
+      value: 'mock',
+      content: '本地调试',
+    },
     {
     {
       value: 'edit',
       value: 'edit',
       content: $t('编辑'),
       content: $t('编辑'),
@@ -1886,8 +2098,12 @@ const addTrigger = (item:any, e:any, i:any) => {
         ],
         ],
       });
       });
       break;
       break;
+    case 'mock':
+      dataMockDialog.data = item;
+      dataMockDialog.show = true;
+      break;
   }
   }
-  if(!['edit', 'delete'].includes(e.value)){
+  if(!['edit', 'delete','mock'].includes(e.value)){
     emit('tabchange',props.pen.triggers.length-1);
     emit('tabchange',props.pen.triggers.length-1);
   }
   }
 }
 }
@@ -1973,8 +2189,104 @@ const getDataSource = async (e) => {
     }
     }
   } else if (e === 'api') {
   } else if (e === 'api') {
     apiDialog.show = true;
     apiDialog.show = true;
+  } else if (e === 'sql') {
+    // getSqlTree();
+    // sqlDialog.show = true;
+    // props.pen.sql = true;
+    sqlDialog.value.dbid = props.pen.dbid;
+    sqlDialog.value.sql = props.pen.sql||'-- eg:SELECT * FROM "directory"';
+    sqlDialog.value.show = true;
+    sqlDialog.value.current = props.pen.pagination?.current;
+    sqlDialog.value.pageSize = props.pen.pagination?.pageSize;
+    sqlList.value =  await getSqlSourceList();
   }
   }
 }
 }
+const sqlDialog = ref({
+  show: false,
+  dbid: '',
+  sql:'',
+  method: 'list',
+  pageSize: 10,
+  current: 1,
+});
+const sqlList = ref([]);
+const sqlChange = (sql)=>{
+  props.pen.sql = sql;
+}
+const sqlConnect =async ()=>{
+  // console.log('value',sqlDialog.value);
+  // if(sqlDialog.value.method === 'exec'){
+  //   let data:any = await doSqlCode({method:'exec',dbid:sqlDialog.value.dbid,sql: sqlDialog.value.sql});
+  //   console.log("data",data);
+  // }else if(sqlDialog.value.method === 'list'){
+  props.pen.sql = sqlDialog.value.sql;
+  props.pen.dbid = sqlDialog.value.dbid;
+  let sql = sqlDialog.value.sql+' LIMIT '+(sqlDialog.value.pageSize||20)+(sqlDialog.value.current>1?(' OFFSET '+(sqlDialog.value.current-1)*sqlDialog.value.pageSize):'');
+  // }
+  let data:any =await doSqlCode({method:'list',dbid:props.pen.dbid,sql});
+  if(data.error){
+    MessagePlugin.error(data.detail);
+  }else{
+    if(data.length){
+      let columns = [];
+      let colWidth = 0;
+      for(let key in data[0]){
+        if(key === 'id'||key === '_id'){
+          columns.unshift({
+            colKey: key,
+            text: key,
+          });
+        }else{
+          columns.push({
+            colKey: key,
+            text: key,
+          });
+        }
+        
+        let len = data[0][key].length*10
+        if(len>colWidth){
+          colWidth = len;
+        }
+      }
+      if(colWidth>200){
+        colWidth = 200;
+      }
+      let _data = [];
+      data.forEach((item)=>{
+        // _data.push(Object.values(item))
+        let itemData = [];
+        columns.forEach((col)=>{
+          itemData.push(item[col.colKey]);
+        });
+        _data.push(itemData);
+      });
+      meta2d.setValue({
+        id:props.pen.id,
+        data: _data,
+        columns,
+        styles:[],
+        mergeCells:[],
+        colWidth,
+        sqlList:[],
+        whiteSpace:"nowrap",
+        ellipsis:true
+      });
+      MessagePlugin.success("导入成功");
+      sqlDialog.value.show = false;
+    }
+   
+  }
+}
+
+const changeColumns = (e)=>{
+  props.pen.columns.forEach((item)=>{
+    if(e.includes(item.colKey)){
+      item.edited = false;
+    }else{
+      delete item.edited;
+    }
+  });
+}
 
 
 const apiDialog = reactive<any>({
 const apiDialog = reactive<any>({
   show: false,
   show: false,

+ 3 - 2
vite.config.ts

@@ -48,8 +48,9 @@ export default defineConfig({
   },
   },
   server: {
   server: {
     proxy: {
     proxy: {
-      '/image': 'https://v.le5le.com/',
-      '/file': 'https://v.le5le.com/',
+      // '/image': 'https://v.le5le.com/',
+      // '/file': 'https://v.le5le.com/',
+      // '/api': 'http://192.168.110.141:7000/',
       '/api': 'https://v.le5le.com/',
       '/api': 'https://v.le5le.com/',
       '/v/material': 'https://v.le5le.com/',
       '/v/material': 'https://v.le5le.com/',
       '/png': 'https://v.le5le.com/',
       '/png': 'https://v.le5le.com/',