<!-- eslint-disable no-useless-escape -->
|
<!-- eslint-disable no-console -->
|
<!-- eslint-disable unicorn/prefer-structured-clone -->
|
<script lang="ts" setup>
|
import { reactive, ref, toRefs, unref, watch } from 'vue';
|
|
import { IWorkbookData } from '@univerjs/core';
|
import { DeviceInputEventType, ITextWatermarkConfig } from '@univerjs/engine-render';
|
import { SetSelectionsOperation, SetWorksheetActiveOperation, WorkbookEditablePermission } from '@univerjs/sheets';
|
import JsBarcode from 'jsbarcode';
|
import { debounce } from 'lodash-es';
|
import { storeToRefs } from 'pinia';
|
import QRCode from 'qrcode';
|
|
import JnpfUniverCellEchart from '../Design/univer/components/Echart/cell.vue';
|
import { CreateUnitProps, DeliverCellDataProps, DeliverFloatEchartOptionProps, DeliverFloatImageOptionProps, DesignStateProps } from './index';
|
import { useJnpfUniverStore } from './store';
|
import { JnpfFUniver } from './univer/facade';
|
import {
|
base64ToFile,
|
getParentCellPosWhenClearCell,
|
getParentCellPosWhenDelete,
|
getParentCellPosWhenInsert,
|
getParentCellPosWhenMove,
|
getParentCellPosWhenMoveCell,
|
isEmptyObject,
|
isNullOrUndefined,
|
} from './univer/utils';
|
import {
|
DefaultDialogSelectCellConfig,
|
DefaultFloatEchartOptions,
|
DefaultFloatImageOption,
|
DefaultPrintConfig,
|
DefaultWatermarkConfig,
|
JnpfCommandIds,
|
jnpfPaperPaddingTypeOptions,
|
jnpfPaperTypeOptions,
|
jnpfPrintAreaOptions,
|
jnpfPrintDirectionOptions,
|
jnpfPrintHAlignOptions,
|
jnpfPrintScaleOptions,
|
jnpfPrintVAlignOptions,
|
JnpfUniverDialogSelectCellKey,
|
} from './univer/utils/define';
|
import {
|
analysisCreateUnitData,
|
arrangeDesignWorkbookData,
|
arrangePreviewWorkbookData,
|
createUniverInstance,
|
judgeSheetHasCustomFloatDom,
|
onInsertedFloatEchart,
|
onInsertedFloatImage,
|
updateFloatStoreId,
|
} from './univer/utils/univer';
|
import { buildUUID } from './univer/utils/uuid';
|
|
import '@univerjs/design/lib/index.css';
|
import '@univerjs/ui/lib/index.css';
|
import '@univerjs/docs-ui/lib/index.css';
|
// import '@univerjs-pro/sheets-print/lib/index.css';
|
import '@univerjs/sheets-ui/lib/index.css';
|
import '@univerjs/sheets-formula-ui/lib/index.css';
|
import '@univerjs/sheets-numfmt-ui/lib/index.css';
|
import '@univerjs/sheets-filter-ui/lib/index.css';
|
import '@univerjs/sheets-sort-ui/lib/index.css';
|
import '@univerjs/sheets-data-validation-ui/lib/index.css';
|
import '@univerjs/sheets-conditional-formatting-ui/lib/index.css';
|
import '@univerjs/sheets-hyper-link-ui/lib/index.css';
|
import '@univerjs/drawing-ui/lib/index.css';
|
import '@univerjs/sheets-drawing-ui/lib/index.css';
|
import '@univerjs/thread-comment-ui/lib/index.css';
|
import '@univerjs/find-replace/lib/index.css';
|
import '@univerjs/sheets-crosshair-highlight/lib/index.css';
|
import '@univerjs/sheets-zen-editor/lib/index.css';
|
import '@univerjs/uniscript/lib/index.css';
|
|
defineOptions({ name: 'JnpfUniverDesign' });
|
const emits = defineEmits(['preview', 'focusFloatEchart', 'focusFloatImage', 'changeCell', 'changeDialogSelectCell']);
|
|
const state = reactive<DesignStateProps>({
|
activeSelections: [],
|
activeWorkbook: null,
|
|
activeWorkbookId: null,
|
|
activeWorksheet: null,
|
|
activeWorksheetId: null,
|
beforeCommandExecuteMonitor: null,
|
commandExecuteMonitor: null,
|
configDialogCellTarget: null,
|
|
containerEleId: null,
|
dialogCellInstance: null,
|
|
jnpfUniverAPI: null,
|
loading: false,
|
|
openDialogCell: false,
|
selectionChangeMonitor: null,
|
univer: null,
|
|
univerCreateMode: 'design',
|
});
|
const {
|
activeSelections,
|
activeWorkbook,
|
activeWorkbookId,
|
activeWorksheet,
|
activeWorksheetId,
|
beforeCommandExecuteMonitor,
|
commandExecuteMonitor,
|
configDialogCellTarget,
|
containerEleId,
|
dialogCellInstance,
|
jnpfUniverAPI,
|
loading,
|
openDialogCell,
|
selectionChangeMonitor,
|
univerCreateMode,
|
} = toRefs(state);
|
|
// 创建设计器的动态id
|
const dynamicJnpfUniverStoreId = `jnpfUniver_${buildUUID()}`;
|
state.containerEleId = dynamicJnpfUniverStoreId;
|
|
const jnpfUniverStore = useJnpfUniverStore(dynamicJnpfUniverStoreId);
|
const { dialogSelectCellDataCache, dialogSelectCellStateCache } = storeToRefs(jnpfUniverStore);
|
|
const jnpfUniverCellEchartRef = ref();
|
|
// 创建工作簿
|
function handleCreateDesignUnit(options?: CreateUnitProps) {
|
// 销毁实例
|
handleDisposeUnit();
|
|
const {
|
defaultActiveSheetId,
|
floatEcharts = {},
|
floatImages = {},
|
loading: createLoading = false,
|
|
mode = 'design',
|
readonly: isReadonly = false,
|
snapshot: workbookData,
|
uiContextMenu = true,
|
|
uiFooter = true,
|
|
uiHeader = true,
|
|
watermark = {},
|
|
darkMode = false,
|
} = options ?? {};
|
|
state.univerCreateMode = mode;
|
state.loading = createLoading;
|
|
const containerEle = getDesignContainerEle();
|
if (!containerEle) {
|
console.warn('报表构建失败');
|
return;
|
}
|
|
// 更新浮动元素的storeId
|
const workbookDataCache = workbookData ? updateFloatStoreId(workbookData, dynamicJnpfUniverStoreId) : '{}';
|
// 解析创建univer实例的快照数据
|
const realWorkbookData = workbookData ? analysisCreateUnitData(workbookDataCache, univerCreateMode.value, isReadonly) : {};
|
|
// 构建实例
|
const univerInstance = createUniverInstance({
|
container: containerEle,
|
contextMenu: uiContextMenu,
|
footer: uiFooter,
|
header: isReadonly ? false : uiHeader,
|
workbookData: realWorkbookData,
|
darkMode,
|
});
|
|
state.univer = univerInstance;
|
state.jnpfUniverAPI = JnpfFUniver.newAPI(univerInstance);
|
|
state.activeWorkbook = jnpfUniverAPI.value?.getActiveWorkbook();
|
state.activeWorkbookId = activeWorkbook.value?.getId();
|
|
// 改变默认激活的工作表
|
if (defaultActiveSheetId) {
|
jnpfUniverAPI.value?.executeCommand(SetWorksheetActiveOperation.id, {
|
subUnitId: defaultActiveSheetId,
|
unitId: activeWorkbookId.value,
|
});
|
}
|
|
state.activeWorksheet = activeWorkbook.value?.getActiveSheet();
|
state.activeWorksheetId = activeWorksheet.value?.getSheetId();
|
|
// 同步数据到store
|
jnpfUniverStore?.setJnpfUniverApiCache(jnpfUniverAPI.value);
|
jnpfUniverStore?.setUniverCreateModeCache(univerCreateMode.value);
|
jnpfUniverStore?.setFloatEchartDataCaches(floatEcharts);
|
jnpfUniverStore?.setFloatImageDataCaches(floatImages);
|
|
// 把store的动态id传给底层
|
jnpfUniverAPI.value?.getSheetsFloatDom()?.savePiniaStoreId(dynamicJnpfUniverStoreId);
|
jnpfUniverAPI.value?.getSheetsFloatEchart()?.savePiniaStoreId(dynamicJnpfUniverStoreId);
|
jnpfUniverAPI.value?.getSheetsFloatImage()?.savePiniaStoreId(dynamicJnpfUniverStoreId);
|
|
setWorkbookPermission(isReadonly); // 设置报表权限
|
bindUniverLifeCycle(realWorkbookData, watermark); // 绑定生命周期
|
|
bindSelectionChange(isReadonly); // 绑定选区变更事件
|
bindBeforeCommandExecute(); // 绑定监听命令执行之前
|
bindAfterCommandExecuted(isReadonly); // 绑定监听命令执行之后
|
|
// 表结构发生了变化
|
jnpfUniverAPI.value?.addEvent(jnpfUniverAPI.value?.Event?.SheetSkeletonChanged, (params: any) => {
|
correctCellEchartSizeDebounce(params);
|
});
|
|
// 这个丢出去后,外层所有的地方都可以用univer的api了
|
return {
|
jnpfUniverAPI: jnpfUniverAPI.value,
|
};
|
}
|
|
// 设置unit权限
|
function setWorkbookPermission(isReadonly: boolean) {
|
if (univerCreateMode.value === 'design' && !isReadonly) {
|
return;
|
}
|
|
updateWorkbookPermission(false);
|
}
|
|
// 更新权限控制
|
function updateWorkbookPermission(state: boolean) {
|
const permission = jnpfUniverAPI.value?.getPermission();
|
|
permission?.setWorkbookPermissionPoint(activeWorkbookId.value, WorkbookEditablePermission, state);
|
permission?.setPermissionDialogVisible(state);
|
}
|
|
// 绑定univer的生命周期
|
function bindUniverLifeCycle(workbookData: IWorkbookData, watermarkInfo: any) {
|
if (!jnpfUniverAPI.value) {
|
return;
|
}
|
|
const univerHooks = jnpfUniverAPI.value?.getHooks();
|
const { config: watermarkConfig, show: showWatermark } = watermarkInfo ?? {};
|
|
jnpfUniverAPI.value?.addEvent(jnpfUniverAPI.value?.Event.LifeCycleChanged, (params: any) => {
|
const { stage } = params;
|
|
if (stage === 2) {
|
jnpfUniverAPI.value?.getSheetsFloatImage()?.cacheImages();
|
}
|
});
|
|
// univerHooks?.onStarting(() => {});
|
univerHooks?.onReady(() => {
|
jnpfUniverAPI.value?.deleteWatermark();
|
});
|
univerHooks?.onRendered(() => {
|
// 预览和有水印配置时才显示水印
|
if (showWatermark && univerCreateMode.value === 'preview') {
|
jnpfUniverAPI.value?.addWatermark('text', { ...watermarkConfig });
|
}
|
// 0.5.3版本开始初始的情况下,不会执行onSelectionChange事件
|
jnpfUniverAPI.value?.executeCommand(SetSelectionsOperation.id, {
|
selections: [
|
{
|
range: {
|
endColumn: 0,
|
endRow: 0,
|
rangeType: 0,
|
startColumn: 0,
|
startRow: 0,
|
},
|
},
|
],
|
subUnitId: activeWorksheetId.value,
|
type: 2,
|
unitId: activeWorkbookId.value,
|
});
|
});
|
univerHooks?.onSteady(() => {
|
/**
|
* 判断当前激活的工作表有没有图表,有图表的话loading层慢慢关一会儿
|
*/
|
jnpfUniverAPI.value?.getFormula()?.executeCalculation();
|
const { resources = [] } = workbookData ?? {};
|
const activeWorksheetHasFloatDomState = resources.some((resource: any) => {
|
if (resource?.name !== 'SHEET_DRAWING_PLUGIN') {
|
return false;
|
}
|
|
const parsedResourceData = JSON.parse(resource?.data || '{}');
|
const currentSheetResourceOption = parsedResourceData?.[activeWorksheetId.value];
|
|
return currentSheetResourceOption?.data && judgeSheetHasCustomFloatDom(currentSheetResourceOption.data);
|
});
|
if (activeWorksheetHasFloatDomState) {
|
setTimeout(() => {
|
loading.value = false;
|
}, 500);
|
} else {
|
loading.value = false;
|
}
|
});
|
}
|
|
// 绑定选区变更事件
|
function bindSelectionChange(isReadonly: boolean) {
|
if (univerCreateMode.value !== 'design' || isReadonly) {
|
state.selectionChangeMonitor = null;
|
return;
|
}
|
|
state.selectionChangeMonitor = activeWorkbook.value?.onSelectionChange((params: any) => {
|
if (!params?.length) {
|
return;
|
}
|
|
state.activeSelections = JSON.parse(JSON.stringify(params));
|
|
// 业务逻辑只选取第一选区的第一个单元格
|
const firstCell = params[0] ?? {};
|
const { startColumn, startRow } = firstCell;
|
const firstCellData = jnpfUniverAPI.value?.getSheetsCell()?.getCellData(startColumn, startRow) ?? {};
|
|
if (!isReadonly) {
|
if (openDialogCell.value) {
|
// 选择关联单元格操作
|
jnpfUniverStore?.setDialogSelectCellDataCache({
|
startColumn,
|
startRow,
|
});
|
} else {
|
// 暴露数据给业务层
|
emits('changeCell', {
|
cellData: JSON.parse(JSON.stringify(firstCellData)),
|
startColumn,
|
startRow,
|
});
|
}
|
}
|
});
|
}
|
|
// 绑定监听命令执行之前
|
function bindBeforeCommandExecute() {
|
// 等待废弃
|
// beforeCommandExecuteMonitor.value = jnpfUniverAPI.value?.onBeforeCommandExecute((_command: any) => {});
|
}
|
|
// 绑定监听命令执行之后
|
function bindAfterCommandExecuted(isReadonly: boolean) {
|
state.commandExecuteMonitor = jnpfUniverAPI.value?.onCommandExecuted((command: any) => {
|
const { id: commandId } = command ?? {};
|
|
// 切换工作本
|
if (activeWorkbook.value && commandId === 'sheet.operation.set-worksheet-active') {
|
state.activeWorksheet = activeWorkbook.value?.getActiveSheet();
|
state.activeWorksheetId = activeWorksheet.value?.getSheetId();
|
}
|
|
// 插入悬浮图表
|
if (commandId === JnpfCommandIds.insertedFloatEchart) {
|
onInsertedFloatEchart(jnpfUniverStore, command);
|
}
|
|
// 聚焦某个悬浮图表
|
if (commandId === JnpfCommandIds.focusFloatEchart) {
|
const { drawingId } = command?.params ?? {};
|
if (!drawingId) {
|
return;
|
}
|
|
const res = jnpfUniverStore?.getFloatEchartDataByDrawingId(drawingId);
|
if (!res) {
|
return;
|
}
|
|
const { echartType, option } = res ?? {};
|
emits('focusFloatEchart', { drawingId, echartType, option } as DeliverFloatEchartOptionProps);
|
} else {
|
jnpfUniverAPI.value?.getSheetsFloatEchart()?.clearFocusDrawingId();
|
}
|
|
// 插入悬浮图片
|
if (commandId === JnpfCommandIds.insertedFloatImage) {
|
onInsertedFloatImage(jnpfUniverStore, command);
|
}
|
|
// 聚焦图片
|
if (commandId === JnpfCommandIds.focusFloatImage) {
|
const { drawingId } = command?.params ?? {};
|
if (!drawingId) {
|
return;
|
}
|
|
const res = jnpfUniverStore?.getFloatImageDataByDrawingId(drawingId);
|
if (!res) {
|
return;
|
}
|
|
const { imageType, option } = res ?? {};
|
emits('focusFloatImage', { drawingId, imageType, option } as DeliverFloatImageOptionProps);
|
} else {
|
jnpfUniverAPI.value?.getSheetsFloatImage()?.clearFocusDrawingId();
|
}
|
|
// 设计预览
|
if (commandId === JnpfCommandIds.preview) {
|
emits('preview');
|
}
|
|
if (univerCreateMode.value === 'design' && !isReadonly) {
|
// 操作单元格合并
|
if (commandId === 'sheet.command.add-worksheet-merge') {
|
correctCellEchartSize(command.params?.selections);
|
}
|
|
// 取消单元格合并
|
if (commandId === 'sheet.mutation.remove-worksheet-merge') {
|
correctCellEchartSize(command.params?.ranges);
|
}
|
|
// 新增行
|
if (commandId === 'sheet.mutation.insert-row') {
|
handleInsertRowAndCol(command.params, 'row');
|
}
|
|
// 新增列
|
if (commandId === 'sheet.mutation.insert-col') {
|
handleInsertRowAndCol(command.params, 'col');
|
}
|
|
// 删除行
|
if (commandId === 'sheet.mutation.remove-rows') {
|
handleDeleteRowAndCol(command.params, 'row');
|
}
|
|
// 删除列
|
if (commandId === 'sheet.mutation.remove-col') {
|
handleDeleteRowAndCol(command.params, 'col');
|
}
|
|
// 移动行
|
if (commandId === 'sheet.mutation.move-rows') {
|
handleMoveRowAndCol(command.params, 'row');
|
}
|
|
// 移动列
|
if (commandId === 'sheet.mutation.move-columns') {
|
handleMoveRowAndCol(command.params, 'col');
|
}
|
|
// 移动单元格【包含剪切】
|
if (commandId === 'sheet.mutation.move-range') {
|
handleMoveCell(command.params);
|
}
|
|
// 清除单元格内容&全部
|
if (commandId === 'sheet.command.clear-selection-content' || commandId === 'sheet.command.clear-selection-all') {
|
handleClearCell();
|
}
|
}
|
});
|
}
|
|
// 暴露 - 获取设计的工作簿数据
|
function getDesignWorkbookData() {
|
const snapshot = activeWorkbook.value ? activeWorkbook.value?.save() : null;
|
if (!snapshot) {
|
console.warn('获取快照失败');
|
return;
|
}
|
|
const { floatEchartDataCaches = {}, floatImageDataCaches = {} } = jnpfUniverStore ?? {};
|
return arrangeDesignWorkbookData(snapshot, floatEchartDataCaches, floatImageDataCaches);
|
}
|
|
// 暴露 - 获取预览的工作簿数据
|
function getPreviewWorkbookData() {
|
const designData = getDesignWorkbookData();
|
|
const { floatEchartToUniverImgDataCaches = {}, floatImageDataCaches = {} } = jnpfUniverStore ?? {};
|
const floatImageToUniverImgDataCaches: any = {};
|
|
for (const dataKey in floatImageDataCaches) {
|
floatImageToUniverImgDataCaches[floatImageDataCaches[dataKey].domId] = floatImageDataCaches[dataKey].option.src;
|
}
|
|
return arrangePreviewWorkbookData(designData, floatEchartToUniverImgDataCaches, floatImageToUniverImgDataCaches);
|
}
|
|
// 暴露 - 更新悬浮图表配置
|
function updateFloatEchartConfig(config: DeliverFloatEchartOptionProps) {
|
const { drawingId, echartType, option } = config ?? {};
|
|
// 校验参数
|
if (!drawingId || !jnpfUniverAPI.value) {
|
return;
|
}
|
|
const originalFloatEchartData = jnpfUniverStore?.getFloatEchartDataByDrawingId(drawingId);
|
if (!originalFloatEchartData) {
|
return;
|
}
|
|
const updateFloatEchartData = {
|
...originalFloatEchartData,
|
echartType,
|
option,
|
};
|
|
const floatEchartDataCaches = jnpfUniverStore?.floatEchartDataCaches ?? {};
|
const updateFloatEchartsData = {
|
...floatEchartDataCaches,
|
[drawingId]: updateFloatEchartData,
|
};
|
|
jnpfUniverStore?.updateFocusedFloatEchartDataCache({
|
domId: originalFloatEchartData?.domId,
|
drawingId,
|
option,
|
});
|
jnpfUniverStore?.setFloatEchartDataCaches(updateFloatEchartsData);
|
}
|
|
// 暴露 - 更新悬浮图片配置
|
function updateFloatImageConfig(config: DeliverFloatImageOptionProps) {
|
const { drawingId, imageType, option } = config ?? {};
|
|
// 校验参数
|
if (!drawingId || !jnpfUniverAPI.value) {
|
return;
|
}
|
|
const originalFloatImageData = jnpfUniverStore?.getFloatImageDataByDrawingId(drawingId);
|
if (!originalFloatImageData) {
|
return;
|
}
|
|
const updateFloatImageData = {
|
...originalFloatImageData,
|
imageType,
|
option,
|
};
|
|
const floatImageDataCaches = jnpfUniverStore?.floatImageDataCaches ?? {};
|
const updateFloatImagesData = {
|
...floatImageDataCaches,
|
[drawingId]: updateFloatImageData,
|
};
|
|
jnpfUniverStore?.updateFocusedFloatImageDataCache({
|
domId: originalFloatImageData?.domId,
|
drawingId,
|
option,
|
});
|
jnpfUniverStore?.setFloatImageDataCaches(updateFloatImagesData);
|
}
|
|
// 暴露 - 更新单元格值【支持多个】
|
function updateCellsData(cellsData: DeliverCellDataProps[]) {
|
if (!cellsData?.length) {
|
return;
|
}
|
|
cellsData?.forEach((config: any) => {
|
const { cellData: configuringCellData = {}, startColumn, startRow } = config ?? {};
|
|
if (isNullOrUndefined(startColumn) || isNullOrUndefined(startRow)) {
|
return;
|
}
|
|
const oldCellData = jnpfUniverAPI.value?.getSheetsCell()?.getCellData(startColumn, startRow) ?? {};
|
|
const { custom = {}, v = '' } = configuringCellData;
|
const { type } = custom;
|
|
// 纯文本
|
if (!type || type === 'text') {
|
const newCellData = {
|
...oldCellData,
|
custom: {
|
...oldCellData?.custom,
|
...custom,
|
type,
|
},
|
v,
|
};
|
|
delete newCellData?.t;
|
delete newCellData?.custom?.type;
|
// delete newCellData?.custom?.fillDirection;
|
|
if (isEmptyObject(newCellData?.custom)) {
|
delete newCellData?.custom;
|
}
|
|
handleSetCellData({ newCellData, startColumn, startRow });
|
}
|
|
// 数据集
|
if (type === 'dataSource') {
|
const newCellData = {
|
...oldCellData,
|
custom: {
|
...oldCellData?.custom,
|
...custom,
|
type,
|
},
|
t: 1,
|
v: isNullOrUndefined(v) || v === '' ? '' : `\${${v}}`,
|
};
|
|
delete newCellData?.p;
|
|
handleSetCellData({ newCellData, startColumn, startRow });
|
}
|
|
// 参数
|
if (type === 'parameter') {
|
const newCellData = {
|
...oldCellData,
|
custom: {
|
...oldCellData?.custom,
|
...custom,
|
type,
|
},
|
t: 1,
|
v: isNullOrUndefined(v) || v === '' ? '' : `\#{${v}}`,
|
};
|
delete newCellData?.p;
|
|
handleSetCellData({ newCellData, startColumn, startRow });
|
}
|
|
// 单元格图表
|
if (type === 'chart') {
|
cellChartToImage(configuringCellData, startColumn, startRow);
|
}
|
|
// 单元格二维码(暂不支持非静态)
|
if (type === 'qrCode') {
|
// 获取单元格的宽高
|
const targetCellSize = jnpfUniverAPI.value?.getSheetsCell()?.getTargetCellSize(startColumn, startRow);
|
if (!targetCellSize) {
|
return;
|
}
|
|
const { cellHeight, cellWidth } = targetCellSize;
|
|
// 强制生成正方形 ---- 取长宽中较小的一个数据作为边长
|
const sideLength = Math.min(cellWidth, cellHeight);
|
if (sideLength <= 0) {
|
return;
|
}
|
|
const { type: codeType, ...codeConfigRest } = custom?.qrCodeOption ?? {};
|
|
if (codeType !== 'static') {
|
return;
|
}
|
|
QRCode?.toDataURL(
|
v,
|
{
|
height: sideLength,
|
width: sideLength,
|
...codeConfigRest,
|
},
|
(err, base64) => {
|
if (err) {
|
return;
|
}
|
|
base64ToFile(base64, 'image.jpeg', 'image/jpeg')
|
.then((file: File) => {
|
jnpfUniverAPI.value?.getSheetsCellImage()?.insertCellImage(file, startRow, startColumn, {
|
...configuringCellData,
|
custom: {
|
...configuringCellData.custom,
|
height: sideLength,
|
width: sideLength,
|
},
|
});
|
})
|
.catch((error: Error) => {
|
console.log(error);
|
});
|
},
|
);
|
}
|
|
// 单元格条形码(暂不支持非静态)
|
if (type === 'jsbarcode') {
|
if (v === '' || isNullOrUndefined(v)) {
|
return;
|
}
|
|
// 获取单元格的宽高
|
const targetCellSize = jnpfUniverAPI.value?.getSheetsCell()?.getTargetCellSize(startColumn, startRow);
|
if (!targetCellSize) {
|
return;
|
}
|
|
const { cellHeight, cellWidth } = targetCellSize;
|
if (cellWidth <= 0 || cellHeight <= 0) {
|
return;
|
}
|
|
const { type: codeType, ...codeConfigRest } = custom?.jsbarcodeOption ?? {};
|
|
if (codeType !== 'static') {
|
return;
|
}
|
|
// 创建一个临时的 canvas 元素
|
const canvas = document.createElement('canvas');
|
// 设置 canvas 的宽度和高度,确保条形码适配这个区域
|
canvas.width = cellWidth;
|
canvas.height = cellHeight;
|
|
// 使用 jsbarcode 生成条形码
|
JsBarcode(canvas, v, {
|
...codeConfigRest,
|
height: cellHeight,
|
});
|
const base64 = canvas.toDataURL();
|
|
// 销毁临时的 canvas 元素
|
canvas.width = 0;
|
canvas.height = 0;
|
canvas.remove();
|
|
base64ToFile(base64, 'image.jpeg', 'image/jpeg')
|
.then((file: File) => {
|
jnpfUniverAPI.value?.getSheetsCellImage()?.insertCellImage(file, startRow, startColumn, {
|
...configuringCellData,
|
custom: {
|
...configuringCellData.custom,
|
height: cellHeight,
|
width: cellWidth,
|
},
|
});
|
})
|
.catch((error: Error) => {
|
console.log(error);
|
});
|
}
|
});
|
}
|
|
// 设置单元格值
|
function handleSetCellData(config: any) {
|
const { newCellData: cellData, startColumn, startRow } = config ?? {};
|
jnpfUniverAPI.value?.getSheetsCell()?.setCellData(startColumn, startRow, cellData); // 设置值
|
|
// 更新视图
|
jnpfUniverAPI.value?.getSheetsCell()?.refreshRangeCellsView(activeWorksheet.value?.getRange(startRow, startColumn));
|
}
|
|
// 获取设计器容器Dom节点
|
function getDesignContainerEle() {
|
if (!containerEleId.value) {
|
return false;
|
}
|
|
return document.getElementById(containerEleId.value) || false;
|
}
|
|
// 暴露 - 打开选择单元格的弹窗窗口
|
function getCellFromDialogSelect(targetCall: any) {
|
const { startColumn, startRow } = targetCall ?? {};
|
if (dialogCellInstance.value || isNullOrUndefined(startRow) || isNullOrUndefined(startColumn)) {
|
return;
|
}
|
updateWorkbookPermission(false); // 开启只读权限
|
|
configDialogCellTarget.value = { ...targetCall }; // 记录配置中的单元格
|
state.openDialogCell = true; // 打开弹窗
|
|
state.dialogCellInstance = activeWorkbook.value?.openDialog({
|
id: `dialogSelectCell${dynamicJnpfUniverStoreId}`,
|
children: {
|
label: JnpfUniverDialogSelectCellKey,
|
value: dynamicJnpfUniverStoreId,
|
},
|
...DefaultDialogSelectCellConfig,
|
});
|
}
|
|
// 暴露 - 让聚焦中的单元格失焦(不失焦的话,最后编辑的单元格数据会缺失)
|
async function setCellEditVisible(): Promise<void> {
|
if (!jnpfUniverAPI.value) {
|
return;
|
}
|
|
// 命令层
|
jnpfUniverAPI.value?.executeCommand('sheet.operation.set-cell-edit-visible', {
|
_eventType: DeviceInputEventType.PointerUp,
|
visible: false,
|
});
|
|
return new Promise(resolve => {
|
setTimeout(() => {
|
resolve();
|
}, 200);
|
});
|
}
|
|
// 暴露 - 销毁工作簿
|
function handleDisposeUnit() {
|
const unitId = activeWorkbookId?.value; // 备份出来
|
|
if (unitId) {
|
try {
|
loading.value = true;
|
|
selectionChangeMonitor.value && selectionChangeMonitor.value?.dispose();
|
beforeCommandExecuteMonitor.value && beforeCommandExecuteMonitor.value?.dispose();
|
commandExecuteMonitor.value && commandExecuteMonitor.value?.dispose();
|
dialogCellInstance.value && dialogCellInstance.value?.dispose();
|
|
jnpfUniverAPI.value && jnpfUniverAPI.value?.disposeUnit(activeWorkbookId.value);
|
|
resetUniverState();
|
jnpfUniverStore?.resetStore();
|
|
loading.value = false;
|
console.log('工作簿已销毁');
|
} catch (error) {
|
console.warn(error);
|
}
|
}
|
}
|
|
// 暴露 - 获取动态的store
|
function getDynamicStore() {
|
return jnpfUniverStore ?? null;
|
}
|
|
// 暴露 - 获取工作簿id
|
function getActiveWorkbookId() {
|
return activeWorkbookId.value ?? null;
|
}
|
|
// 暴露 - 获取激活的工作本id
|
function getActiveWorksheetId() {
|
return activeWorksheetId.value ?? null;
|
}
|
|
// 暴露 - 获取默认的图表配置
|
function getDefaultFloatEchartOptions() {
|
return JSON.parse(JSON.stringify(DefaultFloatEchartOptions));
|
}
|
|
// 暴露 - 获取默认的图片配置
|
function getDefaultFloatImageOption() {
|
return JSON.parse(JSON.stringify(DefaultFloatImageOption));
|
}
|
|
// 暴露 - 获取默认的打印配置
|
function getPrintConfigs() {
|
return JSON.parse(
|
JSON.stringify({
|
defaultConfigForm: DefaultPrintConfig,
|
paperPaddingTypeOptions: jnpfPaperPaddingTypeOptions,
|
paperTypeOptions: jnpfPaperTypeOptions,
|
printAreaOptions: jnpfPrintAreaOptions,
|
printDirectionOptions: jnpfPrintDirectionOptions,
|
printHAlignOptions: jnpfPrintHAlignOptions,
|
printScaleOptions: jnpfPrintScaleOptions,
|
printVAlignOptions: jnpfPrintVAlignOptions,
|
}),
|
);
|
}
|
|
// 暴露 - 获取工作本的名称和id
|
function getSheetsInfo() {
|
if (!jnpfUniverAPI.value) {
|
return;
|
}
|
|
return jnpfUniverAPI.value?.getActiveWorkbook()?.save()?.sheets;
|
}
|
|
// 暴露 - 获取默认的水印配置
|
function getDefaultWatermarkConfig() {
|
return JSON.parse(JSON.stringify(DefaultWatermarkConfig));
|
}
|
|
// 暴露 - 选中工作簿
|
function setWorksheetActiveOperation(sheetId: string) {
|
if (!sheetId) {
|
return;
|
}
|
|
state.jnpfUniverAPI?.executeCommand(SetWorksheetActiveOperation.id, {
|
subUnitId: sheetId,
|
unitId: activeWorkbookId.value,
|
});
|
}
|
|
// 返回弹窗选中的单元格
|
function callbackDialogSelectCell() {
|
if (!dialogCellInstance.value) {
|
return;
|
}
|
|
dialogCellInstance.value && dialogCellInstance.value?.dispose(); // 销毁弹窗
|
dialogCellInstance.value = null;
|
|
const selectCellCache = JSON.parse(JSON.stringify(dialogSelectCellDataCache.value)); // 临时存起来,不然选区变化的时候会被同步修改
|
|
const { startColumn, startRow } = (configDialogCellTarget.value ?? {}) as any;
|
jnpfUniverAPI.value?.getSheetsRange()?.recoveryRange(startRow, startColumn);
|
configDialogCellTarget.value = null;
|
|
updateWorkbookPermission(true);
|
|
state.openDialogCell = false;
|
jnpfUniverStore?.setDialogSelectCellDataCache(null);
|
|
emits('changeDialogSelectCell', selectCellCache);
|
}
|
|
// 重置实例状态
|
function resetUniverState() {
|
state.univer = null;
|
state.jnpfUniverAPI = null;
|
|
state.containerEleId = null;
|
|
state.univerCreateMode = 'design';
|
|
state.activeWorkbook = null;
|
state.activeWorkbookId = null;
|
state.activeWorksheet = null;
|
state.activeWorksheetId = null;
|
|
state.selectionChangeMonitor = null;
|
state.activeSelections = [];
|
|
state.beforeCommandExecuteMonitor = null;
|
state.commandExecuteMonitor = null;
|
|
state.configDialogCellTarget = null;
|
|
state.openDialogCell = false;
|
state.dialogCellInstance = null;
|
|
state.loading = false;
|
}
|
|
// 处理插入行和列
|
function handleInsertRowAndCol(params: any, axis: 'col' | 'row') {
|
const { range } = params;
|
const { endColumn = 0, endRow = 0, startColumn = 0, startRow = 0 } = range ?? {};
|
const offset = axis === 'row' ? endRow - startRow + 1 : endColumn - startColumn + 1;
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
Object.entries(allCellData).forEach(([rowKey, rowData]: [string, any]) => {
|
Object.entries(rowData).forEach(([colKey, colData]: [string, any]) => {
|
if (
|
!colData ||
|
!colData.custom ||
|
isEmptyObject(colData.custom) ||
|
(colData.custom?.leftParentCellType !== 'custom' && colData.custom?.topParentCellType !== 'custom')
|
) {
|
return;
|
}
|
|
const updateCellData = {
|
...allCellData[rowKey][colKey],
|
custom: {
|
...getParentCellPosWhenInsert(range, axis, offset, colData.custom),
|
},
|
};
|
sheetsCellApi?.setCellData(colKey, rowKey, updateCellData);
|
});
|
});
|
}
|
|
// 处理删除行和列
|
function handleDeleteRowAndCol(params: any, axis: 'col' | 'row') {
|
const { range } = params;
|
const { endColumn = 0, endRow = 0, startColumn = 0, startRow = 0 } = range ?? {};
|
const offset = axis === 'row' ? endRow - startRow + 1 : endColumn - startColumn + 1;
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
Object.entries(allCellData).forEach(([rowKey, rowData]: [string, any]) => {
|
Object.entries(rowData).forEach(([colKey, colData]: [string, any]) => {
|
if (
|
!colData ||
|
!colData.custom ||
|
isEmptyObject(colData.custom) ||
|
(colData.custom?.leftParentCellType !== 'custom' && colData.custom?.topParentCellType !== 'custom')
|
) {
|
return;
|
}
|
|
const updateCellData = {
|
...allCellData[rowKey][colKey],
|
custom: {
|
...getParentCellPosWhenDelete(range, axis, offset, colData.custom),
|
},
|
};
|
sheetsCellApi?.setCellData(colKey, rowKey, updateCellData); // 设置值
|
});
|
});
|
}
|
|
// 处理移动行和列
|
function handleMoveRowAndCol(params: any, axis: 'col' | 'row') {
|
const { sourceRange, targetRange } = params;
|
|
const isRow = axis === 'row';
|
const startKey = isRow ? 'startRow' : 'startColumn';
|
const endKey = isRow ? 'endRow' : 'endColumn';
|
const offset =
|
targetRange[startKey] > sourceRange[startKey]
|
? targetRange[startKey] - sourceRange[startKey] - (sourceRange[endKey] - sourceRange[startKey] + 1)
|
: targetRange[startKey] < sourceRange[startKey]
|
? targetRange[startKey] - sourceRange[startKey]
|
: 0;
|
|
const involved = axis === 'row' ? sourceRange.endRow - sourceRange.startRow + 1 : sourceRange.endColumn - sourceRange.startColumn + 1;
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
Object.entries(allCellData).forEach(([rowKey, rowData]: [string, any]) => {
|
Object.entries(rowData).forEach(([colKey, colData]: [string, any]) => {
|
if (
|
!colData ||
|
!colData.custom ||
|
isEmptyObject(colData.custom) ||
|
(colData.custom?.leftParentCellType !== 'custom' && colData.custom?.topParentCellType !== 'custom')
|
) {
|
return;
|
}
|
|
const updateCellData = {
|
...allCellData[rowKey][colKey],
|
custom: {
|
...getParentCellPosWhenMove(sourceRange, targetRange, axis, offset, involved, colData.custom),
|
},
|
};
|
sheetsCellApi?.setCellData(colKey, rowKey, updateCellData); // 设置值
|
});
|
});
|
}
|
|
// 处理移动单元格
|
function handleMoveCell(params: any) {
|
const { fromRange, toRange } = params ?? {};
|
|
const isChangeRow = fromRange.startRow !== toRange.startRow; // 是否改变了纵向
|
const isChangeCol = fromRange.startColumn !== toRange.startColumn; // 是否改变了横向
|
|
const offsetRow = isChangeRow ? toRange.startRow - fromRange.startRow : 0; // 纵向偏移量
|
const offsetCol = isChangeCol ? toRange.startColumn - fromRange.startColumn : 0; // 横向偏移量
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
Object.entries(allCellData).forEach(([rowKey, rowData]: [string, any]) => {
|
Object.entries(rowData).forEach(([colKey, colData]: [string, any]) => {
|
if (
|
!colData ||
|
!colData.custom ||
|
isEmptyObject(colData.custom) ||
|
(colData.custom?.leftParentCellType !== 'custom' && colData.custom?.topParentCellType !== 'custom')
|
) {
|
return;
|
}
|
|
const updateCellData = {
|
...allCellData[rowKey][colKey],
|
custom: {
|
...getParentCellPosWhenMoveCell(
|
fromRange,
|
{
|
offsetCol,
|
offsetRow,
|
},
|
colData.custom,
|
),
|
},
|
};
|
sheetsCellApi?.setCellData(colKey, rowKey, updateCellData);
|
});
|
});
|
}
|
|
// 清除单元格内容和全部
|
function handleClearCell() {
|
const ranges = JSON.parse(JSON.stringify(activeSelections.value));
|
if (!ranges.length) {
|
return;
|
}
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
Object.entries(allCellData).forEach(([rowKey, rowData]: [string, any]) => {
|
Object.entries(rowData).forEach(([colKey, colData]: [string, any]) => {
|
if (
|
!colData ||
|
!colData.custom ||
|
isEmptyObject(colData.custom) ||
|
(colData.custom?.leftParentCellType !== 'custom' && colData.custom?.topParentCellType !== 'custom')
|
) {
|
return;
|
}
|
|
const updateCellData = {
|
...allCellData[rowKey][colKey],
|
custom: {
|
...getParentCellPosWhenClearCell(ranges, colData.custom),
|
},
|
};
|
sheetsCellApi?.setCellData(colKey, rowKey, updateCellData); // 设置值
|
});
|
});
|
}
|
|
// 设置水印
|
function setWatermark(config: ITextWatermarkConfig) {
|
if (!jnpfUniverAPI.value) {
|
return;
|
}
|
|
try {
|
jnpfUniverAPI.value?.addWatermark('text', config);
|
} catch (error) {
|
console.error(error);
|
}
|
}
|
|
// 清除水印
|
function clearWatermark() {
|
if (!jnpfUniverAPI.value) {
|
return;
|
}
|
|
try {
|
jnpfUniverAPI.value?.deleteWatermark();
|
} catch (error) {
|
console.error(error);
|
}
|
}
|
|
// 纠正单元格图表尺寸
|
function correctCellEchartSize(ranges: any) {
|
if (!ranges) {
|
return;
|
}
|
|
const rangeArr: number[][] = [];
|
(ranges ?? []).forEach((range: any) => {
|
for (let row = range.startRow; row <= range.endRow; row++) {
|
for (let col = range.startColumn; col <= range.endColumn; col++) {
|
rangeArr.push([row, col]);
|
}
|
}
|
});
|
const uniqueArr = [...new Set(rangeArr.map(item => JSON.stringify(item)))].map(item => JSON.parse(item));
|
|
const sheetsCellApi = jnpfUniverAPI.value?.getSheetsCell();
|
const allCellData = JSON.parse(JSON.stringify(sheetsCellApi?.getAllCellData())) ?? {};
|
|
uniqueArr.forEach(([rowKey, colKey]: [number, number]) => {
|
const cellData = allCellData?.[rowKey]?.[colKey];
|
if (!cellData) {
|
return;
|
}
|
|
const { custom } = cellData ?? {};
|
if (!custom) {
|
return;
|
}
|
const { type } = custom ?? {};
|
|
if (type !== 'chart') {
|
return;
|
}
|
|
cellChartToImage(cellData, colKey, rowKey);
|
});
|
}
|
|
// 单元图表转成图片
|
function cellChartToImage(cellData: any, startColumn: number, startRow: number) {
|
// 获取单元格的宽高
|
const targetCellSize = jnpfUniverAPI.value?.getSheetsCell()?.getTargetCellSize(startColumn, startRow);
|
if (!targetCellSize) {
|
return;
|
}
|
|
const { cellHeight, cellWidth } = targetCellSize;
|
if (cellWidth <= 0 || cellHeight <= 0) {
|
return;
|
}
|
|
const { custom } = cellData ?? {};
|
|
// 得到了echart的图片
|
const echartImg = unref(jnpfUniverCellEchartRef).render(custom, cellWidth, cellHeight);
|
|
// base64转成文件流后去插入图片
|
base64ToFile(echartImg, 'image.jpeg', 'image/jpeg')
|
.then((file: File) => {
|
jnpfUniverAPI.value?.getSheetsCellImage()?.insertCellImage(file, startRow, startColumn, {
|
...cellData,
|
custom: {
|
...cellData.custom,
|
height: cellHeight,
|
width: cellWidth,
|
},
|
});
|
})
|
.catch((error: Error) => {
|
console.log(error);
|
});
|
}
|
|
// 处理纠正单元格图表尺寸,带3000ms 防抖
|
const correctCellEchartSizeDebounce = debounce((params: any) => {
|
correctCellEchartSize(params?.payload?.params?.ranges);
|
}, 300);
|
|
watch(
|
() => dialogSelectCellStateCache.value,
|
() => {
|
callbackDialogSelectCell();
|
},
|
);
|
|
defineExpose({
|
clearWatermark,
|
getActiveWorkbookId,
|
getActiveWorksheetId,
|
getCellFromDialogSelect,
|
getDefaultFloatEchartOptions,
|
getDefaultFloatImageOption,
|
getDefaultWatermarkConfig,
|
getDesignWorkbookData,
|
getDynamicStore,
|
getPreviewWorkbookData,
|
getPrintConfigs,
|
getSheetsInfo,
|
handleCreateDesignUnit,
|
handleDisposeUnit,
|
setCellEditVisible,
|
setWatermark,
|
setWorksheetActiveOperation,
|
updateCellsData,
|
updateFloatEchartConfig,
|
updateFloatImageConfig,
|
});
|
</script>
|
|
<template>
|
<div class="jnpf-univer-design-content" v-loading="loading">
|
<div :id="containerEleId" class="univer-design-container"></div>
|
</div>
|
<div id="cellEchartsContent" class="cell-echarts-content">
|
<JnpfUniverCellEchart ref="jnpfUniverCellEchartRef" :univer-create-mode="univerCreateMode" />
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.jnpf-univer-design-content {
|
position: relative;
|
flex: 1;
|
height: 100%;
|
overflow: hidden auto;
|
|
.univer-design-container {
|
width: 100%;
|
height: calc(100%);
|
}
|
}
|
|
.cell-echarts-content {
|
position: absolute;
|
inset: 0;
|
z-index: -1;
|
}
|
</style>
|
|
<style lang="scss">
|
.univer-pointer-events-auto.univer-fixed {
|
z-index: 1000 !important;
|
}
|
</style>
|