push
This commit is contained in:
194
lib/util/chalk/ansi-styles/index.d.ts
vendored
Normal file
194
lib/util/chalk/ansi-styles/index.d.ts
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
export interface CSPair {
|
||||
// eslint-disable-line @typescript-eslint/naming-convention
|
||||
/**
|
||||
The ANSI terminal control sequence for starting this style.
|
||||
*/
|
||||
readonly open: string;
|
||||
|
||||
/**
|
||||
The ANSI terminal control sequence for ending this style.
|
||||
*/
|
||||
readonly close: string;
|
||||
}
|
||||
|
||||
export interface ColorBase {
|
||||
/**
|
||||
The ANSI terminal control sequence for ending this color.
|
||||
*/
|
||||
readonly close: string;
|
||||
|
||||
ansi(code: number): string;
|
||||
|
||||
ansi256(code: number): string;
|
||||
|
||||
ansi16m(red: number, green: number, blue: number): string;
|
||||
}
|
||||
|
||||
export interface Modifier {
|
||||
/**
|
||||
Resets the current color chain.
|
||||
*/
|
||||
readonly reset: CSPair;
|
||||
|
||||
/**
|
||||
Make text bold.
|
||||
*/
|
||||
readonly bold: CSPair;
|
||||
|
||||
/**
|
||||
Emitting only a small amount of light.
|
||||
*/
|
||||
readonly dim: CSPair;
|
||||
|
||||
/**
|
||||
Make text italic. (Not widely supported)
|
||||
*/
|
||||
readonly italic: CSPair;
|
||||
|
||||
/**
|
||||
Make text underline. (Not widely supported)
|
||||
*/
|
||||
readonly underline: CSPair;
|
||||
|
||||
/**
|
||||
Make text overline.
|
||||
|
||||
Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.
|
||||
*/
|
||||
readonly overline: CSPair;
|
||||
|
||||
/**
|
||||
Inverse background and foreground colors.
|
||||
*/
|
||||
readonly inverse: CSPair;
|
||||
|
||||
/**
|
||||
Prints the text, but makes it invisible.
|
||||
*/
|
||||
readonly hidden: CSPair;
|
||||
|
||||
/**
|
||||
Puts a horizontal line through the center of the text. (Not widely supported)
|
||||
*/
|
||||
readonly strikethrough: CSPair;
|
||||
}
|
||||
|
||||
export interface ForegroundColor {
|
||||
readonly black: CSPair;
|
||||
readonly red: CSPair;
|
||||
readonly green: CSPair;
|
||||
readonly yellow: CSPair;
|
||||
readonly blue: CSPair;
|
||||
readonly cyan: CSPair;
|
||||
readonly magenta: CSPair;
|
||||
readonly white: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly gray: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly grey: CSPair;
|
||||
|
||||
readonly blackBright: CSPair;
|
||||
readonly redBright: CSPair;
|
||||
readonly greenBright: CSPair;
|
||||
readonly yellowBright: CSPair;
|
||||
readonly blueBright: CSPair;
|
||||
readonly cyanBright: CSPair;
|
||||
readonly magentaBright: CSPair;
|
||||
readonly whiteBright: CSPair;
|
||||
}
|
||||
|
||||
export interface BackgroundColor {
|
||||
readonly bgBlack: CSPair;
|
||||
readonly bgRed: CSPair;
|
||||
readonly bgGreen: CSPair;
|
||||
readonly bgYellow: CSPair;
|
||||
readonly bgBlue: CSPair;
|
||||
readonly bgCyan: CSPair;
|
||||
readonly bgMagenta: CSPair;
|
||||
readonly bgWhite: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGray: CSPair;
|
||||
|
||||
/**
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGrey: CSPair;
|
||||
|
||||
readonly bgBlackBright: CSPair;
|
||||
readonly bgRedBright: CSPair;
|
||||
readonly bgGreenBright: CSPair;
|
||||
readonly bgYellowBright: CSPair;
|
||||
readonly bgBlueBright: CSPair;
|
||||
readonly bgCyanBright: CSPair;
|
||||
readonly bgMagentaBright: CSPair;
|
||||
readonly bgWhiteBright: CSPair;
|
||||
}
|
||||
|
||||
export interface ConvertColor {
|
||||
/**
|
||||
Convert from the RGB color space to the ANSI 256 color space.
|
||||
|
||||
@param red - (`0...255`)
|
||||
@param green - (`0...255`)
|
||||
@param blue - (`0...255`)
|
||||
*/
|
||||
rgbToAnsi256(red: number, green: number, blue: number): number;
|
||||
|
||||
/**
|
||||
Convert from the RGB HEX color space to the RGB color space.
|
||||
|
||||
@param hex - A hexadecimal string containing RGB data.
|
||||
*/
|
||||
hexToRgb(hex: string): [red: number, green: number, blue: number];
|
||||
|
||||
/**
|
||||
Convert from the RGB HEX color space to the ANSI 256 color space.
|
||||
|
||||
@param hex - A hexadecimal string containing RGB data.
|
||||
*/
|
||||
hexToAnsi256(hex: string): number;
|
||||
|
||||
/**
|
||||
Convert from the ANSI 256 color space to the ANSI 16 color space.
|
||||
|
||||
@param code - A number representing the ANSI 256 color.
|
||||
*/
|
||||
ansi256ToAnsi(code: number): number;
|
||||
|
||||
/**
|
||||
Convert from the RGB color space to the ANSI 16 color space.
|
||||
|
||||
@param red - (`0...255`)
|
||||
@param green - (`0...255`)
|
||||
@param blue - (`0...255`)
|
||||
*/
|
||||
rgbToAnsi(red: number, green: number, blue: number): number;
|
||||
|
||||
/**
|
||||
Convert from the RGB HEX color space to the ANSI 16 color space.
|
||||
|
||||
@param hex - A hexadecimal string containing RGB data.
|
||||
*/
|
||||
hexToAnsi(hex: string): number;
|
||||
}
|
||||
|
||||
declare const ansiStyles: {
|
||||
readonly modifier: Modifier;
|
||||
readonly color: ColorBase & ForegroundColor;
|
||||
readonly bgColor: ColorBase & BackgroundColor;
|
||||
readonly codes: ReadonlyMap<number, number>;
|
||||
} & ForegroundColor &
|
||||
BackgroundColor &
|
||||
Modifier &
|
||||
ConvertColor;
|
||||
|
||||
export default ansiStyles;
|
||||
230
lib/util/chalk/ansi-styles/index.ts
Normal file
230
lib/util/chalk/ansi-styles/index.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
const ANSI_BACKGROUND_OFFSET = 10;
|
||||
|
||||
const wrapAnsi16 =
|
||||
(offset = 0) =>
|
||||
(code) =>
|
||||
`\u001B[${code + offset}m`;
|
||||
|
||||
const wrapAnsi256 =
|
||||
(offset = 0) =>
|
||||
(code) =>
|
||||
`\u001B[${38 + offset};5;${code}m`;
|
||||
|
||||
const wrapAnsi16m =
|
||||
(offset = 0) =>
|
||||
(red, green, blue) =>
|
||||
`\u001B[${38 + offset};2;${red};${green};${blue}m`;
|
||||
|
||||
function assembleStyles() {
|
||||
const codes = new Map();
|
||||
const styles = {
|
||||
modifier: {
|
||||
reset: [0, 0],
|
||||
// 21 isn't widely supported and 22 does the same thing
|
||||
bold: [1, 22],
|
||||
dim: [2, 22],
|
||||
italic: [3, 23],
|
||||
underline: [4, 24],
|
||||
overline: [53, 55],
|
||||
inverse: [7, 27],
|
||||
hidden: [8, 28],
|
||||
strikethrough: [9, 29],
|
||||
},
|
||||
color: {
|
||||
black: [30, 39],
|
||||
red: [31, 39],
|
||||
green: [32, 39],
|
||||
yellow: [33, 39],
|
||||
blue: [34, 39],
|
||||
magenta: [35, 39],
|
||||
cyan: [36, 39],
|
||||
white: [37, 39],
|
||||
|
||||
// Bright color
|
||||
blackBright: [90, 39],
|
||||
redBright: [91, 39],
|
||||
greenBright: [92, 39],
|
||||
yellowBright: [93, 39],
|
||||
blueBright: [94, 39],
|
||||
magentaBright: [95, 39],
|
||||
cyanBright: [96, 39],
|
||||
whiteBright: [97, 39],
|
||||
},
|
||||
bgColor: {
|
||||
bgBlack: [40, 49],
|
||||
bgRed: [41, 49],
|
||||
bgGreen: [42, 49],
|
||||
bgYellow: [43, 49],
|
||||
bgBlue: [44, 49],
|
||||
bgMagenta: [45, 49],
|
||||
bgCyan: [46, 49],
|
||||
bgWhite: [47, 49],
|
||||
|
||||
// Bright color
|
||||
bgBlackBright: [100, 49],
|
||||
bgRedBright: [101, 49],
|
||||
bgGreenBright: [102, 49],
|
||||
bgYellowBright: [103, 49],
|
||||
bgBlueBright: [104, 49],
|
||||
bgMagentaBright: [105, 49],
|
||||
bgCyanBright: [106, 49],
|
||||
bgWhiteBright: [107, 49],
|
||||
},
|
||||
};
|
||||
|
||||
// Alias bright black as gray (and grey)
|
||||
styles.color.gray = styles.color.blackBright;
|
||||
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
|
||||
styles.color.grey = styles.color.blackBright;
|
||||
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
|
||||
|
||||
for (const [groupName, group] of Object.entries(styles)) {
|
||||
for (const [styleName, style] of Object.entries(group)) {
|
||||
styles[styleName] = {
|
||||
open: `\u001B[${style[0]}m`,
|
||||
close: `\u001B[${style[1]}m`,
|
||||
};
|
||||
|
||||
group[styleName] = styles[styleName];
|
||||
|
||||
codes.set(style[0], style[1]);
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, groupName, {
|
||||
value: group,
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(styles, 'codes', {
|
||||
value: codes,
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
styles.color.close = '\u001B[39m';
|
||||
styles.bgColor.close = '\u001B[49m';
|
||||
|
||||
styles.color.ansi = wrapAnsi16();
|
||||
styles.color.ansi256 = wrapAnsi256();
|
||||
styles.color.ansi16m = wrapAnsi16m();
|
||||
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
||||
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
||||
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
||||
|
||||
// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
|
||||
Object.defineProperties(styles, {
|
||||
rgbToAnsi256: {
|
||||
value: (red, green, blue) => {
|
||||
// We use the extended greyscale palette here, with the exception of
|
||||
// black and white. normal palette only has 4 greyscale shades.
|
||||
if (red === green && green === blue) {
|
||||
if (red < 8) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (red > 248) {
|
||||
return 231;
|
||||
}
|
||||
|
||||
return Math.round(((red - 8) / 247) * 24) + 232;
|
||||
}
|
||||
|
||||
return (
|
||||
16 +
|
||||
36 * Math.round((red / 255) * 5) +
|
||||
6 * Math.round((green / 255) * 5) +
|
||||
Math.round((blue / 255) * 5)
|
||||
);
|
||||
},
|
||||
enumerable: false,
|
||||
},
|
||||
hexToRgb: {
|
||||
value: (hex) => {
|
||||
const matches = /(?<colorString>[a-f\d]{6}|[a-f\d]{3})/i.exec(hex.toString(16));
|
||||
if (!matches) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
|
||||
let { colorString } = matches.groups;
|
||||
|
||||
if (colorString.length === 3) {
|
||||
colorString = [...colorString].map((character) => character + character).join('');
|
||||
}
|
||||
|
||||
const integer = Number.parseInt(colorString, 16);
|
||||
|
||||
return [
|
||||
/* eslint-disable no-bitwise */
|
||||
(integer >> 16) & 0xff,
|
||||
(integer >> 8) & 0xff,
|
||||
integer & 0xff,
|
||||
/* eslint-enable no-bitwise */
|
||||
];
|
||||
},
|
||||
enumerable: false,
|
||||
},
|
||||
hexToAnsi256: {
|
||||
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
||||
enumerable: false,
|
||||
},
|
||||
ansi256ToAnsi: {
|
||||
value: (code) => {
|
||||
if (code < 8) {
|
||||
return 30 + code;
|
||||
}
|
||||
|
||||
if (code < 16) {
|
||||
return 90 + (code - 8);
|
||||
}
|
||||
|
||||
let red;
|
||||
let green;
|
||||
let blue;
|
||||
|
||||
if (code >= 232) {
|
||||
red = ((code - 232) * 10 + 8) / 255;
|
||||
green = red;
|
||||
blue = red;
|
||||
} else {
|
||||
code -= 16;
|
||||
|
||||
const remainder = code % 36;
|
||||
|
||||
red = Math.floor(code / 36) / 5;
|
||||
green = Math.floor(remainder / 6) / 5;
|
||||
blue = (remainder % 6) / 5;
|
||||
}
|
||||
|
||||
const value = Math.max(red, green, blue) * 2;
|
||||
|
||||
if (value === 0) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-bitwise
|
||||
let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));
|
||||
|
||||
if (value === 2) {
|
||||
result += 60;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
enumerable: false,
|
||||
},
|
||||
rgbToAnsi: {
|
||||
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
||||
enumerable: false,
|
||||
},
|
||||
hexToAnsi: {
|
||||
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
||||
enumerable: false,
|
||||
},
|
||||
});
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
const ansiStyles = assembleStyles();
|
||||
|
||||
export default ansiStyles;
|
||||
317
lib/util/chalk/index.d.ts
vendored
Normal file
317
lib/util/chalk/index.d.ts
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
// TODO: Make it this when TS suports that.
|
||||
// import {ColorInfo, ColorSupportLevel} from '#supports-color';
|
||||
import { ColorInfo, ColorSupportLevel } from './vendor/supports-color/index.js';
|
||||
|
||||
/**
|
||||
Basic foreground colors.
|
||||
|
||||
[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
|
||||
*/
|
||||
export type ForegroundColor =
|
||||
| 'black'
|
||||
| 'red'
|
||||
| 'green'
|
||||
| 'yellow'
|
||||
| 'blue'
|
||||
| 'magenta'
|
||||
| 'cyan'
|
||||
| 'white'
|
||||
| 'gray'
|
||||
| 'grey'
|
||||
| 'blackBright'
|
||||
| 'redBright'
|
||||
| 'greenBright'
|
||||
| 'yellowBright'
|
||||
| 'blueBright'
|
||||
| 'magentaBright'
|
||||
| 'cyanBright'
|
||||
| 'whiteBright';
|
||||
|
||||
/**
|
||||
Basic background colors.
|
||||
|
||||
[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
|
||||
*/
|
||||
export type BackgroundColor =
|
||||
| 'bgBlack'
|
||||
| 'bgRed'
|
||||
| 'bgGreen'
|
||||
| 'bgYellow'
|
||||
| 'bgBlue'
|
||||
| 'bgMagenta'
|
||||
| 'bgCyan'
|
||||
| 'bgWhite'
|
||||
| 'bgGray'
|
||||
| 'bgGrey'
|
||||
| 'bgBlackBright'
|
||||
| 'bgRedBright'
|
||||
| 'bgGreenBright'
|
||||
| 'bgYellowBright'
|
||||
| 'bgBlueBright'
|
||||
| 'bgMagentaBright'
|
||||
| 'bgCyanBright'
|
||||
| 'bgWhiteBright';
|
||||
|
||||
/**
|
||||
Basic colors.
|
||||
|
||||
[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
|
||||
*/
|
||||
export type Color = ForegroundColor | BackgroundColor;
|
||||
|
||||
export type Modifiers =
|
||||
| 'reset'
|
||||
| 'bold'
|
||||
| 'dim'
|
||||
| 'italic'
|
||||
| 'underline'
|
||||
| 'overline'
|
||||
| 'inverse'
|
||||
| 'hidden'
|
||||
| 'strikethrough'
|
||||
| 'visible';
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
Specify the color support for Chalk.
|
||||
|
||||
By default, color support is automatically detected based on the environment.
|
||||
|
||||
Levels:
|
||||
- `0` - All colors disabled.
|
||||
- `1` - Basic 16 colors support.
|
||||
- `2` - ANSI 256 colors support.
|
||||
- `3` - Truecolor 16 million colors support.
|
||||
*/
|
||||
readonly level?: ColorSupportLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
Return a new Chalk instance.
|
||||
*/
|
||||
export const Chalk: new (options?: Options) => ChalkInstance; // eslint-disable-line @typescript-eslint/naming-convention
|
||||
|
||||
export interface ChalkInstance {
|
||||
(...text: unknown[]): string;
|
||||
|
||||
/**
|
||||
The color support for Chalk.
|
||||
|
||||
By default, color support is automatically detected based on the environment.
|
||||
|
||||
Levels:
|
||||
- `0` - All colors disabled.
|
||||
- `1` - Basic 16 colors support.
|
||||
- `2` - ANSI 256 colors support.
|
||||
- `3` - Truecolor 16 million colors support.
|
||||
*/
|
||||
level: ColorSupportLevel;
|
||||
|
||||
/**
|
||||
Use RGB values to set text color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.rgb(222, 173, 237);
|
||||
```
|
||||
*/
|
||||
rgb: (red: number, green: number, blue: number) => this;
|
||||
|
||||
/**
|
||||
Use HEX value to set text color.
|
||||
|
||||
@param color - Hexadecimal value representing the desired color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.hex('#DEADED');
|
||||
```
|
||||
*/
|
||||
hex: (color: string) => this;
|
||||
|
||||
/**
|
||||
Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.ansi256(201);
|
||||
```
|
||||
*/
|
||||
ansi256: (index: number) => this;
|
||||
|
||||
/**
|
||||
Use RGB values to set background color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.bgRgb(222, 173, 237);
|
||||
```
|
||||
*/
|
||||
bgRgb: (red: number, green: number, blue: number) => this;
|
||||
|
||||
/**
|
||||
Use HEX value to set background color.
|
||||
|
||||
@param color - Hexadecimal value representing the desired color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.bgHex('#DEADED');
|
||||
```
|
||||
*/
|
||||
bgHex: (color: string) => this;
|
||||
|
||||
/**
|
||||
Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color.
|
||||
|
||||
@example
|
||||
```
|
||||
import chalk from 'chalk';
|
||||
|
||||
chalk.bgAnsi256(201);
|
||||
```
|
||||
*/
|
||||
bgAnsi256: (index: number) => this;
|
||||
|
||||
/**
|
||||
Modifier: Reset the current style.
|
||||
*/
|
||||
readonly reset: this;
|
||||
|
||||
/**
|
||||
Modifier: Make the text bold.
|
||||
*/
|
||||
readonly bold: this;
|
||||
|
||||
/**
|
||||
Modifier: Make the text have lower opacity.
|
||||
*/
|
||||
readonly dim: this;
|
||||
|
||||
/**
|
||||
Modifier: Make the text italic. *(Not widely supported)*
|
||||
*/
|
||||
readonly italic: this;
|
||||
|
||||
/**
|
||||
Modifier: Put a horizontal line below the text. *(Not widely supported)*
|
||||
*/
|
||||
readonly underline: this;
|
||||
|
||||
/**
|
||||
Modifier: Put a horizontal line above the text. *(Not widely supported)*
|
||||
*/
|
||||
readonly overline: this;
|
||||
|
||||
/**
|
||||
Modifier: Invert background and foreground colors.
|
||||
*/
|
||||
readonly inverse: this;
|
||||
|
||||
/**
|
||||
Modifier: Print the text but make it invisible.
|
||||
*/
|
||||
readonly hidden: this;
|
||||
|
||||
/**
|
||||
Modifier: Puts a horizontal line through the center of the text. *(Not widely supported)*
|
||||
*/
|
||||
readonly strikethrough: this;
|
||||
|
||||
/**
|
||||
Modifier: Print the text only when Chalk has a color level above zero.
|
||||
|
||||
Can be useful for things that are purely cosmetic.
|
||||
*/
|
||||
readonly visible: this;
|
||||
|
||||
readonly black: this;
|
||||
readonly red: this;
|
||||
readonly green: this;
|
||||
readonly yellow: this;
|
||||
readonly blue: this;
|
||||
readonly magenta: this;
|
||||
readonly cyan: this;
|
||||
readonly white: this;
|
||||
|
||||
/*
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly gray: this;
|
||||
|
||||
/*
|
||||
Alias for `blackBright`.
|
||||
*/
|
||||
readonly grey: this;
|
||||
|
||||
readonly blackBright: this;
|
||||
readonly redBright: this;
|
||||
readonly greenBright: this;
|
||||
readonly yellowBright: this;
|
||||
readonly blueBright: this;
|
||||
readonly magentaBright: this;
|
||||
readonly cyanBright: this;
|
||||
readonly whiteBright: this;
|
||||
|
||||
readonly bgBlack: this;
|
||||
readonly bgRed: this;
|
||||
readonly bgGreen: this;
|
||||
readonly bgYellow: this;
|
||||
readonly bgBlue: this;
|
||||
readonly bgMagenta: this;
|
||||
readonly bgCyan: this;
|
||||
readonly bgWhite: this;
|
||||
|
||||
/*
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGray: this;
|
||||
|
||||
/*
|
||||
Alias for `bgBlackBright`.
|
||||
*/
|
||||
readonly bgGrey: this;
|
||||
|
||||
readonly bgBlackBright: this;
|
||||
readonly bgRedBright: this;
|
||||
readonly bgGreenBright: this;
|
||||
readonly bgYellowBright: this;
|
||||
readonly bgBlueBright: this;
|
||||
readonly bgMagentaBright: this;
|
||||
readonly bgCyanBright: this;
|
||||
readonly bgWhiteBright: this;
|
||||
}
|
||||
|
||||
/**
|
||||
Main Chalk object that allows to chain styles together.
|
||||
|
||||
Call the last one as a method with a string argument.
|
||||
|
||||
Order doesn't matter, and later styles take precedent in case of a conflict.
|
||||
|
||||
This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`.
|
||||
*/
|
||||
declare const chalk: ChalkInstance;
|
||||
|
||||
export const supportsColor: ColorInfo;
|
||||
|
||||
export const chalkStderr: typeof chalk;
|
||||
export const supportsColorStderr: typeof supportsColor;
|
||||
|
||||
export {
|
||||
ColorInfo,
|
||||
ColorSupport,
|
||||
ColorSupportLevel, // } from '#supports-color';
|
||||
} from './vendor/supports-color/index.js';
|
||||
|
||||
export default chalk;
|
||||
218
lib/util/chalk/index.ts
Normal file
218
lib/util/chalk/index.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import ansiStyles from './ansi-styles';
|
||||
import supportsColor from './supports-color';
|
||||
import { stringReplaceAll, stringEncaseCRLFWithFirstIndex } from './utilities';
|
||||
import { ChalkInstance } from './index.d';
|
||||
|
||||
const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
|
||||
|
||||
const GENERATOR = Symbol('GENERATOR');
|
||||
const STYLER = Symbol('STYLER');
|
||||
const IS_EMPTY = Symbol('IS_EMPTY');
|
||||
|
||||
// `supportsColor.level` → `ansiStyles.color[name]` mapping
|
||||
const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
|
||||
|
||||
const styles = Object.create(null);
|
||||
|
||||
const applyOptions = (object, options = {}) => {
|
||||
if (
|
||||
options.level &&
|
||||
!(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)
|
||||
) {
|
||||
throw new Error('The `level` option should be an integer from 0 to 3');
|
||||
}
|
||||
|
||||
// Detect level if not set manually
|
||||
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
||||
object.level = options.level === undefined ? colorLevel : options.level;
|
||||
};
|
||||
|
||||
export class Chalk {
|
||||
constructor(options) {
|
||||
// eslint-disable-next-line no-constructor-return
|
||||
return chalkFactory(options);
|
||||
}
|
||||
}
|
||||
|
||||
const chalkFactory = (options) => {
|
||||
const chalk = (...strings) => strings.join(' ');
|
||||
applyOptions(chalk, options);
|
||||
|
||||
Object.setPrototypeOf(chalk, createChalk.prototype);
|
||||
|
||||
return chalk;
|
||||
};
|
||||
|
||||
function createChalk(options) {
|
||||
return chalkFactory(options);
|
||||
}
|
||||
|
||||
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
||||
|
||||
for (const [styleName, style] of Object.entries(ansiStyles)) {
|
||||
styles[styleName] = {
|
||||
get() {
|
||||
const builder = createBuilder(
|
||||
this,
|
||||
createStyler(style.open, style.close, this[STYLER]),
|
||||
this[IS_EMPTY]
|
||||
);
|
||||
Object.defineProperty(this, styleName, { value: builder });
|
||||
return builder;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
styles.visible = {
|
||||
get() {
|
||||
const builder = createBuilder(this, this[STYLER], true);
|
||||
Object.defineProperty(this, 'visible', { value: builder });
|
||||
return builder;
|
||||
},
|
||||
};
|
||||
|
||||
const getModelAnsi = (model, level, type, ...arguments_) => {
|
||||
if (model === 'rgb') {
|
||||
if (level === 'ansi16m') {
|
||||
return ansiStyles[type].ansi16m(...arguments_);
|
||||
}
|
||||
|
||||
if (level === 'ansi256') {
|
||||
return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
|
||||
}
|
||||
|
||||
return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
|
||||
}
|
||||
|
||||
if (model === 'hex') {
|
||||
return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));
|
||||
}
|
||||
|
||||
return ansiStyles[type][model](...arguments_);
|
||||
};
|
||||
|
||||
const usedModels = ['rgb', 'hex', 'ansi256'];
|
||||
|
||||
for (const model of usedModels) {
|
||||
styles[model] = {
|
||||
get() {
|
||||
const { level } = this;
|
||||
return function (...arguments_) {
|
||||
const styler = createStyler(
|
||||
getModelAnsi(model, levelMapping[level], 'color', ...arguments_),
|
||||
ansiStyles.color.close,
|
||||
this[STYLER]
|
||||
);
|
||||
return createBuilder(this, styler, this[IS_EMPTY]);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
|
||||
styles[bgModel] = {
|
||||
get() {
|
||||
const { level } = this;
|
||||
return function (...arguments_) {
|
||||
const styler = createStyler(
|
||||
getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_),
|
||||
ansiStyles.bgColor.close,
|
||||
this[STYLER]
|
||||
);
|
||||
return createBuilder(this, styler, this[IS_EMPTY]);
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const proto = Object.defineProperties(() => {}, {
|
||||
...styles,
|
||||
level: {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return this[GENERATOR].level;
|
||||
},
|
||||
set(level) {
|
||||
this[GENERATOR].level = level;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const createStyler = (open, close, parent) => {
|
||||
let openAll;
|
||||
let closeAll;
|
||||
if (parent === undefined) {
|
||||
openAll = open;
|
||||
closeAll = close;
|
||||
} else {
|
||||
openAll = parent.openAll + open;
|
||||
closeAll = close + parent.closeAll;
|
||||
}
|
||||
|
||||
return {
|
||||
open,
|
||||
close,
|
||||
openAll,
|
||||
closeAll,
|
||||
parent,
|
||||
};
|
||||
};
|
||||
|
||||
const createBuilder = (self, _styler, _isEmpty) => {
|
||||
// Single argument is hot path, implicit coercion is faster than anything
|
||||
// eslint-disable-next-line no-implicit-coercion
|
||||
const builder = (...arguments_) =>
|
||||
applyStyle(builder, arguments_.length === 1 ? '' + arguments_[0] : arguments_.join(' '));
|
||||
|
||||
// We alter the prototype because we must return a function, but there is
|
||||
// no way to create a function with a different prototype
|
||||
Object.setPrototypeOf(builder, proto);
|
||||
|
||||
builder[GENERATOR] = self;
|
||||
builder[STYLER] = _styler;
|
||||
builder[IS_EMPTY] = _isEmpty;
|
||||
|
||||
return builder;
|
||||
};
|
||||
|
||||
const applyStyle = (self, string) => {
|
||||
if (self.level <= 0 || !string) {
|
||||
return self[IS_EMPTY] ? '' : string;
|
||||
}
|
||||
|
||||
let styler = self[STYLER];
|
||||
|
||||
if (styler === undefined) {
|
||||
return string;
|
||||
}
|
||||
|
||||
const { openAll, closeAll } = styler;
|
||||
if (string.includes('\u001B')) {
|
||||
while (styler !== undefined) {
|
||||
// Replace any instances already present with a re-opening code
|
||||
// otherwise only the part of the string until said closing code
|
||||
// will be colored, and the rest will simply be 'plain'.
|
||||
string = stringReplaceAll(string, styler.close, styler.open);
|
||||
|
||||
styler = styler.parent;
|
||||
}
|
||||
}
|
||||
|
||||
// We can move both next actions out of loop, because remaining actions in loop won't have
|
||||
// any/visible effect on parts we add here. Close the styling before a linebreak and reopen
|
||||
// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92
|
||||
const lfIndex = string.indexOf('\n');
|
||||
if (lfIndex !== -1) {
|
||||
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
||||
}
|
||||
|
||||
return openAll + string + closeAll;
|
||||
};
|
||||
|
||||
Object.defineProperties(createChalk.prototype, styles);
|
||||
|
||||
const chalk: ChalkInstance = createChalk();
|
||||
export const chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
||||
|
||||
export { stdoutColor as supportsColor, stderrColor as supportsColorStderr };
|
||||
|
||||
export default chalk;
|
||||
1
lib/util/chalk/supports-color/index.d.ts
vendored
Normal file
1
lib/util/chalk/supports-color/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './index.js';
|
||||
19
lib/util/chalk/supports-color/index.ts
Normal file
19
lib/util/chalk/supports-color/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-env browser */
|
||||
|
||||
const isBlinkBasedBrowser = /\b(Chrome|Chromium)\//.test(navigator.userAgent);
|
||||
|
||||
const colorSupport = isBlinkBasedBrowser
|
||||
? {
|
||||
level: 1,
|
||||
hasBasic: true,
|
||||
has256: false,
|
||||
has16m: false,
|
||||
}
|
||||
: false;
|
||||
|
||||
const supportsColor = {
|
||||
stdout: colorSupport,
|
||||
stderr: colorSupport,
|
||||
};
|
||||
|
||||
export default supportsColor;
|
||||
37
lib/util/chalk/utilities.ts
Normal file
37
lib/util/chalk/utilities.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.
|
||||
export function stringReplaceAll(string, substring, replacer) {
|
||||
let index = string.indexOf(substring);
|
||||
if (index === -1) {
|
||||
return string;
|
||||
}
|
||||
|
||||
const substringLength = substring.length;
|
||||
let endIndex = 0;
|
||||
let returnValue = '';
|
||||
do {
|
||||
returnValue += string.substr(endIndex, index - endIndex) + substring + replacer;
|
||||
endIndex = index + substringLength;
|
||||
index = string.indexOf(substring, endIndex);
|
||||
} while (index !== -1);
|
||||
|
||||
returnValue += string.slice(endIndex);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
export function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
||||
let endIndex = 0;
|
||||
let returnValue = '';
|
||||
do {
|
||||
const gotCR = string[index - 1] === '\r';
|
||||
returnValue +=
|
||||
string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) +
|
||||
prefix +
|
||||
(gotCR ? '\r\n' : '\n') +
|
||||
postfix;
|
||||
endIndex = index + 1;
|
||||
index = string.indexOf('\n', endIndex);
|
||||
} while (index !== -1);
|
||||
|
||||
returnValue += string.slice(endIndex);
|
||||
return returnValue;
|
||||
}
|
||||
14
lib/util/cookie.ts
Normal file
14
lib/util/cookie.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as CookiesJs from 'js-cookie';
|
||||
export const Cookies = {
|
||||
get(key?: any) {
|
||||
return CookiesJs.default.get(key) || sessionStorage.getItem(key);
|
||||
},
|
||||
set(key: any, value: string, params?: Recordable) {
|
||||
CookiesJs.default.set(key, value);
|
||||
return sessionStorage.setItem(key, value);
|
||||
},
|
||||
remove(key: any) {
|
||||
CookiesJs.default.remove(key);
|
||||
sessionStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
20
lib/util/date-util.ts
Normal file
20
lib/util/date-util.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 时间格式函数, Day.js
|
||||
*/
|
||||
import 'dayjs/locale/zh-cn';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm';
|
||||
const DATE_FORMAT = 'YYYY-MM-DD ';
|
||||
|
||||
export function formatToDateTime(date: dayjs.ConfigType, format = DATE_TIME_FORMAT): string {
|
||||
return dayjs(date).format(format);
|
||||
}
|
||||
|
||||
export function formatToDate(date: dayjs.ConfigType, format = DATE_FORMAT): string {
|
||||
return dayjs(date).format(format);
|
||||
}
|
||||
|
||||
export const dateUtil = dayjs;
|
||||
0
lib/util/env.ts
Normal file
0
lib/util/env.ts
Normal file
21
lib/util/http/axios.d.ts
vendored
Normal file
21
lib/util/http/axios.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
export interface Result<T = any> {
|
||||
code: number;
|
||||
success: true | false;
|
||||
requestId: string;
|
||||
msg?: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
// multipart/form-data: upload file
|
||||
export interface UploadFileParams {
|
||||
// Other parameters
|
||||
data?: Recordable;
|
||||
// File parameter interface field name
|
||||
name?: string;
|
||||
// file name
|
||||
file: File | Blob;
|
||||
// file name
|
||||
filename?: string;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
203
lib/util/http/axios.ts
Normal file
203
lib/util/http/axios.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import axios from 'axios';
|
||||
import type { Result } from './axios.d';
|
||||
import { NsMessage } from '/nerv-lib/component/message';
|
||||
import { routerConfig } from '/nerv-base/config/router.config';
|
||||
import { Cookies } from '/nerv-lib/util/cookie';
|
||||
export class NSAxios {
|
||||
private instance: AxiosInstance;
|
||||
private readonly options: AxiosRequestConfig;
|
||||
public apiModule: any = {};
|
||||
public projectType = 'web';
|
||||
public errorMsgKey = 'axiosError'; // 接口错误值有一个提示消息
|
||||
|
||||
constructor(options: AxiosRequestConfig) {
|
||||
this.options = options;
|
||||
this.instance = axios.create(this.options);
|
||||
// this.getModuleList(ApiModule);
|
||||
this.interceptors();
|
||||
}
|
||||
|
||||
public setTimeout(timeout: number) {
|
||||
this.options.timeout = timeout;
|
||||
this.instance = axios.create(this.options);
|
||||
this.interceptors();
|
||||
}
|
||||
public setHeaders(headers: any) {
|
||||
this.options.headers = Object.assign(this.options.headers, headers);
|
||||
this.instance = axios.create(this.options);
|
||||
this.interceptors();
|
||||
}
|
||||
|
||||
private get modules(): Recordable {
|
||||
const list: Recordable = {};
|
||||
Object.keys(this.apiModule).forEach((app) => {
|
||||
this.apiModule[app].forEach((item: string) => {
|
||||
list[item] = app;
|
||||
});
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
private interceptors(): void {
|
||||
this.instance.interceptors.request.use((config: AxiosRequestConfig) => {
|
||||
// config.headers.token = Cookies.get('nervsid');
|
||||
// config.withCredentials = true;
|
||||
if (!config.headers) {
|
||||
config.headers = {};
|
||||
}
|
||||
|
||||
if (Cookies.get('nervsid')) {
|
||||
config.headers['x-token'] = Cookies.get('nervsid');
|
||||
}
|
||||
|
||||
//暂时停用后端自己处理
|
||||
// const projectId = sessionStorage.getItem('projectId');
|
||||
//
|
||||
// if (projectId) {
|
||||
// config.headers['X-Nerv-Auth'] = `projectId="${projectId}"`;
|
||||
// }
|
||||
|
||||
const { url } = config;
|
||||
|
||||
if (url && !url.startsWith('http')) {
|
||||
if (!url.startsWith('/')) {
|
||||
let module = '';
|
||||
if (url.includes('/')) module = url.split('/')[0];
|
||||
if (this.modules.hasOwnProperty(module))
|
||||
config.url = `/api/${this.modules[module]}/objs/${url}`;
|
||||
}
|
||||
|
||||
if (this.projectType !== 'web') config.url = `/${this.projectType}/${url}`;
|
||||
}
|
||||
// let newUrl = url as string;
|
||||
// if (config.method === 'get' && config.params) {
|
||||
// newUrl += '?';
|
||||
// const keys = Object.keys(config.params);
|
||||
// for (const key of keys) {
|
||||
// if (config.params[key] !== undefined) {
|
||||
// newUrl += `${key}=${encodeURIComponent(config.params[key])}&`;
|
||||
// }
|
||||
// }
|
||||
// newUrl = newUrl.substring(0, newUrl.length - 1);
|
||||
// config.params = {};
|
||||
// }
|
||||
// config.url = newUrl;
|
||||
return config;
|
||||
}, undefined);
|
||||
|
||||
this.instance.interceptors.response.use(
|
||||
(res: AxiosResponse) => {
|
||||
return res;
|
||||
},
|
||||
(error: any) => {
|
||||
console.log('error', error);
|
||||
const { response, code, message } = error || {};
|
||||
const msg: string = (response?.data?.msg || response?.data?.message) ?? '';
|
||||
const err: string = error?.toString?.() ?? '';
|
||||
let errMessage = response?.data || '';
|
||||
try {
|
||||
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
||||
errMessage = '接口请求超时,请刷新页面重试!';
|
||||
}
|
||||
if (err?.includes('Network Error')) {
|
||||
errMessage = '网络异常,请检查您的网络连接是否正常!';
|
||||
}
|
||||
if (errMessage && !msg) {
|
||||
NsMessage.error({ content: errMessage, key: this.errorMsgKey });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error as string);
|
||||
}
|
||||
switch (error?.response?.status) {
|
||||
case 403:
|
||||
errMessage = '用户没有权限';
|
||||
//sass项目判断用户是否需要重新登录
|
||||
if (response?.data?.code === 'idass.account.NeedLogin') {
|
||||
routerConfig.logout();
|
||||
}
|
||||
if (response?.data?.code === 'idass.account.OrganizationDisable') {
|
||||
routerConfig.logout();
|
||||
}
|
||||
if (response?.config?.url.includes('CheckAuthorization')) {
|
||||
routerConfig.logout();
|
||||
}
|
||||
break;
|
||||
case 404:
|
||||
errMessage = '链接不存在';
|
||||
break;
|
||||
default:
|
||||
errMessage = msg;
|
||||
}
|
||||
if (errMessage) {
|
||||
if (response?.data?.code === 'idass.account.AccountPwdCheckFail') {
|
||||
// NsMessage.error('原密码错误');
|
||||
NsMessage.error({ content: errMessage, key: this.errorMsgKey });
|
||||
} else {
|
||||
if (response.data.fieldErrors !== undefined) {
|
||||
NsMessage.error({
|
||||
content: JSON.stringify(response.data.fieldErrors).substring(
|
||||
1,
|
||||
JSON.stringify(response.data.fieldErrors).length - 1,
|
||||
),
|
||||
key: this.errorMsgKey,
|
||||
});
|
||||
} else {
|
||||
NsMessage.error({ content: errMessage, key: this.errorMsgKey });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// NsMessage.error(error?.response.data?.error, 1);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
request<T = any>(config: AxiosRequestConfig): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
.request<any, AxiosResponse<Result>>(config)
|
||||
.then((res: AxiosResponse<Result>) => {
|
||||
resolve(res.data as unknown as Promise<T>);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
customRequest<T = any>(config: AxiosRequestConfig): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
.request<any, AxiosResponse<Result>>(config)
|
||||
.then((res: AxiosResponse<Result>) => {
|
||||
resolve(res as unknown as Promise<T>);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request({ url, params, ...config, method: 'GET' });
|
||||
}
|
||||
|
||||
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request({ url, data, ...config, method: 'POST' });
|
||||
}
|
||||
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request({ url, data, ...config, method: 'PUT' });
|
||||
}
|
||||
|
||||
delete<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.request({ url, data, ...config, method: 'DELETE' });
|
||||
}
|
||||
customPost<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.customRequest({ url, data, ...config, method: 'POST' });
|
||||
}
|
||||
customGet<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
|
||||
return this.customRequest({ url, params, ...config, method: 'GET' });
|
||||
}
|
||||
}
|
||||
10
lib/util/http/index.ts
Normal file
10
lib/util/http/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { NSAxios } from './axios';
|
||||
|
||||
function createHttp() {
|
||||
return new NSAxios({
|
||||
headers: { 'Content-Type': 'application/json;charset=UTF-8' },
|
||||
withCredentials: false,
|
||||
timeout: 3 * 1000,
|
||||
});
|
||||
}
|
||||
export const http = createHttp();
|
||||
10
lib/util/index.ts
Normal file
10
lib/util/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from './install';
|
||||
export * from './type';
|
||||
export * from './http';
|
||||
export * from './string-util';
|
||||
export * from './unit-util';
|
||||
export * from './xlsx-util';
|
||||
export * from './date-util';
|
||||
export * from './log';
|
||||
export * from './system';
|
||||
export * from './chalk';
|
||||
9
lib/util/install.ts
Normal file
9
lib/util/install.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { App, Plugin } from 'vue';
|
||||
export const withInstall = <T>(comp: T) => {
|
||||
const c = comp as any;
|
||||
c.install = function (app: App) {
|
||||
app.component(c.displayName || c.name, comp);
|
||||
};
|
||||
|
||||
return comp as T & Plugin;
|
||||
};
|
||||
20
lib/util/jsoneditor.js
Normal file
20
lib/util/jsoneditor.js
Normal file
File diff suppressed because one or more lines are too long
26
lib/util/log.ts
Normal file
26
lib/util/log.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import log from 'loglevel';
|
||||
import chalk from './chalk';
|
||||
import prefix from 'loglevel-plugin-prefix';
|
||||
const colors: any = {
|
||||
TRACE: chalk.magenta,
|
||||
DEBUG: chalk.cyan,
|
||||
INFO: chalk.blue,
|
||||
WARN: chalk.yellow,
|
||||
ERROR: chalk.red,
|
||||
};
|
||||
prefix.reg(log);
|
||||
log.enableAll();
|
||||
prefix.apply(log, {
|
||||
format(level, name, timestamp) {
|
||||
return `${chalk.gray(`[${timestamp}]`)} ${colors[level.toUpperCase()](level)} ${chalk.green(
|
||||
`${name}:`
|
||||
)}`;
|
||||
},
|
||||
});
|
||||
|
||||
// prefix.apply(log.getLogger('critical'), {
|
||||
// format(level, name, timestamp) {
|
||||
// return chalk.red.bold(`[${timestamp}] ${level} ${name}:`);
|
||||
// },
|
||||
// });
|
||||
export { log };
|
||||
51
lib/util/lowcodeMyApp.ts
Normal file
51
lib/util/lowcodeMyApp.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Used to monitor routing changes to change the status of menus and tabs. There is no need to monitor the route, because the route status change is affected by the page rendering time, which will be slow
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import mitt from './mitt';
|
||||
|
||||
const emitter = mitt();
|
||||
const key = Symbol();
|
||||
let appInfo;
|
||||
export function getAppInfo(appInfo) {
|
||||
if (!appInfo) return appInfo;
|
||||
return appInfo;
|
||||
// const { matched, ...opt } = appInfo;
|
||||
// return {
|
||||
// ...opt,
|
||||
// matched: (matched
|
||||
// ? matched.map((item) => ({
|
||||
// meta: item.meta,
|
||||
// name: item.name,
|
||||
// path: item.path,
|
||||
// }))
|
||||
// : undefined) as RouteRecordNormalized[],
|
||||
// };
|
||||
}
|
||||
|
||||
export function setAppClickChange(info) {
|
||||
const r = getAppInfo(info);
|
||||
emitter.emit(key, r);
|
||||
appInfo = r;
|
||||
}
|
||||
export function listenerAppClickChange(callback: (val) => void) {
|
||||
emitter.on(key, callback);
|
||||
// appInfo && callback(appInfo);
|
||||
}
|
||||
|
||||
export function removeAppClickChangeListener() {
|
||||
emitter.clear();
|
||||
}
|
||||
|
||||
//防抖函数
|
||||
type CallbackFn = (item?: any) => void;
|
||||
|
||||
let timer: any = null;
|
||||
export function useDebounce(Callback: CallbackFn, delay = 500) {
|
||||
timer != null ? clearTimeout(timer) : null;
|
||||
timer = setTimeout(() => {
|
||||
Callback && Callback(); //当有值才会执行
|
||||
}, delay);
|
||||
}
|
||||
103
lib/util/mitt.ts
Normal file
103
lib/util/mitt.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* copy to https://github.com/developit/mitt
|
||||
* Expand clear method
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
export type EventType = string | symbol;
|
||||
|
||||
// An event handler can take an optional event argument
|
||||
// and should not return a value
|
||||
export type Handler<T = any> = (event?: T) => void;
|
||||
export type WildcardHandler = (type: EventType, event?: any) => void;
|
||||
|
||||
// An array of all currently registered event handlers for a type
|
||||
export type EventHandlerList = Array<Handler>;
|
||||
export type WildCardEventHandlerList = Array<WildcardHandler>;
|
||||
|
||||
// A map of event types and their corresponding event handlers.
|
||||
export type EventHandlerMap = Map<EventType, EventHandlerList | WildCardEventHandlerList>;
|
||||
|
||||
export interface Emitter {
|
||||
all: EventHandlerMap;
|
||||
|
||||
on<T = any>(type: EventType, handler: Handler<T>): void;
|
||||
on(type: '*', handler: WildcardHandler): void;
|
||||
|
||||
off<T = any>(type: EventType, handler: Handler<T>): void;
|
||||
off(type: '*', handler: WildcardHandler): void;
|
||||
|
||||
emit<T = any>(type: EventType, event?: T): void;
|
||||
emit(type: '*', event?: any): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mitt: Tiny (~200b) functional event emitter / pubsub.
|
||||
* @name mitt
|
||||
* @returns {Mitt}
|
||||
*/
|
||||
export default function mitt(all?: EventHandlerMap): Emitter {
|
||||
all = all || new Map();
|
||||
|
||||
return {
|
||||
/**
|
||||
* A Map of event names to registered handler functions.
|
||||
*/
|
||||
all,
|
||||
|
||||
/**
|
||||
* Register an event handler for the given type.
|
||||
* @param {string|symbol} type Type of event to listen for, or `"*"` for all events
|
||||
* @param {Function} handler Function to call in response to given event
|
||||
* @memberOf mitt
|
||||
*/
|
||||
on<T = any>(type: EventType, handler: Handler<T>) {
|
||||
const handlers = all?.get(type);
|
||||
const added = handlers && handlers.push(handler);
|
||||
if (!added) {
|
||||
all?.set(type, [handler]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an event handler for the given type.
|
||||
* @param {string|symbol} type Type of event to unregister `handler` from, or `"*"`
|
||||
* @param {Function} handler Handler function to remove
|
||||
* @memberOf mitt
|
||||
*/
|
||||
off<T = any>(type: EventType, handler: Handler<T>) {
|
||||
const handlers = all?.get(type);
|
||||
if (handlers) {
|
||||
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoke all handlers for the given type.
|
||||
* If present, `"*"` handlers are invoked after type-matched handlers.
|
||||
*
|
||||
* Note: Manually firing "*" handlers is not supported.
|
||||
*
|
||||
* @param {string|symbol} type The event type to invoke
|
||||
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
|
||||
* @memberOf mitt
|
||||
*/
|
||||
emit<T = any>(type: EventType, evt: T) {
|
||||
((all?.get(type) || []) as EventHandlerList).slice().map((handler) => {
|
||||
handler(evt);
|
||||
});
|
||||
((all?.get('*') || []) as WildCardEventHandlerList).slice().map((handler) => {
|
||||
handler(type, evt);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all
|
||||
*/
|
||||
clear() {
|
||||
this.all.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
53
lib/util/routeChange.ts
Normal file
53
lib/util/routeChange.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Used to monitor routing changes to change the status of menus and tabs. There is no need to monitor the route, because the route status change is affected by the page rendering time, which will be slow
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import mitt from './mitt';
|
||||
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
||||
|
||||
const emitter = mitt();
|
||||
|
||||
const key = Symbol();
|
||||
const reloadKey = Symbol();
|
||||
|
||||
let lastChangeTab: RouteLocationNormalized;
|
||||
|
||||
export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized {
|
||||
if (!route) return route;
|
||||
const { matched, ...opt } = route;
|
||||
return {
|
||||
...opt,
|
||||
matched: (matched
|
||||
? matched.map((item) => ({
|
||||
meta: item.meta,
|
||||
name: item.name,
|
||||
path: item.path,
|
||||
}))
|
||||
: undefined) as RouteRecordNormalized[],
|
||||
};
|
||||
}
|
||||
export function setReloadChange() {
|
||||
emitter.emit(reloadKey);
|
||||
}
|
||||
export function listenerReloadChange(callback: () => void, immediate = true) {
|
||||
emitter.on(reloadKey, callback);
|
||||
immediate && callback();
|
||||
}
|
||||
export function setRouteChange(lastChangeRoute: RouteLocationNormalized) {
|
||||
const r = getRawRoute(lastChangeRoute);
|
||||
emitter.emit(key, r);
|
||||
lastChangeTab = r;
|
||||
}
|
||||
export function listenerRouteChange(
|
||||
callback: (route: RouteLocationNormalized) => void,
|
||||
immediate = true,
|
||||
) {
|
||||
emitter.on(key, callback);
|
||||
immediate && lastChangeTab && callback(lastChangeTab);
|
||||
}
|
||||
|
||||
export function removeTabChangeListener() {
|
||||
emitter.clear();
|
||||
}
|
||||
23
lib/util/string-util.ts
Normal file
23
lib/util/string-util.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export const stringUtil = {
|
||||
// 首写字母大写
|
||||
firstToUpper: (str: String) => {
|
||||
return str.trim().replace(str[0], str[0].toUpperCase());
|
||||
},
|
||||
// 首写字母小写
|
||||
firstToLower: (str: String) => {
|
||||
return str.trim().replace(str[0], str[0].toLowerCase());
|
||||
},
|
||||
|
||||
// 下划线转换驼峰
|
||||
toHump: (str: string) => {
|
||||
return str.replace(/\_(\w)/g, function (all, letter) {
|
||||
return letter.toUpperCase();
|
||||
});
|
||||
},
|
||||
|
||||
// 驼峰转换下划线
|
||||
toLine: (str: string) => {
|
||||
let newStr = str.replace(/([A-Z])/g, '_$1').toLowerCase();
|
||||
return newStr.startsWith('_') ? newStr.replace('_', '') : newStr;
|
||||
},
|
||||
};
|
||||
17
lib/util/system.ts
Normal file
17
lib/util/system.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
import { log } from './log';
|
||||
export const systemInfo = () => {
|
||||
//ver${__APP_INFO__.pkg.version} 暂时不用pack
|
||||
log.info(`The ${import.meta.env.VITE_GLOB_APP_TITLE} compiled at ${__APP_INFO__.buildTime}.`);
|
||||
};
|
||||
export const getLocalSetting = () => {
|
||||
return JSON.parse(localStorage.getItem(import.meta.env.VITE_GLOB_APP_TITLE)) || {};
|
||||
};
|
||||
export const setLocalSetting = (setting) => {
|
||||
const _setting = getLocalSetting() || {};
|
||||
return localStorage.setItem(
|
||||
import.meta.env.VITE_GLOB_APP_TITLE,
|
||||
JSON.stringify(Object.assign(_setting, setting)),
|
||||
);
|
||||
};
|
||||
90
lib/util/type.ts
Normal file
90
lib/util/type.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import type { CSSProperties, VNodeChild, PropType } from 'vue';
|
||||
import type { VueTypeValidableDef, VueTypesInterface } from 'vue-types';
|
||||
import type { RouteComponent, RouteRecordRaw } from 'vue-router';
|
||||
import { createTypes } from 'vue-types';
|
||||
|
||||
type VueNode = VNodeChild | JSX.Element;
|
||||
|
||||
const propTypes = createTypes({
|
||||
func: undefined,
|
||||
bool: undefined,
|
||||
string: undefined,
|
||||
number: undefined,
|
||||
array: undefined,
|
||||
object: undefined,
|
||||
integer: undefined,
|
||||
});
|
||||
//
|
||||
// propTypes.extend([
|
||||
// {
|
||||
// name: 'looseBool',
|
||||
// getter: true,
|
||||
// type: Boolean,
|
||||
// default: undefined,
|
||||
// },
|
||||
// {
|
||||
// name: 'style',
|
||||
// getter: true,
|
||||
// type: [String, Object],
|
||||
// default: undefined,
|
||||
// },
|
||||
// {
|
||||
// name: 'VNodeChild',
|
||||
// getter: true,
|
||||
// type: undefined,
|
||||
// },
|
||||
// ]);
|
||||
//
|
||||
//
|
||||
function withUndefined<T extends { default?: any }>(type: T): T {
|
||||
type.default = undefined;
|
||||
return type;
|
||||
}
|
||||
const PropTypes = propTypes as VueTypesInterface & {
|
||||
readonly looseBool: VueTypeValidableDef<boolean>;
|
||||
readonly style: VueTypeValidableDef<CSSProperties>;
|
||||
readonly VNodeChild: VueTypeValidableDef<VueNode>;
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/questions/46176165/ways-to-get-string-literal-type-of-array-values-without-enum-overhead
|
||||
export const tuple = <T extends string[]>(...args: T) => args;
|
||||
|
||||
export const tupleNum = <T extends number[]>(...args: T) => args;
|
||||
|
||||
/**
|
||||
* https://stackoverflow.com/a/59187769
|
||||
* Extract the type of an element of an array/tuple without performing indexing
|
||||
*/
|
||||
export type ElementOf<T> = T extends (infer E)[] ? E : T extends readonly (infer F)[] ? F : never;
|
||||
|
||||
/**
|
||||
* https://github.com/Microsoft/TypeScript/issues/29729
|
||||
*/
|
||||
export type LiteralUnion<T extends U, U> = T | (U & {});
|
||||
|
||||
type DefaultFactory<T> = (props: Data) => T | null | undefined;
|
||||
|
||||
export interface PropOptions<T = any, D = T> {
|
||||
type?: PropType<T> | true | null;
|
||||
required?: boolean;
|
||||
default?: D | DefaultFactory<D> | null | undefined | object;
|
||||
validator?(value: unknown): boolean;
|
||||
}
|
||||
|
||||
interface RouteMeta {
|
||||
title: string; // 标题
|
||||
icon?: string; // 图标
|
||||
requiresAuth?: boolean;
|
||||
hideChildren?: boolean; // 是否不显示孩子菜单
|
||||
}
|
||||
declare type Lazy<T> = () => Promise<T>;
|
||||
|
||||
interface NsRouteRecordRaw extends Omit<Omit<RouteRecordRaw, 'children'>, 'meta'> {
|
||||
name: string;
|
||||
meta: RouteMeta;
|
||||
component?: Lazy<RouteComponent>;
|
||||
children?: NsRouteRecordRaw[];
|
||||
props?: Recordable;
|
||||
}
|
||||
|
||||
export { VueNode, PropTypes, NsRouteRecordRaw, withUndefined };
|
||||
174
lib/util/unit-util.ts
Normal file
174
lib/util/unit-util.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
export class unitTransfer {
|
||||
//单位进制
|
||||
unitConfig = {
|
||||
B: ['B', 'KB', 'MB', 'GB', 'TB', 'PB'],
|
||||
b: ['b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb'],
|
||||
// def: ['', 'K', 'mill', 'bill', 'trill'],
|
||||
def: ['', 'K', 'M', 'B', 'T', 'Q'],
|
||||
}
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 单位转换,统一用于监控指标的单位换算问题
|
||||
* @param value 数值
|
||||
* @param unit 单位
|
||||
* @param params {tagUnit:想要转化到的单位级别,unitDisplay:是否需要输出单位}
|
||||
*/
|
||||
unitTransfom(value, unit?, params?: {tagUnit?:string,unitDisplay?:boolean}) {
|
||||
if (!value || typeof (value) != 'number') {
|
||||
return value;
|
||||
}
|
||||
if ([undefined, null, ''].indexOf(unit) != -1) {
|
||||
unit = ''
|
||||
}
|
||||
let index = unit.indexOf('/');
|
||||
let moreUnit = '';
|
||||
let resultValue;
|
||||
let tagUnit;
|
||||
let unitDisplay = true;
|
||||
if (params) {
|
||||
tagUnit = params['tagUnit'] || null;
|
||||
unitDisplay = params['unitDisplay'] || true;
|
||||
}
|
||||
if (index > 0) {
|
||||
moreUnit = unit.substring(index);
|
||||
unit = unit.split('/')[0];
|
||||
}
|
||||
|
||||
if (unit == '%') {
|
||||
resultValue = value + unit;
|
||||
}
|
||||
if (this.unitConfig.def.indexOf(unit) > -1 || unit == 'nub') {
|
||||
unit === 'nub' ? unit = '' : '';
|
||||
resultValue = this.formatterFun(value, 'def', { 'tagUnit': tagUnit, 'defaulUnit': unit })
|
||||
}
|
||||
if (this.unitConfig.B.indexOf(unit) > -1) {
|
||||
resultValue = this.formatterFun(value, 'B', { 'defaulvalue': 1024, 'tagUnit': tagUnit, 'defaulUnit': unit }) + moreUnit;
|
||||
}
|
||||
if (this.unitConfig.b.indexOf(unit) > -1) {
|
||||
resultValue = this.formatterFun(value, 'b', { 'defaulvalue': 1024, 'tagUnit': tagUnit, 'defaulUnit': unit }) + moreUnit;
|
||||
}
|
||||
if (unit == 'cnt') {
|
||||
resultValue = this.formatterFun(value, 'def', { 'defaulvalue': 1000, 'defaulUnit': '' }) + '个' + moreUnit;
|
||||
}
|
||||
if (unit == 'ms' || unit == 's') {
|
||||
resultValue = this.Flavorunit(value, unit) + moreUnit;
|
||||
}
|
||||
if (unit == 'bout') {
|
||||
resultValue = this.formatterFun(value, 'def', { 'defaulvalue': 1000, 'defaulUnit': '' }) + '次' + moreUnit;
|
||||
}
|
||||
|
||||
//判断需不需要输出单位
|
||||
if (!unitDisplay) {
|
||||
resultValue = resultValue.replace(/[^0-9,.]*/ig, '');
|
||||
}
|
||||
return resultValue
|
||||
|
||||
}
|
||||
/**
|
||||
* 此处为时间的单位转换
|
||||
* @param value
|
||||
* @param unit
|
||||
*/
|
||||
Flavorunit(value, unit?) {
|
||||
if (value >= 1000 && unit == 'ms') {
|
||||
unit = 's';
|
||||
value = (value / 1000).toFixed(2);
|
||||
}
|
||||
if (value >= 60 && unit == 's') {
|
||||
unit = 'min';
|
||||
value = (value / 60).toFixed(2);
|
||||
}
|
||||
if (value >= 60 && unit == 'min') {
|
||||
unit = 'h';
|
||||
value = (value / 60).toFixed(2);
|
||||
}
|
||||
if (value >= 24 && unit == 'h') {
|
||||
unit = 'd';
|
||||
value = (value / 24).toFixed(2);
|
||||
}
|
||||
return Number(value) + unit;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value 数值
|
||||
* @param unit 单位类别,如果没有默认单位,也可以作为默认单位
|
||||
* @param params {
|
||||
* defaulvalue 默认进制的值,没有值取1000,
|
||||
* defaulUnit 起步单位,没有的话使用单位类别的值作为默认单位,
|
||||
* tagUnit 目标单位,需要转化到改单位
|
||||
* point 保留小数几位
|
||||
* }
|
||||
*/
|
||||
formatterFun(value, unit, params?: {}) {
|
||||
let defaulvalue, defaulUnit, tagUnit, point
|
||||
if (params) {
|
||||
defaulvalue = params['defaulvalue'] ? params['defaulvalue'] : 1000;
|
||||
defaulUnit = params['defaulUnit'];
|
||||
tagUnit = params['tagUnit'] ? params['tagUnit'] : null;
|
||||
point = params['point'] ? params['point'] : 2;
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
|
||||
//判断有没有目标单位
|
||||
if (tagUnit) {
|
||||
let indexOfNow = this.unitConfig[unit].indexOf(defaulUnit);
|
||||
let indexOfTag = this.unitConfig[unit].indexOf(tagUnit);
|
||||
const n = indexOfTag - indexOfNow;
|
||||
value = value / Math.pow(defaulvalue, n);
|
||||
} else {
|
||||
while (value >= defaulvalue && count < 6) {
|
||||
value = value / defaulvalue;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
value = Number(value.toFixed(point));
|
||||
|
||||
let index: number = 0;
|
||||
let resultUnit: string = '';
|
||||
if (this.unitConfig[unit].indexOf(defaulUnit) >= 0) {
|
||||
index = this.unitConfig[unit].indexOf(defaulUnit);
|
||||
resultUnit = this.unitConfig[unit][count + index];
|
||||
}
|
||||
if (tagUnit) {
|
||||
resultUnit = tagUnit;
|
||||
}
|
||||
return value + resultUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式转换
|
||||
* y+ 待办匹配y一次以上,替换为年,其他类似,
|
||||
*/
|
||||
dateFormat(time, fmt) {
|
||||
try {
|
||||
const date = new Date(time);
|
||||
let ret;
|
||||
const opt = {
|
||||
'y+': date.getFullYear().toString(), // 年
|
||||
'm+': (date.getMonth() + 1).toString(), // 月
|
||||
'd+': date.getDate().toString(), // 日
|
||||
'H+': date.getHours().toString(), // 时
|
||||
'M+': date.getMinutes().toString(), // 分
|
||||
'S+': date.getSeconds().toString(), // 秒
|
||||
// 有其他格式化字符需求可以继续添加,必须转化成字符串
|
||||
};
|
||||
for (let k in opt) {
|
||||
ret = new RegExp('(' + k + ')').exec(fmt);
|
||||
if (ret) {
|
||||
fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, '0')))
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const unitUtil = new unitTransfer();
|
||||
174
lib/util/xlsx-util.ts
Normal file
174
lib/util/xlsx-util.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
|
||||
import { utils, write } from 'xlsx';
|
||||
import { dateUtil } from '/nerv-lib/util/date-util';
|
||||
import { NsMessage } from '/nerv-lib/component/message';
|
||||
import axios from 'axios';
|
||||
import { createVNode, h, render as vueRender } from 'vue';
|
||||
import { NsXlsxImport } from '/nerv-lib/component/xlsx';
|
||||
import { NsModal } from '/nerv-lib/component/modal';
|
||||
|
||||
interface MapItem {
|
||||
title: string;
|
||||
dataIndex: string;
|
||||
format?: Function;
|
||||
}
|
||||
type objProps = {
|
||||
[name: string]: any;
|
||||
};
|
||||
|
||||
type argType = {
|
||||
data: Array<object>;
|
||||
xlsxMap: Array<MapItem>;
|
||||
xlsxName: string;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
const DATE_FORMAT = 'YYYY-MM-DD ';
|
||||
const MODAL_INFO = {
|
||||
title: '警告',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
};
|
||||
|
||||
const errorTable = [
|
||||
{
|
||||
title: '行数',
|
||||
dataIndex: 'row',
|
||||
},
|
||||
{
|
||||
title: '错误内容',
|
||||
dataIndex: 'reason',
|
||||
},
|
||||
];
|
||||
|
||||
const sheet2blob = (sheet: any, sheetName = 'sheet1') => {
|
||||
sheetName = sheetName || 'sheet1';
|
||||
const workbook = {
|
||||
SheetNames: [sheetName],
|
||||
Sheets: {},
|
||||
};
|
||||
workbook['Sheets'][sheetName] = sheet;
|
||||
// 生成excel的配置项
|
||||
const wbout = write(workbook, {
|
||||
bookType: 'xlsx', // 要生成的文件类型
|
||||
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
|
||||
type: 'binary',
|
||||
});
|
||||
const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
|
||||
// 字符串转ArrayBuffer
|
||||
function s2ab(s: any) {
|
||||
const buf = new ArrayBuffer(s.length);
|
||||
const view = new Uint8Array(buf);
|
||||
for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
|
||||
return buf;
|
||||
}
|
||||
return blob;
|
||||
};
|
||||
|
||||
function openDownloadDialog(url: string | Blob | MediaSource, saveName: string) {
|
||||
if (typeof url == 'object' && url instanceof Blob) {
|
||||
url = URL.createObjectURL(url); // 创建blob地址
|
||||
}
|
||||
const aLink = document.createElement('a');
|
||||
aLink.href = url;
|
||||
aLink.download = saveName || '';
|
||||
document.body.appendChild(aLink);
|
||||
aLink.click();
|
||||
document.body.removeChild(aLink);
|
||||
}
|
||||
|
||||
function download(table: unknown[][], name: string, config: any) {
|
||||
let isHandle;
|
||||
if (config && config['isHandle']) {
|
||||
isHandle = config['isHandle'];
|
||||
}
|
||||
let sheet;
|
||||
//isHandle 表示自己处理表格样式和数据,不需要再做处理
|
||||
isHandle ? (sheet = table) : (sheet = utils.aoa_to_sheet(table));
|
||||
openDownloadDialog(sheet2blob(sheet), `${name}.xlsx`);
|
||||
}
|
||||
|
||||
function DataHandler(data: Array<object>, keyMap: Array<MapItem>) {
|
||||
const tableHeader: string[] = []; // 表头
|
||||
const tableHeaderKeyMap: objProps = {}; // 表头索引map
|
||||
|
||||
keyMap?.map((item: MapItem) => {
|
||||
tableHeader.push(item['title']);
|
||||
tableHeaderKeyMap[item['title']] = item['dataIndex'];
|
||||
});
|
||||
|
||||
const table = [tableHeader];
|
||||
data.forEach((item: object) => {
|
||||
const rowData: any[] = [];
|
||||
tableHeader.forEach((th: string, index: number) => {
|
||||
let temp = item[tableHeaderKeyMap[th]];
|
||||
const format = keyMap[index].format;
|
||||
if (format) temp = format(temp, item);
|
||||
rowData.push(temp);
|
||||
});
|
||||
table.push(rowData);
|
||||
});
|
||||
return table;
|
||||
}
|
||||
|
||||
export const importFile = (
|
||||
{ api, params }: any,
|
||||
reload: Function,
|
||||
event: any,
|
||||
successBack?: Function,
|
||||
errorBack?: Function,
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
params &&
|
||||
Object.keys(params).map((item) => {
|
||||
formData.append(item, params[item]);
|
||||
});
|
||||
formData.append('file', event);
|
||||
axios
|
||||
.post(api, formData)
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
NsMessage.success('导入成功', 1, () => {
|
||||
reload && reload();
|
||||
successBack && successBack(res);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (errorBack) {
|
||||
errorBack(err);
|
||||
} else {
|
||||
NsMessage.error(err.response?.data?.msg || '导入失败');
|
||||
const error = err.response?.data?.data;
|
||||
if (error)
|
||||
xlsxExport({
|
||||
data: error,
|
||||
xlsxMap: errorTable,
|
||||
xlsxName: '导入数据不规范说明YYYY-MM-DD',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const checkLimit = (data: Array<object>, limit?: number) => {
|
||||
if (limit && data.length > limit) {
|
||||
NsModal.confirm({
|
||||
...MODAL_INFO,
|
||||
content: `本次数据下载超过${limit}条,请重新选择数据!`,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export const xlsxExport = ({ data, xlsxMap, xlsxName, limit }: argType) => {
|
||||
if (!checkLimit(data, limit)) return;
|
||||
const name = dateUtil(new Date()).format(xlsxName);
|
||||
download(DataHandler(data, xlsxMap), `${name}`, '');
|
||||
};
|
||||
|
||||
export const xlsxImport = (data: any) => {
|
||||
const div = document.createElement('div');
|
||||
const vm = h(NsXlsxImport, { ...data }, '');
|
||||
vueRender(vm, div);
|
||||
};
|
||||
Reference in New Issue
Block a user