|
@@ -0,0 +1,1617 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <!-- 按钮 -->
|
|
|
+ <div style="height: auto;width: 100%; padding-bottom: 20px;">
|
|
|
+ <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openPopUp">获取表格数据</el-button>
|
|
|
+ <el-button type="primary" plain size="mini" @click="saveData">保存</el-button>
|
|
|
+ <!-- <el-button type="info" plain icon="el-icon-view" size="mini" @click="showRangeDataObjectsInfo" style="margin-left: 10px;">查看选区数据</el-button> -->
|
|
|
+ </div>
|
|
|
+ <!-- Luckysheet容器 -->
|
|
|
+ <div id="luckysheet" style="margin:0px;padding:0px;width:100%;height:100%;left: 0px;top: 0px;"></div>
|
|
|
+ <!-- 弹窗 -->
|
|
|
+ <el-dialog title="表格编辑" ref="popUpForm" :visible.sync="popUpVisible" @close="popUpVisibleCancel" width="50%"
|
|
|
+ :show-close="false">
|
|
|
+ <el-alert v-if="errorMessage && errorMessage != ''" :title="errorMessage" type="error" show-icon />
|
|
|
+ <div style="display: flex;gap: 20px;">
|
|
|
+ <div class="popUpTitle">
|
|
|
+ <div class="popUpTitleDiv">数据表</div>
|
|
|
+ <el-select v-model="popUpTableName" :placeholder="$t('tableMange.selectTable')" filterable
|
|
|
+ @change="getList" class="mb10">
|
|
|
+ <el-option v-for="item in popUpTableList" :key="item.tableName" :label="item.tableComment"
|
|
|
+ :value="item.tableName">
|
|
|
+ <span class="discribe" style="float: left">{{
|
|
|
+ item.tableComment
|
|
|
+ }}</span>
|
|
|
+ <span style="float: right; color: #8492a6; font-size: 13px">{{
|
|
|
+ item.tableName
|
|
|
+ }}</span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="popUpTitle">
|
|
|
+ <div class="popUpTitleDiv" style="margin-bottom: 10px;">别名</div>
|
|
|
+ <el-input v-model="dtName" placeholder="请输入别名" style="margin-bottom: 10px;width: 221px;" clearable>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-table :data="popUpTableFieldList" border ref="dragTable" row-key="id" max-height="500px">
|
|
|
+ <el-table-column type="index" :label="$t('tableMange.serialNumber')" width="50" class-name="allowDrag">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="fieldName" :label="$t('tableMange.dataField')">
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="fieldDescription" :label="$t('tableMange.fieldDescription')">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <input :class="{
|
|
|
+ isNullDesc:
|
|
|
+ scope.row.fieldDescription == '' &&
|
|
|
+ scope.row.isShow &&
|
|
|
+ isInputInvalid
|
|
|
+ ? true
|
|
|
+ : false,
|
|
|
+ ipt: true,
|
|
|
+ }" v-model="scope.row.fieldDescription" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="relationTable" :label="$t('tableMange.relatedTable')">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-select v-model="scope.row.relationTable" :disabled="!scope.row.relationTableList ||
|
|
|
+ !scope.row.relationTableList.length
|
|
|
+ " :placeholder="$t('tableMange.selectTable')" clearable filterable
|
|
|
+ @change="ralationTableChange(scope.row)">
|
|
|
+ <el-option v-for="item in scope.row.relationTableList" :key="item.tableName"
|
|
|
+ :label="item.tableComment" :value="item.tableName">
|
|
|
+ <span style="float: left">{{ item.tableComment }}</span>
|
|
|
+ <span style="float: right; color: #8492a6; font-size: 13px">{{ item.tableName }}</span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="relationFieldName" :label="$t('tableMange.relatedField')">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-select v-model="scope.row.relationFieldName" @change="relationFieldChange(scope.row)"
|
|
|
+ :disabled="!scope.row.disableRelaFieldName" :placeholder="$t('tableMange.relatedField')"
|
|
|
+ filterable>
|
|
|
+ <el-option v-for="item in scope.row.relaFieldNameList" :key="item.fieldName"
|
|
|
+ :label="item.fieldDescription" :value="item.fieldName">
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="relationType" :label="$t('tableMange.relatedType')">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-select v-model="scope.row.relationType" :placeholder="$t('tableMange.relatedType')"
|
|
|
+ :disabled="!scope.row.disableRelaType" @change="relationTypeChangeHandler(scope.row)"
|
|
|
+ filterable>
|
|
|
+ <el-option v-for="item in relaTypeList" :key="item.value" :label="item.label"
|
|
|
+ :value="item.value">
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column align="center" prop="isShow" :label="$t('tableMange.isShow')">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-switch v-model="scope.row.isShow"></el-switch>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="popUpVisibleCancel">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="popUpCreateHandle">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { mapState } from "vuex";
|
|
|
+import { v4 as uuidv4 } from "uuid";
|
|
|
+// 导入API方法
|
|
|
+import { getDicts } from "@/api/system/dict/data";
|
|
|
+import { addDragTable } from "@/api/tablelist/commonTable.js";
|
|
|
+import {
|
|
|
+ getFormName,
|
|
|
+ getListName
|
|
|
+} from "@/api/dragform/form.js";
|
|
|
+import { getTIdByTableKey, getTableInfo, getTableInfoByTableKey, removeByTableKey, addExcel, getExcelItem, updateExcel } from "@/api/system/table.js";
|
|
|
+export default {
|
|
|
+ name: "ExcelSheetEdit",
|
|
|
+ dicts: ["sys_time_format", "table_statistic_type"],
|
|
|
+ props: [],
|
|
|
+
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ id: '',
|
|
|
+ excelJson: '',
|
|
|
+ name:'',
|
|
|
+ luckysheetOptions: {
|
|
|
+ container: 'luckysheet',
|
|
|
+ lang: 'zh',
|
|
|
+ forceCalculation: false,
|
|
|
+ plugins: ['chart'],
|
|
|
+ myFolderUrl: '/system/fromModel/index/excelSheet',
|
|
|
+ hook: {
|
|
|
+ cellUpdated: (r, c, oldValue, newValue, isRefresh) => {
|
|
|
+ console.log('单元格更新:', r, c, oldValue, newValue);
|
|
|
+ },
|
|
|
+ updated: (operate) => {
|
|
|
+ console.log('操作更新:', operate);
|
|
|
+ },
|
|
|
+ cellEditBefore: (range) => {
|
|
|
+ console.log('编辑前:', range);
|
|
|
+ },
|
|
|
+ cellEditAfter: (range) => {
|
|
|
+ console.log('编辑后:', range);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ luckysheetInitialized: false,
|
|
|
+ originalWindowOpen: null,
|
|
|
+ pendingData: null,
|
|
|
+ // 弹窗
|
|
|
+ popUpVisible: false,
|
|
|
+ // 弹窗表格名称
|
|
|
+ popUpTableName: '',
|
|
|
+ // 弹窗表格列表
|
|
|
+ popUpTableList: [],
|
|
|
+ // 弹窗表格字段option[]
|
|
|
+ popUpTableFieldList: [],
|
|
|
+
|
|
|
+ relationTableList: [], //关联表格列表
|
|
|
+ // 关联方式option[]
|
|
|
+ relaTypeList: [
|
|
|
+ {
|
|
|
+ label: "等值连接",
|
|
|
+ value: "INNER JOIN",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "左连接",
|
|
|
+ value: "LEFT JOIN",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "右连接",
|
|
|
+ value: "RIGHT JOIN",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ isInputInvalid: false,
|
|
|
+ errorMessage: '',
|
|
|
+ dtName: '',
|
|
|
+ uuid: "",
|
|
|
+ tableKey: "",
|
|
|
+ // 修改表格的idList
|
|
|
+ tIdList: [],
|
|
|
+ tId: "",
|
|
|
+ // 当前选区
|
|
|
+ rangeAxis: [],
|
|
|
+ // 选区数据缓存
|
|
|
+ rangeDataCache: {},
|
|
|
+ // 存储所有选区的数据对象
|
|
|
+ rangeDataObjects: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ // 清空之前的数据
|
|
|
+ this.clearPreviousData();
|
|
|
+ // 动态引入Luckysheet资源
|
|
|
+ this.loadLuckysheet();
|
|
|
+ // 获取所有表
|
|
|
+ this.getAllTable();
|
|
|
+ // 获取路由参数
|
|
|
+ const { mode, editorId } = this.$route.query;
|
|
|
+ // console.log('路由参数:', { mode, editorId });
|
|
|
+ if (mode == 3 && editorId) {
|
|
|
+ // 编辑且id存在
|
|
|
+ this.getExistingData(editorId);
|
|
|
+ } else {
|
|
|
+ // 新增模式 - 获取模板数据
|
|
|
+ this.getTemplateData();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加keep-alive支持
|
|
|
+ activated() {
|
|
|
+ // 组件被激活时,清空之前的数据并重新初始化
|
|
|
+ console.log('组件被激活,清空数据并重新初始化');
|
|
|
+ this.clearPreviousData();
|
|
|
+ this.loadLuckysheet();
|
|
|
+ },
|
|
|
+
|
|
|
+ deactivated() {
|
|
|
+ // 组件被缓存时,保存状态
|
|
|
+ console.log('组件被缓存,保存当前状态');
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState({
|
|
|
+ databaseName: (state) => state.user.dataSource.databaseName,
|
|
|
+ databaseType: (state) => state.user.dataSource.databaseType,
|
|
|
+ username: (state) => state.user.dataSource.username,
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ popUpTableName: function (val) {
|
|
|
+ if (val) {
|
|
|
+ this.relationTableList = this.popUpTableList
|
|
|
+ .filter((item) => item.tableName != val)
|
|
|
+ .map((item) => {
|
|
|
+ return {
|
|
|
+ tableName: item.tableName,
|
|
|
+ tableComment: item.tableComment,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.relationTableList = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async openPopUp() {
|
|
|
+ this.popUpVisible = true;
|
|
|
+ this.rangeAxis = luckysheet.getRangeAxis();
|
|
|
+
|
|
|
+ // 添加详细的调试信息
|
|
|
+ console.log('=== openPopUp 调试信息 ===');
|
|
|
+ console.log('this.rangeDataObjects:', this.rangeDataObjects);
|
|
|
+ console.log('this.rangeDataObjects.length:', this.rangeDataObjects.length);
|
|
|
+ console.log('this.rangeDataObjects类型:', typeof this.rangeDataObjects);
|
|
|
+ console.log('this.rangeDataObjects是否为数组:', Array.isArray(this.rangeDataObjects));
|
|
|
+
|
|
|
+ if (this.rangeDataObjects && this.rangeDataObjects.length > 0) {
|
|
|
+ console.log('第一个对象:', this.rangeDataObjects[0]);
|
|
|
+ console.log('第一个对象的rangeAxis:', this.rangeDataObjects[0]?.rangeAxis);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取所有sheet,获取当前激活sheet的数字索引
|
|
|
+ let sheets = luckysheet.getAllSheets();
|
|
|
+ let currentSheet = sheets.find(sheet => sheet.status == 1);
|
|
|
+ let activeSheetIndex = sheets.findIndex(sheet => sheet.index === currentSheet.index);
|
|
|
+ console.log('当前激活的sheet索引:', activeSheetIndex);
|
|
|
+
|
|
|
+ // 检查当前选区是否已存在于rangeDataObjects中,且属于当前工作表
|
|
|
+ let existingRangeData = null;
|
|
|
+ let existingRangeIndex = -1;
|
|
|
+
|
|
|
+ // 遍历当前选区,检查是否已存在且属于当前工作表
|
|
|
+ for (let i = 0; i < this.rangeAxis.length; i++) {
|
|
|
+ const currentRange = this.rangeAxis[i];
|
|
|
+ console.log('=== 开始检查选区 ===');
|
|
|
+ console.log('当前选区:', currentRange, '类型:', typeof currentRange);
|
|
|
+ console.log('当前工作表索引:', activeSheetIndex, '类型:', typeof activeSheetIndex);
|
|
|
+ console.log('rangeDataObjects总数:', this.rangeDataObjects.length);
|
|
|
+
|
|
|
+ const existingIndex = this.rangeDataObjects.findIndex((item, index) => {
|
|
|
+ console.log(`\n--- 检查第${index}个对象 ---`);
|
|
|
+ console.log('item:', item);
|
|
|
+ console.log('item.rangeAxis:', item.rangeAxis);
|
|
|
+ console.log('item.rangeAxis[0]:', item.rangeAxis[0], '类型:', typeof item.rangeAxis[0]);
|
|
|
+ console.log('item.activeSheetIndex:', item.activeSheetIndex, '类型:', typeof item.activeSheetIndex);
|
|
|
+
|
|
|
+ // 严格比较,确保类型一致
|
|
|
+ const rangeMatch = item.rangeAxis[0] === currentRange;
|
|
|
+ const sheetMatch = String(item.activeSheetIndex) === String(activeSheetIndex);
|
|
|
+
|
|
|
+ console.log('选区比较:', item.rangeAxis[0], '===', currentRange, '结果:', rangeMatch);
|
|
|
+ console.log('工作表比较:', String(item.activeSheetIndex), '===', String(activeSheetIndex), '结果:', sheetMatch);
|
|
|
+ console.log('最终结果:', rangeMatch && sheetMatch);
|
|
|
+
|
|
|
+ return rangeMatch && sheetMatch;
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('existingIndex结果:', existingIndex);
|
|
|
+ console.log('=== 选区检查结束 ===\n');
|
|
|
+
|
|
|
+ if (existingIndex !== -1) {
|
|
|
+ console.log(` this.rangeDataObjects: `,this.rangeDataObjects);
|
|
|
+
|
|
|
+ existingRangeData = this.rangeDataObjects[existingIndex];
|
|
|
+ existingRangeIndex = existingIndex;
|
|
|
+ console.log(`找到已存在的选区数据(当前工作表): ${currentRange}`, existingRangeData);
|
|
|
+ break; // 找到第一个匹配的选区就停止
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (existingRangeData) {
|
|
|
+ // 如果找到已存在的选区数据,进行回显
|
|
|
+ console.log('使用已存在的选区数据进行回显:', existingRangeData);
|
|
|
+
|
|
|
+ // 通过tableKey获取配置信息
|
|
|
+ if (existingRangeData.tableKey) {
|
|
|
+ try {
|
|
|
+ // 1. 通过 tableKey 获取 tId
|
|
|
+ let tIdRes = await getTIdByTableKey(existingRangeData.tableKey);
|
|
|
+ if (tIdRes.code == 200 && tIdRes.data) {
|
|
|
+ let tId = tIdRes.data;
|
|
|
+ // 2. 通过 tId 获取表格配置信息
|
|
|
+ let res = await getTableInfo(tId);
|
|
|
+ if (res.code == 200 && res.data) {
|
|
|
+ let echoData = JSON.parse(res.data.echoData);
|
|
|
+ this.popUpTableFieldList = echoData.tableFieldData;
|
|
|
+ this.popUpTableName = echoData.tableName;
|
|
|
+ this.dtName = res.data.dtName || '';
|
|
|
+ console.log('echoData', echoData);
|
|
|
+ } else {
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ console.log('获取表格配置信息失败');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ console.log('通过tableKey获取tId失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('通过tableKey获取配置信息时出错:', error);
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log('没有tableKey,无法获取配置信息');
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果没有找到已存在的选区数据,使用原有的缓存逻辑
|
|
|
+ const cacheKey = this.tableKey + JSON.stringify(this.rangeAxis);
|
|
|
+ if (this.rangeDataCache[cacheKey]) {
|
|
|
+ // 有缓存,回显
|
|
|
+ this.popUpTableFieldList = JSON.parse(JSON.stringify(this.rangeDataCache[cacheKey]));
|
|
|
+ console.log('使用缓存数据回显');
|
|
|
+ } else {
|
|
|
+ // 没有缓存,清空
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ console.log('没有缓存数据,清空表格字段列表');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('打开弹窗,当前选区:', this.rangeAxis);
|
|
|
+ console.log('当前工作表索引:', activeSheetIndex);
|
|
|
+ console.log('当前表格字段列表:', this.popUpTableFieldList);
|
|
|
+ },
|
|
|
+ // 取消弹窗
|
|
|
+ popUpVisibleCancel() {
|
|
|
+ this.popUpVisible = false;
|
|
|
+ // 弹窗表格名称
|
|
|
+ this.popUpTableName = '';
|
|
|
+ // 弹窗表格字段option[] - 清空当前选择的表格字段
|
|
|
+ this.popUpTableFieldList = [];
|
|
|
+ // 关联表格列表 - 清空当前关联表数据
|
|
|
+ this.relationTableList = [];
|
|
|
+ // 重置输入验证状态
|
|
|
+ this.isInputInvalid = false;
|
|
|
+ // 重置别名
|
|
|
+ this.dtName = '';
|
|
|
+ // 重置错误提示
|
|
|
+ this.errorMessage = '';
|
|
|
+
|
|
|
+ },
|
|
|
+ // 确认弹窗
|
|
|
+ async popUpCreateHandle() {
|
|
|
+ this.isInputInvalid = true;
|
|
|
+ let columns = [];
|
|
|
+ let allColumns = [];
|
|
|
+ let validRes = this.validateTableData(this.popUpTableFieldList);
|
|
|
+ if (!validRes.val) {
|
|
|
+ this.errorMessage = validRes.msg;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.getCol(
|
|
|
+ this.popUpTableFieldList,
|
|
|
+ columns,
|
|
|
+ allColumns
|
|
|
+ );
|
|
|
+
|
|
|
+ this.uuid = uuidv4();
|
|
|
+ this.tableKey = uuidv4();
|
|
|
+ let echoData = {
|
|
|
+ tableName: this.popUpTableName,
|
|
|
+ tableFieldData: this.popUpTableFieldList,
|
|
|
+ formData: '',
|
|
|
+ filterData: '',
|
|
|
+ };
|
|
|
+ let data = {
|
|
|
+ dtName: this.dtName,
|
|
|
+ dtTableName: this.popUpTableName,
|
|
|
+ dtType: "8",
|
|
|
+ sqlKey: this.tableKey,
|
|
|
+ tableKey: this.uuid,
|
|
|
+ tId: "",
|
|
|
+ dtColumnName: columns, //列字段标题名称(存储显示字段信息
|
|
|
+ tableSql: this.getSQLStr(),
|
|
|
+ echoData: JSON.stringify(echoData),
|
|
|
+ };
|
|
|
+ console.log(' this.rangeDataObjects', this.rangeDataObjects);
|
|
|
+ if (this.tId) {
|
|
|
+ // res = await editTable(data);
|
|
|
+ // let res = await getTableInfo(this.tId);
|
|
|
+ // console.log('res---------', res);
|
|
|
+ } else {
|
|
|
+ let dataJ = [];
|
|
|
+ let tId = "";
|
|
|
+ let activeSheetIndex = '';
|
|
|
+ let res = await addDragTable(data);
|
|
|
+ if (res.code == 200) {
|
|
|
+
|
|
|
+ // 获取到的表格数据
|
|
|
+ let excelData = await getTableInfoByTableKey(this.uuid);
|
|
|
+ if (excelData.code == 200 && excelData.data) {
|
|
|
+ dataJ = excelData.data;
|
|
|
+ } else {
|
|
|
+ dataJ = [];
|
|
|
+ }
|
|
|
+ // 获取tId
|
|
|
+ let tIdRes = await getTIdByTableKey(this.uuid);
|
|
|
+ if (tIdRes.code == 200 && tIdRes.data) {
|
|
|
+ tId = tIdRes.data;
|
|
|
+ } else {
|
|
|
+ tId = "";
|
|
|
+ }
|
|
|
+ // 获取所有sheet, 遍历sheets获取status为1的sheet名称
|
|
|
+ let sheets = luckysheet.getAllSheets();
|
|
|
+ let currentSheet = sheets.find(sheet => sheet.status == 1);
|
|
|
+ let activeSheetIndex = sheets.findIndex(sheet => sheet.index === currentSheet.index);
|
|
|
+ console.log('当前激活的sheet索引:', activeSheetIndex);
|
|
|
+
|
|
|
+ let dataXQSJ = {
|
|
|
+ tableKey: this.uuid,//tableKey
|
|
|
+ rangeAxis: this.rangeAxis,//当前所有选区
|
|
|
+ dataJ: dataJ,//当前选区数据
|
|
|
+ tId: tId,//tId
|
|
|
+ activeSheetIndex: activeSheetIndex,//当前激活的sheet名称
|
|
|
+ }
|
|
|
+ // 将dataXQSJ的dataJ写入到当前激活的sheet的rangeAxis所有选区中
|
|
|
+ this.fillDataWithSetCellValue(dataXQSJ);
|
|
|
+
|
|
|
+ // 遍历每个选区,存储或替换数据对象
|
|
|
+ this.rangeAxis.forEach(async (range, index) => {
|
|
|
+ console.log('range', range);
|
|
|
+
|
|
|
+ // 创建当前选区的数据对象
|
|
|
+ let rangeDataObj = {
|
|
|
+ tableKey: this.uuid,
|
|
|
+ rangeAxis: [range], // 单个选区
|
|
|
+ activeSheetIndex: activeSheetIndex,
|
|
|
+ tId: tId,
|
|
|
+ };
|
|
|
+
|
|
|
+ // 检查是否有重叠的选区(只判断同一个 sheet)
|
|
|
+ const overlappingIndex = this.rangeDataObjects.findIndex(item => {
|
|
|
+ if (item.activeSheetIndex !== activeSheetIndex) return false;
|
|
|
+ const existingRange = item.rangeAxis[0];
|
|
|
+ return this.isRangeOverlapping(range, existingRange);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (overlappingIndex !== -1) {
|
|
|
+ // 如果存在重叠选区,删除重叠选区之前的所有数据
|
|
|
+ console.log(`检测到重叠选区: ${range} 与 ${this.rangeDataObjects[overlappingIndex].rangeAxis[0]},调用接口删除重叠选区之前的所有数据`);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取需要删除的选区数据(重叠选区之前的所有选区)
|
|
|
+ const rangesToDelete = this.rangeDataObjects.slice(0, overlappingIndex + 1);
|
|
|
+ console.log('需要删除的重叠选区:', rangesToDelete);
|
|
|
+ let tableKey = this.rangeDataObjects[overlappingIndex].tableKey;
|
|
|
+ console.log('需要删除的重叠选区tableKey:', tableKey);
|
|
|
+
|
|
|
+ tableKey = {
|
|
|
+ tableKey: tableKey
|
|
|
+ }
|
|
|
+ // 调用删除接口
|
|
|
+ let res = await removeByTableKey(tableKey);
|
|
|
+ if (res.code == 200) {
|
|
|
+ console.log('删除成功');
|
|
|
+ // 删除成功后,更新本地数组
|
|
|
+ this.rangeDataObjects.splice(overlappingIndex, 1);
|
|
|
+ // 添加新的选区数据
|
|
|
+ this.rangeDataObjects.push(rangeDataObj);
|
|
|
+ console.log(`接口删除成功,已清空重叠选区及其之前的所有数据,添加新选区: ${range}`);
|
|
|
+ } else {
|
|
|
+ console.log('删除失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 模拟API调用
|
|
|
+ console.log('调用删除接口,删除重叠选区:', rangesToDelete.map(item => item.rangeAxis[0]));
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('删除重叠选区数据失败:', error);
|
|
|
+ this.$message.error('删除重叠选区数据失败');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果不存在重复或重叠,添加新数据
|
|
|
+ this.rangeDataObjects.push(rangeDataObj);
|
|
|
+ console.log(`添加新选区数据:`, range);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('当前所有选区数据对象:', this.rangeDataObjects);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 清空错误提示和关闭弹窗
|
|
|
+ this.errorMessage = '';
|
|
|
+ this.popUpVisible = false;
|
|
|
+ },
|
|
|
+ // 递归获取列表信息
|
|
|
+ getCol(
|
|
|
+ tableFieldList,
|
|
|
+ columns,
|
|
|
+ allColumns = []
|
|
|
+ ) {
|
|
|
+ if (!tableFieldList.length) return;
|
|
|
+ for (let i = 0; i < tableFieldList.length; i++) {
|
|
|
+ let temp = tableFieldList[i];
|
|
|
+ let tempFieldName = "",
|
|
|
+ exportFieldName = "";
|
|
|
+ if (temp.isChildren) {
|
|
|
+ tempFieldName = temp.tableName + "_" + temp.fieldName;
|
|
|
+ exportFieldName = temp.tableName + "@" + temp.fieldName;
|
|
|
+ } else {
|
|
|
+ // tempFieldName = temp.fieldName;
|
|
|
+ tempFieldName = temp.tableName + "_" + temp.fieldName;
|
|
|
+ exportFieldName = temp.tableName + "_" + temp.fieldName;
|
|
|
+ }
|
|
|
+ // 保存所有字段
|
|
|
+ let obj = {
|
|
|
+ tableName: temp.tableName,
|
|
|
+ fieldName: temp.fieldName,
|
|
|
+ fieldDescription: temp.fieldDescription,
|
|
|
+ };
|
|
|
+ allColumns.push(obj);
|
|
|
+
|
|
|
+ if (temp.isShow) {
|
|
|
+ let tempObj = {};
|
|
|
+ tempObj[tempFieldName] = temp?.fieldDescription;
|
|
|
+ columns.push(tempObj);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 校验字段合法性(非递归版)
|
|
|
+ validateTableData(popUpTableFieldList) {
|
|
|
+ if (!popUpTableFieldList.length) {
|
|
|
+ return {
|
|
|
+ val: false,
|
|
|
+ msg: "字段个数不能为空",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (!this.dtName) {
|
|
|
+ return {
|
|
|
+ val: false,
|
|
|
+ msg: "别名不能为空",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ for (let i = 0; i < popUpTableFieldList.length; i++) {
|
|
|
+ let temp = popUpTableFieldList[i];
|
|
|
+ if (!temp.fieldDescription?.trim() && temp.isShow) {
|
|
|
+ return {
|
|
|
+ val: false,
|
|
|
+ msg: "显示的字段,字段描述不能为空",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ temp.relationTable &&
|
|
|
+ (!temp.relationFieldName || !temp.relationType)
|
|
|
+ ) {
|
|
|
+ return {
|
|
|
+ val: false,
|
|
|
+ msg: "关联条件不足,请完善关联条件",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (popUpTableFieldList.filter((item) => item.isShow).length == 0) {
|
|
|
+ return {
|
|
|
+ val: false,
|
|
|
+ msg: "显示的字段数不能为空",
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ val: true,
|
|
|
+ msg: "",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 获取表格字段option[]
|
|
|
+ async getAllTable() {
|
|
|
+ let data = {
|
|
|
+ databaseName: this.databaseName,
|
|
|
+ databaseType: this.databaseType,
|
|
|
+ };
|
|
|
+ let res = await getFormName(data);
|
|
|
+ console.log('getForm-Nameres', res);
|
|
|
+ const baseTable = await this.getDicts("base_table");
|
|
|
+ console.log('getDicts-baseTable', baseTable);
|
|
|
+ // 弹窗表格字段option[]
|
|
|
+ // 过滤掉在 baseTable.data 里出现过的表名,toLowerCase忽略大小写
|
|
|
+ this.popUpTableList = res.data.filter((item) => {
|
|
|
+ return !baseTable.data.some(
|
|
|
+ (value) =>
|
|
|
+ value.dictValue.toLowerCase() == item.tableName.toLowerCase()
|
|
|
+ );
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 获取关联表
|
|
|
+ getList() {
|
|
|
+ if (!this.popUpTableName) return;
|
|
|
+ let data = {
|
|
|
+ databaseName: this.databaseName,
|
|
|
+ databaseType: this.databaseType,
|
|
|
+ tableName: this.popUpTableName,
|
|
|
+ };
|
|
|
+ let popUpTableComment = this.getTableCommont(this.popUpTableName, this.popUpTableList);
|
|
|
+ // 获取当前表单结构信息
|
|
|
+ getListName(data).then((res) => {
|
|
|
+ console.log('res', res);
|
|
|
+ this.popUpTableFieldList = res.map((item, index) => {
|
|
|
+ return {
|
|
|
+ id: this.popUpTableName + "_" + item.fieldName,
|
|
|
+ fieldName: item.fieldName,
|
|
|
+ fieldDescription: item.fieldDescription,
|
|
|
+ relationTable: "",
|
|
|
+ relationFieldName: "",
|
|
|
+ relaFieldNameList: [],
|
|
|
+ disableRelaFieldName: false,
|
|
|
+ relationType: "",
|
|
|
+ relationShowField: [],
|
|
|
+ relationShowFiledList: [],
|
|
|
+ disableRelaType: false,
|
|
|
+ isShow: true,
|
|
|
+ isSearch: false,
|
|
|
+ isExport: false,
|
|
|
+ relationTableList: this.relationTableList,
|
|
|
+ tableName: this.popUpTableName,
|
|
|
+ tableComment: popUpTableComment,
|
|
|
+ relationFieldList: [],
|
|
|
+ };
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 获取当前表描述
|
|
|
+ getTableCommont(popUpTableName, popUpTableList) {
|
|
|
+ return popUpTableList.find((item) => item.tableName == popUpTableName).tableComment;
|
|
|
+ },
|
|
|
+ // 关联表变化回调
|
|
|
+ async ralationTableChange(row) {
|
|
|
+ this.popUpTableFieldList = this.popUpTableFieldList.filter((item) => {
|
|
|
+ return !row.relationFieldList.some((val) => {
|
|
|
+ return val.id == item.id;
|
|
|
+ });
|
|
|
+ });
|
|
|
+ row.relationFieldName = "";
|
|
|
+ row.relationType = "";
|
|
|
+ row.disableRelaFieldName = false;
|
|
|
+ row.disableRelaType = false;
|
|
|
+ row.relationFieldList = [];
|
|
|
+ if (!row.relationTable) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 获取关联表的字段
|
|
|
+ let data = {
|
|
|
+ databaseName: this.databaseName,
|
|
|
+ databaseType: this.databaseType,
|
|
|
+ tableName: row.relationTable,
|
|
|
+ };
|
|
|
+ let tableComment = this.getTableCommont(
|
|
|
+ row.relationTable,
|
|
|
+ this.popUpTableList
|
|
|
+ );
|
|
|
+ let res = await getListName(data);
|
|
|
+ // 关联字段下拉列表数据
|
|
|
+ row.relaFieldNameList = res.map((item) => {
|
|
|
+ return {
|
|
|
+ fieldName: item.fieldName,
|
|
|
+ fieldDescription: item.fieldDescription,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ let relationTableList = row.relationTableList.filter(
|
|
|
+ (item) => row.relationTable != item.tableName
|
|
|
+ );
|
|
|
+ row.relationFieldList = row.relaFieldNameList.map((item, index) => {
|
|
|
+ return {
|
|
|
+ id: row.relationTable + "_" + item.fieldName,
|
|
|
+ fieldName: item.fieldName,
|
|
|
+ fieldDescription: item.fieldDescription,
|
|
|
+ relationTable: "",
|
|
|
+ relationFieldName: "",
|
|
|
+ relaFieldNameList: [],
|
|
|
+ disableRelaFieldName: false,
|
|
|
+ relationType: "",
|
|
|
+ relationShowField: [],
|
|
|
+ relationShowFiledList: [],
|
|
|
+ disableRelaType: false,
|
|
|
+ isShow: true,
|
|
|
+ isSearch: false,
|
|
|
+ isExport: false,
|
|
|
+ relationTableList,
|
|
|
+ tableName: row.relationTable,
|
|
|
+ tableComment,
|
|
|
+ relationFieldList: [],
|
|
|
+ isChildren: true,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ row.disableRelaFieldName = true;
|
|
|
+ },
|
|
|
+ // 关联字段回调
|
|
|
+ relationFieldChange(row) {
|
|
|
+ console.log('关联字段回调', row);
|
|
|
+ if (!row.relationFieldName) {
|
|
|
+ row.relationType = "";
|
|
|
+ row.disableRelaType = false;
|
|
|
+ row.relaFieldNameList = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ row.disableRelaType = true;
|
|
|
+ },
|
|
|
+ // 关联类型变化回调
|
|
|
+ relationTypeChangeHandler(row) {
|
|
|
+ let tempRelationFieldList = row.relationFieldList.filter((item) => {
|
|
|
+ return !this.popUpTableFieldList.find((val) => val.id === item.id);
|
|
|
+ });
|
|
|
+ // // 确保关联字段的id是唯一的,添加时间戳或随机数
|
|
|
+ // tempRelationFieldList = tempRelationFieldList.map((item, index) => {
|
|
|
+ // return {
|
|
|
+ // ...item,
|
|
|
+ // id: item.id + '_' + Date.now() + '_' + index
|
|
|
+ // };
|
|
|
+ // });
|
|
|
+ this.popUpTableFieldList = [...this.popUpTableFieldList, ...tempRelationFieldList];
|
|
|
+ },
|
|
|
+ // 清空之前的数据
|
|
|
+ clearPreviousData() {
|
|
|
+ console.log('清空之前的数据...');
|
|
|
+
|
|
|
+ // 不清空选区数据对象数组,因为这是从服务器加载的重要数据
|
|
|
+ // this.rangeDataObjects = [];
|
|
|
+ console.log('保留rangeDataObjects数据:', this.rangeDataObjects);
|
|
|
+
|
|
|
+ // 清空Luckysheet容器
|
|
|
+ const container = document.getElementById('luckysheet');
|
|
|
+ if (container) {
|
|
|
+ container.innerHTML = '';
|
|
|
+ }
|
|
|
+ // 销毁之前的Luckysheet实例
|
|
|
+ if (window.luckysheet) {
|
|
|
+ try {
|
|
|
+ window.luckysheet.destroy();
|
|
|
+ console.log('之前的Luckysheet实例已销毁');
|
|
|
+ } catch (error) {
|
|
|
+ console.log('销毁之前的实例时出错:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置初始化状态
|
|
|
+ this.luckysheetInitialized = false;
|
|
|
+
|
|
|
+ // 清空可能存在的全局变量
|
|
|
+ if (window.luckysheetfile) {
|
|
|
+ delete window.luckysheetfile;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空其他可能的全局变量
|
|
|
+ this.clearGlobalVariables();
|
|
|
+
|
|
|
+ // 移除可能存在的CSS和JS
|
|
|
+ this.removePreviousResources();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清空全局变量
|
|
|
+ clearGlobalVariables() {
|
|
|
+ const globalVars = [
|
|
|
+ 'luckysheetfile',
|
|
|
+ 'luckysheet_select_save',
|
|
|
+ 'luckysheet_alternateformat_save',
|
|
|
+ 'luckysheet_conditionformat_save',
|
|
|
+ 'luckysheet_alternateformat_save_modelCustom'
|
|
|
+ ];
|
|
|
+
|
|
|
+ globalVars.forEach(varName => {
|
|
|
+ if (window[varName]) {
|
|
|
+ delete window[varName];
|
|
|
+ console.log(`已清空全局变量: ${varName}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 移除之前的资源
|
|
|
+ removePreviousResources() {
|
|
|
+ // 移除可能重复的CSS
|
|
|
+ const existingCSS = document.querySelectorAll('link[href*="luckysheet"]');
|
|
|
+ existingCSS.forEach(link => {
|
|
|
+ if (link.href.includes('luckysheet')) {
|
|
|
+ link.remove();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 移除可能重复的JS
|
|
|
+ const existingJS = document.querySelectorAll('script[src*="luckysheet"]');
|
|
|
+ existingJS.forEach(script => {
|
|
|
+ if (script.src.includes('luckysheet')) {
|
|
|
+ script.remove();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 动态加载Luckysheet资源
|
|
|
+ async loadLuckysheet() {
|
|
|
+ try {
|
|
|
+ console.log('开始加载Luckysheet资源...');
|
|
|
+
|
|
|
+ // 动态加载CSS
|
|
|
+ await this.loadCSS('/static/luckysheet/plugins/css/pluginsCss.css');
|
|
|
+ await this.loadCSS('/static/luckysheet/plugins/plugins.css');
|
|
|
+ await this.loadCSS('/static/luckysheet/css/luckysheet.css');
|
|
|
+ await this.loadCSS('/static/luckysheet/assets/iconfont/iconfont.css');
|
|
|
+
|
|
|
+ // 动态加载JS
|
|
|
+ await this.loadJS('/static/luckysheet/plugins/js/plugin.js');
|
|
|
+ await this.loadJS('/static/luckysheet/luckysheet.umd.js');
|
|
|
+
|
|
|
+ console.log('Luckysheet资源加载完成,开始初始化...');
|
|
|
+
|
|
|
+ // 初始化Luckysheet
|
|
|
+ this.initLuckysheet();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载Luckysheet失败:', error);
|
|
|
+ this.$message.error('Luckysheet加载失败,请检查资源路径');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 动态加载CSS
|
|
|
+ loadCSS(href) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 检查是否已经加载过
|
|
|
+ if (document.querySelector(`link[href="${href}"]`)) {
|
|
|
+ resolve();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const link = document.createElement('link');
|
|
|
+ link.rel = 'stylesheet';
|
|
|
+ link.href = href;
|
|
|
+ link.onload = () => {
|
|
|
+ console.log(`CSS加载成功: ${href}`);
|
|
|
+ resolve();
|
|
|
+ };
|
|
|
+ link.onerror = () => {
|
|
|
+ console.error(`CSS加载失败: ${href}`);
|
|
|
+ reject(new Error(`Failed to load CSS: ${href}`));
|
|
|
+ };
|
|
|
+ document.head.appendChild(link);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 动态加载JS
|
|
|
+ loadJS(src) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 检查是否已经加载过
|
|
|
+ if (document.querySelector(`script[src="${src}"]`)) {
|
|
|
+ resolve();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const script = document.createElement('script');
|
|
|
+ script.src = src;
|
|
|
+ script.onload = () => {
|
|
|
+ console.log(`JS加载成功: ${src}`);
|
|
|
+ resolve();
|
|
|
+ };
|
|
|
+ script.onerror = () => {
|
|
|
+ console.error(`JS加载失败: ${src}`);
|
|
|
+ reject(new Error(`Failed to load JS: ${src}`));
|
|
|
+ };
|
|
|
+ document.head.appendChild(script);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 初始化Luckysheet
|
|
|
+ initLuckysheet() {
|
|
|
+ // 确保Luckysheet已加载
|
|
|
+ if (typeof window.luckysheet !== 'undefined') {
|
|
|
+ console.log('Luckysheet对象已存在,标记为已初始化...');
|
|
|
+ try {
|
|
|
+ // 不要在这里创建实例,只标记为已初始化
|
|
|
+ this.luckysheetInitialized = true;
|
|
|
+
|
|
|
+ // 拦截myFolderUrl的点击事件
|
|
|
+ this.interceptMyFolderUrlClick();
|
|
|
+
|
|
|
+ // 检查是否有待处理的数据需要渲染
|
|
|
+ if (this.pendingData) {
|
|
|
+ console.log('渲染待处理的数据');
|
|
|
+ this.renderData(this.pendingData);
|
|
|
+ this.pendingData = null;
|
|
|
+ } else {
|
|
|
+ // 如果没有待处理数据,使用默认数据初始化
|
|
|
+ console.log('使用默认数据初始化Luckysheet');
|
|
|
+ this.renderData(this.getDefaultSheetData());
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Luckysheet初始化失败:', error);
|
|
|
+ this.$message.error('Luckysheet初始化失败');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果还没加载完成,延迟重试
|
|
|
+ console.log('Luckysheet对象未找到,延迟重试...');
|
|
|
+ setTimeout(() => this.initLuckysheet(), 200);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 拦截myFolderUrl的点击事件
|
|
|
+ interceptMyFolderUrlClick() {
|
|
|
+ // 方法1: 移除原有的点击事件
|
|
|
+ $(document).off('click', '.luckysheet-info-detail-title');
|
|
|
+
|
|
|
+ // 方法2: 阻止默认行为并自定义跳转
|
|
|
+ $(document).on('click', '.luckysheet-info-detail-title', (e) => {
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
+ console.log('myFolderUrl点击被拦截,执行自定义跳转');
|
|
|
+
|
|
|
+ // 使用Vue Router进行跳转,避免页面刷新
|
|
|
+ this.$router.push('/system/fromModel/index/excelSheet').then(() => {
|
|
|
+ // 跳转成功后清空数据
|
|
|
+ this.clearPreviousData();
|
|
|
+ });
|
|
|
+
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 方法3: 重写window.open方法
|
|
|
+ this.originalWindowOpen = window.open;
|
|
|
+ const that = this; // 保存this引用
|
|
|
+ window.open = function (url, target, features) {
|
|
|
+ if (url && (url.includes('myFolderUrl') || url.includes('/system/fromModel/index/excelSheet'))) {
|
|
|
+ console.log('myFolderUrl跳转被拦截:', url);
|
|
|
+ console.log('准备执行路由跳转...');
|
|
|
+
|
|
|
+ // 使用Vue Router进行跳转
|
|
|
+ try {
|
|
|
+ // 使用相对路径,避免路径问题
|
|
|
+ that.$router.push('/system/fromModel/index/excelSheet').then(() => {
|
|
|
+ console.log('路由跳转成功');
|
|
|
+ // 跳转成功后清空数据
|
|
|
+ that.clearPreviousData();
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('路由跳转失败:', err);
|
|
|
+ // 如果路由跳转失败,使用备用方法
|
|
|
+ console.log('使用备用跳转方法');
|
|
|
+ window.location.href = '/system/fromModel/index/excelSheet';
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('路由跳转异常:', error);
|
|
|
+ // 如果出现异常,使用备用方法
|
|
|
+ window.location.href = '/system/fromModel/index/excelSheet';
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return that.originalWindowOpen.call(this, url, target, features);
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 设置初始数据
|
|
|
+ setInitialData() {
|
|
|
+ // 这里可以设置一些初始的表格数据
|
|
|
+ // 例如:设置单元格值、格式等
|
|
|
+ console.log('设置初始数据...');
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取表格数据
|
|
|
+ getSheetData() {
|
|
|
+ if (window.luckysheet) {
|
|
|
+ const data = window.luckysheet.getAllSheets();
|
|
|
+ console.log('当前表格数据:', data);
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存数据
|
|
|
+ async saveData() {
|
|
|
+ let data = this.getSheetData();
|
|
|
+ let name = luckysheet.getWorkbookName();
|
|
|
+ if (data) {
|
|
|
+ console.log('保存数据:', data);
|
|
|
+ try {
|
|
|
+ // 获取所有 sheet
|
|
|
+ let allSheets = luckysheet.getAllSheets();
|
|
|
+
|
|
|
+ // 处理 rangeDataObjects,统一 activeSheetIndex 为数字下标
|
|
|
+ this.rangeDataObjects.forEach(obj => {
|
|
|
+ let idx = allSheets.findIndex(sheet => String(sheet.index) === String(obj.activeSheetIndex));
|
|
|
+ if (idx !== -1) {
|
|
|
+ obj.activeSheetIndex = idx;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取路由参数
|
|
|
+ console.log('转换后的数据:', data[0]?.celldata);
|
|
|
+ // 准备保存的数据
|
|
|
+ const saveData = {
|
|
|
+ ...(this.id && { id: +this.id }),
|
|
|
+ name: name || '默认表格',
|
|
|
+ excelJson: JSON.stringify(data.map(sheet => ({
|
|
|
+ name: sheet.name,
|
|
|
+ celldata: sheet.celldata,
|
|
|
+ }))),
|
|
|
+ excelTableConfig: this.rangeDataObjects.length > 0 ? JSON.stringify(this.rangeDataObjects.map(item => ({
|
|
|
+ tableKey: item.tableKey,
|
|
|
+ rangeAxis: item.rangeAxis,
|
|
|
+ activeSheetIndex: item.activeSheetIndex
|
|
|
+ }))) : '', // 保存简化的选区配置数据
|
|
|
+
|
|
|
+ // 可以添加其他需要保存的字段
|
|
|
+ };
|
|
|
+ console.log('调用保存API--------------:', saveData);
|
|
|
+ if(this.id && this.id !== ""){
|
|
|
+ // 有ID,调用更新方法 (PUT)
|
|
|
+ updateExcel(saveData).then(res => {
|
|
|
+ console.log('更新成功:', res);
|
|
|
+ if (res.code == 200) {
|
|
|
+ this.$message.success('数据保存成功');
|
|
|
+ // 关闭当前tab并跳转
|
|
|
+ this.$store.dispatch('tagsView/delView', this.$route).then(() => {
|
|
|
+ this.$router.push('/system/fromModel/index/excelSheet');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message.error('数据保存失败');
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('更新失败:', err);
|
|
|
+ this.$message.error('数据保存失败');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 没有ID,调用新增方法 (POST)
|
|
|
+ addExcel(saveData).then(res => {
|
|
|
+ console.log('新增成功:', res);
|
|
|
+ if (res.code == 200) {
|
|
|
+ this.$message.success('数据保存成功');
|
|
|
+ // 关闭当前tab并跳转
|
|
|
+ this.$store.dispatch('tagsView/delView', this.$route).then(() => {
|
|
|
+ this.$router.push('/system/fromModel/index/excelSheet');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.$message.error('数据保存失败');
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('新增失败:', err);
|
|
|
+ this.$message.error('数据保存失败');
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('保存数据失败:', error);
|
|
|
+ this.$message.error('保存数据失败');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$message.warning('没有数据需要保存');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取模板数据
|
|
|
+ async getTemplateData() {
|
|
|
+ try {
|
|
|
+ // 使用默认的空数据
|
|
|
+ let templateData = this.getDefaultSheetData();
|
|
|
+ console.log('templateData-------------', templateData);
|
|
|
+
|
|
|
+ this.renderData(templateData);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取模板数据失败:', error);
|
|
|
+ this.$message.error('获取模板数据失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取现有数据
|
|
|
+ async getExistingData(editorId) {
|
|
|
+ try {
|
|
|
+ // 当前id赋值
|
|
|
+ this.id = editorId;
|
|
|
+ // 使用 async/await 等待异步操作完成
|
|
|
+ const response = await getExcelItem(editorId);
|
|
|
+ // console.log('API响应:', response);
|
|
|
+ if (response.code == 200 && response.data) {
|
|
|
+ // excel内容数据
|
|
|
+ this.excelJson = JSON.parse(response.data?.excelJson);
|
|
|
+ // 解析选区配置数据
|
|
|
+ try {
|
|
|
+ console.log('=== 解析excelTableConfig ===');
|
|
|
+ console.log('response.data?.excelTableConfig:', JSON.parse(response.data?.excelTableConfig));
|
|
|
+ console.log('excelTableConfig类型:', typeof response.data?.excelTableConfig);
|
|
|
+ console.log('excelTableConfig是否为空:', !response.data?.excelTableConfig);
|
|
|
+ console.log('excelTableConfig是否为空字符串:', response.data?.excelTableConfig === '');
|
|
|
+ console.log('excelTableConfig.trim():', response.data?.excelTableConfig?.trim());
|
|
|
+ if (response.data?.excelTableConfig && response.data.excelTableConfig.trim() !== '') {
|
|
|
+ this.rangeDataObjects = JSON.parse(response.data.excelTableConfig);
|
|
|
+ console.log('成功解析选区配置数据------------:', this.rangeDataObjects);
|
|
|
+ // -----
|
|
|
+ } else {
|
|
|
+ this.rangeDataObjects = [];
|
|
|
+ console.log('没有选区配置数据,初始化为空数组');
|
|
|
+ }
|
|
|
+ } catch (parseError) {
|
|
|
+ console.error('解析选区配置数据失败:', parseError);
|
|
|
+ console.error('解析失败的数据:', response.data?.excelTableConfig);
|
|
|
+ this.rangeDataObjects = [];
|
|
|
+ console.log('解析失败,初始化为空数组');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.name = response.data?.name;
|
|
|
+ console.log('excelJson------------', this.excelJson);
|
|
|
+ console.log('rangeDataObjects------------', this.rangeDataObjects);
|
|
|
+ // excelTableConfig: this.rangeDataObjects.length > 0 ? JSON.stringify(this.rangeDataObjects) : '', // 保存当前的选区数据
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.excelJson = '';
|
|
|
+ this.rangeDataObjects = [];
|
|
|
+ console.log('没有找到数据或数据为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析excelJson
|
|
|
+ let existingData;
|
|
|
+
|
|
|
+ if (this.excelJson) {
|
|
|
+ try {
|
|
|
+ let parsedData;
|
|
|
+ if (typeof this.excelJson === 'string') {
|
|
|
+ parsedData = JSON.parse(this.excelJson);
|
|
|
+ } else {
|
|
|
+ parsedData = this.excelJson;
|
|
|
+ }
|
|
|
+ let sheets = parsedData.map(sheet => ({
|
|
|
+ ...sheet,
|
|
|
+ // 这里可以补全 Luckysheet 需要的字段
|
|
|
+ }));
|
|
|
+ existingData = { sheets };
|
|
|
+ } catch (parseError) {
|
|
|
+ console.error('解析excelJson失败:', parseError);
|
|
|
+ this.$message.error('解析Excel数据失败');
|
|
|
+ // 如果解析失败,使用默认空数据
|
|
|
+ existingData = this.getDefaultSheetData();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log('没有excelJson数据,使用默认数据');
|
|
|
+ existingData = this.getDefaultSheetData();
|
|
|
+ }
|
|
|
+
|
|
|
+ this.renderData(existingData);
|
|
|
+
|
|
|
+ // 确保 activeSheetIndex 一致
|
|
|
+ let sheets = luckysheet.getAllSheets();
|
|
|
+ this.rangeDataObjects.forEach(obj => {
|
|
|
+ let idx = sheets.findIndex(sheet => String(sheet.index) === String(obj.activeSheetIndex));
|
|
|
+ if (idx !== -1) {
|
|
|
+ obj.activeSheetIndex = idx;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取表格数据失败:', error);
|
|
|
+ this.$message.error('获取表格数据失败');
|
|
|
+ // 出错时使用默认数据
|
|
|
+ this.renderData(this.getDefaultSheetData());
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 渲染数据到Luckysheet
|
|
|
+ renderData(data) {
|
|
|
+ console.log('渲染数据到Luckysheet:', data);
|
|
|
+
|
|
|
+ // 等待Luckysheet初始化完成后再渲染数据
|
|
|
+ if (this.luckysheetInitialized && window.luckysheet) {
|
|
|
+ try {
|
|
|
+ // 先销毁当前实例(如果存在)
|
|
|
+ if (window.luckysheetfile) {
|
|
|
+ console.log('销毁之前的Luckysheet实例...');
|
|
|
+ window.luckysheet.destroy();
|
|
|
+ // 等待一小段时间确保销毁完成
|
|
|
+ setTimeout(() => {
|
|
|
+ this.createLuckysheetInstance(data);
|
|
|
+ }, 100);
|
|
|
+ } else {
|
|
|
+ this.createLuckysheetInstance(data);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('渲染数据失败:', error);
|
|
|
+ this.$message.error('渲染数据失败');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果Luckysheet还没初始化,保存数据等待初始化完成
|
|
|
+ this.pendingData = data;
|
|
|
+ console.log('Luckysheet未初始化,数据已保存等待渲染');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 创建Luckysheet实例
|
|
|
+ createLuckysheetInstance(data) {
|
|
|
+ try {
|
|
|
+ console.log('开始创建Luckysheet实例...');
|
|
|
+
|
|
|
+ // 创建新实例并加载数据
|
|
|
+ const options = {
|
|
|
+ ...this.luckysheetOptions,
|
|
|
+ data: JSON.parse(JSON.stringify(data.sheets))
|
|
|
+ };
|
|
|
+ console.log('options--------', options);
|
|
|
+
|
|
|
+ // 确保数据格式正确
|
|
|
+ if (!options.data || !Array.isArray(options.data)) {
|
|
|
+ console.warn('数据格式不正确,使用默认数据');
|
|
|
+ options.data = this.getDefaultSheetData().sheets;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('options.data=================:', options.data);
|
|
|
+ console.log('luckysheetOptions=====================ss:', this.luckysheetOptions);
|
|
|
+
|
|
|
+ window.luckysheet.create({
|
|
|
+ ...this.luckysheetOptions,
|
|
|
+ data: options.data
|
|
|
+ });
|
|
|
+ console.log('Luckysheet实例创建成功');
|
|
|
+
|
|
|
+ if(this.name){
|
|
|
+ luckysheet.setWorkbookName(this.name);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('创建Luckysheet实例失败:', error);
|
|
|
+ this.$message.error('创建Luckysheet实例失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 递归拼接SQL字段和JOIN
|
|
|
+ getSQLString(tableFieldList, fieldArr, tableArr, sqlType = "mysql") {
|
|
|
+ let prefix = "{DBNAME}.";
|
|
|
+ let asOrSpace = sqlType === "oracle" ? " " : " AS ";
|
|
|
+ for (let i = 0; i < tableFieldList.length; i++) {
|
|
|
+ let temp = tableFieldList[i];
|
|
|
+ // 拼接字段
|
|
|
+ let tempArr = prefix + temp.tableName + "." + temp.fieldName;
|
|
|
+ tempArr += asOrSpace + temp.tableName + "_" + temp.fieldName;
|
|
|
+ fieldArr.push(tempArr);
|
|
|
+
|
|
|
+ // 拼接关联
|
|
|
+ if (temp.relationTable && temp.relationFieldName && temp.relationType) {
|
|
|
+ let isNeedUsername = sqlType === "oracle" ? (this.username ? this.username + "." : "") : "";
|
|
|
+ tableArr.push(
|
|
|
+ temp.relationType +
|
|
|
+ " " +
|
|
|
+ isNeedUsername +
|
|
|
+ prefix +
|
|
|
+ temp.relationTable +
|
|
|
+ asOrSpace +
|
|
|
+ temp.relationTable +
|
|
|
+ " ON " +
|
|
|
+ prefix +
|
|
|
+ temp.relationTable +
|
|
|
+ "." +
|
|
|
+ temp.relationFieldName +
|
|
|
+ " = " +
|
|
|
+ prefix +
|
|
|
+ temp.tableName +
|
|
|
+ "." +
|
|
|
+ temp.fieldName
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生成最终SQL
|
|
|
+ getSQLStr() {
|
|
|
+ let prefix = "{DBNAME}.";
|
|
|
+ let sqlType = this.databaseType || "mysql";
|
|
|
+ let asOrSpace = sqlType === "oracle" ? " " : " AS ";
|
|
|
+ let sql = "SELECT ";
|
|
|
+ let fieldNameArr = [], relaTypeArr = [];
|
|
|
+ this.getSQLString(this.popUpTableFieldList, fieldNameArr, relaTypeArr, sqlType);
|
|
|
+ // console.log('fieldNameArr', fieldNameArr);
|
|
|
+ sql += fieldNameArr.join(",") +
|
|
|
+ " FROM " +
|
|
|
+ prefix +
|
|
|
+ this.popUpTableName +
|
|
|
+ asOrSpace +
|
|
|
+ this.popUpTableName;
|
|
|
+ if (relaTypeArr.length) {
|
|
|
+ sql += " " + relaTypeArr.join(" ");
|
|
|
+ }
|
|
|
+ return sql;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // 每个选区都填充同一份二维数据
|
|
|
+ fillDataWithSetCellValue(dataXQSJ) {
|
|
|
+ if (window.luckysheet) {
|
|
|
+ try {
|
|
|
+ const rangeAxis = dataXQSJ.rangeAxis;
|
|
|
+ const dataJ = dataXQSJ.dataJ; // 这里是一份二维数组
|
|
|
+ const flowdata = luckysheet.flowdata();
|
|
|
+
|
|
|
+ rangeAxis.forEach((rangeStr) => {
|
|
|
+ const coordinates = this.parseRangeString(rangeStr);
|
|
|
+ if (coordinates) {
|
|
|
+ this.fillRangeWithData(coordinates, dataJ, flowdata);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ luckysheet.jfrefreshgrid();
|
|
|
+ console.log('所有选区填充完成');
|
|
|
+
|
|
|
+ // 保存本次数据到缓存
|
|
|
+ const cacheKey = dataXQSJ.tableKey + JSON.stringify(dataXQSJ.rangeAxis);
|
|
|
+ this.rangeDataCache[cacheKey] = JSON.parse(JSON.stringify(this.popUpTableFieldList));
|
|
|
+ } catch (error) {
|
|
|
+ console.error('填充数据失败:', error);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.error('Luckysheet未初始化,无法填充数据');
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 填充数据到指定选区,支持二维数组
|
|
|
+ fillRangeWithData(coordinates, dataBlock, flowdata) {
|
|
|
+ try {
|
|
|
+ const { startRow, endRow, startCol, endCol } = coordinates;
|
|
|
+ let rowCount = endRow - startRow + 1;
|
|
|
+ let colCount = endCol - startCol + 1;
|
|
|
+ for (let r = 0; r < rowCount; r++) {
|
|
|
+ for (let c = 0; c < colCount; c++) {
|
|
|
+ const cellValue = (dataBlock[r] && dataBlock[r][c]) ? dataBlock[r][c] : '';
|
|
|
+ luckysheet.setcellvalue(startRow + r, startCol + c, flowdata, cellValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('填充选区数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 解析选区坐标字符串
|
|
|
+ parseRangeString(rangeStr) {
|
|
|
+ try {
|
|
|
+ // 处理单个单元格的情况,如 "A1", "C4"
|
|
|
+ if (/^[A-Z]+\d+$/.test(rangeStr)) {
|
|
|
+ const match = rangeStr.match(/^([A-Z]+)(\d+)$/);
|
|
|
+ if (match) {
|
|
|
+ const col = this.columnToNumber(match[1]);
|
|
|
+ const row = parseInt(match[2]) - 1; // 转换为0基索引
|
|
|
+ return {
|
|
|
+ startRow: row,
|
|
|
+ endRow: row,
|
|
|
+ startCol: col,
|
|
|
+ endCol: col
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理矩形区域的情况,如 "A1:B3", "D9:E12"
|
|
|
+ if (/^[A-Z]+\d+:[A-Z]+\d+$/.test(rangeStr)) {
|
|
|
+ const parts = rangeStr.split(':');
|
|
|
+ const startMatch = parts[0].match(/^([A-Z]+)(\d+)$/);
|
|
|
+ const endMatch = parts[1].match(/^([A-Z]+)(\d+)$/);
|
|
|
+
|
|
|
+ if (startMatch && endMatch) {
|
|
|
+ const startCol = this.columnToNumber(startMatch[1]);
|
|
|
+ const startRow = parseInt(startMatch[2]) - 1;
|
|
|
+ const endCol = this.columnToNumber(endMatch[1]);
|
|
|
+ const endRow = parseInt(endMatch[2]) - 1;
|
|
|
+
|
|
|
+ return {
|
|
|
+ startRow: Math.min(startRow, endRow),
|
|
|
+ endRow: Math.max(startRow, endRow),
|
|
|
+ startCol: Math.min(startCol, endCol),
|
|
|
+ endCol: Math.max(startCol, endCol)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.warn('无法解析选区字符串:', rangeStr);
|
|
|
+ return null;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('解析选区字符串失败:', error);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 将列字母转换为数字
|
|
|
+ columnToNumber(column) {
|
|
|
+ let result = 0;
|
|
|
+ for (let i = 0; i < column.length; i++) {
|
|
|
+ result = result * 26 + (column.charCodeAt(i) - 64);
|
|
|
+ }
|
|
|
+ return result - 1; // 转换为0基索引
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取所有选区数据对象
|
|
|
+ getAllRangeDataObjects() {
|
|
|
+ return this.rangeDataObjects;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 根据range获取数据对象
|
|
|
+ getRangeDataObjectByRange(range) {
|
|
|
+ return this.rangeDataObjects.find(item => item.rangeAxis[0] === range) || null;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 根据索引获取数据对象
|
|
|
+ getRangeDataObjectByIndex(index) {
|
|
|
+ return this.rangeDataObjects[index] || null;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除指定range的数据对象
|
|
|
+ removeRangeDataObject(range) {
|
|
|
+ const index = this.rangeDataObjects.findIndex(item => item.rangeAxis[0] === range);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.rangeDataObjects.splice(index, 1);
|
|
|
+ console.log(`已删除选区数据: ${range}`);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 清空所有选区数据对象
|
|
|
+ clearRangeDataObjects() {
|
|
|
+ this.rangeDataObjects = [];
|
|
|
+ console.log('已清空所有选区数据对象');
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取选区数据对象的数量
|
|
|
+ getRangeDataObjectsCount() {
|
|
|
+ return this.rangeDataObjects.length;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查是否存在指定的range
|
|
|
+ hasRangeDataObject(range) {
|
|
|
+ return this.rangeDataObjects.some(item => item.rangeAxis[0] === range);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 示例:展示选区数据对象的使用
|
|
|
+ showRangeDataObjectsInfo() {
|
|
|
+ console.log('=== 选区数据对象信息 ===');
|
|
|
+ console.log('总数量:', this.getRangeDataObjectsCount());
|
|
|
+
|
|
|
+ this.rangeDataObjects.forEach((dataObj, index) => {
|
|
|
+ console.log(`选区${index + 1}:`);
|
|
|
+ console.log(' - Range:', dataObj.rangeAxis[0]);
|
|
|
+ console.log(' - TableKey:', dataObj.tableKey);
|
|
|
+ console.log(' - TId:', dataObj.tId);
|
|
|
+ console.log(' - activeSheetIndex:', dataObj.activeSheetIndex);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查选区是否重叠
|
|
|
+ isRangeOverlapping(range1, range2) {
|
|
|
+ try {
|
|
|
+ const coords1 = this.parseRangeString(range1);
|
|
|
+ const coords2 = this.parseRangeString(range2);
|
|
|
+
|
|
|
+ if (!coords1 || !coords2) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否有重叠
|
|
|
+ const rowOverlap = coords1.startRow <= coords2.endRow && coords1.endRow >= coords2.startRow;
|
|
|
+ const colOverlap = coords1.startCol <= coords2.endCol && coords1.endCol >= coords2.startCol;
|
|
|
+
|
|
|
+ return rowOverlap && colOverlap;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('检查选区重叠失败:', error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取默认的sheet数据
|
|
|
+ getDefaultSheetData() {
|
|
|
+ return {
|
|
|
+ sheets: [{
|
|
|
+ name: "Sheet1",
|
|
|
+ color: "",
|
|
|
+ index: 0,
|
|
|
+ status: 1,
|
|
|
+ order: 0,
|
|
|
+ hide: 0,
|
|
|
+ row: 36,
|
|
|
+ column: 18,
|
|
|
+ defaultRowHeight: 19,
|
|
|
+ defaultColWidth: 73,
|
|
|
+ celldata: [],
|
|
|
+ config: {
|
|
|
+ merge: {},
|
|
|
+ rowlen: {},
|
|
|
+ columnlen: {},
|
|
|
+ rowhidden: {},
|
|
|
+ colhidden: {},
|
|
|
+ borderInfo: {},
|
|
|
+ authority: {},
|
|
|
+ },
|
|
|
+ scrollLeft: 0,
|
|
|
+ scrollTop: 0,
|
|
|
+ luckysheet_select_save: [],
|
|
|
+ calcChain: [],
|
|
|
+ isPivotTable: false,
|
|
|
+ pivotTable: {},
|
|
|
+ filter_select: {},
|
|
|
+ filter: null,
|
|
|
+ luckysheet_alternateformat_save: [],
|
|
|
+ luckysheet_alternateformat_save_modelCustom: [],
|
|
|
+ luckysheet_conditionformat_save: {},
|
|
|
+ frozen: {},
|
|
|
+ chart: [],
|
|
|
+ zoomRatio: 1,
|
|
|
+ image: [],
|
|
|
+ showGridLines: 1,
|
|
|
+ dataVerification: {},
|
|
|
+ }]
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeDestroy() {
|
|
|
+ // 组件销毁时清理资源
|
|
|
+ if (window.luckysheet) {
|
|
|
+ try {
|
|
|
+ window.luckysheet.destroy();
|
|
|
+ console.log('Luckysheet实例已销毁');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('销毁Luckysheet实例失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 恢复原始的window.open方法
|
|
|
+ if (this.originalWindowOpen) {
|
|
|
+ window.open = this.originalWindowOpen;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移除事件监听器
|
|
|
+ $(document).off('click', '.luckysheet-info-detail-title');
|
|
|
+
|
|
|
+ this.luckysheetInitialized = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ position: relative;
|
|
|
+ height: 100vh;
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ overflow: hidden;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+#luckysheet {
|
|
|
+ z-index: 1;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .luckysheet-wa-editor {
|
|
|
+ overflow-x: auto;
|
|
|
+ overflow-y: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep #luckysheet-icon-morebtn {
|
|
|
+ right: 0;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.ipt {
|
|
|
+ height: 36px;
|
|
|
+ line-height: 36px;
|
|
|
+ font-size: 14px;
|
|
|
+ width: 100%;
|
|
|
+ outline: none;
|
|
|
+ text-align: center;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ color: #606266;
|
|
|
+ display: inline-block;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.isNullDesc {
|
|
|
+ border-color: #ff4949 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.ipt:focus {
|
|
|
+ border-color: #1890ff;
|
|
|
+}
|
|
|
+
|
|
|
+.popUpTitle {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.popUpTitleDiv {
|
|
|
+ width: 50px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+</style>
|