feat: integrate luckysheet inline and fullscreen
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// 封装用户请求axios
|
||||
import axios, { AxiosRequestConfig } from "axios";
|
||||
import { isDev } from "../utils";
|
||||
|
||||
export const fetch = (options: AxiosRequestConfig) => {
|
||||
return axios({
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
axios.defaults.baseURL = isDev() ? "/api" : "";
|
||||
|
||||
// 添加请求拦截器
|
||||
axios.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前进行操作
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 对请求错误进行操作
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 添加响应拦截器
|
||||
axios.interceptors.response.use(
|
||||
function (res) {
|
||||
// 解构返回
|
||||
return res;
|
||||
},
|
||||
function (error) {
|
||||
// 对响应错误进行操作
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
import { fetch } from "./core";
|
||||
|
||||
// 导出初始化工作簿 API
|
||||
export const API_getWorkerBook = (gridKey: string) => {
|
||||
return fetch({
|
||||
url: "/getWorkerBook",
|
||||
method: "post",
|
||||
data: { gridKey },
|
||||
});
|
||||
};
|
||||
|
||||
// 导出图片上传API
|
||||
export const API_uploadImage = (data: FormData) => {
|
||||
return fetch({
|
||||
url: "/uploadImage",
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
// 导出后台服务地址
|
||||
export const SERVER_URL = "http://localhost:9000";
|
||||
|
||||
// 导出协同服务地址
|
||||
export const WS_SERVER_URL = "ws://127.0.0.1:9000";
|
||||
|
||||
// 协同服务初始化失败时,提供的默认初始化数据
|
||||
export const defaultSheetData = [
|
||||
{
|
||||
name: "Sheet1",
|
||||
celldata: [
|
||||
{
|
||||
r: 0,
|
||||
c: 0,
|
||||
v: {
|
||||
v: "协同服务不可用,当前为普通模式",
|
||||
bg: "#ff0000",
|
||||
fc: "#ffffff",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @author https://gitee.com/wfeng0/luckysheet-crdt
|
||||
* @description Luckysheet CRDT 协同全功能实现 - Web App
|
||||
* @license Apache 2.0
|
||||
* @copyright Copyright (c) 2025 https://gitee.com/wfeng0/luckysheet-crdt
|
||||
* @time 2024年12月05日
|
||||
*/
|
||||
|
||||
import "./style/index.css";
|
||||
import { API_getWorkerBook } from "./axios";
|
||||
import { defaultSheetData, WS_SERVER_URL } from "./config";
|
||||
import { uploadImage, imageUrlHandle, getRandom, getLoadUrl, registerPlugins } from "./utils";
|
||||
|
||||
window.onload = initLuckysheet;
|
||||
|
||||
const luckysheet = Reflect.get(window, "luckysheet");
|
||||
|
||||
/**
|
||||
* 需要监听刷新、退出浏览器事件,关闭socket 连接,避免协同异常
|
||||
*/
|
||||
window.onbeforeunload = () => luckysheet && luckysheet.closeWebSocket();
|
||||
|
||||
/**
|
||||
* 初始化前台 Luckysheet
|
||||
* 请注意,目前前台仅为展示,并无其他能力,因此加载的是默认协同演示 worker books 数据,gridkey = gridkey_demo
|
||||
* 常理来说,当前工作簿的数据,都应该通过 fileid (gridkey) 请求得来
|
||||
*/
|
||||
async function initLuckysheet() {
|
||||
const id = getRandom();
|
||||
const username = encodeURIComponent(`用户_${id}`);
|
||||
const gridKey = "gridkey_demo"; // 请注意大小写哈~
|
||||
|
||||
const options = {
|
||||
lang: "zh",
|
||||
title: "Luckysheet",
|
||||
container: "luckysheetContainer",
|
||||
// showinfobar: false, // 隐藏顶部的信息栏
|
||||
// showlogo: false, // 隐藏顶部的 logo
|
||||
allowUpdate: false, // 配置协同功能
|
||||
loadUrl: "",
|
||||
updateUrl: "", // 协同服务转发服务
|
||||
plugins: registerPlugins(),
|
||||
menuHandler: {
|
||||
customs: [
|
||||
{
|
||||
label: "测试",
|
||||
value: "demo",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// 是否开启协同模式
|
||||
const isCollaboration = true;
|
||||
if (!isCollaboration) return luckysheet.create(options);
|
||||
|
||||
try {
|
||||
// 根据 gridkey 请求当前 workerbook 数据
|
||||
const { data } = await API_getWorkerBook(gridKey);
|
||||
|
||||
// 定义请求是否成功
|
||||
const isSuccess = data.code === 200;
|
||||
|
||||
/**
|
||||
* 兼容无数据库服务场景
|
||||
* 1. 如果请求成功,则使用数据库配置的 workerbook 数据
|
||||
* 2. 如果请求失败,则使用默认配置的 workerbook 数据
|
||||
*/
|
||||
options.lang = isSuccess ? data.data.lang : "zh";
|
||||
options.title = isSuccess ? data.data.title : "未命名工作簿";
|
||||
|
||||
// 协同场景下,才进行图片优化
|
||||
Reflect.set(options, "uploadImage", uploadImage);
|
||||
Reflect.set(options, "imageUrlHandle", imageUrlHandle);
|
||||
|
||||
options.allowUpdate = true;
|
||||
options.loadUrl = getLoadUrl(gridKey);
|
||||
options.updateUrl = `${WS_SERVER_URL}?type=luckysheet&userid=${id}&username=${username}&gridkey=${gridKey}`;
|
||||
luckysheet.create(options);
|
||||
} catch (error) {
|
||||
console.error("==> 协同服务异常", error);
|
||||
// 不然初始化普通模式,避免页面空白
|
||||
Reflect.set(options, "data", defaultSheetData);
|
||||
luckysheet.create(options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app,
|
||||
.luckysheetContainer {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
iframe {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.left {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { SERVER_URL } from "../config";
|
||||
import { API_uploadImage } from "../axios";
|
||||
|
||||
// 处理协同图片上传
|
||||
export const uploadImage = async (file: File) => {
|
||||
// 此处拿到的是上传的 file 对象,进行文件上传 ,配合 node 接口实现
|
||||
const formData = new FormData();
|
||||
formData.append("image", file);
|
||||
|
||||
const { data } = await API_uploadImage(formData);
|
||||
|
||||
// *** 关键步骤:需要返回一个地址给 luckysheet ,用于显示图片
|
||||
if (data.code === 200) return Promise.resolve(data.url);
|
||||
else return Promise.resolve("image upload error");
|
||||
};
|
||||
|
||||
// 处理上传图片的地址
|
||||
export const imageUrlHandle = (url: string) => {
|
||||
// 已经是 // http data 开头则不处理
|
||||
if (/^(?:\/\/|(?:http|https|data):)/i.test(url)) return url;
|
||||
// 不然拼接服务器路径
|
||||
return SERVER_URL + url;
|
||||
};
|
||||
|
||||
// 获取随机值
|
||||
export const getRandom = () => {
|
||||
return Math.random().toString(16).slice(2, 8);
|
||||
};
|
||||
|
||||
// 获取当前环境是否为 开发环境
|
||||
export const isDev = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return import.meta.env.MODE === "development";
|
||||
};
|
||||
|
||||
// 获取 loadUrl 地址
|
||||
export const getLoadUrl = (gridKey: string) => {
|
||||
return `${isDev() ? "/api/" : "/"}loadSheetData?gridkey=${gridKey}`;
|
||||
};
|
||||
|
||||
// 注册插件
|
||||
export const registerPlugins = () => {
|
||||
return [
|
||||
{
|
||||
name: "chart",
|
||||
dependScripts: [
|
||||
"/lib/expendPlugins/libs/vue@2.6.11.min.js",
|
||||
"/lib/expendPlugins/libs/vuex.min.js",
|
||||
"/lib/expendPlugins/libs/elementui.min.js",
|
||||
"/lib/expendPlugins/libs/echarts.min.js",
|
||||
"/lib/expendPlugins/libs/chartmix.umd.min.js",
|
||||
],
|
||||
dependLinks: ["/lib/expendPlugins/libs/element-ui.css", "/lib/expendPlugins/libs/chartmix.css"],
|
||||
},
|
||||
{
|
||||
name: "vchart",
|
||||
dependScripts: ["/lib/expendPlugins/libs/vchart.min.js"],
|
||||
dependLinks: ["/lib/expendPlugins/libs/vchart.css"],
|
||||
},
|
||||
{
|
||||
name: "fileImport",
|
||||
dependScripts: ["/lib/expendPlugins/libs/luckyexcel.umd.js"],
|
||||
},
|
||||
{
|
||||
name: "fileExport",
|
||||
dependScripts: ["/lib/expendPlugins/libs/exceljs.min.js", "/lib/expendPlugins/libs/fileSaver.min.js"],
|
||||
},
|
||||
];
|
||||
};
|
||||
Reference in New Issue
Block a user