From 3af53f07de6fc152986da1f20ab81d4479453d44 Mon Sep 17 00:00:00 2001 From: Sinan Date: Sun, 3 Sep 2023 20:17:15 +0800 Subject: [PATCH] TypeScript Fullstack Engineer Assignment by Sinan Lee asdfwslxn@163.com --- fullstack/.gitignore | 6 + fullstack/README.md | 39 ++++ fullstack/app.ts | 41 ++++ fullstack/blogic/base-blogic.ts | 13 ++ fullstack/blogic/url/get.ts | 20 ++ fullstack/blogic/url/save.ts | 22 ++ fullstack/common/base.ts | 26 +++ fullstack/common/db-proxy.ts | 54 +++++ fullstack/common/exception/exception-const.ts | 41 ++++ .../common/exception/permission-exception.ts | 16 ++ .../common/exception/system-exception.ts | 16 ++ fullstack/common/logger.ts | 21 ++ fullstack/images/api-get.png | Bin 0 -> 46460 bytes fullstack/images/api-save.png | Bin 0 -> 40576 bytes fullstack/images/architecture.png | Bin 0 -> 13994 bytes fullstack/images/mocha.png | Bin 0 -> 9035 bytes fullstack/images/nyc.png | Bin 0 -> 14758 bytes fullstack/model/base-model.ts | 17 ++ fullstack/package.json | 89 ++++++++ fullstack/router/base-router.ts | 47 ++++ fullstack/router/system/url.ts | 9 + fullstack/test/tsconfig.test.json | 6 + fullstack/test/unit/api/getShortUrl.spec.ts | 50 ++++ fullstack/test/unit/api/saveShortUrl.spec.ts | 16 ++ fullstack/test/unit/utils/url.spec.ts | 13 ++ fullstack/tsconfig.json | 69 ++++++ fullstack/utils/common.ts | 214 ++++++++++++++++++ fullstack/utils/random.ts | 11 + 28 files changed, 856 insertions(+) create mode 100644 fullstack/.gitignore create mode 100644 fullstack/app.ts create mode 100644 fullstack/blogic/base-blogic.ts create mode 100644 fullstack/blogic/url/get.ts create mode 100644 fullstack/blogic/url/save.ts create mode 100644 fullstack/common/base.ts create mode 100644 fullstack/common/db-proxy.ts create mode 100644 fullstack/common/exception/exception-const.ts create mode 100644 fullstack/common/exception/permission-exception.ts create mode 100644 fullstack/common/exception/system-exception.ts create mode 100644 fullstack/common/logger.ts create mode 100644 fullstack/images/api-get.png create mode 100644 fullstack/images/api-save.png create mode 100644 fullstack/images/architecture.png create mode 100644 fullstack/images/mocha.png create mode 100644 fullstack/images/nyc.png create mode 100644 fullstack/model/base-model.ts create mode 100644 fullstack/package.json create mode 100644 fullstack/router/base-router.ts create mode 100644 fullstack/router/system/url.ts create mode 100644 fullstack/test/tsconfig.test.json create mode 100644 fullstack/test/unit/api/getShortUrl.spec.ts create mode 100644 fullstack/test/unit/api/saveShortUrl.spec.ts create mode 100644 fullstack/test/unit/utils/url.spec.ts create mode 100644 fullstack/tsconfig.json create mode 100644 fullstack/utils/common.ts create mode 100644 fullstack/utils/random.ts diff --git a/fullstack/.gitignore b/fullstack/.gitignore new file mode 100644 index 000000000..4443b89eb --- /dev/null +++ b/fullstack/.gitignore @@ -0,0 +1,6 @@ +node_modules +package-lock.json +tests +yarn.lock +dist +.env* \ No newline at end of file diff --git a/fullstack/README.md b/fullstack/README.md index f20fa11ec..0a4a0284e 100644 --- a/fullstack/README.md +++ b/fullstack/README.md @@ -1,3 +1,42 @@ +# 项目说明 + +- 本框架原本使用 node+typescript+express+mysql 搭建,修改后使用 redis 实现数据存储。 + 因此删掉了大多数不必要的文件,只保留了实现 api 的基础框架。 +- 此项目代码只考虑了长域名和短域名的转换,长域名唯一性校验和 mysql 持久化存储没有实现。 +- 短域名存储接口 url/save +- 短域名读取接口 url/get + +# 递交作业说明 + +1. 源代码 + 见代码。 +2. 单元测试代码以及单元测试覆盖率(覆盖率请勿提交整个目录,一张图片或一个 text table 即可) + ![nyc](./images/nyc.png) +3. API 集成测试案例以及测试结果 + ![api-save](./images/api-save.png) + ![api-get](./images/api-get.png) +4. 简单的框架设计图,以及所有做的假设 + ![简单架构图](./images/architecture.png) + 假设: + - 怎么保证所有的短 url 唯一? + 使用时间戳+10 位随机数生成一个数字,不能说完全唯一,但是重复率极小极小。 + - 怎么保证短 url 长度小于 8 位? + 时间戳长度为 13 位,经过 62 进制编码后长度绝对小于等于 8 位。 + - 怎么保证长域名存储的唯一性? + 本项目只考虑了长短域名的对应,长域名如果想做唯一性校验,可以在持久化到 mysql 数据库时做唯一索引,redis 这里只考虑短域名的唯一,且不考虑获取长域名对应的短域名情况 +5. 涉及的 SQL 或者 NoSQL 的 Schema,注意标注出 Primary key 和 Index 如果有。 + 本项目数据只涉及 redis 存储,schema 为 db0,key(短域名)- value(长域名) + +## 使用说明 + +安装: + +> yarn + +启动: + +> yarn start + # TypeScript Fullstack Engineer Assignment ### Typescript 实现短域名服务(细节可以百度/谷歌) diff --git a/fullstack/app.ts b/fullstack/app.ts new file mode 100644 index 000000000..889449cbc --- /dev/null +++ b/fullstack/app.ts @@ -0,0 +1,41 @@ +const express = require("express"); +const app = express(); +const createError = require("http-errors"); +const bodyParser = require("body-parser"); + +import { ErrorMessage } from "./common/exception/exception-const"; +import { logger } from "./common/logger"; +import * as UrlApi from "./router/system/url"; + +// 服务器设置 +app.use(bodyParser.json({ limit: "50mb" })); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); + +// node服务生命监测 +app.use("*/ping", (req: any, res: any) => { + res.send("pong"); +}); + +// 注册接口 +app.use("/url", UrlApi.router); + +// 404 +app.use(function (req: any, res: any, next: any) { + next(createError(404)); +}); + +// 错误处理 +app.use(function (err: any, req: any, res: any, next: any) { + if (err.name === "UnauthorizedError") { + res.send(ErrorMessage.AUTH_LOGIN); + } + res.locals.message = err.message; + res.locals.error = err; + res.status(err.status || 500); + res.send(err.message); +}); + +app.listen(8888, () => { + logger.info("The app is listening on port 8888!"); +}); diff --git a/fullstack/blogic/base-blogic.ts b/fullstack/blogic/base-blogic.ts new file mode 100644 index 000000000..eb9681759 --- /dev/null +++ b/fullstack/blogic/base-blogic.ts @@ -0,0 +1,13 @@ +import { BLogicContext } from "../common/base"; + +export abstract class BaseBLogic { + abstract doExecute(context: BLogicContext): any; + needAuth: boolean = false; + needLogger: boolean = false; + + public async execute(context: BLogicContext) { + return await this.doExecute(context); + }; +} + + diff --git a/fullstack/blogic/url/get.ts b/fullstack/blogic/url/get.ts new file mode 100644 index 000000000..910309f12 --- /dev/null +++ b/fullstack/blogic/url/get.ts @@ -0,0 +1,20 @@ +/** + * 短域名读取接口:接受短域名信息,返回长域名信息。 + */ + +import { BLogicContext } from "../../common/base"; +import { BaseModel } from "../../model/base-model"; +import { BaseBLogic } from "../base-blogic"; + +export class ShortUrlGetBLogic extends BaseBLogic { + public async doExecute(context: BLogicContext) { + const { url } = context.input; + const baseModel: BaseModel = new BaseModel(context.proxy); + const res: string = await baseModel.get(url); + if (res) { + return { + url: res, + }; + } + } +} diff --git a/fullstack/blogic/url/save.ts b/fullstack/blogic/url/save.ts new file mode 100644 index 000000000..5279ba430 --- /dev/null +++ b/fullstack/blogic/url/save.ts @@ -0,0 +1,22 @@ +/** + * 短域名存储接口:接受长域名信息,返回短域名信息 + */ + +import { BLogicContext } from "../../common/base"; +import { BaseBLogic } from "../base-blogic"; +import { BaseModel } from "../../model/base-model"; +import { getShortUrl } from "../../utils/common"; + +export class ShortUrlSaveBLogic extends BaseBLogic { + public async doExecute(context: BLogicContext) { + const { url } = context.input; + const baseModel: BaseModel = new BaseModel(context.proxy); + const key: string = getShortUrl(); + const res: string = await baseModel.set(key, url); + if (res && res == "OK") { + return { + url: key, + }; + } + } +} diff --git a/fullstack/common/base.ts b/fullstack/common/base.ts new file mode 100644 index 000000000..58203090c --- /dev/null +++ b/fullstack/common/base.ts @@ -0,0 +1,26 @@ +import { DBProxy } from './db-proxy'; + +// 请求 +export interface BLogicContext { + session: { + permission: string; + token: string; + host: string; + uid: string; + username: string; + appid: string; + }; + input: T; + params: any; + proxy: DBProxy; + originalUrl: string; // 请求路径 + reqNo: string; // 请求编号 +} + +// 返回 +export interface ResultData { + ok: boolean; + data: object; + err_code?: number; + err_msg?: string; +} diff --git a/fullstack/common/db-proxy.ts b/fullstack/common/db-proxy.ts new file mode 100644 index 000000000..9dd9f8233 --- /dev/null +++ b/fullstack/common/db-proxy.ts @@ -0,0 +1,54 @@ +import { logger } from "./logger"; + +const redis = require("redis"); + +export class DBProxy { + private clientNo: string; + private client: any; + constructor() { + this.clientNo = "DBProxy" + Math.ceil(Math.random() * 9999); + } + + public async connect() { + if (!this.client) { + this.client = redis.createClient({ + socket: { + host: "127.0.0.1", + port: 6379, + }, + }); + this.client.on("error", function (err: any) { + console.log("Error " + err); + }); + } + await this.client.connect(); + } + + public async disconnect() { + await this.client.disconnect(); + } + + public async set(key: string, value: string) { + logger.debug( + this.clientNo + `: dbproxy set: key=[${key}] value=[${value}]` + ); + try { + const res = await this.client.set(key, value); + return res; + } catch (error) { + logger.error(`DBProxy error: ${this.clientNo} - ${error}`); + return; + } + } + + public async get(key: string) { + logger.debug(this.clientNo + `: dbproxy get: key=[${key}]`); + try { + const res = await this.client.get(key); + return res; + } catch (error) { + logger.error(`DBProxy error: ${this.clientNo} - ${error}`); + return; + } + } +} diff --git a/fullstack/common/exception/exception-const.ts b/fullstack/common/exception/exception-const.ts new file mode 100644 index 000000000..172f9e372 --- /dev/null +++ b/fullstack/common/exception/exception-const.ts @@ -0,0 +1,41 @@ +export enum ErrorConst { + AUTH_LOGIN = 999, + SQL_ERROR = 1001, + External_API = 1002, + WX_AUTH_TOKEN = 4001, + WX_CREATE_MENU = 4002, +} + +export enum ErrorMessage { + AUTH_LOGIN = "登录验证失败", + SQL_ERROR = "数据库操作失败", +} + +/** + * 返回错误信息 + * @param errCode:number 错误码 + * @param msg:string[] 错误提示 + * @returns 字符串可能是内部错误,直接返回 + * @returns 数组或者不存在,用定义好的错误提示和msg拼接 + * @returns 其余情况(对象)序列化后返回 + */ +export function getErrorMessage(errCode: number, msg?: string[]) { + if (typeof msg === "string") { + return msg; + } else if (Array.isArray(msg) || !msg) { + let code = ErrorConst[errCode]; + let info: any = ErrorMessage[`${code as keyof typeof ErrorMessage}`]; + if (info && msg && msg.length == 1) { + info = `${msg[0]}${info}`; + } + if (info && msg && msg.length > 1) { + info = `${msg[0]}${info}${msg[1]}`; + } + if (!info && msg && msg.length) { + info = msg[0]; + } + return info; + } else { + return JSON.stringify(msg); + } +} diff --git a/fullstack/common/exception/permission-exception.ts b/fullstack/common/exception/permission-exception.ts new file mode 100644 index 000000000..0acf233b3 --- /dev/null +++ b/fullstack/common/exception/permission-exception.ts @@ -0,0 +1,16 @@ +import { getErrorMessage } from './exception-const'; + +export class PermissionException extends Error { + code: number; + msg: string; + err: Error | undefined; + constructor(errCode: number, errMsg?: string[], err?: Error) { + let msg: string = getErrorMessage(errCode, errMsg); + super(msg); + this.code = errCode; + this.msg = msg; + if (err) { + this.err = err; + } + } +} diff --git a/fullstack/common/exception/system-exception.ts b/fullstack/common/exception/system-exception.ts new file mode 100644 index 000000000..02bb45315 --- /dev/null +++ b/fullstack/common/exception/system-exception.ts @@ -0,0 +1,16 @@ +import { getErrorMessage } from "./exception-const"; + +export class SystemException extends Error { + code: number; + msg: string; + err: Error | undefined; + constructor(errCode: number, errMsg?: string[], err?: Error) { + let msg: string = getErrorMessage(errCode, errMsg); + super(msg); + this.code = errCode; + this.msg = msg; + if (err) { + this.err = err; + } + } +} diff --git a/fullstack/common/logger.ts b/fullstack/common/logger.ts new file mode 100644 index 000000000..b9ff4f6f0 --- /dev/null +++ b/fullstack/common/logger.ts @@ -0,0 +1,21 @@ +import * as log4js from 'log4js'; +export const logger = log4js.getLogger(); +export const reqLog = log4js.getLogger('reqLog'); +const level = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : 'debug'; +log4js.configure({ + appenders: { + // 控制台输入 + console: { type: 'console' }, + }, + categories: { + // 默认日志 + default: { + appenders: ['console'], + level: level, + }, + reqLog: { + appenders: ['console'], + level: level, + }, + }, +}); diff --git a/fullstack/images/api-get.png b/fullstack/images/api-get.png new file mode 100644 index 0000000000000000000000000000000000000000..1865b93a1b8d738a5aca7d799aaa5733595adea0 GIT binary patch literal 46460 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 z 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

