commonsy
v0.1.2
Published
publcCommon
Readme
commonsy
前后端通用 TypeScript 工具库,包含通用基础、日期时间、金额货币、表单校验、浏览器判断、文件图片、下载链接、加密、WebSocket、服务端、Cesium 地图等工具。源码使用 TypeScript 编写,发布时输出 JavaScript 与 .d.ts 类型声明。
安装
npm install commonsy引用方式
默认入口
import sysFun from 'commonsy';
sysFun.CommonUtils.isEmpty({});
new sysFun.DateUtils.DateTimeFormatter('2022-10-10 11:11:10', 'yyyy-mm-dd').getFormattedDateTime();
new sysFun.MoneyUtils.ComputeMoney(100).add(50).toDollars();分类子路径入口
import CommonUtils from 'commonsy/common';
import DateUtils from 'commonsy/date';
import MoneyUtils from 'commonsy/money';
import WebSocketUtils from 'commonsy/websocket';
import ServerUtils from 'commonsy/server';旧版直达入口
import sysFun from 'commonsy';
new sysFun.DateTimeFormatter('2022-10-10 11:11:10', 'yyyy/mm/dd').getFormattedDateTime();
new sysFun.ComputeMoney(100).add(50).toDollars();目录结构
commonsy
├── index.ts # TypeScript 统一入口
├── dist # 构建后的 JavaScript 与类型声明
├── publicFun
│ ├── common # 通用基础工具
│ ├── date # 日期时间工具
│ ├── money # 金额货币工具
│ ├── validate # 表单校验工具
│ ├── browser # 浏览器判断工具
│ ├── file # 文件图片工具
│ └── download # 下载链接工具
├── encryption # 加密工具
├── webSocket # WebSocket 工具
├── server # 项目启动入口、HTTP 服务、SQL、Redis 工具
├── cesium # Cesium 地图工具
└── test # 测试子路径导出
| 导入路径 | 对应分类 |
| --- | --- |
| commonsy | 全量默认入口 |
| commonsy/common | 通用基础工具 |
| commonsy/date | 日期时间工具 |
| commonsy/money | 金额货币工具 |
| commonsy/validate | 表单校验工具 |
| commonsy/browser | 浏览器判断工具 |
| commonsy/file | 文件图片工具 |
| commonsy/download | 下载链接工具 |
| commonsy/crypto | 加密工具 |
| commonsy/websocket | WebSocket 工具 |
| commonsy/server | 服务端工具,包含项目启动入口、HTTP 服务、SQL、Redis |
| commonsy/map | Cesium 地图工具 |
工具总览
| 分类 | 默认入口名称 | 工具 |
| --- | --- | --- |
| 通用基础 | CommonUtils | isEmpty、deepClone、deepMerge、debounce、throttle、listToTree、treeToList、safeJsonParse、formatFileSize、maskPhone、maskEmail、maskBankCard |
| 类型判断 | TypeUtils | isEmpty |
| 对象处理 | ObjectUtils | deepClone、deepMerge |
| 函数控制 | FunctionUtils | debounce、throttle |
| 树结构 | TreeUtils | listToTree、treeToList |
| JSON | JsonUtils | safeJsonParse |
| 文件格式 | FileUtils | formatFileSize |
| 隐私脱敏 | MaskUtils | maskPhone、maskEmail、maskBankCard |
| 日期时间 | DateUtils | DateTimeFormatter、CountdownTimer |
| 金额货币 | MoneyUtils | BankNumber、ComputeMoney |
| 表单校验 | ValidateUtils | FormValidation |
| 浏览器 | BrowserUtils | GetBrowserType |
| 文件图片 | FileTools | CompressImage、formatFileSize |
| 下载链接 | DownloadUtils | XunLeiDownloadUrl |
| 加密 | CryptoUtils | Encryption |
| WebSocket | WebSocketUtils | WebSocketServer、WebSocketClient |
| 服务端 | ServerUtils | createServerApp、startServerApp、loadConfig、createRouter、composeMiddlewares、createErrorHandler、createLogger、sendSuccess、getPagination、validateRequest、signJwt、securityHeaders、staticMiddleware、uploadMiddleware、createTaskManager、createHealthChecker、createCache、createUuid、getProcessInfo、startHttpServer、queryRows、createRedisClient |
| 地图 | MapUtils | CesiumWrapper |
服务端工具
服务端工具用于组织 Node 项目的基础设施,适合放在业务项目的 server.js、app.js、main.js 中使用。它可以把配置、路由、中间件、统一响应、统一错误、日志、鉴权、安全、静态资源、上传、后台任务、健康检查、缓存、数据库连接、Redis 连接、HTTP 服务启动和退出清理统一管理。
服务端工具默认不强制安装数据库和 Redis 客户端。只有调用 SQL 或 Redis 方法时,才需要在业务项目中安装对应依赖:
npm install mysql2 redis项目启动入口
最常用的写法是通过 startServerApp 创建项目入口,在 startup 中按顺序初始化资源,在 shutdown 中释放资源。
import ServerUtils from 'commonsy/server';
const app = await ServerUtils.startServerApp({
name: 'demo-api',
config: {
port: 3000,
},
startup: [
{
name: 'start-http',
run: async ({ config }) => {
const httpApp = await ServerUtils.startHttpServer({
port: config.port,
routes: [
{
method: 'GET',
path: '/health',
handler: ({ response, sendJson }) => {
sendJson(response, { ok: true });
},
},
],
});
return { httpApp };
},
},
],
shutdown: [
{
name: 'close-http',
run: async ({ httpApp }) => {
await ServerUtils.closeHttpServer(httpApp.server);
},
},
],
});
ServerUtils.bindGracefulShutdown(app);
console.log(app.context.httpApp.url);完整后端入口示例
下面示例展示一个项目入口如何同时启动 MySQL、Redis 和 HTTP 服务,并组合路由、中间件、日志和统一错误处理:
import ServerUtils from 'commonsy/server';
const logger = ServerUtils.createLogger({
name: 'demo-api',
level: 'info',
});
const config = ServerUtils.loadConfig({
defaults: {
port: 3000,
},
envMap: {
port: {
env: 'PORT',
parse: Number,
defaultValue: 3000,
},
'mysql.host': {
env: 'MYSQL_HOST',
defaultValue: 'localhost',
},
'mysql.user': {
env: 'MYSQL_USER',
defaultValue: 'root',
},
'mysql.password': {
env: 'MYSQL_PASSWORD',
defaultValue: 'password',
},
'mysql.database': {
env: 'MYSQL_DATABASE',
defaultValue: 'demo',
},
'redis.url': {
env: 'REDIS_URL',
defaultValue: 'redis://localhost:6379',
},
},
required: ['mysql.host', 'mysql.database', 'redis.url'],
});
const router = ServerUtils.createRouter();
router.get('/health', ({ response, sendJson }) => {
sendJson(response, { ok: true });
});
router.get('/users/:id', async ({ params, response, sendJson }) => {
const users = await ServerUtils.queryRows('select * from users where id = ?', [params.id]);
sendJson(response, { data: users[0] || null });
});
const app = await ServerUtils.startServerApp({
name: 'demo-api',
config,
logger,
startup: [
{
name: 'connect-mysql',
run: async ({ config }) => {
const mysqlPool = await ServerUtils.createMysqlPool(config.mysql);
return { mysqlPool };
},
},
{
name: 'connect-redis',
run: async ({ config }) => {
const redisClient = await ServerUtils.createRedisClient(config.redis);
return { redisClient };
},
},
{
name: 'start-http',
run: async ({ config }) => {
const httpApp = await ServerUtils.startHttpServer({
port: config.port,
routes: router.routes,
middlewares: [
ServerUtils.corsMiddleware(),
ServerUtils.requestLogger(logger),
],
errorHandler: ServerUtils.createErrorHandler(),
});
return { httpApp };
},
},
],
shutdown: [
{
name: 'close-http',
run: async ({ httpApp }) => {
await ServerUtils.closeHttpServer(httpApp.server);
},
},
{
name: 'close-redis',
run: async ({ redisClient }) => {
await ServerUtils.closeRedis(redisClient);
},
},
{
name: 'close-mysql',
run: async ({ mysqlPool }) => {
await ServerUtils.closeMysqlPool(mysqlPool);
},
},
],
});
ServerUtils.bindGracefulShutdown(app);
console.log(`服务已启动:${app.context.httpApp.url}`);基础设施工具分类
| 工具对象 | 说明 |
| --- | --- |
| AppStarter | 项目启动入口、启动步骤、关闭步骤、优雅退出 |
| ConfigUtils | 配置合并、环境变量映射、必填配置校验 |
| ResponseUtils | 成功响应、失败响应、分页响应和常用响应写出 |
| RequestUtils | query、header、客户端 IP、分页参数解析 |
| ServerValidateUtils | body、query、params 的服务端参数校验 |
| AuthUtils | Bearer Token 解析、HS256 JWT 签发验证、鉴权中间件 |
| SecurityUtils | 安全响应头、基础限流、请求体大小限制 |
| RouteUtils | 轻量路由、路径参数、请求匹配 |
| MiddlewareUtils | 中间件组合、CORS 中间件 |
| ErrorUtils | HTTP 错误对象、统一错误响应 |
| LoggerUtils | 轻量日志器、请求日志中间件 |
| StaticUtils | 静态文件服务、MIME 类型识别、安全路径解析 |
| UploadUtils | 文件名清理、轻量 multipart 解析、上传中间件 |
| TaskUtils | 后台定时任务注册、启动和停止 |
| HealthUtils | 健康检查器和健康检查路由 |
| CacheUtils | Redis JSON 缓存、remember 缓存回填 |
| IdUtils | UUID、随机 ID、请求 ID 中间件 |
| ProcessUtils | 进程信息、sleep、异步超时控制 |
| HttpServerUtils | Node 原生 HTTP/HTTPS 服务启动和关闭 |
| SqlUtils | MySQL 连接池、查询、事务 |
| RedisUtils | Redis 连接、读写、删除 |
分步注册启动入口
如果不想一次性传入 startup 和 shutdown,也可以使用 createServerApp 后再逐步注册:
import ServerUtils from 'commonsy/server';
const app = ServerUtils.createServerApp({
name: 'demo-api',
config: {
port: 3000,
},
});
app
.use({
name: 'start-http',
run: async ({ config }) => {
const httpApp = await ServerUtils.startHttpServer({
port: config.port,
routes: [],
});
return { httpApp };
},
})
.onShutdown({
name: 'close-http',
run: async ({ httpApp }) => {
await ServerUtils.closeHttpServer(httpApp.server);
},
});
await app.start();
ServerUtils.bindGracefulShutdown(app);启动入口 API
| 方法 | 说明 |
| --- | --- |
| createServerApp(options) | 创建项目启动入口,不会立即执行启动步骤 |
| startServerApp(options) | 创建项目启动入口并立即执行 startup |
| bindGracefulShutdown(app, options) | 绑定 SIGINT、SIGTERM、未捕获异常和未处理 Promise 异常,触发时执行 app.stop() |
| app.use(step) | 追加启动步骤 |
| app.onShutdown(step) | 追加关闭步骤 |
| app.start() | 按注册顺序执行启动步骤 |
| app.stop() | 按关闭步骤的反向顺序释放资源 |
startup 中每个步骤可以返回对象,返回字段会合并到 app.context,供后续步骤和关闭步骤复用。
路由、中间件和错误处理
import ServerUtils from 'commonsy/server';
const router = ServerUtils.createRouter();
router.get('/users/:id', async (context) => {
ServerUtils.sendSuccess(context, { id: context.params.id });
}, {
middlewares: [
ServerUtils.validateRequest({
params: {
id: {
required: true,
pattern: /^\d+$/,
},
},
}),
],
});
await ServerUtils.startHttpServer({
port: 3000,
routes: router.routes,
middlewares: [
ServerUtils.requestIdMiddleware(),
ServerUtils.securityHeaders(),
ServerUtils.corsMiddleware(),
],
errorHandler: ServerUtils.createErrorHandler(),
});配置工具
import ServerUtils from 'commonsy/server';
const config = ServerUtils.loadConfig({
defaults: {
port: 3000,
},
envMap: {
port: {
env: 'PORT',
parse: Number,
defaultValue: 3000,
},
'mysql.host': 'MYSQL_HOST',
},
overrides: {
port: 4000,
},
required: ['mysql.host'],
});
console.log(config.port);鉴权工具
import ServerUtils from 'commonsy/server';
const token = ServerUtils.signJwt(
{
userId: 1,
role: 'admin',
},
'secret',
{
expiresIn: 3600,
}
);
const user = ServerUtils.verifyJwt(token, 'secret');
console.log(user.userId);路由中可以使用鉴权中间件:
router.get('/profile', (context) => {
ServerUtils.sendSuccess(context, context.user);
}, {
middlewares: [
ServerUtils.authMiddleware({
secret: 'secret',
}),
],
});健康检查和缓存
import ServerUtils from 'commonsy/server';
const health = ServerUtils.createHealthChecker()
.add('mysql', async () => {
await ServerUtils.queryRows('select 1');
return true;
})
.add('redis', async () => {
return redisClient.isOpen;
});
const cache = ServerUtils.createCache(redisClient, {
prefix: 'demo:',
defaultTtlSeconds: 300,
});
router.get('/health', ServerUtils.healthRoute(health));
router.get('/users/:id', async (context) => {
const user = await cache.remember(`user:${context.params.id}`, 60, async () => {
const rows = await ServerUtils.queryRows('select * from users where id = ?', [context.params.id]);
return rows[0] || null;
});
ServerUtils.sendSuccess(context, user);
});静态文件、上传和任务
import ServerUtils from 'commonsy/server';
const tasks = ServerUtils.createTaskManager();
tasks.interval('clear-cache', async () => {
console.log('clear cache');
}, 60 * 1000);
tasks.start();
await ServerUtils.startHttpServer({
port: 3000,
middlewares: [
ServerUtils.staticMiddleware({
rootDir: './public',
prefix: '/static',
}),
],
routes: [
{
method: 'POST',
path: '/upload',
middlewares: [
ServerUtils.uploadMiddleware({
maxBytes: 10 * 1024 * 1024,
}),
],
handler: (context) => {
ServerUtils.sendSuccess(context, {
files: context.upload.files.map((file) => ({
filename: file.filename,
size: file.size,
})),
});
},
},
],
});启动 HTTP 服务
import ServerUtils from 'commonsy/server';
const app = await ServerUtils.startHttpServer({
port: 3000,
routes: [
{
method: 'GET',
path: '/health',
handler: ({ response, sendJson }) => {
sendJson(response, { ok: true });
},
},
],
});
console.log(app.url); // http://localhost:3000查询 SQL
import ServerUtils from 'commonsy/server';
await ServerUtils.createMysqlPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'demo',
});
const users = await ServerUtils.queryRows('select * from users where status = ?', [1]);
console.log(users);连接 Redis
import ServerUtils from 'commonsy/server';
await ServerUtils.createRedisClient({
url: 'redis://localhost:6379',
});
await ServerUtils.redisSet('token:user:1', 'abc', { ttlSeconds: 3600 });
const token = await ServerUtils.redisGet('token:user:1');
console.log(token);通用基础工具
isEmpty
判断值是否为空。支持 null、undefined、空字符串、空数组、空对象、空 Map、空 Set。
import CommonUtils from 'commonsy/common';
CommonUtils.isEmpty(null); // true
CommonUtils.isEmpty(' '); // true
CommonUtils.isEmpty([]); // true
CommonUtils.isEmpty({}); // true
CommonUtils.isEmpty({ name: 'sy' }); // falsedeepClone
深拷贝对象、数组、日期、正则,并支持循环引用。
import CommonUtils from 'commonsy/common';
const source = { user: { name: 'sy' }, tags: ['a'] };
const target = CommonUtils.deepClone(source);
target.user.name = 'new name';
console.log(source.user.name); // sydeepMerge
深度合并对象,后面的对象覆盖前面的同名字段。
import CommonUtils from 'commonsy/common';
const result = CommonUtils.deepMerge(
{ user: { name: 'sy', age: 18 } },
{ user: { age: 20 } }
);
console.log(result); // { user: { name: 'sy', age: 20 } }debounce
防抖。常用于搜索输入、窗口尺寸变化、按钮防重复触发。
import CommonUtils from 'commonsy/common';
const onSearch = CommonUtils.debounce((keyword) => {
console.log(keyword);
}, 300);
onSearch('commonsy');第三个参数为 true 时,首次立即执行。
const submit = CommonUtils.debounce(() => {
console.log('submit');
}, 500, true);throttle
节流。常用于滚动、拖拽、鼠标移动等高频事件。
import CommonUtils from 'commonsy/common';
const onScroll = CommonUtils.throttle(() => {
console.log('scroll');
}, 300);listToTree
将扁平数组转换为树形结构。
import CommonUtils from 'commonsy/common';
const list = [
{ id: 1, parentId: null, name: '菜单' },
{ id: 2, parentId: 1, name: '子菜单' },
];
const tree = CommonUtils.listToTree(list);
console.log(tree);支持自定义字段:
CommonUtils.listToTree(list, {
idKey: 'id',
parentKey: 'parentId',
childrenKey: 'children',
rootValue: null,
});treeToList
将树形结构拍平成数组。
import CommonUtils from 'commonsy/common';
const list = CommonUtils.treeToList(tree);
console.log(list);safeJsonParse
安全解析 JSON,失败时返回默认值。
import CommonUtils from 'commonsy/common';
CommonUtils.safeJsonParse('{"name":"sy"}', {}); // { name: 'sy' }
CommonUtils.safeJsonParse('{ bad json }', {}); // {}formatFileSize
格式化文件大小。
import CommonUtils from 'commonsy/common';
CommonUtils.formatFileSize(1024); // 1 KB
CommonUtils.formatFileSize(1048576); // 1 MB
CommonUtils.formatFileSize(1536, 1); // 1.5 KBmaskPhone
手机号脱敏。
import CommonUtils from 'commonsy/common';
CommonUtils.maskPhone('13812345678'); // 138****5678maskEmail
邮箱脱敏。
import CommonUtils from 'commonsy/common';
CommonUtils.maskEmail('[email protected]'); // t***[email protected]maskBankCard
银行卡号脱敏。
import CommonUtils from 'commonsy/common';
CommonUtils.maskBankCard('6222021234567890'); // 6222 **** **** 7890日期时间工具
DateTimeFormatter
按指定格式输出日期时间。
import DateUtils from 'commonsy/date';
const formatter = new DateUtils.DateTimeFormatter('2022-10-10 11:11:10', 'yyyy-mm-dd HH:mm:ss');
console.log(formatter.getFormattedDateTime()); // 2022-10-10 11:11:10支持格式:
| 格式 | 示例 |
| --- | --- |
| yyyy-mm-dd HH:mm:ss | 2022-10-10 11:11:10 |
| yyyy-mm-dd | 2022-10-10 |
| yyyy/mm/dd | 2022/10/10 |
| yyyy/mm/dd HH:mm:ss | 2022/10/10 11:11:10 |
CountdownTimer
倒计时工具,返回剩余总毫秒数、天、小时、分钟、秒。
import DateUtils from 'commonsy/date';
const countdown = new DateUtils.CountdownTimer('2026-12-31T23:59:59');
const firstRemaining = countdown.start((remaining) => {
console.log(remaining.days, remaining.hours, remaining.minutes, remaining.seconds);
});
console.log(firstRemaining);
// 主动停止
countdown.stop();也可以只计算一次:
const remaining = countdown.getTimeRemaining();
console.log(remaining);返回结构:
{
total: 1000,
days: 0,
hours: 0,
minutes: 0,
seconds: 1
}金额货币工具
BankNumber
使用 Intl.NumberFormat 格式化货币显示。
import MoneyUtils from 'commonsy/money';
const amount = new MoneyUtils.BankNumber(1000.5, 'US', 'USD');
console.log(amount.formatCurrency('US', 'USD')); // $1,000.50常见参数:
| 地区 | currency |
| --- | --- |
| US | USD |
| CN | CNY |
| JP | JPY |
| UK | GBP |
| EU | EUR |
ComputeMoney
使用分为单位处理金额,减少小数精度误差。
import MoneyUtils from 'commonsy/money';
const money = new MoneyUtils.ComputeMoney(100);
money.add(50);
console.log(money.toDollars()); // 150.00
money.multiply(2);
console.log(money.toDollars()); // 300.00支持方法:
money.add(10);
money.subtract(5);
money.multiply(2);
money.divide(3);
money.toDollars();表达式计算:
const result = MoneyUtils.ComputeMoney.calculate('(300 - 50) / 2 + 10');
const finalMoney = new MoneyUtils.ComputeMoney(result);
console.log(finalMoney.toDollars()); // 135.00表单校验工具
FormValidation
按字段配置执行非空、格式、最大长度、最小长度校验。
import ValidateUtils from 'commonsy/validate';
const formData = [
{
val: '13812345678',
valName: '手机号',
rule: /^1[3-9]\d{9}$/,
max: 11,
min: 11,
validList: ['isNull', 'isFormattingError', 'isMax', 'isMin'],
},
];
const validator = new ValidateUtils.FormValidation(formData);
console.log(validator.validationData()); // true支持规则:
| 规则 | 作用 | 依赖字段 |
| --- | --- | --- |
| isNull | 判断是否为空 | valName、val |
| isFormattingError | 判断正则格式是否匹配 | valName、rule、val |
| isMax | 判断长度是否超过最大值 | valName、max、val |
| isMin | 判断长度是否小于最小值 | valName、min、val |
校验失败时返回错误文案:
const validator = new ValidateUtils.FormValidation([
{ val: '', valName: '姓名', validList: ['isNull'] },
]);
console.log(validator.validationData()); // 姓名不能为空.浏览器工具
GetBrowserType
判断当前运行容器。
import BrowserUtils from 'commonsy/browser';
const browserType = new BrowserUtils.GetBrowserType();
console.log(browserType.throwType());返回值:
| 返回值 | 含义 |
| --- | --- |
| wechat | 微信内置浏览器 |
| alipay | 支付宝内置浏览器 |
| H5 | 普通 H5 环境或无法识别环境 |
文件图片工具
CompressImage
浏览器端图片压缩。传入 File,返回压缩后的 Blob。
import FileTools from 'commonsy/file';
const image = new FileTools.CompressImage(file, 1024, 1024, 0.8);
const blob = await image.compressImg();
console.log(blob);参数:
| 参数 | 说明 |
| --- | --- |
| file | 浏览器文件对象 |
| maxWidth | 最大宽度 |
| maxHeight | 最大高度 |
| quality | 图片质量,通常为 0 到 1 |
dataURLtoBlob
将 DataURL 转换为 Blob。
import FileTools from 'commonsy/file';
const blob = FileTools.CompressImage.dataURLtoBlob(dataUrl);formatFileSize
FileTools 中也包含 formatFileSize。
import FileTools from 'commonsy/file';
FileTools.formatFileSize(1024); // 1 KB下载链接工具
XunLeiDownloadUrl
将普通下载地址转换为迅雷 thunder:// 协议地址。
import DownloadUtils from 'commonsy/download';
const thunderUrl = new DownloadUtils.XunLeiDownloadUrl('http://localhost/file.zip').changeUrl();
console.log(thunderUrl);加密工具
Encryption
提供 MD5、AES、RSA 工具。
import CryptoUtils from 'commonsy/crypto';
const encryption = new CryptoUtils.Encryption();
console.log(encryption.md5('abc')); // 900150983cd24fb0d6963f7d28e17f72AES 加密和解密
import CryptoUtils from 'commonsy/crypto';
const encryption = new CryptoUtils.Encryption();
const result = encryption.aesEncrypt('hello');
console.log(result.encryptedData);
console.log(result.key);
console.log(result.iv);
const text = encryption.aesDecrypt(result.encryptedData, result.key, result.iv);
console.log(text); // helloRSA 加密
import CryptoUtils from 'commonsy/crypto';
const encryption = new CryptoUtils.Encryption();
const encrypted = encryption.rsaEncrypt('hello');
console.log(encrypted);preEncrypt
按 type 自动分发加密方法。
import CryptoUtils from 'commonsy/crypto';
const encryption = new CryptoUtils.Encryption();
encryption.preEncrypt({ type: 'MD5', value: 'abc' });
encryption.preEncrypt({ type: 'AES', value: 'hello' });
encryption.preEncrypt({ type: 'RSA', value: 'hello' });WebSocket 工具
WebSocketServer
Node 服务端 WebSocket 封装。
import WebSocketUtils from 'commonsy/websocket';
const server = new WebSocketUtils.WebSocketServer({ port: 8080 });
server.on('connection', (client) => {
client.on('message', (message) => {
console.log('收到消息:', message);
client.send(`服务器已收到消息: ${message}`);
});
client.on('close', () => {
console.log('客户端已断开连接');
});
});内置 JSON 消息类型:
| type | 行为 |
| --- | --- |
| auth | 调用 handleAuth(userId) |
| greeting | 返回欢迎信息 |
| question | 返回问题回复 |
| ping | 返回 pong |
| broadcast | 广播 content 给其他客户端 |
可用方法:
server.on('connection', callback);
server.broadcast('hello', senderSocket);
server.close();WebSocketClient
浏览器或 Node 客户端 WebSocket 封装,支持心跳和自动重连。
import WebSocketUtils from 'commonsy/websocket';
const client = new WebSocketUtils.WebSocketClient('ws://localhost:8080', {
heartbeatInterval: 30000,
reconnectDelay: 5000,
});
client.connect('user-001');
client.sendMessage(JSON.stringify({ type: 'greeting' }));
// 主动关闭
client.close();Cesium 地图工具
CesiumWrapper
按需加载 Cesium,封装 Viewer 初始化、相机控制、点线面绘制、标注、GeoJSON 加载和资源清理。
import MapUtils from 'commonsy/map';
const map = new MapUtils.CesiumWrapper('container');
const viewer = await map.init({
animation: false,
timeline: false,
});
console.log(viewer);相机控制
map.setCameraView({
longitude: 116.391,
latitude: 39.907,
height: 3000,
heading: 0,
pitch: -45,
roll: 0,
});
map.flyTo({
longitude: 116.391,
latitude: 39.907,
height: 3000,
duration: 2,
});添加点
const point = map.addPoint({
id: 'point-1',
name: '位置点',
longitude: 116.391,
latitude: 39.907,
height: 0,
});添加图片标注
const marker = map.addBillboard({
id: 'marker-1',
name: '图标标注',
longitude: 116.391,
latitude: 39.907,
altitude: 0,
image: '/marker.png',
width: 32,
billboardHeight: 32,
});添加文字标签
const label = map.addLabel({
id: 'label-1',
text: '北京',
longitude: 116.391,
latitude: 39.907,
});添加线
const line = map.addPolyline({
id: 'line-1',
positions: [
[116.391, 39.907, 0],
[121.473, 31.23, 0],
],
width: 4,
});添加面
const polygon = map.addPolygon({
id: 'polygon-1',
positions: [
[116.38, 39.9, 0],
[116.4, 39.9, 0],
[116.4, 39.92, 0],
[116.38, 39.92, 0],
],
});加载 GeoJSON
const dataSource = await map.addGeoJson('/data/area.geojson', {
flyTo: true,
clampToGround: true,
});删除和清理
map.removeEntity('point-1');
map.clearEntities();
map.clearDataSources();
map.destroy();常用方法:
| 方法 | 作用 |
| --- | --- |
| init(options) | 初始化 Viewer |
| loadCesium() | 按需加载 Cesium 模块 |
| getViewer() | 获取 Viewer 实例 |
| toCartesian(longitude, latitude, height) | 经纬度转 Cartesian3 |
| toCartesianArray(positions) | 经纬度数组转 Cartesian3 数组 |
| setCameraView(options) | 立即设置相机视角 |
| flyTo(options) | 飞行到指定位置 |
| addPoint(options) | 添加点实体 |
| addBillboard(options) | 添加图片标注 |
| addLabel(options) | 添加文字标签 |
| addPolyline(options) | 添加线实体 |
| addPolygon(options) | 添加面实体 |
| addGeoJson(data, options) | 加载 GeoJSON 数据源 |
| removeEntity(entityOrId) | 删除实体 |
| clearEntities() | 清空实体 |
| clearDataSources(destroy) | 清空数据源 |
| destroy() | 销毁 Viewer |
注意:Cesium 体积较大,业务项目需要自行安装并处理 Cesium 资源和样式。
默认入口完整示例
import sysFun from 'commonsy';
sysFun.CommonUtils.maskPhone('13812345678');
new sysFun.DateUtils.DateTimeFormatter('2022-10-10 11:11:10', 'yyyy-mm-dd').getFormattedDateTime();
new sysFun.MoneyUtils.ComputeMoney(100).add(50).toDollars();
new sysFun.ValidateUtils.FormValidation([{ val: '', valName: '姓名', validList: ['isNull'] }]).validationData();
new sysFun.BrowserUtils.GetBrowserType().throwType();
new sysFun.DownloadUtils.XunLeiDownloadUrl('http://localhost').changeUrl();
new sysFun.CryptoUtils.Encryption().md5('abc');
new sysFun.MapUtils.CesiumWrapper('container');测试
npm test环境说明
- 包格式为 ES Module。
CompressImage依赖浏览器FileReader、Image、document、canvas、Blob。WebSocketServer依赖 Node 环境和ws。CesiumWrapper需要业务项目安装并配置cesium。- 加密工具依赖
crypto-js和node-rsa。
