Commit b94305bc authored by haiyoucuv's avatar haiyoucuv

init

parents
# 顶部的EditorConfig文件
root = true
# unix风格的换行符,每个文件都以换行符结尾
[*]
end_of_line = lf
insert_final_newline = true
# 设置默认字符集
charset = utf-8
# 去除行尾空白字符
trim_trailing_whitespace = true
# 使用空格缩进,设置2个空格缩进
indent_style = space
indent_size = 2
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
tmp.txt
dist/*/*
!dist/index.html
# NO SPARK !!!!!
# 为了消除疯火台影响,特地做此框架,建设中,未完工
UPLOAD_DIR=db_games/spark/v3
\ No newline at end of file
# .env.production
CDN_DOMAIN=https://yun.duiba.com.cn
OSS_REGION=oss-cn-hangzhou
OSS_BUCKET=duiba
OSS_ACCESS_KEY_ID=LTAI5tPUSSxgkEmKPAfVXUQQ
OSS_ACCESS_SECRET=6sk3EDd1BYrXlAUoh8maMuN7hOMkh1
import {exec, execSync} from 'child_process';
import * as path from "path";
import {promises as fs} from "fs";
import * as Os from "os";
import * as fsSync from "fs";
/** 压缩引擎路径表 */
const enginePathMap = {
/** macOS */
'darwin': 'pngquant/macos/pngquant',
/** Windows */
'win32': 'pngquant/windows/pngquant'
}
export async function compressAllImage(
paths = [],
onProgress: (cur?: number, total?: number) => void = () => void 0,
) {
const platform = Os.platform();
const pngquantPath = path.join(__dirname, "./", enginePathMap[platform]);
// 设置引擎文件的执行权限(仅 macOS)
if (pngquantPath && platform === 'darwin') {
if ((await fs.stat(pngquantPath)).mode != 33261) {
// 默认为 33188
await fs.chmod(pngquantPath, 33261);
}
}
const qualityParam = `--quality 0-99`,
speedParam = `--speed 4`,
skipParam = platform == "win32" ? "" : '--skip-if-larger',
outputParam = '--ext=.png',
writeParam = '--force',
// colorsParam = config.colors,
// compressOptions = `${qualityParam} ${speedParam} ${skipParam} ${outputParam} ${writeParam} ${colorsParam}`;
compressOptions = `${qualityParam} ${speedParam} ${skipParam} ${outputParam} ${writeParam}`;
let completed = 0;
if (platform == "win32") {
const now = Date.now();
const tempDir = `C:\\Temp\\duiba\\${now}`;
if (!fsSync.existsSync("C:\\Temp")) await fs.mkdir("C:\\Temp");
if (!fsSync.existsSync("C:\\Temp\\duiba")) await fs.mkdir("C:\\Temp\\duiba");
if (!fsSync.existsSync(tempDir)) await fs.mkdir(tempDir);
const ps = paths.map(async (imgPath, idx) => {
const tempName = `${tempDir}/${idx}.png`;
await fs.copyFile(imgPath, tempName);
execSync(`"${pngquantPath}" ${compressOptions} "${tempName}"`);
await fs.copyFile(tempName, imgPath);
completed++;
onProgress(completed, paths.length);
});
await Promise.all(ps);
await fs.rm(tempDir, {recursive: true});
} else {
const chunkSize = 20;
const totalBatches = Math.ceil(paths.length / chunkSize);
// 批次执行
for (let i = 0; i < paths.length; i += chunkSize) {
const currentBatch = Math.floor(i / chunkSize) + 1;
console.log(`正在处理第 ${currentBatch}/${totalBatches} 批图片压缩...`);
const chunk = paths.slice(i, i + chunkSize);
let command = "";
chunk.forEach((imgPath) => {
command += `"${pngquantPath}" ${compressOptions} "${imgPath}" &`; // 使用分号替代&实现串行
});
await new Promise<void>((resolve) => {
exec(command, (error, stdout, stderr) => {
if (error) {
// console.error(error);
}
completed += chunk.length;
onProgress(completed, paths.length);
resolve();
});
});
}
}
}
import {promises as fs} from "fs";
import SvgaDescriptor from "./SvgaDescriptor";
import {compressAllImage} from "./ImageCompress";
import * as pako from "pako";
import protobuf from "protobufjs";
import chalk from "chalk";
import * as Os from "node:os";
import * as path from "node:path";
const ProtoMovieEntity = protobuf.Root
.fromJSON(SvgaDescriptor)
.lookupType('com.opensource.svga.MovieEntity');
/**
* 压缩Svga
* @author haiyoucuv
* @param {string}svga
* @return {Promise<boolean|ArrayBuffer>}
*/
export async function compressSvga(svga: string): Promise<Uint8Array> {
try {
const buffer = await fs.readFile(svga);
// 解析svga
const data = ProtoMovieEntity.decode(pako.inflate(buffer)).toJSON();
const {images} = data;
let tempDir = svga.replace(/\.svga/, '') + "__temp__/";
// if (Os.platform() == "win32") {
// const now = Date.now();
// tempDir = `C:\\Temp\\duiba\\${now}`
//
// if (!fs.existsSync("C:\\Temp")) fs.mkdirSync("C:\\Temp");
// if (!fs.existsSync("C:\\Temp\\duiba")) fs.mkdirSync("C:\\Temp\\duiba");
// if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir);
// }
await fs.mkdir(tempDir);
const ps1 = Object.keys(images).map(async (name) => {
const path = `${tempDir}${name}.png`;
await fs.writeFile(path, Buffer.from(images[name], 'base64'));
return path;
});
// 保存图片
const imgPaths = await Promise.all(ps1);
// 压缩图片
await compressAllImage(imgPaths);
// 读取图片,还原到data
const ps2 = Object.keys(images).map(async (name) => {
const path = `${tempDir}${name}.png`;
const buffer = await fs.readFile(path);
data.images[name] = buffer.toString('base64');
});
await Promise.all(ps2);
await fs.rm(tempDir, {recursive: true});
// 压缩buffer
return pako.deflate(ProtoMovieEntity.encode(data).finish());
} catch (e) {
console.log(e);
return null;
}
}
export async function compressAllSvga(
paths = [],
onProgress: (cur?: number, total?: number) => void = () => void 0,
) {
for (let i = 0; i < paths.length; i++) {
const svga = paths[i];
const fileName = path.basename(svga);
try {
const sizePre = (await fs.stat(svga)).size;
const result = await compressSvga(svga);
if (result) {
await fs.writeFile(svga, result);
const sizeOp = (await fs.stat(svga)).size;
const radio = ((1 - sizeOp / sizePre) * 100).toFixed(2);
console.log(chalk.green("压缩Svga成功:" + fileName, `,压缩率:${radio}`));
}
} catch (e) {
console.log(chalk.red("压缩Svga失败:" + fileName));
}
onProgress(i + 1, paths.length);
}
// let completed = 0;
// const svgaPArr = paths.map((svga) => {
// return (async () => {
// const fileName = path.basename(svga);
// try {
// const sizePre = (await fs.stat(svga)).size;
// const result = await compressSvga(svga);
// if (result) {
// await fs.writeFile(svga, result);
// const sizeOp = (await fs.stat(svga)).size;
// const radio = ((1 - sizeOp / sizePre) * 100).toFixed(2);
// console.log(chalk.green("压缩Svga成功:" + fileName, `,压缩率:${radio}`));
// }
// } catch (e) {
// console.log(chalk.red("压缩Svga失败:" + fileName));
// }
//
// onProgress(completed++, paths.length);
// })();
// });
//
// await Promise.all(svgaPArr);
}
This diff is collapsed.
This diff is collapsed.
# pngquant 3 [![CI](https://github.com/kornelski/pngquant/actions/workflows/ci.yml/badge.svg)](https://github.com/kornelski/pngquant/actions/workflows/ci.yml)
[pngquant](https://pngquant.org) is a PNG compressor that significantly reduces file sizes by converting images to a more efficient 8-bit PNG format *with alpha channel* (often 60-80% smaller than 24/32-bit PNG files). Compressed images are fully standards-compliant and are supported by all web browsers and operating systems.
[This](https://github.com/kornelski/pngquant) is the official `pngquant` repository. The compression engine is also available [as an embeddable library](https://github.com/ImageOptim/libimagequant).
## Usage
- batch conversion of multiple files: `pngquant *.png`
- Unix-style stdin/stdout chaining: `… | pngquant - | …`
To further reduce file size, try [oxipng](https://lib.rs/oxipng), [ImageOptim](https://imageoptim.com), or [zopflipng](https://github.com/google/zopfli).
## Features
* High-quality palette generation
- advanced quantization algorithm with support for gamma correction and premultiplied alpha
- unique dithering algorithm that does not add unnecessary noise to the image
* Configurable quality level
- automatically finds required number of colors and can skip images which can't be converted with the desired quality
* Fast, modern code
- based on a portable [libimagequant library](https://github.com/ImageOptim/libimagequant)
- C99 with no workarounds for legacy systems or compilers ([apart from Visual Studio](https://github.com/kornelski/pngquant/tree/msvc))
- multicore support (via OpenMP) and Intel SSE optimizations
## Options
See `pngquant -h` for full list.
### `--quality min-max`
`min` and `max` are numbers in range 0 (worst) to 100 (perfect), similar to JPEG. pngquant will use the least amount of colors required to meet or exceed the `max` quality. If conversion results in quality below the `min` quality the image won't be saved (if outputting to stdin, 24-bit original will be output) and pngquant will exit with status code 99.
pngquant --quality=65-80 image.png
### `--ext new.png`
Set custom extension (suffix) for output filename. By default `-or8.png` or `-fs8.png` is used. If you use `--ext=.png --force` options pngquant will overwrite input files in place (use with caution).
### `-o out.png` or `--output out.png`
Writes converted file to the given path. When this option is used only single input file is allowed.
### `--skip-if-larger`
Don't write converted files if the conversion isn't worth it.
### `--speed N`
Speed/quality trade-off from 1 (slowest, highest quality, smallest files) to 11 (fastest, less consistent quality, light comperssion). The default is 4. It's recommended to keep the default, unless you need to generate images in real time (e.g. map tiles). Higher speeds are fine with 256 colors, but don't handle lower number of colors well.
### `--nofs`
Disables Floyd-Steinberg dithering.
### `--floyd=0.5`
Controls level of dithering (0 = none, 1 = full). Note that the `=` character is required.
### `--posterize bits`
Reduce precision of the palette by number of bits. Use when the image will be displayed on low-depth screens (e.g. 16-bit displays or compressed textures in ARGB444 format).
### `--strip`
Don't copy optional PNG chunks. Metadata is always removed on Mac (when using Cocoa reader).
See [man page](https://github.com/kornelski/pngquant/blob/master/pngquant.1) (`man pngquant`) for the full list of options.
## License
pngquant is dual-licensed:
* Under **GPL v3** or later with an additional [copyright notice](https://github.com/kornelski/pngquant/blob/master/COPYRIGHT) that must be kept for the older parts of the code.
* Or [a **commercial license**](https://supso.org/projects/pngquant) for use in non-GPL software (e.g. closed-source or App Store distribution). You can [get the license via Super Source](https://supso.org/projects/pngquant). Email kornel@pngquant.org if you have any questions.
Apple's Notarization is a control-freak mess, and I don't have enough patience to deal with their tooling. 'brew install pngquant' may work too
This diff is collapsed.
@echo off
set path=%~d0%~p0
:start
"%path%pngquant.exe" --force --verbose --quality=45-85 %1
"%path%pngquant.exe" --force --verbose --ordered --speed=1 --quality=50-90 %1
shift
if NOT x%1==x goto start
@echo off
set path=%~d0%~p0
:start
"%path%pngquant.exe" --force --verbose 256 %1
shift
if NOT x%1==x goto start
# pngquant 2
[pngquant](https://pngquant.org) is a PNG compresor that significantly reduces file sizes by converting images to a more efficient 8-bit PNG format *with alpha channel* (often 60-80% smaller than 24/32-bit PNG files). Compressed images are fully standards-compliant and are supported by all web browsers and operating systems.
[This](https://github.com/kornelski/pngquant) is the official `pngquant` repository. The compression engine is also available [as an embeddable library](https://github.com/ImageOptim/libimagequant).
## Usage
- batch conversion of multiple files: `pngquant *.png`
- Unix-style stdin/stdout chaining: `… | pngquant - | …`
To further reduce file size, try [optipng](http://optipng.sourceforge.net), [ImageOptim](https://imageoptim.com), or [zopflipng](https://github.com/google/zopfli).
## Features
* High-quality palette generation
- advanced quantization algorithm with support for gamma correction and premultiplied alpha
- unique dithering algorithm that does not add unnecessary noise to the image
* Configurable quality level
- automatically finds required number of colors and can skip images which can't be converted with the desired quality
* Fast, modern code
- based on a portable [libimagequant library](https://github.com/ImageOptim/libimagequant)
- C99 with no workarounds for legacy systems or compilers ([apart from Visual Studio](https://github.com/kornelski/pngquant/tree/msvc))
- multicore support (via OpenMP) and Intel SSE optimizations
## Options
See `pngquant -h` for full list.
### `--quality min-max`
`min` and `max` are numbers in range 0 (worst) to 100 (perfect), similar to JPEG. pngquant will use the least amount of colors required to meet or exceed the `max` quality. If conversion results in quality below the `min` quality the image won't be saved (if outputting to stdin, 24-bit original will be output) and pngquant will exit with status code 99.
pngquant --quality=65-80 image.png
### `--ext new.png`
Set custom extension (suffix) for output filename. By default `-or8.png` or `-fs8.png` is used. If you use `--ext=.png --force` options pngquant will overwrite input files in place (use with caution).
### `-o out.png` or `--output out.png`
Writes converted file to the given path. When this option is used only single input file is allowed.
### `--skip-if-larger`
Don't write converted files if the conversion isn't worth it.
### `--speed N`
Speed/quality trade-off from 1 (slowest, highest quality, smallest files) to 11 (fastest, less consistent quality, light comperssion). The default is 3. It's recommended to keep the default, unless you need to generate images in real time (e.g. map tiles). Higher speeds are fine with 256 colors, but don't handle lower number of colors well.
### `--nofs`
Disables Floyd-Steinberg dithering.
### `--floyd=0.5`
Controls level of dithering (0 = none, 1 = full). Note that the `=` character is required.
### `--posterize bits`
Reduce precision of the palette by number of bits. Use when the image will be displayed on low-depth screens (e.g. 16-bit displays or compressed textures in ARGB444 format).
### `--strip`
Don't copy optional PNG chunks. Metadata is always removed on Mac (when using Cocoa reader).
See [man page](https://github.com/kornelski/pngquant/blob/master/pngquant.1) (`man pngquant`) for the full list of options.
## License
pngquant is dual-licensed:
* Under **GPL v3** or later with an additional [copyright notice](https://github.com/kornelski/pngquant/blob/master/COPYRIGHT) that must be kept for the older parts of the code.
* Or [a **commercial license**](https://supportedsource.org/projects/pngquant) for use in non-GPL software (e.g. closed-source or App Store distribution). You can [get the license via Supported Source](https://supportedsource.org/projects/pngquant/purchase). Email kornel@pngquant.org if you have any questions.
import chalk from "chalk";
import AutoUpload from "../Uploader/Uploader.ts";
import * as path from "path";
import {findFiles} from "../commom/helper.ts";
import {compressAllImage} from "../AssetsMin/ImageCompress.ts";
import {compressAllSvga} from "../AssetsMin/SvgaCompress.ts";
interface IDuibaPublishOptions {
buildVersion: string | number,
uploadDir: string,
accessKeySecret: string,
accessKeyId: string,
bucket: string,
region: string,
}
export default function DuibaPublish(options: IDuibaPublishOptions) {
const {
buildVersion,
uploadDir,
accessKeySecret,
accessKeyId,
bucket,
region,
} = options;
return {
name: 'duiba-publish',
async closeBundle() {
// 资源压缩
console.log(chalk.green("开始资源压缩了"));
console.log(chalk.green("开始压缩图片了"));
const imgPaths = findFiles(path.resolve("dist"), /\.png$/);
process.stdout.write(chalk.green(`\r压缩图片进度:${0}/${imgPaths.length}`));
await compressAllImage(imgPaths, (cur, total) => {
// process.stdout.write("\r");
process.stdout.write(chalk.green(`\r压缩图片进度:${cur}/${total}`));
});
console.log(chalk.green("\n压缩图片结束了\n"));
// 资源压缩
console.log(chalk.green("开始压缩Svga了"));
const svgaPaths = findFiles(path.resolve("dist"), /\.svga$/);
await compressAllSvga(svgaPaths, (cur, total) => {
// process.stdout.write(chalk.green(`\r压缩Svga进度:${cur}/${total}`));
});
console.log(chalk.green("\n压缩Svga结束了\n"));
console.log(chalk.green("开始上传了"));
const autoUpload = new AutoUpload({
dir: path.resolve("dist"),
originDir: `/${uploadDir}/${buildVersion}/`,
accessKeySecret, accessKeyId, bucket, region,
});
await autoUpload.start();
console.log(`${chalk.green(`上传成功,版本号: ${buildVersion}`)}`);
}
}
}
import * as path from "path";
import * as fs from "fs";
import ProgressBar from "progress";
import OSS from "ali-oss";
interface IAutoUploadOptions {
dir: string,
originDir: string,
bucket: string,
accessKeyId: string,
accessKeySecret: string,
region: string,
}
export default class AutoUpload {
options: IAutoUploadOptions = {
dir: "",
originDir: "",
region: "oss-cn-hangzhou",
accessKeyId: "",
accessKeySecret: "",
bucket: ""
};
client = null;
bar = null;
private _files: any[];
private existFiles: number = 0;
private uploadFiles: number = 0;
private errorFiles: number = 0;
constructor(props: IAutoUploadOptions) {
this.options = Object.assign({}, this.options, props);
const checkOptions = [
"dir", "originDir",
"bucket", "region",
"accessKeySecret", "accessKeyId",
];
for (const optionKey of checkOptions) {
if (!this.options[optionKey]) {
throw new Error(`AutoUpload: required option "${optionKey}"`);
}
}
this.init();
}
init() {
const {accessKeyId, accessKeySecret, bucket, region} = this.options;
this.client = new OSS({region, accessKeyId, accessKeySecret, bucket});
this.bar = new ProgressBar(`文件上传中 [:bar] :current/${this.files().length} :percent :elapseds`, {
complete: "●",
incomplete: "○",
width: 20,
total: this.files().length,
callback: () => {
console.log("%cAll complete.", "color: green");
console.log(`%c本次队列文件共${this.files().length}个,已存在文件${this.existFiles}个,上传文件${this.uploadFiles}个,上传失败文件${this.errorFiles}个`, "color: green");
}
})
return this;
}
files() {
if (this._files) return this._files;
this._files = [];
/**
* 文件遍历方法
* @param filePath 需要遍历的文件路径
*/
const fileDisplay = (filePath) => {
//根据文件路径读取文件,返回文件列表
const files = fs.readdirSync(filePath);
files.forEach((filename) => {
//获取当前文件的绝对路径
const fileDir = path.join(filePath, filename);
//根据文件路径获取文件信息,返回一个fs.Stats对象
const stats = fs.statSync(fileDir);
const isFile = stats.isFile();//是文件
const isDir = stats.isDirectory();//是文件夹
if (isFile) {
this._files.push(fileDir);
} else if (isDir) {
fileDisplay(fileDir);//递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
});
}
//调用文件遍历方法
fileDisplay(this.options.dir);
return this._files;
}
async start() {
const ps = this.files().map((file) => {
const relativePath = path.relative(this.options.dir, file)
.replace(path.sep, "/");
this.existFiles = 0;
this.uploadFiles = 0;
this.errorFiles = 0;
const originPath = `${this.options.originDir}${relativePath}`;
return (async () => {
let originFile = null;
originFile = await this.client.head(originPath)
.catch((error: Error) => originFile = error);
try {
if (originFile.status === 404) {
await this.client.put(originPath, file);
this.uploadFiles += 1;
} else {
this.existFiles += 1;
}
} catch (error) {
this.errorFiles += 1;
}
this.bar.tick();
})();
});
await Promise.all(ps).catch((err) => {
console.error("上传错误", err);
});
}
}
import * as fs from "node:fs";
export function findFiles(dir: string, regExp: RegExp) {
let fileArr = [];
if (fs.existsSync(dir)) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const fpath = dir + '/' + file;
const stat = fs.lstatSync(fpath);
if (stat.isFile() && regExp.test(file)) {
fileArr.push(fpath);
} else if (stat.isDirectory()) {
fileArr.push(...findFiles(fpath, regExp));
}
})
}
return fileArr;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="dns-prefetch" href="//yun.duiba.com.cn" />
<link rel="preconnect" href="//embedlog.duiba.com.cn">
<title>守护权益对对碰</title>
<script type="text/javascript">
if (localStorage && localStorage.isWebp) {
document
.getElementsByTagName('html')[0]
.setAttribute('duiba-webp', 'true');
}
</script>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
var CFG = CFG || {};
CFG.projectId = location.pathname.split('/')[2] || '1';
function getUrlParam(name) {
var search = window.location.search;
var matched = search
.slice(1)
.match(new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'));
return search.length ? matched && matched[2] : null;
}
CFG.appID = '${APPID}';
if (!getUrlParam("appID")) {
// alert("【警告】检测到活动url中没有appID参数\n缺少该参数会导致埋点、分享、app信息获取错误。")
}
</script>
<script type="module" crossorigin src="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/index-58DNo98O.js"></script>
<link rel="modulepreload" crossorigin href="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/vendor-BcaFA3fM.js">
<link rel="stylesheet" crossorigin href="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/vendor-CWeaUrOh.css">
<link rel="stylesheet" crossorigin href="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/index-DeWsH3SG.css">
<script type="module">import.meta.url;import("_").catch(()=>1);(async function*(){})().next();if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script>
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
</head>
<body>
<div id="root"></div>
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
<script nomodule crossorigin id="vite-legacy-polyfill" src="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/polyfills-legacy-C2MhNPfJ.js"></script>
<script nomodule crossorigin id="vite-legacy-entry" data-src="https://yun.duiba.com.cn/db_games/spark/v3/1746968226438/assets/index-legacy-D09RGcIT.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-expressions": "off",
"prefer-rest-params": "off",
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="dns-prefetch" href="//yun.duiba.com.cn" />
<link rel="preconnect" href="//embedlog.duiba.com.cn">
<title>天天领积分</title>
<script type="text/javascript">
if (localStorage && localStorage.isWebp) {
document
.getElementsByTagName('html')[0]
.setAttribute('duiba-webp', 'true');
}
</script>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
var CFG = CFG || {};
CFG.projectId = location.pathname.split('/')[2] || '1';
function getUrlParam(name) {
var search = window.location.search;
var matched = search
.slice(1)
.match(new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'));
return search.length ? matched && matched[2] : null;
}
CFG.appID = '${APPID}';
if (!getUrlParam("appID")) {
// alert("【警告】检测到活动url中没有appID参数\n缺少该参数会导致埋点、分享、app信息获取错误。")
}
</script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/App.tsx"></script>
</body>
</html>
import CryptoJS from 'crypto-js';
const { mode, pad, enc, AES } = CryptoJS;
const getOptions = (iv: string) => {
return {
iv: enc.Utf8.parse(iv),
mode: mode.CBC,
padding: pad.ZeroPadding,
};
}
/** 加密 */
export function AESEncrypt(str: string, key: string, iv: string) {
const options = getOptions(iv);
return AES.encrypt(str, enc.Utf8.parse(key), options).toString();
}
/** 解密 */
export function AESDecrypt(cipherText: string, key: string, iv: string) {
const options = getOptions(iv);
return AES.decrypt(cipherText, enc.Utf8.parse(key), options)
.toString(enc.Utf8)
.trim()
.replace(//g, '')
.replace(//g, '')
.replace(/\v/g, '')
.replace(/\x00/g, '');
}
import { AESDecrypt, AESEncrypt } from "./Crypto";
export default [
{
url: '/tcs/index.do',
response: ({ query }) => {
return {
"success": true,
"code": "",
"message": "",
"timeStamp": Date.now(),
"data": {
"startTime": Date.now() - 1000000,
"endTime": Date.now() + 1000000,
"remainTimes": 12,
"uid": "uiduiduiduiduiduiduid",
}
}
},
},
{
url: '/tcs/start.do',
response: ({ query }) => {
return {
"success": true,
"code": "",
"message": "",
"data": AESEncrypt(JSON.stringify({
recordId: "recordId",
countdownSeconds: 120,
guide: true,
}), "3C8C48E792E9241B", "cDOiBC1n2QrkAY2P"),
}
},
},
{
url: '/tcs/submit.do',
response: ({ query }) => {
return {
success: true,
code: "",
message: "",
data: {
score: 888,
rank: 1,
prizeName: "一等奖",
reachTargetScore: 666,
drawChance: 10,
}
}
},
},
{
url: '/tcs/guide.do',
response: ({ query }) => {
return {
success: true,
code: "",
message: "",
data: null,
}
},
},
{
url: "/gaw/address/getChildrenByParentCode",
response: ({ query }) => {
return {
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1736580360076,
"data": [{
"name": "东华门街道",
"adCode": "110101001",
"level": 4
},
{
"name": "景山街道",
"adCode": "110101002",
"level": 4
},
{
"name": "交道口街道",
"adCode": "110101003",
"level": 4
},
{
"name": "安定门街道",
"adCode": "110101004",
"level": 4
},
{
"name": "北新桥街道",
"adCode": "110101005",
"level": 4
},
{
"name": "东四街道",
"adCode": "110101006",
"level": 4
},
{
"name": "朝阳门街道",
"adCode": "110101007",
"level": 4
},
{
"name": "建国门街道",
"adCode": "110101008",
"level": 4
},
{
"name": "东直门街道",
"adCode": "110101009",
"level": 4
},
{
"name": "和平里街道",
"adCode": "110101010",
"level": 4
},
{
"name": "前门街道",
"adCode": "110101011",
"level": 4
},
{
"name": "崇文门外街道",
"adCode": "110101012",
"level": 4
},
{
"name": "东花市街道",
"adCode": "110101013",
"level": 4
},
{
"name": "龙潭街道",
"adCode": "110101014",
"level": 4
},
{
"name": "体育馆路街道",
"adCode": "110101015",
"level": 4
},
{
"name": "天坛街道",
"adCode": "110101016",
"level": 4
},
{
"name": "永定门外街道",
"adCode": "110101017",
"level": 4
}
]
}
},
},
{
url: '/draw/myPrizeRecord.do',
response: ({ query }) => {
return {
"success": true,
"code": "",
"message": "",
"data": [
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: '',
boolThirdObject: true
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: '',
boolThirdObject: false
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: false,
prizeId: '',
boolThirdObject: true
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "一等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
},
{
extra: {
name: "四等奖",
icon: 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png',
},
needFillAddress: true,
prizeId: ''
}
]
}
}
},
{
url: '/inviteAssist_1/getInviteCode.do',
response: ({ query }) => {
return {
"code": null,
"data": {
"dueTime": null,
"extra": null,
"inviteCode": "ZHHUJS",
"timestamp": 1746965897230
},
"message": null,
"success": true,
"timeStamp": 1746965897241
}
}
}
]
import {AESEncrypt} from "./Crypto";
export default [
{
url: '/projectRule.query',
method: 'get',
response: ({query}) => {
return {
"data": "<p>以下是游戏规则:手速要快,点击红包雨。。333。。。。。。。。。。。。。。。。。。。。11111111111111sadasdadadsad5555555557777777777799999999999911111111111111111111111222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333311111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333331111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333</p>",
"success": true
}
},
},
{
url: '/coop_frontVariable.query',
method: 'get',
response: ({query}) => {
return {
"success": true,
"message": "报错了~",
"code": null,
"data": {
"privacyTxt": "privacyTxtprivacyTxtprivacyTxtprivacyTxtprivacyTxtprivacyTxtprivacyTxtprivacyTxt",
"prizeInfoAuthTxt": "prizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxtprizeInfoAuthTxt",
"test_config_02": "111",
shareInfo: {
"title": '守护权益对对碰',
"desc": '2025年“3·15”金融消费者权益保护教育宣传活动',
"imgUrl": 'https://yun.duiba.com.cn/polaris/shareImg.721503d9417b09af6346ae018493aec558ca31af.png'
},
shopUrl:'https://'
}
}
},
},
{
url: '/join.do',
response: ({query}) => {
return {
"code": "code",
"success": true,
"message": "message",
"timeStamp": Date.now(),
"data": AESEncrypt(JSON.stringify({
"startId": "officia",
"countDown": 30
}), "1696BD3E5BB915A0", "cDOiBC1n2QrkAY2P"),
}
},
},
{
url: '/records.query',
response: ({query}) => {
return {
"code": "code",
"success": true,
"message": "message",
"timeStamp": Date.now(),
"data": [
{
"extra": {
"name": "优惠券-大转盘02优惠券-大转盘02优惠券-大转盘02",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"strategyId": 11,
"gmtCreate": 1565213353000,
"id": 331,
"prizeId": "g4c4c3edd"
},
{
"extra": {
"name": "优惠券-大转盘03",
"icon": "//yun.duiba.com.cn/polaris/%E6%95%B0%E6%8D%AE%E5%86%B3%E7%AD%96%E5%B7%A5%E5%85%B7.531c2dae250ab379fd6216eb038e60bc12ab9dd6.png",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"strategyId": 11,
"gmtCreate": 1565213116000,
"id": 330,
"prizeId": "g0e432eeb"
},
{
"extra": {
"name": "优惠券-大转盘05",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"strategyId": 11,
"gmtCreate": 1565212826000,
"id": 329,
"prizeId": "g900c8442"
},
{
"extra": {
"name": "优惠券-大转盘01",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"gmtCreate": 1565205625000,
"id": 328,
"strategyId": 11,
"prizeId": "g4c7ba888"
},
{
"extra": {
"name": "优惠券-大转盘05",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"strategyId": 11,
"gmtCreate": 1565203101000,
"id": 327,
"prizeId": "g900c8442"
},
{
"extra": {
"name": "优惠券-大转盘03",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"strategyId": 11,
"gmtCreate": 1565203040000,
"id": 326,
"prizeId": "g0e432eeb"
},
{
"extra": {
"name": "优惠券-大转盘04",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"gmtCreate": 1565197386000,
"id": 325,
"prizeId": "gc1a8c03c"
},
{
"extra": {
"name": "优惠券-大转盘02",
"icon": "//yun.dui88.com/images/201907/tua0um9jjp.jpg",
"refType": "coupon",
"refId": "49354",
"type": 2
},
"gmtCreate": 1565197080000,
"id": 324,
"strategyId": 11,
"prizeId": "g0e432eeb"
}
],
}
},
},
]
export default [
{
url: '/log/click',
method: 'get',
response: 1,
},
{
url: '/exposure/standard',
method: 'get',
response: 1,
},
]
This diff is collapsed.
export default [
{
url: '/wechatShare/getShareInfo/v2',
method: 'get',
response: 1,
},
]
{
"name": "grace-templete",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@csstools/normalize.css": "^12.1.1",
"@grace/built-in": "*",
"@grace/svgaplayer": "*",
"@grace/ui": "*",
"@pixi/ui": "^2.2.3",
"@spark/dbdomain": "^1.0.25",
"@tailwindcss/postcss": "^4.0.6",
"@types/qrcode": "^1.5.5",
"axios": "^1.9.0",
"chalk": "^5.3.0",
"classnames": "^2.5.1",
"crypto-js": "^4.2.0",
"cssnano": "^7.0.6",
"detect-collisions": "^9.26.4",
"duiba-utils": "^2.0.2",
"emittery": "^1.1.0",
"gsap": "^3.12.7",
"howler": "^2.2.4",
"html2canvas": "^1.4.1",
"intersection-observer": "^0.12.2",
"less": "^4.3.0",
"mobx": "^6.13.7",
"mobx-react": "^9.2.0",
"pixi-stats": "^4.1.2",
"pixi.js": "^8.9.1",
"postcss": "^8.5.3",
"progress": "^2.0.3",
"protobufjs": "^7.5.0",
"qrcode": "^1.5.4",
"qs": "^6.14.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"spark-utils": "^1.1.2",
"swiper": "8.4.5",
"tailwindcss": "^4.1.4"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.24.7",
"@eslint/js": "^9.9.0",
"@types/ali-oss": "^6.16.11",
"@types/crypto-js": "^4.2.2",
"@types/howler": "^2.2.12",
"@types/pako": "^2.0.3",
"@types/postcss-pxtorem": "^6.0.3",
"@types/progress": "^2.0.7",
"@types/qs": "^6.9.16",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-legacy": "^5.4.2",
"@vitejs/plugin-react": "^4.3.1",
"ali-oss": "^6.21.0",
"autoprefixer": "^10.4.20",
"dotenv": "^16.4.5",
"eslint": "^9.9.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"mockjs": "^1.1.0",
"pako": "^2.1.0",
"postcss-pxtorem": "^6.1.0",
"terser": "^5.36.0",
"typescript": "5.5.4",
"typescript-eslint": "^8.0.1",
"vite": "^6.3.3",
"vite-plugin-mock": "^3.0.2"
}
}
This diff is collapsed.
{"proSetting":{"projectxIDs":{"testId":[{"label":"test","value":"pf83a66bf"}],"prodId":[{"label":"线上测试","value":"p6f94589a"},{"label":"线上","value":"p70e6516f"}]},"skinVariables":[],"mockSetting":{"projectId":"","pageId":""}},"envSetting":{},"psdSetting":{"psdFSSetting":true,"psdCenterSetting":true}}
{"proName":"未命名项目","proDesc":"","proPath":"F:\\2025\\20250506泸州老窖贪吃蛇","createTime":1729847802806}
export function RES_PATH() {
}
import React, {Component} from 'react'
import {observer} from "mobx-react";
import {createRoot} from "react-dom/client";
import store from "./store/store";
import "./core/checkwebp.ts";
import "./MD";
import './App.less'
import '@csstools/normalize.css';
import bgm from "@/assets/music/bgm.mp3";
import musicStore from "@/store/musicStore.ts";
import {initWx} from "@/built-in/share/weixin/weixin.ts";
import { ModalCtrl } from "@/core/ctrls/ModalCtrl.tsx";
import { PageCtrl } from "@/core/ctrls/PageCtrl.tsx";
import { GetCurrSkinId, getCustomShareId } from "@/utils/utils.ts";
import HomePage from "@/pages/HomePage/HomePage.tsx";
import MyPrize from "@/pages/MyPrize/MyPrize.tsx";
@observer
class App extends Component {
showDefaultPage = () => {
const skinId = GetCurrSkinId() || getCustomShareId();
const defaultPage = {
myPrize: MyPrize, // TODO 举例子 新宿台奖品页
index: HomePage,
}[skinId] || HomePage;
PageCtrl.changePage(defaultPage);
}
async componentDidMount() {
this.showDefaultPage();
musicStore.playSound(bgm, true);
await store.getFrontVariable();
initWx(store.frontVariable.shareInfo);
}
componentWillUnmount() {
}
render() {
return (
<>
<PageCtrl/>
<ModalCtrl/>
</>
);
}
}
const root = createRoot(document.getElementById('root')!);
root.render(
<App/>
);
export function isWeiXin() {
return /micromessenger/i.test(navigator.userAgent.toLowerCase());
}
/**
* 判断是否为ios系统
*/
export function isIos() {
return navigator.userAgent.match(/iphone|ipod|ipad/gi)
}
import { logClick, logExposure, MDAuto } from "@grace/built-in";
import { IAutoMdData } from "@grace/built-in";
import {getUrlParam} from "@/utils/utils.ts";
const appId = CFG.appID;
const dcm = "202." + CFG.projectId + ".0.0";
const domain = "";
const channel = getUrlParam("channel");
const dom = `${channel}.0.0.0`;
const MDList: IAutoMdData[] = new Array(20).fill("").map((_, i) => {
return {
ele: `.md${i + 1}`,
data: {
dpm: `${appId}.110.${i + 1}.0`,
dcm,
dom,
domain,
appId,
},
once: false,
};
});
MDAuto({
show: MDList, // 曝光
click: MDList, // 点击
});
export function handleLogExposure(id: number | string, id2: number | string = 0) {
logExposure({
dpm: `${appId}.110.${id}.${id2}`,
dcm,
domain,
appId,
});
}
export function handleLogClick(id: number | string, id2: number | string = 0) {
logClick({
dpm: `${appId}.110.${id}.${id2}`,
dcm,
domain,
appId,
});
}
import { generateAPI } from "./utils"
const API = generateAPI({
/** 获取活动规则 */
getRule: 'projectRule.query',
/** 获取前端配置项 */
getFrontVariable: 'coop_frontVariable.query',
// getShareInfo: '/wechatShare/getShareInfo/v2',
getShareInfo: '/wechatMiniApp/ticket/info',
/** 签到 */
doSign: {
uri: 'checkin_1/doSign.do',
withToken: true, // 携带token
},
// cookie丢失-临时保存cookie
tempSaveCookie: {
uri: "/autoLogin/tempSaveCookie",
showMsg: false,
},
// cookie丢失-重新设置cookie
resetCookie: "/autoLogin/resetCookie",
userLogin: {
uri: "userLogin.check",
showMsg: false,
},
records: "records.query",
index: "tcs/index.do",
submit: {
uri: "tcs/submit.do",
withToken: true,
method: "post",
},
start: {
uri: "tcs/start.do",
withToken: true,
},
guide: "tcs/guide.do",
rankInfo: 'tcs/rankIndex.do',
drawIndex: 'draw/index.do',
doDraw: {
uri: 'draw/draw.do',
withToken: true,
},
queryTasks: 'task_1/queryTasks.do',
sendPrize: {
uri: 'task_1/sendPrize.do',
withToken: true,
},
getInviteCode: {
uri: 'inviteAssist_1/getInviteCode.do',
withToken: true,
method: 'post',
},
doAssist: {
uri: 'inviteAssist_1/doAssist.do',
withToken: true,
method: 'post',
},
getPrizeList: 'draw/myPrizeRecord.do',
receivePrize: {
uri: "draw/objectReceive.do",
withToken: true,
method: "post"
},
/** 获取地区 */
getParentCode: "/gaw/address/getChildrenByParentCode",
})
// console.log('======', API)
export default API
import {isFromShare, newUser} from '@/built-in/duiba-utils';
import {errorHandler} from "@/utils/errorHandler.js";
import {getPxToken} from "@/built-in/getPxToken.js";
import {Axios, AxiosRequestConfig} from 'axios';
import qs from "qs";
import {getUrlParam} from "@/utils/utils.ts";
interface IRes {
success: boolean;
data: any;
msg?: string;
code?: number | string;
timeStamp?: number;
timestamp?: number;
}
const mergeData = {
user_type: newUser ? '0' : '1',
is_from_share: isFromShare ? '0' : '1',
from: getUrlParam("channel"),
}
// let tempCookieId = "";
//
// export function setCookieId(cookieId) {
// tempCookieId = cookieId;
// }
export function resetBackCookie(duibaTempCookieId) {
return new Promise((resolve) => {
apiAxios.request({
url: "/autoLogin/resetCookie",
params: {
duibaTempCookieId
}
}).then((resp) => {
return resolve('success');
}, (e) => {
return resolve(e);
});
});
}
/**
* 请求方法get、post处理
* @param {*} value
* @returns
*/
function getRequestParams(value) {
if (typeof value === 'string') {
return {uri: value, method: 'get'};
} else if (typeof value === 'object') {
const {
uri,
method = 'get',
showMsg = true,
headers, withToken,
} = value;
return {uri, method, headers, withToken, showMsg};
} else {
console.error('getRequestParams: 传参有误');
}
}
const apiAxios = new Axios({
timeout: 10000,
});
apiAxios.interceptors.response.use(
async (resp) => {
try {
return JSON.parse(resp.data);
} catch (e) {
return {success: false};
}
},
async (error) => {
console.error(error);
return {success: false};
}
);
export interface IApiCfg {
uri: string,
method?: "get" | "post" | "GET" | "POST",
showMsg?: boolean,
withToken?: boolean,
headers?: any,
}
export interface IApiList {
[key: string]: string | IApiCfg;
}
/**
* 请求API通用处理
* @returns
* @param apiList
*/
export function generateAPI<T extends IApiList>(apiList: T): { [key in keyof T]: (params?, headers?) => Promise<IRes> } {
const api = {} as { [key in keyof T]: (params?, headers?) => Promise<IRes> };
for (const key in apiList) {
let value: string | IApiCfg = apiList[key];
if (typeof value === 'string') {
value = {
uri: value,
method: 'get'
} as IApiCfg;
}
const {
method = 'get',
uri,
headers: mHeaders,
withToken,
showMsg = true
} = value;
api[key] = async (params: any = {}, headers: any = {}) => {
const isPost = method.toLowerCase() === 'post';
// cookie丢失的问题
// 如遇跳转Cookie丢失,打开如下代码
// const duibaTempCookieId = localStorage.getItem("db_temp_cookie");
// // const duibaTempCookieId = tempCookieId;
//
// if (duibaTempCookieId) {
// localStorage.removeItem("db_temp_cookie");
// // tempCookieId = " ";
//
// const res = await API.userLogin()
// .catch(async () => {
// await resetBackCookie(duibaTempCookieId);
// });
//
// if (!res || !res.success) {
// await resetBackCookie(duibaTempCookieId);
// }
// }
if (withToken) { // 是否携带token
params.token = await getPxToken()
.catch(() => {
// Toast('网络异常,请稍后再试~');
return "";
});
}
const mergedHeaders = {...mHeaders, ...headers}
params = {...params, ...mergeData};
const config: AxiosRequestConfig = {
method,
url: uri,
headers: mergedHeaders,
}
if (isPost) {
config.data = qs.stringify(params);
} else {
config.params = params;
}
const res: IRes = await apiAxios.request(config);
if (!res.success && showMsg) {
errorHandler(res);
}
return res;
}
}
return api;
}
@import "tailwindcss";
* {
margin: 0;
padding: 0;
}
html,
body {
font-size: 24px;
width: 100%;
height: 100%;
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
overflow: hidden;
}
.modal_center {
left: 0 !important;
top: 0 !important;
bottom: 0 !important;
right: 0 !important;
margin: auto;
}
#app {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.console {
width: 100%;
height: 100%;
}
.testBtn{
width: 750px;
height: 100px;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment