<template>
  <div class="dataset-edit">
    <!-- 表字段预览弹框 -->
    <el-dialog :visible.sync="showViewFields" append-to-body class="dataset-edit-table-fields" title="字段预览" width="400px">
      <div v-if="nowTable" class="title">
        {{ nowTable.sqlName ? nowTable.sqlName + ' ' + nowTable.viewName : nowTable.tableComments + ' ' + nowTable.tableViewName }}
      </div>
      <el-table v-loading="nowTable && !nowTable.fields.length" :data="nowTable && nowTable.fields" border height="400px" size="mini">
        <el-table-column label="字段名" prop="columnName"></el-table-column>
        <el-table-column label="注释" prop="columnComment"></el-table-column>
        <el-table-column label="类型" prop="viewDataType"></el-table-column>
      </el-table>
    </el-dialog>
    <!-- 文件上传抽屉 -->
    <!--    <dataset-file-upload-->
    <!--      ref="upload" v-model="showUpload" :fileTableList="fileTableList" :tableSearchKey="tableSearchKey"-->
    <!--      @getTables="getTables" @updateFileTableSearched="$event=>fileTableListSelected=$event"-->
    <!--    ></dataset-file-upload>-->
    <!-- 表连接编辑抽屉 -->
    <el-drawer v-if="nowNode && rightNode" :show-close="false" :modal="false" :visible.sync="showEditJoin" class="join-drawer" direction="rtl" size="700px" title="编辑表关联">
      <div class="field-panel">
        <div class="panel my-shadow">
          <div class="title">{{ nowNode.target }}</div>
          <div class="field-title">
            <div>物理字段</div>
            <el-input v-model="nowNode.key" clearable placeholder="筛选字段" size="mini" style="width: 140px" @input="onTableSearchFields(nowNode)"></el-input>
            <div>
              <el-button size="mini" type="text" @click="onSelectFieldBatch('left', 0)">全选</el-button>
              <span style="margin: 0 3px">/</span>
              <el-button size="mini" type="text" @click="onSelectFieldBatch('left', 1)">全不选</el-button>
            </div>
          </div>
          <el-table v-loading="!nowNode.fields.length" :data="nowNode.searched" size="mini">
            <el-table-column align="center" label="展示" width="50">
              <template slot-scope="field">
                <el-checkbox v-model="field.row.hiddenStatus" :false-label="1" :true-label="0"></el-checkbox>
              </template>
            </el-table-column>
            <el-table-column label="字段名">
              <template slot-scope="scope">
                <span v-if="scope.row.checkFlag === 1" style="color: #67c23a">{{ scope.row.columnName }}</span>
                <span v-if="scope.row.checkFlag === 2" style="color: #f56c6c">{{ scope.row.columnName }}</span>
                <span v-if="!scope.row.checkFlag">{{ scope.row.columnName }}</span>
              </template>
            </el-table-column>
            <el-table-column label="注释" prop="columnComment"></el-table-column>
          </el-table>
          <!--          <div class="field-title">计算字段</div>-->
          <!--          <el-table v-loading="!nowNode.fields.length" :data="nowNode.computed" size="mini">-->
          <!--            <el-table-column align="center" label="展示" width="50">-->
          <!--              <template slot-scope="field">-->
          <!--                <el-checkbox v-model="field.row.hiddenStatus" :false-label="1" :true-label="0"></el-checkbox>-->
          <!--              </template>-->
          <!--            </el-table-column>-->
          <!--            <el-table-column label="展示名" prop="columnTitle"></el-table-column>-->
          <!--          </el-table>-->
          <!--          <el-button-->
          <!--            icon="el-icon-plus" size="mini" style="margin: 10px 95px 0;" @click="onAddComputedField('left')"-->
          <!--          >-->
          <!--            新建计算字段-->
          <!--          </el-button>-->
        </div>
        <div class="panel my-shadow">
          <div class="title">{{ rightNode.target }}</div>
          <div class="field-title">
            <div>物理字段</div>
            <el-input v-model="rightNode.key" clearable placeholder="筛选字段" size="mini" style="width: 140px" @input="onTableSearchFields(rightNode)"></el-input>
            <div>
              <el-button size="mini" type="text" @click="onSelectFieldBatch('right', 0)">全选</el-button>
              <span style="margin: 0 3px">/</span>
              <el-button size="mini" type="text" @click="onSelectFieldBatch('right', 1)">全不选</el-button>
            </div>
          </div>
          <el-table v-loading="!rightNode.fields.length" :data="rightNode.searched" size="mini">
            <el-table-column align="center" label="展示" width="50">
              <template slot-scope="field">
                <el-checkbox v-model="field.row.hiddenStatus" :false-label="1" :true-label="0"></el-checkbox>
              </template>
            </el-table-column>
            <el-table-column label="字段名">
              <template slot-scope="scope">
                <span v-if="scope.row.checkFlag === 1" style="color: #67c23a">{{ scope.row.columnName }}</span>
                <span v-if="scope.row.checkFlag === 2" style="color: #f56c6c">{{ scope.row.columnName }}</span>
                <span v-if="!scope.row.checkFlag">{{ scope.row.columnName }}</span>
              </template>
            </el-table-column>
            <el-table-column label="注释" prop="columnComment"></el-table-column>
          </el-table>
          <!--          <div class="field-title">计算字段</div>-->
          <!--          <el-table v-loading="!rightNode.fields.length" :data="rightNode.computed" size="mini">-->
          <!--            <el-table-column align="center" label="展示" width="50">-->
          <!--              <template slot-scope="field">-->
          <!--                <el-checkbox v-model="field.row.hiddenStatus" :false-label="1" :true-label="0"></el-checkbox>-->
          <!--              </template>-->
          <!--            </el-table-column>-->
          <!--            <el-table-column label="展示名" prop="columnTitle"></el-table-column>-->
          <!--          </el-table>-->
          <!--          <el-button-->
          <!--            icon="el-icon-plus" size="mini" style="margin: 10px 95px 0;" @click="onAddComputedField('right')"-->
          <!--          >-->
          <!--            新建计算字段-->
          <!--          </el-button>-->
        </div>
      </div>
      <div class="join-wrapper my-shadow">
        <div class="join-title">
          <span style="flex: 1">数据关联</span>
          <el-select v-model="joinForm.joinType" size="mini">
            <el-option label="左关联" value="LEFT_JOIN"></el-option>
            <el-option label="右关联" value="RIGHT_JOIN"></el-option>
            <el-option label="内关联" value="INNER_JOIN"></el-option>
          </el-select>
          <el-button icon="el-icon-plus" plain size="mini" type="primary" @click="onAddJoinKey"> 添加关联字段 </el-button>
        </div>
        <div v-for="(key, i) of joinForm.joinKeys" :key="i" class="join-key">
          <div class="key-item">
            <!--            <el-checkbox v-model="key.sourceKeyVtState" @change="key.sourceKey = ''"> 计算字段</el-checkbox>-->
            <el-select v-if="!key.sourceKeyVtState" v-model="key.sourceKey" filterable size="mini" @change="onJoinKeyChange(key)">
              <el-option v-for="(k, j) of nowNode.fields" :key="j" :label="k.columnName + '【' + k.columnTitle + '】'" :value="k.columnName"></el-option>
            </el-select>
            <el-select v-else v-model="key.sourceKey" filterable size="mini" @change="onJoinKeyChange(key)">
              <el-option v-for="(k, j) of nowNode.computed" :key="j" :label="'【' + k.columnTitle + '】'" :value="k.columnFormula"></el-option>
            </el-select>
          </div>
          <div class="key-item">
            <!--            <el-checkbox v-model="key.targetKeyVtState" @change="key.targetKey = ''"> 计算字段</el-checkbox>-->
            <el-select v-if="!key.targetKeyVtState" v-model="key.targetKey" filterable size="mini" @change="onJoinKeyChange(key)">
              <el-option v-for="(k, j) of rightNode.fields" :key="j" :label="k.columnName + '【' + k.columnTitle + '】'" :value="k.columnName"></el-option>
            </el-select>
            <el-select v-else v-model="key.targetKey" filterable size="mini" @change="onJoinKeyChange(key)">
              <el-option v-for="(k, j) of rightNode.computed" :key="j" :label="'【' + k.columnTitle + '】'" :value="k.columnFormula"></el-option>
            </el-select>
          </div>
          <i class="el-icon-delete" @click="onDelJoinKey(i)"></i>
        </div>
        <div class="btns">
          <el-button size="small" @click="showEditJoin = false">取消</el-button>
          <el-button size="small" type="primary" @click="onConfirmJoin"> 确定</el-button>
        </div>
      </div>
    </el-drawer>
    <!-- 节点字段选择抽屉 -->
    <el-drawer v-if="nowNode" :visible.sync="showFieldsSelect" :modal="false" class="fields-drawer" direction="rtl" size="500px" title="字段选择">
      <div class="title">{{ nowNode.comment + ' 表名 :【' + nowNode.target + '】' }}</div>
      <el-table :data="nowNode.fields" size="mini">
        <el-table-column align="center" label="展示" width="50">
          <template slot-scope="field">
            <el-checkbox v-model="field.row.hiddenStatus" :false-label="1" :true-label="0"></el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="物理字段">
          <template slot-scope="scope">
            <span v-if="scope.row.checkFlag === 1" style="color: #67c23a">{{ scope.row.columnName }}</span>
            <span v-if="scope.row.checkFlag === 2" style="color: #f56c6c">{{ scope.row.columnName }}</span>
            <span v-if="!scope.row.checkFlag">{{ scope.row.columnName }}</span>
          </template>
        </el-table-column>
        <el-table-column label="数据类型" prop="viewDataType"> </el-table-column>
        <el-table-column label="注释">
          <template slot-scope="field">
            <el-input v-model="field.row.columnComment" size="mini"></el-input>
          </template>
        </el-table-column>
        <el-table-column align="center" label="操作" width="80px">
          <template slot-scope="field">
            <el-button plain size="mini" type="danger" @click="onFieldDel(field.row)"> 删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-drawer>
    <!-- 计算字段编辑弹窗 -->
    <el-dialog
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :title="(editComputedFieldType == 'add' ? '添加' : '编辑') + '计算字段'"
      :visible.sync="showEditComputedField"
      append-to-body
      class="dataset-edit-computed-fields"
      width="920px"
    >
      <div class="name">
        <div class="label">字段展示名</div>
        <el-input v-model="nowComputedField.columnTitle" placeholder="请输入字段名称" size="mini"></el-input>
      </div>
      <div class="panels">
        <div class="main">
          <div class="label label-title">
            <!--            <span class="flex-between">-->
            <!--              字段表达式-->
            <!--              <el-button class="ml-10" type="text" @click="dialogGpt = true">AI编写</el-button>-->
            <!--              <el-dialog :modal="false" :visible.sync="dialogGpt">-->
            <!--                <div class="flex-center">-->
            <!--                  <el-input v-model="gptKeyword" @keydown.enter="gptSubmit"></el-input>-->
            <!--                  <el-button :loading="gptLoading" class="ml-30" @click="gptSubmit">生成sql</el-button>-->
            <!--                </div>-->
            <!--              </el-dialog>-->
            <!--            </span>-->
            <el-popover ref="paramSelector" placement="bottom-start" trigger="click">
              <el-cascader-panel v-model="nowParam" :options="paramList" :props="{ expandTrigger: 'click', emitPath: false, value: 'paramKey' }" @change="onSetParam"></el-cascader-panel>
              <span slot="reference" class="label" style="color: #409eff; cursor: pointer"> <i class="el-icon-plus"></i> 添加全局参数 </span>
            </el-popover>
          </div>
          <b-ace-editor ref="editor" v-model="nowComputedField.columnFormula" height="240" lang="sql" snippets wrap> </b-ace-editor>
          <div class="form-item">
            <div class="label">选择数据表</div>
            <el-select v-model="nowComputedField.tableName" :disabled="!computedFieldCanSelectTable" size="mini">
              <!--              <el-option label="不选择" value=""></el-option>-->
              <el-option v-for="t of availableTables" :key="t.value" :label="t.name" :value="t.value"></el-option>
            </el-select>
          </div>
          <div class="form-item">
            <div class="label">字段类型</div>
            <el-radio-group v-model="nowComputedField.dimensionType">
              <el-radio label="WEIDU">维度</el-radio>
              <el-radio label="ZHIBIAO">指标</el-radio>
            </el-radio-group>
          </div>
          <div class="form-item">
            <div class="label">计算字段数据类型</div>
            <el-radio-group v-model="nowComputedField.oldViewDataType">
              <el-radio label="STRING">字符串</el-radio>
              <el-radio label="DATETIME">日期时间</el-radio>
              <el-radio label="NUMBER">数字</el-radio>
            </el-radio-group>
          </div>
          <div class="form-item">
            <div class="label">展示数据类型</div>
            <el-radio-group v-model="nowComputedField.viewDataType">
              <el-radio label="STRING">字符串</el-radio>
              <el-radio label="DATETIME">日期时间</el-radio>
              <el-radio label="NUMBER">数字</el-radio>
            </el-radio-group>
          </div>
          <div class="form-item">
            <div class="label">字段描述</div>
            <el-input v-model="nowComputedField.columnComment" size="mini" type="textarea"></el-input>
          </div>
        </div>
        <div class="panel" style="margin-right: 10px">
          <div class="label">点击引用字段</div>
          <div class="search-box">
            <el-input v-model="computedSearchKey" clearable placeholder="输入以搜索" size="mini"></el-input>
          </div>
          <div class="fields">
            <div class="tab">维度</div>
            <template v-for="field of tobeChooseWeiduSearched">
              <div v-if="nowComputedField.columnTitle !== field.columnTitle" :key="field.columnTitle" :title="field.columnName" class="weidu" @click="onComputedAddField(field)">
                {{ field.columnTitle + '【' + field.columnName + '】' }}
              </div>
            </template>
            <div class="tab">指标</div>
            <template v-for="field of tobeChooseZhibiaoSearched">
              <div v-if="nowComputedField.columnTitle !== field.columnTitle" :key="field.columnTitle" :title="field.columnName" class="zhibiao" @click="onComputedAddField(field)">
                {{ field.columnTitle + '【' + field.columnName + '】' }}
              </div>
            </template>
          </div>
        </div>
        <div class="panel">
          <div class="label">点击引用函数</div>
          <div class="search-box">
            <el-select v-model="funcAttr" size="mini" style="width: 110px" @change="onSearchFunc">
              <el-option v-for="(attr, i) of funcAttrList" :key="i" :label="attr.message" :value="attr.value"></el-option>
            </el-select>
            <el-input v-model="funcKey" clearable placeholder="搜索" size="mini" style="width: 90px" @input="onSearchFunc"></el-input>
          </div>
          <div class="functions">
            <div v-for="(func, i) of functionListSearched" :title="func.description" class="func" @click="onComputedAddFunc(func)">
              {{ func.name }}
            </div>
          </div>
        </div>
      </div>
      <div class="btns">
        <el-button size="mini" @click="showEditComputedField = false"> 取消</el-button>
        <el-button size="mini" type="primary" @click="onEditComputedFieldConfirm"> 确定</el-button>
      </div>
    </el-dialog>
    <!-- 字段检查弹窗 -->
    <el-dialog :visible.sync="showCheck" append-to-body custom-class="newbi-extra-dialog" title="字段检查">
      <div class="tips">
        <div class="text">
          <i class="el-icon-info"></i>
          有
          <span class="span" style="color: #67c23a">{{ checkFieldsLength[0] }}</span>
          个新增字段，
          <span class="span" style="color: #f56c6c">{{ checkFieldsLength[1] }}</span>
          个删除字段
        </div>
        <div style="flex: 1"></div>
        <el-button size="mini" type="primary" @click="onExtraSelectAll">全选本页</el-button>
      </div>
      <el-table :data="extraFieldPage" border size="mini" max-height="540px">
        <el-table-column label="表名" prop="tableName"></el-table-column>
        <el-table-column label="物理字段名">
          <template slot-scope="scope">
            <span v-if="scope.row.checkFlag === 1" style="color: #67c23a">{{ scope.row.columnName }}</span>
            <span v-if="scope.row.checkFlag === 2" style="color: #f56c6c">{{ scope.row.columnName }}</span>
          </template>
        </el-table-column>
        <el-table-column label="字段注释" prop="columnTitle"></el-table-column>
        <el-table-column label="字段类型">
          <template slot-scope="scope">{{ scope.row.dimensionType === 'WEIDU' ? '维度' : '指标' }}</template>
        </el-table-column>
        <el-table-column label="数据类型">
          <template slot-scope="scope">{{ fieldDataTypeMap[scope.row.viewDataType] }}</template>
        </el-table-column>
        <el-table-column label="展示" width="50" align="center">
          <template slot-scope="field">
            <el-checkbox v-model="field.row.hiddenStatus" :true-label="0" :false-label="1"></el-checkbox>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        :current-page.sync="extraPage.current"
        :page-size="extraPage.size"
        :page-sizes="[10, 20, 30, 50]"
        :total="extraFields.length"
        background
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="extraSizeChange"
      ></el-pagination>
      <div class="btns">
        <!--        <el-button size="mini" @click="showCheck = false">取消</el-button>-->
        <el-button size="mini" type="primary" @click="showCheck = false">确定</el-button>
      </div>
    </el-dialog>
    <!-- 全局过滤器 -->
    <global-filter v-if="cubeId" v-model="showGlobalFilter" :cubeId="cubeId" :fields="tableFields" :filterJson="cubeForm.filterJson" @set="setFilterJson"></global-filter>
    <!-- 权限过滤器 -->
    <dataset-filter v-if="cubeId" v-model="showDatasetFilter" :cubeId="cubeId" :fields="tableFields"></dataset-filter>
    <!-- 配置权限组 -->
    <el-dialog :visible.sync="showAuthGroup" append-to-body custom-class="select-auth-before-save" title="权限设置" width="600px">
      <el-form label-width="120px" size="mini">
        <el-form-item label="是否公开">
          <el-radio-group v-model="publicStatus">
            <el-radio :label="1">公开</el-radio>
            <el-radio :label="0">权限组控制</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-show="publicStatus == 0" label="选择默认权限组">
          <el-button size="mini" type="primary" @click="onSelectAllAuth(true)">全选</el-button>
          <el-button size="mini" type="primary" @click="onSelectAllAuth(false)">全不选</el-button>
          <div class="wrapper">
            <div v-for="group of mineAuthGroup" :key="group.id" :class="{ selected: group.select }" class="auth" @click="group.select = !group.select">
              <div class="name">
                <el-checkbox v-model="group.select" style="margin-left: 0" @click.native.prevent></el-checkbox>
                <div>{{ group.permName }}</div>
                <div style="flex: 1"></div>
              </div>
              <div class="selected">
                <div v-for="item of group.dpList" :key="item.id" class="tag"><i class="el-icon-s-flag" style="color: #67c23a; margin-right: 5px"></i>{{ item.name }}</div>
                <div v-for="item of group.roleList" :key="item.id" class="tag"><i class="el-icon-user-solid" style="color: #e6a23c; margin-right: 5px"></i>{{ item.name }}</div>
                <div v-for="item of group.userList" :key="item.id" class="tag"><i class="el-icon-user" style="color: #909399; margin-right: 5px"></i>{{ item.name }}</div>
                <div v-for="item of group.blackUserList" :key="item.id" class="tag">
                  <i class="el-icon-error" style="color: #909399; margin-right: 5px"></i>
                  <span style="color: #f56c6c; text-decoration: line-through">{{ item.name }}</span>
                </div>
              </div>
            </div>
            <div v-if="!mineAuthGroup.length" style="color: #777; text-align: center">暂无数据</div>
          </div>
        </el-form-item>
      </el-form>
      <div class="btns">
        <el-button size="small" type="primary" @click="onSubmit(1)">确定</el-button>
      </div>
    </el-dialog>
    <!-- 视图编辑 -->
    <ViewTables ref="view" :datasourceId="datasource ? datasource.id : 0" :tables="tableList.concat(fileTableList)" @getViews="getViews(datasource.id)"></ViewTables>
    <!-- 添加分类 -->
    <el-dialog :visible.sync="showCategoryEdit" append-to-body title="添加分类" width="400px">
      <el-form label-width="80px" size="mini">
        <el-form-item label="分类名">
          <el-input v-model="categoryForm.wsName"></el-input>
        </el-form-item>
        <el-form-item label="父级分类">
          <el-select v-model="categoryForm.parentId">
            <el-option :value="0" label="顶级分类"></el-option>
            <el-option v-for="c of categoryList" v-show="c.id != categoryForm.id" :key="c.id" :label="c.wsName" :value="c.id"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <el-button size="mini" style="width: 100px; margin: 30px auto 0; display: block" type="primary" @click="onCategoryEditConfirm"> 保存 </el-button>
    </el-dialog>
    <!-- 左侧栏 -->
    <div :style="{ flex: `0 0 ${leftPanelWidth}px` }" class="left-panel">
      <div class="datasource-info">
        所用数据源：
        <div v-if="datasource" class="name">
          {{ datasource.dsDb + ' ' + datasource.remark || '' }}
        </div>
      </div>
      <div class="table-type-list">
        <div :class="{ active: tableTypeIndex === 0 }" class="type" @click="tableTypeIndex = 0">数据表</div>
        <div :class="{ active: tableTypeIndex === 1 }" class="type" @click="tableTypeIndex = 1">来自文件</div>
        <!--        <div :class="{ active: tableTypeIndex === 2 }" class="type" @click="tableTypeIndex = 2"> SQL创建</div>-->
        <div style="flex: 1"></div>
        <i v-show="tableTypeIndex === 1" class="el-icon-upload2" @click="showUpload = true"></i>
        <i v-show="tableTypeIndex === 2" class="el-icon-plus" @click="onAddView"></i>
      </div>
      <el-input v-model="tableSearchKey" class="table-search" clearable placeholder="搜索数据表" size="mini" @input="onSelectTable"></el-input>
      <!-- 数据表列表 -->
      <div v-show="tableTypeIndex === 0" class="table-list">
        <div v-for="(table, i) of tableListSelected" :key="i" :title="table.tableComments + ' ' + table.tableViewName" class="item" draggable @dragstart="onTableDragStart(table)">
          <i class="iconfont icon-table"></i>
          <span class="name">{{ table.tableComments + ' ' + table.tableViewName }}</span>
          <i class="iconfont icon-info" @click="onSearchFields(table, 'table')"></i>
        </div>
      </div>
      <!-- 来自文件的表列表 -->
      <div v-show="tableTypeIndex === 1" class="table-list">
        <div v-for="(table, i) of fileTableListSelected" :key="i" :title="table.tableComments + ' ' + table.tableViewName" class="item" draggable @dragstart="onTableDragStart(table)">
          <i class="iconfont icon-table"></i>
          <span class="name">{{ table.tableComments + ' ' + table.tableViewName }}</span>
          <i class="iconfont icon-info" @click="onSearchFields(table, 'table')"></i>
        </div>
      </div>
      <!-- SQL创建的视图 -->
      <div v-show="tableTypeIndex === 2" class="table-list">
        <div v-for="(view, i) of viewListSelected" :key="i" :title="view.sqlName + ' ' + view.viewName" class="item" draggable @dragstart="onTableDragStart(view, 1)">
          <i class="iconfont icon-SQLpeizhi"></i>
          <span class="name">{{ view.sqlName + ' ' + view.viewName }}</span>
          <i class="el-icon-edit" style="color: #409eff; margin-right: 5px" @click="onEditView(view)"></i>
          <i class="iconfont icon-info" @click="onSearchFields(view, 'view')"></i>
        </div>
      </div>
      <!--      <div v-if="datasetDetail.isEdit > 0" class="cube-form">-->
      <!--        <el-form label-width="75px" size="mini">-->
      <!--          <el-form-item label="数据集名称">-->
      <!--            <el-input v-model="cubeForm.cubeName"></el-input>-->
      <!--          </el-form-item>-->
      <!--          <el-form-item label="数据集分类">-->
      <!--            <el-cascader-->
      <!--              v-model="cubeForm.workspaceId" :options="categoryList"-->
      <!--              :props="{expandTrigger: 'click',emitPath: false,value: 'id',label: 'wsName',}" :show-all-levels="false"-->
      <!--              clearable filterable-->
      <!--              style="width: 106px"-->
      <!--            ></el-cascader>-->
      <!--            <el-button-->
      <!--              icon="el-icon-plus" size="mini" style="width: 30px;padding:7px;margin-left: 5px"-->
      <!--              title="添加分类" @click="onCategoryAdd"-->
      <!--            ></el-button>-->
      <!--          </el-form-item>-->
      <!--          <el-form-item label="数据集描述">-->
      <!--            <el-input v-model="cubeForm.remark" type="textarea"></el-input>-->
      <!--          </el-form-item>-->
      <!--          <el-button class="btn" round size="small" type="primary" @click="onSubmit(null)"> 保存</el-button>-->
      <!--        </el-form>-->
      <!--      </div>-->
    </div>
    <!-- 主区域 -->
    <div class="right-wrapper">
      <div class="left-toggle" @click="onLeftPanelToggle">
        <i v-if="leftPanelWidth === 0" class="el-icon el-icon-caret-right"></i>
        <i v-else class="el-icon el-icon-caret-left"></i>
      </div>
      <!-- 表连接面板 -->
      <div :style="{ height: topPanelHeight + 'px' }" class="top-panel">
        <div id="panel" :style="{ height: bottomPosition + 'px' }" @drop="onInitTableDragEnd">
          <div v-show="!nodes.length" class="empty">拖拽添加一张表</div>
          <div
            v-for="(node, i) of nodes"
            :key="i"
            :class="{ node: 1, unuse: node.unuse }"
            :style="{ left: node.x + 'px', top: node.y + 'px', opacity: !node.unuse || showDragProcess ? 1 : 0 }"
            :title="(node.comment || '') + ' ' + node.target"
            @dragenter="onTableDragEnter(node)"
            @dragover="onDragOver"
            @drop="onTableDragEnd"
          >
            <i v-if="!node.unuse" :class="['iconfont', node.type === 'view' ? 'icon-SQLpeizhi' : 'el-icon-s-grid']" style="color: #409eff"></i>
            <div :class="{ unuse: node.unuse }" class="name">
              {{ node.unuse ? '添加表关联' : node.comment || node.target }}
            </div>
            <el-popover v-if="!node.unuse" placement="bottom-end" popper-class="dataset-edit-node-popover" trigger="hover" width="170">
              <i slot="reference" class="el-icon-more"></i>
              <div class="btn" @click="onJoinEditFields(node)">字段选择</div>
              <div v-if="node.chidren.length <= 1" class="btn" @click="onJoinDel(node)">删除</div>
            </el-popover>
            <div v-if="node.sourceId" class="line1">
              <div class="left"></div>
              <div v-if="node.unuse" class="text"></div>
              <el-tooltip v-else content="编辑关联关系" placement="left">
                <div :class="[node.joinType]" class="icon" @click="onEditJoin(node)"></div>
              </el-tooltip>
              <div class="right"></div>
            </div>
            <div v-if="node.sourceId" :style="countLineStyle(node)" class="line2"></div>
          </div>
        </div>
      </div>
      <div :style="{ top: topPanelHeight - 9 + 'px' }" class="top-toggle" @click="onTopPanelToggle">
        <i v-if="topPanelHeight > 240" class="el-icon el-icon-caret-top"></i>
        <i v-else class="el-icon el-icon-caret-bottom"></i>
      </div>
      <div :style="{ top: topPanelHeight - 2 + 'px' }" class="drag-line" draggable @drag="onLineDrag"></div>
      <div class="main-wrapper">
        <!-- 面板头部 -->
        <div class="main-header">
          <div :class="{ active: mainIndex === 0 }" class="tab" @click="mainIndex = 0">数据预览</div>
          <div :class="{ active: mainIndex === 1 }" class="tab" @click="mainIndex = 1">批量配置</div>
          <el-checkbox v-model="showOnlyAvailable" style="margin-left: 10px">只展示可用字段</el-checkbox>
          <div style="flex: 1"></div>
          <!--          <el-button size="mini" @click="some">测试</el-button>-->
          <!--          <el-button icon="el-icon-plus" size="mini" @click="onAddComputedField('whole')">新建计算字段</el-button>-->
          <el-button v-if="cubeId && canSetFilter" icon="el-icon-key" plain size="mini" type="info" @click="showGlobalFilter = true"> 全局过滤器 </el-button>
          <!--          <el-button-->
          <!--            v-if="cubeId&&canSetFilter" icon="el-icon-open" plain size="mini" type="info"-->
          <!--            @click="showDatasetFilter=true"-->
          <!--          >-->
          <!--            权限过滤器-->
          <!--          </el-button>-->
          <el-button icon="el-icon-question" plain size="mini" type="warning" @click="onCheckFields"> 字段检查 </el-button>
          <el-button icon="el-icon-refresh" size="mini" type="primary" @click="onPreview"> 刷新预览</el-button>
          <el-button class="el-icon-edit" size="mini" type="primary" @click="onSubmit(null)"> 保存</el-button>
          <el-button class="el-icon-close" size="mini" type="default" @click="onClose(null)"> 关闭</el-button>
        </div>
        <!-- 预览区域 -->
        <div v-show="mainIndex === 0" class="data-wrapper">
          <div class="left-fields">
            <template v-if="tableFieldsWeidu.length">
              <div class="title WEIDU" @click="weiduFold = !weiduFold">
                <div>维度</div>
                <i v-if="weiduFold" class="icon el-icon-arrow-right"></i>
                <i v-else class="icon el-icon-arrow-down"></i>
              </div>
              <vuedraggable
                v-model="showOnlyAvailable ? tableFieldsWeiduAvailable : tableFieldsWeidu"
                :animation="150"
                :style="{ height: weiduFold ? 0 : 'unset', overflowY: 'hidden' }"
                @change="setFieldsSort"
              >
                <div v-for="(field, i) of showOnlyAvailable ? tableFieldsWeiduAvailable : tableFieldsWeidu" :key="i" :class="['item', field.hiddenStatus ? 'unuse' : 'weidu']">
                  <div class="text">{{ field.columnTitle + '【' + (field.columnName || '计算字段') + ' 】' }}</div>
                  <!--                  <i class="el-icon-close" @click="onFieldDel(field)"></i>-->
                </div>
              </vuedraggable>
            </template>
            <template v-if="tableFieldsZhibiao.length">
              <div class="title ZHIBIAO" @click="zhibiaoFold = !zhibiaoFold">
                <div>指标</div>
                <i v-if="zhibiaoFold" class="icon el-icon-arrow-right"></i>
                <i v-else class="icon el-icon-arrow-down"></i>
              </div>
              <vuedraggable
                v-model="showOnlyAvailable ? tableFieldsZhibiaoAvailable : tableFieldsZhibiao"
                :animation="150"
                :style="{ height: zhibiaoFold ? 0 : 'unset', overflowY: 'hidden' }"
                @change="setFieldsSort"
              >
                <div v-for="(field, i) of showOnlyAvailable ? tableFieldsZhibiaoAvailable : tableFieldsZhibiao" :key="i" :class="['item', field.hiddenStatus ? 'unuse' : 'zhibiao']">
                  <div class="text">{{ field.columnTitle + '【' + (field.columnName || '计算字段') + ' 】' }}</div>
                  <!--                  <i class="el-icon-close" @click="onFieldDel(field)"></i>-->
                </div>
              </vuedraggable>
            </template>
          </div>
          <!-- 预览表格 -->
          <vxe-table :data="previewData" :header-cell-style="countPreviewTableHeader" border height="100%" size="mini">
            <vxe-column v-for="(field, i) of tableFields" :key="i" min-width="120" :title="field.columnTitle" :field="field.columnTitle"></vxe-column>
          </vxe-table>
        </div>
        <!-- 字段配置区域 -->
        <div v-show="mainIndex === 1" class="field-wrapper">
          <dataset-field-table
            :availableData="tableFieldsWeiduAvailable"
            :originData="tableFieldsWeidu"
            :showAvailable="showOnlyAvailable"
            header-color="#468cff"
            title="维度"
            type="WEIDU"
            @editComputedField="editComputedField"
            @fieldTypeToggle="fieldTypeToggle"
            @onFieldDel="onFieldDel"
          ></dataset-field-table>
          <dataset-field-table
            :availableData="tableFieldsZhibiaoAvailable"
            :originData="tableFieldsZhibiao"
            :showAvailable="showOnlyAvailable"
            header-color="#00c13a"
            title="指标"
            type="ZHIBIAO"
            @editComputedField="editComputedField"
            @fieldTypeToggle="fieldTypeToggle"
            @onFieldDel="onFieldDel"
          ></dataset-field-table>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { getDatasourceDetail, listViewsByDataSource } from '@/api/newbi/report'
