Commit 45a494c6 authored by wildfirecode13's avatar wildfirecode13

change mode

parent 0918eff8
No preview for this file type
# project ignores
node_modules
released
.DS_Store
node_modules/
___cache/
__cache/
coverage/
dist/
npm-debug.log
selenium-debug.log
.idea
.builds
.project
.vscode
yarn-error.log
.yarn
.package-lock
yarn.lock
.cache
packages/**/package-lock.json
released
output.js
output.js.map
.psd
.psb
#src/assets/
\ No newline at end of file
yarn-error.log
\ No newline at end of file
import MD from 'spark-utils/out/md/index.js';
let appId = CFG.appID;
const dcm = '202.' + CFG.projectId + '.0.0';
const domain = '//embedlog.duiba.com.cn';
let MDList = [
{
ele: `.test-md1`,
data: {
dpm: `${appId}.110.5.1`,
dcm,
domain,
appId
},
once: false
}
];
export default () =>
MD({
show: MDList, // 曝光
click: MDList // 点击
});
# spark-template
# 最新模板
烽火台app3.0中的静态模板配置
\ No newline at end of file
### 生成模块 有psd生成皮肤数据时使用
会根据参数Panel或者Scene生成ts文件写入./src/panels或./src/scenes文件夹
```shell script
npm run createModule RulePanel
```
### 资源配置刷新
有资源删除或增加时执行
会根据resource里的子级文件夹分组
文件夹名字用于各模块里的groupNames,用于按需资源加载
```shell script
npm run flushRes
```
### 本地开发
```shell script
npm run dev
```
### 图集工具安装
```shell script
#全局安装
cnpm install pack_textures -g
#终端输入packTextures检查环境变量是否存在
```
### 淘宝打包流程
```shell script
#带资源打包,并生成./released/resource文件夹和./released/output.js文件
npm run build
#只打包代码,
npm run buildTS
#脚本copyJs.js自行修改小程序output.js文件路径,嫌麻烦自行修改package.json里的build和buildTS,也可自行复制output.js
npm run copyJs
```
### web打包流程
```shell script
#带资源打包,并生成./released/resource文件夹和./output.js文件及./released/index.html,可复制进皮肤
npm run buildWeb
#只打包代码,并生成./output.js文件及./released/index.html,会打印版本号,可直接更换皮肤的版本号
npm run buildWebTS
```
### 适配
./module/views/layers.ts可设置所有层级适配(弹框场景等等)
单独模块的适配自行在模块里处理,修改this.y
\ No newline at end of file
const { assets } = require("spark-assets");
const args = process.argv.splice(2);
let argsObj = {
imgmin: false,
imgup: false
}
if (args.length == 1) {
argsObj.imgmin = 'imgmin' == args[0];
argsObj.imgup = 'imgup' == args[0];
} else if (args.length == 2) {
argsObj.imgmin = 'imgmin' == args[0];
argsObj.imgup = 'imgup' == args[1];
}
assets(argsObj)
\ No newline at end of file
exports.SPARK_CONFIG_DIR_KEY = ['OUTPUT_DIR', 'SOURCE_DIR', 'TEMP_DIR', 'ENTRY', 'TEMPLATE']
exports.SPARK_CONFIG = 'sparkrc.js'
//对应项目在线素材存储的cdn配置,用于迭代开发从线上拉取素材到本地
exports.SPARK_CDN_RES_CFG='sparkrescfg.json'
\ No newline at end of file
const loaderUtils = require('loader-utils');
module.exports = function (source) {
const options = loaderUtils.getOptions(this);
let result = source;
if (options.arr) {
options.arr.map(op => {
result = result.replace(op.replaceFrom, op.replaceTo);
})
} else {
result = source.replace(options.replaceFrom, options.replaceTo);
}
return result
};
const babel = require('@babel/core');
const HtmlWebpackPlugin = require("html-webpack-plugin");
class HtmlJsToES5Plugin {
process(htmlPluginData) {
return new Promise(function (resolve) {
const scriptRegExp = /<script>[\s\S]*?<\/script>/gis;
htmlPluginData.html = htmlPluginData.html.replace(scriptRegExp, function (match) {
const code = match.replace("<script>", "").replace("</script>", "");
const es5Code = babel.transform(code, { 'presets': ['@babel/preset-env'] }).code;
return `<script>${es5Code}</script>`;
});
resolve();
});
};
apply(compiler){
compiler.hooks.compilation.tap('HtmlJsToES5Plugin', (compilation) => {
HtmlWebpackPlugin.getHooks(compilation).afterTemplateExecution.tapAsync(
"HtmlJsToES5Plugin",
async (html, cb) => {
await this.process(html);
cb(null, html);
}
);
});
}
}
// exports.default = HtmlJsToES5Plugin;
module.exports = HtmlJsToES5Plugin;
// 端口是否被占用
exports.getProcessIdOnPort=function(port) {
try {
const execOptions = {
encoding: 'utf8',
stdio: [
'pipe',
'pipe',
'ignore',
],
};
return execSync('lsof -i:' + port + ' -P -t -sTCP:LISTEN', execOptions)
.split('\n')[0]
.trim();
} catch (e) {
return null;
}
}
const childProcessSync=async function(cmd, params, cwd, printLog = true) {
return new Promise((resolve, reject) => {
let proc = childProcess(cmd, params, cwd, printLog);
proc.on('close', (code) => {
if (code === 0) {
resolve(proc['logContent']);
} else {
reject(code);
}
});
});
}
const getGitBranch=async function(cwd) {
try {
const result = await childProcessSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], cwd, false);
if (!result.startsWith('fatal:')) {
return result.trim();
}
} catch (e) {
return undefined;
}
}
const getProjectNameByPackage=function() {
return require(`${process.cwd()}/package.json`).name
}
/**
* 理论上每个项目独一无二的文件夹名字-默认取分支名
* 如果当前未创建分支,取包名+日期
* (实际很多情况是直接clone老项目,包名相同,以防资源被替换,所以用日期加一下)
*/
exports.getCdnFolderName=async function() {
const branch = await getGitBranch(process.cwd());
const date = Date.now();
if (branch) {
return branch + "/" + date;
}
let foldername = getProjectNameByPackage() + "/" + date;
return foldername;
}
\ No newline at end of file
const path = require('path');
const fs = require("fs");
const { SPARK_CONFIG_DIR_KEY, SPARK_CONFIG } = require('./scripts/constant');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ProgressBarPlugin = require("progress-bar-webpack-plugin");
module.exports = function (isProd) {
const appPath = process.cwd();
const sparkConfig = require(path.join(appPath, SPARK_CONFIG));
const isEslint = fs.existsSync(`${appPath}/.eslintrc.js`);
const cssReg = /\.(css|less)$/;
// 处理相对路径
SPARK_CONFIG_DIR_KEY.map((key) => {
sparkConfig[key] = path.resolve(appPath, sparkConfig[key]);
});
const stylePlugins = [
require("autoprefixer")({
overrideBrowserslist: ["> 1%", "last 2 versions", "not ie <= 8"],
})
];
if (sparkConfig.PX2REM) {
stylePlugins.push(
require("postcss-px2rem-exclude")({
remUnit: 100, // 注意算法,这是750设计稿,html的font-size按照750比例
exclude: /node_modules/i,
})
);
}
const styleLoader = (cssOptions = {}) => {
return [
{
loader: "style-loader",
},
isProd && {
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
{
loader: "css-loader",
options: {
...cssOptions,
importLoaders: 2, // 如果遇到css里面的 @import 执行后面两个loader。 不然如果import了less,css-loader是解析不了
},
},
{
loader: "postcss-loader",
options: {
sourceMap: isProd,
plugins: stylePlugins,
},
},
{
loader: require.resolve("less-loader"),
options: {
sourceMap: isProd,
},
},
].filter(Boolean);
};
return {
entry: sparkConfig.ENTRY,
mode: isProd ? 'production' : 'development',
devtool: isProd ? "source-map" : "cheap-module-source-map",
output: {
path: path.resolve(__dirname, sparkConfig.OUTPUT_DIR),
filename: "js/[name].js",
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
"@src": path.resolve(__dirname, sparkConfig.SOURCE_DIR),
},
},
module: {
rules: [
// 提前进行eslint, 默认从下往上,通过enforce pre提前
isEslint && {
test: /\.js|jsx/,
enforce: "pre",
loader: "eslint-loader",
options: {
cache: true,
formatter: require("eslint-friendly-formatter"),
fix: true,
failOnError: true,
configFile: `${appPath}/.eslintrc.js`,
},
include: sparkConfig.SOURCE_DIR,
},
{
test: cssReg,
use: styleLoader(),
include: sparkConfig.SOURCE_DIR,
},
{
test: /\.(js|jsx)$/,
loader: require.resolve("babel-loader"),
exclude: [path.resolve("node_modules")],
options: {
presets: [
require("@babel/preset-env").default,
require("@babel/preset-react").default
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": false }],
require("@babel/plugin-transform-runtime").default,
],
sourceType: 'unambiguous'
},
},
{
test: [/\.(jpg|jpeg|png|svg|bmp)$/, /\.(eot|woff2?|ttf|svg)$/],
loader: require.resolve("url-loader"),
options: {
name: "[path][name].[ext]", // name默认是加上hash值。这里做了更改,不让加
outputPath: "images",
limit: 10240, // url-loader处理图片默认是转成base64, 这里配置如果小于10kb转base64,否则使用file-loader打包到images文件夹下
},
},
].filter(Boolean),
},
plugins: [
isProd &&
new MiniCssExtractPlugin({
filename: "styles/[name].[hash].css",
}),
new HtmlWebpackPlugin({
template: sparkConfig.TEMPLATE,
minify: !sparkConfig.UNMINIFY_INDEX && isProd,
}),
new CleanWebpackPlugin({
// cleanOnceBeforeBuildPatterns:['**/*', 'dist'] // 这里不用写 是默认的。 路径会根据output 输出的路径去清除
}),
new ProgressBarPlugin(),
].filter(Boolean),
optimization: {
minimize: isProd,
minimizer: [
// 替换的js压缩 因为uglifyjs不支持es6语法,
new TerserPlugin({
cache: true,
sourceMap: isProd,
extractComments: false, // 提取注释
parallel: true, // 多线程
terserOptions: {
compress: {
pure_funcs: ["console.log"],
},
},
}),
// 压缩css
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorPluginOptions: {
preset: ["default", { discardComments: { removeAll: true } }],
},
canPrint: true,
}),
],
// 修改文件的ids的形成方式,避免单文件修改,会导致其他文件的hash值变化,影响缓存
moduleIds: "hashed",
splitChunks: {
chunks: "all",
minSize: 30000, //小于这个限制的会打包进Main.js
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10, // 优先级权重,层级 相当于z-index。 谁值越大权会按照谁的规则打包
name: "vendors",
},
},
},
// chunks 映射关系的 list单独从 app.js里提取出来
runtimeChunk: {
name: (entrypoint) => `runtime-${entrypoint.name}`,
},
},
};
}
\ No newline at end of file
const { SPARK_CONFIG } = require("./scripts/constant");
const Webpack = require("webpack");
const webpackBaseConfig = require("./webpack.common.config");
const WebpackMerge = require("webpack-merge");
const WebpackDevServer = require("webpack-dev-server");
const opn = require("opn");
const apiMocker = require('mocker-api');
const path = require('path');
const { getProcessIdOnPort } = require("./scripts/utils");
const sparkConfig = require(path.resolve(SPARK_CONFIG));
const webpackDevConfig = function () {
return {
devServer: {
useLocalIp: true,
open: false,
hot: true,
host: "0.0.0.0",
// hotOnly: true
before(app) {
if (sparkConfig.API_MOCK) {
apiMocker(app, path.resolve('./mock/index.js'), {
changeHost: true,
})
}
}
},
plugins: [
// new Webpack.WatchIgnorePlugin([/[\\/]mock[\\/]/]),
new Webpack.HotModuleReplacementPlugin()
]
};
};
const buildDev = async function (config) {
let { port } = config;
return new Promise((resolve, reject) => {
const config = WebpackMerge(webpackBaseConfig(false), webpackDevConfig());
const compiler = Webpack(config);
const devServerOptions = Object.assign({}, config.devServer);
console.log('devServerOptions', devServerOptions);
const server = new WebpackDevServer(compiler, devServerOptions);
if (getProcessIdOnPort(port)) {
reject(`端口 ${port} 已被使用`);
return;
} else {
server.listen(
port || 8088,
"0.0.0.0",
() => {
console.log(`Starting server on http://localhost:${port}`);
opn(`http://localhost:${port || 8088}`);
resolve();
},
(err) => {
if (err) console.error("server linsten err--", err);
reject();
}
);
}
});
};
const args = process.argv.splice(2);
const port = args[0] || 8088
buildDev({
port: Number(port)
})
const path = require("path");
const chalk = require("chalk");
const fs = require('fs-extra');
const Webpack = require("webpack");
const WebpackMerge = require("webpack-merge");
const webpackBaseConfig = require("./webpack.common.config");
const { uploadFiles } = require("spark-assets");
const isProd = true;
const { getCdnFolderName } = require("./scripts/utils");
const { SPARK_CONFIG } = require("./scripts/constant");
const HtmlJsToES5Plugin = require("./scripts/plugins/HtmlJsToES5Plugin");
const { DepReporter } =require('spark-log-event');
const sparkConfig = require('../sparkrc');
const webpackProdConfig = function (cdnFolderName, resPathProd) {
return {
output: {
publicPath: `//yun.duiba.com.cn/spark/v2/${cdnFolderName}/`,
filename: isProd ? "js/[name].[contenthash:8].js" : "js/[name].[contenthash:4].js",
},
resolveLoader: {
modules: ['node_modules', path.resolve(__dirname, './scripts/loaders')]
},
module: {
rules: [
{
test: /sparkrc\.js$/,
exclude: [path.resolve("node_modules")],
use: [
{
loader: 'replaceLoader',
options: {
arr: [
{
replaceFrom: /(MOCK_STATUS: true)|(MOCK_STATUS:true)|("MOCK_STATUS": true)|("MOCK_STATUS":true)/,
replaceTo: '"MOCK_STATUS": false'
},
{
replaceFrom: /(RES_PATH:'\/src\/assets\/')|(RES_PATH: '\/src\/assets\/')|("RES_PATH":"\/src\/assets\/")|("RES_PATH": "\/src\/assets\/")/,
replaceTo: `"RES_PATH":"${resPathProd}/"`
}
]
}
}
]
}
]
},
plugins: [
new Webpack.IgnorePlugin(/[\\/]mock[\\/]/),
new HtmlJsToES5Plugin(),
new DepReporter()
],
node: {
crypto: 'empty'
}
};
};
const buildProd = async function () {
const cdnFolderName = await getCdnFolderName();
const appPath = process.cwd();
const sparkConfig = require(path.join(appPath, SPARK_CONFIG));
const _webpackProdConfig = await webpackProdConfig(cdnFolderName, sparkConfig.RES_PATH_PROD || '');
//新增 JS_PATH_PROD 用作
let newSparkCfg = Object.assign({}, sparkConfig);
newSparkCfg['JS_PATH_PROD'] = `https://yun.duiba.com.cn/spark/v2/${cdnFolderName}/js`;
const str = `module.exports =${JSON.stringify(newSparkCfg, null, 2)}`;
fs.writeFileSync(path.join(appPath, SPARK_CONFIG), str);
return new Promise((resolve, reject) => {
const config = WebpackMerge(webpackBaseConfig(isProd), _webpackProdConfig);
const compiler = Webpack(config);
compiler.run(async (error, stats) => {
if (error) {
return reject(error);
}
console.log(
stats.toString({
chunks: false, // 使构建过程更静默无输出
colors: true, // 在控制台展示颜色
})
);
console.log(`${chalk.yellow("打包成功, 等待上传")}\n`);
// await uploadFiles(config.output.path, '', cdnFolderName);
await uploadFiles(config.output.path, '', cdnFolderName, /.map$/);
resolve();
});
});
};
buildProd();
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="full-screen" content="true" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-fullscreen" content="true" />
<meta name="360-fullscreen" content="true" />
<!-- 渲染引擎 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge2018.minSpine.js" crossorigin="anonymous"></script>
<!-- svga解析库 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script>
<style>
html,
body {
padding: 0;
margin: 0;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
background-color: #9a3636;
/* background: linear-gradient(#93dbb7,#ff0,#b5d89a); */
/* background: linear-gradient(#93dbb7,#b5d89a); */
/* 背景图片,解决加载太慢,白屏问题,加了这个下面的__loading__可以删掉了 */
/* background-size: 100%;
background-position: center;
background-image: url("https://yun.duiba.com.cn/db_games/activity/game/1550472986/resource/assets/playscene/playscenebg.jpg"); */
}
</style>
</head>
<body>
<div id="__loading__" style="position:absolute;left:50%;top:50%;margin-left:-45px;color:#ffffff">拼命加载中...</div>
<div id="cusEngine" style="line-height:0;font-size:0;position: absolute;">
<canvas id="canvas" style="width: 100%;height: 100%"></canvas>
</div>
<!-- 帧率检测 -->
<script src="https://yun.duiba.com.cn/db_games/libs0126/stats.js"></script>
<script>
//TODO我的奖品链接
window["recordUrl"] = "fe071865b.html";
window.addEventListener("load", function () {
//获取canvas
var canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth * (window.devicePixelRatio || 1)
canvas.height = document.body.clientHeight * (window.devicePixelRatio || 1)
var main = new Main(canvas);
var mouseEvent = main.stage.onMouseEvent.bind(main.stage);
canvas.addEventListener("touchstart", mouseEvent, false);
canvas.addEventListener('touchmove', mouseEvent, false);
canvas.addEventListener('touchend', mouseEvent, false);
window.stage = main.stage
})
</script>
<!-- 构建的js -->
<script src="output.js" crossorigin="anonymous"></script>
</body>
</html>
\ No newline at end of file
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@src/*": ["src/*"]
}
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
declare module SvgaParser {
/**
* 加载方法
* @param url 资源路径
* @param success
* @param failure
*/
export function loadSvga(url: string, success: (videoItem: VideoEntity) => void, failure?: (err: string) => void): void;
/**
* 导出只是当作类型接口用
*/
export interface VideoEntity {
/**
* SVGA 文件版本
*/
version: string;
/**
* 影片尺寸
*/
videoSize: {
width: number;
height: number;
};
/**
* 帧率,60,30等每秒
*/
FPS: number;
/**
* 总帧数
*/
frames: number;
/**
* base64图片数据记录
*/
images: {
[key: string]: string
};
/**
* 图片是否已被缓存,缓存全局,注意名字覆盖
*/
hasBeenCached: boolean;
/**
* sprite对象数据
*/
sprites: SpriteEntity[];
}
interface SpriteEntity {
/**
* 标识
*/
matteKey: string;
/**
* 图片key值
*/
imageKey: string;
/**
* 帧数据数组
*/
frames: FrameEntity[];
}
/**
* 还有很多其他数据,暂不需要,比如矢量路径和遮罩路径暂时都无
*/
interface FrameEntity {
/**
* 透明度
*/
alpha: number;
/**
* 2维矩阵数据
*/
transform: {
a: number,
b: number,
c: number,
d: number,
tx: number,
ty: number,
};
}
}
declare module "svga-parser" { export = SvgaParser; }
\ No newline at end of file
// Type definitions for howler.js v2.1.1
// Project: https://github.com/goldfire/howler.js
// Definitions by: Pedro Casaubon <https://github.com/xperiments>
// Alexander Leon <https://github.com/alien35>
// Nicholas Higgins <https://github.com/nicholashza>
// Carlos Urango <https://github.com/cjurango>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
interface HowlerGlobal {
mute(muted: boolean): this;
volume(): number;
volume(volume: number): this;
codecs(ext: string): boolean;
unload(): this;
usingWebAudio: boolean;
html5PoolSize: number;
noAudio: boolean;
autoUnlock: boolean;
autoSuspend: boolean;
ctx: AudioContext;
masterGain: GainNode;
stereo(pan: number): this;
pos(x: number, y: number, z: number): this | void;
orientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): this | void;
}
declare let Howler: HowlerGlobal;
interface IHowlSoundSpriteDefinition {
[name: string]: [number, number] | [number, number, boolean]
}
interface IHowlProperties {
src: string | string[];
volume?: number;
html5?: boolean;
loop?: boolean;
preload?: boolean;
autoplay?: boolean;
mute?: boolean;
sprite?: IHowlSoundSpriteDefinition;
rate?: number;
pool?: number;
format?: string[] | string;
xhrWithCredentials?: boolean;
onload?: () => void;
onloaderror?: (soundId: number, error: any) => void;
onplay?: (soundId: number) => void;
onplayerror?: (soundId: number, error: any) => void;
onend?: (soundId: number) => void;
onpause?: (soundId: number) => void;
onstop?: (soundId: number) => void;
onmute?: (soundId: number) => void;
onvolume?: (soundId: number) => void;
onrate?: (soundId: number) => void;
onseek?: (soundId: number) => void;
onfade?: (soundId: number) => void;
onunlock?: (soundId: number) => void;
}
interface Howl {
play(spriteOrId?: string | number): number; // .play() is not chainable; the other methods are
pause(id?: number): this;
stop(id?: number): this;
mute(): boolean;
mute(muted: boolean, id?: number): this;
volume(): number;
volume(idOrSetVolume: number): this | number;
volume(volume: number, id: number): this;
fade(from: number, to: number, duration: number, id?: number): this;
rate(): number;
rate(idOrSetRate: number): this | number;
rate(rate: number, id: number): this;
seek(seek?: number, id?: number): this | number;
loop(id?: number): boolean;
loop(loop: boolean, id?: number): this;
playing(id?: number): boolean;
duration(id?: number): number;
state(): 'unloaded' | 'loading' | 'loaded';
load(): this;
unload(): void;
on(event: 'load', callback: () => void, id?: number): this;
on(event: 'loaderror', callback: (soundId: number, error: any) => void, id?: number): this;
on(event: 'play', callback: (soundId: number) => void, id?: number): this;
on(event: 'playerror', callback: (soundId: number, error: any) => void, id?: number): this;
on(event: 'end', callback: (soundId: number) => void, id?: number): this;
on(event: 'pause', callback: (soundId: number) => void, id?: number): this;
on(event: 'stop', callback: (soundId: number) => void, id?: number): this;
on(event: 'mute', callback: (soundId: number) => void, id?: number): this;
on(event: 'volume', callback: (soundId: number) => void, id?: number): this;
on(event: 'rate', callback: (soundId: number) => void, id?: number): this;
on(event: 'seek', callback: (soundId: number) => void, id?: number): this;
on(event: 'fade', callback: (soundId: number) => void, id?: number): this;
on(event: string, callback: Function, id?: number): this;
on(event: 'unlock', callback: (soundId: number) => void, id?: number): this;
once(event: 'load', callback: () => void, id?: number): this;
once(event: 'loaderror', callback: (soundId: number, error: any) => void, id?: number): this;
once(event: 'play', callback: (soundId: number) => void, id?: number): this;
once(event: 'playerror', callback: (soundId: number, error: any) => void, id?: number): this;
once(event: 'end', callback: (soundId: number) => void, id?: number): this;
once(event: 'pause', callback: (soundId: number) => void, id?: number): this;
once(event: 'stop', callback: (soundId: number) => void, id?: number): this;
once(event: 'mute', callback: (soundId: number) => void, id?: number): this;
once(event: 'volume', callback: (soundId: number) => void, id?: number): this;
once(event: 'rate', callback: (soundId: number) => void, id?: number): this;
once(event: 'seek', callback: (soundId: number) => void, id?: number): this;
once(event: 'fade', callback: (soundId: number) => void, id?: number): this;
once(event: string, callback: Function, id?: number): this;
once(event: 'unlock', callback: (soundId: number) => void, id?: number): this;
off(event: string, callback?: Function, id?: number): this;
off(): this;
stereo(pan: number, id?: number): this | void;
pos(x: number, y: number, z: number, id?: number): this | void;
orientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): this | void;
pannerAttr(o: {
coneInnerAngle?: number,
coneOuterAngle?: number, coneOuterGain?: number,
distanceModel: 'inverse' | 'linear', maxDistance: number,
panningModel: 'HRTF' | 'equalpower', refDistance: number, rolloffFactor: number
}, id?: number): this;
}
interface HowlStatic {
new(properties: IHowlProperties): Howl;
}
declare let Howl: HowlStatic;
declare module "howler" {
export let Howler: HowlerGlobal;
export let Howl: HowlStatic;
}
module.exports = {
"data": 3,
"success": true
}
\ No newline at end of file
module.exports = {
"data": "<p>以下是游戏规则:手速要快,点击红包雨。。333。。。。。。。。。。。。。。。。。。。。11111111111111sadasdadadsad5555555557777777777799999999999911111111111111111111111222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333311111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333331111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333</p>",
"success": true
}
\ No newline at end of file
const path = require('path');
const config = {
'/ngame/new/datapash': {
data: './json/datapash.json'
},
'/hdtool/recon/ngame/ngameSubmit': {
data: './json/ngameSubmit.json'
},
'/hdtool/recon/ajaxElement': {
data: './json/ajaxElement.json'
},
'/hdtool/recon/getOrderStatus': {
data: './json/getOrderStatus.json'
},
'/hdtool/recon/doJoin': {
data: './json/doJoin.json'
},
'/hdtool/recon/ngame/getNgameStartStatus': {
data: './json/getNgameStartStatus.json'
},
}
for (let item in config) {
if (config.hasOwnProperty(item))
config[item].path = path.resolve(__dirname, config[item].data);
}
module.exports = config;
\ No newline at end of file
const rule = require("./common/rule");
const drawNum = require("./common/drawNum");
const proxy = {
"GET /projectRule.query": rule,
"GET /drawNum.query": drawNum
};
module.exports = proxy;
{
"code": "0000000000",
"data": {
"creditsConf": {
"creditsUp": 100,
"creditsType": "virtual",
"creditsDown": 50,
"prize": [
{
"img": "adsfsadf",
"credits": 20,
"id": 4,
"title": "0.3"
},
{
"img": "sadfasdf",
"credits": 150,
"id": 3,
"title": "1.5倍"
},
{
"img": "sadfasdf",
"credits": 100,
"id": 2,
"title": "1倍"
},
{
"img": "sadfasdf",
"credits": 50,
"id": 1,
"title": "0.5倍"
}
]
},
"floating": {
"jsTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191434.js",
"cssTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191440.css"
},
"options": [
{
"itemId": 47861,
"hidden": false,
"prizeType": "thanks",
"name": "谢谢参与",
"description": "",
"logo": "//yun1.duiba.com.cn/upload/uP99F1462438316972.png",
"id": 15581
},
{
"itemId": 47862,
"hidden": false,
"prizeType": "lucky",
"name": "幸运福袋",
"description": "",
"logo": "//yun1.duiba.com.cn/webapp/img/luckynewn.png",
"id": 15582
},
{
"itemId": 47863,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
},
{
"itemId": 47864,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
}
],
"rule": "adsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【iadsfasdfasd啊实打实爱的额求稳怕哦i求稳怕请问赔钱片尾曲哦物品i区乌日千万人i去我日哦确认iqo【i",
"type": "hdtool",
"element": {
"isCreditsTypeOpen": false,
"myCreditsLong": 999999632167,
"freeLimit": 5,
"success": false,
"myCredits": "999999632167",
"needCredits": "100",
"freeEmpty": true,
"needCreditsLong": 9,
"status": 7
},
"coinPusherConf": {
"exchangeRate": 60,
"creditsGear": "25,60,75,80"
}
},
"success": true,
"desc": "OK",
"timestamp": 1548832971636
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":123456
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1550570639368,
"data":{
"orderId":"883006813674240289",
"submitToken":"d895deb9118f4b938d0b70a3dd2ace19",
"credits":"999999491765",
"unitName":"金币",
"consumerCredits":999999491765
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548923950498,
"data":{
"element":{
"success":false,
"isCreditsTypeOpen":false,
"needCredits":"100",
"myCredits":"1123",
"myCreditsLong":1123,
"needCreditsLong":9,
"freeLimit":2,
"status":6,
"freeEmpty":true
},
"lottery":{
"id":null,
"type":"111",
"imgUrl":"//yun.duiba.com.cn/images/201607/73htz55ih9.jpg",
"link":null,
"title":"重复券测试grape",
"itemId":null,
"appItemId":null,
"bonus":null,
"bonusMin":null,
"bonusMax":null,
"needAccount":null,
"appLucky":null,
"tip":null,
"useBtnText":null,
"validate":null,
"couponCode":null,
"couponKey":null,
"stInfoDpmImg":null,
"stInfoDpmClose":null,
"stInfoDpmGoUse":null,
"showUse":null,
"openUrl":null,
"iosDownloadUrl":null,
"androidDownloadUrl":null,
"isDownloadUrl":null,
"confirm":null,
"phaseNumber":null,
"happyCode":null,
"appHidden":true,
"zybangJson":null
},
"exposure":11111,
"creditsInfo":{
"activityId":82567,
"prizeId":4,
"orderNum":null,
"developerBizId":"3029576",
"score":null,
"recordStatus":1,
"errorMsg":null
},
"againTag":null
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1550646190489,
"data":{
"score":100,
"maxScore":100
}
}
\ No newline at end of file
{
"success": true,
"message": "",
"code": "",
"data": {
"ruleIdList": [
"ru_1",
"ru_2",
"ru_3",
"ru_4"
],
"drawStatus": 12,
"prizeId": "aa",
"gameCounts": 1
}
}
\ No newline at end of file
{
"success": true,
"message": "",
"code": "",
"data": 1234
}
\ No newline at end of file
{
"success": true,
"message": "",
"code": "",
"data": {
"type": 1,
"status": 1,
"prize": {
"prizeId": "sp_1",
"prizeType": 1,
"optionId": "sdhjfhjhjjj",
"optionName": "10元话费",
"optionImg": "https://www.baidu.com/xxoo2.png",
"userRecordId": 1235,
"url": "https://www.baidu.com/order/1235"
}
}
}
\ No newline at end of file
{
"success": true,
"message": "",
"data": "<p class=\"p1\">1、什么人可以参与抽奖?</p><p class=\"p1\">同时持有中信银行借记卡和信用卡的客户,活动期间内预约报名(每个自然月均可报名),完成绑定中信银行借记卡并用中信银行手机银行app对本人绑定的信用卡进行自动还款任务即视为达标获得抽奖资格。达标用户将以短信形式通知抽奖。 </p><p>  </p><p class=\"p1\">2、抽奖的时间是什么时候?</p><p class=\"p1\">报名成功次月10日-15日。每期的抽奖资格当期有效,若满足抽奖资格未在有效期内抽奖,资格不保留。首轮达标客户的抽奖开启时间为:7月10-15日。</p><p>  </p><p class=\"p1\">3、活动说明:</p><p class=\"p1\">1)点击“立即抽奖”按钮,摇奖机开始转动,最终摇奖机中间停留的即为您所中的奖品。</p><p class=\"p1\">2)活动期间,每位客户每个自然月均可报名参与活动,预约报名并完成绑定中信银行借记卡并用中信银行手机银行app对本人绑定的信用卡进行自动还款任务即视为达标获得抽奖资格,可获抽奖资格,每位客户每个自然月最多可获一次抽奖机会,请在抽奖有效期内(报名次月10日—15日)通过短信路径或登录手机银行首页——特色服务——还款抽奖——进入页面抽奖,每期的抽奖资格当期有效,若满足抽奖资格未在有效期内抽奖,资格不保留。</p><p class=\"p1\">3)客户抽中的“10元话费”奖励将在当月30日前直接充值到您预留报名的手机号码中,请注意查收;</p><p class=\"p1\">4)大牌券奖励中奖后客户可在活动页面右上角的【我的奖品】中找到,奖品具体使用规则可在奖品详情页查看,大牌权益奖励兑换及使用将会跳转至权益对应的提供方平台,您填写的信息仅用于奖品或权益发放时使用(如姓名、手机号、地址等)。本活动服务由第三方杭州兑吧网络科技有限公司提供,相关责任将由杭州兑吧网络科技有限公司承担,如有问题请咨询该公司客服。中信银行仅为相关活动提供链接服务,不提供任何形式的担保和承诺。大牌券的领取使用有任何问题请致电兑吧客服专线:400-609-0828;</p><p class=\"p1\">5)为保证活动的公平公正,通过不当手段、利用系统漏洞恶意套取奖励等不当途径参与本活动抽奖的客户,中信银行有权终止该客户参与活动的权利并取消其获奖资格;</p><p class=\"p1\">6)凡参与活动的客户,即视为接受活动所有规则,在法律允许范围内,中信银行保留对本次活动的解释权、随时调整本活动优惠信息、变更活动的权利;</p><p class=\"p1\">7)通过本软件参加的任何商业活动,均与Apple Inc.无关;</p><p><span style=\"font-size:10.5ptpx\">8)本次活动授权杭州兑吧网络科技有限公司提供营销服务,若有相关疑问,请致电兑吧客服专线:400-609-0828。</span></p>"
}
\ No newline at end of file
{}
\ No newline at end of file
interface ResData {
/**
* 分组数据
*/
groups: GroupInt[];
//暂时没有工具,不用
resources?: any;
path?: string;
}
interface GroupInt {
/**
* 所有的资源名字,根据,分割,根据后缀区分类型
*
*/
keys: string;//"aa.png,bb.jpg,name.json"
/**
* 文件夹名字吧
*/
name: string;
/**
* 图集
* 线上打包合图可能有多张,暂时发现texturePacker版本问题只有一张
*/
atlas: {
[name: string]: {
"x": number,
"y": number,
"w": number,
"h": number,
"ox": number,
"oy": number,
"sw": number,
"sh": number,
"ro": boolean
},
};
}
interface SkinInt {
name: string,
x: 0,
y: 0,
type: 'container' | 'text' | 'button' | 'sprite' | 'rect' | 'item',//item的不初始化进节点,只作为数据
children?: SkinInt[],
id?: string,
alpha: number,
props?: {
source?: string,
text: string,
size: number,
fillColor: string,
textAlpha: number,
width: number,
height: number,
tUp: string,
tDown: string,
tDisable: string
}
}
/**
* 简单点,有工具的话像egret那样玩,可以自动生成图片组数据
*/
export namespace RES {
let resData: ResData
/**
* 资源路径
*/
export let resPath: string;
/**
* RES单独缓存一下纹理,全局的FYGE缓存纹理对于多page有覆盖的问题;
*/
let textureHash: {
[name: string]: FYGE.Texture;
} = {};
/**
* movieClip的ve数据
*/
let videoEntityHash: {
[name: string]: SvgaParser.VideoEntity
} = {};
/**
* 音频的加载
*/
let soundHash = {}
/**
* 记录组加载完成
*/
let groupsCompleteHash: {
[name: string]: boolean
} = {}
/**
* 记录加载的promise
*/
let groupsPromiseHash: {
[name: string]: Promise<any>
} = {}
/**
* 单独资源加载的promise记录
*/
let singleResPromiseHash: {
[name: string]: Promise<any>
} = {}
/**
*
* @param res 资源数据,就是对象,不考虑加载json先
* res格式{
* path:1111/
* groups: [
* {
*
* }
* ];
* }
* @param path
*/
export function loadConfig(res) {
resData = res;
resPath = res.path;
}
/**
* 根据组名加载一组资源,通常用于加载一个视图的的所有资源
* 里的promise的resolve并没有返回值
* @param name
*/
export function loadGroup(name: string): Promise<void> {
//已经加载完成的直接返回
if (groupsCompleteHash[name]) {//其实直接return就行
return new Promise((resolve) => {
resolve()
})
}
//如果是正在加载中的,返回正在加载中的promise
if (groupsPromiseHash[name]) {
return groupsPromiseHash[name];
}
//如果首次加载
//获取资源组
let arr = getGroupResByName(name);
//如果不存在arr,直接返回空p,且标记完成
if (!arr || !arr.length) {
groupsCompleteHash[name] = true;
return new Promise((resolve) => {
resolve()
})
}
// 建一个promise
let p:Promise<void> = new Promise((resolve, reject) => {
loadResList((s) => {
//移除
delete groupsPromiseHash[name];
if (s) {
groupsCompleteHash[name] = true;
resolve()
} else {
reject();
}
}, arr/*, resPath + name*/)
})
groupsPromiseHash[name] = p;
return p;
}
/**
* var textue = await RES.getResAsync(str);
* @param str 可以是网络图片路径或键值
* @param comFun 加载回调
* @param thisObj this指向
*/
export function getResAsync(str: string, comFun?: (res: any, str: string) => void, thisObj?: any): Promise<any> {
// var arr = str.split(".");
var type = str.substring(str.lastIndexOf(".") + 1, str.length);
//如果是图片
if (type == "png" || type == "jpg") {
//原先就有了,加载过的,且已加载完成的
let cached = textureHash[str] || FYGE.TextureCache[str];
if (cached) {
//回调形式
comFun && comFun.call(thisObj, cached, str)
// return cached;
return new Promise((r) => { //为了能.then
r(cached)
})
}
//未加载完成的
else if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
}
else {
//判断是否在资源里,判断是否要加载图集,注意已排除jpg
var groupName = hasRes(str);
if (groupName && type != "jpg") {
var group = getGroupByName(groupName);
if (group && group.atlas) {
//加载图集,现在就一张,以后有机会改
var json = groupName + ".json"//group.atlas.split(",")[0];
//找json是否在加载中
if (singleResPromiseHash[json]) {
return singleResPromiseHash[json].then(
(r) => {
//正在加载中,getResAsync首次加载的回调会缓存,完成后返回需要的,
let cached = textureHash[str] || FYGE.TextureCache[str]
comFun && comFun.call(thisObj, cached, str)
return cached;
},
() => {
comFun && comFun.call(thisObj, null, str)
return null
}
)
} else {
return getResAsync(json)
.then(() => {
let cached = textureHash[str] || FYGE.TextureCache[str]
comFun && comFun.call(thisObj, cached, str)
return cached
}, () => {
comFun && comFun.call(thisObj, null, str)
return null
})
}
}
}
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
FYGE.GlobalLoader.loadImage((s, image) => {
//移除
delete singleResPromiseHash[str];
//入缓存
if (s) {
let cached = FYGE.Texture.from(image);
//入RES,
textureHash[str] = cached;
//入全局
FYGE.Texture.addToCache(cached, str);
comFun && comFun.call(thisObj, cached, str)
resolve(cached)
} else {
comFun && comFun.call(thisObj, null, str)
reject()
}
}, src)
})
singleResPromiseHash[str] = p
return p
}
}
else if (type == "svga") {//暂时不用,小程序时,也千万别把svga放入其他组,开发时和线上做区分
if (videoEntityHash[str]) {
comFun && comFun.call(thisObj, videoEntityHash[str], str)
return new Promise((r) => {
r(videoEntityHash[str])
})
}
//未加载完成的
else if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
} else {
var groupName = hasRes(str);
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
SvgaParser.loadSvga(
src,
(v) => {
delete singleResPromiseHash[str];
videoEntityHash[str] = v;
comFun && comFun.call(thisObj, v, str)
resolve(v)
},
(err) => {
delete singleResPromiseHash[str];
comFun && comFun.call(thisObj, null, str)
reject(err)
}
)
//@ts-ignore //以后要加
// FYGE.GlobalLoader.loadSvga((s, v) => {
// //移除
// delete singleResPromiseHash[str];
// //入缓存
// if (s) {
// if (s) videoEntityHash[str] = v;
// comFun && comFun.call(thisObj, v, str)
// resolve(v)
// } else {
// comFun && comFun.call(thisObj, null, str)
// reject()
// }
// }, src)
})
singleResPromiseHash[str] = p;
return p
}
}
//json图集的话,不晓得用啥判断加载完成,所以不删除promise吧,其实json可能只是数据,不管先
else if (type == "json") {
if (singleResPromiseHash[str]) {
return returnSingleResPromise(str, comFun, thisObj)
} else {
var groupName = hasRes(str);//json现在肯定在内,暂时不能加载其他域名的json
var src = groupName ? resPath + groupName + "/" + str : str;
var p = new Promise((resolve, reject) => {
var jsonData = getGroupByName(groupName).atlas
FYGE.GlobalLoader.loadImage((s, data) => {
if (s) {
//createTextureSheet会自行缓存全局
var t = FYGE.createTextureSheet(new FYGE.BaseTexture(data/*.img*/), jsonData)
//缓存进RES
for (let key in t) textureHash[key] = t[key];
comFun && comFun.call(thisObj, t, str)
resolve(t)
} else {
//加载失败,移除要,否则再次触发加载会出问题
delete singleResPromiseHash[str];
comFun && comFun.call(thisObj, null, str)
reject()
}
}, src.replace("json", "png"))
})
singleResPromiseHash[str] = p
return p
}
}
}
/**
* 待写,根据网络路径加载图片
*/
export function getResByUrl() {
}
/**
* 获取素材,
* @param str
* @return 已加载好得素材或null
*/
export function getRes(str: string)/*: Texture | VideoEntity*/ {
if (!str) return null;
var type = str.substring(str.lastIndexOf(".") + 1, str.length);
if (type == "png" || type == "jpg") {
return textureHash[str] || FYGE.TextureCache[str] || null;
}
else if (type == "svga") {
return videoEntityHash[str] || null;
}
else if (type == "mp3") {
return soundHash[str] || null;
}
}
/**
* 偷懒的方法,加载配置里所有的资源,基本也不用
*/
export function loadAllGroup() {
var groups = resData.groups;
var p = []
groups.forEach((g) => {
p.push(loadGroup(g.name))
})
return Promise.all(p)
}
/**
* 判断是否在资源组里
* 考虑是否init就做表
* 有就返回组名,为了加载路径,不然以后有工具可以放入resources
*/
function hasRes(str: string): string {
for (var i = 0; i < resData.groups.length; i++) {
var group = resData.groups[i];
var keys = group.keys;
if (keys && keys.split(",").indexOf(str) > -1) {
return group.name;
}
//如果是图集的json,altas现在是图集
if (group.atlas && group.name + ".json" == str) {
return group.name;
}
}
return null
}
/**
* 处理数据,获得所有资源单项
* @param name
*/
function getGroupResByName(name: string) {
var group: GroupInt = getGroupByName(name);
if (!group) return null;
//判断加载图集还是单图
if (group.atlas) {
// var arr: string[] = [].concat(group.atlas.split(","));
var arr = [name + ".json"]
//再添加非图片的资源,和图集已排除jpg
if (group.keys) {
arr = arr.concat(group.keys.split(",").filter((k: string) => {
return k.substr(-4) != ".png" //&& k.substr(-4) != ".jpg"
}))
}
return arr
}
else if (group.keys) {
return group.keys.split(",")
} else {
return null
}
}
/**
* 根据名字找组
* @param name
*/
function getGroupByName(name: string): GroupInt {
var groups = resData.groups;
var group: GroupInt;
for (var i = 0; i < groups.length; i++) {
if (groups[i].name === name) {
group = groups[i];
break;
}
}
return group
}
/**
* 新版的加载一列资源
* @param callback
* @param arr
*/
function loadResList(callback: (allLoaded: boolean) => void, arr: string[]) {
let count = 0;
let countAll = arr.length;
if (!countAll) callback(true);
let mark = true;
for (var i = 0; i < countAll; i++) {
let resName = arr[i];
getResAsync(resName, (res, str) => {
//标记失败,如果有一项资源加载失败,标记下
if (!res) mark = false
if (++count == countAll) callback(mark);
}, this)
}
}
/**
*
* @param str
* @param comFun
* @param thisObj
*/
function returnSingleResPromise(str: string, comFun?: (res: any, str: string) => void, thisObj?: any) {
//已判断是否存在
singleResPromiseHash[str].then(
(r) => {
comFun && comFun.call(thisObj, r, str)
},
() => {
comFun && comFun.call(thisObj, null, str)
}
)
return singleResPromiseHash[str];
}
//皮肤相关的也放在RES吧
let skinData: SkinInt
/**
* 添加皮肤配置文件
*/
export function loadSkinConfig(skinJson) {
skinData = skinJson;
}
/**
* 根据
* @param con 添加显示对象的容器
* @param skin 皮肤名字或数据
* @param root 根容器,为了添加自定义引用
*/
export function initSkinDisplay(con: FYGE.Container, skin: string | SkinInt, root?: FYGE.Container) {
//@ts-ignore
var data: SkinInt = typeof (skin) == 'string' ? getSkinDataByName(skin) : skin;
if (!data.children || !data.children.length) return;
// for (var i = data.children.length - 1; i >= 0; i--) {
for (var i = 0; i < data.children.length; i++) {
var child = data.children[i];
if (child.type == "item") continue;
var dis = con.addChild(getDisplayByData(child));
if (root && child.id) root[child.id] = dis;
if (child.type == "container") initSkinDisplay(dis, child, root);
}
}
/**
* 遍历根据名字找节点数据,只会是container的
* @param skinName
*/
export function getSkinDataByName(skinName: string, skinNode: SkinInt = skinData): SkinInt {
if (!skinNode || !skinNode.children || !skinNode.children.length) return null;
for (var i = 0; i < skinNode.children.length; i++) {
var child = skinNode.children[i];
if (child.name == skinName && (child.type == "container" || child.type == "item")) return child;
var gson = getSkinDataByName(skinName, child);
if (gson) return gson
}
return null;
}
/**
* 通过数据创建显示对象
* @param data
*/
function getDisplayByData(data: SkinInt): FYGE.Container {
var dis: FYGE.Container;
switch (data.type) {
case "container":
dis = new FYGE.Container();
break;
case "button":
dis = new FYGE.Button(
getRes(data.props.tUp),
data.props.tDown ? getRes(data.props.tDown) : null,
data.props.tDisable ? getRes(data.props.tDisable) : null,
);
break;
case "text":
dis = new FYGE.TextField();
for (let key in data.props) dis[key] = data.props[key];
break;
case "sprite":
dis = new FYGE.Sprite(getRes(data.props.source));
break;
case "rect":
// dis = new FYGE.Graphics()
// .beginFill(data.props.fillColor)
// .drawRect(0, 0, data.props.width, data.props.height)
// .endFill();
dis = new FYGE.Shape()
//@ts-ignore
dis.beginFill(FYGE.string2hex(data.props.fillColor))
//@ts-ignore
dis.drawRect(0, 0, data.props.width, data.props.height)
//@ts-ignore
dis.endFill();
break;
}
dis.name = data.name;
dis.alpha = data.alpha || 1;
dis.position.set(data.x, data.y);
// if (data.type == "text") dis.y -= 4;//文本莫名偏下,移动下,手机调试的时候也试试
return dis;
}
/**
* 销毁组纹理
* 线上才有用,待测试,TODO
* @param name
*/
export function destroyGroup(name: string) {
var group: GroupInt = getGroupByName(name);
if (!group) return;
var arr = [];
if (group.keys) {
arr = group.keys.split(",")
}
var removedBase = [];
//散图清除
for (var i = 0; i < arr.length; i++) {
var t: FYGE.Texture = getRes(arr[i]);
if (t) {
//base的清除,不要重复清除
if (removedBase.indexOf(t.baseTexture) == -1) {
t.baseTexture.destroy();
removedBase.push(t.baseTexture)
}
//自己纹理清除
t.destroy();
}
//RES里单独缓存的清除
delete textureHash[arr[i]]
}
}
//貌似不需要,为了加载过一次的资源不用重新加载
function destroyRES() {
}
}
/**
* 到时放到Loader里,增加open类型、headers、参数、等等
* @param options
*/
export function ajax(options: ajaxParameterInt) {
/**
* 默认为GET请求
*/
options.type = options.type || "GET";
/**
* 返回值类型默认为json
*/
options.dataType = options.dataType || 'json';
/**
* 默认为异步请求
*/
options.async = options.async === false ? false : true;
/**
* 对需要传入的参数的处理
*/
var params = getParams(options.data);
var xhr: XMLHttpRequest;
/**
* 创建一个 ajax请求
* W3C标准和IE标准
*/
if (window["XMLHttpRequest"]) {
//W3C标准
xhr = new window["XMLHttpRequest"]();
} else if (window["ActiveXObject"]) {
//@ts-ignore IE标准
xhr = new ActiveXObject('Microsoft.XMLHTTP')
} else {
console.error("当前浏览器不支持XHR请求")
return
}
//返回类型
xhr.responseType = options.dataType;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var status = xhr.status;
if (status >= 200 && status < 300) {
options.success && options.success(xhr.response);
} else {
options.error && options.error(status || "error");
}
}
};
if (options.type == 'GET') {
xhr.open("GET", options.url + '?' + params, options.async);
xhr.send(null)
} else if (options.type == 'POST') {
/**
*打开请求
*/
xhr.open('POST', options.url, options.async);//待测试,post请求
/**
* POST请求设置请求头
*/
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
if (options.headers) {
for (let key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]);
}
}
/**
* 发送请求参数
*/
xhr.send(params);
}
}
/**
* jsonp模拟,不考虑回调
* @param url
* @param params
*/
export function jsonp(url: string, params: any) {
const src = url + '?' + getParams(params);
const scriptEl = document.createElement('script');
scriptEl.src = src;
scriptEl.onload = function () {//docment考虑改成head
document.body.removeChild(scriptEl);
};
scriptEl.onerror = function () {
document.body.removeChild(scriptEl);
};
document.body.appendChild(scriptEl);
}
/**
* 对象参数的处理
* @param data
* @returns {string}
*/
function getParams(data): string {
if (!data) return "";//没有就返回空字符
var arr = [];
for (var param in data) {
arr.push(encodeURIComponent(param) + '=' + encodeURIComponent(data[param]));
}
//不缓存
arr.push('_=' + Date.now());
return arr.join('&');
}
//基本没用到过cache,先不加
interface ajaxParameterInt {
url: string,
data?: any,
type?: "GET" | "POST",
async?: boolean,
dataType?: 'text' | 'json' | 'arraybuffer',
headers?: any,
success?: (res: any) => void,
error?: (err: any) => void
}
/**
* 对封装好的ajax请求进行调用
* */
// ajax({
// url: "", //请求地址
// type: 'GET', //请求方式
// data: { name: 'zhangsan', age: '23', email: '2372734044@qq.com' }, //请求参数
// dataType: "json", // 返回值类型的设定
// async: false, //是否异步
// headers: {},
// success: function (response) {
// console.log(response); // 此处执行请求成功后的代码
// },
// error: function (status) {
// console.log('状态码为' + status); // 此处为执行成功后的代码
// }
// });
import { destroyWaiting } from "./waitingCtrl";
import PanelCtrl from "./panelCtrl";
import SceneCtrl from "./sceneCtrl";
import { destroyToast } from "./toastCtrl";
import ConfirmPanel from "../../src/common/IConfirmPanel";
export { showToast } from "./toastCtrl";
export * from "./waitingCtrl";
/**
* 展示弹框
* @param panel 弹框类
* @param data 数据
*/
export const showPanel = (panel: any, data?: any) => {
return PanelCtrl.instance.show(panel, data)
}
export const showConfirm = (panel: any, data?: any) => {
const confirmPanel: ConfirmPanel = PanelCtrl.instance.show(panel, data);
return confirmPanel.makePromise();
}
/**
* 关闭所有弹框
*/
export const closeAllPanels = () => {
PanelCtrl.instance.closeAll();
}
/**
* 关闭当前弹框
*/
export const closeCurrentPanel = () => {
PanelCtrl.instance.closeCurrent();
}
/**
* 替换场景
* @param scene
* @param data
*/
export const changeScene = (scene: any, data?: any) => {
SceneCtrl.instance.change(scene, data)
}
/**
* 获取当前场景
*/
export function getCurrentScene(): any {
return SceneCtrl.instance.currentScene
}
/**
* 淘宝小程序的alert
* @param {string} title
* @param {string} content
*/
export const showAlert = (title?: string, content?: string) => {
//@ts-ignore
if (my) {
//@ts-ignore
my.alert({
title: title || "",
content: content || ""
});
} else {
console.log(title, content)
}
}
/**
* 替换setTimeout 因为页面销毁时setTimeout不会停
* 所以干脆用Tween的
* @param {Function} callback
* @param {number} time 毫秒计
*/
export function wait(callback: () => void, time: number): {} {
let obj = {};
FYGE.Tween.get(obj)
.wait(time)
.call(callback)
return obj
}
export function clearWait(obj: {}) {
obj && FYGE.Tween.removeTweens(obj);
}
/**
* 递归清除显示对象里面所有的Tween
* @param obj
* @param isRecursive 默认true,递归移除子级
*/
export function removeTweens(obj, isRecursive: boolean = true) {
if (!obj) return
FYGE.Tween.removeTweens(obj);
if (!isRecursive || !obj.children || !obj.children.length) return
obj.children.forEach(child => {
removeTweens(child)
});
}
/**
* 销毁方法
*/
export function destroyAllCtrls() {
destroyToast();
destroyWaiting();
PanelCtrl.instance.destroy();
SceneCtrl.instance.destroy();
}
import { Panel } from "../views/Panel";
import { layers } from "../views/layers";
import { showWaiting, hideWaiting } from "./waitingCtrl";
import { showToast } from "./toastCtrl";
export default class PanelCtrl {
/**
* 父级容器
*/
private _parent: FYGE.Container;
/**
* 半透明黑色背景
*/
private _bg: FYGE.Shape;//FYGE.Graphics;
/**
* 所有的弹框
*/
private stacks: Panel[] = [];
private static _instance: PanelCtrl;
static get instance() {
return PanelCtrl._instance || (PanelCtrl._instance = new PanelCtrl())
}
init(parent: FYGE.Container) {
this._parent = parent;
let bg = new FYGE.Shape();//Graphics()//Shape();
bg.beginFill(0);
bg.drawRect(//引用适配
layers.stageOffsetX - parent.x,
layers.stageOffsetY - parent.y,
layers.stageWidth,
layers.stageHeight
);
bg.endFill();
bg.hitTestByPixel = false;
bg.visible = false;
this._parent.addChild(bg);
this._bg = bg;
}
/**
* 关闭所有弹框
*/
closeAll() {
this.stacks.forEach(e => e.hidePanel());
}
show<T extends Panel>(cls: any, data?: any): T {
showWaiting()
const panel: T = new cls(data);
this.add(panel);
this.stacks.push(panel);
panel.onLoaded = () => {
hideWaiting();
this.updateView(false);//这里更新不显示动画先,自行判断是否显示
//start只执行一边
panel.start(data);
//如果是最后一个才显示动画
if (panel.visible) panel.showAni();
}
//资源加载失败时
panel.onLoadError = () => {
hideWaiting();
showToast("资源加载失败")
panel.removeEventListener('onDestroy', this.onPanelHide, this);
this.remove(panel);
}
return panel;
}
private bgAni: "hide" | "show";
private updateView(showPanelAni: boolean = true) {
//没有弹框的时候
if (!this.stacks.length) {
// this._bg.visible = false;
// this._current = null;
// this._parent.visible = false;
if (this._bg.visible) {//原先背景存在时,待测试
this.bgAni = "hide"
FYGE.Tween.removeTweens(this._bg);
FYGE.Tween.get(this._bg)
.to({ alpha: 0 }, 200, FYGE.Ease.cubicOut)
.call(() => {
this._bg.visible = false;
this._current = null;
this._parent.visible = false;
})
}
} else {
//显示弹框层
this._parent.visible = true;
if (this.bgAni == "hide") {//如果正在执行蒙层消失动画,
this.bgAni = "show"
FYGE.Tween.removeTweens(this._bg);
this._bg.alpha = 0.7;
}
//如果首次出现弹框,加个动画
if (this._bg.visible === false) {
this._bg.visible = true;
this._bg.alpha = 0;
FYGE.Tween.get(this._bg).to({ alpha: 0.7 }, 200, FYGE.Ease.cubicOut)
}
}
for (let i = 0; i < this.stacks.length; i++) {
if (i < this.stacks.length - 1) {
this.stacks[i].visible = false;
} else {
this.stacks[i].visible = true;
if (showPanelAni) this.stacks[i].showAni();
this._current = this.stacks[i];
}
}
}
/**
* 添加进父级并添加事件
* @param panel
*/
private add(panel: Panel) {
this._parent.addChild(panel);
panel.addEventListener('onDestroy', this.onPanelHide, this);
}
/**
* 移除
* @param panel
*/
private remove(panel: Panel) {
this._parent.removeChild(panel);
this.stacks = this.stacks.filter(e => e != panel);
}
/**
* 弹框移除时执行
* @param e
*/
private onPanelHide(e: FYGE.Event) {
const panel = e.target as Panel;
panel.removeEventListener('onDestroy', this.onPanelHide, this);
this.remove(panel);
this.updateView();
}
//当前弹框
private _current: Panel;
/**
* 关闭当前弹框
*/
closeCurrent() {
if (this._current) {
this._current.hidePanel();
// this._current.removeEventListener('onDestroy', this.onPanelHide, this);
// this.remove(this._current);
// this.updateView();
}
}
destroy() {
PanelCtrl._instance = null;
this.stacks = null;
this._current = null;
this._parent = null;
FYGE.Tween.removeTweens(this._bg);
this._bg = null;
}
}
\ No newline at end of file
import { Scene } from "../views/Scene";
import { showWaiting, hideWaiting } from "./waitingCtrl";
import { showToast } from "./toastCtrl";
export default class SceneCtrl {
private _parent: FYGE.Container;
private _currentScene: Scene;
private static _instance: SceneCtrl;
static get instance() {
return SceneCtrl._instance || (SceneCtrl._instance = new SceneCtrl())
}
init(parent: FYGE.Container) {
this._parent = parent;
}
change(cls: any, data?: any) {
//如果是同一个场景,考虑是替换还是return
// if (this._currentScene && this._currentScene instanceof cls) return;//new一个得了,playScene维护太蛋疼,到时看性能吧
let scene: Scene = new cls(data);
scene.visible = false;
showWaiting();
let preScene: Scene = this._currentScene;
scene.onLoaded = () => {
hideWaiting();
scene.showAni(() => {
if (preScene) preScene.destroy();
})
scene.visible = true;
//start里可能处理资源信息,所以在onLoaded后执行
scene.start(data);
}
//加载失败,继续用之前的场景,移除scene
scene.onLoadError = () => {
hideWaiting();
showToast("资源加载失败")
this._currentScene = preScene || null;
this._parent.removeChild(scene);
}
this._currentScene = scene;
this._parent.addChild(scene);
}
get currentScene() {
return this._currentScene
}
destroy() {
SceneCtrl._instance = null;
this._currentScene = null;
this._parent = null;
}
}
\ No newline at end of file
import { layers } from "../views/layers";
import { RES } from "../RES";
let inited = false;
let _toast: Toast;
let _parent: FYGE.Container;
let startY: number
let endY: number
const initToast = () => {
if (!inited) {
inited = true;
_toast = new Toast();
_parent = layers.toastLayer;
_toast.alpha = 0;
_toast.x = layers.stageOffsetX - _parent.x + (layers.stageWidth - _toast.width) / 2;
var h = _toast.height;
var y = layers.stageOffsetY - _parent.y;
startY = y - h;
endY = y + (layers.stageHeight - h) / 2;
}
}
export const showToast = (msg: string) => {
initToast();
_toast.show(msg)
_parent.addChild(_toast);
FYGE.Tween.removeTweens(_toast);
FYGE.Tween.get(_toast)//动画看需求
.set({ y: startY, alpha: 1 })
.to({ y: endY }, 500, FYGE.Ease.quartOut)
.wait(800)
.to({ alpha: 0 }, 300)
.call(() => {
_parent.removeChild(_toast);
})
}
/**
* 对于之前淘宝小程序遇到的问题,需要销毁,否则会出问题
*/
export const destroyToast = () => {
if (inited && _toast && !_toast.destroyed) {
_toast.destroy();
_toast = null;
_parent = null;
inited = false;
}
}
/**
* toast类,不对外导出,适配居中有问题,有时间改
* 自身居中,
*/
class Toast extends FYGE.Container {
msg: FYGE.TextField;
bg: FYGE.Sprite;
PADDING = 40;
constructor() {
super();
this.mouseChildren = false;
this.mouseEnable = false;
var toastBgTexture: FYGE.Texture = RES.getRes("toastBg.png");
this.bg = new FYGE.Sprite(toastBgTexture);
// this.bg.x = (750 - 460) / 2// (layers.stageWidth - this.bg.width) / 2
this.addChild(this.bg);
this.msg = new FYGE.TextField();
this.msg.size = 28;
this.msg.fillColor = "0xffffff";
this.msg.text = "";
this.msg.verticalAlign = FYGE.VERTICAL_ALIGN.MIDDLE;
this.msg.textHeight = toastBgTexture.height;
this.msg.textAlign = FYGE.TEXT_ALIGN.CENTER;
this.addChild(this.msg)
}
/**
* 显示时调用
* @param msg
*/
show(msg: string) {
this.msg.text = msg;
//文本居中适配
this.msg.x = (this.bg.width - this.msg.textWidth) / 2//(layers.stageWidth - this.msg.textWidth) / 2;
//是否需要根据文本宽度缩放背景
// this.bg.width = Math.min(this.msg.textWidth + this.PADDING * 2, 523);
//背景居中适配,由于上面一行注释,那这行就构造函数里只执行一次吧
// this.bg.x = (layers.stageWidth - this.bg.width) / 2
}
destroy() {
FYGE.Tween.removeTweens(this);
super.destroy();
this.msg = null
this.bg = null;
}
}
\ No newline at end of file
import { RES } from "../RES";
import { layers } from "../views/layers";
import { showAlert } from ".";
let inited = false;
let _waiting: Waiting;
let _parent: FYGE.Container
const initWaiting = () => {
if (!inited) {
inited = true;
const waiting = new Waiting();
_parent = layers.topLayer;
_waiting = waiting;
//居中偏移
var offX = (layers.stageWidth - 160/*_waiting.width*/) / 2;
var offY = (layers.stageHeight - _waiting.height) / 2;
//位置适配
_waiting.x = layers.stageOffsetX - _parent.x + offX;
_waiting.y = layers.stageOffsetY - _parent.y + offY;
//阻止事件用
var bg: FYGE.Graphics = new FYGE.Graphics()
.beginFill(0x000000)
.drawRect(-offX, -offY, layers.stageWidth, layers.stageHeight)
.endFill();
bg.alpha = 0;
_waiting.addChildAt(bg, 0);
}
}
/**
* 显示菊花圈
* @param msg 尽量三个字
*/
export const showWaiting = (msg?: string) => {
initWaiting();
_waiting.show(msg)
_parent.addChild(_waiting);
}
/**
* 隐藏菊花圈
*/
export const hideWaiting = () => {
_parent.removeChild(_waiting);
}
export const destroyWaiting = () => {
if (inited && _waiting && !_waiting.destroyed) {
_waiting.destroy();
_waiting = null;
_parent = null;
inited = false;
}
}
/**
* 菊花圈,有机会重写,应该适应所有场景居中
*/
class Waiting extends FYGE.Container {
msg: FYGE.TextField;
constructor() {
super();
//圆角矩形背景
var rectBgTexture: FYGE.Texture = RES.getRes("waitingBg.png")
var rectBg = new FYGE.Sprite(rectBgTexture);
this.addChild(rectBg);
var rotTexture: FYGE.Texture = RES.getRes("waitingRot.png")
let rot = new FYGE.Sprite(rotTexture);
rot.x = (rectBgTexture.width - rotTexture.width) / 2
rot.y = 47//533;
rot.anchorX = rotTexture.width / 2;
rot.anchorY = rotTexture.height / 2;
this.addChild(rot);
let count = 0;
rot.addEventListener(FYGE.Event.ENTER_FRAME, () => {
count++;
if (count % 30 == 0) rot.rotation += 45;
}, this)
this.msg = new FYGE.TextField();
this.msg.y = 125;
this.msg.textWidth = rectBgTexture.width;
this.msg.textAlign = FYGE.TEXT_ALIGN.CENTER;
this.msg.size = 26
this.msg.fillColor = "#ffffff";
this.addChild(this.msg);
}
show(msg: string = "加载中") {
this.msg.text = msg;
}
destroy() {
super.destroy();
this.msg = null;
}
}
const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/**
* base64编码汉字,
* 一般用于链接参数传递,
* 先base64.encode,再encodeURIComponent后带入,取参数时会decodeURIComponent,然后再base64.decode后
* 直接调用Base64.ins
*/
export class Base64 {
// private property
// _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
private static instance: Base64;
public static get ins(): Base64 {
if (!this.instance) {
this.instance = new Base64();
}
return this.instance;
}
constructor() {
}
// public method for encoding
encode(input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = this._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
decode(input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = this._utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
private _utf8_encode(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
private _utf8_decode(utftext) {
var string = "";
var i = 0;
var c = 0;
var c2 = 0;
var c3 = 0
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
\ No newline at end of file
/**
* 回收池
*/
export class GPool {
private static pool = {};
/**
* 取出
* @param name
*/
public static takeOut(name: string) {
if (this.pool[name] && this.pool[name].length) {
return this.pool[name].shift();
}
return null;
}
/**
* 回收
* @param name
* @param obj
*/
public static recover(name: string, obj) {
if (!this.pool[name]) {
this.pool[name] = [];
}
this.pool[name].push(obj);
}
}
\ No newline at end of file
/**
* 用到的和业务相关的
* 各种静态方法汇总
*
* 获取修改链接参数
* 获取cookie
* 缓存相关
* 数组相关
*
*/
export class GTool {
/**
* 读取缓存
*/
public static readCache(key: string/*, type: string = 'localStorage'*/) {
//@ts-ignore
return my ? my.getStorageSync({ key: key }).data : localStorage ? localStorage.getItem(key) : null;
// if (!window.localStorage) {
// return false;
// }
// return window[type].getItem(key);
}
/**
* 写缓存
*/
public static writeCache(key: string, value: any = 'true'/*, type: string = 'localStorage'*/) {
//@ts-ignore
my ? my.setStorageSync({ key: key, data: value }) : localStorage && localStorage.setItem(key, value);
// if (!window.localStorage) {
// // trace(Func.replace(SysLang.lang_012, [type]));
// return;
// }
// window[type].setItem(key, value);
}
/**
* 获得cacheKey今日次数
* 第二天归0重新计数
* @param cacheKey
*/
public static returnTodayTimes(cacheKey: string): number {
var year1 = this.readCache("year" + cacheKey);
var month1 = this.readCache("month" + cacheKey);
var day1 = this.readCache("day" + cacheKey);
var date = new Date();
var year2 = date.getFullYear().toString();
var month2 = date.getMonth().toString();
var day2 = date.getDate().toString();
if (this.int(year2) <= this.int(year1)) {
if (this.int(month2) <= this.int(month1)) {
if (this.int(day2) <= this.int(day1)) {
return this.int(this.readCache(cacheKey));
}
}
}
//如果不是同一天了,归0
var today = "0";
this.writeCache("year" + cacheKey, year2);
this.writeCache("month" + cacheKey, month2);
this.writeCache("day" + cacheKey, day2);
this.writeCache(cacheKey, today);
return 0;
}
/**
* 随机,两个参数时是数值范围,比如randomT(1,10),一个参数时是数组
* @param e
* @param n
*/
public static randomT(e, n?) {
return e && "number" == typeof e.length && e.length ? e[Math.floor(Math.random() * e.length)] : ("number" != typeof n && (n = e || 1, e = 0), e + Math.random() * (n - e))
}
/**
* 从数组中移除一个元素
* @param e 元素
* @param arr 数组
*/
public static removeEle(e, arr) {
var index = arr.indexOf(e);
if (index >= 0) {
arr.splice(index, 1)
}
}
/**
* 数组中插入一个数值,按顺序的
* 数组是从小到大的
* @param num
* @param arr
*/
public static insert(num, arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if (num > arr[i]) {
//在arr[i]后加num
arr.splice(i + 1, 0, num);
break
}
}
}
/**
* 获取start到end里的n个整数
* @param start 0
* @param end 19
* @param n 3
*/
public static getRandomNumber(start: number, end: number, n: number): number[] {
var arr = [];
for (var i = 0; i < n; i++) {
var number = Math.floor(Math.random() * (end - start + 1) + start);
if (arr.indexOf(number) < 0) {
arr.push(number);
} else {
i--;
}
}
return arr;
}
/**
* 打乱数字数组,改变原数组
* @param arr
*/
public static disturbNumberArr(arr: number[]) {
arr.sort(function () {
return (0.5 - Math.random());
});
}
public static disturbArr(arr: any[]) {
return arr.sort(function () {
return (0.5 - Math.random());
});
}
/**
* 其实打乱数组取前几个就行
* 随机取数组arr中count个元素,不改变原数组
* @param arr
* @param count
*/
public static getRandomArrayElements(arr: any[], count: number) {
var shuffled = arr.slice(0), i = arr.length, min = i - count, temp, index;
//如果count大于等于数组长度,返回所有数组
if (min <= 0) return shuffled;
if (count <= 0) return [];
//随机排序,然后取出后面的元素
while (i-- > min) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
}
/**
* 随机取数组arr中count个元素,原数组减少count个
* @param arr
* @param count
*/
public static getRandomArrayElementsEx(arr: any[], count: number): any[] {
//如果count大于等于数组长度,返回所有数组
if (arr.length <= count) return arr.slice();
if (count <= 0) return [];
var arrCopy = arr.slice();
var outArr = [];
while (count--) {
var rand = Math.floor(Math.random() * arrCopy.length);
var ele = arrCopy.splice(rand, 1)[0];
outArr.push(ele);
}
return outArr
}
/**
* 向下取整,或把字符串执行parseInt(字符串转数字取整数部分)
* @param n 数字或字符串
*/
private static int(n: any): number {
return n >> 0;//~~n
};
/**
* emoji正则式
*/
public static emojiReg = /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/ig
/**
* 在字符串间加空格
* @param str
*/
public static addSpaceInString(str: string) {
if (!str.length || str.length == 1) return str;
var txt = "";
//每个字符后加空格
for (var i = 0; i < str.length - 1; i++) {
txt = txt + str[i] + " ";
}
txt = txt + str[str.length - 1]
return txt
}
/**
* 毫秒剩余时间转成时分秒
* 1小时1分1秒
* @param timeStamp
*/
public static getShiFenMiaoByTimeStamp(timeStamp: number) {
var hours: any = Math.floor((timeStamp % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes: any = Math.floor((timeStamp % (1000 * 60 * 60)) / (1000 * 60));
// var seconds: any = (timeStamp % (1000 * 60)) / 1000;
var seconds: any = Math.floor((timeStamp % (1000 * 60)) / 1000);
hours = hours < 10 ? ('0' + hours) : hours;
minutes = minutes < 10 ? ('0' + minutes) : minutes;
seconds = seconds < 10 && seconds >= 1 ? ('0' + seconds) : seconds;
// return hours + " :" + minutes + " :" + seconds;
return hours + "小时" + minutes + "分" + seconds + "秒";
}
/**
* 获取字符串真实长度,中文算两个
* @param str
*/
static getRealStringLength(str: string): number {
var realLength = 0, len = str.length, charCode = -1;
for (var i = 0; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode >= 0 && charCode <= 128) realLength += 1;
else realLength += 2;
}
return realLength;
}
/**
* 切字符串
* @param str
* @param realLength
* @param tailStr
*/
static cutStringAcoRealLength(str: string, limit: number, tailStr: string = "...") {
let length = 0;
let out = "";
for (let i of str) {
let charCode = i.charCodeAt(0);
if (charCode >= 0 && charCode <= 128) length += 1;
else length += 2;
if (length <= limit) {
out = out.concat(i);
} else {
out = out.concat(tailStr);
break;
}
}
return out;
}
}
\ No newline at end of file
/////这里集成一些只有web环境才会用到的方法,链接参数,cookie参数等等
let urlParams: { [key: string]: string | true };
/**
* 获取链接参数
* @param key
*/
export function getUrlParams(key: string): string | true {
if (urlParams) return urlParams[key];
urlParams = {};
let search = window.location.search;
try {
search = top.location.search; //尝试获取顶层的链接
} catch (e) {
}
//获取链接参数
for (let item of search.replace('?', '').split('&')) {
let arr = item.split('=');
urlParams[arr[0]] = arr.length === 1 ? true : decodeURIComponent(arr[1]);
}
return urlParams[key];
}
let cookieParams: { [key: string]: string }
/**
* cookie参数
*/
export function getCookieParams(key: string): string {
if (cookieParams) return cookieParams[key]
cookieParams = {};
var arr1 = document.cookie.split("; ");//由于cookie是通过一个分号+空格的形式串联起来的,所以这里需要先按分号空格截断,变成[name=Jack,pwd=123456,age=22]数组类型;
for (var i = 0; i < arr1.length; i++) {
var arr2 = arr1[i].split("=");//通过=截断,把name=Jack截断成[name,Jack]数组;
cookieParams[arr2[0]] = decodeURIComponent(arr2[1]);
// if (arr2[0] == key) {
// return decodeURIComponent(arr2[1]);
// }
}
return cookieParams[key];
}
/**
* 替换或添加url里的参数
* @param url 修改的url
* @param arg 参数名
* @param arg_val 参数值
*/
export function changeURLArg(url: string, arg: string, arg_val: string) {
var pattern = arg + '=([^&]*)';
var replaceText = arg + '=' + arg_val;
if (url.match(pattern)) {
var tmp = '/(' + arg + '=)([^&]*)/gi';
tmp = url.replace(eval(tmp), replaceText);
return tmp;
} else {
if (url.match('[\?]')) {
return url + '&' + replaceText;
} else {
return url + '?' + replaceText;
}
}
}
/**
* 输入框ios兼容,如果加过输入框,加
*/
export function inputFeildIosEnable() {
var u = navigator.userAgent, app = navigator.appVersion
var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isIOS) {
setTimeout(() => {
document.getElementsByTagName('input')[0].onblur = function () {
if (isIOS) {
blurAdjust()
// alert("1231321233")
}
};
}, 50)
}
// 解决苹果不回弹页面
function blurAdjust() {
setTimeout(() => {
// alert("1231321233")
if (document.activeElement.tagName == 'INPUT' || document.activeElement.tagName == 'TEXTAREA') {
return
}
let result = 'pc';
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { //判断iPhone|iPad|iPod|iOS
result = 'ios'
} else if (/(Android)/i.test(navigator.userAgent)) {  //判断Android
result = 'android'
}
if (result = 'ios') {
document.activeElement["scrollIntoViewIfNeeded"](true);
}
}, 100)
}
}
/**
* 处理iOS 微信客户端弹窗状态下调起输入法后关闭输入法页面元素错位解决办法
* 输入框不能在屏幕外下面放dom,否则回弹有问题
*/
export function inputIosAdapte() {
var ua = window.navigator.userAgent.toLowerCase();
if (/iphone|ipod|ipad/i.test(navigator.appVersion) && /MicroMessenger/i.test(ua)) {
document.body.addEventListener('focusout', () => {
console.log('focusout')
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
});
}
}
let el: HTMLDivElement;
/**
* html文本转纯文本
* @param htmlText
*/
export function htmlToPureText(htmlText: string) {
if (!el) el = document.createElement('div');
el.innerHTML = htmlText;
document.body.appendChild(el);
let pureText = el.innerText;
document.body.removeChild(el);
return pureText;
}
\ No newline at end of file
export const duiba_md5 = (function (/*$*/) {
// function safe_add(x, y) {
// var lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16);
// return (msw << 16) | (lsw & 65535)
// }
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t)
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t)
}
function binl_md5(x, len) {
x[len >> 5] |= 128 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var i, olda, oldb, oldc, oldd, a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
for (i = 0; i < x.length; i += 16) {
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = md5_ff(a, b, c, d, x[i], 7, -680876936);
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i], 20, -373897302);
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5_hh(d, a, b, c, x[i], 11, -358537222);
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i], 6, -198630844);
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd)
}
return [a, b, c, d]
}
function binl2rstr(input) {
var i, output = "";
for (i = 0; i < input.length * 32; i += 8) {
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 255)
}
return output
}
function rstr2binl(input) {
var i, output = [];
output[(input.length >> 2) - 1] = undefined;
for (i = 0; i < output.length; i += 1) {
output[i] = 0
}
for (i = 0; i < input.length * 8; i += 8) {
output[i >> 5] |= (input.charCodeAt(i / 8) & 255) << (i % 32)
}
return output
}
function rstr_md5(s) {
return binl2rstr(binl_md5(rstr2binl(s), s.length * 8))
}
function rstr_hmac_md5(key, data) {
var i, bkey = rstr2binl(key), ipad = [], opad = [], hash;
ipad[15] = opad[15] = undefined;
if (bkey.length > 16) {
bkey = binl_md5(bkey, key.length * 8)
}
for (i = 0; i < 16; i += 1) {
ipad[i] = bkey[i] ^ 909522486;
opad[i] = bkey[i] ^ 1549556828
}
hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binl_md5(opad.concat(hash), 512 + 128))
}
function rstr2hex(input) {
var hex_tab = "0123456789abcdef", output = "", x, i;
for (i = 0; i < input.length; i += 1) {
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 15) + hex_tab.charAt(x & 15)
}
return output
}
function str2rstr_utf8(input) {
return unescape(encodeURIComponent(input))
}
function raw_md5(s) {
return rstr_md5(str2rstr_utf8(s))
}
function hex_md5(s) {
return rstr2hex(raw_md5(s))
}
function raw_hmac_md5(k, d) {
return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))
}
function hex_hmac_md5(k, d) {
return rstr2hex(raw_hmac_md5(k, d))
}
var duiba_md5 = function (string, key?, raw?) {
if (!key) {
if (!raw) {
return hex_md5(string)
} else {
return raw_md5(string)
}
}
if (!raw) {
return hex_hmac_md5(key, string)
} else {
return raw_hmac_md5(key, string)
}
};
var hexcase = 0;
var b64pad = "";
var chrsz = 8;
// $.extend({
// duiba_b64_sha: function (input) {
// return binb2b64(core_sha1(str2binb(input), input.length * chrsz))
// }
// });
function core_sha1(x, len) {
x[len >> 5] |= 128 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for (var j = 0; j < 80; j++) {
if (j < 16) {
w[j] = x[i + j]
} else {
w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1)
}
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde)
}
return Array(a, b, c, d, e)
}
function sha1_ft(t, b, c, d) {
if (t < 20) {
return (b & c) | ((~b) & d)
}
if (t < 40) {
return b ^ c ^ d
}
if (t < 60) {
return (b & c) | (b & d) | (c & d)
}
return b ^ c ^ d
}
function sha1_kt(t) {
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514
}
function core_hmac_sha1(key, data) {
var bkey = str2binb(key);
if (bkey.length > 16) {
bkey = core_sha1(bkey, key.length * chrsz)
}
var ipad = Array(16), opad = Array(16);
for (var i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 909522486;
opad[i] = bkey[i] ^ 1549556828
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160)
}
function safe_add(x, y) {
var lsw = (x & 65535) + (y & 65535);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 65535)
}
function rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt))
}
function str2binb(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz) {
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i % 32)
}
return bin
}
function binb2str(bin) {
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz) {
str += String.fromCharCode((bin[i >> 5] >>> (32 - chrsz - i % 32)) & mask)
}
return str
}
function binb2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 15) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 15)
}
return str
}
function binb2b64(binarray) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3) {
var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 255) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 255) << 8) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 255);
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32) {
str += b64pad
} else {
str += tab.charAt((triplet >> 6 * (3 - j)) & 63)
}
}
}
str = str + "=";
return str
}
// window.duiba_md5 = duiba_md5;
return duiba_md5
}(/*Zepto*/));
\ No newline at end of file
///////////////////时间相关的方法放这里
/**
* 判断当前时间是否在指定时间区间内,每日,注意没判断起始时间是否肯定小于结束时间
* @param beginTime 形如"9:30","09:30",起始时间
* @param endTime 形如"21:30",结束时间
*/
export function checkAuditDayTime(beginTime: string, endTime: string): boolean {
return !checkBeforeDayTime(beginTime) && checkBeforeDayTime(endTime)
}
/**
* 判断当前时间是否在给定时间前,每天
* 精确到分,有需要自行改造截取方法和setHours传参
* @param time 形如"11:30","09:30",小时 0(午夜) ~ 23(晚上11点),分0 ~ 59 之间,负数或超出,会进行进制换算
* @returns 返回true表示当前时间小于传入时间,即未到传入时间
*/
export function checkBeforeDayTime(time: string): boolean {
var nowDate = new Date();
var timeDate = new Date(nowDate);
var index = time.lastIndexOf("\:");
var hour = time.substring(0, index);
var minue = time.substring(index + 1, time.length);
timeDate.setHours(+hour, +minue, 0, 0);
return nowDate.getTime() < timeDate.getTime()
}
/**
* 毫秒剩余时间转成时分秒,具体格式自行修改
* 01时01分01秒
* @param timeStamp
*/
export function getShiFenMiaoByTimeStamp(timeStamp: number): string {
var hours: any = Math.floor((timeStamp % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes: any = Math.floor((timeStamp % (1000 * 60 * 60)) / (1000 * 60));
var seconds: any = Math.floor((timeStamp % (1000 * 60)) / 1000);
hours = hours < 10 ? ('0' + hours) : hours;
minutes = minutes < 10 ? ('0' + minutes) : minutes;
seconds = seconds < 10 ? ('0' + seconds) : seconds;
// return hours + ":" + minutes + ":" + seconds;
return hours + "时" + minutes + "分" + seconds + "秒";
}
/**
* 根据时间戳返回各种格式,自行修改,到时加枚举
* @param timeStamp 时间戳
* @return 20190606 09:05:33 2019-06-06 09:05:33 2019/06/06 09:05:33 2019年3月12日10时9分29秒
*/
export function getDateTime(timeStamp: number): string {
function add0(m: number) {
return m < 10 ? '0' + m : m
}
var time = new Date(timeStamp);
var y = time.getFullYear();
var m = time.getMonth() + 1;
var d = time.getDate();
var h = time.getHours();
var mm = time.getMinutes();
var s = time.getSeconds();
// return "" + y + add0(m) + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
// return "" + y + '-' + add0(m) + '-' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
// return "" + y + '/' + add0(m) + '/' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s);
return y + "年" + m + '月' + d + '日' + h + '时' + mm + '分' + s + '秒'
}
/**
* 日期格式转时间戳
* 时间格式得用/,ios用-有问题,"2019/06/17 00:00:00",,,,ios也不能直接用Number(new Date())
* @param date "2019/06/17 00:00:00" "2019-06-17 00:00:00"
*/
export function getTimeStampByDate(date: string) {
return new Date(date.replace(/-/g, "/")).getTime();
}
/**
* 快速获取年月日时分秒 "2021-02-01 18:32:32"
* @param timeStamp 不传表示当前
*/
export function getDate(timeStamp: number = Date.now()): string {
//有局限性,但是无妨 19暂时年份不会超
return new Date(timeStamp + 8 * 3600 * 1000).toJSON().substr(0, 19).replace("T", " ");
}
/**
* 判断两个时间戳是否为同一天
* @param time1
* @param time2
*/
export function checkSameDay(time1: number, time2: number): boolean {
return new Date(time1).toDateString() === new Date(time2).toDateString()
}
import { ajax } from "../ajax";
// sdk 不能加crossorign
// <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
// 小程序分享得用这个
// <script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
/**
* 判断是否是微信环境
*/
export function isWxClient() {
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) && ua.match(/MicroMessenger/i)[0] == "micromessenger") {
return true;
}
return false;
};
/**
* 初始化微信分享配置
*/
export function initWxConfig(callback?: (s: boolean) => void, debug: boolean = false) {
if (!isWxClient()) {
callback && callback(false)
return;
}
//微信分享,获取分享签名
ajax({
type: 'GET',
url: '/wechatShare/getShareInfo/v2',
data: { url: window.location.href },//有问题再检查链接//部分链接参数会导致初始化失败,以后中文参数用base,%用自定字符替换
dataType: 'json',
success: function (data) {
if (data.success) {
console.log("微信配置获取:")
window["wx"].config({
debug,
appId: data.wxappid,
timestamp: data.wxtimestamp,
nonceStr: data.wxnonceStr,
signature: data.wxsignature,
jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'chooseImage']
});
callback && callback(true)
} else {
callback && callback(false)
}
},
error: function (data) {
callback && callback(false)
}
});
}
/**
* 初始化分享信息
* @param title 标题
* @param desc 描述,朋友圈无
* @param link 主域名一致的链接,且是https
* @param imgUrl 图片必须是https
*/
export function initWxShare(
title: string,
desc: string,
link: string,
imgUrl: string
) {
//执行ready可重新设置分享信息
window["wx"].ready(function () {
window["wx"].onMenuShareTimeline({
title,
link,
imgUrl,
success: function (res) {
}
});
//监听“分享给朋友”按钮点击、自定义分享内容及分享结果接口
window["wx"].onMenuShareAppMessage({
title,
desc,
link,
imgUrl,
success: function (res) {
}
});
})
}
//模拟下$ TODO
// 或者引个zepto
// <script crossorigin="anonymous" src="//yun.duiba.com.cn/db_games/libs/zepto_security_downloadApp.min.js"></script>
//易盾的sdk
// <script type="text/javascript" src="//cstaticdun.126.net/load.min.js"></script> -->
var $ = window["$"]
/**
* @note 极验 - 第三方插件
* @author 张晨辰
* @email zcc@duiba.com.cn
* @create 2017-04-19 12:01:45
* @update 2017-06-28 10:06:00
* @des https://www.163yun.com/help/documents/294963579379175424
* @dependencies <script type="text/javascript" src="//c.dun.163yun.com/js/c.js"></script>
* 2.0 <script src="//cstaticdun.126.net/load.min.js"></script> 用下面这个
*/
let captchaIns;
export function initNECaptcha(options) {
if (!options.captchaId) {
return false;
}
$('body').append('<div class="captcha"><div id="check_wrapper" class="neCaptcha-dialog"></div></div>');
var opts = {
element: '#check_wrapper', // 可以是验证码容器id,也可以是HTMLElement
captchaId: options.captchaId, // 这里填入申请到的验证码id
width: options.width || 270, // 验证码组件显示宽度
mode: options.mode || 'embed',
onVerify: function (err, data) {
if (!err) {
$(".captcha").unbind("click");
$('.captcha').remove();
// data.validate = base64.encode(data.validate);
options.callback && options.callback(data);
}
}
}
window["initNECaptcha"] && window["initNECaptcha"](opts, function (instance) {
captchaIns = instance
$(".captcha").click(function (e) {
if (e.target.className == "captcha") {
if (captchaIns) captchaIns.refresh()
}
});
}, function (err) {
console.log(err, 55655665)
//初始化失败,点击黑色区域重新初始
$(".captcha").click(function (e) {
// if (e.target.className == "captcha") {
$(".captcha").unbind("click");
$('.captcha').remove();
initNECaptcha(options)
// }
});
});
window["loading"] && window["loading"].close();
$('.captcha').show();
};
//例子
initNECaptcha({
captchaId: /*Tools.captchId*/111, //a869bfdfb9bd4cdf88e1ff2f8667a114
callback: function (ret) {
console.log(ret.validate)
}
})
/* 易盾css*/
.captcha {
display: none;
position: fixed;
z-index: 10000;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.6);
}
.captcha .neCaptcha-dialog {
background-color: #fff;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.35);
-webkit-box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.35);
position: absolute;
left: 50%;
top: 45%;
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
width: 270px;
height: 134px;
}
.captcha .neCaptcha-dialog::after {
position: absolute;
content: '单次游戏结束,请拖动滑块提交分数';
width: 100%;
height: 30px;
top: -40px;
left: 0;
text-align: center;
line-height: 30px;
font-size: 16px;
color: #ffff00;
}
.captcha .neCaptcha-dialog::before {
background-color: #fff;
content: '';
display: block;
width: 280px;
height: 144px;
position: absolute;
top: -5px;
left: -5px;
z-index: -1;
}
\ No newline at end of file
import { RES } from "../RES";
/**
* 暂时用列表的接口
*/
export class Item extends FYGE.Container implements FYGE.IScrollListItem {
get skinName(): string { return null };
constructor(data?) {
super();
if (this.skinName) RES.initSkinDisplay(this, this.skinName, this);
/*setTimeout(() => {*/ this.initUi(data); /*})*///考虑是否可以不加延时,加了会有问题,自行调用的updateData会先执行,不加的话继承类里initUi里的属性。。。
}
/**
* 自定义的初始布局方法
* 注意声明的变量会覆盖initUi里赋值的变量,
*/
initUi(data?) {
}
/**
* 自行调用的更新数据方法
*/
updateData(data?) {
}
/**
* 滚动列表的数据更新方法
* @param id
* @param data
*/
initData(id: number, data: any): void {
this.id = id;//这两个直接赋值吧
this.data = data;
this.resetData();
}
id: number;
data: any;
/**
* 滚动列表ScrollList里专用
* 重置item里属性及显示对象属性的方法,
* 在每次initData会调用
*/
resetData() {
}
}
import { RES } from "../RES";
import { removeTweens } from "../ctrls";
/**
*
*/
export class Module extends FYGE.Container {
protected data: any;
constructor(data?: any) {
super();
this.data = data;
this.init();
}
/**
* 初始化资源和皮肤
*/
private init() {
this.preLoadRes().then(
() => {
//添加皮肤配置
if (this.skinName) RES.initSkinDisplay(this, this.skinName, this);
this.initUi();
this.onLoaded && this.onLoaded();
},
() => {
this.onLoadError && this.onLoadError();
}
);
}
/**
* 提前加载的资源
*/
protected preLoadRes() {
return new Promise((resolve, reject) => {
if (this.groupNames && this.groupNames.length) {
var arr: Promise<any>[] = [];
for (var i = 0; i < this.groupNames.length; i++) {
arr.push(RES.loadGroup(this.groupNames[i]))
}
Promise.all(arr).then(resolve, reject)
} else {
resolve()
}
})
}
/**
* 初始化ui
* 子类修改
*/
protected initUi() {
}
/**
* 资源加载完成后执行,用于场景及弹框控制
*/
onLoaded: () => void
/**
* 资源加载失败时执行,用于场景及弹框控制
*/
onLoadError: () => void;
/**
* 可以有多个组
*/
get groupNames(): string[] { return null }
/**
* 皮肤名字
*/
get skinName(): string { return null };
/**
* 在构造函数后执行
*/
start(data?: any) {
this.initEvents();
}
/**
* 添加事件
*/
initEvents(): void {
}
/**
* 移除事件
*/
removeEvents(): void {
}
/**
* 鼠标事件
* @param enable
*/
protected enableMouseEvt(enable: boolean): void {
this.mouseEnable = enable;
this.mouseChildren = enable;
}
/**
* 延时防连点
* @param target
* @param {number} delay
*/
protected btnDelay(target, delay = 2000) {
target.mouseEnable = false;
target.mouseChildren = false;
setTimeout(() => {
target.mouseEnable = true;
target.mouseChildren = true;
}, delay);
}
public destroy(): void {
//以防有些地方用了showAni
removeTweens(this);
// this.data = null;//看情况吧,有时候hidePanel后用了data,注意,还是先去掉吧
//移除事件
this.removeEvents();
//派发销毁事件,主要用于场景及弹框控制
this.dispatchEvent("onDestroy");
super.destroy();
}
}
import { Module } from "./Module";
export class Panel extends Module {
protected isShowing: boolean
showAni() {
if (this.isShowing) return;
this.isShowing = true;
let oriY = this.y || 0;
this.y = -200;
FYGE.Tween.get(this)
.to({y: oriY}, 500, FYGE.Ease.quartOut)
.call(() => {
this.isShowing = false;
})
}
initEvents() {
this.closeBtns.forEach(
btn => {
if (btn) btn.addEventListener(FYGE.MouseEvent.CLICK, this.hidePanel, this)
}
)
}
removeEvents() {
this.closeBtns.forEach(
btn => {
if (btn) btn.removeEventListener(FYGE.MouseEvent.CLICK, this.hidePanel, this)
}
)
}
/**
* 需要的放入,不重复写关闭按钮事件
*/
protected get closeBtns(): any[] {
return [this['closeBtn']]
}
hidePanel() {
this.destroy();
}
}
import { Module } from "./Module";
export class Scene extends Module {
/**
* 显示动画
* 继承时注意,回调要加
* 因为这种动画基本原场景最好不消失
*/
showAni(callback: Function) {
callback()
}
/**
* 统一更新方法
*/
updateScene() {
}
}
\ No newline at end of file
import PanelCtrl from "../ctrls/panelCtrl";
import SceneCtrl from "../ctrls/sceneCtrl";
/**
* 添加进舞台的所有层级
* 仿白鹭的那套
*/
class Layers extends FYGE.Container {
private _bottomLayer: FYGE.Container;
private _sceneLayer: FYGE.Container;
private _popupLayer: FYGE.Container;
private _toastLayer: FYGE.Container;
private _topLayer: FYGE.Container;
private _shareLayer: FYGE.Container;
init(stage: FYGE.Stage) {
stage.addChild(this);
var arr = [
"_bottomLayer",
"_sceneLayer",
"_popupLayer",
"_toastLayer",
"_topLayer",
"_shareLayer"
];
for (var i = 0; i < arr.length; i++) {
this[arr[i]] = new FYGE.Container();
//有些时候,定宽的时候,部分layer置顶,部分居中,再处理
//为了都置顶和置左,stage的方式永远居中视窗,要么改stage永远左上为00
// this[arr[i]].y = this.stageOffsetY;
//如果定宽这里没必要,肯定是0
// this[arr[i]].x = this.stageOffsetX;//去掉,定高时就居中了
this.addChild(this[arr[i]]);
}
//都以顶部适配
// this.sceneLayer.y = this.stageOffsetY;
// this.popupLayer.y = this.stageOffsetY;
//都以底部适配
// this.sceneLayer.y = -this.stageOffsetY;
// this.popupLayer.y = -this.stageOffsetY;
//这个因为psd弹框不规范
// this.popupLayer.y -= 420 / 2;
this.shareLayer.y = -this.stageOffsetY;
//初始化场景层级
SceneCtrl.instance.init(this.sceneLayer)
//初始化弹框层级
PanelCtrl.instance.init(this.popupLayer)
}
/**
* 底图所在层级,比如统一的背景
*/
get bottomLayer() { return this._bottomLayer }
/**
* 场景
*/
get sceneLayer() { return this._sceneLayer }
/**
* 弹框
*/
get popupLayer() { return this._popupLayer }
/**
* toast所在层级
*/
get toastLayer() { return this._toastLayer }
/**
* 顶层,比如统一标题栏等
*/
get topLayer() { return this._topLayer }
/**
* 分享引导层
*/
get shareLayer() { return this._shareLayer }
/**
* 舞台信息都放在layers里吧
* 舞台可见高度,初始化后才能使用
*/
get stageHeight() {
if (!this.stage) return 0;
return this.stage.viewRect.height;
}
/**
* 舞台可见宽度
*/
get stageWidth() {
if (!this.stage) return 0;
return this.stage.viewRect.width;
}
/**
* 适配方式x两边偏移的量,固定宽度x为0
*/
get stageOffsetX() {
if (!this.stage) return 0;
return this.stage.viewRect.x;
}
get stageOffsetY() {
if (!this.stage) return 0;
return this.stage.viewRect.y;
}
/**
* 舞台中心点位置x
*/
// get stageCenterX(): number {
// return this.stage.viewRect.x + this.stage.viewRect.width >> 1;
// }
/**
* 舞台中心点位置y,layer位置做过偏移的就不对了,所以还是自行算吧
*/
// get stageCenterY(): number {
// return this.stage.viewRect.y + this.stage.viewRect.height >> 1;
// }
}
export const layers = new Layers();
//先执行,在淘宝小程序中重新进入会再次初始化
export function destroyLayers() {
//所有层级移除,init会重新建
layers.removeChildren();
//从父级stage移除自己,init会重新加
if (layers.parent) layers.parent.removeChild(layers)
}
import { SentryInit } from '@spark/monitor-sdk';
if (CFG && CFG.MONITOR) {
SentryInit({
projectId: CFG.projectId,
name: CFG.projectName, // 线上正式项目的名称
sourcemapVersion:CFG.SOURCEVERSION,
users: [] // 前端开发者的钉钉手机号,字符串类型,可多个, 例如 ['176xxxx', '151xxxx']
});
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "temp_base",
"name": "temp_fygecanvas",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development node ./config/webpack.dev.config.js",
"imgmin": "node ./config/scripts/assets/index.js imgmin",
"imgup": "node ./config/scripts/assets/index.js imgup",
"imgminup": "node ./config/scripts/assets/index.js imgmin imgup",
"prod": "cross-env NODE_ENV=production node ./config/webpack.prod.config.js",
"build": "cross-env NODE_ENV=production node ./config/scripts/assets/index.js imgmin imgup && node ./config/webpack.prod.config.js"
"description": "",
"main": "index.html",
"devDependencies": {
"ali-oss": "^4.11.4",
"chalk": "^2.3.0",
"co": "^4.6.0",
"del": "^2.2.1",
"fs": "0.0.2",
"imagemin": "^7.0.1",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"mock-webpack-plugin": "^2.0.0",
"path": "^0.12.7",
"progress": "^2.0.0",
"ts-loader": "^4.0.0",
"tslint": "^5.9.1",
"typescript": "^3.5.1",
"webpack": "^4.1.0",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.0",
"webpack-merge": "^4.1.2",
"readline": "^1.3.0"
},
"dependencies": {
"@spark/api-base": "^2.0.30",
"@spark/monitor-sdk": "^1.1.3",
"@spark/projectx": "^2.0.13",
"@spark/ui": "^2.0.36",
"@spark/utils": "^2.0.46",
"axios": "^0.19.2",
"css-loader": "^3.6.0",
"duiba-utils": "^1.0.2",
"history": "^4.10.1",
"mobx": "^6.2.0",
"mobx-react": "^7.1.0",
"postcss-loader": "^3.0.0",
"prettier": "^2.0.5",
"qs": "^6.9.4",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-router-dom": "^5.2.0",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0",
"spark-utils": "^0.0.12",
"style-loader": "^1.2.1",
"@spark/api-common": "^2.0.15",
"@spark/share": "^2.0.86",
"@spark/nbxiaoxiaole": "^1.0.84",
"@spark/animation": "^2.0.44"
"duiba-utils": "^1.0.9"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-decorators": "^7.13.15",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"autoprefixer": "^9.8.6",
"babel-loader": "^8.2.2",
"chalk": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.3",
"eslint-loader": "^4.0.2",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "^4.5.1",
"less": "^4.1.0",
"less-loader": "^7.2.1",
"mini-css-extract-plugin": "^1.3.4",
"mocker-api": "^2.7.5",
"mockjs": "^1.1.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-px2rem-exclude": "0.0.6",
"progress-bar-webpack-plugin": "^2.1.0",
"spark-assets": "^1.1.5",
"spark-log-event": "^1.0.2",
"url-loader": "^4.1.1",
"webpack": "^4.43.0",
"webpack-cli": "^4.3.1",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2"
}
"scripts": {
"clearSameImg": "node scripts/clearSameImg && node scripts/flushRes",
"createModule": "node scripts/createModule",
"createAllModule": "node scripts/createAllModule",
"flushRes": "node scripts/flushRes",
"handleRes": "node scripts/delRel && node scripts/copyRes && node scripts/createTm && node scripts/textureMerge && node scripts/delTm && node scripts/imageMin",
"upload": "node scripts/upload",
"build": "npm run handleRes && node scripts/mergeJson && npm run upload && npm run buildTS",
"watch": "webpack --watch",
"dev": "webpack-dev-server --open --config webpack.dev.js --host 0.0.0.0",
"buildTS": "webpack --config webpack.prod.js && node scripts/mergeJs",
"copyJs": "node scripts/copyJs",
"buildWeb": "npm run handleRes && node scripts/mergeJson && node scripts/upload 1",
"buildWebTS": "webpack --config webpack.prod.js && node scripts/uploadSingleJs 1"
},
"author": "MrKwon",
"license": "ISC"
}
{
"type": "activity",
"name": "template"
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<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">
<title>活动标题</title>
<script src="//yun.duiba.com.cn/spark/v2/spark.base.fz.wxpollyfill.js"></script>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="//yun.duiba.com.cn/h5/lib/zepto.min.js"></script>
<script>
function getApp() {
return {
cloud: {},
cloudName: "clientTemplate2C",
requestType: "mock"
}
}
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>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"groups": [
{
"keys": "comCloseBtn.png,toastBg.png,waitingBg.png,waitingRot.png,关闭按钮.png,知道啦.png",
"name": "common"
},
{
"keys": "进度条.png,进度条底.png",
"name": "loading"
},
{
"keys": "playBg.jpg",
"name": "playScene"
},
{
"keys": "ruleBg.png,我知道了.png",
"name": "RulePanel"
},
{
"keys": "startSceneBg.jpg,奖品按钮.png,底部按钮区背景.png,开始游戏.png,排行榜按钮.png,规则按钮.png,赚次数按钮.png,运动锦鲤按钮.png",
"name": "StartScene"
}
],
"path": "./resource/"
}
\ No newline at end of file
{
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "RulePanel",
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "ruleBg",
"x": 28,
"y": 248,
"type": "sprite",
"props": {
"source": "ruleBg.png"
}
},
{
"name": "规则内容",
"x": 74,
"y": 369,
"type": "text",
"props": {
"text": "游戏规则\n",
"size": 30,
"fillColor": "#000000",
"textAlpha": 1
},
"id": "ruleTxt"
},
{
"name": "我知道了",
"x": 164,
"y": 1197,
"type": "button",
"props": {
"tUp": "我知道了.png"
},
"id": "knowBtn"
},
{
"name": "关闭按钮",
"x": 625,
"y": 272,
"type": "button",
"props": {
"tUp": "关闭按钮.png"
},
"id": "closeBtn"
}
]
},
{
"name": "StartScene",
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "startSceneBg",
"x": 0,
"y": 0,
"type": "sprite",
"props": {
"source": "startSceneBg.jpg"
}
},
{
"name": "底部按钮区",
"x": 0,
"y": 1242,
"type": "container",
"children": [
{
"name": "底部按钮区背景",
"x": 0,
"y": 0,
"type": "sprite",
"props": {
"source": "底部按钮区背景.png"
}
},
{
"name": "icon",
"x": 56,
"y": 35,
"type": "container",
"children": [
{
"name": "赚次数按钮",
"x": 547,
"y": 0,
"type": "button",
"props": {
"tUp": "赚次数按钮.png"
},
"id": "taskBtn"
},
{
"name": "运动锦鲤按钮",
"x": 258,
"y": 0,
"type": "button",
"props": {
"tUp": "运动锦鲤按钮.png"
},
"id": "lotBtn"
},
{
"name": "排行榜按钮",
"x": 0,
"y": 0,
"type": "button",
"props": {
"tUp": "排行榜按钮.png"
},
"id": "rankBtn"
}
]
}
]
},
{
"name": "timesTxt",
"x": 286,
"y": 1205,
"type": "text",
"props": {
"text": "剩余次数:3次",
"size": 16.00722,
"fillColor": "#ffffff",
"textAlpha": 1
},
"id": "timesTxt"
},
{
"name": "开始游戏",
"x": 171,
"y": 1052,
"type": "button",
"props": {
"tUp": "开始游戏.png"
},
"id": "startBtn"
},
{
"name": "规则按钮",
"x": 621,
"y": 212,
"type": "button",
"props": {
"tUp": "规则按钮.png"
},
"id": "ruleBtn"
},
{
"name": "奖品按钮",
"x": 11,
"y": 212,
"type": "button",
"props": {
"tUp": "奖品按钮.png"
},
"id": "recordBtn"
}
]
}
]
}
\ No newline at end of file
var fs = require("fs");
var path = require('path');
var del = require('del');
var pathName = "./resource";
var inPath = "./resource/common/";
{
key: ["aa", "bb"]
}
var hash = {};//记录名字和所在文件夹
var files = fs.readdirSync(pathName);
files.forEach(function (file) {
//文件common,不处理
if (file == "common") return
//路径
let fPath = path.join(pathName, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
var sonFiles = fs.readdirSync(fPath);
//没有文件
if (!sonFiles.length) return;
sonFiles.forEach(function (s) {
if (!hash[s]) hash[s] = [];
hash[s + ""].push(file);
})
}
})
//遍历
for (var key in hash) {
//有重复的,拷贝到common,删除原文件夹里的文件,
if (hash[key].length > 1) {
// 拷贝到common
fs.writeFileSync(inPath + key, fs.readFileSync(pathName + "/" + hash[key][0] + "/" + key));
console.log("重复资源:" + key)
//删除原文件夹里的文件,
hash[key].forEach(function (s) {
del(pathName + "/" + s + "/" + key)
})
}
}
console.log("重复资源处理完成")
\ No newline at end of file
var fs = require("fs");
// fs.writeFileSync(
// "./released/output.js",
// fs.readFileSync("./output.js")
// )
// var endPath = 'D:/duibaGame/测试项目0527/taobaominiTest/client/pages/index1/';
var endPath = 'D:/duibaGame/淘宝项目/taobao_mini/babycare_xiaoxiaole/babycare_c_client/client/pages/index/';
var version = Math.round(new Date().getTime() / 1000);
// fs.writeFileSync(endPath + "output." + version + ".js", fs.readFileSync("./released/output.js"));
fs.writeFileSync(endPath + "output.js", fs.readFileSync("./released/output.js"));
// console.log("js覆盖完成")
console.log(`版本号:
${version}`)
// cp infile outfile 拷贝文件直接放指令里
\ No newline at end of file
var fs = require('fs');
var path = require("path");
function writeFile(p, text) {
fs.writeFile(p, text, function (err) {
// if (!err)
// console.log("写入成功!")
})
}
//递归创建目录 同步方法
function mkdirsSync(dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
// console.log("mkdirsSync = " + dirname);
fs.mkdirSync(dirname);
return true;
}
}
}
function _copy(src, dist) {
var paths = fs.readdirSync(src)
paths.forEach(function (p) {
var _src = src + '/' + p;
var _dist = dist + '/' + p;
var stat = fs.statSync(_src)
if (stat.isFile()) {// 判断是文件还是目录
fs.writeFileSync(_dist, fs.readFileSync(_src));
} else if (stat.isDirectory()) {
copyDir(_src, _dist)// 当是目录是,递归复制
}
})
}
/*
* 复制目录、子目录,及其中的文件
* @param src {String} 要复制的目录
* @param dist {String} 复制到目标目录
*/
function copyDir(src, dist) {
var b = fs.existsSync(dist)
// console.log("dist = " + dist)
if (!b) {
// console.log("mk dist = ",dist)
mkdirsSync(dist);//创建目录
}
// console.log("_copy start")
_copy(src, dist);
}
function createDocs(src, dist, callback) {
// console.log("createDocs...")
copyDir(src, dist);
// console.log("copyDir finish exec callback")
if (callback) {
callback();
}
}
createDocs("./resource", "./released/resource/", function () {
console.log("资源拷贝成功")
})
\ No newline at end of file
var exec = require('child_process').exec;
var fs = require("fs");
//用这个生成所有的,最好把createModule里的warn去掉,否则子进程的打不到
const skinDataAll = JSON.parse(fs.readFileSync("./resource/skin.json"));
skinDataAll.children.forEach(c => {
const cmd = "node ./scripts/createModule.js " + c.name;
exec(cmd, { encoding: 'utf8' }, (e) => {
console.log("生成模块:" + c.name)
})
});
var fs = require("fs");
function createHtml(url) {
var js = `//yun.duiba.com.cn/db_games/${url}/output.js`;
var template = fs.readFileSync("./index.html").toString();
//写入released
fs.writeFileSync("./released/index.html", template.replace("output.js", js))
}
module.exports = createHtml
\ No newline at end of file
var fs = require("fs");
function createHtml(url) {
var template =
`<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="full-screen" content="true" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-fullscreen" content="true" />
<meta name="360-fullscreen" content="true" />
<!-- <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> -->
<!-- 小程序分享得用这个 -->
<!-- <script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script> -->
<!-- 易盾js -->
<!-- <script type="text/javascript" src="//cstaticdun.126.net/load.min.js"></script> -->
<!-- 渲染引擎 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge158.min.js" crossorigin="anonymous"></script>
<!-- svga解析js(按需) -->
<!-- <script src="//yun.duiba.com.cn/db_games/libs0924/svgaParser.minWeb.js" crossorigin="anonymous"></script> -->
<!-- 音效引擎(按需) -->
<!-- <script src="//yun.duiba.com.cn/db_games/libs0924/howler.min.js"></script> -->
<!-- vConsole -->
<script src="//yun.duiba.com.cn/db_games/libs0924/vConsole.min.js"></script>
<!-- 淘宝小程序webview sdk -->
<!-- <script type="text/javascript" src="https://appx/web-view.min.js"></script> -->
<style>
html,
body {
padding: 0;
margin: 0;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
background-color: #015581;
}
</style>
</head>
<body>
<div id="__loading__" style="position:absolute;left:50%;top:50%;margin-left:-45px;color:#ffffff">拼命加载中...</div>
<div id="cusEngine" style="line-height:0;font-size:0;position:absolute;">
<canvas id="canvas" style="width: 100%;height: 100%"></canvas>
</div>
</body>
<script>
window.addEventListener("load", function () {
//获取canvas
var canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth * (window.devicePixelRatio || 1)
canvas.height = document.body.clientHeight * (window.devicePixelRatio || 1)
var main = new Main(canvas);
var mouseEvent = main.stage.onMouseEvent.bind(main.stage);
canvas.addEventListener("touchstart", mouseEvent, false);
canvas.addEventListener('touchmove', mouseEvent, false);
canvas.addEventListener('touchend', mouseEvent, false);
window.stage = main.stage
})
</script>
<script src="//yun.duiba.com.cn/db_games/${url}/output.js" crossorigin="anonymous"></script>
</html>`;
//写入released
fs.writeFileSync("./released/index.html", template)
}
module.exports = createHtml
\ No newline at end of file
var fs = require("fs");
var warn = require("./warn")
//类型对应
const DISRES = {
'container': "Container",
'text': "TextField",
'button': "Button",
'sprite': "Sprite",
'rect': "Graphics",
// 'skin'
}
const skinDataAll = JSON.parse(fs.readFileSync("./resource/skin.json"))
//取指令后的参数
let arg = process.argv.splice(2);
//类名
var className = arg[0];
//皮肤名字
var skinName = arg[0]; //arg[1];
//是否弹框,存在参数就是场景
var moduleType = className.indexOf("Scene") > -1 ? "Scene" : "Panel";
// console.log('类名:',className)
// console.log('皮肤名字:',skinName)
var skinData = getSkinDataByName(skinName, skinDataAll);
if (!skinData) {
console.log(skinName + "皮肤不存在");
return
}
var groupName = skinData.name;
var endPath = moduleType == "Panel" ? "./src/panels/" : "./src/scenes/";
// var template =
// (moduleType == "Panel" ?
// 'import { Panel } from "../../module/views/Panel";\n' :
// 'import { Scene } from "../../module/views/Scene";\n') +
// 'export class ' + className + ' extends ' + moduleType + ' {\n' +
// '\tget groupNames() { return ["' + groupName + '"] }\n' +
// '\tget skinName() { return "' + skinName + '" }\n' +
// '\t' + getIds(skinData) + "\n" +
// '\tinitUi() {\n' +
// ' \n' +
// '\t}\n' +
// '\tstart(data) {\n' +
// '\t\tsuper.start();\n' +
// '\t}\n' +
// '\tinitEvents() {\n' +
// '\t\tsuper.initEvents();' +
// ' \n' +
// '\t}\n' +
// '\tremoveEvents() {\n' +
// '\t\tsuper.removeEvents();' +
// ' \n' +
// '\t}\n' +
// '}\n'
var template =
(moduleType == "Panel" ?
'import { Panel } from "../../module/views/Panel";\n' :
'import { Scene } from "../../module/views/Scene";\n') +
`export class ${className} extends ${moduleType} {
get groupNames() { return ["${groupName}"] };
get skinName() { return "${skinName}" };
${getIds(skinData)}
initUi() {
}
start(data) {
super.start();
}
initEvents() {
super.initEvents();
}
removeEvents() {
super.removeEvents();
}
}\n\n`
//取出skinName里的Item
var skins = getItemSkins(skinData)
if (skins.length) template = 'import { Item } from "../../module/views/Item";\n' + template;
for (var i = 0; i < skins.length; i++) {
var skin = skins[i];
// template +=
// 'class ' + upperCaseFirstChar(skin.name) + ' extends Item {\n' +
// '\tget skinName() { return "' + skin.name + '" }\n' +
// '\t' + getIds(skin) + "\n" +
// '\tinitUi(data?) {\n' +
// ' \n' +
// '\t}\n' +
// '\tupdateData(data?) {\n' +
// ' \n' +
// '\t}\n' +
// '\tinitData(id: number, data: any): void {\n' +
// '\t\tsuper.initData(id,data);\n' +
// ' \n' +
// '\t}\n' +
// '\tresetData() {\n' +
// ' \n' +
// '\t}\n' +
// '}\n'
template +=
`class ${upperCaseFirstChar(skin.name)} extends Item {
get skinName() { return "${skin.name}" }
${getIds(skin)}
initUi(data?) {
}
updateData(data?) {
}
initData(id: number, data: any): void {
if (id < 0 || !data) return;
super.initData(id,data);
}
resetData() {
}
}\n\n`;
}
//不存在时建一个
if (!fs.existsSync(endPath)) fs.mkdirSync(endPath);
//判断ts文件是否已存在
if (fs.existsSync(endPath + className + ".ts")) {
warn(
className + ".ts已存在,是否覆盖",
() => {
fs.writeFileSync(endPath + className + ".ts", template)
},
() => { }
)
} else {
fs.writeFileSync(endPath + className + ".ts", template)
}
// function cutIds(ids) {
// var str = ''
// var arr = ids.split(";")
// // console.log(arr)
// arr.forEach(element => {
// if (element) str += element + ";\n\t"
// });
// return str
// }
/**
* 获取皮肤数据
* @param {*} skinName
* @param {*} skinNode
*/
function getSkinDataByName(skinName, skinNode) {
if (!skinNode || !skinNode.children || !skinNode.children.length) return null;
for (var i = 0; i < skinNode.children.length; i++) {
var child = skinNode.children[i];
//皮肤数据得是容器
if (child.name == skinName && (child.type == "container" || child.type == "item")) return child;
var gson = getSkinDataByName(skinName, child);
if (gson) return gson
}
return null;
}
//取出所有的Item的皮肤,标记为item的
function getItemSkins(skinNode) {
var arr = []
for (var i = 0; i < skinNode.children.length; i++) {
var c = skinNode.children[i];
if (c.type == 'item') arr.push(c);
if (c.children) getItemSkins(c).forEach((cc) => {
arr.push(cc);
})
}
return arr
}
function getIds(skinNode, str) {
str = str || ''
for (var i = 0; i < skinNode.children.length; i++) {
var c = skinNode.children[i];
if (c.id) str += c.id + ": FYGE." + DISRES[c.type] + ";\n\t";
//作为item的不进
if (c.type == "container" && c.type != "item") str = getIds(c, str);
}
return str
}
function upperCaseFirstChar(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
var fs = require("fs");
var iconv = require('iconv-lite');
var del = require('del');
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data); //eval(data)
//取出里面的图片,暂存到tm文件夹中,同时删除文件夹里的,和本身json里的
if (!fs.existsSync("./released/tm"))
fs.mkdirSync("./released/tm");
for (var i = 0; i < data.groups.length; i++) {
var name = data.groups[i].name;
var path = readPath + name + "/";
var arr = data.groups[i].keys.split(",");
//取出图片的,注意已排除jpg
var images = arr.filter((f) => { return (f.substr(-4) == ".png" /*|| f.substr(-4) == ".jpg"*/) })
//没有图片,
if (!images.length) continue;
//去掉原先数据里的
// data.groups[i].keys = arr.filter((f) => { return (f.substr(-4) != ".png" && f.substr(-4) != ".jpg") }).join(",");
//添加新的json,加到atlas里
// if (data.groups[i].keys) data.groups[i].keys += ","
data.groups[i].atlas = name + ".json"
//读取原先路径里的图片,写到tm的文件夹里,并删除原文件夹里的图片
fs.mkdirSync("./released/tm/" + name);
for (var m = 0; m < images.length; m++) {
fs.writeFileSync(
"./released/tm/" + name + "/" + images[m],
fs.readFileSync(path + images[m])
)
del(path + images[m])
}
}
//序列化
fs.writeFileSync(readPath + "res.json", JSON.stringify(data, "", "\t"));
var fs = require("fs");
var del = require('del');
function delDir(path, isSelf) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file, index) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
if (!isSelf) fs.rmdirSync(path);
}
}
var paths = './released/';//设置删除路径
// delDir(paths, true);//删除文件夹
del(paths).then(() => {
fs.mkdirSync(paths);
}).catch(()=>{
fs.mkdirSync(paths);
})
// var tasks = [];
// function addTask(task) {
// tasks.push(task);
// }
// function next() {
// if (tasks.length > 0) {
// tasks.shift()();
// } else {
// return;
// }
// }
// var delRel = function () {
// del(paths).then(() => {
// // console.log("del")
// next();
// })
// }
// var createRel = function () {
// fs.mkdirSync(paths);
// // console.log("create")
// next();
// }
// addTask(delRel)
// addTask(createRel)
// next();
\ No newline at end of file
var del = require('del');
del("./released/tm")
\ No newline at end of file
//生成res.json
//遍历资源文件夹,生成
var fs = require('fs');
var path = require("path");
var readPath = "./resource/"
var files = fs.readdirSync(readPath);
var obj = { groups: [] };//每项包括keys合name
files.forEach(function (file) {
//路径
let fPath = path.join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//继续读每个子文件夹,json和png名字有相同的,只留json,
var sonFiles = fs.readdirSync(fPath);
//没有文件
if (!sonFiles.length) return
//取出所有json
var jsons = sonFiles.filter((f) => { return f.substr(-5) == ".json" })
//去掉json所带png的图片
sonFiles = sonFiles.filter((f) => { return jsons.indexOf(f.substring(0, f.length - 4) + ".json") == -1 })
//去掉mac上的缓存文件
sonFiles = sonFiles.filter((f) => { return f != '.DS_Store' })
var group = {
keys: "",
name: file
}
for (var i = 0; i < sonFiles.length; i++) {
if (i != 0) group.keys += ",";
group.keys += sonFiles[i]
}
obj.groups.push(group)
}
})
obj.path="./resource/"
console.log("资源更新完成")
//生成json
fs.writeFileSync(readPath + "res.json", JSON.stringify(obj, "", "\t"));
//TS也更新
var endPath = './src/';
var endFile = `export const ResJson = ${JSON.stringify(obj, "", "\t")}`
fs.writeFileSync(endPath + "ResJson.ts", endFile);
\ No newline at end of file
const imagemin = require('imagemin');
// const imageminJpegtran = require('imagemin-jpegtran');imagemin-mozjpeg
const imageminJpegtran = require('imagemin-mozjpeg');
const imageminPngquant = require('imagemin-pngquant');
var fs = require('fs');
var path = require('path');
// 要处理的图片文件夹路径
var altasPath = "./released/resource/"
var folders = getFolders(altasPath);
folders.map(async function (folder) {
const files = await imagemin([altasPath + folder + '/*.{png,jpg}'], {
destination: altasPath + folder,
plugins: [
imageminJpegtran(),
imageminPngquant({
quality: [0.6, 0.8]
})
]
});
if (files && files.length) {
files.forEach((v) => {
console.log("压缩图片成功:", v.sourcePath.substring(v.sourcePath.lastIndexOf("/") + 1, v.sourcePath.length))
})
}
});
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function (file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
\ No newline at end of file
var fs = require("fs");
// fs.writeFileSync(
// "./released/output.js",
// fs.readFileSync("./output.js")
// )
var endPath = './released/';
fs.writeFileSync(endPath + "output.js",
// 'import * as FYGE from "fyge-tbmini";\n' +
'import * as FYGE from "fyge";\n' +//以后改成这个
// 'import * as SvgaParser from "svga-parser";\n' +
fs.readFileSync("./output.js"));
console.log("js生成")
var fs = require("fs");
var path = require('path');
var del = require('del');
var iconv = require('iconv-lite');
const join = require('path').join;
//写入图集的文件夹,将文件夹内所有的json合并,并删除原先json
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data);
var files = fs.readdirSync(readPath);
// let obj = {};
let count = 0;
let countAll = files.length
files.forEach(function (file) {
//路径
let fPath = join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//读文件夹fPath里的json文件
fs.readdir(fPath, function (err, files) {
if (err) {
console.warn(err)
} else {
var hasJson
//遍历
for (var i = 0; i < files.length; i++) {
let filename = files[i];
if (filename.indexOf(".json") == -1) continue
hasJson = true;
//获取当前文件的绝对路径
let filedir = path.join(fPath, filename);
let content = fs.readFileSync(filedir, 'utf-8');
let group = getGroupByName(filename.replace(".json", ""), data.groups)
group.atlas = JSON.parse(content);
//删除原先json
del(filedir)
if (++count == countAll) endFun();
}
if(!hasJson)if (++count == countAll) endFun();
//序列化,不格式化,节省内存
}
})
} else {
if (++count == countAll) endFun();
}
})
function endFun() {
console.log("资源配置js生成完毕")
// del(join(readPath, "res.json"))
fs.writeFileSync(readPath + "res.json", JSON.stringify(data, "", "\t"));
}
function getGroupByName(name, groups) {
var group;
for (var i = 0; i < groups.length; i++) {
if (groups[i].name === name) {
group = groups[i];
break;
}
}
return group
}
var fs = require("fs");
var exec = require('child_process').exec;
var iconv = require('iconv-lite');
var del = require('del');
const join = require('path').join;
// var packTextures = require("pack_textures")
//写入图集的文件夹
var outPath = "./released/resource/";
//读取散图的文件夹
var readPath = "./released/tm/";
var files = fs.readdirSync(readPath);
files.forEach(function (file) {
//路径
let fPath = join(readPath, file);
//只处理文件夹
if (fs.statSync(fPath).isDirectory()) {
//判断文件夹内是否有图片
if (!judgeHasImage(fPath)) return;
//如果文件夹不存在
if (!fs.existsSync(outPath + file)) {
fs.mkdirSync(outPath + file);
}
else {
//图集文件存在就删除
if (fs.existsSync(outPath + file + "/" + file + ".json")) {
del(outPath + file + "/" + file + ".json")
}
if (fs.existsSync(outPath + file + "/" + file + ".png")) {
del(outPath + file + "/" + file + ".png")
}
}
// packTextures(
// fPath,
// outPath + file + "/" + file,
// 4096,
// 4096,
// false,
// 2,
// 2,
// true,
// true
// )
//全局命令装过,就直接用命令行
exec(
'packTextures' + //基础指令
' -i ' + fPath + //要合图集的文件夹路径
' -o ' + outPath + file + "/" + file + //输出路径及名字
' --mw ' + 4096 + //最大宽度
' --mh ' + 4096 +//最大高度
' -p ' + false + //长宽是否2的指数,canvas下没必要,false
' --sp ' + 2 + //图片间隔
' --bp ' + 2 + //边界间隔
' -r ' + true + //是否允许图片旋转
' -t ' + true //是否允许裁切图片边缘透明像素
, { encoding: 'utf8' }, (e) => {
if (e) {
console.log(e)
return
}
console.log("生成图集:" + file)
}
)
}
})
/**
* 判断文件夹内是否有图片
* @param {*} path
*/
function judgeHasImage(path) {
var files = fs.readdirSync(path);
for (var i = 0; i < files.length; i++) {
var itm = files[i]
var stat = fs.statSync(path + "/" + itm);
if (stat.isDirectory()) {
//递归读取文件
if (judgeHasImage(path + "/" + itm + "/")) return true;
} else {
if (itm.substr(-4) == ".jpg" || itm.substr(-4) == ".png") return true;
}
}
return false;
}
\ No newline at end of file
var fs = require('fs');
var path = require('path');
const co = require('co');
const OSS = require('ali-oss');
const chalk = require('chalk');
const ProgressBar = require('progress');
class TuiaAutoUpload {
constructor(props, type) {
this.type = type;
const defaultOptions = {
dir: undefined,
originDir: undefined
}
this.options = Object.assign({}, defaultOptions, props);
if (!this.options.dir || !this.options.originDir) {
console.log(chalk.red('缺少参数,初始化失败'))
return;
}
this.init();
}
init() {
var _this = this;
this.client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: 'LTAI4Fw25WcfcGv7FvcHoiHK',
accessKeySecret: 'NZk1NtT9J5HFaAolNbtQdzTzLLvLYm',
bucket: _this.type === 'prod' ? 'duiba' : 'daily-duiba'
});
this.bar = new ProgressBar(chalk.yellow(` 文件上传中 [:bar] :current/${this.files().length} :percent :elapseds`), {
complete: '●',
incomplete: '○',
width: 20,
total: this.files().length,
callback: () => {
console.log(chalk.green('\n All complete.'));
console.log(chalk.blue(`\n 本次队列文件共${this.files().length}个,已存在文件${this.existFiles}个,上传文件${this.uploadFiles}个,上传失败文件${this.errorFiles}个\n`));
}
})
return this;
}
files() {
var _this = this;
if (this._files) return this._files;
this._files = [];
/**
* 文件遍历方法
* @param filePath 需要遍历的文件路径
*/
function fileDisplay(filePath) {
//根据文件路径读取文件,返回文件列表
var files = fs.readdirSync(filePath);
files.forEach(function (filename) {
//获取当前文件的绝对路径
var filedir = path.join(filePath, filename);
//根据文件路径获取文件信息,返回一个fs.Stats对象
var stats = fs.statSync(filedir);
var isFile = stats.isFile();//是文件
var isDir = stats.isDirectory();//是文件夹
if (isFile) {
var sep = '/';
if ('win32' == process.platform)
sep = '\\';
var newDirArr = filedir.split(sep);
newDirArr.shift();
_this._files.push(newDirArr.join('/'));
}
if (isDir) {
fileDisplay(filedir);//递归,如果是文件夹,就继续遍历该文件夹下面的文件
}
});
}
//调用文件遍历方法
fileDisplay(this.options.dir);
return this._files;
}
start() {
this.files().map((file, index) => {
let _this = this;
const path1 = path.join(path.resolve(__dirname, '..'), 'released', file);
let originFile;
this.existFiles = 0;
this.uploadFiles = 0;
this.errorFiles = 0;
co(function* () {
const originPath = `${_this.options.originDir}${file}`;
try {
originFile = yield _this.client.head(originPath);
} catch (error) {
originFile = error;
}
if (_this.type === 'prod') {
if (originFile.status === 404) {
yield _this.client.put(originPath, path1);
_this.uploadFiles += 1;
} else {
_this.existFiles += 1;
}
} else if (_this.type === 'dev') {
if (originFile.status === 404 || originFile.status === 200) {
_this.existFiles += 1;
}
yield _this.client.put(originPath, path1, {
headers: {
'Cache-Control': 'no-cache'
}
})
_this.uploadFiles += 1;
}
_this.bar.tick();
}).catch(function (err) {
_this.errorFiles += 1;
console.log(err);
});
});
}
}
const configFileName = 'project.json';
if (!fs.existsSync(configFileName)) {
throw new Error(`${configFileName}不存在.`)
}
let config = fs.readFileSync('project.json');
config = JSON.parse(config + '');
if (!config.type) {
throw new Error(`${configFileName}的type不存在.`)
}
if (!config.name) {
throw new Error(`${configFileName}的name不存在.`)
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
console.log(`版本号:
${version}`)
const autoupload = new TuiaAutoUpload({
dir: './released/',
// dir: path.join(__dirname, './released/'),
originDir: `/db_games/${config.type}/${config.name}/${version}/`
}, "prod")
autoupload.start()
var iconv = require('iconv-lite');
var readPath = "./released/resource/";
//读取json文件
var data = iconv.decode(fs.readFileSync(readPath + "res.json"), "utf-8");//GBK
//反序列化
data = JSON.parse(data);
data.path = `https://yun.duiba.com.cn/db_games/${config.type}/${config.name}/${version}/resource/`
//写入目标文件夹,可配置,每个项目必须修改,或者直接和project的保持一致(淘宝项目文件固定后)
var endPath = './src/';
var endFile = `export const ResJson = ${JSON.stringify(data, "", "\t")}`
fs.writeFileSync(endPath + "ResJson.ts", endFile);
//根据参数吧,有就是web。需要生成皮肤和js,没有就不执行后续
let arg = process.argv.splice(2);
if (!arg[0]) return;
//有版本号了,模板也生成吧
require("./createHtml")(`${config.type}/${config.name}/${version}`);
var uploadSingleJs = require("./uploadSingleJs")
var exec = require('child_process').exec;
//打包js
exec("webpack --config webpack.prod.js", { encoding: 'utf8' }, (e) => {
if (e) {
console.log(e)
return
}
uploadSingleJs(`${config.type}/${config.name}/${version}`)
//再打印一次
console.log(`版本号:
${version}`)
})
\ No newline at end of file
const co = require('co');
const OSS = require('ali-oss');
var fs = require('fs');
let arg = process.argv.splice(2);
//只打包js时,自执行上传
if(arg[0])uploadSingleJs();
function uploadSingleJs(url) {
if (!url) {//不传的时候
const configFileName = 'project.json';
if (!fs.existsSync(configFileName)) {
throw new Error(`${configFileName}不存在.`)
}
let config = fs.readFileSync('project.json');
config = JSON.parse(config + '');
if (!config.type) {
throw new Error(`${configFileName}的type不存在.`)
}
if (!config.name) {
throw new Error(`${configFileName}的name不存在.`)
}
const now = new Date();
const version = Math.round(now.getTime() / 1000);
console.log(`版本号:
${version}`)
url = `${config.type}/${config.name}/${version}`;
require("./createHtml")(`${config.type}/${config.name}/${version}`);
}
//单js文件上传
co(function* () {
const originPath = `/db_games/${url}/output.js`;
var client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: 'LTAI4Fw25WcfcGv7FvcHoiHK',
accessKeySecret: 'NZk1NtT9J5HFaAolNbtQdzTzLLvLYm',
bucket: 'duiba'
})
var originFile;
try {
originFile = yield client.head(originPath);
} catch (error) {
originFile = error;
}
if (originFile.status === 404)
yield client.put(originPath, "./output.js");
})
}
module.exports = uploadSingleJs
\ No newline at end of file
var readline = require('readline');//node上有,不为了锁版本,可以不用安装
// warn("aaasd",()=>{console.log(213)},()=>{console.log(65)})
/**
* 提醒脚本
* @param {string} msg 提示信息
* @param {Function} resolve yes回调
* @param {Function} reject no回调
*/
function warn(msg, resolve, reject) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(msg + "[y/n]", function (answer) {
switch (answer) {
case 'y':
case 'Y':
case 'yes':
case 'YES':
resolve && resolve();
// 不加close,则不会结束
rl.close();
break;
case 'n':
case 'N':
case 'no':
case 'NO':
default:
reject && reject();
rl.close();
break;
}
});
}
module.exports = warn
\ No newline at end of file
module.exports = {
OUTPUT_DIR: "dist",
SOURCE_DIR: "src",
TEMP_DIR: "./.temp",
ENTRY: "src/app.jsx",
TEMPLATE: "./public/index.html",
API_MOCK: true,
PX2REM: true,
IMAGE_Q1: 0.6, //图片压缩质量
IMAGE_Q2: 0.8,
RES_PATH:'/src/assets/', //资源配置路径,打包发布后会自动替换成cdn链接
RES_PATH_PROD:'/src/assets/'
};
import { ajax, jsonp } from "../module/ajax"
import { showToast } from "../module/ctrls"
import { duiba_md5 } from "../module/tools/security"
//////////补给站用到的接口集成
//部分情况需要,比如duiba_md5,需跳转下载的
// <script crossorigin="anonymous" src="//yun.duiba.com.cn/db_games/libs/zepto_security_downloadApp.min.js"></script>
/**
* 获取基本信息
*/
export function ajaxElement(): Promise<{ success: boolean, data?: any }> {
return new Promise((r) => {
ajax({
url: "/hdtool/recon/ajaxElement", //请求地址
type: "GET",//"POST", //请求方式
data: {
duibaId: window['CFG'].hdToolId,
activityId: window['CFG'].actId,
}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
// headers: headers,
success: function (res) {
if (!res.success) showToast(res.desc || "网络异常,请稍后再试")
r(res)
},
error: function (status) {
showToast("网络异常,请稍后再试")
r({ success: false })
},
})
})
}
/**
* 参与游戏
*/
export function doJoin(): Promise<{ success: boolean, data?: any }> {
return new Promise(async (r) => {
//获取token
var token = await getTokenHdtool();
if (!token) {//如果没有token
showToast("token获取失败")
r({ success: false })
return
}
ajax({
url: "/hdtool/recon/doJoin",
type: "GET",//"POST", //请求方式
data: {
token,
activityId: window['CFG'].actId,
activityType: "hdtool",
consumerId: window['CFG'].consumerId
}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
// headers: headers,
success: function (res) {
if (!res.success) showToast(res.desc || "网络异常,请稍后再试")
r(res)
},
error: function (status) {
showToast("网络异常,请稍后再试")
r({ success: false })
},
})
})
}
/**
* 开始游戏轮询
* @param orderId doJoin返回的数据中的data字段
*/
export function getNgameStartStatus(orderId): Promise<any> {
let count = 0;
return new Promise((resolve) => {
(async function ask(r) {
const data = await getN(orderId);
if (data.code == "0000000000") {
r(data);
} else {
//超过10次的话,提示下
if (++count >= 10) {
showToast("获取开始游戏信息失败\n请稍后重试")
r({ success: false })
return
}
setTimeout(() => { ask(r) }, 500)
}
})(resolve)
})
}
function getN(orderId): Promise<{ success: boolean, data?: any, code?: string }> {
return new Promise((r) => {
ajax({
url: "/hdtool/recon/ngame/getNgameStartStatus",
type: "GET",//"POST", //请求方式
data: {
orderId,
}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
// headers: headers,
success: function (res) {
r(res)
},
error: function (status) {
r({ success: false })
},
})
})
}
/**
*
* @param orderId doJoin里的数据data字段
* @param score 分数可能传1
* @param submitToken 轮询数据里的data.submitToken
*/
export function submit(orderId: string, score: number, submitToken: string): Promise<{ success: boolean, data?: any }> {
let gameData = "[]";
// let sgin = window['duiba_md5'](orderId + '' + score + '' + gameData + '' + submitToken);
let sgin = duiba_md5(orderId + '' + score + '' + gameData + '' + submitToken);
let dynamicData = JSON.stringify(`{t2:${new Date().getTime()}}`);
const param: any = {
orderId,
score,
gameData,
sgin,
dynamicData
};
return new Promise((r) => {
ajax({
url: "/hdtool/recon/ngame/ngameSubmit",
type: "POST", //请求方式
data: param, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
// headers: headers,
success: function (res) {
if (!res.success) showToast(res.desc || "网络异常,请稍后再试")
r(res)
},
error: function (status) {
showToast("网络异常,正在重试中")
r({ success: false })
},
})
})
}
/**
* 获取奖品信息,这里面的data.element用于更新ajaxElement,要轮询
* @param orderId doJoin里的数据data字段
*/
export function getOrderStatus(orderId): Promise<{ success: boolean, data?: any }> {
let count = 0;
return new Promise((resolve) => {
(async function ask(r) {
const data = await getO(orderId);
if (data.code == "0000000000") {
r(data);
} else {
//超过10次的话,提示下
if (++count >= 10) {
showToast("获取开始游戏信息失败\n请稍后重试")
r({ success: false })
return
}
setTimeout(() => { ask(r) }, 500)
}
})(resolve)
})
}
function getO(orderId): Promise<{ success: boolean, data?: any, code?: string }> {
return new Promise((r) => {
ajax({
url: "/hdtool/recon/getOrderStatus", //请求地址
type: "GET",//"POST", //请求方式
data: {
orderId
}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
// headers: headers,
success: function (res) {
r(res)
},
error: function (status) {
r({ success: false })
},
})
})
}
/**
* 补给站获取token
*/
function getTokenHdtool(): Promise<string> {
return new Promise((r) => {
if (window.location.port == "8080") {//本地开发
r("token")
} else {
if (!window['getDuibaToken']) {
r(null);
} else {
window['getDuibaToken']((tokenObj) => {
r(tokenObj.token);
}, (key, messageObj) => {
r(null);
});
}
}
})
}
/**
* 获取我的奖品链接,老活动工具 window.location.href = getRecordUrl('00');
* @param type
* @param ids
*/
export function getRecordUrl(type: '00', ids?) {
let recordUrl;
let oaId;
oaId = window["CFG"].oaId;
recordUrl = window["CFG"].recordUrl;
if (!ids) {
ids = [oaId];
}
let i = 0;
const len = ids.length;
for (i; i < len; i++) {
if (window.location.href.indexOf("?") == -1) {
recordUrl += '?origins=' + ids[i] + type;
} else {
recordUrl += '&origins=' + ids[i] + type;
}
}
return recordUrl;
}
/**
* 补给站埋点
* @param type
* @param area
*/
export function sendLogBuji(type: 'exposure' | 'click', area: number) {
var appId = window["CFG"].appId;
var oaId = window["CFG"].oaId;
var dpm = appId + '.' + 263 + '.' + area + '.' + 1;//怎么拼按具体需求
var dcm = 202 + '.' + oaId + '.0.0';//怎么拼按具体需求
let params: any = {
dpm,
dcm,
appId,
consumerId: window["CFG"].consumerId,
domain: '//embedlog.duiba.com.cn'
};
let isExposure = (type == "exposure");
if (isExposure) {
jsonp('//embedlog.duiba.com.cn/exposure/standard', params);
} else {
jsonp('/log/click', params);
}
}
//补给站老活动会用到
window["CFG"] = {
actId: '143212468677481',
oaId: '143212468677481',
unitName: '猫币',
btnUnitName: '猫币',
doJoin: '/hdtool/doJoin?dpm=1.3.1.0&activityId=143212468677481',
quireOrder: '/hdtool/getOrderStatus',
styleConfig: '/hdtool/getHdtoolConfig',
getElement: '/hdtool/ajaxElement',
getPrizeDetail: '/hdtool/prizeDetail',
ajaxThroughInfo: '/hdtool/ajaxThroughInfo',
throughSubmit: '/hdtool/throughSubmit',
gameGetOrder: '/hdtool/getOrderInfo',//游戏获取订单信息接口
gameSubmit: '/hdtool/gameSubmit',//游戏结果提交接口
doSubmit: '/hdtool/submit',
adslotId: '',
consumerId: '1',
isNotLoginUser: false,
uid: '1',
hdType: 'duiba',
hdToolId: '43743',
appType: 'credits',
subType: 'lotteryMachine',
directSendCoupon: 'false',
ajaxAction: '',
recommendQueue: '/recommend/getRecommend',
recommendSkin: '/recommend/getRecommendSkin',
isShowDetail: true,
preview: false,
from: '',
login: '//activity.m.duiba.com.cn/hdtool/login?dpm=1.3.3.0',
flowRedirectUrl: '',
flowRedirectTuiaUrl: '',
isOpenRecommend: false,
getCreditsLink: 'mxsa://magicshop/cointask?uid=1&dbnewopen',
appId: '1',
recordUrl: '//activity.m.duiba.com.cn/crecord/record?dbnewopen&dpm=1.3.2.0',
shareDesc: '分享分享文案文案',
entranceDesc: '测试领奖,也可到我的奖品领奖哦!!!',
isSHowMeat: true,
needCouponModal: true, // 给前端用,判断是否需要使用配置的优惠券弹窗
needRecommendModal: true, // 给前端用,判断是否需要公用推荐位弹窗
asyncFiles: [], // 给前端用,异步加载的文件
shareAndroidLinkActivity: 'http://www.baidu.com',
shareIosLinkActivity: 'http://www.iqiyi.com'
};
import { layers, destroyLayers } from "../module/views/layers";
import { RES } from "../module/RES";
import { changeScene, showWaiting, destroyAllCtrls, showPanel, hideWaiting } from "../module/ctrls";
import { ResJson } from "./ResJson";
import { SkinJson } from "./SkinJson";
import { LoadingScene } from "./template/LoadingScene";
import { destroyWebNetData } from "./WebNet";
/**
* 全局事件,为了和小程序交互
* 有可能多处页面用到,所以单开
*/
export const GDispatcher = new FYGE.EventDispatcher();
export class Main {
//主舞台
stage: FYGE.Stage;
private requestID;
constructor(canvas: HTMLCanvasElement) {
//建舞台
var stage = new FYGE.Stage(
canvas,
750,//设计宽度,按设计搞给的就行
1624,//设计高度
document.body.clientWidth,
document.body.clientHeight,
FYGE.RENDERER_TYPE.CANVAS,
true //视窗居中裁切
);
this.stage = stage;
//stage初始化
stage.addEventListener(FYGE.Event.INIT_STAGE, this.onAddToStage, this);
//循环
var self = this;
loop();
function loop() {
FYGE.Tween.flush()
stage.flush();
self.requestID = window.requestAnimationFrame(loop);
}
}
private async onAddToStage() {
//初始化层级
layers.init(this.stage);
console.log("初始化层级完成")
//初始化资源配置
RES.loadConfig(ResJson);
console.log("初始化资源配置完成")
//皮肤配置加载
RES.loadSkinConfig(SkinJson);
console.log("初始化皮肤配置完成")
//加载通用资源
await RES.loadGroup("common");
console.log("通用资源加载完成")
//h5环境时,隐藏加载中
if (FYGE.getEnv() == "web" && document.getElementById("__loading__")) document.getElementById("__loading__").style.display = "none";
//显示场景
changeScene(LoadingScene)
}
/**
* 添加全局事件,用于小程序的交互调用
* 一直很犹豫要不要放在main的实例里,还是和Main同级导出,还有上面的pause,run,下面的事件等
* @param name
* @param fun
* @param thisObj
*/
addGlobalEvent(name: string, fun: Function, thisObj?: any, once: boolean = false) {
if (once) {
GDispatcher.once(name, fun, thisObj)
} else {
GDispatcher.addEventListener(name, fun, thisObj)
}
}
/**
* 派发全局事件,用于小程序的交互调用
* @param name 可以是事件名,也可以是事件
* @param data
*/
dispatchGlobalEvent(name: string | any, data?: any) {
GDispatcher.dispatchEvent(name, data)
}
/**
* 移除全局事件,用于小程序交互调用
* @param name
* @param fun
* @param thisObj
*/
removeGlobalEvent(name: string, fun: Function, thisObj?: any) {
GDispatcher.removeEventListener(name, fun, thisObj)
}
//在小程序页面卸载时调用onUnload,多次销毁后会有问题,再检查
destroy() {
//Tween都移除,注意吧,可能原先的也被移除,,对于多page时注意,会把其他页面的也去掉
FYGE.Tween.removeAllTweens()
//停掉计时器
window.cancelAnimationFrame(this.requestID);
//层级销毁
destroyLayers()
//销毁控制器
destroyAllCtrls();
//舞台销毁
this.stage.destroy();
//全局事件置空
GDispatcher.removeAllEventListener();
//网络数据记录清空
destroyWebNetData();
}
}
export const ResJson = {
"groups": [
{
"keys": "comCloseBtn.png,toastBg.png,waitingBg.png,waitingRot.png,关闭按钮.png,知道啦.png",
"name": "common"
},
{
"keys": "进度条.png,进度条底.png",
"name": "loading"
},
{
"keys": "playBg.jpg",
"name": "playScene"
},
{
"keys": "ruleBg.png,我知道了.png",
"name": "RulePanel"
},
{
"keys": "startSceneBg.jpg,奖品按钮.png,底部按钮区背景.png,开始游戏.png,排行榜按钮.png,规则按钮.png,赚次数按钮.png,运动锦鲤按钮.png",
"name": "StartScene"
}
],
"path": "./resource/"
}
\ No newline at end of file
export const SkinJson = {
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "RulePanel",
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "ruleBg",
"x": 28,
"y": 248,
"type": "sprite",
"props": {
"source": "ruleBg.png"
}
},
{
"name": "规则内容",
"x": 74,
"y": 369,
"type": "text",
"props": {
"text": "游戏规则\n",
"size": 30,
"fillColor": "#000000",
"textAlpha": 1
},
"id": "ruleTxt"
},
{
"name": "我知道了",
"x": 164,
"y": 1197,
"type": "button",
"props": {
"tUp": "我知道了.png"
},
"id": "knowBtn"
},
{
"name": "关闭按钮",
"x": 625,
"y": 272,
"type": "button",
"props": {
"tUp": "关闭按钮.png"
},
"id": "closeBtn"
}
]
},
{
"name": "StartScene",
"x": 0,
"y": 0,
"type": "container",
"children": [
{
"name": "startSceneBg",
"x": 0,
"y": 0,
"type": "sprite",
"props": {
"source": "startSceneBg.jpg"
}
},
{
"name": "底部按钮区",
"x": 0,
"y": 1242,
"type": "container",
"children": [
{
"name": "底部按钮区背景",
"x": 0,
"y": 0,
"type": "sprite",
"props": {
"source": "底部按钮区背景.png"
}
},
{
"name": "icon",
"x": 56,
"y": 35,
"type": "container",
"children": [
{
"name": "赚次数按钮",
"x": 547,
"y": 0,
"type": "button",
"props": {
"tUp": "赚次数按钮.png"
},
"id": "taskBtn"
},
{
"name": "运动锦鲤按钮",
"x": 258,
"y": 0,
"type": "button",
"props": {
"tUp": "运动锦鲤按钮.png"
},
"id": "lotBtn"
},
{
"name": "排行榜按钮",
"x": 0,
"y": 0,
"type": "button",
"props": {
"tUp": "排行榜按钮.png"
},
"id": "rankBtn"
}
]
}
]
},
{
"name": "timesTxt",
"x": 286,
"y": 1205,
"type": "text",
"props": {
"text": "剩余次数:3次",
"size": 28,
"fillColor": "#ffffff",
"textAlpha": 1
},
"id": "timesTxt"
},
{
"name": "开始游戏",
"x": 171,
"y": 1052,
"type": "button",
"props": {
"tUp": "开始游戏.png"
},
"id": "startBtn"
},
{
"name": "规则按钮",
"x": 621,
"y": 212,
"type": "button",
"props": {
"tUp": "规则按钮.png"
},
"id": "ruleBtn"
},
{
"name": "奖品按钮",
"x": 11,
"y": 212,
"type": "button",
"props": {
"tUp": "奖品按钮.png"
},
"id": "recordBtn"
}
]
}
]
}
\ No newline at end of file
import { RES } from "../module/RES";
import { layers } from "../module/views/layers";
import Tween = FYGE.Tween;
import Ease = FYGE.Ease;
/**
* 定制,记录一些全局量和通用方法
*/
export class Tools {
/**
* 缓存key
*/
public static cacheKey: string = "guideThreeSquirrels"
public static isMember: boolean;
/**
* 通过res里的名字生成一个sprite
* @param imageName
* @param x
* @param y
*/
public static getSprite(imageName: string, x: number = 0, y: number = 0): FYGE.Sprite {
var sprite = new FYGE.Sprite(RES.getRes(imageName));
sprite.x = x;
sprite.y = y
return sprite
}
/**
*
* @param txt 内容
* @param size 字号
* @param color 颜色 #打头
* @param textWidth 文本宽度
* @param align 文本对齐方式
* @param x
* @param y
*/
public static getText(
txt: string,
size: number,
color: string = "#000000",
align: FYGE.TEXT_ALIGN = FYGE.TEXT_ALIGN.LEFT,
textWidth: number = 0,
x: number = 0,
y: number = 0
): FYGE.TextField {
var text = new FYGE.TextField();
text.fillColor = color;
text.size = size;
text.textWidth = textWidth;
text.textAlign = align;
text.x = x;
text.y = y;
text.text = txt;
return text
}
/**
* 已左上角作为原点
* @param width
* @param height
* @param color
* @param alpha
* @param radius
* @param x
* @param y
*/
public static getRect(
width: number,
height: number,
color: number = 0xff0000,
alpha: number = 1,
radius: number = 0,
x: number = 0,
y: number = 0,
): FYGE.Graphics {
var g = new FYGE.Graphics();
g.beginFill(color);
g.alpha = alpha;
if (!radius) {
g.drawRect(0, 0, width, height)
} else {
g.drawRoundedRect(0, 0, width, height, radius)
}
g.endFill();
g.position.set(x, y);
return g
}
/**
* 中心原点
* @param radius
* @param color
* @param alpha
* @param x
* @param y
*/
public static getCircle(
radius: number = 10,
color: number = 0xff0000,
alpha: number = 1,
x: number = 0,
y: number = 0
): FYGE.Graphics {
var g = new FYGE.Graphics();
g.beginFill(color);
g.alpha = alpha;
g.drawCircle(0, 0, radius)
g.endFill();
g.position.set(x, y);
return g
}
/**
* 高度适配
* 遮挡上面的情况
* 顶部部ui要适配
* @param maxDis 最大距离
* @param minDis 最小距离
* @param type 页面适配类型
* @return y值
*/
public static getAdjustHeight(maxDis: number, minDis: number, type: "top" | "mid" | "bot" = "bot"): number {
//图层偏移量
var offsetY: number = (() => {
//顶部适配。layers会被置顶,返回0
if (type == "top") return 0;
//底部适配。layers会置底,返回两倍的
if (type == "bot") return layers.stageOffsetY * 2;
return layers.stageOffsetY;
})()
//小于1206时固定距离顶部高度
if (layers.stageHeight <= 1206) return minDis + offsetY;
//大于1206时取插值
return (layers.stageHeight - 1206) / (1624 - 1206) * (maxDis - minDis) + minDis + offsetY;
}
/**
* 修改皮肤上的文本对齐方式,原先默认是左的,多汗行的时候计算有误,待查
* @param text
* @param align
* @param textWidth
*/
public static changeTextAlign(text: FYGE.TextField, align: FYGE.TEXT_ALIGN, textWidth?: number) {
if (align == FYGE.TEXT_ALIGN.LEFT) return;
text.textAlign = align;
//没有就原先的
textWidth = textWidth || text.textWidth;
//修改位置
if (align == FYGE.TEXT_ALIGN.CENTER) text.x -= (textWidth - text.textWidth) / 2;
if (align == FYGE.TEXT_ALIGN.RIGHT) text.x -= textWidth - text.textWidth
text.textWidth = textWidth;
}
public static customToast(
target: FYGE.DisplayObject,
call: Function = () => 0,
time: number = 2000,
showTime: number = 300
) {
Tween.get(target)
.set({ alpha: 0, visible: true })
.to({ alpha: 1 }, showTime, Ease.quadIn)
.wait(time)
.to({ alpha: 0 }, showTime, Ease.quadOut)
.set({ alpha: 0, visible: false })
.call(() => {
call();
});
}
/**
* 延时防连点
* @param target
* @param {number} delay 默认2000毫秒
*/
public static btnDelay(target: FYGE.Container, delay: number = 2000) {
target.mouseEnable = false;
target.mouseChildren = false;
setTimeout(() => {
target.mouseEnable = true;
target.mouseChildren = true;
}, delay);
}
/**
* 根据名字获取0到9的贴图
* 位图字每次都写太烦了
* @param name
*/
public static getNumTextures(name: string): { [key: number]: FYGE.Texture } {
var arr = {}
for (var i = 0; i <= 9; i++) arr[i] = RES.getRes(name + i + ".png")
return arr
}
/**
* 获得距离底部的百分比高度,还要减个自身的高度,自行处理
* @param {number} percent 百分比
* @returns {number}
*/
static getAdjustBottomHeight(percent: number): number {
return layers.stageHeight - layers.stageHeight * percent + layers.stageOffsetY;//stageOffsetY加不加取决于页面适配类型
}
/**
* 获得距离顶部的百分比高度
* @param {number} percent 百分比
* @returns {number}
*/
static getAdjustTopHeight(percent: number): number {
return layers.stageHeight * percent + layers.stageOffsetY;//stageOffsetY加不加取决于页面适配类型
}
}
import { showToast } from "../module/ctrls";
import { ajax, jsonp } from "../module/ajax";
import { GDispatcher } from "./Main";
import { getUrlParams } from "../module/tools/WebTool";
import { isFromShare, newUser } from 'duiba-utils';
let mergeData = {
user_type: newUser ? '0' : '1',
is_from_share: isFromShare ? '0' : '1',
}
//////////////星速台接口方法集成
/**
* web接口枚举,mock 文件名类似aaa/homeInfo.do
*/
export enum WebNetName {
/**
* 首页
*/
index = "/projectx/{projectId}/game/index.do",
/**
* 参与
*/
join = "/projectx/{projectId}/game/join.do",
/**
* 获取结果
*/
queryResult = "/projectx/{projectId}/game/queryResult.do",
/**
* 获取规则
*/
projectRule = "/projectx/{projectId}/projectRule.query"
}
//返回数据类型
interface dataOut {
success: boolean,
data?: any
code?: string,
message?: string
}
//记录数据
let dataRecord: {
[name: string]: any
} = {};
/**
* 发送接口
* @param netName
* @param parameter
* @param callback
* @param hideMsg
*/
export function sendWebNet(
netName: WebNetName,
parameter?: any,
callback?: (success: boolean, res?: dataOut) => void,
hideMsg: boolean = false,
isGet: boolean = true,//这两个参数基本不设置,放后面吧
headers?: any,
): Promise<dataOut> {
parameter = { ...parameter, ...mergeData };
return new Promise((resolve, reject) => {
if (window.location.port == "8080") {//本地开发环境端口8080
let path = netName.split('{projectId}/')[1];//后缀名字之前的是文件夹,mock里结构
if (path.indexOf('/') <= -1) path = `projectX/${path}`;
const url = "../../mock/webNet/" + path + ".json";
fetchAsync(url)
.then((data) => {
//记录数据
dataRecord[netName] = data;
//统一错误信息提示
if (!hideMsg && !data.success) showToast(data.message || "网络异常")
//回调
callback && callback(data.success, data);
resolve(data)
console.log(
`\n%c[ mock ]\n`
+ `NAME : ${netName} \n`
+ `STATE : %o \n`
+ `PARAM : %o \n`
+ `%cDATA : %o \n`
, `${data.success ? 'color:green' : 'color:red'}`
, data.success
, parameter
, `${data.success ? 'color:green' : 'color:red'}`
, data
);
}, () => {
})
return
}
//网络请求
ajax({
url: netName.replace("{projectId}", getProjectId()), //请求地址
type: isGet ? 'GET' : "POST", //请求方式
data: parameter || {}, //请求参数
dataType: "json", // 返回值类型的设定,暂时只有json
async: true, //是否异步
headers: headers,
success: function (response) {
//发现有些接口成功了,但是response为空
response = response || {}
//记录数据
dataRecord[netName] = response;
//统一错误信息提示,
if (!hideMsg && !response.success) {
showToast(response.message || "网络异常")
}
callback && callback(response.success, response)
resolve(response)
console.log(
`\n%c[ request ]\n`
+ `NAME : ${netName} \n`
+ `STATE : %o \n`
+ `PARAM : %o \n`
+ `%cDATA : %o \n`
, `${response.success ? 'color:green' : 'color:red'}`
, response.success
, parameter
, `${response.success ? 'color:green' : 'color:red'}`
, response
);
},
error: function (status) {
if (!hideMsg) showToast("网络超时");
callback && callback(false)
resolve({ success: false });
console.log("接口" + netName + ":网络超时");
},
})
})
}
/**
* 获取数据
* @param netName
*/
export function getWebData(netName: WebNetName): dataOut {
return dataRecord[netName] || null;
}
//销毁数据
export function destroyWebNetData() {
dataRecord = {}
}
async function fetchAsync(url: string) {
// await response of fetch call
let response = await fetch(url);
// only proceed once promise is resolved
let data = await response.json();
// only proceed once second promise is resolved
return data;
}
const projectxString = "projectx/";
let projectId: string;
/**
* 获取链接上的projectId
*/
export function getProjectId(): string {
if (projectId) return projectId;
let windowUrl = window.location.href;
let splitArr = windowUrl.split(projectxString);
if (splitArr.length != 2) {
return projectId = "projectId"
}
let start = windowUrl.indexOf(projectxString) + projectxString.length;
let end = splitArr[1].indexOf("/");
return projectId = windowUrl.substr(start, end);
}
//这个临时,如星速台链接有变,注意
var isProd = location.href.indexOf(".com.cn/projectx") >= 0;
/**
* 刷新星速台tokenkey,注意多活动跳转手动执行一边
* @param callback
*/
export function refreshPxTokenKey(callback?: (success: boolean) => void) {
if (isProd) {//线上
var head = document.getElementsByTagName("head")[0];
const scriptEl = document.createElement('script');
scriptEl.src = "getTokenKey?_=" + Date.now();
scriptEl.onload = function () {
head.removeChild(scriptEl);
callback && callback(true)
};
scriptEl.onerror = function () {
head.removeChild(scriptEl);
callback && callback(false)
};
head.appendChild(scriptEl);
} else {//本地环境
callback && callback(true)
}
}
//执行一次
refreshPxTokenKey();
/**
* 带重刷tokenkey功能的获取token,返回token字符串或null
* @returns
*/
export function getPxTokenSave() {
return new Promise<string>((reslove, reject) => {
getPxToken(async (msg, token) => {
if (token) {
reslove(token);
return
}
//只重试一次,刷新tokenKey
var suc = await new Promise((r) => {
refreshPxTokenKey(r);
});
//刷新失败,返回空
if (!suc) {
reslove(null);
return;
}
//再次获取
getPxToken((msg, token) => {
reslove(token)
})
})
})
}
/**
* 获取星速台token
* @param callback
*/
function getPxToken(callback: (msg: string, token?: string) => void) {
if (!isProd) {//本地环境
callback(null, "token")
return
}
if (!window["ohjaiohdf"]) {
callback("need reload")
return
}
var xml = new XMLHttpRequest;
xml.open("get", "getToken?_t=" + Date.now(), !0);
xml.onreadystatechange = function () {
if (xml.readyState === 4 && xml.status === 200) {
var e = JSON.parse(xml.response);
if (e.success) {
window.eval(e.data);
callback(null, window["ohjaiohdf"]());
}
else {
var msg = (() => {
switch (e.code) {
case "100001":
return "need login"
case "100024":
return "state invalid"
default:
return e.code
}
})();
callback(msg);
}
}
}
xml.onerror = function () {
callback("net error")
};
xml.onloadend = function () {
xml.status === 404 && callback("net error")
};
xml.send()
}
export enum LOG_TYPE {
EXPOSURE = 'exposure',
CLICK = 'click',
}
/**
* 埋点 sendLog(LOG_TYPE.EXPOSURE,"4")
* @param type
* @param data
*/
export function sendLog(type: LOG_TYPE | 'exposure' | 'click', area: number) {
const projectID = getProjectId();
const appID = getUrlParams("appID");
//给个提示
if (!appID) console.error("appID不存在,检查链接")
var dpm = `${appID || 'appID'}.110.${area}.1`;// TODO appID注意默认写死一个,已防链接没有
var dcm = `202.${projectID || 'projectID'}.0.0`;
//看需求
// var dom = `${isWxClient() ? '2' : '1'}.0.0.0`;
let params: any = {
dpm,
dcm,
appId: appID
};
//看需求
// if (dom) params.dom = dom;
let isExposure = (type == LOG_TYPE.EXPOSURE);
if (isExposure) {
//曝光
jsonp('//embedlog.duiba.com.cn/exposure/standard', params);
} else {
//点击
jsonp('/log/click', params);
}
// console.log('try log', {type, ...params});
}
/**
* 根据规则id获取奖品列表
* @param strategyId 规则id
* @param optionId 不传表示返回所有奖品
*/
export function queryPrizeList(strategyId: string, optionId?: string): Promise<dataOut> {
let url = `/projectx/${getProjectId()}/${strategyId}.query`;
return new Promise((resolve) => {
if (window.location.port == "8080") {//本地环境
resolve({//自定义数据。暂时这样
"success": true,
"message": "consequat ea",
"data": [
{
"prizeType": "dolore culpa in tempor",
"name": "ka3",
"refType": "Excepteur adipisicing sint",
"icon": "//yun.duiba.com.cn/spark/assets/58184d8d965c556b412026acf7a5d5d9e7a975f5.png",
"index": "Ut in pariatur",
"id": "et",
"refId": "minim culpa veniam aliqua ut",
"prizeId": "aa",
"icon2": "aliquip consectetur laborum Duis"
}
],
"code": "fugiat velit in esse aute"
})
} else {
ajax({
url,
type: 'GET',
data: optionId ? { optionId } : {},
dataType: "json",
async: true,
success: function (response) {
resolve(response)
},
error: function () {
resolve({ success: false })
}
})
}
})
}
\ No newline at end of file
const apiCfg = {
getRule:`projectRule.query`,
doJoin: {
uri: `join.do`,
method: "post"
},
}
export default apiCfg;
import apiCfg from './apicfg';
import {getPxToken} from "@spark/projectx";
import {callApi} from '@spark/api-base'
import {Toast} from '@spark/ui'
import {isFromShare, newUser} from 'duiba-utils';
let mergeData = {
user_type: newUser ? '0' : '1',
is_from_share: isFromShare ? '0' : '1',
}
const apiList = {
...apiCfg
}
const API = generateAPI(apiList);
export default API;
function getRequestParams(value) {
if (typeof value === 'string') {
return {
uri: value,
method: 'get'
}
} else if (typeof value === 'object') {
const {uri, method = 'get', headers, withToken, secret, secretKey, contentType = 'form'} = value;
return {
uri,
method,
headers,
withToken,
secret,
secretKey,
contentType,
}
} else {
console.error('getRequestParams: 传参有误');
}
}
function generateAPI(apiList) {
const api = {};
for (let key in apiList) {
let value = apiList[key];
const {method, uri, headers: mHeaders, withToken, secret, secretKey, contentType} = getRequestParams(value);
api[key] = async (params = {}, headers) => {
let token;
if (withToken) {
try {
token = await getPxToken();
} catch (e) {
Toast('星速台token获取失败,***请补全该处理逻辑***');
return;
}
}
let mergedHeaders = {...mHeaders, ...headers}
if (withToken && token) {
params.token = token;
}
params = {...params, ...mergeData};
const result = await callApi(uri, params, method, mergedHeaders, false, secret, secretKey, contentType)
.catch(e => {
//捕获网络异常
Toast((e.message || '网络异常') + ' ***请补全该处理逻辑***');
});
if (result) {
//判断接口错误
if (!result.success) {
Toast((result.message || '接口错误') + ' ***请补全该处理逻辑***');
}
//返回整个结果
return result;
}
}
}
return api;
}
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./app.less";
import Modal from './modal/modal';
import MD from '../MD';
MD();
import "../monitor.js"; //前端错误监控
//此处为spark-cli动态生成
class App extends Component {
render() {
return (
<div>
<div>请在app.jsx中指定首页</div>
<Modal />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
* {
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;
}
export enum G_EVENT {
ON_SHOW = 'onShow', // 页面显示
ON_HIDE = 'onHide', // 页面隐藏
UPDATE_TASK = 'onUpdateTask', // 更新任务
UPDATE_SCENE= "onUpdateScene",//更新场景
}
import { Panel } from "../../module/views/Panel";
// interface IConfirmPanel {
//
// resolve: Function;
// reject: Function;
// promise: Promise<any>;
//
// make(): Promise<any>;
//
// }
export default class ConfirmPanel extends Panel {
resolve: Function = null;
reject: Function = null;
promise: Promise<any> = null;
public makePromise(): Promise<any> {
this.promise = new Promise<any>((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
return this.promise;
}
}
import { RES } from "../../module/RES";
import { getLightBgTexture } from "./getLightBgTexture";
/**
* 旋转光
*/
export class Light extends FYGE.Sprite {
constructor() {
super();
this.texture = RES.getRes("light.png");
this.anchorTexture.set(0.5, 0.5);
this.addEventListener(FYGE.Event.ENTER_FRAME, () => {
this.rotation += 1;
}, this)
}
}
/**
* 自行生成的光
*/
export class RotateLight extends FYGE.Sprite {
constructor(
lightColor: string = "#fffbb0",
lightRadius: number = 425,
lightNum: number = 18,
bgColor: string = lightColor,
bgRadius: number = lightRadius - 25
) {
super();
this.texture = getLightBgTexture(
lightColor,
lightRadius,
lightNum,
bgColor,
bgRadius
);
this.anchorTexture.set(0.5, 0.5);
this.addEventListener(FYGE.Event.ENTER_FRAME, () => {
this.rotation += 1;
}, this)
}
}
\ No newline at end of file
import { Tools } from "../Tools";
import { RES } from "../../module/RES";
/**
* 纯色进度条
*/
export class ProgressBar extends FYGE.Container {
/**
* 0到1的进度
*/
private _value = 0;
private upImage: FYGE.Graphics;
private progressTxt: FYGE.TextField;
private maxLength: number;
constructor() {
super()
this.maxLength = 377//最大长度
this._value = 0;
this.upImage = this.addChild(new FYGE.Graphics())
.beginFill(0xf8c862)
.drawRoundedRect(0, 0, this.value * this.maxLength, 19, 10)
.endFill();
this.progressTxt = this.addChild(Tools.getText(
"0%",
22,
"#f8c862",
FYGE.TEXT_ALIGN.CENTER,
80,
(this.maxLength - 80) / 2,
36,
))
}
get value() {
return this._value;
}
set value(v) {
if (v < 0) v = 0;
if (v > 1) v = 1;
this._value = v;
this.progressTxt.text = ((v * 100) >> 0) + "%";
var length = this._value * this.maxLength
this.upImage.clear()
.beginFill(0xf8c862)
.drawRoundedRect(0, 0, length, 19, 10)
.endFill();
}
}
/**
* 传入文案和进度条图片
* 进度条图片位移,固定遮罩
* 貌似这样就不需要继承显示类了
*/
export class ProgressBarS {
/**
* 0到1的进度
*/
private _value = 0;
private upImage: FYGE.Sprite;
private progressTxt: FYGE.TextField;
private maxLength: number;
private oriX: number
constructor(upImage: FYGE.Sprite, txt?: FYGE.TextField) {
this.maxLength = upImage.width;//最大长度,直接取图片宽度
this.upImage = upImage;
this.progressTxt = txt;
this.oriX = upImage.x;
var delta = 0
//传入的也可能是帧动画,这样原点就有问题了
if (upImage instanceof FYGE.FrameAni) delta = 0.5
//给图片加个矩形遮罩
this.upImage.mask = this.upImage.parent.addChild(new FYGE.Graphics())
.beginFill(0xf8c862)
.drawRoundedRect(
upImage.x - upImage.width * delta,
upImage.y - upImage.height * delta,
upImage.width,
upImage.height,
111
)
.endFill();
this.value = 0;
}
get value() {
return this._value;
}
set value(v) {
if (v < 0) v = 0;
if (v > 1) v = 1;
this._value = v;
if (this.progressTxt) this.progressTxt.text = ((v * 100) >> 0) + "%";
this.upImage.x = this.oriX - (1 - this._value) * this.maxLength
}
}
// var aa = this.addChild(new RichText(
// [
// { text: "啊请问请问", style: { color: "#000000", size: 30 } },
// { text: "=2134324234啊请问请问", style: { color: "#ff0000", size: 30 } },
// { text: "驱蚊器问问", style: { color: "#000000", size: 30 } }
// ]
// ))
// aa.text = [
// { text: "啊请问请问", style: { color: "#000000", size: 30 } },
// { text: "=2134", style: { color: "#ff0000", size: 30 } },
// { text: "驱蚊器问问", style: { color: "#000000", size: 30 } }
// ]
// aa.position.set(375, 800);
// [{text: "测试",style:{color: ""}},{},{}]
interface IRichTextEle {
text: string,
style: { color: string, size: number }
}
export class RichText extends FYGE.Container {
private static cache: FYGE.TextField[] = []
/**
*
* @param text
*/
constructor(text?: IRichTextEle[]) {
super()
if (text) this.text = text;
}
/**
* 水平对齐方式,默认居中
*/
get textAlign() {
return this._textAlign
}
set textAlign(value: FYGE.TEXT_ALIGN) {
if (this._textAlign !== value) {
this._textAlign = value;
this.adaptate();
}
}
private _textAlign: FYGE.TEXT_ALIGN = FYGE.TEXT_ALIGN.CENTER;
/**
* 垂直居中方式,默认居中
*/
get verticalAlign() {
return this._verticalAlign
}
set verticalAlign(value: FYGE.VERTICAL_ALIGN) {
if (this._verticalAlign !== value) {
this._verticalAlign = value;
this.adaptate();
}
}
private _verticalAlign: FYGE.VERTICAL_ALIGN = FYGE.VERTICAL_ALIGN.MIDDLE;
/**
* 文字间隙
*/
get gap(): number {
return this._gap;
};
set gap(value: number) {
if (this._gap != value) {
this._gap = value;
this.adaptate();
}
};
private _gap: number = 0;
/**
* 文本
*/
private _text: IRichTextEle[];
/**
* 按顺序
*/
get text(): IRichTextEle[] {
return this._text
}
/**
*
*/
set text(value: IRichTextEle[]) {
this._text = value;
var arr = value || [];
for (var i = 0; i < arr.length; i++) {
let a = arr[i];
let c: FYGE.TextField = this.children[i] || this.addChild(RichText.cache.shift() || new FYGE.TextField());
c.text = a.text;
c.fillColor = a.style.color;
c.size = a.style.size;
}
//如果多了,去掉后面的,回收
if (this.children.length > arr.length) {
//移除后序
for (var i = this.children.length - 1; i >= arr.length; i--) {
let c = this.children[i];
this.removeChild(c);
RichText.cache.push(c);
}
}
//适配
this.adaptate()
}
/**
* 适配,
*/
private adaptate() {
if (!this.children.length) return
var len = this.children.length;
//算总长度
var sum = 0;
for (var m = 0; m < len; m++) {
sum += this.children[m].textWidth;
}
sum += (len - 1) * this._gap;
//算出左边第一个元素的位置
var left: number;
if (this._textAlign == FYGE.TEXT_ALIGN.LEFT) {
left = 0
}
else if (this._textAlign == FYGE.TEXT_ALIGN.RIGHT) {
left = -sum
} else {
left = -sum / 2
}
var temSum = 0;
for (var i = 0; i < this.children.length; i++) {
this.children[i].x = left + temSum
temSum += this.children[i].textWidth + this._gap;
}
var up: number;
if (this._verticalAlign == FYGE.VERTICAL_ALIGN.UP) {
up = 0
}
else if (this._verticalAlign == FYGE.VERTICAL_ALIGN.DOWN) {
up = -1
} else {
up = -1 / 2
}
for (var i = 0; i < this.children.length; i++) {
this.children[i].y = this.children[i].textHeight * up;
}
}
}
\ No newline at end of file
//sdk
// <script src="//yun.duiba.com.cn/db_games/libs0924/howler.min.js"></script>
var resPath = "https://yun.duiba.com.cn/db_games/qx/hyundaiXXL/sound/";
export enum SoundType {
bg = "bg",
line = 'line',
boom = 'boom',
fall = 'fall',
eliminate = 'eliminate',
bonusTime = 'bonusTime',
}
export function cusPlaySound(type: SoundType, loop: boolean = false) {
playSound(resPath + type + ".mp3", loop);
}
/**
* 提前加载音频
* @param type
*/
export function preloadSound(type: SoundType) {
let src = resPath + type + ".mp3";
soundHash[src] = new Howl({
src: src,
preload: true,
});
}
/**
* 根据路径记录
*/
const soundHash: { [key: string]: Howl } = {};
export function playSound(src: string, loop: boolean = false) {
//console.log('测试音效',src);
let sound: Howl;
//循环的,且有缓存,取缓存的
if (soundHash[src] && loop) sound = soundHash[src]
//没有就新建
if (!sound) sound = new Howl({ src: [src], autoplay: false, loop });
//记录下,方便停止
soundHash[src] = sound;
//不循环删除缓存
if (!loop) sound.on('stop', function () { delete soundHash[src] });
//播放
sound.play();
//console.log('测试是否播放音效',src);
//返回一个,可以自行控制
return sound;
}
export function stopSound(src: string) {
if (soundHash[src]) soundHash[src].stop();
}
export function stopAllSound() {
for (let key in soundHash) soundHash[key].stop();
}
export function playAllSound() {
for (let key in soundHash) soundHash[key].play();
}
//设置隐藏属性和改变可见属性的事件的名称
let hidden: string, visibilityChange: string;
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document['msHidden'] !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
} else if (typeof document['webkitHidden'] !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}
const handleVisibilityChange = (e) => {
if (document.visibilityState == "visible") {
playAllSound();
console.log("网页显示")
}
else if (document.visibilityState == "hidden") {
stopAllSound()
console.log("网页隐藏")
}
};
document.addEventListener(
visibilityChange,
handleVisibilityChange,
false
);
window.onbeforeunload = function () {
//发接口
}
// window.addEventListener('beforeunload', ()=>{
// //发接口出去,
// })
// document.body['onbeforeunload'] = () => {
// }
/**
*
* @param dis
* @param zoomCenter 是否设定中心缩放,默认true,为了自行确定锚点的对象
*/
export function addBreathing(dis: FYGE.DisplayObject, zoomCenter: boolean = true) {
if (zoomCenter) {
dis.anchorX = dis.width / 2;
dis.anchorY = dis.height / 2;
}
FYGE.Tween.get(dis, { loop: true })
.to({ scaleX: 1.1, scaleY: 1.1 }, 1000)
.to({ scaleX: 1, scaleY: 1 }, 1000)
}
/**
*
* @param dis
* @param zoomCenter 是否设定中心缩放,默认true,为了自行确定锚点的对象
*/
export function addClickZoom(dis: FYGE.DisplayObject, zoomCenter: boolean = true) {
if (zoomCenter) {
dis.anchorX = dis.width / 2;
dis.anchorY = dis.height / 2;
}
dis.addEventListener("onMouseDown", _mouseEvent, dis)
.addEventListener("onMouseUp", _mouseEvent, dis)
.addEventListener("onMouseOut", _mouseEvent, dis);
let s = dis;
function _mouseEvent(e: FYGE.MouseEvent) {
if (e.type == FYGE.MouseEvent.MOUSE_DOWN) {
FYGE.Tween.removeTweens(s);
FYGE.Tween.get(s).to({ scaleX: 0.9, scaleY: 0.9 }, 50);
} else {
FYGE.Tween.removeTweens(s);
FYGE.Tween.get(s).to({ scaleX: 1, scaleY: 1 }, 50);
}
}
}
\ No newline at end of file
/**
* 倒计时
* @param time 毫秒计算
* @param onChange 根据时间倒计时的执行函数
*/
export function countDown(time: number, onChange: (t: number) => void) {
var timeObj = { a: time };
FYGE.Tween.get(timeObj, {
onChange: () => {
onChange(timeObj.a)
// this.timeTxt.text = "" + Math.round(timeObj.a / 1000) + "s"
// if (timeObj.a < 100) {
// FYGE.Tween.removeTweens(timeObj)
// callback()
// }
}
})
.to({ a: 0 }, time)
//返回一个,可以中途取消
return timeObj
}
/**
* 中断倒计时
* @param timeObj
*/
export function clearCountDown(timeObj) {
if (!timeObj) return
FYGE.Tween.removeTweens(timeObj)
}
const cache: {
[key: string]: FYGE.Texture
} = {}
/**
*
* @param lightColor 颜色
* @param lightRadius 光环半径
* @param lightNum 光环扇形数量
* @param bgColor 背光颜色
* @param bgRadius 背光半径
*/
export function getLightBgTexture(
lightColor: string = "#fffbb0",
lightRadius: number = 425,
lightNum: number = 18,
bgColor: string = lightColor,
bgRadius: number = lightRadius - 25
) {
const cacheKey = `${lightColor}_${lightRadius}_${lightNum}_${bgColor}_${bgRadius}`;
//缓存过就返回
if (cache[cacheKey]) return cache[cacheKey];
const canvas = FYGE.createCanvas()// document.createElement("canvas");
canvas.width = canvas.height = lightRadius * 2;
const x = lightRadius, y = x;
const ctx = canvas.getContext("2d");
//最大值18,否则开放每个灯光角度
lightNum = Math.floor(Math.min(18, lightNum));
//背景的光晕
var colorObj = ctx.createRadialGradient(x, y, 0, x, y, bgRadius);
colorObj.addColorStop(0, bgColor);
colorObj.addColorStop(1, bgColor + "00");
ctx.fillStyle = colorObj;
ctx.beginPath();
ctx.arc(x, y, lightRadius, 0, 2 * Math.PI)
ctx.fill()
//径向的光
var colorObj = ctx.createRadialGradient(x, y, 0, x, y, lightRadius);
colorObj.addColorStop(0, lightColor);
colorObj.addColorStop(1, lightColor + "00");
ctx.fillStyle = colorObj;
ctx.beginPath();
var anglePer = Math.PI / 12;
var delta = Math.PI * 2 / lightNum;
for (var i = 0; i < lightNum; i++) {
ctx.moveTo(x, y)
ctx.arc(x, y, lightRadius, Math.PI * 1.5 - anglePer / 2 + delta * i, Math.PI * 1.5 + anglePer / 2 + delta * i)
}
ctx.fill();
//缓存
cache[cacheKey] = FYGE.Texture.fromCanvas(canvas);
return cache[cacheKey];
}
\ No newline at end of file
import React, { Component } from "react";
import './modal.less';
import { observer } from 'mobx-react';
import modalStore from '../store/modal';
import { toJS } from 'mobx';
export const cfg = {
};
@observer
class Modal extends Component {
constructor(props) {
super(props);
}
componentDidMount() { }
render() {
const list = toJS(modalStore.popList);
if (!list.length) {
//TODO:此处根据需要自行修改
document.body.style.overflow='auto';
return <section></section>;
}
let PopUp, popData, PopUpMulti, popUpMultiData;
if (list.length > 1 && list[list.length - 1].isMulti == true) {
const popObj2 = list[list.length - 1];
PopUpMulti = cfg[popObj2.key];
popUpMultiData = popObj2.data;
}
const popObj = list[0];
PopUp = cfg[popObj.key];
popData = popObj.data;
if (PopUp || PopUpMulti) {
document.body.style.overflow='hidden';
}
return <section className="modal-hoc-bg" style={{
zIndex: !!modalStore.popList.length ? 1000 : -1,
display: !!modalStore.popList.length ? 'block' : 'none'
}}>
{PopUp && <PopUp popData={popData} />}
{PopUpMulti && <section className="modal-hoc-bg" style={{
zIndex: !!modalStore.popList.length ? 1000 : -1,
display: !!modalStore.popList.length ? 'block' : 'none'
}}><PopUpMulti popData={popUpMultiData} />
</section>}
</section>;
}
}
export default Modal;
\ No newline at end of file
.modal-hoc-bg {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1000;
}
\ No newline at end of file
import { makeAutoObservable } from 'mobx';
import API from '../api/index';
const store = makeAutoObservable({
ruleInfo: '',
setRule(ruleInfo) {
this.ruleInfo = ruleInfo
},
async initRule() {
// 模拟获取远程的数据
const { data } = await API.getRule();
this.setRule(data)
}
})
export default store;
\ No newline at end of file
import { makeAutoObservable,toJS } from 'mobx';
//此处配置页面的优先级,越大优先级越高
// PopIndex:11
const modalIndex = {
}
const modalStore = makeAutoObservable({
popList: [],
/**
*
* @param {*} key 弹窗名,一般是类名的字符串
* @param {*} data 需要传递的数据,弹窗中使用 const {popData} = props; 获取
* @param {*} isMulti 是否是二级弹窗,在不关闭已有弹窗的基础上,弹出当前弹窗。注意,如果是二级弹窗,关闭时必须传key
*/
pushPop(key, data,isMulti=false) {
if (this.popList.length) {
let cacheList = this.popList.slice();
cacheList.push({ key, data,isMulti });
cacheList = cacheList.sort((a, b) => ((modalIndex[b.key] ? modalIndex[b.key] : 10) - (modalIndex[a.key] ? modalIndex[a.key] : 10)))
this.popList.clear();
this.popList.push(...cacheList);
} else {
this.popList.push({ key, data,isMulti });
}
// console.log("this.popList:::",toJS(this.popList));
},
closePop(key) {
if (key) {
let cacheList = this.popList.slice();
cacheList = cacheList.filter(obj => (obj.key != key));
this.popList.clear();
this.popList.push(...cacheList);
} else {
this.popList.shift();
}
},
closePopAll() {
this.popList.clear();
}
});
export default modalStore;
import { changeScene } from "../../module/ctrls";
import { RES } from "../../module/RES";
import { Scene } from "../../module/views/Scene";
import { ProgressBarS } from "../common/ProgressBarS";
import { getWebData, sendWebNet, WebNetName } from "../WebNet";
import { StartScene } from "./StartScene";
export class LoadingScene extends Scene {
get groupNames() {
return ["loading"]
}
progressBar: ProgressBarS;
initUi() {
//适配
// this.y = -layers.stageOffsetY
//背景
// this.addChild(FYGE.Sprite.fromUrl("xxxxxxxx"))
// .position.set(0, 0)
//进度条底图
this.addChild(FYGE.Sprite.fromFrame("进度条底.png"))
.position.set((750 - 577) / 2, 1288 - 24)
//进度条
var pro = this.addChild(FYGE.Sprite.fromFrame("进度条.png"));
pro.position.set((750 - 577) / 2, 1288 - 24)
//进度条托管
this.progressBar = new ProgressBarS(pro);
}
async start() {
super.start()
//监听进度条事件
this.addEventListener(FYGE.Event.PROGRESS, this.progressEvent, this)
//首次进度一点
this.dispatchEvent(FYGE.Event.PROGRESS, 0.2)
//做些啥?
this.dispatchEvent(FYGE.Event.PROGRESS, 0.3);
// 接口示例
var res1 = await sendWebNet(WebNetName.index)
//做些啥?
if (!res1.success) return
//判断是否结束
//
this.dispatchEvent(FYGE.Event.PROGRESS, 0.5);
//资源1
await RES.loadGroup("StartScene")
this.dispatchEvent(FYGE.Event.PROGRESS, 0.6);
//资源2
// await RES.loadGroup("mapCrabEffect")
this.dispatchEvent(FYGE.Event.PROGRESS, 0.7);
//资源
// await RES
this.dispatchEvent(FYGE.Event.PROGRESS, 0.8);
//随便异步示例
await new Promise((r) => {
setTimeout(r, 100)
})
this.dispatchEvent(FYGE.Event.PROGRESS, 1);
}
progressEvent(e: FYGE.Event) {
let pro = e.data;
FYGE.Tween.removeTweens(this.progressBar)
FYGE.Tween.get(this.progressBar)
.to({ value: pro }, 2000)
.call(() => {
if (pro >= 1) {
this.removeEventListener(FYGE.Event.PROGRESS, this.progressEvent, this);
changeScene(StartScene,getWebData(WebNetName.index).data)
}
})
}
}
import { Scene } from "../../module/views/Scene"
import { Tools } from "../Tools";
export class PlayScene extends Scene {
get groupNames() { return ["playScene"] };
initUi() {
this.addChild(Tools.getSprite("playBg.jpg"))
.addEventListener(FYGE.MouseEvent.CLICK, () => {
console.log("点击背景")
}, this)
.position.set(0, 0)
}
start(data) {
super.start();
}
initEvents() {
super.initEvents();
}
removeEvents() {
super.removeEvents();
}
}
\ No newline at end of file
import { Panel } from "../../module/views/Panel";
import { Tools } from "../Tools";
import { getWebData, sendWebNet, WebNetName } from "../WebNet";
let section;
export class RulePanel extends Panel {
get groupNames() { return ["RulePanel"] }
get skinName() { return "RulePanel" }
ruleTxt: FYGE.TextField;
knowBtn: FYGE.Button;
closeBtn: FYGE.Button;
//两个按钮都是关闭作用
get closeBtns() {
return [this.closeBtn, this.knowBtn];
}
async start(data) {
super.start();
//取接口数据
const res = await sendWebNet(WebNetName.projectRule)
if (!res.success) return
var ruleStr = res.data;
//原先视图上有一个
this.removeChild(this.ruleTxt);
this.addChild(this.closeBtn);
console.log(this.closeBtn)
//文案
// var scroll = this.addChild(new FYGE.ScrollPage(610, 816, 100, true, false))
// scroll.position.copy(this.ruleTxt.position)
// //加文案
// var txt = scroll.view.addChild(Tools.getText(
// ruleStr,
// 30,//this.ruleTxt.size,
// this.ruleTxt.fillColor,
// FYGE.TEXT_ALIGN.LEFT,
// 610
// ))
// //多行设置
// txt.lineType = FYGE.TEXT_lINETYPE.MULTI;
// //行间距设置
// txt.lineSpacing = 20;
// //滚动最大长度按文本高度
// scroll.maxDistance = txt.textHeight
if (!section) {//避免文案过长,用这种方式
document.getElementById("cusEngine").style.position = "absolute"
section = document.createElement('section');
section.id = "rule";
section.style.overflowX = "hidden";
section.style.overflowY = "auto";
section.style.width = 610 + "px";
section.style.height = 816 + "px";
section.style.lineHeight = 48 + "px";
section.style.fontSize = this.ruleTxt.size + 'px';
section.style.color = this.ruleTxt.fillColor;
section.style.whiteSpace = "pre-line";
section.innerHTML = ruleStr;
}
var rule = this.addChild(new FYGE.FloatDisplay());
rule.position.set(this.ruleTxt.x, this.ruleTxt.y)
rule.init(section);
}
}
const ruleTemplate = `啊企鹅去欧文u去外婆偶尔u欺骗我如情人坡i去哦日期【人贫穷人品【去哦微软【哦前往平壤【 去哦【让我气泡【让我去【王培荣亲王【人跑去欧文人【强我弱【\n 去哦人权为荣哦破千万人脾气【微软哦亲哦人气泡【 人游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则
游戏规则游戏规则游戏规则游戏规则游戏规则`
import { Scene } from "../../module/views/Scene";
import { showPanel, showWaiting, hideWaiting, showToast, changeScene } from "../../module/ctrls";
import { RulePanel } from "./RulePanel";
import { Tools } from "../Tools";
import { layers } from "../../module/views/layers";
import { GDispatcher } from "../Main";
import { G_EVENT } from "../common/G_EVENT";
import { PlayScene } from "./PlayScene";
import { sendWebNet, WebNetName } from "../WebNet";
export class StartScene extends Scene {
get groupNames() { return ["StartScene"] }
get skinName() { return "StartScene" }
taskBtn: FYGE.Button;
lotBtn: FYGE.Button;
rankBtn: FYGE.Button;
timesTxt: FYGE.TextField;
startBtn: FYGE.Button;
ruleBtn: FYGE.Button;
recordBtn: FYGE.Button;
initUi() {
// this.y -= layers.stageOffsetY;
//次数文案居中
Tools.changeTextAlign(this.timesTxt, FYGE.TEXT_ALIGN.CENTER, 300);
//加滚动
if (layers.stageHeight < 1624) {
var scroll = new FYGE.ScrollPage(750, layers.stageHeight, 1624 - layers.stageOffsetY, true, true)
// 所有内容加入滚动
// this.children.forEach((c)=>{ //这种方式有问题,因为子级的索引
// scroll.view.addChild(c);
// })
scroll.view.addChildren(...this.removeChildren());
// scroll.view.addChildren.apply(scroll.view,this.removeChildren())
// //滚动加入加入父级
this.addChild(scroll);
}
}
async start(data) {
super.start()
//次数文案修改
this.timesTxt.text = "剩余次数:" + this.data.gameCounts + "次";
}
initEvents() {
super.initEvents();
//开始游戏
this.startBtn.addEventListener(FYGE.MouseEvent.CLICK, async () => {
showWaiting();
var res = await sendWebNet(WebNetName.join)
hideWaiting();
if (res.success) {
changeScene(PlayScene, { ...res.data });
} else {
//TODO
}
}, this)
//规则按钮
this.ruleBtn.addEventListener(FYGE.MouseEvent.CLICK, () => {
showPanel(RulePanel)
}, this)
//我的奖品按钮
this.recordBtn.addEventListener(FYGE.MouseEvent.CLICK, () => {
//弄个延时
Tools.btnDelay(this.recordBtn)
//跳转,链接待定
location.href = window["recordUrl"];
}, this)
//排行榜按钮
this.rankBtn.addEventListener(FYGE.MouseEvent.CLICK, () => {
console.log("点击了排行榜弹框")
}, this)
//任务弹框
this.taskBtn.addEventListener(FYGE.MouseEvent.CLICK, () => {
console.log("点击了任务弹框")
}, this)
//监听下次数修改
GDispatcher.addEventListener(G_EVENT.UPDATE_SCENE, this.updateScene, this);
}
removeEvents() {
super.removeEvents();
//移除次数监听
GDispatcher.removeEventListener(G_EVENT.UPDATE_SCENE, this.updateScene, this);
//其他的按钮事件不写了,没存引用,反正destroy会把挂在场景上的所有显示对象的事件都清除
}
}
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"noImplicitAny": false,
"sourceMap": true,
"removeComments": true,
"noEmitOnError":true,
"outDir":"dist",
/*"outFile": "./index.js",*/
"lib": [
"es5",
"dom",
"es2015.promise"
]
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
const path = require('path');
module.exports = {
entry: './src/Main.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'output.js',
path: __dirname,
libraryTarget: 'umd',
}
};
\ No newline at end of file
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const MockWebpackPlugin = require('mock-webpack-plugin');
const mockConfig = require('./mock/config.js');
module.exports = merge(common, {
devtool: 'eval-source-map',
devServer: {
contentBase: '.',
proxy: {
'/plugin/*':'http://localhost:3000',
'/ngapi/*': 'http://localhost:3000',
'/ngame/*': 'http://localhost:3000',
'/hdtool/*': 'http://localhost:3000',
}
},
plugins: [
new MockWebpackPlugin({
config: mockConfig,
port: 3000
})
]
});
\ No newline at end of file
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
module.exports = merge(common, {
mode: "production",//production development
devtool: 'source-map',
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
});
\ No newline at end of file
{
"proName": "sxbank_money_0802",
"proDesc": "",
"proPath": "/Users/wanghongyuan/wfc13/sxbank_money_0802",
"createTime": 1627871281519
}
\ No newline at end of file
{"proName":"test","proDesc":"","proPath":"/Users/wanghongyuan/wfc13/sxbank_money_0802","createTime":1627874091255}
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