Tr&a6_QWTv^t8deOQ<;DU`cizz%I2m?G1By%# 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

-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 QsL5qz@uPX!QC#f50O>$uegFUf literal 0 HcmV?d00001 diff --git a/fullstack/images/architecture.png b/fullstack/images/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d1325737ca7fd106a6285201c8fc56765d8d98 GIT binary patch literal 13994 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 literal 0 HcmV?d00001 diff --git a/fullstack/images/mocha.png b/fullstack/images/mocha.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9f6f278eefd904d61004eaaa2a1db2ccb672a9 GIT binary patch literal 9035 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 literal 0 HcmV?d00001 diff --git a/fullstack/images/nyc.png b/fullstack/images/nyc.png new file mode 100644 index 0000000000000000000000000000000000000000..07a19b45d382c1b1552cbe260cf8d16bc906b335 GIT binary patch literal 14758 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 { + const reqNo: string = "Req" + Math.ceil(Math.random() * 9999); + const dbproxy: DBProxy = new DBProxy(); + dbproxy.connect(); + const blogic: BaseBLogic = new BLogicClass(); + const originalUrl: string = req.originalUrl; + let data: any = path.includes("upload") ? { req: req } : req.body; + + let session: any = { host: req.get("host") }; + let context: BLogicContext = { + session: session, + input: data, + params: req.params, + proxy: dbproxy, + originalUrl, + reqNo, + }; + let resData: ResultData = { ok: true, data: {} }; + try { + const r = await blogic.execute(context); + resData.data = r; + } catch (err) { + logger.error(JSON.stringify(err)); + resData.ok = false; + if (err instanceof SystemException) { + resData.err_code = err.code; + resData.err_msg = err.msg; + } else if (err instanceof PermissionException) { + resData.err_code = err.code; + resData.err_msg = err.msg; + } + } + res.send(resData); + dbproxy.disconnect(); + }); + } +} diff --git a/fullstack/router/system/url.ts b/fullstack/router/system/url.ts new file mode 100644 index 000000000..12c06809c --- /dev/null +++ b/fullstack/router/system/url.ts @@ -0,0 +1,9 @@ +const express = require("express"); +import { ShortUrlSaveBLogic } from "../../blogic/url/save"; +import { ShortUrlGetBLogic } from "../../blogic/url/get"; +import { BaseRouter } from "../base-router"; +export const router = express.Router(); + +// 短域名服务相关接口 +BaseRouter.post(router, "/save", ShortUrlSaveBLogic); +BaseRouter.post(router, "/get", ShortUrlGetBLogic); diff --git a/fullstack/test/tsconfig.test.json b/fullstack/test/tsconfig.test.json new file mode 100644 index 000000000..484405d0e --- /dev/null +++ b/fullstack/test/tsconfig.test.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "ts-node": { + "transpileOnly": true + } +} diff --git a/fullstack/test/unit/api/getShortUrl.spec.ts b/fullstack/test/unit/api/getShortUrl.spec.ts new file mode 100644 index 000000000..a26da48a5 --- /dev/null +++ b/fullstack/test/unit/api/getShortUrl.spec.ts @@ -0,0 +1,50 @@ +import { assert, expect } from "chai"; +const axios = require("axios"); + +describe("api:/url/get", () => { + let shortUrl: string = ""; + + before(() => { + // 先存一个长url + return axios + .post("http://localhost:8888/url/save", { + url: "/scdt-china/interview-assignments/blob/master/fullstack/README.md", + }) + .then( + ( + res: ApiResult = { status: 0, data: { ok: false, data: { url: "" } } } + ) => { + shortUrl = res.data.data.url; + } + ); + }); + + describe("/url/get", () => { + it("post request: /url/get", async () => { + const data = { + url: shortUrl, + }; + const res: ApiResult = await axios.post( + "http://localhost:8888/url/get", + data + ); + expect(res.status)?.to.equal(200); + expect(res.data.ok)?.to.equal(true); + assert.isString(res.data.data.url); + }); + }); +}); + +interface UrlData { + url: string; +} + +interface ApiResultData { + ok: boolean; + data: UrlData; +} + +interface ApiResult { + status: number; + data: ApiResultData; +} diff --git a/fullstack/test/unit/api/saveShortUrl.spec.ts b/fullstack/test/unit/api/saveShortUrl.spec.ts new file mode 100644 index 000000000..b640b5af5 --- /dev/null +++ b/fullstack/test/unit/api/saveShortUrl.spec.ts @@ -0,0 +1,16 @@ +import { assert, expect } from "chai"; +const axios = require("axios"); +// const api = require('../src/api'); // 引入要测试的API模块 + +describe("api:/url/save", () => { + it("post request: /url/save", async () => { + const data = { + url: "/scdt-china/interview-assignments/blob/master/fullstack/README.md", + }; + const res = await axios.post("http://localhost:8888/url/save", data); + expect(res.status).to.equal(200); + expect(res.data.ok).to.equal(true); + assert.isString(res.data.data.url); + assert.match(res.data.data.url, /^[0-9a-zA-Z]{1,8}$/); + }); +}); diff --git a/fullstack/test/unit/utils/url.spec.ts b/fullstack/test/unit/utils/url.spec.ts new file mode 100644 index 000000000..25b452146 --- /dev/null +++ b/fullstack/test/unit/utils/url.spec.ts @@ -0,0 +1,13 @@ +import { assert } from "chai"; +import { getShortUrl } from "../../../utils/common"; + +describe("util:getShortUrl", () => { + it("should return a string", () => { + const actualUrl = getShortUrl(); + assert.isString(actualUrl); + }); + it("should length < 8", () => { + const actualUrl = getShortUrl(); + assert.match(actualUrl, /^[0-9a-zA-Z]{1,8}$/); + }); +}); diff --git a/fullstack/tsconfig.json b/fullstack/tsconfig.json new file mode 100644 index 000000000..1a522019a --- /dev/null +++ b/fullstack/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + /* 访问 https://aka.ms/tsconfig.json 以阅读有关此文件的更多信息 */ + + /* 基本选项 */ + // "incremental": true, /* 启用增量编译 */ + "target": "ES2017" /* 指定 ECMAScript 目标版本:'ES3'、'ES5'(默认)、'ES2015'、'ES2016'、'ES2017'、'ES2018'、'ES2019'、'ES2020' 或 'ESNEXT'。 */, + "module": "commonjs" /* 指定模块代码生成:“none”、“commonjs”、“amd”、“system”、“umd”、“es2015”、“es2020”或“ESNext”。 */, + "lib": ["ES2018", "DOM"] /* 指定要包含在编译中的库文件。 */, + // "allowJs": true /* 允许编译 javascript 文件。 */, + // "checkJs": true /* 报告 .js 文件中的错误。 */, + // "jsx": "preserve" /* 指定 JSX 代码生成:'preserve'、'react-native' 或 'react'。 */, + // "declaration": true /* 生成相应的“.d.ts”文件。 */, + // "declarationMap": true /* 为每个对应的“.d.ts”文件生成一个源映射。 */, + "sourceMap": true /* 生成相应的“.map”文件。 */, + // "outFile": "./" /* 连接输出到单个文件。 */, + "outDir": "./dist" /* 将输出结构重定向到目录。 */, + // "rootDir": "./" /* 指定输入文件的根目录。用于通过 --outDir 控制输出目录结构。 */, + // "composite": true /* 启用项目编译 */, + // "tsBuildInfoFile": "./" /* 指定文件存放增量编译信息 */, + // "removeComments": true /* 不要向输出发出注释。 */, + // "noEmit": true /* 不发出输出。 */, + // "importHelpers": true /* 从 'tslib' 导入发射助手。 */, + // "downlevelIteration": true /* 以“ES5”或“ES3”为目标时,为“for-of”、展开和解构中的迭代提供全面支持。 */, + // "isolatedModules": true /* 将每个文件转换为一个单独的模块(类似于 'ts.transpileModule')。 */, + + /* 严格的类型检查选项 */ + "strict": true /* 启用所有严格的类型检查选项。 */, + "noImplicitAny": true /* 使用隐含的“任何”类型在表达式和声明上引发错误。 */, + // "strictNullChecks": true /* 启用严格的空检查。 */, + // "strictFunctionTypes": true /* 启用函数类型的严格检查。 */, + // "strictBindCallApply": true /* 在函数上启用严格的“绑定”、“调用”和“应用”方法。 */, + // "strictPropertyInitialization": true /* 启用对类中属性初始化的严格检查。 */, + // "noImplicitThis": true /* 使用隐含的“any”类型在“this”表达式上引发错误。 */, + // "alwaysStrict": true /* 以严格模式解析并为每个源文件发出“使用严格”。 */, + + /* 额外检查 */ + // "noUnusedLocals": true /* 报告未使用的本地人的错误。 */, + // "noUnusedParameters": true /* 报告未使用参数的错误。 */, + // "noImplicitReturns": true /* 不是函数中的所有代码路径都返回值时报告错误。 */, + // "noFallthroughCasesInSwitch": true /* 在 switch 语句中报告失败情况的错误。 */, + + /* 模块分辨率选项 */ + // "moduleResolution": "node" /* 指定模块解析策略:'node' (Node.js) 或 'classic' (TypeScript pre-1.6)。 */, + // "baseUrl": "./" /* 解析非绝对模块名称的基目录。 */, + // "paths": {} /* 一系列将导入重新映射到相对于“baseUrl”的查找位置的条目。 */, + // "rootDirs": [] /* 根文件夹列表,其组合内容代表运行时项目的结构。 */, + "typeRoots": ["node_modules/@types"] /* 包含类型定义的文件夹列表。 */, + // "types": [] /* 类型声明文件要包含在编译中。 */, + // "allowSyntheticDefaultImports": true /* 允许从没有默认导出的模块中默认导入。 这不会影响代码发出,只是类型检查。 */, + "esModuleInterop": true /* 通过为所有导入创建命名空间对象,在 CommonJS 和 ES 模块之间启用发射互操作性。 暗示“allowSyntheticDefaultImports”。 */, + // "preserveSymlinks": true /* 不解析符号链接的真实路径。 */, + // "allowUmdGlobalAccess": true /* 允许从模块访问 UMD 全局变量。 */, + + /* 源映射选项 */ + // "sourceRoot": "" /* 指定调试器应该定位 TypeScript 文件而不是源位置的位置。 */, + // "mapRoot": "" /* 指定调试器应该定位映射文件而不是生成位置的位置。 */, + // "inlineSourceMap": true /* 发出带有源映射的单个文件而不是单独的文件。 */, + // "inlineSources": true /* 在单个文件中与源映射一起发出源; 需要设置“--inlineSourceMap”或“--sourceMap”。 */, + + /* 实验选项 */ + "experimentalDecorators": true /* 启用对 ES7 装饰器的实验性支持。 */, + "emitDecoratorMetadata": true /* 为装饰器的发射类型元数据启用实验性支持。 */, + + /* 高级选项 */ + "skipLibCheck": true /* 跳过声明文件的类型检查。 */, + "forceConsistentCasingInFileNames": true /* 禁止对同一文件的大小写不一致的引用。 */ + } +} diff --git a/fullstack/utils/common.ts b/fullstack/utils/common.ts new file mode 100644 index 000000000..43422e7de --- /dev/null +++ b/fullstack/utils/common.ts @@ -0,0 +1,214 @@ +/** + * 返回字符串 为n个char构成 + * @param char 重复的字符 + * @param count 次数 + * @return String + * @author adswads@gmail.com + */ +export const charString = (char: string, count: number): string => { + var str: string = ""; + while (count--) { + str += char; + } + return str; +}; + +/** + * 对日期进行格式化, 和C#大致一致 默认yyyy-MM-dd HH:mm:ss + * 可不带参数 一个日期参数 或一个格式化参数 + * @param date 要格式化的日期 + * @param format 进行格式化的模式字符串 + * 支持的模式字母有: + * y:年, + * M:年中的月份(1-12), + * d:月份中的天(1-31), + * H:小时(0-23), + * h:小时(0-11), + * m:分(0-59), + * s:秒(0-59), + * f:毫秒(0-999), + * q:季度(1-4) + * @return String + * @author adswads@gmail.com + */ +export const dateFormat = (date?: any, format?: string): string => { + //无参数 + if (date == undefined && format == undefined) { + date = new Date(); + format = "yyyy-MM-dd HH:mm:ss"; + } + //无日期 + else if (typeof date == "string") { + format = date; + date = new Date(); + } + //无格式化参数 + else if (format === undefined) { + format = "yyyy-MM-dd HH:mm:ss"; + } else { + } + //没有分隔符的特殊处理 + + let map: any = { + y: date.getFullYear() + "", //年份 + M: date.getMonth() + 1 + "", //月份 + d: date.getDate() + "", //日 + h: date.getHours(), //小时 12 + H: date.getHours(), //小时 24 + m: date.getMinutes() + "", //分 + s: date.getSeconds() + "", //秒 + q: Math.floor((date.getMonth() + 3) / 3) + "", //季度 + f: date.getMilliseconds() + "", //毫秒 + }; + //小时 12 + if (map["H"] > 12) { + map["h"] = map["H"] - 12 + ""; + } else { + map["h"] = map["H"] + ""; + } + map["H"] += ""; + + let reg = "yMdHhmsqf"; + let all = "", + str = ""; + for (let i = 0, n = 0; i < reg.length; i++) { + n = format.indexOf(reg[i]); + if (n < 0) { + continue; + } + all = ""; + for (; n < format.length; n++) { + if (format[n] != reg[i]) { + break; + } + all += reg[i]; + } + if (all.length > 0) { + if (all.length == map[reg[i]].length) { + str = map[reg[i]]; + } else if (all.length > map[reg[i]].length) { + if (reg[i] == "f") { + str = map[reg[i]] + charString("0", all.length - map[reg[i]].length); + } else { + str = charString("0", all.length - map[reg[i]].length) + map[reg[i]]; + } + } else { + switch (reg[i]) { + case "y": + str = map[reg[i]].substr(map[reg[i]].length - all.length); + break; + case "f": + str = map[reg[i]].substr(0, all.length); + break; + default: + str = map[reg[i]]; + break; + } + } + format = format.replace(all, str); + } + } + return format; +}; + +// 带_字符串转驼峰 +export function ToHump(name: string): string { + if (name.includes("_")) { + let oarr = name.split("_"); + for (let i = 1; i < oarr.length; i++) { + oarr[i] = oarr[i].charAt(0).toUpperCase() + oarr[i].slice(1); + } + return oarr.join(""); + } + return name; +} + +// 对象属性带_转驼峰 +export function HumpObj(obj: any) { + if (!obj) return obj; + + let humpObj: any = {}; + for (let key in obj) { + humpObj[ToHump(key)] = obj[key]; + + if (obj[key] && obj[key] instanceof Object) { + humpObj[ToHump(key)] = HumpObj(obj[key]); + } + } + + return humpObj; +} + +// 数组对象转驼峰 +export function HumpArray(arr: any) { + if (arr instanceof Array) { + arr.forEach((item, i) => { + arr[i] = HumpObj(item); + }); + } else { + arr = HumpObj(arr); + } + return arr; +} + +// 渲染二级菜单 +export function renderMenu(arr: any, topValue: any = 0) { + let newArray: any[] = []; + // 添加一级菜单 + for (let i = 0; i < arr.length; i++) { + if (arr[i]["parentId"] == topValue) { + arr[i].list = []; + newArray.push(arr[i]); + } + } + for (let i = 0; i < arr.length; i++) { + for (let j = 0; j < newArray.length; j++) { + if (arr[i]["parentId"] == newArray[j]["menuId"]) { + newArray[j].list.push(arr[i]); + } + } + } + return newArray; +} + +// 获得当前时间 +export function getCurrentTime(): string { + let ctime = dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss"); + return ctime; +} + +// 字符串转16进制 +export function toHex(str: string): string { + let val = ""; + for (let i = 0; i < str.length; i++) { + if (val == "") val = str.charCodeAt(i).toString(16); + else val += str.charCodeAt(i).toString(16); + } + val += "0a"; + return val; +} + +// 数字转62进制 +export function decimalTo62(num: number): string { + const base62 = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let res = ""; + while (num > 0) { + const remainder = num % 62; + res = base62.charAt(remainder) + res; + num = Math.floor(num / 62); + } + return res; +} + +/** + * 生成一个唯一的字符串作为短域名 + * @returns string 短域名 + */ +export function getShortUrl(): string { + // 使用当前时间戳+随机数作为唯一id,随机数取10位,避免id重复 + const timestamp = new Date().getTime(); + const rand = Math.floor(Math.random() * Math.pow(10, 10)); + // 转62进制返回字符串 + return decimalTo62(timestamp + rand); +} diff --git a/fullstack/utils/random.ts b/fullstack/utils/random.ts new file mode 100644 index 000000000..e5683d57a --- /dev/null +++ b/fullstack/utils/random.ts @@ -0,0 +1,11 @@ +// 生成特定长度的随机字符串 +export function randomString(len: number): string { + let str = 'abcdefg012ABCDEFGhijklmn345HIJKLMNopqrstOPQRST678uvwxyz0UVWXYZ'; + let res = ''; + let strLen = str.length - 1; + for (let i = 0; i < len; i++) { + let n = Math.round(Math.random() * strLen); + res += str.slice(n, n + 1); + } + return res; +}