import {
  categoryList,
  cubeDetail,
  cubeFieldDel,
  cubeFieldList,
  cubePreview,
  cubeSave,
  tableFieldList,
  tableFileList,
  tableFunctionList,
  checkHavePoly,
  viewList,
  categorySave
} from '@/api/newbi/dataset'
import { funcAttrList } from '@/api/newbi/func'
import { getMineAuthGroup } from '@/api/system/authGroup'
import util from './wey'
import { Base64 } from 'js-base64'
import datasetFieldTable from './comps/datasetFieldTable.vue'
import vuedraggable from 'vuedraggable'
import DatasetFilter from '@/views/dataset/comps/datasetFilter'
import ViewTables from '@/views/dataset/comps/viewTables'
import GlobalFilter from '@/views/dataset/comps/globalFilter'
import { paramList, categoryList as globalCategoryList } from '@/api/newbi/globalParams'

export default {
  components: { datasetFieldTable, vuedraggable, DatasetFilter, ViewTables, GlobalFilter },
  props: {
    cubeRes: {
      type: Object,
      default: {}
    },
    dataForm: {
      type: Object,
      default: {}
    }
  },
  data() {
    return {
      showUpload: false,
      leftPanelWidth: 240,
      topPanelHeight: 240,
      cubeId: 0,
      editType: 'add',
      tableList: [],
      tableListSelected: [],
      fileTableList: [],
      fileTableListSelected: [],
      datasource: null,
      tableSearchKey: '',
      tableTypeIndex: 0, // 左侧数据表列表类型
      showViewFields: false,
      cubeForm: { cubeName: '', remark: '', workspaceId: '', filterJson: '' },
      nodes: [], // 选中的表组成的节点数组
      bottomPosition: 240,
      tree: null, // 节点数组计算出的树结构
      nowTable: null, // 预览时选择的表
      selectedNode: null, // 拖拽时所放置的节点
      showDragProcess: false,
      joinForm: {},
      showEditJoin: false,
      nowNode: null, //编辑连接时的左边源表
      rightNode: null, // 编辑连接时的右边目标表
      editJoinType: 'add', // 编辑连接时方式 新增/修改
      showFieldsSelect: false,
      mainIndex: 0,
      tableFieldsWeidu: [], // 自定义字段列表-维度
      tableFieldsZhibiao: [], // 自定义字段列表-指标
      computedFields: [], // 计算字段列表
      functionList: [], // 用于创建计算字段的函数列表
      functionListSearched: [],
      nowComputedField: {}, // 当前计算字段
      showEditComputedField: false,
      editComputedFieldType: 'add', // 编辑计算字段时模式是添加还是修改
      computedFieldType: 'whole', // 编辑计算字段时是给某个表加还是给整体加
      computedFieldCanSelectTable: true, // 编辑计算字段时是否可选择所属表
      previewData: [], // 预览数据
      categoryList: [],
      saveStatus: true,
      tobeChooseWeidu: [], // 计算字段编辑框里维度字段
      tobeChooseZhibiao: [], // 计算字段编辑框里指标字段
      computedSearchKey: '',
      showCheck: false,
      extraFields: [],
      fieldDataTypeMap: { STRING: '字符串', DATETIME: '日期', NUMBER: '数字' },
      weiduFold: false,
      zhibiaoFold: false,
      showDatasetFilter: false,
      funcAttr: -1,
      funcAttrList: [],
      funcKey: '',
      mineAuthGroup: [],
      showAuthGroup: false,
      viewList: [],
      viewListSelected: [],
      publicStatus: 0,
      showCategoryEdit: false,
      categoryForm: {},
      showGlobalFilter: false,
      paramList: [], // 全局参数列表
      nowParam: '',
      showOnlyAvailable: true, // 是否只展示非隐藏字段
      gptKeyword: '',
      dialogGpt: false, //弹出gpt编写框
      gptLoading: false,
      // 数据集详情
      datasetDetail: { isEdit: 1 },
      extraPage: { size: 10, current: 1 }
    }
  },
  watch: {
    nodes() {
      this.computeField()
    },
    computedFields() {
      this.computeField()
    }
  },
  computed: {
    extraFieldPage() {
      let current = (this.extraPage.current - 1) * this.extraPage.size
      return this.extraFields.slice(current, current + this.extraPage.size)
    },
    checkFieldsLength() {
      let addNum = this.extraFields.filter((i) => i.checkFlag === 1).length
      let delNum = this.extraFields.filter((i) => i.checkFlag === 2).length
      return [addNum, delNum]
    },
    canSetFilter() {
      // return !!this.$store.state.user.permission.cube_filter_row;
    },
    tableFields() {
      this.previewData = []
      return this.tableFieldsWeidu.concat(this.tableFieldsZhibiao).filter((i) => !i.hiddenStatus)
    },
    tableFieldsWeiduAvailable() {
      return this.tableFieldsWeidu.filter((i) => !i.hiddenStatus)
    },
    tableFieldsZhibiaoAvailable() {
      return this.tableFieldsZhibiao.filter((i) => !i.hiddenStatus)
    },
    availableTables() {
      return this.nodes.filter((i, index) => !i.unuse && index > 0).map((i) => ({ name: i.comment, value: i.target }))
    },
    // 计算字段编辑框里维度字段
    tobeChooseWeiduSearched() {
      let key = this.computedSearchKey
      return this.tobeChooseWeidu.filter((i) => {
        return i.columnName.toUpperCase().includes(key) || i.columnTitle.includes(key)
      })
    },
    // 计算字段编辑框里指标字段
    tobeChooseZhibiaoSearched() {
      let key = this.computedSearchKey
      return this.tobeChooseZhibiao.filter((i) => {
        return i.columnName.toUpperCase().includes(key) || i.columnTitle.includes(key)
      })
    }
  },
  async created() {
    // this.getInitData();
    let { sourceid, datasourceId, ws, tableName } = this.cubeRes
    sourceid = this.dataForm.dbSourceId
    tableName = this.dataForm.primaryTableName
    if (this.cubeRes.columnList) {
      this.cubeRes.columnList = g.clearColumn(this.cubeRes.columnList, 'id')
      this.cubeRes.columnList.forEach((i) => {
        i.columnName = g.replaceAll(i.columnName, i.tableName + '_', '')
      })
    }
    if (datasourceId) {
      return this.fillback(0)
    }
    if (sourceid) {
      this.cubeForm.workspaceId = parseInt(ws)
      getDatasourceDetail({ id: sourceid }).then((res) => {
        this.datasource = res.data.data
        this.getFuncList()
      })
      this.getViews(sourceid)
      await this.getTables(sourceid)
      if (tableName) {
        let tables = this.tableList.concat(this.fileTableList)
        let now = tables.find((i) => i.tableViewName == tableName)
        if (!now) return
        this.onTableDragStart(now, false)
        this.onInitTableDragEnd()
      }
    }
  },
  mounted() {
    document.addEventListener('dragover', function (e) {
      e.preventDefault()
    })
    document.addEventListener('drop', () => (this.showDragProcess = false))
  },
  methods: {
    some() {
      logjson(this.nodes)
    },
    extraSizeChange(size) {
      this.extraPage.size = size
    },
    onSelectAllAuth(flag) {
      this.mineAuthGroup.forEach((i) => (i.select = flag))
    },
    // 选择全局参数时
    onSetParam(val) {
      let allParams = this.paramList.reduce((r, i) => r.concat(i.children), [])
      let now = allParams.find((i) => i.paramKey == val)
      this.$nextTick(() => (this.nowParam = ''))
      this.$refs.editor.editor.insert(now.paramColumnType == 'STRING' ? `'\${${val}}'` : `\${${val}}`)
      this.$refs.paramSelector.doClose()
    },
    // 获取初始化数据,
    getInitData() {
      // funcAttrList().then(res => {
      //   let list = res.data.data;
      //   list.unshift({value: -1, name: '', message: '全部类型'});
      //   this.funcAttrList = list;
      // });
      // getMineAuthGroup().then(res => {
      //   console.log(res)
      //   this.mineAuthGroup = res.data.data.map(i => {
      //     let {dpList, roleList, userList, blackUserList} = JSON.parse(i.permJson);
      //     blackUserList = blackUserList || [];
      //     return {...i, dpList, roleList, userList, blackUserList, select: true};
      //   });
      // });
      // globalCategoryList({size: 10000, current: 1}).then(res => {
      //   let list = res.data.data.records;
      //   let parents = list.filter((i) => !i.parentId);
      //   let categoryList = [];
      //   list.forEach((i) => {
      //     i.children = [];
      //     if (i.parentId) {
      //       let parent = parents.find((j) => j.id == i.parentId);
      //       parent.hasChild = true;
      //       i.label = parent.typeName + ' / ' + i.typeName;
      //       categoryList.push(i);
      //     } else {
      //       i.label = i.typeName;
      //     }
      //   });
      //   categoryList = categoryList.concat(parents.filter(i => !i.hasChild));
      //   paramList({size: 10000, current: 1}).then(res => {
      //     let params = res.data.data.records;
      //     params.forEach(i => {
      //       i.label = i.paramName;
      //       let parent = categoryList.find(j => j.id == i.typeId);
      //       parent.children.push(i);
      //     });
      //     this.paramList = categoryList;
      //   });
      // });
    },
    // 更新全局筛选器
    setFilterJson(json) {
      this.cubeForm.filterJson = json
      this.showGlobalFilter = false
    },
    // 添加分类时
    onCategoryAdd() {
      this.categoryForm = { wsName: '', sortNum: 0, parentId: 0 }
      this.showCategoryEdit = true
    },
    // 确认添加分类时
    onCategoryEditConfirm() {
      if (!this.categoryForm.wsName) {
        this.$message({ type: 'warning', message: '请填写分类名' })
        return
      }
      categorySave(this.categoryForm).then((res) => {
        this.$message({ type: 'success', message: '保存成功' })
        this.showCategoryEdit = false
        this.getCategory()
      })
    },
    // 获取分类
    getCategory() {
      categoryList().then((res) => {
        let list = res.data.data
        let categoryList = list.filter((i) => !i.parentId)
        list.forEach((i) => {
          if (i.parentId) {
            let parent = categoryList.find((j) => j.id === i.parentId)
            if (!parent) return
            if (!parent.children) {
              parent.children = []
            }
            parent.children.push(i)
          }
        })
        this.categoryList = categoryList
      })
    },
    // 数据表批量选择字段
    onSelectFieldBatch(type, flag) {
      if (type == 'left') {
        this.nowNode.fields.forEach((i) => (i.hiddenStatus = flag))
      } else if (type == 'right') {
        this.rightNode.fields.forEach((i) => (i.hiddenStatus = flag))
        this.rightNode.fields = [...this.rightNode.fields]
      }
    },
    // 获取视图列表
    getViews(id) {
      id = id || this.datasource.id
      viewList({ datasourceId: id }).then((res) => {
        let data = res.data.data
        data.forEach((i) => {
          i.fields = []
          i.key = ''
          i.searched = []
        })
        this.viewList = data
        this.viewListSelected = [...this.viewList]
      })
    },
    // 添加视图时
    onAddView() {
      this.$refs.view.onAdd()
    },
    // 编辑视图时
    onEditView(view) {
      this.$refs.view.onEdit(view)
    },
    // 数据表筛选字段
    onTableSearchFields(node) {
      let { key } = node
      node.searched = node.fields.filter((i) => i.columnTitle.includes(key) || i.columnName.includes(key))
    },
    onSearchFunc() {
      let { name } = this.funcAttrList.find((i) => i.value == this.funcAttr)
      let funcKey = this.funcKey.toLowerCase()
      let list = []
      if (this.funcAttr == -1) {
        list = [...this.functionList]
      } else {
        list = this.functionList.filter((i) => i.funcAttr == name)
      }
      this.functionListSearched = list.filter((i) => {
        let name = i.name.toLowerCase()
        let description = i.description.toLowerCase()
        return name.includes(funcKey) || description.includes(funcKey)
      })
    },
    // 获取当前数据源类型下计算函数
    getFuncList() {
      tableFunctionList({ dsType: this.datasource.dsTypeSyl }).then((res) => {
        this.functionList = res.data.data
        this.functionListSearched = [...this.functionList]
        this.funcAttr = -1
      })
    },
    async fillback(id) {
      this.cubeId = id
      this.editType = 'edit'
      // 获取数据集详情
      let cubeRes = this.cubeRes
      this.datasetDetail = cubeRes
      let { cubeName, remark, linksJoin, datasourceId, cubeTableNames, workspaceId, filterJson } = cubeRes
      cubeTableNames = JSON.parse(cubeTableNames)
      this.getTables(datasourceId)
      this.getViews(datasourceId)
      this.cubeForm = { cubeName, remark, workspaceId, filterJson }
      // 获取数据源详情
      getDatasourceDetail({ id: datasourceId }).then((res) => {
        this.datasource = res.data.data
        // this.$nextTick(() => this.$refs.upload.fileForm.dsId = this.datasource.id);
        this.getFuncList()
      })
      let links = JSON.parse(linksJoin)
      // 获取之前的字段配置
      let wholeFields = cubeRes.columnList
      // 整理节点信息
      let nodes = links.map((i) => ({ ...i, chidren: [], x: 0, y: 0 }))
      // 如果之前有关联
      if (nodes.length) {
        let { source, sourceId } = links[0]
        nodes.unshift({ chidren: [], x: 0, y: 0, target: source, targetId: sourceId, sourceId: 0 })
        // 如果之前没有关联
      } else {
        let { tableName, tableAliasName, tableComment, type } = cubeTableNames[0]
        nodes.unshift({
          chidren: [],
          x: 0,
          y: 0,
          target: tableName,
          targetId: tableAliasName,
          sourceId: 0,
          comment: tableComment,
          type: type || 'table'
        })
      }
      nodes.forEach((node) => {
        node.fields = wholeFields.filter((i) => i.tableAliasName === node.targetId)
        let nowTable = cubeTableNames.find((j) => j.tableName === node.target)
        node.comment = nowTable.tableComment || nowTable.tableName
        node.type = nowTable.type || 'table'
      })
      this.computedFields = wholeFields.filter((i) => i.columnAttr === 'VIRTUAL')
      this.nodes = nodes
      this.countTree()
    },
    onExtraSelectAll() {
      this.extraFieldPage.forEach((i) => (i.hiddenStatus = 0))
    },
    // 点击字段检查时
    onCheckFields() {
      this.extraFields = []
      let dsId = this.datasource.id
      let fields = []
      let tasks = this.nodes
        .filter((item) => !item.unuse)
        .map((item) => {
          return tableFieldList({ tableName: item.target, dsId }).then((r) => {
            fields = fields.concat(r.data.data)
          })
        })
      Promise.all(tasks).then((_) => {
        let oldFields = this.tableFieldsWeidu.concat(this.tableFieldsZhibiao).filter((i) => i.columnAttr === 'NORMAL')
        let addFields = fields.filter((i) => !oldFields.find((j) => j.columnName === i.columnName))
        addFields.forEach((i) => {
          i.checkFlag = 1
          i.hiddenStatus = 1
        })
        let delFields = oldFields.filter((i) => !fields.find((j) => j.columnName === i.columnName))
        delFields.forEach((i) => (i.checkFlag = 2))
        let extraFields = addFields.concat(delFields)
        if (!extraFields.length) {
          this.$message({ type: 'success', message: '无可同步字段' })
        } else {
          extraFields.forEach((item) => {
            let node = this.nodes.find((i) => i.target === item.tableName)
            if (!node) return
            if (item.checkFlag === 1) {
              item.tableAliasName = node.targetId
              node.fields.push(item)
            }
            if (item.checkFlag === 2) {
              let oldField = node.fields.find((i) => i.columnName === item.columnName)
              if (oldField) {
                oldField.checkFlag = 2
              }
            }
          })
          this.extraFields = extraFields
          this.computeField()
          this.showCheck = true
        }
      })
    },
    // 点击跳转创建大屏
    onCreateBigdata() {
      let routeUrl = this.$router.resolve({ path: '/newbi/visual/bigdataEdit?ds=' + this.cubeId })
      window.open(routeUrl.href, '_blank')
    },
    // 选择表连接字段时
    onJoinKeyChange(key) {
      let { sourceKey, targetKey, sourceKeyVtState, targetKeyVtState } = key
      if (!sourceKey || !targetKey) return
      let left, right
      if (sourceKeyVtState) {
        left = this.nowNode.computed.find((i) => i.columnFormula === sourceKey)
      } else {
        left = this.nowNode.fields.find((i) => i.columnName === sourceKey)
      }
      if (targetKeyVtState) {
        right = this.rightNode.computed.find((i) => i.columnFormula === targetKey)
      } else {
        right = this.rightNode.fields.find((i) => i.columnName === targetKey)
      }
      if (left.viewDataType !== right.viewDataType) {
        this.$message({
          type: 'warning',
          message: `${sourceKey} 字段和 .${targetKey} 字段数据类型不一致，不能进行关联，请检查`
        })
      }
    },
    // 提交保存
    onSubmit(confirm) {
      // if (!this.cubeForm.cubeName) {
      //   return this.$message({type: "warning", message: "请填写名称"});
      // }
      // if (!this.cubeForm.workspaceId) {
      //   return this.$message({type: "warning", message: "请选择分类"});
      // }
      // if (!confirm && this.editType == 'add') {
      //   return this.showAuthGroup = true;
      // }
      if (!this.saveStatus) return
      let data = this.countWholeData()
      if (!data) return
      if (this.editType == 'add') {
        data.cubeData.publicStatus = this.publicStatus
        if (this.publicStatus == 0) {
          data.dataPermIdList = this.mineAuthGroup.filter((i) => i.select).map((i) => i.id)
        } else {
          data.dataPermIdList = []
        }
      }
      this.$emit('onSubmit', data)
      this.$parent.closeDrawer()
      return
      this.saveStatus = false
      setTimeout(() => (this.saveStatus = true), 3000)
      cubeSave(Base64.encode(JSON.stringify(data))).then((res) => {
        this.$message({ type: 'success', message: '保存成功' })
        this.showAuthGroup = false
        if (this.editType === 'add') {
          this.$router.replace('/newbi/dataset/edit?id=' + res.data.data)
        } else {
          location.reload()
        }
      })
    },
    onClose() {
      this.$parent.closeDrawer()
    },
    // 预览数据
    onPreview() {
      let data = this.countWholeData()
      if (this.editType === 'edit') {
        data.cubeDataId = this.cubeId
      }
      data.columnList = g.clearColumn(data.columnList, 'id')
      data = Base64.encode(JSON.stringify(data))
      cubePreview(data).then((res) => {
        let { dataList, fieldDict } = res.data.data
        this.previewData = util.arrReplaceKeys(dataList, fieldDict)
      })
    },
    // 整理预览/提交数据
    countWholeData() {
      let linksJoin = this.nodes
        .filter((i) => i.sourceId && !i.unuse)
        .map((i) => ({
          joinType: i.joinType,
          joinKeys: i.joinKeys,
          source: i.source,
          target: i.target,
          targetId: i.targetId,
          sourceId: i.sourceId
        }))
      this.setFieldsSort()
      let tableFields = this.tableFieldsWeidu.concat(this.tableFieldsZhibiao)
      let cubeTableNames = this.nodes.filter((i) => !i.unuse).map((i) => ({ tableName: i.target, tableAliasName: i.targetId, tableComment: i.comment, type: i.type }))
      let columnList = JSON.parse(JSON.stringify(tableFields))
      columnList.forEach((i) => {
        if (this.editType === 'add') {
          delete i.id
        }
        delete i.cubeDataId
        delete i.createTime
        delete i.createBy
        delete i.createUserId
      })
      let checkedJoins = linksJoin.reduce((r, i) => {
        let { source, target } = i
        return r.concat(i.joinKeys.map((k) => Object.assign({ source, target }, k)))
      }, [])
      for (let i = 0; i < checkedJoins.length; i++) {
        let { source, sourceKey, target, targetKey, sourceKeyVtState, targetKeyVtState } = checkedJoins[i]
        let left, right
        if (sourceKeyVtState) {
          left = columnList.find((j) => j.tableName === source && j.columnFormula === sourceKey && j.columnAttr === 'VIRTUAL')
        } else {
          left = columnList.find((j) => j.tableName === source && j.columnName === sourceKey && j.columnAttr === 'NORMAL')
        }
        if (targetKeyVtState) {
          right = columnList.find((j) => j.tableName === target && j.columnFormula === targetKey && j.columnAttr === 'VIRTUAL')
        } else {
          right = columnList.find((j) => j.tableName === target && j.columnName === targetKey && j.columnAttr === 'NORMAL')
        }
        if (left.viewDataType !== right.viewDataType) {
          this.$message({
            type: 'warning',
            message: `${source}.${sourceKey} 字段和 ${target}.${targetKey} 字段数据类型不一致，不能进行关联，请检查`
          })
          return false
        }
      }
      let cubeData = {
        ...this.cubeForm,
        cubeTableNames: JSON.stringify(cubeTableNames),
        datasourceId: this.datasource.id,
        tableType: linksJoin.length ? 'LOGIC' : 'PHYSICS',
        linksJoin: JSON.stringify(linksJoin)
      }
      if (this.editType === 'edit') {
        cubeData.id = this.cubeId
      }
      return { columnList, cubeData, datasourceId: this.datasource.id, orderByList: [] }
    },
    // 获取数据源下的表
    async getTables(id) {
      id = id || this.datasource.id
      let fileRes = await tableFileList({ dsId: id })
      let fileTables = fileRes.data.data
        .map((i) => ({
          datasourceId: i.datasourceId,
          tableComments: i.tableComment,
          tableViewName: i.tableName,
          fields: []
        }))
        .sort((a, b) => (a.createTime > b.createTime ? 1 : -1))
      let tableRes = await listViewsByDataSource({ datasourceId: id, current: 1, size: 10000 })
      let tables = tableRes.data.data.records.filter((i) => !fileTables.find((j) => j.tableViewName === i.tableViewName))
      this.tableList = tables.map((i) => ({ ...i, fields: [] }))
      this.tableListSelected = [...this.tableList]
      this.fileTableList = fileTables
      this.fileTableListSelected = [...this.fileTableList]
    },
    // 判断删除某字段
    async onFieldDel(field) {
      if (this.editType === 'add') {
        this.onFieldDelConfirm(field)
      } else {
        this.$confirm('确定删除此字段?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })
          .then(() => {
            if (field.id < 1) {
              this.onFieldDelConfirm(field)
              return
            }
            cubeFieldDel({ columnId: field.id }).then((_) => {
              this.$message({ type: 'success', message: '删除成功!' })
              this.onFieldDelConfirm(field)
            })
          })
          .catch(() => {})
        // if (await this.countFieldCanDel(field)) {
        //   this.onFieldDelConfirm(field);
        // } else {
        //   this.$message({ type: "error", message: "该字段目前使用中" });
        // }
      }
    },
    // 判断某字段是否可删除
    async countFieldCanDel(field) {
      return true
    },
    // 确定可以删除某字段时
    onFieldDelConfirm(field) {
      if (field.columnAttr === 'NORMAL') {
        let node = this.nodes.find((i) => i.targetId === field.tableAliasName)
        let index = node.fields.findIndex((i) => i === field)
        node.fields.splice(index, 1)
        this.computeField()
      } else {
        let index = this.computedFields.findIndex((i) => i === field)
        this.computedFields.splice(index, 1)
      }
    },
    // 确定保存计算字段时
    onEditComputedFieldConfirm() {
      let { columnTitle, columnFormula } = this.nowComputedField
      if (!columnTitle || !columnFormula) {
        return this.$message({ message: '请补充完整', type: 'warning' })
      }
      if (!this.nowComputedField.tableName) {
        return this.$message({ message: '请选择表', type: 'warning' })
      }
      if (this.editComputedFieldType === 'add') {
        let flag = this.tableFieldsWeidu.concat(this.tableFieldsZhibiao).find((i) => i.columnTitle === columnTitle)
        if (flag) {
          return this.$message({ message: '字段展示名重复', type: 'warning' })
        }
      }
      let checkData = { columnFormula: this.nowComputedField, datasourceId: this.datasource.id }
      // 判断是否包含聚合函数
      checkHavePoly(Base64.encode(JSON.stringify(checkData))).then((res) => {
        this.nowComputedField.virtualAggregationStatus = res.data.data ? 1 : 0
        if (this.editComputedFieldType === 'add') {
          this.computedFields.push(this.nowComputedField)
          if (this.computedFieldType === 'left') {
            this.nowNode.computed.push(this.nowComputedField)
          } else if (this.computedFieldType === 'right') {
            this.rightNode.computed.push(this.nowComputedField)
          }
        }
        this.showEditComputedField = false
      })
    },
    // 编辑计算字段
    editComputedField(field) {
      this.computedFieldType = 'whole'
      this.computedFieldCanSelectTable = true
      this.tobeChooseWeidu = this.tableFieldsWeidu.filter((i) => i.columnAttr === 'NORMAL')
      this.tobeChooseZhibiao = this.tableFieldsZhibiao.filter((i) => i.columnAttr === 'NORMAL')
      this.nowComputedField = field
      let tableName = field.tableName
      if (!this.availableTables.find((i) => i.value === tableName)) {
        this.nowComputedField.tableName = ''
      }
      this.editComputedFieldType = 'edit'
      this.showEditComputedField = true
      this.computedSearchKey = ''
    },
    // 计算字段拼入函数
    onComputedAddFunc(func) {
      this.$refs.editor.editor.insert(func.method)
    },
    // 计算字段拼入物理字段
    onComputedAddField(field) {
      this.$refs.editor.editor.insert(`[${field.columnTitle}]`)
    },
    // 点击新建计算字段时
    onAddComputedField(type) {
      this.computedFieldType = type
      this.computedFieldCanSelectTable = type == 'whole'
      let tableName = ''
      if (type == 'left') {
        tableName = this.nowNode.target
        this.tobeChooseWeidu = this.nowNode.fields.filter((i) => i.dimensionType == 'WEIDU' && i.columnAttr == 'NORMAL')
        this.tobeChooseZhibiao = this.nowNode.fields.filter((i) => i.dimensionType == 'ZHIBIAO' && i.columnAttr == 'NORMAL')
      } else if (type == 'right') {
        tableName = this.rightNode.target
        this.tobeChooseWeidu = this.rightNode.fields.filter((i) => i.dimensionType == 'WEIDU' && i.columnAttr == 'NORMAL')
        this.tobeChooseZhibiao = this.rightNode.fields.filter((i) => i.dimensionType == 'ZHIBIAO' && i.columnAttr == 'NORMAL')
      } else {
        this.tobeChooseWeidu = this.tableFieldsWeidu.filter((i) => i.columnAttr == 'NORMAL')
        this.tobeChooseZhibiao = this.tableFieldsZhibiao.filter((i) => i.columnAttr == 'NORMAL')
      }
      this.nowComputedField = {
        tableName,
        columnTitle: '',
        columnComment: '',
        columnFormula: '',
        columnAttr: 'VIRTUAL',
        hiddenStatus: 0,
        numberDataFormat: 'AUTO',
        sortNum: 0,
        viewDataType: 'STRING',
        dimensionType: 'ZHIBIAO',
        timeDataFormat: 'yyyy_MM_ddhh$mm$ss',
        oldViewDataType: 'STRING',
        virtualAggregationStatus: 0,
        aggregationType: 'SUM'
      }
      this.editComputedFieldType = 'add'
      this.showEditComputedField = true
      this.computedSearchKey = ''
    },
    // 计算预览表格头部样式
    countPreviewTableHeader({ columnIndex }) {
      let flag = this.tableFields[columnIndex].dimensionType === 'WEIDU'
      return { color: flag ? '#468cff' : '#00c13a' }
    },
    // 字段按顺序设置排序
    setFieldsSort() {
      this.tableFieldsWeidu.forEach((item, index) => (item.sortNum = index + 1))
      this.tableFieldsZhibiao.forEach((item, index) => (item.sortNum = index + 1))
    },
    // 字段类型转换
    fieldTypeToggle(field) {
      if (field.dimensionType === 'WEIDU') {
        let index = this.tableFieldsWeidu.findIndex((i) => i == field)
        field.dimensionType = 'ZHIBIAO'
        this.tableFieldsWeidu.splice(index, 1)
        this.tableFieldsZhibiao.push(field)
      } else if (field.dimensionType === 'ZHIBIAO') {
        let index = this.tableFieldsZhibiao.findIndex((i) => i == field)
        field.dimensionType = 'WEIDU'
        this.tableFieldsZhibiao.splice(index, 1)
        this.tableFieldsWeidu.push(field)
      }
      this.setFieldsSort()
    },
    // 计算当前维度指标字段列表
    computeField() {
      let newFields = this.nodes
        .filter((i) => !i.unuse)
        .reduce((r, i) => r.concat(i.fields), [])
        .concat(this.computedFields)
        .map((i) => {
          i.columnTitle = i.columnTitle || i.columnComment
          return i
        })
      let res = []
      newFields.forEach((i) => {
        let j = res.find((j) => j.columnTitle === i.columnTitle)
        if (j) {
          i.columnTitle += 1
          if (i.viewDataType === j.viewDataType) {
            i.hiddenStatus = 1
          }
        }
        res.push(i)
      })
      this.tableFieldsWeidu = res.filter((i) => i.dimensionType === 'WEIDU').sort((a, b) => a.sortNum - b.sortNum)
      this.tableFieldsZhibiao = res.filter((i) => i.dimensionType === 'ZHIBIAO').sort((a, b) => a.sortNum - b.sortNum)
      this.setFieldsSort()
    },
    // 删除关联字段时
    onDelJoinKey(i) {
      if (this.joinForm.joinKeys.length <= 1) return
      this.joinForm.joinKeys.splice(i, 1)
    },
    // 添加关联字段时
    onAddJoinKey() {
      this.joinForm.joinKeys.push({ sourceKey: '', targetKey: '' })
    },
    // 查看节点字段
    onJoinEditFields(node) {
      this.nowNode = node
      this.showFieldsSelect = true
    },
    // 判断删除连接节点
    async onJoinDel(node) {
      if (this.editType === 'add') {
        this.onJoinDelConfirm(node)
      } else {
        // 循环判断该节点下某字段是否使用中
        for (let i = 0; i < node.fields.length; i++) {
          if (!(await this.countFieldCanDel(node.fields[i])))
            return this.$message({
              message: node.fields[i].columnTitle + ' 字段目前使用中，不允许删除节点',
              type: 'error'
            })
        }
        this.onJoinDelConfirm(node)
      }
    },
    // 确认删除连接节点
    onJoinDelConfirm(node) {
      this.$confirm('删除表将同步删除表下的计算字段，若有其他与此表相关计算字段，请检查并手动删除', '提示', { confirmButtonText: '确定删除', cancelButtonText: '取消', type: 'warning' })
        .then(() => {
          let index = this.nodes.findIndex((i) => i.targetId === node.targetId)
          this.nodes.splice(index, 1)
          this.computedFields = this.computedFields.filter((i) => i.tableName !== node.target)
          let newNodes = this.nodes.filter((i) => !i.unuse)
          newNodes.forEach((i) => (i.chidren = []))
          this.nodes = newNodes
          this.countTree()
        })
        .catch(() => {})
    },
    // 拖拽添加第一个节点时
    async onInitTableDragEnd() {
      if (!this.rightNode) return
      // 如果所选表没有字段先获取
      if (!this.rightNode.fields.length) {
        let res = await tableFieldList({ tableName: this.rightNode.target, dsId: this.datasource.id })
        this.rightNode.fields = res.data.data
      }
      if (!this.nodes.length) {
        let { fields, targetId, target, comment, type } = this.rightNode
        fields.forEach((i) => (i.tableAliasName = targetId))
        fields = JSON.parse(JSON.stringify(fields))
        this.nodes.push({
          comment,
          target,
          fields,
          targetId,
          sourceId: 0,
          chidren: [],
          type: type || 'table',
          x: 0,
          y: 0
        })
        this.countTree()
      }
    },
    // 点击编辑连接关系时
    onEditJoin(node) {
      this.rightNode = node
      this.nowNode = this.nodes.find((i) => i.targetId === node.sourceId)
      this.joinForm = node
      this.editJoinType = 'edit'
      // 设置字段搜索区
      this.$set(this.nowNode, 'key', '')
      this.$set(this.nowNode, 'searched', [...this.nowNode.fields])
      this.$set(this.rightNode, 'key', '')
      this.$set(this.rightNode, 'searched', [...this.rightNode.fields])
      // 设置计算字段区
      this.$set(
        this.nowNode,
        'computed',
        this.computedFields.filter((i) => i.tableName === this.nowNode.target)
      )
      this.$set(
        this.rightNode,
        'computed',
        this.computedFields.filter((i) => i.tableName === this.rightNode.target)
      )
      this.showEditJoin = true
    },
    // 拖拽结束，添加连接关系前组织表单
    async onTableDragEnd() {
      // 如果所选表没有字段先获取
      if (!this.rightNode.fields.length) {
        let res = await tableFieldList({ tableName: this.rightNode.target, dsId: this.datasource.id })
        this.rightNode.fields = res.data.data
      }
      if (!this.selectedNode.unuse) return
      this.selectedNode = this.nodes.find((i) => i.targetId === this.selectedNode.sourceId)
      this.nowNode = this.selectedNode
      this.joinForm = {
        joinType: 'LEFT_JOIN',
        source: this.nowNode.target,
        target: this.rightNode.target,
        joinKeys: [{ sourceKey: '', targetKey: '', sourceKeyVtState: false, targetKeyVtState: false }]
      }
      this.editJoinType = 'add'
      // 设置字段搜索区
      this.$set(this.nowNode, 'key', '')
      this.$set(this.nowNode, 'searched', [...this.nowNode.fields])
      this.$set(this.rightNode, 'key', '')
      this.$set(this.rightNode, 'searched', [...this.rightNode.fields])
      // 设置计算字段区
      this.$set(
        this.nowNode,
        'computed',
        this.computedFields.filter((i) => i.tableName === this.nowNode.target)
      )
      this.$set(
        this.rightNode,
        'computed',
        this.computedFields.filter((i) => i.tableName === this.rightNode.target)
      )
      this.showEditJoin = true
    },
    // 确认编辑关联关系，分新增和修改两种情况处理
    onConfirmJoin() {
      if (this.joinForm.joinKeys.find((i) => !i.sourceKey || !i.targetKey)) {
        return this.$message({ message: '请填写完整关联字段', type: 'error' })
      }
      // 添加新关联关系时
      if (this.editJoinType === 'add') {
        let newNodes = this.nodes.filter((i) => !i.unuse)
        newNodes = JSON.parse(JSON.stringify(newNodes))
        newNodes.forEach((i) => (i.chidren = []))
        let { targetId, fields, comment, type } = this.rightNode
        fields.forEach((i) => (i.tableAliasName = targetId))
        newNodes.push({
          ...this.joinForm,
          comment,
          targetId,
          fields: JSON.parse(JSON.stringify(fields)),
          sourceId: this.selectedNode.targetId,
          chidren: [],
          type: type || 'table',
          x: 0,
          y: 0
        })
        this.nodes = newNodes
        this.countTree()
        this.showEditJoin = false
      } else {
        // 修改关联关系时
        this.showEditJoin = false
      }
    },
    onDragOver(e) {
      e.preventDefault()
    },
    // 拖拽到想关联的节点时记录下来
    onTableDragEnter(node) {
      this.selectedNode = node
    },
    // 拖拽开始，根据选择的表生成右边节点
    onTableDragStart(table, isView) {
      if (isView) {
        this.rightNode = {
          comment: table.sqlName,
          target: table.viewName,
          targetId: util.getRandomStr(5),
          fields: table.fields,
          type: 'view'
        }
      } else {
        this.rightNode = {
          comment: table.tableComments,
          target: table.tableViewName,
          targetId: util.getRandomStr(5),
          fields: table.fields,
          type: 'table'
        }
      }
      this.showDragProcess = true
    },
    // 计算左边连接线
    countLineStyle(item) {
      if (!item.sourceId) return
      let parent = this.nodes.find((i) => i.targetId === item.sourceId)
      if (parent.y === item.y) {
        return { width: '20px', height: '1px' }
      } else {
        return { width: '1px', height: item.y - parent.y + 'px' }
      }
    },
    // 计算节点树形结构
    countTree() {
      this.nodes.forEach((item) => {
        let parent = this.nodes.find((i) => i.targetId === item.sourceId)
        parent && parent.chidren.push(item)
      })
      let unuseNodes = []
      this.nodes.forEach((i) => {
        let unuseNode = { unuse: true, x: 0, y: 0, chidren: [], sourceId: i.targetId }
        i.chidren.push(unuseNode)
        unuseNodes.push(unuseNode)
      })
      this.nodes = this.nodes.concat(unuseNodes)
      this.tree = this.nodes.find((i) => !i.sourceId)
      this.countNodePosition(0, 0, this.tree)
      this.bottomPosition = Math.max(this.nodes.reduce((r, i) => Math.max(r, i.y), 0) + 50, 240)
    },
    // 计算节点位置
    countNodePosition(xLevel, yLevel, node) {
      if (!node) return
      node.x = xLevel * 270 + 20
      node.y = yLevel * 40 + 20
      let startYLevel = yLevel
      if (node.chidren.length) {
        node.chidren.forEach((item) => (startYLevel = this.countNodePosition(xLevel + 1, startYLevel, item) + 1))
        startYLevel--
      }
      return startYLevel
    },
    // 数据表字段预览，如果表字段不存在，先请求获取
    async onSearchFields(table, type, flag) {
      this.nowTable = table
      let data = { dsId: this.datasource.id }
      if (type == 'table') {
        data.tableName = table.tableViewName
      } else if (type == 'view') {
        data.tableName = table.viewName
      }
      if (!table.fields.length) {
        let res = await tableFieldList(data)
        table.fields = res.data.data
      }
      this.showViewFields = !flag
    },
    // 关键字过滤数据表
    onSelectTable(val) {
      this.tableListSelected = this.tableList.filter((i) => (i.tableComments && i.tableComments.includes(val)) || i.tableViewName.includes(val))
      this.fileTableListSelected = this.fileTableList.filter((i) => (i.tableComments && i.tableComments.includes(val)) || i.tableViewName.includes(val))
      this.viewListSelected = this.viewList.filter((i) => i.viewName.includes(val) || i.sqlName.includes(val))
    },
    onLeftPanelToggle() {
      this.leftPanelWidth = this.leftPanelWidth === 0 ? 240 : 0
    },
    onTopPanelToggle() {
      if (this.topPanelHeight > 240) {
        this.topPanelHeight = 240
      } else {
        this.topPanelHeight = document.getElementsByClassName('right-wrapper')[0].getBoundingClientRect().height
      }
    },
    onLineDrag(e) {
      this.topPanelHeight += e.layerY
    },
    async gptSubmit() {
      this.gptLoading = true
      //this.tableData转字符串
      let str = ''
      Object.values(this.tobeChooseWeiduSearched).map((item, index) => {
        str += `${item.columnName}${item.columnComment}${item.viewDataType},`
      })
      Object.values(this.tableFieldsZhibiao).map((item, index) => {
        str += `${item.columnName}${item.columnComment}${item.viewDataType},`
      })
      let prompt = `该数据库表的字段为${str},我希望您充当SQL助手，帮我编辑这个字段语法为（${this.gptKeyword}），我只想要用在sql查询中，不需要完整的sql查询语法，谢谢！`
      const data = await chat(prompt, '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')
      //去掉\n
      data.choices[0].text = data.choices[0].text.replace(/\n/g, '')
      //去掉尾部的分号
      data.choices[0].text = data.choices[0].text.replace(/;*$/g, '')
      this.nowComputedField.columnFormula = data.choices[0].text
      this.gptLoading = false
    }
  }
}
</script>
<style lang="scss">
@import './edit.scss';
</style>
