feat: 增加摸金风向标小程序代码

master
laixingyu 3 years ago
commit 335c69074a

@ -0,0 +1,16 @@
{ // launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}

@ -0,0 +1,33 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
this.setToken()
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
methods: {
setToken() {
if (this.$cache.get('token')) {
uni.switchTab({
url: `/pages/home/home`,
})
} else {
uni.reLaunch({
url: '/pages/index/index',
})
}
},
},
}
</script>
<style lang="scss">
/*每个页面公共css */
@import '@/uni_modules/uview-ui/index.scss';
</style>

@ -0,0 +1,7 @@
export default {
// server: 'https://daike2.tt.demo.cq1080.com/api/v1', // 开发接口地址
server: 'https://gupiao.365rise.top/ssdmn-gupiao-api', // 生产接口地址
appKey: 'bc097852a77d4ee9ce3435e0948d0e5e', // 接口 appkey
prefix: 'yyq_', // 缓存信息 key 前缀
}

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

@ -0,0 +1,37 @@
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import uView from '@/uni_modules/uview-ui'
import store from './store'
import api from './plugins/api'
import cache from './plugins/cache'
import permission from './plugins/permission'
import * as util from './plugins/util'
import config from './config'
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
Vue.use(uView)
Vue.prototype.$api = api
Vue.prototype.$cache = cache
Vue.prototype.$store = store
Vue.prototype.$permission = permission
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App,
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app,
store,
}
}
app.$mount()
// #endif

@ -0,0 +1,92 @@
{
"name" : "gupiao_weixin_uniapp",
"appid" : "__UNI__FFD798D",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx1ff32548702fbfdc",
"setting" : {
"urlCheck" : false,
"minified" : true
},
"usingComponents" : true,
"lazyCodeLoading" : "requiredComponents",
"optimization" : {
"subPackages" : true
},
"packOptions" : "",
"include" : [
{
"type" : "file",
"value" : "uni_modules/lime-echart/static/echarts.min.js"
},
{
"type" : "file",
"value" : "uni_modules/lime-echart/static/ecStat.min"
},
{
"type" : "file",
"value" : "uni_modules/lime-echart/static/uni.webview.1.5.3"
}
]
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
}

15
node_modules/.bin/xss generated vendored

@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../xss/bin/xss" "$@"
ret=$?
else
node "$basedir/../xss/bin/xss" "$@"
ret=$?
fi
exit $ret

7
node_modules/.bin/xss.cmd generated vendored

@ -0,0 +1,7 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\xss\bin\xss" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\xss\bin\xss" %*
)

25
node_modules/.yarn-integrity generated vendored

@ -0,0 +1,25 @@
{
"systemParams": "win32-x64-93",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [
"md5@^2.3.0",
"qs@^5.2.1",
"xss@^1.0.14"
],
"lockfileEntries": {
"charenc@0.0.2": "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667",
"commander@^2.20.3": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33",
"crypt@0.0.2": "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b",
"cssfilter@0.0.10": "https://registry.npmmirror.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae",
"is-buffer@~1.1.6": "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be",
"md5@^2.3.0": "https://registry.npmmirror.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f",
"qs@^5.2.1": "https://registry.npmmirror.com/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc",
"xss@^1.0.14": "https://registry.npmmirror.com/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694"
},
"files": [],
"artifacts": {}
}

27
node_modules/charenc/LICENSE.mkd generated vendored

@ -0,0 +1,27 @@
Copyright © 2011, Paul Vorbach. All rights reserved.
Copyright © 2009, Jeff Mott. All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name Crypto-JS nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
node_modules/charenc/README.js generated vendored

@ -0,0 +1 @@
**enc** provides crypto character encoding utilities.

33
node_modules/charenc/charenc.js generated vendored

@ -0,0 +1,33 @@
var charenc = {
// UTF-8 encoding
utf8: {
// Convert a string to a byte array
stringToBytes: function(str) {
return charenc.bin.stringToBytes(unescape(encodeURIComponent(str)));
},
// Convert a byte array to a string
bytesToString: function(bytes) {
return decodeURIComponent(escape(charenc.bin.bytesToString(bytes)));
}
},
// Binary encoding
bin: {
// Convert a string to a byte array
stringToBytes: function(str) {
for (var bytes = [], i = 0; i < str.length; i++)
bytes.push(str.charCodeAt(i) & 0xFF);
return bytes;
},
// Convert a byte array to a string
bytesToString: function(bytes) {
for (var str = [], i = 0; i < bytes.length; i++)
str.push(String.fromCharCode(bytes[i]));
return str.join('');
}
}
};
module.exports = charenc;

24
node_modules/charenc/package.json generated vendored

@ -0,0 +1,24 @@
{
"author": "Paul Vorbach <paul@vorb.de> (http://vorb.de)",
"name": "charenc",
"description": "character encoding utilities",
"tags": [
"utf8",
"binary",
"byte",
"string"
],
"version": "0.0.2",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "git://github.com/pvorb/node-charenc.git"
},
"bugs": {
"url": "https://github.com/pvorb/node-charenc/issues"
},
"main": "charenc.js",
"engines": {
"node": "*"
}
}

419
node_modules/commander/CHANGELOG.md generated vendored

@ -0,0 +1,419 @@
2.20.3 / 2019-10-11
==================
* Support Node.js 0.10 (Revert #1059)
* Ran "npm unpublish commander@2.20.2". There is no 2.20.2.
2.20.1 / 2019-09-29
==================
* Improve executable subcommand tracking
* Update dev dependencies
2.20.0 / 2019-04-02
==================
* fix: resolve symbolic links completely when hunting for subcommands (#935)
* Update index.d.ts (#930)
* Update Readme.md (#924)
* Remove --save option as it isn't required anymore (#918)
* Add link to the license file (#900)
* Added example of receiving args from options (#858)
* Added missing semicolon (#882)
* Add extension to .eslintrc (#876)
2.19.0 / 2018-10-02
==================
* Removed newline after Options and Commands headers (#864)
* Bugfix - Error output (#862)
* Fix to change default value to string (#856)
2.18.0 / 2018-09-07
==================
* Standardize help output (#853)
* chmod 644 travis.yml (#851)
* add support for execute typescript subcommand via ts-node (#849)
2.17.1 / 2018-08-07
==================
* Fix bug in command emit (#844)
2.17.0 / 2018-08-03
==================
* fixed newline output after help information (#833)
* Fix to emit the action even without command (#778)
* npm update (#823)
2.16.0 / 2018-06-29
==================
* Remove Makefile and `test/run` (#821)
* Make 'npm test' run on Windows (#820)
* Add badge to display install size (#807)
* chore: cache node_modules (#814)
* chore: remove Node.js 4 (EOL), add Node.js 10 (#813)
* fixed typo in readme (#812)
* Fix types (#804)
* Update eslint to resolve vulnerabilities in lodash (#799)
* updated readme with custom event listeners. (#791)
* fix tests (#794)
2.15.0 / 2018-03-07
==================
* Update downloads badge to point to graph of downloads over time instead of duplicating link to npm
* Arguments description
2.14.1 / 2018-02-07
==================
* Fix typing of help function
2.14.0 / 2018-02-05
==================
* only register the option:version event once
* Fixes issue #727: Passing empty string for option on command is set to undefined
* enable eqeqeq rule
* resolves #754 add linter configuration to project
* resolves #560 respect custom name for version option
* document how to override the version flag
* document using options per command
2.13.0 / 2018-01-09
==================
* Do not print default for --no-
* remove trailing spaces in command help
* Update CI's Node.js to LTS and latest version
* typedefs: Command and Option types added to commander namespace
2.12.2 / 2017-11-28
==================
* fix: typings are not shipped
2.12.1 / 2017-11-23
==================
* Move @types/node to dev dependency
2.12.0 / 2017-11-22
==================
* add attributeName() method to Option objects
* Documentation updated for options with --no prefix
* typings: `outputHelp` takes a string as the first parameter
* typings: use overloads
* feat(typings): update to match js api
* Print default value in option help
* Fix translation error
* Fail when using same command and alias (#491)
* feat(typings): add help callback
* fix bug when description is add after command with options (#662)
* Format js code
* Rename History.md to CHANGELOG.md (#668)
* feat(typings): add typings to support TypeScript (#646)
* use current node
2.11.0 / 2017-07-03
==================
* Fix help section order and padding (#652)
* feature: support for signals to subcommands (#632)
* Fixed #37, --help should not display first (#447)
* Fix translation errors. (#570)
* Add package-lock.json
* Remove engines
* Upgrade package version
* Prefix events to prevent conflicts between commands and options (#494)
* Removing dependency on graceful-readlink
* Support setting name in #name function and make it chainable
* Add .vscode directory to .gitignore (Visual Studio Code metadata)
* Updated link to ruby commander in readme files
2.10.0 / 2017-06-19
==================
* Update .travis.yml. drop support for older node.js versions.
* Fix require arguments in README.md
* On SemVer you do not start from 0.0.1
* Add missing semi colon in readme
* Add save param to npm install
* node v6 travis test
* Update Readme_zh-CN.md
* Allow literal '--' to be passed-through as an argument
* Test subcommand alias help
* link build badge to master branch
* Support the alias of Git style sub-command
* added keyword commander for better search result on npm
* Fix Sub-Subcommands
* test node.js stable
* Fixes TypeError when a command has an option called `--description`
* Update README.md to make it beginner friendly and elaborate on the difference between angled and square brackets.
* Add chinese Readme file
2.9.0 / 2015-10-13
==================
* Add option `isDefault` to set default subcommand #415 @Qix-
* Add callback to allow filtering or post-processing of help text #434 @djulien
* Fix `undefined` text in help information close #414 #416 @zhiyelee
2.8.1 / 2015-04-22
==================
* Back out `support multiline description` Close #396 #397
2.8.0 / 2015-04-07
==================
* Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee
* Fix bug in Git-style sub-commands #372 @zhiyelee
* Allow commands to be hidden from help #383 @tonylukasavage
* When git-style sub-commands are in use, yet none are called, display help #382 @claylo
* Add ability to specify arguments syntax for top-level command #258 @rrthomas
* Support multiline descriptions #208 @zxqfox
2.7.1 / 2015-03-11
==================
* Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.
2.7.0 / 2015-03-09
==================
* Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
* Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage
* Add support for camelCase on `opts()`. Close #353 @nkzawa
* Add node.js 0.12 and io.js to travis.yml
* Allow RegEx options. #337 @palanik
* Fixes exit code when sub-command failing. Close #260 #332 @pirelenito
* git-style `bin` files in $PATH make sense. Close #196 #327 @zhiyelee
2.6.0 / 2014-12-30
==================
* added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee
* Add application description to the help msg. Close #112 @dalssoft
2.5.1 / 2014-12-15
==================
* fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee
2.5.0 / 2014-10-24
==================
* add support for variadic arguments. Closes #277 @whitlockjc
2.4.0 / 2014-10-17
==================
* fixed a bug on executing the coercion function of subcommands option. Closes #270
* added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage
* added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage
* fixed a bug on subcommand name. Closes #248 @jonathandelgado
* fixed function normalize doesnt honor option terminator. Closes #216 @abbr
2.3.0 / 2014-07-16
==================
* add command alias'. Closes PR #210
* fix: Typos. Closes #99
* fix: Unused fs module. Closes #217
2.2.0 / 2014-03-29
==================
* add passing of previous option value
* fix: support subcommands on windows. Closes #142
* Now the defaultValue passed as the second argument of the coercion function.
2.1.0 / 2013-11-21
==================
* add: allow cflag style option params, unit test, fixes #174
2.0.0 / 2013-07-18
==================
* remove input methods (.prompt, .confirm, etc)
1.3.2 / 2013-07-18
==================
* add support for sub-commands to co-exist with the original command
1.3.1 / 2013-07-18
==================
* add quick .runningCommand hack so you can opt-out of other logic when running a sub command
1.3.0 / 2013-07-09
==================
* add EACCES error handling
* fix sub-command --help
1.2.0 / 2013-06-13
==================
* allow "-" hyphen as an option argument
* support for RegExp coercion
1.1.1 / 2012-11-20
==================
* add more sub-command padding
* fix .usage() when args are present. Closes #106
1.1.0 / 2012-11-16
==================
* add git-style executable subcommand support. Closes #94
1.0.5 / 2012-10-09
==================
* fix `--name` clobbering. Closes #92
* fix examples/help. Closes #89
1.0.4 / 2012-09-03
==================
* add `outputHelp()` method.
1.0.3 / 2012-08-30
==================
* remove invalid .version() defaulting
1.0.2 / 2012-08-24
==================
* add `--foo=bar` support [arv]
* fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
1.0.1 / 2012-08-03
==================
* fix issue #56
* fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
1.0.0 / 2012-07-05
==================
* add support for optional option descriptions
* add defaulting of `.version()` to package.json's version
0.6.1 / 2012-06-01
==================
* Added: append (yes or no) on confirmation
* Added: allow node.js v0.7.x
0.6.0 / 2012-04-10
==================
* Added `.prompt(obj, callback)` support. Closes #49
* Added default support to .choose(). Closes #41
* Fixed the choice example
0.5.1 / 2011-12-20
==================
* Fixed `password()` for recent nodes. Closes #36
0.5.0 / 2011-12-04
==================
* Added sub-command option support [itay]
0.4.3 / 2011-12-04
==================
* Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24
==================
* Added travis support
* Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18
==================
* Removed listening for "close" on --help
0.4.0 / 2011-11-15
==================
* Added support for `--`. Closes #24
0.3.3 / 2011-11-14
==================
* Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01
==================
* Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31
==================
* Changed `--version` short flag to `-V` from `-v`
* Changed `.version()` so it's configurable [felixge]
0.3.0 / 2011-10-31
==================
* Added support for long flags only. Closes #18
0.2.1 / 2011-10-24
==================
* "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26
==================
* Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24
==================
* Added support for custom `--help` output
0.0.5 / 2011-08-18
==================
* Changed: when the user enters nothing prompt for password again
* Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15
==================
* Fixed `Commander#args`
0.0.3 / 2011-08-15
==================
* Added default option value support
0.0.2 / 2011-08-15
==================
* Added mask support to `Command#password(str[, mask], fn)`
* Added `Command#password(str, fn)`
0.0.1 / 2010-01-03
==================
* Initial release

22
node_modules/commander/LICENSE generated vendored

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

428
node_modules/commander/Readme.md generated vendored

@ -0,0 +1,428 @@
# Commander.js
[![Build Status](https://api.travis-ci.org/tj/commander.js.svg?branch=master)](http://travis-ci.org/tj/commander.js)
[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://npmcharts.com/compare/commander?minimal=true)
[![Install Size](https://packagephobia.now.sh/badge?p=commander)](https://packagephobia.now.sh/result?p=commander)
[![Join the chat at https://gitter.im/tj/commander.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tj/commander.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
[API documentation](http://tj.github.com/commander.js/)
## Installation
$ npm install commander
## Option parsing
Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq-sauce', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbqSauce) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
```
Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
Note that multi-word options starting with `--no` prefix negate the boolean value of the following word. For example, `--no-sauce` sets the value of `program.sauce` to false.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.option('--no-sauce', 'Remove sauce')
.parse(process.argv);
console.log('you ordered a pizza');
if (program.sauce) console.log(' with sauce');
else console.log(' without sauce');
```
To get string arguments from options you will need to use angle brackets <> for required inputs or square brackets [] for optional inputs.
e.g. ```.option('-m --myarg [myVar]', 'my super cool description')```
Then to access the input if it was passed in.
e.g. ```var myInput = program.myarg```
**NOTE**: If you pass a argument without using brackets the example above will return true and not the value passed in.
## Version option
Calling the `version` implicitly adds the `-V` and `--version` options to the command.
When either of these options is present, the command prints the version number and exits.
$ ./examples/pizza -V
0.0.1
If you want your program to respond to the `-v` option instead of the `-V` option, simply pass custom flags to the `version` method using the same syntax as the `option` method.
```js
program
.version('0.0.1', '-v, --version')
```
The version flags can be named anything, but the long option is required.
## Command-specific options
You can attach options to a command.
```js
#!/usr/bin/env node
var program = require('commander');
program
.command('rm <dir>')
.option('-r, --recursive', 'Remove recursively')
.action(function (dir, cmd) {
console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
})
program.parse(process.argv)
```
A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
## Coercion
```js
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
function collect(val, memo) {
memo.push(val);
return memo;
}
function increaseVerbosity(v, total) {
return total + 1;
}
program
.version('0.1.0')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.option('-c, --collect [value]', 'A repeatable value', collect, [])
.option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);
```
## Regular Expression
```js
program
.version('0.1.0')
.option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
.option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
.parse(process.argv);
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);
```
## Variadic arguments
The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
append `...` to the argument name. Here is an example:
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.command('rmdir <dir> [otherDirs...]')
.action(function (dir, otherDirs) {
console.log('rmdir %s', dir);
if (otherDirs) {
otherDirs.forEach(function (oDir) {
console.log('rmdir %s', oDir);
});
}
});
program.parse(process.argv);
```
An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
to your action as demonstrated above.
## Specify the argument syntax
```js
#!/usr/bin/env node
var program = require('commander');
program
.version('0.1.0')
.arguments('<cmd> [env]')
.action(function (cmd, env) {
cmdValue = cmd;
envValue = env;
});
program.parse(process.argv);
if (typeof cmdValue === 'undefined') {
console.error('no command given!');
process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");
```
Angled brackets (e.g. `<cmd>`) indicate required input. Square brackets (e.g. `[env]`) indicate optional input.
## Git-style sub-commands
```js
// file: ./examples/pm
var program = require('commander');
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('list', 'list packages installed', {isDefault: true})
.parse(process.argv);
```
When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`.
Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the subcommand from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
### `--harmony`
You can enable `--harmony` option in two ways:
* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version dont support this pattern.
* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```
$ ./examples/pizza --help
Usage: pizza [options]
An application for pizzas ordering
Options:
-h, --help output usage information
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineapple
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-C, --no-cheese You do not want any cheese
```
## Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviors, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
console.log('stuff');
```
Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
```
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
## .outputHelp(cb)
Output help information without exiting.
Optional callback cb allows post-processing of help text before it is displayed.
If you want to display help by default (e.g. if no command was provided), you can use something like:
```js
var program = require('commander');
var colors = require('colors');
program
.version('0.1.0')
.command('getstream [url]', 'get stream URL')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
```
## .help(cb)
Output help information and exit immediately.
Optional callback cb allows post-processing of help text before it is displayed.
## Custom event listeners
You can execute custom actions by listening to command and option events.
```js
program.on('option:verbose', function () {
process.env.VERBOSE = this.verbose;
});
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
```
## Examples
```js
var program = require('commander');
program
.version('0.1.0')
.option('-C, --chdir <path>', 'change the working directory')
.option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
.option('-T, --no-tests', 'ignore test hook');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option("-s, --setup_mode [mode]", "Which setup mode to use")
.action(function(env, options){
var mode = options.setup_mode || "normal";
env = env || 'all';
console.log('setup for %s env(s) with %s mode', env, mode);
});
program
.command('exec <cmd>')
.alias('ex')
.description('execute the given remote cmd')
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
}).on('--help', function() {
console.log('');
console.log('Examples:');
console.log('');
console.log(' $ deploy exec sequential');
console.log(' $ deploy exec async');
});
program
.command('*')
.action(function(env){
console.log('deploying "%s"', env);
});
program.parse(process.argv);
```
More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
## License
[MIT](https://github.com/tj/commander.js/blob/master/LICENSE)

1224
node_modules/commander/index.js generated vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
{
"name": "commander",
"version": "2.20.3",
"description": "the complete solution for node.js command-line programs",
"keywords": [
"commander",
"command",
"option",
"parser"
],
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/tj/commander.js.git"
},
"scripts": {
"lint": "eslint index.js",
"test": "node test/run.js && npm run test-typings",
"test-typings": "tsc -p tsconfig.json"
},
"main": "index",
"files": [
"index.js",
"typings/index.d.ts"
],
"dependencies": {},
"devDependencies": {
"@types/node": "^12.7.8",
"eslint": "^6.4.0",
"should": "^13.2.3",
"sinon": "^7.5.0",
"standard": "^14.3.1",
"ts-node": "^8.4.1",
"typescript": "^3.6.3"
},
"typings": "typings/index.d.ts"
}

@ -0,0 +1,310 @@
// Type definitions for commander 2.11
// Project: https://github.com/visionmedia/commander.js
// Definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace local {
class Option {
flags: string;
required: boolean;
optional: boolean;
bool: boolean;
short?: string;
long: string;
description: string;
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags: string, description?: string);
}
class Command extends NodeJS.EventEmitter {
[key: string]: any;
args: string[];
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name?: string);
/**
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* @param {string} str
* @param {string} [flags]
* @returns {Command} for chaining
*/
version(str: string, flags?: string): Command;
/**
* Add command `name`.
*
* The `.action()` callback is invoked when the
* command `name` is specified via __ARGV__,
* and the remaining arguments are applied to the
* function for access.
*
* When the `name` is "*" an un-matched command
* will be passed as the first arg, followed by
* the rest of __ARGV__ remaining.
*
* @example
* program
* .version('0.0.1')
* .option('-C, --chdir <path>', 'change the working directory')
* .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
* .option('-T, --no-tests', 'ignore test hook')
*
* program
* .command('setup')
* .description('run remote setup commands')
* .action(function() {
* console.log('setup');
* });
*
* program
* .command('exec <cmd>')
* .description('run the given remote command')
* .action(function(cmd) {
* console.log('exec "%s"', cmd);
* });
*
* program
* .command('teardown <dir> [otherDirs...]')
* .description('run teardown commands')
* .action(function(dir, otherDirs) {
* console.log('dir "%s"', dir);
* if (otherDirs) {
* otherDirs.forEach(function (oDir) {
* console.log('dir "%s"', oDir);
* });
* }
* });
*
* program
* .command('*')
* .description('deploy the given env')
* .action(function(env) {
* console.log('deploying "%s"', env);
* });
*
* program.parse(process.argv);
*
* @param {string} name
* @param {string} [desc] for git-style sub-commands
* @param {CommandOptions} [opts] command options
* @returns {Command} the new command
*/
command(name: string, desc?: string, opts?: commander.CommandOptions): Command;
/**
* Define argument syntax for the top-level command.
*
* @param {string} desc
* @returns {Command} for chaining
*/
arguments(desc: string): Command;
/**
* Parse expected `args`.
*
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
*
* @param {string[]} args
* @returns {Command} for chaining
*/
parseExpectedArgs(args: string[]): Command;
/**
* Register callback `fn` for the command.
*
* @example
* program
* .command('help')
* .description('display verbose help')
* .action(function() {
* // output help here
* });
*
* @param {(...args: any[]) => void} fn
* @returns {Command} for chaining
*/
action(fn: (...args: any[]) => void): Command;
/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
*
* The `flags` string should contain both the short and long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
*
* @example
* // simple boolean defaulting to false
* program.option('-p, --pepper', 'add pepper');
*
* --pepper
* program.pepper
* // => Boolean
*
* // simple boolean defaulting to true
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => false
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
*
* @param {string} flags
* @param {string} [description]
* @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default
* @param {*} [defaultValue]
* @returns {Command} for chaining
*/
option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
option(flags: string, description?: string, defaultValue?: any): Command;
/**
* Allow unknown options on the command line.
*
* @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options.
* @returns {Command} for chaining
*/
allowUnknownOption(arg?: boolean): Command;
/**
* Parse `argv`, settings options and invoking commands when defined.
*
* @param {string[]} argv
* @returns {Command} for chaining
*/
parse(argv: string[]): Command;
/**
* Parse options from `argv` returning `argv` void of these options.
*
* @param {string[]} argv
* @returns {ParseOptionsResult}
*/
parseOptions(argv: string[]): commander.ParseOptionsResult;
/**
* Return an object containing options as key-value pairs
*
* @returns {{[key: string]: any}}
*/
opts(): { [key: string]: any };
/**
* Set the description to `str`.
*
* @param {string} str
* @param {{[argName: string]: string}} argsDescription
* @return {(Command | string)}
*/
description(str: string, argsDescription?: {[argName: string]: string}): Command;
description(): string;
/**
* Set an alias for the command.
*
* @param {string} alias
* @return {(Command | string)}
*/
alias(alias: string): Command;
alias(): string;
/**
* Set or get the command usage.
*
* @param {string} str
* @return {(Command | string)}
*/
usage(str: string): Command;
usage(): string;
/**
* Set the name of the command.
*
* @param {string} str
* @return {Command}
*/
name(str: string): Command;
/**
* Get the name of the command.
*
* @return {string}
*/
name(): string;
/**
* Output help information for this command.
*
* @param {(str: string) => string} [cb]
*/
outputHelp(cb?: (str: string) => string): void;
/** Output help information and exit.
*
* @param {(str: string) => string} [cb]
*/
help(cb?: (str: string) => string): never;
}
}
declare namespace commander {
type Command = local.Command
type Option = local.Option
interface CommandOptions {
noHelp?: boolean;
isDefault?: boolean;
}
interface ParseOptionsResult {
args: string[];
unknown: string[];
}
interface CommanderStatic extends Command {
Command: typeof local.Command;
Option: typeof local.Option;
CommandOptions: CommandOptions;
ParseOptionsResult: ParseOptionsResult;
}
}
declare const commander: commander.CommanderStatic;
export = commander;

27
node_modules/crypt/LICENSE.mkd generated vendored

@ -0,0 +1,27 @@
Copyright © 2011, Paul Vorbach. All rights reserved.
Copyright © 2009, Jeff Mott. All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name Crypto-JS nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
node_modules/crypt/README.mkd generated vendored

@ -0,0 +1 @@
**crypt** provides utilities for encryption and hashing

96
node_modules/crypt/crypt.js generated vendored

@ -0,0 +1,96 @@
(function() {
var base64map
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
crypt = {
// Bit-wise rotation left
rotl: function(n, b) {
return (n << b) | (n >>> (32 - b));
},
// Bit-wise rotation right
rotr: function(n, b) {
return (n << (32 - b)) | (n >>> b);
},
// Swap big-endian to little-endian and vice versa
endian: function(n) {
// If number given, swap endian
if (n.constructor == Number) {
return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00;
}
// Else, assume array and swap all items
for (var i = 0; i < n.length; i++)
n[i] = crypt.endian(n[i]);
return n;
},
// Generate an array of any length of random bytes
randomBytes: function(n) {
for (var bytes = []; n > 0; n--)
bytes.push(Math.floor(Math.random() * 256));
return bytes;
},
// Convert a byte array to big-endian 32-bit words
bytesToWords: function(bytes) {
for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
words[b >>> 5] |= bytes[i] << (24 - b % 32);
return words;
},
// Convert big-endian 32-bit words to a byte array
wordsToBytes: function(words) {
for (var bytes = [], b = 0; b < words.length * 32; b += 8)
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
return bytes;
},
// Convert a byte array to a hex string
bytesToHex: function(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16));
hex.push((bytes[i] & 0xF).toString(16));
}
return hex.join('');
},
// Convert a hex string to a byte array
hexToBytes: function(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
},
// Convert a byte array to a base-64 string
bytesToBase64: function(bytes) {
for (var base64 = [], i = 0; i < bytes.length; i += 3) {
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
for (var j = 0; j < 4; j++)
if (i * 8 + j * 6 <= bytes.length * 8)
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
else
base64.push('=');
}
return base64.join('');
},
// Convert a base-64 string to a byte array
base64ToBytes: function(base64) {
// Remove non-base-64 characters
base64 = base64.replace(/[^A-Z0-9+\/]/ig, '');
for (var bytes = [], i = 0, imod4 = 0; i < base64.length;
imod4 = ++i % 4) {
if (imod4 == 0) continue;
bytes.push(((base64map.indexOf(base64.charAt(i - 1))
& (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2))
| (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
}
return bytes;
}
};
module.exports = crypt;
})();

22
node_modules/crypt/package.json generated vendored

@ -0,0 +1,22 @@
{
"author": "Paul Vorbach <paul@vorb.de> (http://vorb.de)",
"name": "crypt",
"description": "utilities for encryption and hashing",
"tags": [
"hash",
"security"
],
"version": "0.0.2",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "git://github.com/pvorb/node-crypt.git"
},
"bugs": {
"url": "https://github.com/pvorb/node-crypt/issues"
},
"main": "crypt.js",
"engines": {
"node": "*"
}
}

22
node_modules/cssfilter/LICENSE generated vendored

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 老雷
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

86
node_modules/cssfilter/README.md generated vendored

@ -0,0 +1,86 @@
[![NPM version](https://badge.fury.io/js/cssfilter.png)](http://badge.fury.io/js/xss)
[![Build Status](https://secure.travis-ci.org/leizongmin/js-css-filter.png?branch=master)](http://travis-ci.org/leizongmin/js-css-filter)
[![Dependencies Status](https://david-dm.org/leizongmin/js-css-filter.png)](https://david-dm.org/leizongmin/js-css-filter)
[![coveralls-image](https://img.shields.io/coveralls/leizongmin/js-css-filter.svg?style=flat-square)](https://coveralls.io/r/leizongmin/js-css-filter?branch=master)
# cssfilter
Sanitize untrusted CSS with a configuration specified by a Whitelist. 根据白名单过滤CSS
## 安装
```bash
$ npm install cssfilter --save
```
## 使用方法
```javascript
var cssfilter = require('cssfilter');
var css = cssfilter('position:fixed; /* this is comments */ width:100px; height:100px; background:#aaa;');
console.log(css);
// 输出width:100px; height:100px; background:#aaa;
// 因为position不在白名单允许范围
```
或者:
```javascript
options = {
// 白名单,可选
whiteList: {
a: true, // true表示允许
b: /^fixed|relative$/, // 正则test()返回true表示允许
c: function (value) {
// 返回true表示允许
},
d: false // 除以上三个以外,所有值均表示不允许
},
// 当匹配到一个在白名单中的属性时
onAttr: function (name, value, options) {
// name为属性名
// value为属性值
// 返回字符串表示覆盖此段CSS
// 不返回任何值表示使用默认生成方法,即 name:value
},
// 当匹配到一个不在白名单中的属性时
onIgnoreAttr: function (name, value, options) {
// name为属性名
// value为属性值
// 返回字符串表示覆盖此段CSS
// 不返回任何值表示使用默认生成方法即将此段CSS去掉
}
};
mycss = new cssfilter.FilterCSS(options);
// then apply mycss.process()
css = mycss.process('position:fixed; width:100px; height:100px; background:#aaa;');
console.log(css);
```
## License
```
The MIT License (MIT)
Copyright (c) 2015-2016 Zongmin Lei(雷宗民) <leizongmin@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

110
node_modules/cssfilter/lib/css.js generated vendored

@ -0,0 +1,110 @@
/**
* cssfilter
*
* @author 老雷<leizongmin@gmail.com>
*/
var DEFAULT = require('./default');
var parseStyle = require('./parser');
var _ = require('./util');
/**
* 返回值是否为空
*
* @param {Object} obj
* @return {Boolean}
*/
function isNull (obj) {
return (obj === undefined || obj === null);
}
/**
* 浅拷贝对象
*
* @param {Object} obj
* @return {Object}
*/
function shallowCopyObject (obj) {
var ret = {};
for (var i in obj) {
ret[i] = obj[i];
}
return ret;
}
/**
* 创建CSS过滤器
*
* @param {Object} options
* - {Object} whiteList
* - {Function} onAttr
* - {Function} onIgnoreAttr
* - {Function} safeAttrValue
*/
function FilterCSS (options) {
options = shallowCopyObject(options || {});
options.whiteList = options.whiteList || DEFAULT.whiteList;
options.onAttr = options.onAttr || DEFAULT.onAttr;
options.onIgnoreAttr = options.onIgnoreAttr || DEFAULT.onIgnoreAttr;
options.safeAttrValue = options.safeAttrValue || DEFAULT.safeAttrValue;
this.options = options;
}
FilterCSS.prototype.process = function (css) {
// 兼容各种奇葩输入
css = css || '';
css = css.toString();
if (!css) return '';
var me = this;
var options = me.options;
var whiteList = options.whiteList;
var onAttr = options.onAttr;
var onIgnoreAttr = options.onIgnoreAttr;
var safeAttrValue = options.safeAttrValue;
var retCSS = parseStyle(css, function (sourcePosition, position, name, value, source) {
var check = whiteList[name];
var isWhite = false;
if (check === true) isWhite = check;
else if (typeof check === 'function') isWhite = check(value);
else if (check instanceof RegExp) isWhite = check.test(value);
if (isWhite !== true) isWhite = false;
// 如果过滤后 value 为空则直接忽略
value = safeAttrValue(name, value);
if (!value) return;
var opts = {
position: position,
sourcePosition: sourcePosition,
source: source,
isWhite: isWhite
};
if (isWhite) {
var ret = onAttr(name, value, opts);
if (isNull(ret)) {
return name + ':' + value;
} else {
return ret;
}
} else {
var ret = onIgnoreAttr(name, value, opts);
if (!isNull(ret)) {
return ret;
}
}
});
return retCSS;
};
module.exports = FilterCSS;

@ -0,0 +1,398 @@
/**
* cssfilter
*
* @author 老雷<leizongmin@gmail.com>
*/
function getDefaultWhiteList () {
// 白名单值说明:
// true: 允许该属性
// Function: function (val) { } 返回true表示允许该属性其他值均表示不允许
// RegExp: regexp.test(val) 返回true表示允许该属性其他值均表示不允许
// 除上面列出的值外均表示不允许
var whiteList = {};
whiteList['align-content'] = false; // default: auto
whiteList['align-items'] = false; // default: auto
whiteList['align-self'] = false; // default: auto
whiteList['alignment-adjust'] = false; // default: auto
whiteList['alignment-baseline'] = false; // default: baseline
whiteList['all'] = false; // default: depending on individual properties
whiteList['anchor-point'] = false; // default: none
whiteList['animation'] = false; // default: depending on individual properties
whiteList['animation-delay'] = false; // default: 0
whiteList['animation-direction'] = false; // default: normal
whiteList['animation-duration'] = false; // default: 0
whiteList['animation-fill-mode'] = false; // default: none
whiteList['animation-iteration-count'] = false; // default: 1
whiteList['animation-name'] = false; // default: none
whiteList['animation-play-state'] = false; // default: running
whiteList['animation-timing-function'] = false; // default: ease
whiteList['azimuth'] = false; // default: center
whiteList['backface-visibility'] = false; // default: visible
whiteList['background'] = true; // default: depending on individual properties
whiteList['background-attachment'] = true; // default: scroll
whiteList['background-clip'] = true; // default: border-box
whiteList['background-color'] = true; // default: transparent
whiteList['background-image'] = true; // default: none
whiteList['background-origin'] = true; // default: padding-box
whiteList['background-position'] = true; // default: 0% 0%
whiteList['background-repeat'] = true; // default: repeat
whiteList['background-size'] = true; // default: auto
whiteList['baseline-shift'] = false; // default: baseline
whiteList['binding'] = false; // default: none
whiteList['bleed'] = false; // default: 6pt
whiteList['bookmark-label'] = false; // default: content()
whiteList['bookmark-level'] = false; // default: none
whiteList['bookmark-state'] = false; // default: open
whiteList['border'] = true; // default: depending on individual properties
whiteList['border-bottom'] = true; // default: depending on individual properties
whiteList['border-bottom-color'] = true; // default: current color
whiteList['border-bottom-left-radius'] = true; // default: 0
whiteList['border-bottom-right-radius'] = true; // default: 0
whiteList['border-bottom-style'] = true; // default: none
whiteList['border-bottom-width'] = true; // default: medium
whiteList['border-collapse'] = true; // default: separate
whiteList['border-color'] = true; // default: depending on individual properties
whiteList['border-image'] = true; // default: none
whiteList['border-image-outset'] = true; // default: 0
whiteList['border-image-repeat'] = true; // default: stretch
whiteList['border-image-slice'] = true; // default: 100%
whiteList['border-image-source'] = true; // default: none
whiteList['border-image-width'] = true; // default: 1
whiteList['border-left'] = true; // default: depending on individual properties
whiteList['border-left-color'] = true; // default: current color
whiteList['border-left-style'] = true; // default: none
whiteList['border-left-width'] = true; // default: medium
whiteList['border-radius'] = true; // default: 0
whiteList['border-right'] = true; // default: depending on individual properties
whiteList['border-right-color'] = true; // default: current color
whiteList['border-right-style'] = true; // default: none
whiteList['border-right-width'] = true; // default: medium
whiteList['border-spacing'] = true; // default: 0
whiteList['border-style'] = true; // default: depending on individual properties
whiteList['border-top'] = true; // default: depending on individual properties
whiteList['border-top-color'] = true; // default: current color
whiteList['border-top-left-radius'] = true; // default: 0
whiteList['border-top-right-radius'] = true; // default: 0
whiteList['border-top-style'] = true; // default: none
whiteList['border-top-width'] = true; // default: medium
whiteList['border-width'] = true; // default: depending on individual properties
whiteList['bottom'] = false; // default: auto
whiteList['box-decoration-break'] = true; // default: slice
whiteList['box-shadow'] = true; // default: none
whiteList['box-sizing'] = true; // default: content-box
whiteList['box-snap'] = true; // default: none
whiteList['box-suppress'] = true; // default: show
whiteList['break-after'] = true; // default: auto
whiteList['break-before'] = true; // default: auto
whiteList['break-inside'] = true; // default: auto
whiteList['caption-side'] = false; // default: top
whiteList['chains'] = false; // default: none
whiteList['clear'] = true; // default: none
whiteList['clip'] = false; // default: auto
whiteList['clip-path'] = false; // default: none
whiteList['clip-rule'] = false; // default: nonzero
whiteList['color'] = true; // default: implementation dependent
whiteList['color-interpolation-filters'] = true; // default: auto
whiteList['column-count'] = false; // default: auto
whiteList['column-fill'] = false; // default: balance
whiteList['column-gap'] = false; // default: normal
whiteList['column-rule'] = false; // default: depending on individual properties
whiteList['column-rule-color'] = false; // default: current color
whiteList['column-rule-style'] = false; // default: medium
whiteList['column-rule-width'] = false; // default: medium
whiteList['column-span'] = false; // default: none
whiteList['column-width'] = false; // default: auto
whiteList['columns'] = false; // default: depending on individual properties
whiteList['contain'] = false; // default: none
whiteList['content'] = false; // default: normal
whiteList['counter-increment'] = false; // default: none
whiteList['counter-reset'] = false; // default: none
whiteList['counter-set'] = false; // default: none
whiteList['crop'] = false; // default: auto
whiteList['cue'] = false; // default: depending on individual properties
whiteList['cue-after'] = false; // default: none
whiteList['cue-before'] = false; // default: none
whiteList['cursor'] = false; // default: auto
whiteList['direction'] = false; // default: ltr
whiteList['display'] = true; // default: depending on individual properties
whiteList['display-inside'] = true; // default: auto
whiteList['display-list'] = true; // default: none
whiteList['display-outside'] = true; // default: inline-level
whiteList['dominant-baseline'] = false; // default: auto
whiteList['elevation'] = false; // default: level
whiteList['empty-cells'] = false; // default: show
whiteList['filter'] = false; // default: none
whiteList['flex'] = false; // default: depending on individual properties
whiteList['flex-basis'] = false; // default: auto
whiteList['flex-direction'] = false; // default: row
whiteList['flex-flow'] = false; // default: depending on individual properties
whiteList['flex-grow'] = false; // default: 0
whiteList['flex-shrink'] = false; // default: 1
whiteList['flex-wrap'] = false; // default: nowrap
whiteList['float'] = false; // default: none
whiteList['float-offset'] = false; // default: 0 0
whiteList['flood-color'] = false; // default: black
whiteList['flood-opacity'] = false; // default: 1
whiteList['flow-from'] = false; // default: none
whiteList['flow-into'] = false; // default: none
whiteList['font'] = true; // default: depending on individual properties
whiteList['font-family'] = true; // default: implementation dependent
whiteList['font-feature-settings'] = true; // default: normal
whiteList['font-kerning'] = true; // default: auto
whiteList['font-language-override'] = true; // default: normal
whiteList['font-size'] = true; // default: medium
whiteList['font-size-adjust'] = true; // default: none
whiteList['font-stretch'] = true; // default: normal
whiteList['font-style'] = true; // default: normal
whiteList['font-synthesis'] = true; // default: weight style
whiteList['font-variant'] = true; // default: normal
whiteList['font-variant-alternates'] = true; // default: normal
whiteList['font-variant-caps'] = true; // default: normal
whiteList['font-variant-east-asian'] = true; // default: normal
whiteList['font-variant-ligatures'] = true; // default: normal
whiteList['font-variant-numeric'] = true; // default: normal
whiteList['font-variant-position'] = true; // default: normal
whiteList['font-weight'] = true; // default: normal
whiteList['grid'] = false; // default: depending on individual properties
whiteList['grid-area'] = false; // default: depending on individual properties
whiteList['grid-auto-columns'] = false; // default: auto
whiteList['grid-auto-flow'] = false; // default: none
whiteList['grid-auto-rows'] = false; // default: auto
whiteList['grid-column'] = false; // default: depending on individual properties
whiteList['grid-column-end'] = false; // default: auto
whiteList['grid-column-start'] = false; // default: auto
whiteList['grid-row'] = false; // default: depending on individual properties
whiteList['grid-row-end'] = false; // default: auto
whiteList['grid-row-start'] = false; // default: auto
whiteList['grid-template'] = false; // default: depending on individual properties
whiteList['grid-template-areas'] = false; // default: none
whiteList['grid-template-columns'] = false; // default: none
whiteList['grid-template-rows'] = false; // default: none
whiteList['hanging-punctuation'] = false; // default: none
whiteList['height'] = true; // default: auto
whiteList['hyphens'] = false; // default: manual
whiteList['icon'] = false; // default: auto
whiteList['image-orientation'] = false; // default: auto
whiteList['image-resolution'] = false; // default: normal
whiteList['ime-mode'] = false; // default: auto
whiteList['initial-letters'] = false; // default: normal
whiteList['inline-box-align'] = false; // default: last
whiteList['justify-content'] = false; // default: auto
whiteList['justify-items'] = false; // default: auto
whiteList['justify-self'] = false; // default: auto
whiteList['left'] = false; // default: auto
whiteList['letter-spacing'] = true; // default: normal
whiteList['lighting-color'] = true; // default: white
whiteList['line-box-contain'] = false; // default: block inline replaced
whiteList['line-break'] = false; // default: auto
whiteList['line-grid'] = false; // default: match-parent
whiteList['line-height'] = false; // default: normal
whiteList['line-snap'] = false; // default: none
whiteList['line-stacking'] = false; // default: depending on individual properties
whiteList['line-stacking-ruby'] = false; // default: exclude-ruby
whiteList['line-stacking-shift'] = false; // default: consider-shifts
whiteList['line-stacking-strategy'] = false; // default: inline-line-height
whiteList['list-style'] = true; // default: depending on individual properties
whiteList['list-style-image'] = true; // default: none
whiteList['list-style-position'] = true; // default: outside
whiteList['list-style-type'] = true; // default: disc
whiteList['margin'] = true; // default: depending on individual properties
whiteList['margin-bottom'] = true; // default: 0
whiteList['margin-left'] = true; // default: 0
whiteList['margin-right'] = true; // default: 0
whiteList['margin-top'] = true; // default: 0
whiteList['marker-offset'] = false; // default: auto
whiteList['marker-side'] = false; // default: list-item
whiteList['marks'] = false; // default: none
whiteList['mask'] = false; // default: border-box
whiteList['mask-box'] = false; // default: see individual properties
whiteList['mask-box-outset'] = false; // default: 0
whiteList['mask-box-repeat'] = false; // default: stretch
whiteList['mask-box-slice'] = false; // default: 0 fill
whiteList['mask-box-source'] = false; // default: none
whiteList['mask-box-width'] = false; // default: auto
whiteList['mask-clip'] = false; // default: border-box
whiteList['mask-image'] = false; // default: none
whiteList['mask-origin'] = false; // default: border-box
whiteList['mask-position'] = false; // default: center
whiteList['mask-repeat'] = false; // default: no-repeat
whiteList['mask-size'] = false; // default: border-box
whiteList['mask-source-type'] = false; // default: auto
whiteList['mask-type'] = false; // default: luminance
whiteList['max-height'] = true; // default: none
whiteList['max-lines'] = false; // default: none
whiteList['max-width'] = true; // default: none
whiteList['min-height'] = true; // default: 0
whiteList['min-width'] = true; // default: 0
whiteList['move-to'] = false; // default: normal
whiteList['nav-down'] = false; // default: auto
whiteList['nav-index'] = false; // default: auto
whiteList['nav-left'] = false; // default: auto
whiteList['nav-right'] = false; // default: auto
whiteList['nav-up'] = false; // default: auto
whiteList['object-fit'] = false; // default: fill
whiteList['object-position'] = false; // default: 50% 50%
whiteList['opacity'] = false; // default: 1
whiteList['order'] = false; // default: 0
whiteList['orphans'] = false; // default: 2
whiteList['outline'] = false; // default: depending on individual properties
whiteList['outline-color'] = false; // default: invert
whiteList['outline-offset'] = false; // default: 0
whiteList['outline-style'] = false; // default: none
whiteList['outline-width'] = false; // default: medium
whiteList['overflow'] = false; // default: depending on individual properties
whiteList['overflow-wrap'] = false; // default: normal
whiteList['overflow-x'] = false; // default: visible
whiteList['overflow-y'] = false; // default: visible
whiteList['padding'] = true; // default: depending on individual properties
whiteList['padding-bottom'] = true; // default: 0
whiteList['padding-left'] = true; // default: 0
whiteList['padding-right'] = true; // default: 0
whiteList['padding-top'] = true; // default: 0
whiteList['page'] = false; // default: auto
whiteList['page-break-after'] = false; // default: auto
whiteList['page-break-before'] = false; // default: auto
whiteList['page-break-inside'] = false; // default: auto
whiteList['page-policy'] = false; // default: start
whiteList['pause'] = false; // default: implementation dependent
whiteList['pause-after'] = false; // default: implementation dependent
whiteList['pause-before'] = false; // default: implementation dependent
whiteList['perspective'] = false; // default: none
whiteList['perspective-origin'] = false; // default: 50% 50%
whiteList['pitch'] = false; // default: medium
whiteList['pitch-range'] = false; // default: 50
whiteList['play-during'] = false; // default: auto
whiteList['position'] = false; // default: static
whiteList['presentation-level'] = false; // default: 0
whiteList['quotes'] = false; // default: text
whiteList['region-fragment'] = false; // default: auto
whiteList['resize'] = false; // default: none
whiteList['rest'] = false; // default: depending on individual properties
whiteList['rest-after'] = false; // default: none
whiteList['rest-before'] = false; // default: none
whiteList['richness'] = false; // default: 50
whiteList['right'] = false; // default: auto
whiteList['rotation'] = false; // default: 0
whiteList['rotation-point'] = false; // default: 50% 50%
whiteList['ruby-align'] = false; // default: auto
whiteList['ruby-merge'] = false; // default: separate
whiteList['ruby-position'] = false; // default: before
whiteList['shape-image-threshold'] = false; // default: 0.0
whiteList['shape-outside'] = false; // default: none
whiteList['shape-margin'] = false; // default: 0
whiteList['size'] = false; // default: auto
whiteList['speak'] = false; // default: auto
whiteList['speak-as'] = false; // default: normal
whiteList['speak-header'] = false; // default: once
whiteList['speak-numeral'] = false; // default: continuous
whiteList['speak-punctuation'] = false; // default: none
whiteList['speech-rate'] = false; // default: medium
whiteList['stress'] = false; // default: 50
whiteList['string-set'] = false; // default: none
whiteList['tab-size'] = false; // default: 8
whiteList['table-layout'] = false; // default: auto
whiteList['text-align'] = true; // default: start
whiteList['text-align-last'] = true; // default: auto
whiteList['text-combine-upright'] = true; // default: none
whiteList['text-decoration'] = true; // default: none
whiteList['text-decoration-color'] = true; // default: currentColor
whiteList['text-decoration-line'] = true; // default: none
whiteList['text-decoration-skip'] = true; // default: objects
whiteList['text-decoration-style'] = true; // default: solid
whiteList['text-emphasis'] = true; // default: depending on individual properties
whiteList['text-emphasis-color'] = true; // default: currentColor
whiteList['text-emphasis-position'] = true; // default: over right
whiteList['text-emphasis-style'] = true; // default: none
whiteList['text-height'] = true; // default: auto
whiteList['text-indent'] = true; // default: 0
whiteList['text-justify'] = true; // default: auto
whiteList['text-orientation'] = true; // default: mixed
whiteList['text-overflow'] = true; // default: clip
whiteList['text-shadow'] = true; // default: none
whiteList['text-space-collapse'] = true; // default: collapse
whiteList['text-transform'] = true; // default: none
whiteList['text-underline-position'] = true; // default: auto
whiteList['text-wrap'] = true; // default: normal
whiteList['top'] = false; // default: auto
whiteList['transform'] = false; // default: none
whiteList['transform-origin'] = false; // default: 50% 50% 0
whiteList['transform-style'] = false; // default: flat
whiteList['transition'] = false; // default: depending on individual properties
whiteList['transition-delay'] = false; // default: 0s
whiteList['transition-duration'] = false; // default: 0s
whiteList['transition-property'] = false; // default: all
whiteList['transition-timing-function'] = false; // default: ease
whiteList['unicode-bidi'] = false; // default: normal
whiteList['vertical-align'] = false; // default: baseline
whiteList['visibility'] = false; // default: visible
whiteList['voice-balance'] = false; // default: center
whiteList['voice-duration'] = false; // default: auto
whiteList['voice-family'] = false; // default: implementation dependent
whiteList['voice-pitch'] = false; // default: medium
whiteList['voice-range'] = false; // default: medium
whiteList['voice-rate'] = false; // default: normal
whiteList['voice-stress'] = false; // default: normal
whiteList['voice-volume'] = false; // default: medium
whiteList['volume'] = false; // default: medium
whiteList['white-space'] = false; // default: normal
whiteList['widows'] = false; // default: 2
whiteList['width'] = true; // default: auto
whiteList['will-change'] = false; // default: auto
whiteList['word-break'] = true; // default: normal
whiteList['word-spacing'] = true; // default: normal
whiteList['word-wrap'] = true; // default: normal
whiteList['wrap-flow'] = false; // default: auto
whiteList['wrap-through'] = false; // default: wrap
whiteList['writing-mode'] = false; // default: horizontal-tb
whiteList['z-index'] = false; // default: auto
return whiteList;
}
/**
* 匹配到白名单上的一个属性时
*
* @param {String} name
* @param {String} value
* @param {Object} options
* @return {String}
*/
function onAttr (name, value, options) {
// do nothing
}
/**
* 匹配到不在白名单上的一个属性时
*
* @param {String} name
* @param {String} value
* @param {Object} options
* @return {String}
*/
function onIgnoreAttr (name, value, options) {
// do nothing
}
var REGEXP_URL_JAVASCRIPT = /javascript\s*\:/img;
/**
* 过滤属性值
*
* @param {String} name
* @param {String} value
* @return {String}
*/
function safeAttrValue(name, value) {
if (REGEXP_URL_JAVASCRIPT.test(value)) return '';
return value;
}
exports.whiteList = getDefaultWhiteList();
exports.getDefaultWhiteList = getDefaultWhiteList;
exports.onAttr = onAttr;
exports.onIgnoreAttr = onIgnoreAttr;
exports.safeAttrValue = safeAttrValue;

@ -0,0 +1,32 @@
/**
* cssfilter
*
* @author 老雷<leizongmin@gmail.com>
*/
var DEFAULT = require('./default');
var FilterCSS = require('./css');
/**
* XSS过滤
*
* @param {String} css 要过滤的CSS代码
* @param {Object} options 选项whiteList, onAttr, onIgnoreAttr
* @return {String}
*/
function filterCSS (html, options) {
var xss = new FilterCSS(options);
return xss.process(html);
}
// 输出
exports = module.exports = filterCSS;
exports.FilterCSS = FilterCSS;
for (var i in DEFAULT) exports[i] = DEFAULT[i];
// 在浏览器端使用
if (typeof window !== 'undefined') {
window.filterCSS = module.exports;
}

@ -0,0 +1,74 @@
/**
* cssfilter
*
* @author 老雷<leizongmin@gmail.com>
*/
var _ = require('./util');
/**
* 解析style
*
* @param {String} css
* @param {Function} onAttr 处理属性的函数
* 参数格式 function (sourcePosition, position, name, value, source)
* @return {String}
*/
function parseStyle (css, onAttr) {
css = _.trimRight(css);
if (css[css.length - 1] !== ';') css += ';';
var cssLength = css.length;
var isParenthesisOpen = false;
var lastPos = 0;
var i = 0;
var retCSS = '';
function addNewAttr () {
// 如果没有正常的闭合圆括号,则直接忽略当前属性
if (!isParenthesisOpen) {
var source = _.trim(css.slice(lastPos, i));
var j = source.indexOf(':');
if (j !== -1) {
var name = _.trim(source.slice(0, j));
var value = _.trim(source.slice(j + 1));
// 必须有属性名称
if (name) {
var ret = onAttr(lastPos, retCSS.length, name, value, source);
if (ret) retCSS += ret + '; ';
}
}
}
lastPos = i + 1;
}
for (; i < cssLength; i++) {
var c = css[i];
if (c === '/' && css[i + 1] === '*') {
// 备注开始
var j = css.indexOf('*/', i + 2);
// 如果没有正常的备注结束,则后面的部分全部跳过
if (j === -1) break;
// 直接将当前位置调到备注结尾,并且初始化状态
i = j + 1;
lastPos = i + 1;
isParenthesisOpen = false;
} else if (c === '(') {
isParenthesisOpen = true;
} else if (c === ')') {
isParenthesisOpen = false;
} else if (c === ';') {
if (isParenthesisOpen) {
// 在圆括号里面,忽略
} else {
addNewAttr();
}
} else if (c === '\n') {
addNewAttr();
}
}
return _.trim(retCSS);
}
module.exports = parseStyle;

@ -0,0 +1,35 @@
module.exports = {
indexOf: function (arr, item) {
var i, j;
if (Array.prototype.indexOf) {
return arr.indexOf(item);
}
for (i = 0, j = arr.length; i < j; i++) {
if (arr[i] === item) {
return i;
}
}
return -1;
},
forEach: function (arr, fn, scope) {
var i, j;
if (Array.prototype.forEach) {
return arr.forEach(fn, scope);
}
for (i = 0, j = arr.length; i < j; i++) {
fn.call(scope, arr[i], i, arr);
}
},
trim: function (str) {
if (String.prototype.trim) {
return str.trim();
}
return str.replace(/(^\s*)|(\s*$)/g, '');
},
trimRight: function (str) {
if (String.prototype.trimRight) {
return str.trimRight();
}
return str.replace(/(\s*$)/g, '');
}
};

@ -0,0 +1,49 @@
{
"name": "cssfilter",
"version": "0.0.10",
"description": "Sanitize untrusted CSS with a configuration specified by a Whitelist. 根据白名单过滤CSS",
"main": "lib/index.js",
"files": [
"lib"
],
"scripts": {
"test": "istanbul cover _mocha --report lcovonly -- -t 5000 -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage",
"build": "./build",
"prepublish": "npm run test && npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/leizongmin/js-css-filter.git"
},
"keywords": [
"sanitization",
"xss",
"sanitize",
"sanitisation",
"input",
"security",
"escape",
"encode",
"filter",
"validator",
"html",
"css",
"injection",
"whitelist"
],
"author": "Zongmin Lei <leizongmin@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/leizongmin/js-css-filter/issues"
},
"homepage": "https://github.com/leizongmin/js-css-filter",
"devDependencies": {
"blanket": "^1.1.6",
"browserify": "^13.1.1",
"coveralls": "^2.11.14",
"istanbul": "^0.4.5",
"mocha": "^3.1.2",
"should": "^11.1.1",
"uglify-js": "^2.7.4"
}
}

21
node_modules/is-buffer/LICENSE generated vendored

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Feross Aboukhadijeh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

53
node_modules/is-buffer/README.md generated vendored

@ -0,0 +1,53 @@
# is-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
[travis-image]: https://img.shields.io/travis/feross/is-buffer/master.svg
[travis-url]: https://travis-ci.org/feross/is-buffer
[npm-image]: https://img.shields.io/npm/v/is-buffer.svg
[npm-url]: https://npmjs.org/package/is-buffer
[downloads-image]: https://img.shields.io/npm/dm/is-buffer.svg
[downloads-url]: https://npmjs.org/package/is-buffer
[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg
[standard-url]: https://standardjs.com
#### Determine if an object is a [`Buffer`](http://nodejs.org/api/buffer.html) (including the [browserify Buffer](https://github.com/feross/buffer))
[![saucelabs][saucelabs-image]][saucelabs-url]
[saucelabs-image]: https://saucelabs.com/browser-matrix/is-buffer.svg
[saucelabs-url]: https://saucelabs.com/u/is-buffer
## Why not use `Buffer.isBuffer`?
This module lets you check if an object is a `Buffer` without using `Buffer.isBuffer` (which includes the whole [buffer](https://github.com/feross/buffer) module in [browserify](http://browserify.org/)).
It's future-proof and works in node too!
## install
```bash
npm install is-buffer
```
## usage
```js
var isBuffer = require('is-buffer')
isBuffer(new Buffer(4)) // true
isBuffer(undefined) // false
isBuffer(null) // false
isBuffer('') // false
isBuffer(true) // false
isBuffer(false) // false
isBuffer(0) // false
isBuffer(1) // false
isBuffer(1.0) // false
isBuffer('string') // false
isBuffer({}) // false
isBuffer(function foo () {}) // false
```
## license
MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org).

21
node_modules/is-buffer/index.js generated vendored

@ -0,0 +1,21 @@
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}

@ -0,0 +1,51 @@
{
"name": "is-buffer",
"description": "Determine if an object is a Buffer",
"version": "1.1.6",
"author": {
"name": "Feross Aboukhadijeh",
"email": "feross@feross.org",
"url": "http://feross.org/"
},
"bugs": {
"url": "https://github.com/feross/is-buffer/issues"
},
"dependencies": {},
"devDependencies": {
"standard": "*",
"tape": "^4.0.0",
"zuul": "^3.0.0"
},
"keywords": [
"buffer",
"buffers",
"type",
"core buffer",
"browser buffer",
"browserify",
"typed array",
"uint32array",
"int16array",
"int32array",
"float32array",
"float64array",
"browser",
"arraybuffer",
"dataview"
],
"license": "MIT",
"main": "index.js",
"repository": {
"type": "git",
"url": "git://github.com/feross/is-buffer.git"
},
"scripts": {
"test": "standard && npm run test-node && npm run test-browser",
"test-browser": "zuul -- test/*.js",
"test-browser-local": "zuul --local -- test/*.js",
"test-node": "tape test/*.js"
},
"testling": {
"files": "test/*.js"
}
}

@ -0,0 +1,24 @@
var isBuffer = require('../')
var test = require('tape')
test('is-buffer', function (t) {
t.equal(isBuffer(Buffer.alloc(4)), true, 'new Buffer(4)')
t.equal(isBuffer(Buffer.allocUnsafeSlow(100)), true, 'SlowBuffer(100)')
t.equal(isBuffer(undefined), false, 'undefined')
t.equal(isBuffer(null), false, 'null')
t.equal(isBuffer(''), false, 'empty string')
t.equal(isBuffer(true), false, 'true')
t.equal(isBuffer(false), false, 'false')
t.equal(isBuffer(0), false, '0')
t.equal(isBuffer(1), false, '1')
t.equal(isBuffer(1.0), false, '1.0')
t.equal(isBuffer('string'), false, 'string')
t.equal(isBuffer({}), false, '{}')
t.equal(isBuffer([]), false, '[]')
t.equal(isBuffer(function foo () {}), false, 'function foo () {}')
t.equal(isBuffer({ isBuffer: null }), false, '{ isBuffer: null }')
t.equal(isBuffer({ isBuffer: function () { throw new Error() } }), false, '{ isBuffer: function () { throw new Error() } }')
t.end()
})

7
node_modules/md5/.travis.yml generated vendored

@ -0,0 +1,7 @@
language: node_js
node_js:
- 0.12
- 4
- 5
- 6
- 7

27
node_modules/md5/LICENSE generated vendored

@ -0,0 +1,27 @@
Copyright © 2011-2012, Paul Vorbach.
Copyright © 2009, Jeff Mott.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name Crypto-JS nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

111
node_modules/md5/README.md generated vendored

@ -0,0 +1,111 @@
# MD5
[![build status](https://secure.travis-ci.org/pvorb/node-md5.png)](http://travis-ci.org/pvorb/node-md5) [![info badge](https://img.shields.io/npm/dt/md5.svg)](http://npm-stat.com/charts.html?package=md5)
a JavaScript function for hashing messages with MD5.
node-md5 is being sponsored by the following tool; please help to support us by taking a look and signing up to a free trial
<a href="https://tracking.gitads.io/?repo=node-md5"><img src="https://images.gitads.io/node-md5" alt="GitAds"/></a>
## Installation
You can use this package on the server side as well as the client side.
### [Node.js](http://nodejs.org/):
~~~
npm install md5
~~~
## API
~~~ javascript
md5(message)
~~~
* `message` -- `String`, `Buffer`, `Array` or `Uint8Array`
* returns `String`
## Usage
~~~ javascript
var md5 = require('md5');
console.log(md5('message'));
~~~
This will print the following
~~~
78e731027d8fd50ed642340b7c9a63b3
~~~
It supports buffers, too
~~~ javascript
var fs = require('fs');
var md5 = require('md5');
fs.readFile('example.txt', function(err, buf) {
console.log(md5(buf));
});
~~~
## Versions
Before version 2.0.0 there were two packages called md5 on npm, one lowercase,
one uppercase (the one you're looking at). As of version 2.0.0, all new versions
of this module will go to lowercase [md5](https://www.npmjs.com/package/md5) on
npm. To use the correct version, users of this module will have to change their
code from `require('MD5')` to `require('md5')` if they want to use versions >=
2.0.0.
## Bugs and Issues
If you encounter any bugs or issues, feel free to open an issue at
[github](https://github.com/pvorb/node-md5/issues).
## Credits
This package is based on the work of Jeff Mott, who did a pure JS implementation
of the MD5 algorithm that was published by Ronald L. Rivest in 1991. I needed a
npm package of the algorithm, so I used Jeffs implementation for this package.
The original implementation can be found in the
[CryptoJS](http://code.google.com/p/crypto-js/) project.
## License
~~~
Copyright © 2011-2015, Paul Vorbach.
Copyright © 2009, Jeff Mott.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name Crypto-JS nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
~~~

48
node_modules/md5/demo/index.html generated vendored

@ -0,0 +1,48 @@
<input type="file" id="input">
<output id="output"></output>
<style>
output::before {
content: "output:";
}
output {
display: block;
padding: 1em;
margin: 1em;
outline: 1px solid gray;
white-space: pre-wrap;
}
</style>
<script src="../dist/md5.min.js"></script>
<script>
function readAsArrayBuffer(file){
return new Promise(function(resolve) {
var reader = new FileReader();
reader.readAsArrayBuffer(file)
reader.onload = function(e) {
resolve(e.target.result)
};
});
}
input.onchange = function(e) {
var file = input.files[0];
readAsArrayBuffer(file)
.then(buffer => {
console.log(buffer);
var now = performance.now();
var hash = MD5(buffer);
var after = performance.now() - now;
output.innerHTML = `
file: ${file.name}
size: ${file.size} bytes
type: ${file.type}
md5: ${hash}
duration: ${after.toFixed(2)} ms
`;
})
}
</script>

7
node_modules/md5/dist/md5.min.js generated vendored

File diff suppressed because one or more lines are too long

160
node_modules/md5/md5.js generated vendored

@ -0,0 +1,160 @@
(function(){
var crypt = require('crypt'),
utf8 = require('charenc').utf8,
isBuffer = require('is-buffer'),
bin = require('charenc').bin,
// The core
md5 = function (message, options) {
// Convert to byte array
if (message.constructor == String)
if (options && options.encoding === 'binary')
message = bin.stringToBytes(message);
else
message = utf8.stringToBytes(message);
else if (isBuffer(message))
message = Array.prototype.slice.call(message, 0);
else if (!Array.isArray(message) && message.constructor !== Uint8Array)
message = message.toString();
// else, assume byte array already
var m = crypt.bytesToWords(message),
l = message.length * 8,
a = 1732584193,
b = -271733879,
c = -1732584194,
d = 271733878;
// Swap endian
for (var i = 0; i < m.length; i++) {
m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF |
((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00;
}
// Padding
m[l >>> 5] |= 0x80 << (l % 32);
m[(((l + 64) >>> 9) << 4) + 14] = l;
// Method shortcuts
var FF = md5._ff,
GG = md5._gg,
HH = md5._hh,
II = md5._ii;
for (var i = 0; i < m.length; i += 16) {
var aa = a,
bb = b,
cc = c,
dd = d;
a = FF(a, b, c, d, m[i+ 0], 7, -680876936);
d = FF(d, a, b, c, m[i+ 1], 12, -389564586);
c = FF(c, d, a, b, m[i+ 2], 17, 606105819);
b = FF(b, c, d, a, m[i+ 3], 22, -1044525330);
a = FF(a, b, c, d, m[i+ 4], 7, -176418897);
d = FF(d, a, b, c, m[i+ 5], 12, 1200080426);
c = FF(c, d, a, b, m[i+ 6], 17, -1473231341);
b = FF(b, c, d, a, m[i+ 7], 22, -45705983);
a = FF(a, b, c, d, m[i+ 8], 7, 1770035416);
d = FF(d, a, b, c, m[i+ 9], 12, -1958414417);
c = FF(c, d, a, b, m[i+10], 17, -42063);
b = FF(b, c, d, a, m[i+11], 22, -1990404162);
a = FF(a, b, c, d, m[i+12], 7, 1804603682);
d = FF(d, a, b, c, m[i+13], 12, -40341101);
c = FF(c, d, a, b, m[i+14], 17, -1502002290);
b = FF(b, c, d, a, m[i+15], 22, 1236535329);
a = GG(a, b, c, d, m[i+ 1], 5, -165796510);
d = GG(d, a, b, c, m[i+ 6], 9, -1069501632);
c = GG(c, d, a, b, m[i+11], 14, 643717713);
b = GG(b, c, d, a, m[i+ 0], 20, -373897302);
a = GG(a, b, c, d, m[i+ 5], 5, -701558691);
d = GG(d, a, b, c, m[i+10], 9, 38016083);
c = GG(c, d, a, b, m[i+15], 14, -660478335);
b = GG(b, c, d, a, m[i+ 4], 20, -405537848);
a = GG(a, b, c, d, m[i+ 9], 5, 568446438);
d = GG(d, a, b, c, m[i+14], 9, -1019803690);
c = GG(c, d, a, b, m[i+ 3], 14, -187363961);
b = GG(b, c, d, a, m[i+ 8], 20, 1163531501);
a = GG(a, b, c, d, m[i+13], 5, -1444681467);
d = GG(d, a, b, c, m[i+ 2], 9, -51403784);
c = GG(c, d, a, b, m[i+ 7], 14, 1735328473);
b = GG(b, c, d, a, m[i+12], 20, -1926607734);
a = HH(a, b, c, d, m[i+ 5], 4, -378558);
d = HH(d, a, b, c, m[i+ 8], 11, -2022574463);
c = HH(c, d, a, b, m[i+11], 16, 1839030562);
b = HH(b, c, d, a, m[i+14], 23, -35309556);
a = HH(a, b, c, d, m[i+ 1], 4, -1530992060);
d = HH(d, a, b, c, m[i+ 4], 11, 1272893353);
c = HH(c, d, a, b, m[i+ 7], 16, -155497632);
b = HH(b, c, d, a, m[i+10], 23, -1094730640);
a = HH(a, b, c, d, m[i+13], 4, 681279174);
d = HH(d, a, b, c, m[i+ 0], 11, -358537222);
c = HH(c, d, a, b, m[i+ 3], 16, -722521979);
b = HH(b, c, d, a, m[i+ 6], 23, 76029189);
a = HH(a, b, c, d, m[i+ 9], 4, -640364487);
d = HH(d, a, b, c, m[i+12], 11, -421815835);
c = HH(c, d, a, b, m[i+15], 16, 530742520);
b = HH(b, c, d, a, m[i+ 2], 23, -995338651);
a = II(a, b, c, d, m[i+ 0], 6, -198630844);
d = II(d, a, b, c, m[i+ 7], 10, 1126891415);
c = II(c, d, a, b, m[i+14], 15, -1416354905);
b = II(b, c, d, a, m[i+ 5], 21, -57434055);
a = II(a, b, c, d, m[i+12], 6, 1700485571);
d = II(d, a, b, c, m[i+ 3], 10, -1894986606);
c = II(c, d, a, b, m[i+10], 15, -1051523);
b = II(b, c, d, a, m[i+ 1], 21, -2054922799);
a = II(a, b, c, d, m[i+ 8], 6, 1873313359);
d = II(d, a, b, c, m[i+15], 10, -30611744);
c = II(c, d, a, b, m[i+ 6], 15, -1560198380);
b = II(b, c, d, a, m[i+13], 21, 1309151649);
a = II(a, b, c, d, m[i+ 4], 6, -145523070);
d = II(d, a, b, c, m[i+11], 10, -1120210379);
c = II(c, d, a, b, m[i+ 2], 15, 718787259);
b = II(b, c, d, a, m[i+ 9], 21, -343485551);
a = (a + aa) >>> 0;
b = (b + bb) >>> 0;
c = (c + cc) >>> 0;
d = (d + dd) >>> 0;
}
return crypt.endian([a, b, c, d]);
};
// Auxiliary functions
md5._ff = function (a, b, c, d, x, s, t) {
var n = a + (b & c | ~b & d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._gg = function (a, b, c, d, x, s, t) {
var n = a + (b & d | c & ~d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._hh = function (a, b, c, d, x, s, t) {
var n = a + (b ^ c ^ d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._ii = function (a, b, c, d, x, s, t) {
var n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
// Package private blocksize
md5._blocksize = 16;
md5._digestsize = 16;
module.exports = function (message, options) {
if (message === undefined || message === null)
throw new Error('Illegal argument ' + message);
var digestbytes = crypt.wordsToBytes(md5(message, options));
return options && options.asBytes ? digestbytes :
options && options.asString ? bin.bytesToString(digestbytes) :
crypt.bytesToHex(digestbytes);
};
})();

38
node_modules/md5/package.json generated vendored

@ -0,0 +1,38 @@
{
"name": "md5",
"description": "js function for hashing messages with MD5",
"version": "2.3.0",
"author": "Paul Vorbach <paul@vorba.ch> (http://paul.vorba.ch)",
"contributors": [
"salba"
],
"tags": [
"md5",
"hash",
"encryption",
"message digest"
],
"repository": {
"type": "git",
"url": "git://github.com/pvorb/node-md5.git"
},
"bugs": {
"url": "https://github.com/pvorb/node-md5/issues"
},
"main": "md5.js",
"scripts": {
"test": "mocha",
"webpack": "webpack -p"
},
"dependencies": {
"charenc": "0.0.2",
"crypt": "0.0.2",
"is-buffer": "~1.1.6"
},
"devDependencies": {
"mocha": "~2.3.4",
"webpack": "~2.4.1"
},
"optionalDependencies": {},
"license": "BSD-3-Clause"
}

75
node_modules/md5/test.js generated vendored

@ -0,0 +1,75 @@
var md5 = require('./md5.js');
var assert = require('assert');
describe('md5', function () {
it('should throw an error for an undefined value', function() {
assert.throws(function() {
md5(undefined);
});
});
it('should allow the hashing of the string `undefined`', function() {
assert.equal('5e543256c480ac577d30f76f9120eb74', md5('undefined'));
});
it('should throw an error for `null`', function() {
assert.throws(function() {
md5(null);
});
});
it('should return the expected MD5 hash for "message"', function() {
assert.equal('78e731027d8fd50ed642340b7c9a63b3', md5('message'));
});
it('should not return the same hash for random numbers twice', function() {
var msg1 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();
var msg2 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();
if (msg1 !== msg2) {
assert.notEqual(md5(msg1), md5(msg2));
} else {
assert.equal(md5(msg1), md5(msg1));
}
});
it('should support Node.js Buffers', function() {
var buffer = new Buffer('message áßäöü', 'utf8');
assert.equal(md5(buffer), md5('message áßäöü'));
})
it('should be able to use a binary encoded string', function() {
var hash1 = md5('abc', { asString: true });
var hash2 = md5(hash1 + 'a', { asString: true, encoding : 'binary' });
var hash3 = md5(hash1 + 'a', { encoding : 'binary' });
assert.equal(hash3, '131f0ac52813044f5110e4aec638c169');
});
it('should support Uint8Array', function() {
// Polyfills
if (!Array.from) {
Array.from = function(src, fn) {
var result = new Array(src.length);
for (var i = 0; i < src.length; ++i)
result[i] = fn(src[i]);
return result;
};
}
if (!Uint8Array.from) {
Uint8Array.from = function(src) {
var result = new Uint8Array(src.length);
for (var i = 0; i < src.length; ++i)
result[i] = src[i];
return result;
};
}
var message = 'foobarbaz';
var u8arr = Uint8Array.from(
Array.from(message, function(c) { return c.charCodeAt(0); }));
var u8aHash = md5(u8arr);
assert.equal(u8aHash, md5(message));
});
});

@ -0,0 +1,13 @@
const {resolve} = require('path');
module.exports = {
entry: [
'./md5.js'
],
output: {
path: resolve('./dist'),
filename: 'md5.min.js',
libraryTarget: "var",
library: "MD5"
}
};

1
node_modules/qs/.eslintignore generated vendored

@ -0,0 +1 @@
dist

18
node_modules/qs/.npmignore generated vendored

@ -0,0 +1,18 @@
.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
config.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
coverage.*
lib-cov
complexity.md

8
node_modules/qs/.travis.yml generated vendored

@ -0,0 +1,8 @@
language: node_js
node_js:
- 0.10
- 4.0
- 4
sudo: false

104
node_modules/qs/CHANGELOG.md generated vendored

@ -0,0 +1,104 @@
## **5.2.1**
- [Fix] ensure `key[]=x&key[]&key[]=y` results in 3, not 2, values
## [**5.2.0**](https://github.com/ljharb/qs/issues?milestone=30&state=closed)
- [**#64**](https://github.com/ljharb/qs/issues/64) Add option to sort object keys in the query string
## [**5.1.0**](https://github.com/ljharb/qs/issues?milestone=29&state=closed)
- [**#117**](https://github.com/ljharb/qs/issues/117) make URI encoding stringified results optional
- [**#106**](https://github.com/ljharb/qs/issues/106) Add flag `skipNulls` to optionally skip null values in stringify
## [**5.0.0**](https://github.com/ljharb/qs/issues?milestone=28&state=closed)
- [**#114**](https://github.com/ljharb/qs/issues/114) default allowDots to false
- [**#100**](https://github.com/ljharb/qs/issues/100) include dist to npm
## [**4.0.0**](https://github.com/ljharb/qs/issues?milestone=26&state=closed)
- [**#98**](https://github.com/ljharb/qs/issues/98) make returning plain objects and allowing prototype overwriting properties optional
## [**3.1.0**](https://github.com/ljharb/qs/issues?milestone=24&state=closed)
- [**#89**](https://github.com/ljharb/qs/issues/89) Add option to disable "Transform dot notation to bracket notation"
## [**3.0.0**](https://github.com/ljharb/qs/issues?milestone=23&state=closed)
- [**#80**](https://github.com/ljharb/qs/issues/80) qs.parse silently drops properties
- [**#77**](https://github.com/ljharb/qs/issues/77) Perf boost
- [**#60**](https://github.com/ljharb/qs/issues/60) Add explicit option to disable array parsing
- [**#74**](https://github.com/ljharb/qs/issues/74) Bad parse when turning array into object
- [**#81**](https://github.com/ljharb/qs/issues/81) Add a `filter` option
- [**#68**](https://github.com/ljharb/qs/issues/68) Fixed issue with recursion and passing strings into objects.
- [**#66**](https://github.com/ljharb/qs/issues/66) Add mixed array and object dot notation support Closes: #47
- [**#76**](https://github.com/ljharb/qs/issues/76) RFC 3986
- [**#85**](https://github.com/ljharb/qs/issues/85) No equal sign
- [**#84**](https://github.com/ljharb/qs/issues/84) update license attribute
## [**2.4.1**](https://github.com/ljharb/qs/issues?milestone=20&state=closed)
- [**#73**](https://github.com/ljharb/qs/issues/73) Property 'hasOwnProperty' of object #<Object> is not a function
## [**2.4.0**](https://github.com/ljharb/qs/issues?milestone=19&state=closed)
- [**#70**](https://github.com/ljharb/qs/issues/70) Add arrayFormat option
## [**2.3.3**](https://github.com/ljharb/qs/issues?milestone=18&state=closed)
- [**#59**](https://github.com/ljharb/qs/issues/59) make sure array indexes are >= 0, closes #57
- [**#58**](https://github.com/ljharb/qs/issues/58) make qs usable for browser loader
## [**2.3.2**](https://github.com/ljharb/qs/issues?milestone=17&state=closed)
- [**#55**](https://github.com/ljharb/qs/issues/55) allow merging a string into an object
## [**2.3.1**](https://github.com/ljharb/qs/issues?milestone=16&state=closed)
- [**#52**](https://github.com/ljharb/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
## [**2.3.0**](https://github.com/ljharb/qs/issues?milestone=15&state=closed)
- [**#50**](https://github.com/ljharb/qs/issues/50) add option to omit array indices, closes #46
## [**2.2.5**](https://github.com/ljharb/qs/issues?milestone=14&state=closed)
- [**#39**](https://github.com/ljharb/qs/issues/39) Is there an alternative to Buffer.isBuffer?
- [**#49**](https://github.com/ljharb/qs/issues/49) refactor utils.merge, fixes #45
- [**#41**](https://github.com/ljharb/qs/issues/41) avoid browserifying Buffer, for #39
## [**2.2.4**](https://github.com/ljharb/qs/issues?milestone=13&state=closed)
- [**#38**](https://github.com/ljharb/qs/issues/38) how to handle object keys beginning with a number
## [**2.2.3**](https://github.com/ljharb/qs/issues?milestone=12&state=closed)
- [**#37**](https://github.com/ljharb/qs/issues/37) parser discards first empty value in array
- [**#36**](https://github.com/ljharb/qs/issues/36) Update to lab 4.x
## [**2.2.2**](https://github.com/ljharb/qs/issues?milestone=11&state=closed)
- [**#33**](https://github.com/ljharb/qs/issues/33) Error when plain object in a value
- [**#34**](https://github.com/ljharb/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
- [**#24**](https://github.com/ljharb/qs/issues/24) Changelog? Semver?
## [**2.2.1**](https://github.com/ljharb/qs/issues?milestone=10&state=closed)
- [**#32**](https://github.com/ljharb/qs/issues/32) account for circular references properly, closes #31
- [**#31**](https://github.com/ljharb/qs/issues/31) qs.parse stackoverflow on circular objects
## [**2.2.0**](https://github.com/ljharb/qs/issues?milestone=9&state=closed)
- [**#26**](https://github.com/ljharb/qs/issues/26) Don't use Buffer global if it's not present
- [**#30**](https://github.com/ljharb/qs/issues/30) Bug when merging non-object values into arrays
- [**#29**](https://github.com/ljharb/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
- [**#23**](https://github.com/ljharb/qs/issues/23) Ability to not limit parameters?
## [**2.1.0**](https://github.com/ljharb/qs/issues?milestone=8&state=closed)
- [**#22**](https://github.com/ljharb/qs/issues/22) Enable using a RegExp as delimiter
## [**2.0.0**](https://github.com/ljharb/qs/issues?milestone=7&state=closed)
- [**#18**](https://github.com/ljharb/qs/issues/18) Why is there arrayLimit?
- [**#20**](https://github.com/ljharb/qs/issues/20) Configurable parametersLimit
- [**#21**](https://github.com/ljharb/qs/issues/21) make all limits optional, for #18, for #20
## [**1.2.2**](https://github.com/ljharb/qs/issues?milestone=6&state=closed)
- [**#19**](https://github.com/ljharb/qs/issues/19) Don't overwrite null values
## [**1.2.1**](https://github.com/ljharb/qs/issues?milestone=5&state=closed)
- [**#16**](https://github.com/ljharb/qs/issues/16) ignore non-string delimiters
- [**#15**](https://github.com/ljharb/qs/issues/15) Close code block
## [**1.2.0**](https://github.com/ljharb/qs/issues?milestone=4&state=closed)
- [**#12**](https://github.com/ljharb/qs/issues/12) Add optional delim argument
- [**#13**](https://github.com/ljharb/qs/issues/13) fix #11: flattened keys in array are now correctly parsed
## [**1.1.0**](https://github.com/ljharb/qs/issues?milestone=3&state=closed)
- [**#7**](https://github.com/ljharb/qs/issues/7) Empty values of a POST array disappear after being submitted
- [**#9**](https://github.com/ljharb/qs/issues/9) Should not omit equals signs (=) when value is null
- [**#6**](https://github.com/ljharb/qs/issues/6) Minor grammar fix in README
## [**1.0.2**](https://github.com/ljharb/qs/issues?milestone=2&state=closed)
- [**#5**](https://github.com/ljharb/qs/issues/5) array holes incorrectly copied into object on large index

1
node_modules/qs/CONTRIBUTING.md generated vendored

@ -0,0 +1 @@
Please view our [hapijs contributing guide](https://github.com/hapijs/hapi/blob/master/CONTRIBUTING.md).

28
node_modules/qs/LICENSE generated vendored

@ -0,0 +1,28 @@
Copyright (c) 2014 Nathan LaFreniere and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *
The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors

331
node_modules/qs/README.md generated vendored

@ -0,0 +1,331 @@
# qs
A querystring parsing and stringifying library with some added security.
[![Build Status](https://secure.travis-ci.org/hapijs/qs.svg)](http://travis-ci.org/hapijs/qs)
Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf)
The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
## Usage
```javascript
var Qs = require('qs');
var obj = Qs.parse('a=c'); // { a: 'c' }
var str = Qs.stringify(obj); // 'a=c'
```
### Parsing Objects
```javascript
Qs.parse(string, [options]);
```
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
For example, the string `'foo[bar]=baz'` converts to:
```javascript
{
foo: {
bar: 'baz'
}
}
```
When using the `plainObjects` option the parsed value is returned as a plain object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
```javascript
Qs.parse('a.hasOwnProperty=b', { plainObjects: true });
// { a: { hasOwnProperty: 'b' } }
```
By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
```javascript
Qs.parse('a.hasOwnProperty=b', { allowPrototypes: true });
// { a: { hasOwnProperty: 'b' } }
```
URI encoded strings work too:
```javascript
Qs.parse('a%5Bb%5D=c');
// { a: { b: 'c' } }
```
You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
```javascript
{
foo: {
bar: {
baz: 'foobarbaz'
}
}
}
```
By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
```javascript
{
a: {
b: {
c: {
d: {
e: {
f: {
'[g][h][i]': 'j'
}
}
}
}
}
}
}
```
This depth can be overridden by passing a `depth` option to `Qs.parse(string, [options])`:
```javascript
Qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
// { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }
```
The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
```javascript
Qs.parse('a=b&c=d', { parameterLimit: 1 });
// { a: 'b' }
```
An optional delimiter can also be passed:
```javascript
Qs.parse('a=b;c=d', { delimiter: ';' });
// { a: 'b', c: 'd' }
```
Delimiters can be a regular expression too:
```javascript
Qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
// { a: 'b', c: 'd', e: 'f' }
```
Option `allowDots` can be used to enable dot notation:
```javascript
Qs.parse('a.b=c', { allowDots: true });
// { a: { b: 'c' } }
```
### Parsing Arrays
**qs** can also parse arrays using a similar `[]` notation:
```javascript
Qs.parse('a[]=b&a[]=c');
// { a: ['b', 'c'] }
```
You may specify an index as well:
```javascript
Qs.parse('a[1]=c&a[0]=b');
// { a: ['b', 'c'] }
```
Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
their order:
```javascript
Qs.parse('a[1]=b&a[15]=c');
// { a: ['b', 'c'] }
```
Note that an empty string is also a value, and will be preserved:
```javascript
Qs.parse('a[]=&a[]=b');
// { a: ['', 'b'] }
Qs.parse('a[0]=b&a[1]=&a[2]=c');
// { a: ['b', '', 'c'] }
```
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
instead be converted to an object with the index as the key:
```javascript
Qs.parse('a[100]=b');
// { a: { '100': 'b' } }
```
This limit can be overridden by passing an `arrayLimit` option:
```javascript
Qs.parse('a[1]=b', { arrayLimit: 0 });
// { a: { '1': 'b' } }
```
To disable array parsing entirely, set `parseArrays` to `false`.
```javascript
Qs.parse('a[]=b', { parseArrays: false });
// { a: { '0': 'b' } }
```
If you mix notations, **qs** will merge the two items into an object:
```javascript
Qs.parse('a[0]=b&a[b]=c');
// { a: { '0': 'b', b: 'c' } }
```
You can also create arrays of objects:
```javascript
Qs.parse('a[][b]=c');
// { a: [{ b: 'c' }] }
```
### Stringifying
```javascript
Qs.stringify(object, [options]);
```
When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
```javascript
Qs.stringify({ a: 'b' });
// 'a=b'
Qs.stringify({ a: { b: 'c' } });
// 'a%5Bb%5D=c'
```
This encoding can be disabled by setting the `encode` option to `false`:
```javascript
Qs.stringify({ a: { b: 'c' } }, { encode: false });
// 'a[b]=c'
```
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
When arrays are stringified, by default they are given explicit indices:
```javascript
Qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d'
```
You may override this by setting the `indices` option to `false`:
```javascript
Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
// 'a=b&a=c&a=d'
```
You may use the `arrayFormat` option to specify the format of the output array
```javascript
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
```
Empty strings and null values will omit the value, but the equals sign (=) remains in place:
```javascript
Qs.stringify({ a: '' });
// 'a='
```
Properties that are set to `undefined` will be omitted entirely:
```javascript
Qs.stringify({ a: null, b: undefined });
// 'a='
```
The delimiter may be overridden with stringify as well:
```javascript
Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' });
// 'a=b;c=d'
```
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
pass an array, it will be used to select properties and array indices for stringification:
```javascript
function filterFunc(prefix, value) {
if (prefix == 'b') {
// Return an `undefined` value to omit a property.
return;
}
if (prefix == 'e[f]') {
return value.getTime();
}
if (prefix == 'e[g][0]') {
return value * 2;
}
return value;
}
Qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc })
// 'a=b&c=d&e[f]=123&e[g][0]=4'
Qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] })
// 'a=b&e=f'
Qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] })
// 'a[0]=b&a[2]=d'
```
### Handling of `null` values
By default, `null` values are treated like empty strings:
```javascript
Qs.stringify({ a: null, b: '' });
// 'a=&b='
```
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
```javascript
Qs.parse('a&b=')
// { a: '', b: '' }
```
To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
values have no `=` sign:
```javascript
Qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
// 'a&b='
```
To parse values without `=` back to `null` use the `strictNullHandling` flag:
```javascript
Qs.parse('a&b=', { strictNullHandling: true });
// { a: null, b: '' }
```
To completely skip rendering keys with `null` values, use the `skipNulls` flag:
```javascript
qs.stringify({ a: 'b', c: null}, { skipNulls: true })
// 'a=b'
```

22
node_modules/qs/bower.json generated vendored

@ -0,0 +1,22 @@
{
"name": "qs",
"main": "dist/qs.js",
"version": "5.1.0",
"homepage": "https://github.com/hapijs/qs",
"authors": [
"Nathan LaFreniere <quitlahok@gmail.com>"
],
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"keywords": [
"querystring",
"qs"
],
"license": "BSD-3-Clause",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

15
node_modules/qs/component.json generated vendored

@ -0,0 +1,15 @@
{
"name": "qs",
"repository": "hapijs/qs",
"description": "query-string parser / stringifier with nesting support",
"version": "5.1.0",
"keywords": ["querystring", "query", "parser"],
"main": "lib/index.js",
"scripts": [
"lib/index.js",
"lib/parse.js",
"lib/stringify.js",
"lib/utils.js"
],
"license": "BSD-3-Clause"
}

551
node_modules/qs/dist/qs.js generated vendored

@ -0,0 +1,551 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Load modules
var Stringify = require('./stringify');
var Parse = require('./parse');
// Declare internals
var internals = {};
module.exports = {
stringify: Stringify,
parse: Parse
};
},{"./parse":2,"./stringify":3}],2:[function(require,module,exports){
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
depth: 5,
arrayLimit: 20,
parameterLimit: 1000,
strictNullHandling: false,
plainObjects: false,
allowPrototypes: false,
allowDots: false
};
internals.parseValues = function (str, options) {
var obj = {};
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
for (var i = 0, il = parts.length; i < il; ++i) {
var part = parts[i];
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
var key, val;
if (pos === -1) {
key = Utils.decode(part);
val = options.strictNullHandling ? null : '';
} else {
key = Utils.decode(part.slice(0, pos));
val = Utils.decode(part.slice(pos + 1));
}
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj[key] = [].concat(obj[key]).concat(val);
} else {
obj[key] = val;
}
}
return obj;
};
internals.parseObject = function (chain, val, options) {
if (!chain.length) {
return val;
}
var root = chain.shift();
var obj;
if (root === '[]') {
obj = [];
obj = obj.concat(internals.parseObject(chain, val, options));
}
else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
var index = parseInt(cleanRoot, 10);
var indexString = '' + index;
if (!isNaN(index) &&
root !== cleanRoot &&
indexString === cleanRoot &&
index >= 0 &&
(options.parseArrays &&
index <= options.arrayLimit)) {
obj = [];
obj[index] = internals.parseObject(chain, val, options);
}
else {
obj[cleanRoot] = internals.parseObject(chain, val, options);
}
}
return obj;
};
internals.parseKeys = function (key, val, options) {
if (!key) {
return;
}
// Transform dot notation to bracket notation
if (options.allowDots) {
key = key.replace(/\.([^\.\[]+)/g, '[$1]');
}
// The regex chunks
var parent = /^([^\[\]]*)/;
var child = /(\[[^\[\]]*\])/g;
// Get the parent
var segment = parent.exec(key);
// Stash the parent if it exists
var keys = [];
if (segment[1]) {
// If we aren't using plain objects, optionally prefix keys
// that would overwrite object prototype properties
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1])) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(segment[1]);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while ((segment = child.exec(key)) !== null && i < options.depth) {
++i;
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
if (!options.allowPrototypes) {
continue;
}
}
keys.push(segment[1]);
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return internals.parseObject(keys, val, options);
};
module.exports = function (str, options) {
options = options || {};
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
options.parseArrays = options.parseArrays !== false;
options.allowDots = typeof options.allowDots === 'boolean' ? options.allowDots : internals.allowDots;
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : internals.plainObjects;
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : internals.allowPrototypes;
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
if (str === '' ||
str === null ||
typeof str === 'undefined') {
return options.plainObjects ? Object.create(null) : {};
}
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
var obj = options.plainObjects ? Object.create(null) : {};
// Iterate over the keys and setup the new object
var keys = Object.keys(tempObj);
for (var i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
var newObj = internals.parseKeys(key, tempObj[key], options);
obj = Utils.merge(obj, newObj, options);
}
return Utils.compact(obj);
};
},{"./utils":4}],3:[function(require,module,exports){
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
arrayPrefixGenerators: {
brackets: function (prefix, key) {
return prefix + '[]';
},
indices: function (prefix, key) {
return prefix + '[' + key + ']';
},
repeat: function (prefix, key) {
return prefix;
}
},
strictNullHandling: false,
skipNulls: false,
encode: true
};
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) {
if (typeof filter === 'function') {
obj = filter(prefix, obj);
}
else if (Utils.isBuffer(obj)) {
obj = obj.toString();
}
else if (obj instanceof Date) {
obj = obj.toISOString();
}
else if (obj === null) {
if (strictNullHandling) {
return encode ? Utils.encode(prefix) : prefix;
}
obj = '';
}
if (typeof obj === 'string' ||
typeof obj === 'number' ||
typeof obj === 'boolean') {
if (encode) {
return [Utils.encode(prefix) + '=' + Utils.encode(obj)];
}
return [prefix + '=' + obj];
}
var values = [];
if (typeof obj === 'undefined') {
return values;
}
var objKeys;
if (Array.isArray(filter)) {
objKeys = filter;
} else {
var keys = Object.keys(obj);
objKeys = sort ? keys.sort(sort) : keys;
}
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
if (skipNulls &&
obj[key] === null) {
continue;
}
if (Array.isArray(obj)) {
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
}
else {
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
}
}
return values;
};
module.exports = function (obj, options) {
options = options || {};
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls;
var encode = typeof options.encode === 'boolean' ? options.encode : internals.encode;
var sort = typeof options.sort === 'function' ? options.sort : null;
var objKeys;
var filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
}
else if (Array.isArray(options.filter)) {
objKeys = filter = options.filter;
}
var keys = [];
if (typeof obj !== 'object' ||
obj === null) {
return '';
}
var arrayFormat;
if (options.arrayFormat in internals.arrayPrefixGenerators) {
arrayFormat = options.arrayFormat;
}
else if ('indices' in options) {
arrayFormat = options.indices ? 'indices' : 'repeat';
}
else {
arrayFormat = 'indices';
}
var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat];
if (!objKeys) {
objKeys = Object.keys(obj);
}
if (sort) {
objKeys.sort(sort);
}
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
if (skipNulls &&
obj[key] === null) {
continue;
}
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort));
}
return keys.join(delimiter);
};
},{"./utils":4}],4:[function(require,module,exports){
// Load modules
// Declare internals
var internals = {};
internals.hexTable = new Array(256);
for (var h = 0; h < 256; ++h) {
internals.hexTable[h] = '%' + ((h < 16 ? '0' : '') + h.toString(16)).toUpperCase();
}
exports.arrayToObject = function (source, options) {
var obj = options.plainObjects ? Object.create(null) : {};
for (var i = 0, il = source.length; i < il; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
exports.merge = function (target, source, options) {
if (!source) {
return target;
}
if (typeof source !== 'object') {
if (Array.isArray(target)) {
target.push(source);
}
else if (typeof target === 'object') {
target[source] = true;
}
else {
target = [target, source];
}
return target;
}
if (typeof target !== 'object') {
target = [target].concat(source);
return target;
}
if (Array.isArray(target) &&
!Array.isArray(source)) {
target = exports.arrayToObject(target, options);
}
var keys = Object.keys(source);
for (var k = 0, kl = keys.length; k < kl; ++k) {
var key = keys[k];
var value = source[key];
if (!Object.prototype.hasOwnProperty.call(target, key)) {
target[key] = value;
}
else {
target[key] = exports.merge(target[key], value, options);
}
}
return target;
};
exports.decode = function (str) {
try {
return decodeURIComponent(str.replace(/\+/g, ' '));
} catch (e) {
return str;
}
};
exports.encode = function (str) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str;
}
if (typeof str !== 'string') {
str = '' + str;
}
var out = '';
for (var i = 0, il = str.length; i < il; ++i) {
var c = str.charCodeAt(i);
if (c === 0x2D || // -
c === 0x2E || // .
c === 0x5F || // _
c === 0x7E || // ~
(c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5A) || // a-z
(c >= 0x61 && c <= 0x7A)) { // A-Z
out += str[i];
continue;
}
if (c < 0x80) {
out += internals.hexTable[c];
continue;
}
if (c < 0x800) {
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
++i;
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
}
return out;
};
exports.compact = function (obj, refs) {
if (typeof obj !== 'object' ||
obj === null) {
return obj;
}
refs = refs || [];
var lookup = refs.indexOf(obj);
if (lookup !== -1) {
return refs[lookup];
}
refs.push(obj);
if (Array.isArray(obj)) {
var compacted = [];
for (var i = 0, il = obj.length; i < il; ++i) {
if (typeof obj[i] !== 'undefined') {
compacted.push(obj[i]);
}
}
return compacted;
}
var keys = Object.keys(obj);
for (i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
obj[key] = exports.compact(obj[key], refs);
}
return obj;
};
exports.isRegExp = function (obj) {
return Object.prototype.toString.call(obj) === '[object RegExp]';
};
exports.isBuffer = function (obj) {
if (obj === null ||
typeof obj === 'undefined') {
return false;
}
return !!(obj.constructor &&
obj.constructor.isBuffer &&
obj.constructor.isBuffer(obj));
};
},{}]},{},[1])(1)
});

15
node_modules/qs/lib/index.js generated vendored

@ -0,0 +1,15 @@
// Load modules
var Stringify = require('./stringify');
var Parse = require('./parse');
// Declare internals
var internals = {};
module.exports = {
stringify: Stringify,
parse: Parse
};

182
node_modules/qs/lib/parse.js generated vendored

@ -0,0 +1,182 @@
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
depth: 5,
arrayLimit: 20,
parameterLimit: 1000,
strictNullHandling: false,
plainObjects: false,
allowPrototypes: false,
allowDots: false
};
internals.parseValues = function (str, options) {
var obj = {};
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
for (var i = 0, il = parts.length; i < il; ++i) {
var part = parts[i];
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
var key, val;
if (pos === -1) {
key = Utils.decode(part);
val = options.strictNullHandling ? null : '';
} else {
key = Utils.decode(part.slice(0, pos));
val = Utils.decode(part.slice(pos + 1));
}
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj[key] = [].concat(obj[key]).concat(val);
} else {
obj[key] = val;
}
}
return obj;
};
internals.parseObject = function (chain, val, options) {
if (!chain.length) {
return val;
}
var root = chain.shift();
var obj;
if (root === '[]') {
obj = [];
obj = obj.concat(internals.parseObject(chain, val, options));
}
else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
var index = parseInt(cleanRoot, 10);
var indexString = '' + index;
if (!isNaN(index) &&
root !== cleanRoot &&
indexString === cleanRoot &&
index >= 0 &&
(options.parseArrays &&
index <= options.arrayLimit)) {
obj = [];
obj[index] = internals.parseObject(chain, val, options);
}
else {
obj[cleanRoot] = internals.parseObject(chain, val, options);
}
}
return obj;
};
internals.parseKeys = function (key, val, options) {
if (!key) {
return;
}
// Transform dot notation to bracket notation
if (options.allowDots) {
key = key.replace(/\.([^\.\[]+)/g, '[$1]');
}
// The regex chunks
var parent = /^([^\[\]]*)/;
var child = /(\[[^\[\]]*\])/g;
// Get the parent
var segment = parent.exec(key);
// Stash the parent if it exists
var keys = [];
if (segment[1]) {
// If we aren't using plain objects, optionally prefix keys
// that would overwrite object prototype properties
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1])) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(segment[1]);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while ((segment = child.exec(key)) !== null && i < options.depth) {
++i;
if (!options.plainObjects &&
Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
if (!options.allowPrototypes) {
continue;
}
}
keys.push(segment[1]);
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return internals.parseObject(keys, val, options);
};
module.exports = function (str, options) {
options = options || {};
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
options.parseArrays = options.parseArrays !== false;
options.allowDots = typeof options.allowDots === 'boolean' ? options.allowDots : internals.allowDots;
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : internals.plainObjects;
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : internals.allowPrototypes;
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
if (str === '' ||
str === null ||
typeof str === 'undefined') {
return options.plainObjects ? Object.create(null) : {};
}
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
var obj = options.plainObjects ? Object.create(null) : {};
// Iterate over the keys and setup the new object
var keys = Object.keys(tempObj);
for (var i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
var newObj = internals.parseKeys(key, tempObj[key], options);
obj = Utils.merge(obj, newObj, options);
}
return Utils.compact(obj);
};

154
node_modules/qs/lib/stringify.js generated vendored

@ -0,0 +1,154 @@
// Load modules
var Utils = require('./utils');
// Declare internals
var internals = {
delimiter: '&',
arrayPrefixGenerators: {
brackets: function (prefix, key) {
return prefix + '[]';
},
indices: function (prefix, key) {
return prefix + '[' + key + ']';
},
repeat: function (prefix, key) {
return prefix;
}
},
strictNullHandling: false,
skipNulls: false,
encode: true
};
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) {
if (typeof filter === 'function') {
obj = filter(prefix, obj);
}
else if (Utils.isBuffer(obj)) {
obj = obj.toString();
}
else if (obj instanceof Date) {
obj = obj.toISOString();
}
else if (obj === null) {
if (strictNullHandling) {
return encode ? Utils.encode(prefix) : prefix;
}
obj = '';
}
if (typeof obj === 'string' ||
typeof obj === 'number' ||
typeof obj === 'boolean') {
if (encode) {
return [Utils.encode(prefix) + '=' + Utils.encode(obj)];
}
return [prefix + '=' + obj];
}
var values = [];
if (typeof obj === 'undefined') {
return values;
}
var objKeys;
if (Array.isArray(filter)) {
objKeys = filter;
} else {
var keys = Object.keys(obj);
objKeys = sort ? keys.sort(sort) : keys;
}
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
if (skipNulls &&
obj[key] === null) {
continue;
}
if (Array.isArray(obj)) {
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
}
else {
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter));
}
}
return values;
};
module.exports = function (obj, options) {
options = options || {};
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls;
var encode = typeof options.encode === 'boolean' ? options.encode : internals.encode;
var sort = typeof options.sort === 'function' ? options.sort : null;
var objKeys;
var filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
}
else if (Array.isArray(options.filter)) {
objKeys = filter = options.filter;
}
var keys = [];
if (typeof obj !== 'object' ||
obj === null) {
return '';
}
var arrayFormat;
if (options.arrayFormat in internals.arrayPrefixGenerators) {
arrayFormat = options.arrayFormat;
}
else if ('indices' in options) {
arrayFormat = options.indices ? 'indices' : 'repeat';
}
else {
arrayFormat = 'indices';
}
var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat];
if (!objKeys) {
objKeys = Object.keys(obj);
}
if (sort) {
objKeys.sort(sort);
}
for (var i = 0, il = objKeys.length; i < il; ++i) {
var key = objKeys[i];
if (skipNulls &&
obj[key] === null) {
continue;
}
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort));
}
return keys.join(delimiter);
};

190
node_modules/qs/lib/utils.js generated vendored

@ -0,0 +1,190 @@
// Load modules
// Declare internals
var internals = {};
internals.hexTable = new Array(256);
for (var h = 0; h < 256; ++h) {
internals.hexTable[h] = '%' + ((h < 16 ? '0' : '') + h.toString(16)).toUpperCase();
}
exports.arrayToObject = function (source, options) {
var obj = options.plainObjects ? Object.create(null) : {};
for (var i = 0, il = source.length; i < il; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
exports.merge = function (target, source, options) {
if (!source) {
return target;
}
if (typeof source !== 'object') {
if (Array.isArray(target)) {
target.push(source);
}
else if (typeof target === 'object') {
target[source] = true;
}
else {
target = [target, source];
}
return target;
}
if (typeof target !== 'object') {
target = [target].concat(source);
return target;
}
if (Array.isArray(target) &&
!Array.isArray(source)) {
target = exports.arrayToObject(target, options);
}
var keys = Object.keys(source);
for (var k = 0, kl = keys.length; k < kl; ++k) {
var key = keys[k];
var value = source[key];
if (!Object.prototype.hasOwnProperty.call(target, key)) {
target[key] = value;
}
else {
target[key] = exports.merge(target[key], value, options);
}
}
return target;
};
exports.decode = function (str) {
try {
return decodeURIComponent(str.replace(/\+/g, ' '));
} catch (e) {
return str;
}
};
exports.encode = function (str) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str;
}
if (typeof str !== 'string') {
str = '' + str;
}
var out = '';
for (var i = 0, il = str.length; i < il; ++i) {
var c = str.charCodeAt(i);
if (c === 0x2D || // -
c === 0x2E || // .
c === 0x5F || // _
c === 0x7E || // ~
(c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5A) || // a-z
(c >= 0x61 && c <= 0x7A)) { // A-Z
out += str[i];
continue;
}
if (c < 0x80) {
out += internals.hexTable[c];
continue;
}
if (c < 0x800) {
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
continue;
}
++i;
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF));
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)];
}
return out;
};
exports.compact = function (obj, refs) {
if (typeof obj !== 'object' ||
obj === null) {
return obj;
}
refs = refs || [];
var lookup = refs.indexOf(obj);
if (lookup !== -1) {
return refs[lookup];
}
refs.push(obj);
if (Array.isArray(obj)) {
var compacted = [];
for (var i = 0, il = obj.length; i < il; ++i) {
if (typeof obj[i] !== 'undefined') {
compacted.push(obj[i]);
}
}
return compacted;
}
var keys = Object.keys(obj);
for (i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
obj[key] = exports.compact(obj[key], refs);
}
return obj;
};
exports.isRegExp = function (obj) {
return Object.prototype.toString.call(obj) === '[object RegExp]';
};
exports.isBuffer = function (obj) {
if (obj === null ||
typeof obj === 'undefined') {
return false;
}
return !!(obj.constructor &&
obj.constructor.isBuffer &&
obj.constructor.isBuffer(obj));
};

29
node_modules/qs/package.json generated vendored

@ -0,0 +1,29 @@
{
"name": "qs",
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"homepage": "https://github.com/hapijs/qs",
"version": "5.2.1",
"repository": {
"type": "git",
"url": "https://github.com/hapijs/qs.git"
},
"main": "lib/index.js",
"keywords": [
"querystring",
"qs"
],
"engines": ">=0.10.40",
"dependencies": {},
"devDependencies": {
"browserify": "^10.2.1",
"code": "1.x.x",
"lab": "5.x.x"
},
"scripts": {
"test": "lab -a code -t 100 -L",
"test-tap": "lab -a code -r tap -o tests.tap",
"test-cov-html": "lab -a code -r html -o coverage.html",
"dist": "browserify --standalone Qs lib/index.js > dist/qs.js"
},
"license": "BSD-3-Clause"
}

483
node_modules/qs/test/parse.js generated vendored

@ -0,0 +1,483 @@
/* eslint no-extend-native:0 */
// Load modules
var Code = require('code');
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('parse()', function () {
it('parses a simple string', function (done) {
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' });
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' });
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } });
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } });
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } });
expect(Qs.parse('foo', { strictNullHandling: true })).to.deep.equal({ foo: null });
expect(Qs.parse('foo' )).to.deep.equal({ foo: '' });
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' });
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' });
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' });
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' });
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' });
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' });
expect(Qs.parse('foo=bar&baz', { strictNullHandling: true })).to.deep.equal({ foo: 'bar', baz: null });
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' });
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World'
});
done();
});
it('allows enabling dot notation', function (done) {
expect(Qs.parse('a.b=c')).to.deep.equal({ 'a.b': 'c' });
expect(Qs.parse('a.b=c', { allowDots: true })).to.deep.equal({ a: { b: 'c' } });
done();
});
it('parses a single nested string', function (done) {
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } });
done();
});
it('parses a double nested string', function (done) {
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } });
done();
});
it('defaults to a depth of 5', function (done) {
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } });
done();
});
it('only parses one level when depth = 1', function (done) {
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } });
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } });
done();
});
it('parses a simple array', function (done) {
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
done();
});
it('parses an explicit array', function (done) {
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] });
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
done();
});
it('parses a mix of simple and explicit arrays', function (done) {
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] });
done();
});
it('parses a nested array', function (done) {
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } });
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } });
done();
});
it('allows to specify array indices', function (done) {
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] });
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] });
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] });
done();
});
it('limits specific array indices to 20', function (done) {
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] });
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } });
done();
});
it('supports keys that begin with a number', function (done) {
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } });
done();
});
it('supports encoded = signs', function (done) {
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' });
done();
});
it('is ok with url encoded strings', function (done) {
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } });
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } });
done();
});
it('allows brackets in the value', function (done) {
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' });
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' });
done();
});
it('allows empty values', function (done) {
expect(Qs.parse('')).to.deep.equal({});
expect(Qs.parse(null)).to.deep.equal({});
expect(Qs.parse(undefined)).to.deep.equal({});
done();
});
it('transforms arrays to objects', function (done) {
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', c: true } });
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', '1': 'c', x: 'y' } });
done();
});
it('transforms arrays to objects (dot notation)', function (done) {
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: 'baz' } });
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } });
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] });
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] });
expect(Qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
expect(Qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true })).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true })).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
done();
});
it('can add keys to objects', function (done) {
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } });
done();
});
it('correctly prunes undefined values when converting an array to an object', function (done) {
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
done();
});
it('supports malformed uri characters', function (done) {
expect(Qs.parse('{%:%}', { strictNullHandling: true })).to.deep.equal({ '{%:%}': null });
expect(Qs.parse('{%:%}=')).to.deep.equal({ '{%:%}': '' });
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' });
done();
});
it('doesn\'t produce empty keys', function (done) {
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' });
done();
});
it('cannot access Object prototype', function (done) {
Qs.parse('constructor[prototype][bad]=bad');
Qs.parse('bad[constructor][prototype][bad]=bad');
expect(typeof Object.prototype.bad).to.equal('undefined');
done();
});
it('parses arrays of objects', function (done) {
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
done();
});
it('allows for empty strings in arrays', function (done) {
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] });
expect(Qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true, arrayLimit: 20 })).to.deep.equal({ a: ['b', null, 'c', ''] });
expect(Qs.parse('a[]=b&a[]&a[]=c&a[]=', { strictNullHandling: true, arrayLimit: 0 })).to.deep.equal({ a: ['b', null, 'c', ''] });
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true, arrayLimit: 20 })).to.deep.equal({ a: ['b', '', 'c', null] });
expect(Qs.parse('a[]=b&a[]=&a[]=c&a[]', { strictNullHandling: true, arrayLimit: 0 })).to.deep.equal({ a: ['b', '', 'c', null] });
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] });
done();
});
it('compacts sparse arrays', function (done) {
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] });
done();
});
it('parses semi-parsed strings', function (done) {
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } });
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } });
done();
});
it('parses buffers correctly', function (done) {
var b = new Buffer('test');
expect(Qs.parse({ a: b })).to.deep.equal({ a: b });
done();
});
it('continues parsing when no parent is found', function (done) {
expect(Qs.parse('[]=&a=b')).to.deep.equal({ '0': '', a: 'b' });
expect(Qs.parse('[]&a=b', { strictNullHandling: true })).to.deep.equal({ '0': null, a: 'b' });
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' });
done();
});
it('does not error when parsing a very long array', function (done) {
var str = 'a[]=a';
while (Buffer.byteLength(str) < 128 * 1024) {
str += '&' + str;
}
expect(function () {
Qs.parse(str);
}).to.not.throw();
done();
});
it('should not throw when a native prototype has an enumerable property', { parallel: false }, function (done) {
Object.prototype.crash = '';
Array.prototype.crash = '';
expect(Qs.parse.bind(null, 'a=b')).to.not.throw();
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' });
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw();
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
delete Object.prototype.crash;
delete Array.prototype.crash;
done();
});
it('parses a string with an alternative string delimiter', function (done) {
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('parses a string with an alternative RegExp delimiter', function (done) {
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('does not use non-splittable objects as delimiters', function (done) {
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('allows overriding parameter limit', function (done) {
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' });
done();
});
it('allows setting the parameter limit to Infinity', function (done) {
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('allows overriding array limit', function (done) {
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } });
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } });
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
done();
});
it('allows disabling array parsing', function (done) {
expect(Qs.parse('a[0]=b&a[1]=c', { parseArrays: false })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
done();
});
it('parses an object', function (done) {
var input = {
'user[name]': { 'pop[bob]': 3 },
'user[email]': null
};
var expected = {
'user': {
'name': { 'pop[bob]': 3 },
'email': null
}
};
var result = Qs.parse(input);
expect(result).to.deep.equal(expected);
done();
});
it('parses an object in dot notation', function (done) {
var input = {
'user.name': { 'pop[bob]': 3 },
'user.email.': null
};
var expected = {
'user': {
'name': { 'pop[bob]': 3 },
'email': null
}
};
var result = Qs.parse(input, { allowDots: true });
expect(result).to.deep.equal(expected);
done();
});
it('parses an object and not child values', function (done) {
var input = {
'user[name]': { 'pop[bob]': { 'test': 3 } },
'user[email]': null
};
var expected = {
'user': {
'name': { 'pop[bob]': { 'test': 3 } },
'email': null
}
};
var result = Qs.parse(input);
expect(result).to.deep.equal(expected);
done();
});
it('does not blow up when Buffer global is missing', function (done) {
var tempBuffer = global.Buffer;
delete global.Buffer;
var result = Qs.parse('a=b&c=d');
global.Buffer = tempBuffer;
expect(result).to.deep.equal({ a: 'b', c: 'd' });
done();
});
it('does not crash when parsing circular references', function (done) {
var a = {};
a.b = a;
var parsed;
expect(function () {
parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
}).to.not.throw();
expect(parsed).to.contain('foo');
expect(parsed.foo).to.contain('bar', 'baz');
expect(parsed.foo.bar).to.equal('baz');
expect(parsed.foo.baz).to.deep.equal(a);
done();
});
it('parses plain objects correctly', function (done) {
var a = Object.create(null);
a.b = 'c';
expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
var result = Qs.parse({ a: a });
expect(result).to.contain('a');
expect(result.a).to.deep.equal(a);
done();
});
it('parses dates correctly', function (done) {
var now = new Date();
expect(Qs.parse({ a: now })).to.deep.equal({ a: now });
done();
});
it('parses regular expressions correctly', function (done) {
var re = /^test$/;
expect(Qs.parse({ a: re })).to.deep.equal({ a: re });
done();
});
it('can allow overwriting prototype properties', function (done) {
expect(Qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true })).to.deep.equal({ a: { hasOwnProperty: 'b' } }, { prototype: false });
expect(Qs.parse('hasOwnProperty=b', { allowPrototypes: true })).to.deep.equal({ hasOwnProperty: 'b' }, { prototype: false });
done();
});
it('can return plain objects', function (done) {
var expected = Object.create(null);
expected.a = Object.create(null);
expected.a.b = 'c';
expected.a.hasOwnProperty = 'd';
expect(Qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true })).to.deep.equal(expected);
expect(Qs.parse(null, { plainObjects: true })).to.deep.equal(Object.create(null));
var expectedArray = Object.create(null);
expectedArray.a = Object.create(null);
expectedArray.a['0'] = 'b';
expectedArray.a.c = 'd';
expect(Qs.parse('a[]=b&a[c]=d', { plainObjects: true })).to.deep.equal(expectedArray);
done();
});
});

293
node_modules/qs/test/stringify.js generated vendored

@ -0,0 +1,293 @@
/* eslint no-extend-native:0 */
// Load modules
var Code = require('code');
var Lab = require('lab');
var Qs = require('../');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('stringify()', function () {
it('stringifies a querystring object', function (done) {
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
expect(Qs.stringify({ a: 1 })).to.equal('a=1');
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2');
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z');
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC');
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80');
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90');
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7');
done();
});
it('stringifies a nested object', function (done) {
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
expect(Qs.stringify({ a: { b: { c: { d: 'e' } } } })).to.equal('a%5Bb%5D%5Bc%5D%5Bd%5D=e');
done();
});
it('stringifies an array value', function (done) {
expect(Qs.stringify({ a: ['b', 'c', 'd'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
done();
});
it('omits nulls when asked', function (done) {
expect(Qs.stringify({ a: 'b', c: null }, { skipNulls: true })).to.equal('a=b');
done();
});
it('omits nested nulls when asked', function (done) {
expect(Qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true })).to.equal('a%5Bb%5D=c');
done();
});
it('omits array indices when asked', function (done) {
expect(Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false })).to.equal('a=b&a=c&a=d');
done();
});
it('stringifies a nested array value', function (done) {
expect(Qs.stringify({ a: { b: ['c', 'd'] } })).to.equal('a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
done();
});
it('stringifies an object inside an array', function (done) {
expect(Qs.stringify({ a: [{ b: 'c' }] })).to.equal('a%5B0%5D%5Bb%5D=c');
expect(Qs.stringify({ a: [{ b: { c: [1] } }] })).to.equal('a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
done();
});
it('does not omit object keys when indices = false', function (done) {
expect(Qs.stringify({ a: [{ b: 'c' }] }, { indices: false })).to.equal('a%5Bb%5D=c');
done();
});
it('uses indices notation for arrays when indices=true', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { indices: true })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses indices notation for arrays when no arrayFormat is specified', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses indices notation for arrays when no arrayFormat=indices', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
done();
});
it('uses repeat notation for arrays when no arrayFormat=repeat', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).to.equal('a=b&a=c');
done();
});
it('uses brackets notation for arrays when no arrayFormat=brackets', function (done) {
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).to.equal('a%5B%5D=b&a%5B%5D=c');
done();
});
it('stringifies a complicated object', function (done) {
expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e');
done();
});
it('stringifies an empty value', function (done) {
expect(Qs.stringify({ a: '' })).to.equal('a=');
expect(Qs.stringify({ a: null }, { strictNullHandling: true })).to.equal('a');
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b=');
expect(Qs.stringify({ a: null, b: '' }, { strictNullHandling: true })).to.equal('a&b=');
expect(Qs.stringify({ a: { b: '' } })).to.equal('a%5Bb%5D=');
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: true })).to.equal('a%5Bb%5D');
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: false })).to.equal('a%5Bb%5D=');
done();
});
it('stringifies an empty object', function (done) {
var obj = Object.create(null);
obj.a = 'b';
expect(Qs.stringify(obj)).to.equal('a=b');
done();
});
it('returns an empty string for invalid input', function (done) {
expect(Qs.stringify(undefined)).to.equal('');
expect(Qs.stringify(false)).to.equal('');
expect(Qs.stringify(null)).to.equal('');
expect(Qs.stringify('')).to.equal('');
done();
});
it('stringifies an object with an empty object as a child', function (done) {
var obj = {
a: Object.create(null)
};
obj.a.b = 'c';
expect(Qs.stringify(obj)).to.equal('a%5Bb%5D=c');
done();
});
it('drops keys with a value of undefined', function (done) {
expect(Qs.stringify({ a: undefined })).to.equal('');
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).to.equal('a%5Bc%5D');
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).to.equal('a%5Bc%5D=');
expect(Qs.stringify({ a: { b: undefined, c: '' } })).to.equal('a%5Bc%5D=');
done();
});
it('url encodes values', function (done) {
expect(Qs.stringify({ a: 'b c' })).to.equal('a=b%20c');
done();
});
it('stringifies a date', function (done) {
var now = new Date();
var str = 'a=' + encodeURIComponent(now.toISOString());
expect(Qs.stringify({ a: now })).to.equal(str);
done();
});
it('stringifies the weird object from qs', function (done) {
expect(Qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F');
done();
});
it('skips properties that are part of the object prototype', function (done) {
Object.prototype.crash = 'test';
expect(Qs.stringify({ a: 'b' })).to.equal('a=b');
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c');
delete Object.prototype.crash;
done();
});
it('stringifies boolean values', function (done) {
expect(Qs.stringify({ a: true })).to.equal('a=true');
expect(Qs.stringify({ a: { b: true } })).to.equal('a%5Bb%5D=true');
expect(Qs.stringify({ b: false })).to.equal('b=false');
expect(Qs.stringify({ b: { c: false } })).to.equal('b%5Bc%5D=false');
done();
});
it('stringifies buffer values', function (done) {
expect(Qs.stringify({ a: new Buffer('test') })).to.equal('a=test');
expect(Qs.stringify({ a: { b: new Buffer('test') } })).to.equal('a%5Bb%5D=test');
done();
});
it('stringifies an object using an alternative delimiter', function (done) {
expect(Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).to.equal('a=b;c=d');
done();
});
it('doesn\'t blow up when Buffer global is missing', function (done) {
var tempBuffer = global.Buffer;
delete global.Buffer;
var result = Qs.stringify({ a: 'b', c: 'd' });
global.Buffer = tempBuffer;
expect(result).to.equal('a=b&c=d');
done();
});
it('selects properties when filter=array', function (done) {
expect(Qs.stringify({ a: 'b' }, { filter: ['a'] })).to.equal('a=b');
expect(Qs.stringify({ a: 1 }, { filter: [] })).to.equal('');
expect(Qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).to.equal('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
done();
});
it('supports custom representations when filter=function', function (done) {
var calls = 0;
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
var filterFunc = function (prefix, value) {
calls++;
if (calls === 1) {
expect(prefix).to.be.empty();
expect(value).to.equal(obj);
}
else if (prefix === 'c') {
return;
}
else if (value instanceof Date) {
expect(prefix).to.equal('e[f]');
return value.getTime();
}
return value;
};
expect(Qs.stringify(obj, { filter: filterFunc })).to.equal('a=b&e%5Bf%5D=1257894000000');
expect(calls).to.equal(5);
done();
});
it('can disable uri encoding', function (done) {
expect(Qs.stringify({ a: 'b' }, { encode: false })).to.equal('a=b');
expect(Qs.stringify({ a: { b: 'c' } }, { encode: false })).to.equal('a[b]=c');
expect(Qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false })).to.equal('a=b&c');
done();
});
it('can sort the keys', function (done) {
var sort = function alphabeticalSort (a, b) {
return a.localeCompare(b);
};
expect(Qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort : sort })).to.equal('a=c&b=f&z=y');
expect(Qs.stringify({ a: 'c', z: { j: 'a', i:'b' }, b : 'f' }, { sort : sort })).to.equal('a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a');
done();
});
});

28
node_modules/qs/test/utils.js generated vendored

@ -0,0 +1,28 @@
// Load modules
var Code = require('code');
var Lab = require('lab');
var Utils = require('../lib/utils');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var expect = Code.expect;
var describe = lab.experiment;
var it = lab.test;
describe('merge()', function () {
it('can merge two objects with the same key', function (done) {
expect(Utils.merge({ a: 'b' }, { a: 'c' })).to.deep.equal({ a: ['b', 'c'] });
done();
});
});

23
node_modules/xss/LICENSE generated vendored

@ -0,0 +1,23 @@
Copyright (c) 2012-2018 Zongmin Lei(雷宗民) <leizongmin@gmail.com>
http://ucdok.com
The MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

508
node_modules/xss/README.md generated vendored

@ -0,0 +1,508 @@
[![NPM version][npm-image]][npm-url]
[![Node.js CI](https://github.com/leizongmin/js-xss/actions/workflows/nodejs.yml/badge.svg)](https://github.com/leizongmin/js-xss/actions/workflows/nodejs.yml)
[![Test coverage][coveralls-image]][coveralls-url]
[![David deps][david-image]][david-url]
[![node version][node-image]][node-url]
[![npm download][download-image]][download-url]
[![npm license][license-image]][download-url]
[npm-image]: https://img.shields.io/npm/v/xss.svg?style=flat-square
[npm-url]: https://npmjs.org/package/xss
[coveralls-image]: https://img.shields.io/coveralls/leizongmin/js-xss.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/leizongmin/js-xss?branch=master
[david-image]: https://img.shields.io/david/leizongmin/js-xss.svg?style=flat-square
[david-url]: https://david-dm.org/leizongmin/js-xss
[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square
[node-url]: http://nodejs.org/download/
[download-image]: https://img.shields.io/npm/dm/xss.svg?style=flat-square
[download-url]: https://npmjs.org/package/xss
[license-image]: https://img.shields.io/npm/l/xss.svg
# Sanitize untrusted HTML (to prevent XSS) with a configuration specified by a Whitelist.
[![Greenkeeper badge](https://badges.greenkeeper.io/leizongmin/js-xss.svg)](https://greenkeeper.io/)
![xss](https://nodei.co/npm/xss.png?downloads=true&stars=true)
---
`xss` is a module used to filter input from users to prevent XSS attacks.
([What is XSS attack?](http://en.wikipedia.org/wiki/Cross-site_scripting))
**Project Homepage:** http://jsxss.com
**Try Online:** http://jsxss.com/en/try.html
**[中文版文档](https://github.com/leizongmin/js-xss/blob/master/README.zh.md)**
---
## Features
- Specifies HTML tags and their attributes allowed with whitelist
- Handle any tags or attributes using custom function.
## Reference
- [XSS Filter Evasion Cheat Sheet](https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet)
- [Data URI scheme](http://en.wikipedia.org/wiki/Data_URI_scheme)
- [XSS with Data URI Scheme](http://hi.baidu.com/badzzzz/item/bdbafe83144619c199255f7b)
## Benchmark (for references only)
- the xss module: 22.53 MB/s
- `xss()` function from module `validator@0.3.7`: 6.9 MB/s
For test code please refer to `benchmark` directory.
## They are using xss module
- **nodeclub** - A Node.js bbs using MongoDB - https://github.com/cnodejs/nodeclub
- **cnpmjs.org** - Private npm registry and web for Enterprise - https://github.com/cnpm/cnpmjs.org
- **cocalc.com** - Collaborative Calculation and Data Science - https://cocalc.com
## Install
### NPM
```bash
npm install xss
```
### Bower
```bash
bower install xss
```
Or
```bash
bower install https://github.com/leizongmin/js-xss.git
```
## Usages
### On Node.js
```javascript
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
```
### On Browser
Shim mode (reference file `test/test.html`):
```html
<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>
<script>
// apply function filterXSS in the same way
var html = filterXSS('<script>alert("xss");</scr' + "ipt>");
alert(html);
</script>
```
AMD mode - shim:
```html
<script>
require.config({
baseUrl: "./",
paths: {
xss: "https://rawgit.com/leizongmin/js-xss/master/dist/xss.js",
},
shim: {
xss: { exports: "filterXSS" },
},
});
require(["xss"], function (xss) {
var html = xss('<script>alert("xss");</scr' + "ipt>");
alert(html);
});
</script>
```
**Notes: please don't use the URL https://rawgit.com/leizongmin/js-xss/master/dist/xss.js in production environment.**
## Command Line Tool
### Process File
You can use the xss command line tool to process a file. Usage:
```bash
xss -i <input_file> -o <output_file>
```
Example:
```bash
xss -i origin.html -o target.html
```
### Active Test
Run the following command, them you can type HTML
code in the command-line, and check the filtered output:
```bash
xss -t
```
For more details, please run `$ xss -h` to see it.
## Custom filter rules
When using the `xss()` function, the second parameter could be used to specify
custom rules:
```javascript
options = {}; // Custom rules
html = xss('<script>alert("xss");</script>', options);
```
To avoid passing `options` every time, you can also do it in a faster way by
creating a `FilterXSS` instance:
```javascript
options = {}; // Custom rules
myxss = new xss.FilterXSS(options);
// then apply myxss.process()
html = myxss.process('<script>alert("xss");</script>');
```
Details of parameters in `options` would be described below.
### Whitelist
By specifying a `whiteList`, e.g. `{ 'tagName': [ 'attr-1', 'attr-2' ] }`. Tags
and attributes not in the whitelist would be filter out. For example:
```javascript
// only tag a and its attributes href, title, target are allowed
var options = {
whiteList: {
a: ["href", "title", "target"],
},
};
// With the configuration specified above, the following HTML:
// <a href="#" onclick="hello()"><i>Hello</i></a>
// would become:
// <a href="#">&lt;i&gt;Hello&lt;/i&gt;</a>
```
For the default whitelist, please refer `xss.whiteList`.
`allowList` is also supported, and has the same function as `whiteList`.
### Customize the handler function for matched tags
By specifying the handler function with `onTag`:
```javascript
function onTag(tag, html, options) {
// tag is the name of current tag, e.g. 'a' for tag <a>
// html is the HTML of this tag, e.g. '<a>' for tag <a>
// options is some addition informations:
// isWhite boolean, whether the tag is in whitelist
// isClosing boolean, whether the tag is a closing tag, e.g. true for </a>
// position integer, the position of the tag in output result
// sourcePosition integer, the position of the tag in input HTML source
// If a string is returned, the current tag would be replaced with the string
// If return nothing, the default measure would be taken:
// If in whitelist: filter attributes using onTagAttr, as described below
// If not in whitelist: handle by onIgnoreTag, as described below
}
```
### Customize the handler function for attributes of matched tags
By specifying the handler function with `onTagAttr`:
```javascript
function onTagAttr(tag, name, value, isWhiteAttr) {
// tag is the name of current tag, e.g. 'a' for tag <a>
// name is the name of current attribute, e.g. 'href' for href="#"
// isWhiteAttr whether the attribute is in whitelist
// If a string is returned, the attribute would be replaced with the string
// If return nothing, the default measure would be taken:
// If in whitelist: filter the value using safeAttrValue as described below
// If not in whitelist: handle by onIgnoreTagAttr, as described below
}
```
### Customize the handler function for tags not in the whitelist
By specifying the handler function with `onIgnoreTag`:
```javascript
function onIgnoreTag(tag, html, options) {
// Parameters are the same with onTag
// If a string is returned, the tag would be replaced with the string
// If return nothing, the default measure would be taken (specifies using
// escape, as described below)
}
```
### Customize the handler function for attributes not in the whitelist
By specifying the handler function with `onIgnoreTagAttr`:
```javascript
function onIgnoreTagAttr(tag, name, value, isWhiteAttr) {
// Parameters are the same with onTagAttr
// If a string is returned, the value would be replaced with this string
// If return nothing, then keep default (remove the attribute)
}
```
### Customize escaping function for HTML
By specifying the handler function with `escapeHtml`. Following is the default
function **(Modification is not recommended)**:
```javascript
function escapeHtml(html) {
return html.replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
```
### Customize escaping function for value of attributes
By specifying the handler function with `safeAttrValue`:
```javascript
function safeAttrValue(tag, name, value) {
// Parameters are the same with onTagAttr (without options)
// Return the value as a string
}
```
### Customize CSS filter
If you allow the attribute `style`, the value will be processed by [cssfilter](https://github.com/leizongmin/js-css-filter) module. The cssfilter module includes a default css whitelist. You can specify the options for cssfilter module like this:
```javascript
myxss = new xss.FilterXSS({
css: {
whiteList: {
position: /^fixed|relative$/,
top: true,
left: true,
},
},
});
html = myxss.process('<script>alert("xss");</script>');
```
If you don't want to filter out the `style` content, just specify `false` to the `css` option:
```javascript
myxss = new xss.FilterXSS({
css: false,
});
```
For more help, please see https://github.com/leizongmin/js-css-filter
### Quick Start
#### Filter out tags not in the whitelist
By using `stripIgnoreTag` parameter:
- `true` filter out tags not in the whitelist
- `false`: by default: escape the tag using configured `escape` function
Example:
If `stripIgnoreTag = true` is set, the following code:
```html
code:
<script>
alert(/xss/);
</script>
```
would output filtered:
```html
code:alert(/xss/);
```
#### Filter out tags and tag bodies not in the whitelist
By using `stripIgnoreTagBody` parameter:
- `false|null|undefined` by default: do nothing
- `'*'|true`: filter out all tags not in the whitelist
- `['tag1', 'tag2']`: filter out only specified tags not in the whitelist
Example:
If `stripIgnoreTagBody = ['script']` is set, the following code:
```html
code:
<script>
alert(/xss/);
</script>
```
would output filtered:
```html
code:
```
#### Filter out HTML comments
By using `allowCommentTag` parameter:
- `true`: do nothing
- `false` by default: filter out HTML comments
Example:
If `allowCommentTag = false` is set, the following code:
```html
code:<!-- something -->
END
```
would output filtered:
```html
code: END
```
## Examples
### Allow attributes of whitelist tags start with `data-`
```javascript
var source = '<div a="1" b="2" data-a="3" data-b="4">hello</div>';
var html = xss(source, {
onIgnoreTagAttr: function (tag, name, value, isWhiteAttr) {
if (name.substr(0, 5) === "data-") {
// escape its value using built-in escapeAttrValue function
return name + '="' + xss.escapeAttrValue(value) + '"';
}
},
});
console.log("%s\nconvert to:\n%s", source, html);
```
Result:
```html
<div a="1" b="2" data-a="3" data-b="4">hello</div>
convert to:
<div data-a="3" data-b="4">hello</div>
```
### Allow tags start with `x-`
```javascript
var source = "<x><x-1>he<x-2 checked></x-2>wwww</x-1><a>";
var html = xss(source, {
onIgnoreTag: function (tag, html, options) {
if (tag.substr(0, 2) === "x-") {
// do not filter its attributes
return html;
}
},
});
console.log("%s\nconvert to:\n%s", source, html);
```
Result:
```html
<x
><x-1>he<x-2 checked></x-2>wwww</x-1
><a>
convert to: &lt;x&gt;<x-1>he<x-2 checked></x-2>wwww</x-1><a></a></a
></x>
```
### Parse images in HTML
```javascript
var source =
'<img src="img1">a<img src="img2">b<img src="img3">c<img src="img4">d';
var list = [];
var html = xss(source, {
onTagAttr: function (tag, name, value, isWhiteAttr) {
if (tag === "img" && name === "src") {
// Use the built-in friendlyAttrValue function to escape attribute
// values. It supports converting entity tags such as &lt; to printable
// characters such as <
list.push(xss.friendlyAttrValue(value));
}
// Return nothing, means keep the default handling measure
},
});
console.log("image list:\n%s", list.join(", "));
```
Result:
```html
image list: img1, img2, img3, img4
```
### Filter out HTML tags (keeps only plain text)
```javascript
var source = "<strong>hello</strong><script>alert(/xss/);</script>end";
var html = xss(source, {
whiteList: {}, // empty, means filter out all tags
stripIgnoreTag: true, // filter out all HTML not in the whitelist
stripIgnoreTagBody: ["script"], // the script tag is a special case, we need
// to filter out its content
});
console.log("text: %s", html);
```
Result:
```html
text: helloend
```
## License
```text
Copyright (c) 2012-2018 Zongmin Lei(雷宗民) <leizongmin@gmail.com>
http://ucdok.com
The MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```

491
node_modules/xss/README.zh.md generated vendored

@ -0,0 +1,491 @@
[![NPM version][npm-image]][npm-url]
[![Node.js CI](https://github.com/leizongmin/js-xss/actions/workflows/nodejs.yml/badge.svg)](https://github.com/leizongmin/js-xss/actions/workflows/nodejs.yml)
[![Test coverage][coveralls-image]][coveralls-url]
[![David deps][david-image]][david-url]
[![node version][node-image]][node-url]
[![npm download][download-image]][download-url]
[![npm license][license-image]][download-url]
[npm-image]: https://img.shields.io/npm/v/xss.svg?style=flat-square
[npm-url]: https://npmjs.org/package/xss
[coveralls-image]: https://img.shields.io/coveralls/leizongmin/js-xss.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/leizongmin/js-xss?branch=master
[david-image]: https://img.shields.io/david/leizongmin/js-xss.svg?style=flat-square
[david-url]: https://david-dm.org/leizongmin/js-xss
[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square
[node-url]: http://nodejs.org/download/
[download-image]: https://img.shields.io/npm/dm/xss.svg?style=flat-square
[download-url]: https://npmjs.org/package/xss
[license-image]: https://img.shields.io/npm/l/xss.svg
# 根据白名单过滤 HTML(防止 XSS 攻击)
![xss](https://nodei.co/npm/xss.png?downloads=true&stars=true)
---
`xss`是一个用于对用户输入的内容进行过滤,以避免遭受 XSS 攻击的模块([什么是 XSS 攻击?](http://baike.baidu.com/view/2161269.htm))。主要用于论坛、博客、网上商店等等一些可允许用户录入页面排版、格式控制相关的 HTML 的场景,`xss`模块通过白名单来控制允许的标签及相关的标签属性,另外还提供了一系列的接口以便用户扩展,比其他同类模块更为灵活。
**项目主页:** http://jsxss.com
**在线测试:** http://jsxss.com/zh/try.html
---
## 特性
- 白名单控制允许的 HTML 标签及各标签的属性
- 通过自定义处理函数,可对任意标签及其属性进行处理
## 参考资料
- [XSS 与字符编码的那些事儿 ---科普文](http://drops.wooyun.org/tips/689)
- [腾讯实例教程:那些年我们一起学 XSS](http://www.wooyun.org/whitehats/%E5%BF%83%E4%BC%A4%E7%9A%84%E7%98%A6%E5%AD%90)
- [mXSS 攻击的成因及常见种类](http://drops.wooyun.org/tips/956)
- [XSS Filter Evasion Cheat Sheet](https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet)
- [Data URI scheme](http://en.wikipedia.org/wiki/Data_URI_scheme)
- [XSS with Data URI Scheme](http://hi.baidu.com/badzzzz/item/bdbafe83144619c199255f7b)
## 性能(仅作参考)
- xss 模块22.53 MB/s
- validator@0.3.7 模块的 xss()函数6.9 MB/s
测试代码参考 benchmark 目录
## 安装
### NPM
```bash
npm install xss
```
### Bower
```bash
bower install xss
```
或者
```bash
bower install https://github.com/leizongmin/js-xss.git
```
## 使用方法
### 在 Node.js 中使用
```javascript
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
```
### 在浏览器端使用
Shim 模式(参考文件 `test/test.html`:
```html
<script src="https://rawgit.com/leizongmin/js-xss/master/dist/xss.js"></script>
<script>
// 使用函数名 filterXSS用法一样
var html = filterXSS('<script>alert("xss");</scr' + "ipt>");
alert(html);
</script>
```
AMD 模式(参考文件 `test/test_amd.html`:
```html
<script>
require.config({
baseUrl: "./",
paths: {
xss: "https://rawgit.com/leizongmin/js-xss/master/dist/xss.js",
},
shim: {
xss: { exports: "filterXSS" },
},
});
require(["xss"], function (xss) {
var html = xss('<script>alert("xss");</scr' + "ipt>");
alert(html);
});
</script>
```
**说明:请勿将 URL https://rawgit.com/leizongmin/js-xss/master/dist/xss.js 用于生产环境。**
### 使用命令行工具来对文件进行 XSS 处理
### 处理文件
可通过内置的 `xss` 命令来对输入的文件进行 XSS 处理。使用方法:
```bash
xss -i <源文件> -o <目标文件>
```
例:
```bash
xss -i origin.html -o target.html
```
### 在线测试
执行以下命令,可在命令行中输入 HTML 代码,并看到过滤后的代码:
```bash
xss -t
```
详细命令行参数说明,请输入 `$ xss -h` 来查看。
## 自定义过滤规则
在调用 `xss()` 函数进行过滤时,可通过第二个参数来设置自定义规则:
```javascript
options = {}; // 自定义规则
html = xss('<script>alert("xss");</script>', options);
```
如果不想每次都传入一个 `options` 参数,可以创建一个 `FilterXSS` 实例(使用这种方法速度更快):
```
options = {}; // 自定义规则
myxss = new xss.FilterXSS(options);
// 以后直接调用 myxss.process() 来处理即可
html = myxss.process('<script>alert("xss");</script>');
```
`options` 参数的详细说明见下文。
### 白名单
通过 `whiteList` 来指定,格式为:`{'标签名': ['属性1', '属性2']}`。不在白名单上的标签将被过滤,不在白名单上的属性也会被过滤。以下是示例:
```javascript
// 只允许a标签该标签只允许href, title, target这三个属性
var options = {
whiteList: {
a: ["href", "title", "target"],
},
};
// 使用以上配置后下面的HTML
// <a href="#" onclick="hello()"><i>大家好</i></a>
// 将被过滤为
// <a href="#">大家好</a>
```
默认白名单参考 `xss.whiteList`
### 自定义匹配到标签时的处理方法
通过 `onTag` 来指定相应的处理函数。以下是详细说明:
```javascript
function onTag(tag, html, options) {
// tag是当前的标签名称比如<a>标签则tag的值是'a'
// html是该标签的HTML比如<a>标签则html的值是'<a>'
// options是一些附加的信息具体如下
// isWhite boolean类型表示该标签是否在白名单上
// isClosing boolean类型表示该标签是否为闭合标签比如</a>时为true
// position integer类型表示当前标签在输出的结果中的起始位置
// sourcePosition integer类型表示当前标签在原HTML中的起始位置
// 如果返回一个字符串,则当前标签将被替换为该字符串
// 如果不返回任何值,则使用默认的处理方法:
// 在白名单上: 通过onTagAttr来过滤属性详见下文
// 不在白名单上通过onIgnoreTag指定详见下文
}
```
### 自定义匹配到标签的属性时的处理方法
通过 `onTagAttr` 来指定相应的处理函数。以下是详细说明:
```javascript
function onTagAttr(tag, name, value, isWhiteAttr) {
// tag是当前的标签名称比如<a>标签则tag的值是'a'
// name是当前属性的名称比如href="#"则name的值是'href'
// value是当前属性的值比如href="#"则value的值是'#'
// isWhiteAttr是否为白名单上的属性
// 如果返回一个字符串,则当前属性值将被替换为该字符串
// 如果不返回任何值,则使用默认的处理方法
// 在白名单上: 调用safeAttrValue来过滤属性值并输出该属性详见下文
// 不在白名单上通过onIgnoreTagAttr指定详见下文
}
```
### 自定义匹配到不在白名单上的标签时的处理方法
通过 `onIgnoreTag` 来指定相应的处理函数。以下是详细说明:
```javascript
function onIgnoreTag(tag, html, options) {
// 参数说明与onTag相同
// 如果返回一个字符串,则当前标签将被替换为该字符串
// 如果不返回任何值则使用默认的处理方法通过escape指定详见下文
}
```
### 自定义匹配到不在白名单上的属性时的处理方法
通过 `onIgnoreTagAttr` 来指定相应的处理函数。以下是详细说明:
```javascript
function onIgnoreTagAttr(tag, name, value, isWhiteAttr) {
// 参数说明与onTagAttr相同
// 如果返回一个字符串,则当前属性值将被替换为该字符串
// 如果不返回任何值,则使用默认的处理方法(删除该属)
}
```
### 自定义 HTML 转义函数
通过 `escapeHtml` 来指定相应的处理函数。以下是默认代码 **(不建议修改)**
```javascript
function escapeHtml(html) {
return html.replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
```
### 自定义标签属性值的转义函数
通过 `safeAttrValue` 来指定相应的处理函数。以下是详细说明:
```javascript
function safeAttrValue(tag, name, value) {
// 参数说明与onTagAttr相同没有options参数
// 返回一个字符串表示该属性值
}
```
### 自定义 CSS 过滤器
如果配置中允许了标签的 `style` 属性,则它的值会通过[cssfilter](https://github.com/leizongmin/js-css-filter) 模块处理。
`cssfilter` 模块包含了一个默认的 CSS 白名单,你可以通过以下的方式配置:
```javascript
myxss = new xss.FilterXSS({
css: {
whiteList: {
position: /^fixed|relative$/,
top: true,
left: true,
},
},
});
html = myxss.process('<script>alert("xss");</script>');
```
如果不想使用 CSS 过滤器来处理 `style` 属性的内容,可指定 `css` 选项的值为 `false`
```javascript
myxss = new xss.FilterXSS({
css: false,
});
```
要获取更多的帮助信息可看这里https://github.com/leizongmin/js-css-filter
### 快捷配置
#### 去掉不在白名单上的标签
通过 `stripIgnoreTag` 来设置:
- `true`:去掉不在白名单上的标签
- `false`:(默认),使用配置的`escape`函数对该标签进行转义
示例:
当设置 `stripIgnoreTag = true`时,以下代码
```html
code:
<script>
alert(/xss/);
</script>
```
过滤后将输出
```html
code:alert(/xss/);
```
#### 去掉不在白名单上的标签及标签体
通过 `stripIgnoreTagBody` 来设置:
- `false|null|undefined`:(默认),不特殊处理
- `'*'|true`:去掉所有不在白名单上的标签
- `['tag1', 'tag2']`:仅去掉指定的不在白名单上的标签
示例:
当设置 `stripIgnoreTagBody = ['script']`时,以下代码
```html
code:
<script>
alert(/xss/);
</script>
```
过滤后将输出
```html
code:
```
#### 去掉 HTML 备注
通过 `allowCommentTag` 来设置:
- `true`:不处理
- `false`:(默认),自动去掉 HTML 中的备注
示例:
当设置 `allowCommentTag = false` 时,以下代码
```html
code:<!-- something -->
END
```
过滤后将输出
```html
code: END
```
## 应用实例
### 允许标签以 data-开头的属性
```javascript
var source = '<div a="1" b="2" data-a="3" data-b="4">hello</div>';
var html = xss(source, {
onIgnoreTagAttr: function (tag, name, value, isWhiteAttr) {
if (name.substr(0, 5) === "data-") {
// 通过内置的escapeAttrValue函数来对属性值进行转义
return name + '="' + xss.escapeAttrValue(value) + '"';
}
},
});
console.log("%s\nconvert to:\n%s", source, html);
```
运行结果:
```html
<div a="1" b="2" data-a="3" data-b="4">hello</div>
convert to:
<div data-a="3" data-b="4">hello</div>
```
### 允许名称以 x-开头的标签
```javascript
var source = "<x><x-1>he<x-2 checked></x-2>wwww</x-1><a>";
var html = xss(source, {
onIgnoreTag: function (tag, html, options) {
if (tag.substr(0, 2) === "x-") {
// 不对其属性列表进行过滤
return html;
}
},
});
console.log("%s\nconvert to:\n%s", source, html);
```
运行结果:
```html
<x
><x-1>he<x-2 checked></x-2>wwww</x-1
><a>
convert to: &lt;x&gt;<x-1>he<x-2 checked></x-2>wwww</x-1><a></a></a
></x>
```
### 分析 HTML 代码中的图片列表
```javascript
var source =
'<img src="img1">a<img src="img2">b<img src="img3">c<img src="img4">d';
var list = [];
var html = xss(source, {
onTagAttr: function (tag, name, value, isWhiteAttr) {
if (tag === "img" && name === "src") {
// 使用内置的friendlyAttrValue函数来对属性值进行转义可将&lt;这类的实体标记转换成打印字符<
list.push(xss.friendlyAttrValue(value));
}
// 不返回任何值,表示还是按照默认的方法处理
},
});
console.log("image list:\n%s", list.join(", "));
```
运行结果:
```html
image list: img1, img2, img3, img4
```
### 去除 HTML 标签(只保留文本内容)
```javascript
var source = "<strong>hello</strong><script>alert(/xss/);</script>end";
var html = xss(source, {
whiteList: {}, // 白名单为空,表示过滤所有标签
stripIgnoreTag: true, // 过滤所有非白名单标签的HTML
stripIgnoreTagBody: ["script"], // script标签较特殊需要过滤标签中间的内容
});
console.log("text: %s", html);
```
运行结果:
```html
text: helloend
```
## 授权协议
```text
Copyright (c) 2012-2018 Zongmin Lei(雷宗民) <leizongmin@gmail.com>
http://ucdok.com
The MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```

67
node_modules/xss/bin/xss generated vendored

@ -0,0 +1,67 @@
#!/usr/bin/env node
/**
* 命令行工具
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var fs = require('fs');
var path = require('path');
var program = require('commander');
var xss = require('../');
var packageInfo = require('../package.json');
program
.version(packageInfo.version)
.option('-t, --test', 'active test')
.option('-i, --input <input_file>', 'input file name')
.option('-o, --output <output_file>', 'output filename')
.option('-c, --config <config_file>', 'load custom config')
.option('-s, --strip-ignore-tag', 'set stripIgnoreTag=true')
.option('-b, --strip-ignore-tag-body', 'set stripIgnoreTagBody=true');
program.on('--help', function () {
console.log(' Examples:');
console.log('');
console.log(' $ xss -t');
console.log(' $ xss -i origin.html');
console.log(' $ xss -i origin.html -o targer.html');
console.log(' $ xss -i origin.html -c config.js');
console.log(' $ xss -i origin.html -s');
console.log(' $ xss -i origin.html -s -b');
console.log('');
console.log(' For more details, please see: https://npmjs.org/package/xss')
});
program.parse(process.argv);
if (program.test) {
require('../lib/cli');
return;
}
var config = {};
if (program.config) {
config = require(path.resolve(program.config));
}
if (program.input) {
var input = fs.readFileSync(program.input, 'utf8');
} else {
program.help();
}
if (program['strip-ignore-tag']) {
config.stripIgnoreTag = true;
}
if (program['strip-ignore-tag-body']) {
config.stripIgnoreTagBody = true;
}
var output = xss(input, config);
if (program.output) {
fs.writeFileSync(program.output, output);
} else {
console.log(output);
}

15
node_modules/xss/dist/test.html generated vendored

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>测试</title>
<meta charset="utf8">
</head>
<body>
<pre id="result"></pre>
</body>
</html>
<script src="xss.js"></script>
<script>
var code = '<script>alert("xss");</' + 'script>';
document.querySelector('#result').innerText = code + '\n被转换成了\n' + filterXSS(code);
</script>

1700
node_modules/xss/dist/xss.js generated vendored

File diff suppressed because it is too large Load Diff

1
node_modules/xss/dist/xss.min.js generated vendored

File diff suppressed because one or more lines are too long

45
node_modules/xss/lib/cli.js generated vendored

@ -0,0 +1,45 @@
/**
* command line tool
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var xss = require("./");
var readline = require("readline");
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.log('Enter a blank line to do xss(), enter "@quit" to exit.\n');
function take(c, n) {
var ret = "";
for (var i = 0; i < n; i++) {
ret += c;
}
return ret;
}
function setPrompt(line) {
line = line.toString();
rl.setPrompt("[" + line + "]" + take(" ", 5 - line.length));
rl.prompt();
}
setPrompt(1);
var html = [];
rl.on("line", function (line) {
if (line === "@quit") return process.exit();
if (line === "") {
console.log("");
console.log(xss(html.join("\r\n")));
console.log("");
html = [];
} else {
html.push(line);
}
setPrompt(html.length + 1);
});

459
node_modules/xss/lib/default.js generated vendored

@ -0,0 +1,459 @@
/**
* default settings
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var FilterCSS = require("cssfilter").FilterCSS;
var getDefaultCSSWhiteList = require("cssfilter").getDefaultWhiteList;
var _ = require("./util");
function getDefaultWhiteList() {
return {
a: ["target", "href", "title"],
abbr: ["title"],
address: [],
area: ["shape", "coords", "href", "alt"],
article: [],
aside: [],
audio: [
"autoplay",
"controls",
"crossorigin",
"loop",
"muted",
"preload",
"src",
],
b: [],
bdi: ["dir"],
bdo: ["dir"],
big: [],
blockquote: ["cite"],
br: [],
caption: [],
center: [],
cite: [],
code: [],
col: ["align", "valign", "span", "width"],
colgroup: ["align", "valign", "span", "width"],
dd: [],
del: ["datetime"],
details: ["open"],
div: [],
dl: [],
dt: [],
em: [],
figcaption: [],
figure: [],
font: ["color", "size", "face"],
footer: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
header: [],
hr: [],
i: [],
img: ["src", "alt", "title", "width", "height"],
ins: ["datetime"],
li: [],
mark: [],
nav: [],
ol: [],
p: [],
pre: [],
s: [],
section: [],
small: [],
span: [],
sub: [],
summary: [],
sup: [],
strong: [],
strike: [],
table: ["width", "border", "align", "valign"],
tbody: ["align", "valign"],
td: ["width", "rowspan", "colspan", "align", "valign"],
tfoot: ["align", "valign"],
th: ["width", "rowspan", "colspan", "align", "valign"],
thead: ["align", "valign"],
tr: ["rowspan", "align", "valign"],
tt: [],
u: [],
ul: [],
video: [
"autoplay",
"controls",
"crossorigin",
"loop",
"muted",
"playsinline",
"poster",
"preload",
"src",
"height",
"width",
],
};
}
var defaultCSSFilter = new FilterCSS();
/**
* default onTag function
*
* @param {String} tag
* @param {String} html
* @param {Object} options
* @return {String}
*/
function onTag(tag, html, options) {
// do nothing
}
/**
* default onIgnoreTag function
*
* @param {String} tag
* @param {String} html
* @param {Object} options
* @return {String}
*/
function onIgnoreTag(tag, html, options) {
// do nothing
}
/**
* default onTagAttr function
*
* @param {String} tag
* @param {String} name
* @param {String} value
* @return {String}
*/
function onTagAttr(tag, name, value) {
// do nothing
}
/**
* default onIgnoreTagAttr function
*
* @param {String} tag
* @param {String} name
* @param {String} value
* @return {String}
*/
function onIgnoreTagAttr(tag, name, value) {
// do nothing
}
/**
* default escapeHtml function
*
* @param {String} html
*/
function escapeHtml(html) {
return html.replace(REGEXP_LT, "&lt;").replace(REGEXP_GT, "&gt;");
}
/**
* default safeAttrValue function
*
* @param {String} tag
* @param {String} name
* @param {String} value
* @param {Object} cssFilter
* @return {String}
*/
function safeAttrValue(tag, name, value, cssFilter) {
// unescape attribute value firstly
value = friendlyAttrValue(value);
if (name === "href" || name === "src") {
// filter `href` and `src` attribute
// only allow the value that starts with `http://` | `https://` | `mailto:` | `/` | `#`
value = _.trim(value);
if (value === "#") return "#";
if (
!(
value.substr(0, 7) === "http://" ||
value.substr(0, 8) === "https://" ||
value.substr(0, 7) === "mailto:" ||
value.substr(0, 4) === "tel:" ||
value.substr(0, 11) === "data:image/" ||
value.substr(0, 6) === "ftp://" ||
value.substr(0, 2) === "./" ||
value.substr(0, 3) === "../" ||
value[0] === "#" ||
value[0] === "/"
)
) {
return "";
}
} else if (name === "background") {
// filter `background` attribute (maybe no use)
// `javascript:`
REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
return "";
}
} else if (name === "style") {
// `expression()`
REGEXP_DEFAULT_ON_TAG_ATTR_7.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_7.test(value)) {
return "";
}
// `url()`
REGEXP_DEFAULT_ON_TAG_ATTR_8.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_8.test(value)) {
REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
return "";
}
}
if (cssFilter !== false) {
cssFilter = cssFilter || defaultCSSFilter;
value = cssFilter.process(value);
}
}
// escape `<>"` before returns
value = escapeAttrValue(value);
return value;
}
// RegExp list
var REGEXP_LT = /</g;
var REGEXP_GT = />/g;
var REGEXP_QUOTE = /"/g;
var REGEXP_QUOTE_2 = /&quot;/g;
var REGEXP_ATTR_VALUE_1 = /&#([a-zA-Z0-9]*);?/gim;
var REGEXP_ATTR_VALUE_COLON = /&colon;?/gim;
var REGEXP_ATTR_VALUE_NEWLINE = /&newline;?/gim;
// var REGEXP_DEFAULT_ON_TAG_ATTR_3 = /\/\*|\*\//gm;
var REGEXP_DEFAULT_ON_TAG_ATTR_4 =
/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a):/gi;
// var REGEXP_DEFAULT_ON_TAG_ATTR_5 = /^[\s"'`]*(d\s*a\s*t\s*a\s*)\:/gi;
// var REGEXP_DEFAULT_ON_TAG_ATTR_6 = /^[\s"'`]*(d\s*a\s*t\s*a\s*)\:\s*image\//gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_7 =
/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_8 = /u\s*r\s*l\s*\(.*/gi;
/**
* escape double quote
*
* @param {String} str
* @return {String} str
*/
function escapeQuote(str) {
return str.replace(REGEXP_QUOTE, "&quot;");
}
/**
* unescape double quote
*
* @param {String} str
* @return {String} str
*/
function unescapeQuote(str) {
return str.replace(REGEXP_QUOTE_2, '"');
}
/**
* escape html entities
*
* @param {String} str
* @return {String}
*/
function escapeHtmlEntities(str) {
return str.replace(REGEXP_ATTR_VALUE_1, function replaceUnicode(str, code) {
return code[0] === "x" || code[0] === "X"
? String.fromCharCode(parseInt(code.substr(1), 16))
: String.fromCharCode(parseInt(code, 10));
});
}
/**
* escape html5 new danger entities
*
* @param {String} str
* @return {String}
*/
function escapeDangerHtml5Entities(str) {
return str
.replace(REGEXP_ATTR_VALUE_COLON, ":")
.replace(REGEXP_ATTR_VALUE_NEWLINE, " ");
}
/**
* clear nonprintable characters
*
* @param {String} str
* @return {String}
*/
function clearNonPrintableCharacter(str) {
var str2 = "";
for (var i = 0, len = str.length; i < len; i++) {
str2 += str.charCodeAt(i) < 32 ? " " : str.charAt(i);
}
return _.trim(str2);
}
/**
* get friendly attribute value
*
* @param {String} str
* @return {String}
*/
function friendlyAttrValue(str) {
str = unescapeQuote(str);
str = escapeHtmlEntities(str);
str = escapeDangerHtml5Entities(str);
str = clearNonPrintableCharacter(str);
return str;
}
/**
* unescape attribute value
*
* @param {String} str
* @return {String}
*/
function escapeAttrValue(str) {
str = escapeQuote(str);
str = escapeHtml(str);
return str;
}
/**
* `onIgnoreTag` function for removing all the tags that are not in whitelist
*/
function onIgnoreTagStripAll() {
return "";
}
/**
* remove tag body
* specify a `tags` list, if the tag is not in the `tags` list then process by the specify function (optional)
*
* @param {array} tags
* @param {function} next
*/
function StripTagBody(tags, next) {
if (typeof next !== "function") {
next = function () {};
}
var isRemoveAllTag = !Array.isArray(tags);
function isRemoveTag(tag) {
if (isRemoveAllTag) return true;
return _.indexOf(tags, tag) !== -1;
}
var removeList = [];
var posStart = false;
return {
onIgnoreTag: function (tag, html, options) {
if (isRemoveTag(tag)) {
if (options.isClosing) {
var ret = "[/removed]";
var end = options.position + ret.length;
removeList.push([
posStart !== false ? posStart : options.position,
end,
]);
posStart = false;
return ret;
} else {
if (!posStart) {
posStart = options.position;
}
return "[removed]";
}
} else {
return next(tag, html, options);
}
},
remove: function (html) {
var rethtml = "";
var lastPos = 0;
_.forEach(removeList, function (pos) {
rethtml += html.slice(lastPos, pos[0]);
lastPos = pos[1];
});
rethtml += html.slice(lastPos);
return rethtml;
},
};
}
/**
* remove html comments
*
* @param {String} html
* @return {String}
*/
function stripCommentTag(html) {
var retHtml = "";
var lastPos = 0;
while (lastPos < html.length) {
var i = html.indexOf("<!--", lastPos);
if (i === -1) {
retHtml += html.slice(lastPos);
break;
}
retHtml += html.slice(lastPos, i);
var j = html.indexOf("-->", i);
if (j === -1) {
break;
}
lastPos = j + 3;
}
return retHtml;
}
/**
* remove invisible characters
*
* @param {String} html
* @return {String}
*/
function stripBlankChar(html) {
var chars = html.split("");
chars = chars.filter(function (char) {
var c = char.charCodeAt(0);
if (c === 127) return false;
if (c <= 31) {
if (c === 10 || c === 13) return true;
return false;
}
return true;
});
return chars.join("");
}
exports.whiteList = getDefaultWhiteList();
exports.getDefaultWhiteList = getDefaultWhiteList;
exports.onTag = onTag;
exports.onIgnoreTag = onIgnoreTag;
exports.onTagAttr = onTagAttr;
exports.onIgnoreTagAttr = onIgnoreTagAttr;
exports.safeAttrValue = safeAttrValue;
exports.escapeHtml = escapeHtml;
exports.escapeQuote = escapeQuote;
exports.unescapeQuote = unescapeQuote;
exports.escapeHtmlEntities = escapeHtmlEntities;
exports.escapeDangerHtml5Entities = escapeDangerHtml5Entities;
exports.clearNonPrintableCharacter = clearNonPrintableCharacter;
exports.friendlyAttrValue = friendlyAttrValue;
exports.escapeAttrValue = escapeAttrValue;
exports.onIgnoreTagStripAll = onIgnoreTagStripAll;
exports.StripTagBody = StripTagBody;
exports.stripCommentTag = stripCommentTag;
exports.stripBlankChar = stripBlankChar;
exports.cssFilter = defaultCSSFilter;
exports.getDefaultCSSWhiteList = getDefaultCSSWhiteList;

51
node_modules/xss/lib/index.js generated vendored

@ -0,0 +1,51 @@
/**
* xss
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var DEFAULT = require("./default");
var parser = require("./parser");
var FilterXSS = require("./xss");
/**
* filter xss function
*
* @param {String} html
* @param {Object} options { whiteList, onTag, onTagAttr, onIgnoreTag, onIgnoreTagAttr, safeAttrValue, escapeHtml }
* @return {String}
*/
function filterXSS(html, options) {
var xss = new FilterXSS(options);
return xss.process(html);
}
exports = module.exports = filterXSS;
exports.filterXSS = filterXSS;
exports.FilterXSS = FilterXSS;
(function () {
for (var i in DEFAULT) {
exports[i] = DEFAULT[i];
}
for (var j in parser) {
exports[j] = parser[j];
}
})();
// using `xss` on the browser, output `filterXSS` to the globals
if (typeof window !== "undefined") {
window.filterXSS = module.exports;
}
// using `xss` on the WebWorker, output `filterXSS` to the globals
function isWorkerEnv() {
return (
typeof self !== "undefined" &&
typeof DedicatedWorkerGlobalScope !== "undefined" &&
self instanceof DedicatedWorkerGlobalScope
);
}
if (isWorkerEnv()) {
self.filterXSS = module.exports;
}

257
node_modules/xss/lib/parser.js generated vendored

@ -0,0 +1,257 @@
/**
* Simple HTML Parser
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var _ = require("./util");
/**
* get tag name
*
* @param {String} html e.g. '<a hef="#">'
* @return {String}
*/
function getTagName(html) {
var i = _.spaceIndex(html);
var tagName;
if (i === -1) {
tagName = html.slice(1, -1);
} else {
tagName = html.slice(1, i + 1);
}
tagName = _.trim(tagName).toLowerCase();
if (tagName.slice(0, 1) === "/") tagName = tagName.slice(1);
if (tagName.slice(-1) === "/") tagName = tagName.slice(0, -1);
return tagName;
}
/**
* is close tag?
*
* @param {String} html '<a hef="#">'
* @return {Boolean}
*/
function isClosing(html) {
return html.slice(0, 2) === "</";
}
/**
* parse input html and returns processed html
*
* @param {String} html
* @param {Function} onTag e.g. function (sourcePosition, position, tag, html, isClosing)
* @param {Function} escapeHtml
* @return {String}
*/
function parseTag(html, onTag, escapeHtml) {
"use strict";
var rethtml = "";
var lastPos = 0;
var tagStart = false;
var quoteStart = false;
var currentPos = 0;
var len = html.length;
var currentTagName = "";
var currentHtml = "";
chariterator: for (currentPos = 0; currentPos < len; currentPos++) {
var c = html.charAt(currentPos);
if (tagStart === false) {
if (c === "<") {
tagStart = currentPos;
continue;
}
} else {
if (quoteStart === false) {
if (c === "<") {
rethtml += escapeHtml(html.slice(lastPos, currentPos));
tagStart = currentPos;
lastPos = currentPos;
continue;
}
if (c === ">" || currentPos === len - 1) {
rethtml += escapeHtml(html.slice(lastPos, tagStart));
currentHtml = html.slice(tagStart, currentPos + 1);
currentTagName = getTagName(currentHtml);
rethtml += onTag(
tagStart,
rethtml.length,
currentTagName,
currentHtml,
isClosing(currentHtml)
);
lastPos = currentPos + 1;
tagStart = false;
continue;
}
if (c === '"' || c === "'") {
var i = 1;
var ic = html.charAt(currentPos - i);
while (ic.trim() === "" || ic === "=") {
if (ic === "=") {
quoteStart = c;
continue chariterator;
}
ic = html.charAt(currentPos - ++i);
}
}
} else {
if (c === quoteStart) {
quoteStart = false;
continue;
}
}
}
}
if (lastPos < len) {
rethtml += escapeHtml(html.substr(lastPos));
}
return rethtml;
}
var REGEXP_ILLEGAL_ATTR_NAME = /[^a-zA-Z0-9\\_:.-]/gim;
/**
* parse input attributes and returns processed attributes
*
* @param {String} html e.g. `href="#" target="_blank"`
* @param {Function} onAttr e.g. `function (name, value)`
* @return {String}
*/
function parseAttr(html, onAttr) {
"use strict";
var lastPos = 0;
var lastMarkPos = 0;
var retAttrs = [];
var tmpName = false;
var len = html.length;
function addAttr(name, value) {
name = _.trim(name);
name = name.replace(REGEXP_ILLEGAL_ATTR_NAME, "").toLowerCase();
if (name.length < 1) return;
var ret = onAttr(name, value || "");
if (ret) retAttrs.push(ret);
}
// 逐个分析字符
for (var i = 0; i < len; i++) {
var c = html.charAt(i);
var v, j;
if (tmpName === false && c === "=") {
tmpName = html.slice(lastPos, i);
lastPos = i + 1;
lastMarkPos = html.charAt(lastPos) === '"' || html.charAt(lastPos) === "'" ? lastPos : findNextQuotationMark(html, i + 1);
continue;
}
if (tmpName !== false) {
if (
i === lastMarkPos
) {
j = html.indexOf(c, i + 1);
if (j === -1) {
break;
} else {
v = _.trim(html.slice(lastMarkPos + 1, j));
addAttr(tmpName, v);
tmpName = false;
i = j;
lastPos = i + 1;
continue;
}
}
}
if (/\s|\n|\t/.test(c)) {
html = html.replace(/\s|\n|\t/g, " ");
if (tmpName === false) {
j = findNextEqual(html, i);
if (j === -1) {
v = _.trim(html.slice(lastPos, i));
addAttr(v);
tmpName = false;
lastPos = i + 1;
continue;
} else {
i = j - 1;
continue;
}
} else {
j = findBeforeEqual(html, i - 1);
if (j === -1) {
v = _.trim(html.slice(lastPos, i));
v = stripQuoteWrap(v);
addAttr(tmpName, v);
tmpName = false;
lastPos = i + 1;
continue;
} else {
continue;
}
}
}
}
if (lastPos < html.length) {
if (tmpName === false) {
addAttr(html.slice(lastPos));
} else {
addAttr(tmpName, stripQuoteWrap(_.trim(html.slice(lastPos))));
}
}
return _.trim(retAttrs.join(" "));
}
function findNextEqual(str, i) {
for (; i < str.length; i++) {
var c = str[i];
if (c === " ") continue;
if (c === "=") return i;
return -1;
}
}
function findNextQuotationMark(str, i) {
for (; i < str.length; i++) {
var c = str[i];
if (c === " ") continue;
if (c === "'" || c === '"') return i;
return -1;
}
}
function findBeforeEqual(str, i) {
for (; i > 0; i--) {
var c = str[i];
if (c === " ") continue;
if (c === "=") return i;
return -1;
}
}
function isQuoteWrapString(text) {
if (
(text[0] === '"' && text[text.length - 1] === '"') ||
(text[0] === "'" && text[text.length - 1] === "'")
) {
return true;
} else {
return false;
}
}
function stripQuoteWrap(text) {
if (isQuoteWrapString(text)) {
return text.substr(1, text.length - 2);
} else {
return text;
}
}
exports.parseTag = parseTag;
exports.parseAttr = parseAttr;

34
node_modules/xss/lib/util.js generated vendored

@ -0,0 +1,34 @@
module.exports = {
indexOf: function (arr, item) {
var i, j;
if (Array.prototype.indexOf) {
return arr.indexOf(item);
}
for (i = 0, j = arr.length; i < j; i++) {
if (arr[i] === item) {
return i;
}
}
return -1;
},
forEach: function (arr, fn, scope) {
var i, j;
if (Array.prototype.forEach) {
return arr.forEach(fn, scope);
}
for (i = 0, j = arr.length; i < j; i++) {
fn.call(scope, arr[i], i, arr);
}
},
trim: function (str) {
if (String.prototype.trim) {
return str.trim();
}
return str.replace(/(^\s*)|(\s*$)/g, "");
},
spaceIndex: function (str) {
var reg = /\s|\n|\t/;
var match = reg.exec(str);
return match ? match.index : -1;
},
};

229
node_modules/xss/lib/xss.js generated vendored

@ -0,0 +1,229 @@
/**
* filter xss
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
var FilterCSS = require("cssfilter").FilterCSS;
var DEFAULT = require("./default");
var parser = require("./parser");
var parseTag = parser.parseTag;
var parseAttr = parser.parseAttr;
var _ = require("./util");
/**
* returns `true` if the input value is `undefined` or `null`
*
* @param {Object} obj
* @return {Boolean}
*/
function isNull(obj) {
return obj === undefined || obj === null;
}
/**
* get attributes for a tag
*
* @param {String} html
* @return {Object}
* - {String} html
* - {Boolean} closing
*/
function getAttrs(html) {
var i = _.spaceIndex(html);
if (i === -1) {
return {
html: "",
closing: html[html.length - 2] === "/",
};
}
html = _.trim(html.slice(i + 1, -1));
var isClosing = html[html.length - 1] === "/";
if (isClosing) html = _.trim(html.slice(0, -1));
return {
html: html,
closing: isClosing,
};
}
/**
* shallow copy
*
* @param {Object} obj
* @return {Object}
*/
function shallowCopyObject(obj) {
var ret = {};
for (var i in obj) {
ret[i] = obj[i];
}
return ret;
}
function keysToLowerCase(obj) {
var ret = {};
for (var i in obj) {
if (Array.isArray(obj[i])) {
ret[i.toLowerCase()] = obj[i].map(function (item) {
return item.toLowerCase();
});
} else {
ret[i.toLowerCase()] = obj[i];
}
}
return ret;
}
/**
* FilterXSS class
*
* @param {Object} options
* whiteList (or allowList), onTag, onTagAttr, onIgnoreTag,
* onIgnoreTagAttr, safeAttrValue, escapeHtml
* stripIgnoreTagBody, allowCommentTag, stripBlankChar
* css{whiteList, onAttr, onIgnoreAttr} `css=false` means don't use `cssfilter`
*/
function FilterXSS(options) {
options = shallowCopyObject(options || {});
if (options.stripIgnoreTag) {
if (options.onIgnoreTag) {
console.error(
'Notes: cannot use these two options "stripIgnoreTag" and "onIgnoreTag" at the same time'
);
}
options.onIgnoreTag = DEFAULT.onIgnoreTagStripAll;
}
if (options.whiteList || options.allowList) {
options.whiteList = keysToLowerCase(options.whiteList || options.allowList);
} else {
options.whiteList = DEFAULT.whiteList;
}
options.onTag = options.onTag || DEFAULT.onTag;
options.onTagAttr = options.onTagAttr || DEFAULT.onTagAttr;
options.onIgnoreTag = options.onIgnoreTag || DEFAULT.onIgnoreTag;
options.onIgnoreTagAttr = options.onIgnoreTagAttr || DEFAULT.onIgnoreTagAttr;
options.safeAttrValue = options.safeAttrValue || DEFAULT.safeAttrValue;
options.escapeHtml = options.escapeHtml || DEFAULT.escapeHtml;
this.options = options;
if (options.css === false) {
this.cssFilter = false;
} else {
options.css = options.css || {};
this.cssFilter = new FilterCSS(options.css);
}
}
/**
* start process and returns result
*
* @param {String} html
* @return {String}
*/
FilterXSS.prototype.process = function (html) {
// compatible with the input
html = html || "";
html = html.toString();
if (!html) return "";
var me = this;
var options = me.options;
var whiteList = options.whiteList;
var onTag = options.onTag;
var onIgnoreTag = options.onIgnoreTag;
var onTagAttr = options.onTagAttr;
var onIgnoreTagAttr = options.onIgnoreTagAttr;
var safeAttrValue = options.safeAttrValue;
var escapeHtml = options.escapeHtml;
var cssFilter = me.cssFilter;
// remove invisible characters
if (options.stripBlankChar) {
html = DEFAULT.stripBlankChar(html);
}
// remove html comments
if (!options.allowCommentTag) {
html = DEFAULT.stripCommentTag(html);
}
// if enable stripIgnoreTagBody
var stripIgnoreTagBody = false;
if (options.stripIgnoreTagBody) {
stripIgnoreTagBody = DEFAULT.StripTagBody(
options.stripIgnoreTagBody,
onIgnoreTag
);
onIgnoreTag = stripIgnoreTagBody.onIgnoreTag;
}
var retHtml = parseTag(
html,
function (sourcePosition, position, tag, html, isClosing) {
var info = {
sourcePosition: sourcePosition,
position: position,
isClosing: isClosing,
isWhite: Object.prototype.hasOwnProperty.call(whiteList, tag),
};
// call `onTag()`
var ret = onTag(tag, html, info);
if (!isNull(ret)) return ret;
if (info.isWhite) {
if (info.isClosing) {
return "</" + tag + ">";
}
var attrs = getAttrs(html);
var whiteAttrList = whiteList[tag];
var attrsHtml = parseAttr(attrs.html, function (name, value) {
// call `onTagAttr()`
var isWhiteAttr = _.indexOf(whiteAttrList, name) !== -1;
var ret = onTagAttr(tag, name, value, isWhiteAttr);
if (!isNull(ret)) return ret;
if (isWhiteAttr) {
// call `safeAttrValue()`
value = safeAttrValue(tag, name, value, cssFilter);
if (value) {
return name + '="' + value + '"';
} else {
return name;
}
} else {
// call `onIgnoreTagAttr()`
ret = onIgnoreTagAttr(tag, name, value, isWhiteAttr);
if (!isNull(ret)) return ret;
return;
}
});
// build new tag html
html = "<" + tag;
if (attrsHtml) html += " " + attrsHtml;
if (attrs.closing) html += " /";
html += ">";
return html;
} else {
// call `onIgnoreTag()`
ret = onIgnoreTag(tag, html, info);
if (!isNull(ret)) return ret;
return escapeHtml(html);
}
},
escapeHtml
);
// if enable stripIgnoreTagBody
if (stripIgnoreTagBody) {
retHtml = stripIgnoreTagBody.remove(retHtml);
}
return retHtml;
};
module.exports = FilterXSS;

65
node_modules/xss/package.json generated vendored

@ -0,0 +1,65 @@
{
"name": "xss",
"main": "./lib/index.js",
"typings": "./typings/xss.d.ts",
"version": "1.0.14",
"description": "Sanitize untrusted HTML (to prevent XSS) with a configuration specified by a Whitelist",
"author": "Zongmin Lei <leizongmin@gmail.com> (http://ucdok.com)",
"repository": {
"type": "git",
"url": "git://github.com/leizongmin/js-xss.git"
},
"engines": {
"node": ">= 0.10.0"
},
"dependencies": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
},
"devDependencies": {
"browserify": "^17.0.0",
"coveralls": "^3.1.1",
"debug": "^4.3.4",
"eslint": "^8.16.0",
"mocha": "^8.4.0",
"nyc": "^15.1.0",
"uglify-js": "^3.15.5"
},
"files": [
"lib",
"bin/xss",
"dist",
"typings/*.d.ts"
],
"bin": {
"xss": "./bin/xss"
},
"scripts": {
"lint": "eslint lib/**",
"test": "export DEBUG=xss:* && mocha -t 5000",
"test-cov": "nyc --reporter=lcov mocha --exit \"test/*.js\" && nyc report",
"coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
"build": "./bin/build",
"prepublish": "npm run test && npm run build"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/leizongmin/js-xss/issues"
},
"homepage": "https://github.com/leizongmin/js-xss",
"keywords": [
"sanitization",
"xss",
"sanitize",
"sanitisation",
"input",
"security",
"escape",
"encode",
"filter",
"validator",
"html",
"injection",
"whitelist"
]
}

203
node_modules/xss/typings/xss.d.ts generated vendored

@ -0,0 +1,203 @@
/**
* xss
*
* @author Zongmin Lei<leizongmin@gmail.com>
*/
declare module "xss" {
global {
function filterXSS(html: string, options?: IFilterXSSOptions): string;
namespace XSS {
export interface IFilterXSSOptions {
allowList?: IWhiteList;
whiteList?: IWhiteList;
onTag?: OnTagHandler;
onTagAttr?: OnTagAttrHandler;
onIgnoreTag?: OnTagHandler;
onIgnoreTagAttr?: OnTagAttrHandler;
safeAttrValue?: SafeAttrValueHandler;
escapeHtml?: EscapeHandler;
stripIgnoreTag?: boolean;
stripIgnoreTagBody?: boolean | string[];
allowCommentTag?: boolean;
stripBlankChar?: boolean;
css?: {} | boolean;
}
interface IWhiteList extends Record<string, string[] | undefined> {
a?: string[];
abbr?: string[];
address?: string[];
area?: string[];
article?: string[];
aside?: string[];
audio?: string[];
b?: string[];
bdi?: string[];
bdo?: string[];
big?: string[];
blockquote?: string[];
br?: string[];
caption?: string[];
center?: string[];
cite?: string[];
code?: string[];
col?: string[];
colgroup?: string[];
dd?: string[];
del?: string[];
details?: string[];
div?: string[];
dl?: string[];
dt?: string[];
em?: string[];
figure?: string[];
figcaption?: string[];
font?: string[];
footer?: string[];
h1?: string[];
h2?: string[];
h3?: string[];
h4?: string[];
h5?: string[];
h6?: string[];
header?: string[];
hr?: string[];
i?: string[];
img?: string[];
ins?: string[];
li?: string[];
mark?: string[];
nav?: string[];
ol?: string[];
p?: string[];
pre?: string[];
s?: string[];
section?: string[];
small?: string[];
span?: string[];
sub?: string[];
sup?: string[];
strong?: string[];
strike?: string[];
summary?: string[];
table?: string[];
tbody?: string[];
td?: string[];
tfoot?: string[];
th?: string[];
thead?: string[];
tr?: string[];
tt?: string[];
u?: string[];
ul?: string[];
video?: string[];
}
type OnTagHandler = (
tag: string,
html: string,
options: {
sourcePosition?: number;
position?: number;
isClosing?: boolean;
isWhite?: boolean;
}
) => string | void;
type OnTagAttrHandler = (
tag: string,
name: string,
value: string,
isWhiteAttr: boolean
) => string | void;
type SafeAttrValueHandler = (
tag: string,
name: string,
value: string,
cssFilter: ICSSFilter
) => string;
type EscapeHandler = (str: string) => string;
interface ICSSFilter {
process(value: string): string;
}
}
}
export interface IFilterXSSOptions extends XSS.IFilterXSSOptions {}
export interface IWhiteList extends XSS.IWhiteList {}
export type OnTagHandler = XSS.OnTagHandler;
export type OnTagAttrHandler = XSS.OnTagAttrHandler;
export type SafeAttrValueHandler = XSS.SafeAttrValueHandler;
export type EscapeHandler = XSS.EscapeHandler;
export interface ICSSFilter extends XSS.ICSSFilter {}
export function StripTagBody(
tags: string[],
next: () => void
): {
onIgnoreTag(
tag: string,
html: string,
options: {
position: number;
isClosing: boolean;
}
): string;
remove(html: string): string;
};
export class FilterXSS {
constructor(options?: IFilterXSSOptions);
process(html: string): string;
}
export function filterXSS(html: string, options?: IFilterXSSOptions): string;
export function parseTag(
html: string,
onTag: (
sourcePosition: number,
position: number,
tag: string,
html: string,
isClosing: boolean
) => string,
escapeHtml: EscapeHandler
): string;
export function parseAttr(
html: string,
onAttr: (name: string, value: string) => string
): string;
export const whiteList: IWhiteList;
export function getDefaultWhiteList(): IWhiteList;
export const onTag: OnTagHandler;
export const onIgnoreTag: OnTagHandler;
export const onTagAttr: OnTagAttrHandler;
export const onIgnoreTagAttr: OnTagAttrHandler;
export const safeAttrValue: SafeAttrValueHandler;
export const escapeHtml: EscapeHandler;
export const escapeQuote: EscapeHandler;
export const unescapeQuote: EscapeHandler;
export const escapeHtmlEntities: EscapeHandler;
export const escapeDangerHtml5Entities: EscapeHandler;
export const clearNonPrintableCharacter: EscapeHandler;
export const friendlyAttrValue: EscapeHandler;
export const escapeAttrValue: EscapeHandler;
export function onIgnoreTagStripAll(): string;
export const stripCommentTag: EscapeHandler;
export const stripBlankChar: EscapeHandler;
export const cssFilter: ICSSFilter;
export function getDefaultCSSWhiteList(): ICSSFilter;
const xss: (html: string, options?: IFilterXSSOptions) => string;
export default xss;
}

@ -0,0 +1,17 @@
{
"name": "yangyangquan_kehu_uniapp",
"version": "1.0.0",
"description": "",
"main": "main.js",
"dependencies": {
"qs": "^5.2.1",
"xss": "^1.0.14",
"md5": "^2.3.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

@ -0,0 +1,219 @@
{
"pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "登录",
"mp-weixin": {
"titleNView": false
}
}
},
{
"path": "pages/index/phoneLogin",
"style": {
"navigationBarTitleText": "",
"mp-weixin": {
"titleNView": false
}
}
},
{
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "我的",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/collection",
"style": {
"navigationBarTitleText": "我的收藏",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/user/collectionSerch",
"style": {
"navigationBarTitleText": "搜索",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/user/allBreakeven",
"style": {
"navigationBarTitleText": "所有个股盈亏",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/user/breakevenDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/tradeStats",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/user/edit/editUser",
"style": {
"navigationBarTitleText": "个人信息",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/edit/editName",
"style": {
"navigationBarTitleText": "修改昵称",
"enablePullDownRefresh": false
}
},
{
"path": "pages/user/edit/editPhone",
"style": {
"navigationBarTitleText": "修改手机号",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/home",
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/home/market/allTrendModule",
"style": {
"navigationBarTitleText": "趋势板块",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/home/private/serch",
"style": {
"navigationBarTitleText": "搜索",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/private/privateDetail",
"style": {
"navigationBarTitleText": "个股详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/market/allMarket",
"style": {
"navigationBarTitleText": "全部",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/home/market/marketDetail",
"style": {
"navigationBarTitleText": "个股",
"enablePullDownRefresh": false
}
},
{
"path": "pages/home/market/trendDetail",
"style": {
"navigationBarTitleText": "趋势详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/trade/trade",
"style": {
"navigationBarTitleText": "交易",
"enablePullDownRefresh": false,
"onReachBottonDistance": 50
}
},
{
"path": "pages/trade/tradeDateil",
"style": {
"navigationBarTitleText": "交易详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/trade/tradeInfo",
"style": {
"navigationBarTitleText": "录入信息",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "股票",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#999999",
"selectedColor": "#EC7C00",
"backgroundColor": "#fff",
"borderStyle": "white",
"height": "50px",
"fontSize": "12px",
"iconWidth": "20px",
"list": [
{
"pagePath": "pages/home/home",
"pageName": "home",
"iconPath": "static/home_false.png",
"selectedIconPath": "static/home_true.png",
"text": "首页"
},
{
"pagePath": "pages/trade/trade",
"pageName": "trade",
"iconPath": "static/jiaoyi_false.png",
"selectedIconPath": "static/jiaoyi_true.png",
"text": "交易"
},
{
"pagePath": "pages/user/user",
"pageName": "user",
"iconPath": "static/user_false.png",
"selectedIconPath": "static/user_true.png",
"text": "我的"
}
]
},
"uniIdRouter": {},
"subPackages": [
{
"root": "subpkgA",
"pages": [
{
"path": "marketIndex",
"style": {
"navigationBarTitleText": "指数",
"onReachBottonDistance": 50,
"enablePullDownRefresh": false
}
}
]
}
]
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,615 @@
<template>
<view class="all_market">
<view class="head">
<view class="head_date">
<image
src="../../../static/home_left.png"
class="date_icon"
mode="scaleToFill"
@tap="beforeDay(date)"
/>
<input
type="text"
v-model="date"
disabled
class="ipt_date"
@tap="selectDate"
/>
<image
src="../../../static/home_right.png"
class="date_icon"
mode="scaleToFill"
@tap="afterDay(date)"
/>
</view>
</view>
<view class="main_chart">
<l-echart ref="columnar"></l-echart>
</view>
<view class="private_table_head">
<view class="private_table_head_left">
<view class="private_head_name">股票名称</view>
<view class="private_head_price">价格</view>
<view class="private_head_gains" @tap="showGains = true">
<view>{{ RiseOrDecline }}</view>
<image
src="../../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/>
</view>
</view>
<view class="private_table_head_right" @tap="privateBelong">
<view>{{ currentBelong }}</view>
<!-- <image
src="../../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/> -->
</view>
</view>
<view v-if="list.length > 0">
<view
class="private_table_list"
v-for="(item, index) in list"
:key="index"
@tap="toPrivateDetail(item.securityName, item.securityCode)"
>
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.securityName }}</view>
<view class="table_list_code">{{ item.securityCode }}</view>
</view>
<view
class="table_list_price"
:class="{ table_list_price1: item.riseLossesCurrentDay < 0 }"
>
{{ item.closingPrice }}
</view>
<view
class="table_list_gains"
:class="{ table_list_price1: item.riseLossesCurrentDay < 0 }"
>
{{ item.riseLossesCurrentDay.toFixed(2) }}
</view>
</view>
<view>{{ item.dongCaiIndustryIndexLevel2 }}</view>
</view>
</view>
<view v-else>
<u-empty
mode="data"
icon="http://cdn.uviewui.com/uview/empty/data.png"
marginTop="50"
>
</u-empty>
</view>
<!-- 选择时间 -->
<u-datetime-picker
:show="dateShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelDate"
@confirm="confirmDate"
></u-datetime-picker>
<!-- 个股所属板块 -->
<u-picker
:show="showPrivateBelong"
:columns="columnsBelong"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelPrivateBelong"
@confirm="confirmPrivateBelong"
></u-picker>
<!-- 数据上涨还是下降筛选 -->
<u-picker
:show="showGains"
:columns="columnsGains"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showGains = false"
@confirm="confirmGains"
></u-picker>
</view>
</template>
<script>
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
export default {
data() {
return {
// or
RiseOrDecline: '涨停',
showGains: false,
columnsGains: [['涨停', '跌停']],
date: '2023-04-10',
//
dateShow: false,
list: [
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10.06%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10.05%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
],
//
showPrivateBelong: false,
currentBelong: '所属板块',
columnsBelong: [['所属板块', '成交量']],
pagename: 1,
last_page: null,
}
},
onLoad(options) {
this.date = this.getTime(Date.parse(new Date()))
this.rending()
},
onReachBottom() {
if (this.pagenum < this.last_page) {
this.getnewGoods()
}
},
mounted() {
this.$nextTick(() => {
// echarts
// this.initEcharts()
this.columnarInitCharts()
})
},
methods: {
rending() {
// /stock/riseLossesDetail
this.$api
.post('/stock/originalIssueStockDetail', {
businessDate: this.date,
pageModel: {
pageNo: this.pagename,
pageSize: 20,
sortField: '',
sortWay: '',
},
riseOrLosses: 1,
securityCode: '',
securityType: '',
})
.then(r => {
if (r) {
// this.data = r
this.list = r.list
// this.last_page = r.totalPage
// this.privateList = r.list
this.last_page = r.totalPage
}
})
.catch(fall => {
console.log(fall)
})
},
rending1() {
// /stock/riseLossesDetail
this.$api
.post('/stock/originalIssueStockDetail', {
businessDate: this.date,
pageModel: {
pageNo: this.pagename,
pageSize: 20,
sortField: '',
sortWay: '',
},
riseOrLosses: 1,
securityCode: '',
securityType: '',
})
.then(r => {
if (r) {
// this.data = r
this.list = [...this.list, ...r.list]
// this.privateList = r.list
this.last_page = r.totalPage
}
})
.catch(fall => {
console.log(fall)
})
},
//
beforeDay(date) {
this.pagenum = 1
this.date = this.getTime(new Date(date).getTime() - 24 * 60 * 60 * 1000)
this.columnarInitCharts()
this.rending()
},
//
afterDay(date) {
this.pagenum = 1
this.date = this.getTime(new Date(date).getTime() + 24 * 60 * 60 * 1000)
this.columnarInitCharts()
this.rending()
},
//
selectDate() {
this.dateShow = true
},
//
cancelDate() {
this.dateShow = false
},
//
confirmDate(e) {
this.pagenum = 1
this.$nextTick(() => {
this.date = this.getTime(e.value)
this.columnarInitCharts()
this.rending()
})
this.dateShow = false
},
//
privateBelong() {
this.showPrivateBelong = true
},
//
cancelPrivateBelong() {
this.showPrivateBelong = false
},
//
confirmPrivateBelong(e) {
this.currentBelong = e.value[0]
this.showPrivateBelong = false
},
//
confirmGains(e) {
this.RiseOrDecline = e.value[0]
this.$api
.post('/stock/originalIssueStockDetail', {
businessDate: this.date,
pageModel: {
pageNo: 1,
pageSize: 20,
sortField: '',
sortWay: '',
},
riseOrLosses: this.RiseOrDecline == '涨停' ? 1 : 0,
securityCode: '',
securityType: '',
})
.then(r => {
if (r) {
// this.data = r
this.list = r.list
// this.privateList = r.list
this.last_page = r.totalPage
}
})
.catch(fall => {
console.log(fall)
})
this.showGains = false
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
//
columnarInitCharts() {
this.$api
.post('/stock/riseLossesStatistics', {
businessDate: this.date,
securityCode: '',
securityType: '',
})
.then(r => {
if (r) {
// this.data = r
this.$refs.columnar.init(echarts, chart => {
let option = {
xAxis: {},
yAxis: {
// type: 'value',
type: 'category',
data: [
'≥10%',
'≥7%',
'7-5%',
'5-3%',
'3-0%',
'平',
'-3至-5%',
'-5至-7%',
'≤-7%',
'≤-10%',
],
},
series: [
{
data: r.data,
type: 'bar',
itemStyle: {
normal: {
//
color: function (params) {
//
var colorList = [
'#D9001B',
'#D9001B',
'#D9001B',
'#D9001B',
'#D9001B',
'#999999',
'#6FBB60',
'#6FBB60',
'#6FBB60',
'#6FBB60',
]
return colorList[params.dataIndex]
},
label: {
show: true, //
position: 'right', //
textStyle: {
//
// color: "black",
fontSize: 14,
},
},
},
},
},
],
grid: {
top: '5%',
},
}
chart.setOption(option)
})
}
})
.catch(fall => {
console.log(fall)
})
},
getnewGoods() {
this.pagenum = this.pagenum + 1
// 1.loading
uni.showLoading({
title: '数据加载中...',
})
// 2.
this.isLoading = true
// 3.
this.rending1()
//
// 4.loading
uni.hideLoading()
// 5.
this.isLoading = false
},
//
toPrivateDetail(name, id) {
uni.navigateTo({
url: `/pages/home/private/privateDetail?name=${name}&id=${id}`,
})
},
},
}
</script>
<style lang="scss" scoped>
.head {
display: flex;
padding: 32rpx 24rpx;
}
.head_date {
padding: 16rpx 32rpx;
border-radius: 8rpx;
border: 2rpx solid #ec7c00;
display: flex;
align-items: center;
.ipt_date {
color: #ec7c00;
width: 180rpx;
font-size: 24rpx;
text-align: center;
}
.date_icon {
width: 24rpx;
height: 24rpx;
}
}
.select_days {
margin-left: 40rpx;
padding: 16rpx 32rpx;
border-radius: 8rpx;
border: 2rpx solid #999999;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.select_days_icon {
margin-left: 40rpx;
width: 18rpx;
height: 10rpx;
}
}
.main_chart {
// height: 550rpx;
// background-color: pink;
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 200rpx;
}
.private_head_price {
width: 150rpx;
text-align: center;
}
.private_head_gains {
width: 150rpx;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 200rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 150rpx;
text-align: center;
color: #d9001b;
}
.table_list_gains {
width: 150rpx;
text-align: center;
color: #d9001b;
}
.table_list_price1 {
color: #6fbb60;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
</style>

@ -0,0 +1,452 @@
<template>
<view class="all_trend_module">
<view class="center">
<view class="date">
<image
src="../../../static/home_left.png"
class="date_icon"
mode="scaleToFill"
@tap="beforeDay(date)"
/>
<input
type="text"
v-model="date"
disabled
class="ipt_date"
@tap="selectDate"
/>
<image
src="../../../static/home_right.png"
class="date_icon"
mode="scaleToFill"
@tap="afterDay(date)"
/>
</view>
<view class="nav">
<view
class="nav_select"
@tap="selectTrend(item.name)"
:class="{ nav_select1: item.is }"
v-for="(item, index) in navList"
:key="index"
>
{{ item.name }}
</view>
</view>
<view class="module_head">
<view>交易日期</view>
<view class="module_head_name">东财行业指数2级</view>
<view class="module_head_rank" @tap="marketRankSelect">
<view>板块排名</view>
<view class="module_head_icon" v-if="marketRank">
<image
src="../../../static/shengxu_true.png"
class="head_icon"
mode="scaleToFill"
/>
<image
src="../../../static/jiangxu_false.png"
class="head_icon"
mode="scaleToFill"
/>
</view>
<view class="module_head_icon" v-else>
<image
src="../../../static/shengxu_false.png"
class="head_icon"
mode="scaleToFill"
/>
<image
src="../../../static/jiangxu_true.png"
class="head_icon"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view v-if="list.length > 0">
<view
class="module_list"
v-for="(item, index) in list"
:key="index"
@tap="
toTrendDetail(
item.securityName,
item.securityCode,
item.securityType
)
"
>
<view class="module_list_date">{{ item.businessDate }}</view>
<view class="module_list_name">{{ item.securityName }}</view>
<view class="module_list_ranking">
<view>
{{ item.sort }}
</view>
<view class="list_ranking_right">
<image
v-if="item.sortChange > 0"
src="../../../static/home_paiming_shangsheng.png"
class="module_list_icon"
mode="scaleToFill"
/>
<image
v-if="item.sortChange < 0"
src="../../../static/home_paiming_xiajiang.png"
class="module_list_icon"
mode="scaleToFill"
/>
<u-icon
name="minus"
v-if="item.sortChange == 0"
size="12"
></u-icon>
<view
v-if="item.sortChange != 0"
class="rise_decline"
:style="{ color: item.color }"
>
{{ Math.abs(item.sortChange) }}
</view>
</view>
</view>
</view>
</view>
<view v-else>
<u-empty
mode="data"
icon="http://cdn.uviewui.com/uview/empty/data.png"
marginTop="50"
>
</u-empty>
</view>
</view>
<!-- 选择时间 -->
<u-datetime-picker
:show="dateShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelDate"
@confirm="confirmDate"
></u-datetime-picker>
</view>
</template>
<script>
export default {
data() {
return {
navList: [
{
name: '当日趋势',
is: true,
current: 1,
},
{
name: '5日趋势',
is: false,
current: 5,
},
{
name: '10日趋势',
is: false,
current: 10,
},
{
name: '15日趋势',
is: false,
current: 15,
},
{
name: '20日趋势',
is: false,
current: 20,
},
{
name: '30日趋势',
is: false,
current: 30,
},
],
//
list: [],
// or
marketRank: true,
trendCurrent: 1,
date: '',
pagenum: 1,
last_page: null,
dateShow: false,
}
},
onLoad(options) {
this.date = options.date
this.rending()
},
onReachBottom() {
if (this.pagenum < this.last_page) {
this.getnewGoods()
}
},
methods: {
//
marketRankSelect() {
this.marketRank = !this.marketRank
this.rending()
},
//
selectTrend(name) {
this.navList.forEach(item => {
if (item.name === name) {
item.is = true
this.trendCurrent = item.current
this.rending()
} else {
item.is = false
}
})
},
rending() {
this.$api
.post('/stock/trendPlate', {
businessDate: this.date,
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: 'sort',
sortWay: this.marketRank ? 'asc' : 'desc',
},
trendType: this.trendCurrent,
})
.then(r => {
if (r) {
console.log(r.list)
this.list = r.list
this.last_page = r.totalPage
// this.data = r
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
rending1() {
this.$api
.post('/stock/trendPlate', {
businessDate: this.date,
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: 'sort',
sortWay: this.marketRank ? 'asc' : 'desc',
},
trendType: this.trendCurrent,
})
.then(r => {
if (r) {
console.log(r.list)
this.list = [...this.list, ...r.list]
this.last_page = r.totalPage
// this.data = r
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
getnewGoods() {
this.pagenum = this.pagenum + 1
// 1.loading
uni.showLoading({
title: '数据加载中...',
})
// 2.
this.isLoading = true
// 3.
this.rending1()
//
// 4.loading
uni.hideLoading()
// 5.
this.isLoading = false
},
toTrendDetail(name, id, type) {
uni.navigateTo({
url: `/pages/home/market/trendDetail?name=${name}&id=${id}&type=${type}&date=${this.date}`,
})
},
//
beforeDay(date) {
this.pagenum = 1
this.date = this.getTime(new Date(date).getTime() - 24 * 60 * 60 * 1000)
this.rending()
},
//
afterDay(date) {
this.pagenum = 1
this.date = this.getTime(new Date(date).getTime() + 24 * 60 * 60 * 1000)
this.rending()
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
//
selectDate() {
this.dateShow = true
uni.hideTabBar({})
},
//
cancelDate() {
this.dateShow = false
uni.showTabBar({})
},
//
confirmDate(e) {
this.pagenum = 1
this.$nextTick(() => {
this.date = this.getTime(e.value)
this.rending()
})
this.dateShow = false
uni.showTabBar({})
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 24rpx;
}
.nav {
display: flex;
align-items: center;
overflow-x: auto;
}
.nav_select {
flex-shrink: 0;
margin-top: 24rpx;
padding: 10rpx 20rpx;
border: 2rpx solid #999999;
border-radius: 8rpx;
margin-right: 20rpx;
font-size: 24rpx;
color: #999999;
}
.nav_select1 {
border-color: #ec7c00;
color: #ec7c00;
background-color: #fffcf9;
}
.module_head {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 24rpx;
font-size: 24rpx;
font-weight: bold;
padding: 20rpx 28rpx 20rpx 36rpx;
width: 686rpx;
margin-left: -24rpx;
background-color: #fff9f3;
.module_head_name {
margin-left: 64rpx;
}
.module_head_rank {
display: flex;
align-items: center;
}
.module_head_icon {
margin-left: 8rpx;
display: flex;
flex-direction: column;
.head_icon {
width: 18rpx;
height: 10rpx;
margin-top: 4rpx;
}
}
}
.module_list {
padding-top: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.module_list_date {
// margin-right: 120rpx;
}
.module_list_name {
width: 400rpx;
text-align: center;
// margin-left: 120rpx;
}
.module_list_ranking {
display: flex;
align-items: center;
margin-right: 16rpx;
}
.list_ranking_right {
margin-left: 24rpx;
display: flex;
align-items: center;
justify-content: center;
width: 40rpx;
.rise_decline {
font-size: 24rpx;
margin-left: 4rpx;
}
}
.module_list_icon {
text-align: center;
width: 18rpx;
height: 10rpx;
line-height: 10rpx;
font-size: 28rpx;
color: #999999;
}
}
.date {
display: flex;
align-items: center;
justify-content: flex-end;
.ipt_date {
width: 180rpx;
font-size: 24rpx;
text-align: center;
}
.date_icon {
width: 24rpx;
height: 24rpx;
}
}
</style>

@ -0,0 +1,232 @@
<template>
<view class="trend_detail">
<view class="private_table_head">
<view class="private_table_head_left">
<view class="private_head_name">股票名称</view>
<view class="private_head_price">价格</view>
<view class="private_head_gains">涨幅</view>
</view>
<view class="private_table_head_right">
<view>{{ currentBelong }}</view>
<!-- <image
src="../../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/> -->
</view>
</view>
<view class="private_table_list" v-for="(item, index) in list" :key="index">
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.name }}</view>
<view class="table_list_code">{{ item.code }}</view>
</view>
<view class="table_list_price" :style="{ color: item.color }">
{{ item.price }}
</view>
<view class="table_list_gains" :style="{ color: item.color }">
{{ item.gains }}
</view>
</view>
<view>{{ item.suoshu }}</view>
</view>
<u-picker
:show="showPrivateBelong"
:columns="columnsBelong"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelPrivateBelong"
@confirm="confirmPrivateBelong"
></u-picker>
</view>
</template>
<script>
export default {
data() {
return {
list: [
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
],
//
showPrivateBelong: false,
currentBelong: '所属板块',
columnsBelong: [['所属板块', '成交量']],
}
},
onLoad(options) {
uni.setNavigationBarTitle({
title: options.name,
})
},
methods: {
//
privateBelong() {
uni.hideTabBar({})
this.showPrivateBelong = true
},
//
cancelPrivateBelong() {
this.showPrivateBelong = false
uni.showTabBar({})
},
//
confirmPrivateBelong(e) {
this.currentBelong = e.value[0]
this.showPrivateBelong = false
uni.showTabBar({})
},
},
}
</script>
<style lang="scss" scoped>
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 200rpx;
}
.private_head_price {
width: 150rpx;
text-align: center;
}
.private_head_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 200rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 150rpx;
text-align: center;
}
.table_list_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,853 @@
<template>
<u-loading-page v-if="load" :loading="load"></u-loading-page>
<view class="market_index" v-else>
<view class="market_head" :class="{ market_head1: isUnfold }">
<view class="market_head_top">
<view class="closed_price" @tap="collection">
<view class="closed_price_top">
<view
class="closed_price_text colorGreen"
:class="{ colorRed: data.riseLossesCurrentDay > 0 }"
>{{ data.closingPrice }}</view
>
<u-icon v-if="!isCollection" name="star" size="20"></u-icon>
<u-icon v-else name="star-fill" size="20" color="#EC7C00"></u-icon>
</view>
<view
class="closed_price_bottom colorGreen"
:class="{ colorRed: data.riseLossesCurrentDay > 0 }"
>{{ data.cha.toFixed(2) }} [{{
data.riseLossesCurrentDay.toFixed(2)
}}%]</view
>
</view>
<view class="closed_opening">
<view style="margin-top: 4rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.openingPrice }}</text>
</view>
<view style="margin-top: 20rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.closingPrice }}</text>
</view>
</view>
<view class="quantity_quota" @tap="isUnfold = !isUnfold">
<view style="margin-top: 4rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.volume }}</text>
</view>
<view style="margin-top: 20rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.turnover }}</text>
</view>
</view>
<view @tap="isUnfold = !isUnfold">
<image
src="../../../static/zhan.png"
v-if="!isUnfold"
style="width: 32rpx; height: 32rpx"
mode="scaleToFill"
/>
<image
v-else
src="../../../static/show.png"
style="width: 32rpx; height: 32rpx"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view class="line"> </view>
<view style="height: 1100rpx; padding: 0 20rpx; width: 710rpx">
<l-echart ref="chart"></l-echart>
</view>
<view class="line_1"> </view>
<view class="footer">
<view>基本信息</view>
<view class="footer_list">
<view class="footer_list_left">首发上市日期</view>
<view>{{ data.initialListingDate }}</view>
</view>
<view class="footer_list">
<view class="footer_list_left">可交易日数</view>
<view>{{ data.numberDaysAvailable }}</view>
</view>
<view class="footer_list">
<view class="footer_list_left">机构持仓合计</view>
<view>{{ data.totalInstitutionalPositions }}</view>
</view>
<view class="footer_list">
<view class="footer_list_left">所属东财行业指数2级</view>
<view>汽车</view>
</view>
<view class="footer_list">
<view class="footer_list_left">所属东财行业指数3级</view>
<view>{{ data.dongCaiIndustryIndexLevel3 }}</view>
</view>
<view class="footer_list">
<view class="footer_list_left">所属东财行业指数代码</view>
<view>802030.EI</view>
</view>
</view>
<u-popup :show="isUnfold" mode="top">
<view class="market_head" :class="{ market_head1: isUnfold }">
<view class="market_head_top">
<view class="closed_price" @tap="collection">
<view class="closed_price_top">
<view
class="closed_price_text colorGreen"
:class="{ colorRed: data.riseLossesCurrentDay > 0 }"
>{{ data.closingPrice }}</view
>
<u-icon v-if="!isCollection" name="star" size="20"></u-icon>
<u-icon
v-else
name="star-fill"
size="20"
color="#EC7C00"
></u-icon>
</view>
<view
class="closed_price_bottom colorGreen"
:class="{ colorRed: data.riseLossesCurrentDay > 0 }"
>
{{ data.cha.toFixed(2) }} [{{
data.riseLossesCurrentDay.toFixed(2)
}}%]
</view>
</view>
<view class="closed_opening">
<view style="margin-top: 4rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.openingPrice }}</text>
</view>
<view style="margin-top: 20rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.closingPrice }}</text>
</view>
</view>
<view class="quantity_quota" @tap="isUnfold = !isUnfold">
<view style="margin-top: 4rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.volume }}</text>
</view>
<view style="margin-top: 20rpx">
<text class="head_text"></text>
<text class="head_num">{{ data.turnover }}</text>
</view>
</view>
<view @tap="isUnfold = !isUnfold">
<image
src="../../../static/zhan.png"
v-if="!isUnfold"
style="width: 32rpx; height: 32rpx"
mode="scaleToFill"
/>
<image
v-else
src="../../../static/show.png"
style="width: 32rpx; height: 32rpx"
mode="scaleToFill"
/>
</view>
</view>
<view class="market_head_bottom">
<view class="head_bottom_list">
<view class="security_code">
<view class="bottom_list_text"> 证券代码 </view>
<view class="bottom_list_num">{{ data.securityCode }}</view>
</view>
<view class="trade_date">
<view class="bottom_list_text"> 交易日 </view>
<view class="bottom_list_num">{{ data.businessDate }}</view>
</view>
<view class="opening_high">
<view class="bottom_list_text"> 最高 </view>
<view class="bottom_list_num">{{ data.highestPrice }}</view>
</view>
<view class="opening_less">
<view class="bottom_list_text"> 最低 </view>
<view class="bottom_list_num">{{ data.lowestPrice }}</view>
</view>
</view>
<view class="head_bottom_list">
<view class="security_code">
<view class="bottom_list_text"> 涨跌幅 </view>
<view class="bottom_list_num"
>{{ data.riseLossesCurrentDay.toFixed(2) }}%</view
>
</view>
<view class="trade_date">
<view class="bottom_list_text"> 10日涨跌幅 </view>
<view class="bottom_list_num"
>{{ data.rangeRiseLosses10.toFixed(2) }}%</view
>
</view>
<view class="opening_high">
<view class="bottom_list_text"> 20日涨跌幅 </view>
<view class="bottom_list_num"
>{{ data.rangeRiseLosses20.toFixed(2) }}%</view
>
</view>
<view class="opening_less">
<view class="bottom_list_text"> 60日涨跌幅 </view>
<view class="bottom_list_num"
>{{ data.rangeRiseLosses60.toFixed(2) }}%</view
>
</view>
</view>
<view class="head_bottom_list">
<view class="security_code">
<view class="bottom_list_text"> 流通 </view>
<view class="bottom_list_num">{{ data.freeCapitalization }}</view>
</view>
<view class="trade_date">
<view class="bottom_list_text"> 20日区间平均成交量 </view>
<view class="bottom_list_num">{{ data.averageVolumeDay20 }}</view>
</view>
</view>
</view>
</view>
</u-popup>
<!-- 个股所属板块 -->
<!-- <u-picker
:show="showPrivateBelong"
:columns="columnsBelong"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelPrivateBelong"
@confirm="confirmPrivateBelong"
></u-picker> -->
</view>
</template>
<script>
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
export default {
data() {
return {
isCollection: false,
isUnfold: false,
data: {},
load: true,
id: '',
}
},
onLoad(options) {
uni.setNavigationBarTitle({
title: options.name,
})
this.id = options.id
// this.rending(options.id)
},
mounted() {
this.$nextTick(() => {
// echarts
this.rending()
})
},
methods: {
rending(id) {
this.$api
.post('/stock/getByCode', {
businessDate: '',
securityCode: this.id,
})
.then(r => {
if (r) {
this.data = r
this.data.cha = this.data.closingPrice - this.data.openingPrice
this.load = false
this.$api
.post('/stock/kLine', {
securityCode: this.data.securityCode,
securityType: '',
})
.then(r => {
if (r) {
// this.data = r
console.log(r)
this.$refs.chart.init(echarts, chart => {
let upColor = '#ec0000'
let downColor = '#00da3c'
// (open)(close)(lowest)(highest)
let data = splitData(r)
function splitData(rawData) {
let categoryData = []
let values = []
let volumes = []
for (let i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0])
values.push(rawData[i])
volumes.push([
i,
rawData[i][4],
rawData[i][0] > rawData[i][1] ? 1 : -1,
])
}
return {
categoryData: categoryData,
values: values,
volumes: volumes,
}
}
function calculateMA(dayCount) {
let result = []
for (
let i = 0, len = data.values.length;
i < len;
i++
) {
if (i < dayCount) {
result.push('-')
continue
}
let sum = 0
for (let j = 0; j < dayCount; j++) {
sum += data.values[i - j][1]
}
result.push(sum / dayCount)
}
return result
}
let option = {
animation: false,
legend: {
top: 10,
left: 'center',
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30'],
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
},
formatter: function (param) {
// let param1 = param[1];
if (param[0].data.length < 6) {
param = param[1]
console.log(param)
return [
'日期: ' + param.axisValue + '\n',
'开盘: ' + param.data[1] + '\n',
'关盘: ' + param.data[2] + '\n',
'最低: ' + param.data[3] + '\n',
'最高: ' + param.data[4] + '\n',
'成交额: ' + param.data[5] + '\n',
].join('')
} else {
param = param[0]
console.log(param)
return [
'日期: ' + param.axisValue + '\n',
'开盘: ' + param.data[1] + '\n',
'关盘: ' + param.data[2] + '\n',
'最低: ' + param.data[3] + '\n',
'最高: ' + param.data[4] + '\n',
'成交额: ' + param.data[5] + '\n',
].join('')
}
},
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
textStyle: {
color: '#000',
},
position: function (pos, params, el, elRect, size) {
const obj = {
top: 10,
}
obj[
['left', 'right'][
+(pos[0] < size.viewSize[0] / 2)
]
] = 30
return obj
},
// extraCssText: 'width: 170px'
},
axisPointer: {
link: [
{
xAxisIndex: 'all',
},
],
label: {
backgroundColor: '#777',
},
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: false,
},
brush: {
type: ['lineX', 'clear'],
},
},
},
brush: {
xAxisIndex: 'all',
brushLink: 'all',
outOfBrush: {
colorAlpha: 0.1,
},
},
visualMap: {
show: false,
seriesIndex: 5,
dimension: 2,
pieces: [
{
value: 1,
color: upColor,
},
{
value: -1,
color: downColor,
},
],
},
grid: [
{
left: '10%',
right: '8%',
height: '50%',
},
{
left: '10%',
right: '8%',
top: '63%',
height: '16%',
},
],
xAxis: [
{
type: 'category',
data: data.categoryData,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax',
axisPointer: {
z: 100,
},
},
{
type: 'category',
gridIndex: 1,
data: data.categoryData,
boundaryGap: false,
axisLine: { onZero: false },
axisTick: { show: false },
splitLine: { show: false },
axisLabel: { show: false },
min: 'dataMin',
max: 'dataMax',
},
],
yAxis: [
{
scale: true,
splitArea: {
show: true,
},
},
{
scale: true,
gridIndex: 1,
splitNumber: 2,
axisLabel: { show: false },
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: false },
},
],
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 1],
start: 0,
end: 100,
},
{
show: true,
xAxisIndex: [0, 1],
type: 'slider',
top: '85%',
start: 0,
end: 100,
},
],
series: [
{
name: '日K',
type: 'candlestick',
data: data.values,
itemStyle: {
color: downColor,
color0: upColor,
borderColor: undefined,
borderColor0: undefined,
},
tooltip: {
formatter: function (param) {
console.log(param)
param = param[0]
return [
'Date: ' +
param.name +
'<hr size=1 style="margin: 3px 0">',
'开盘: ' + param.data[0] + '<br/>',
'Close: ' + param.data[1] + '<br/>',
'Lowest: ' + param.data[2] + '<br/>',
'Highest: ' + param.data[3] + '<br/>',
].join('')
},
},
},
{
name: 'MA5',
type: 'line',
data: calculateMA(5, data),
smooth: true,
lineStyle: {
opacity: 0.5,
},
},
{
name: 'MA10',
type: 'line',
data: calculateMA(10, data),
smooth: true,
lineStyle: {
opacity: 0.5,
},
},
{
name: 'MA20',
type: 'line',
data: calculateMA(20, data),
smooth: true,
lineStyle: {
opacity: 0.5,
},
},
{
name: 'MA30',
type: 'line',
data: calculateMA(30, data),
smooth: true,
lineStyle: {
opacity: 0.5,
},
},
{
name: 'Volume',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
itemStyle: {
// normal: {
// color: function (param) {
// return downColor;
// },
// },
},
data: data.volumes,
},
],
}
chart.setOption(option)
})
}
})
.catch(fall => {
console.log(fall)
})
this.queryCollection()
// this.data = r
// this.privateList = r.list
// console.log(this.privateList)
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
//
queryCollection() {
this.$api
.post('/collect/queryIsCollect', {
securityCode: this.id,
})
.then(r => {
if (r) {
r == 1 ? (this.isCollection = true) : (this.isCollection = false)
}
})
.catch(fall => {
console.log(fall)
})
},
//
selectNav(name) {
this.showLoad = true
this.navList.forEach((item, index) => {
if (item.name == name) {
item.is = true
setTimeout(() => {
this.showLoad = false
}, 1000)
} else {
item.is = false
}
})
},
//
collection() {
if (this.isCollection) {
this.$api
.post('/collect/del', {
securityCode: this.data.securityCode,
securityType: this.data.securityType,
})
.then(r => {
// if (r.code == 200) {
uni.$u.toast('已取消收藏')
this.isCollection = false
// }
})
.catch(fall => {
uni.$u.toast('已取消收藏')
this.isCollection = false
console.log(fall)
})
} else {
this.$api
.post('/collect/add', {
securityCode: this.data.securityCode,
securityType: this.data.securityType,
})
.then(r => {
// if (r.code == 200) {
uni.$u.toast('收藏成功')
this.isCollection = true
// }
})
.catch(fall => {
uni.$u.toast('收藏成功')
this.isCollection = true
console.log(fall)
})
}
},
initEcharts() {},
},
}
</script>
<style lang="scss" scoped>
.show_load {
margin-top: 100rpx;
}
.market_head {
padding: 32rpx 24rpx 0 24rpx;
height: 100rpx;
width: 702rpx;
overflow: hidden;
.closed_price {
font-size: 24rpx;
.closed_price_top {
display: flex;
font-size: 40rpx;
}
}
.closed_price_text {
margin-right: 24rpx;
font-weight: bold;
}
.closed_price_bottom {
margin-top: 10rpx;
}
}
.market_head1 {
height: 100%;
}
.market_head_top {
display: flex;
align-items: center;
justify-content: space-between;
}
.market_head_bottom {
padding-bottom: 32rpx;
}
.head_bottom_list {
margin-top: 32rpx;
display: flex;
align-items: center;
.security_code {
width: 158rpx;
border-right: 2rpx dashed #c8c8c8;
}
.trade_date {
width: 208rpx;
border-right: 2rpx dashed #c8c8c8;
margin-left: 20rpx;
}
.opening_high {
border-right: 2rpx dashed #c8c8c8;
margin-left: 20rpx;
width: 160rpx;
}
.opening_less {
margin-left: 20rpx;
}
.bottom_list_text {
font-size: 24rpx;
color: #999999;
}
.bottom_list_num {
margin-top: 8rpx;
font-size: 28rpx;
}
}
.closed_opening {
font-size: 28rpx;
}
.quantity_quota {
font-size: 28rpx;
}
.head_text {
color: #999999;
}
.head_num {
margin-left: 16rpx;
}
.line {
height: 2rpx;
background-color: #f6f6f6;
margin-top: 32rpx;
}
.nav_list {
padding: 32rpx 24rpx;
color: #999999;
.nav_list_text {
margin-right: 32rpx;
}
.nav_list_text1 {
font-weight: bold;
color: #333333;
}
}
.line_1 {
height: 20rpx;
background-color: #f6f6f6;
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 200rpx;
}
.private_head_price {
width: 150rpx;
text-align: center;
}
.private_head_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 200rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 150rpx;
text-align: center;
}
.table_list_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.list_footer {
padding: 32rpx 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #ec7c00;
.see_more {
display: flex;
align-items: center;
.see_more_icon {
width: 22rpx;
height: 22rpx;
margin-left: 10rpx;
}
}
}
.footer {
padding: 32rpx 24rpx;
font-weight: bold;
padding-bottom: 100rpx;
.footer_list {
padding-top: 32rpx;
font-size: 28rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: space-between;
.footer_list_left {
color: #666666;
}
}
}
.colorGreen {
color: #6fbb60;
}
.colorRed {
color: red;
}
</style>

@ -0,0 +1,185 @@
<template>
<view>
<view class="center">
<view class="serch">
<u-input
placeholder="请输入个股代码、板块或名称"
v-model="serchValue"
prefixIcon="search"
prefixIconStyle="font-size: 22px;color: #909399"
shape="circle"
@input="change"
fontSize="24rpx"
style="margin-right: "
></u-input>
<view class="serch_text" @tap="submit"></view>
</view>
<!-- <view
class="serch_list"
v-for="(item, index) in serchList"
:key="index"
@tap="detail(item)"
>
<image
src="../../../static/serch.png"
mode="scaleToFill"
style="width: 26rpx; height: 26rpx"
/>
<view style="margin-left: 10rpx">{{ item.name }}</view>
</view> -->
</view>
<view class="table_head" v-if="this.list.length > 0">
<view class="head_code">股票代码</view>
<view class="head_name">股票名称</view>
<view class="head_price">价格</view>
<view class="head_gains">涨幅</view>
</view>
<view class="table_list" v-for="(item, index) in list" :key="index">
<view>{{ item.securityCode }}</view>
<view>{{ item.securityName }}</view>
<view
class="list_price"
:class="{ list_price1: item.riseLossesCurrentDay < 0 }"
>{{ item.closingPrice }}</view
>
<view
class="list_price"
:class="{ list_price1: item.riseLossesCurrentDay < 0 }"
>{{ item.riseLossesCurrentDay.toFixed(2) }}</view
>
</view>
</view>
</template>
<script>
export default {
data() {
return {
serchValue: '',
serchList: [],
list: [],
}
},
methods: {
change() {
// this.list = []
// this.$api
// .post('/getHomeInfo', {
// keyword: this.serchValue,
// })
// .then(r => {
// if (r) {
this.serchList = []
// }
// })
if (this.serchValue.length == 0) {
this.serchList = []
}
},
detail(item) {
this.serchList = []
// this.$api.post('/getHomeInfo', {}).then(r => {
// if (r) {
// this.isMarket = false
// this.list = r
// this.list.forEach(item => {})
// this.list = [...this.list]
// this.showLoad = false
// }
// })
},
submit() {
console.log(111)
this.$api
.post('/stock/originalIssueStockDetail', {
businessDate: '',
keyWord: this.serchValue,
market: '',
pageModel: {
pageNo: 1,
pageSize: 30,
sortField: '',
sortWay: '',
},
})
.then(r => {
if (r) {
// this.data = r
this.list = r.list
}
})
.catch(fall => {
console.log(fall)
})
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 0 24rpx;
}
.serch {
position: relative;
}
.serch_text {
position: absolute;
right: 0;
top: 0;
width: 120rpx;
height: 75rpx;
background-color: #ec7c00;
color: white;
border-radius: 36rpx;
text-align: center;
line-height: 75rpx;
font-size: 28rpx;
font-weight: bold;
}
/deep/.u-border {
border-color: #ec7c00 !important;
}
.serch_list {
padding: 32rpx 0;
display: flex;
align-items: center;
font-size: 24rpx;
border-bottom: 1px solid #cfcfcf;
}
.table_head {
padding: 20rpx 24rpx;
background-color: #fff9f3;
font-size: 24rpx;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 34rpx;
}
.table_head view {
width: 140rpx;
text-align: center;
}
.table_list {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 24rpx 0 24rpx;
font-size: 28rpx;
}
.table_list view {
text-align: center;
width: 140rpx;
}
.list_price {
color: #d9001b;
}
.list_price1 {
color: #6fbb60;
}
/deep/ .u-input__content__field-wrapper {
margin-right: 120rpx !important;
}
</style>

@ -0,0 +1,148 @@
<template>
<view class="login">
<view class="center">
<view class="logo_box">
<image
src="../../static/logo.png"
style="width: 200rpx; height: 200rpx"
mode="scaleToFill"
/>
</view>
<!-- <button class="submit_weixin btn" @tap="getPhoneNumber"></button> -->
<!-- open-type="getPhoneNumber" -->
<!-- @getphonenumber="getPhoneNumber" -->
<button class="btn submit_phone" @tap="toPhone">/</button>
<!-- <button class="btn submit_phone">游客登陆</button> -->
<view class="protocol">
<image
v-if="!isChoose"
src="../../static/login_xuanze.png"
mode="scaleToFill"
style="width: 40rpx; height: 40rpx"
@tap="isChoose = !isChoose"
/>
<image
v-if="isChoose"
src="../../static/login_xuanze_true.png"
mode="scaleToFill"
style="width: 40rpx; height: 40rpx"
@tap="isChoose = !isChoose"
/>
<view class="protocolText" @tap.stop="isChoose = !isChoose">
我已阅读并同意
<view @tap.stop="toWeb(1)" style="color: #62afed">用户协议</view>
<view @tap.stop="toWeb(2)" style="color: #62afed">隐私政策</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
//
isChoose: true,
}
},
onLoad() {},
methods: {
//
getPhoneNumber(e) {
console.log(e)
if (this.isChoose) {
// uni.navigateTo({
// url: `/pages/index/enroll`,
// })
// this.$api
// .post('/phoneLogin', {
// openid: this.$store.state.WXcode.openid,
// session_key: this.$store.state.WXcode.session_key,
// code: e.detail.code,
// })
// .then(r => {
// if (r) {
uni.switchTab({
url: `/pages/home/home`,
})
// }
// })
} else {
uni.$u.toast('请先同意协议')
}
// uni.switchTab({
// url: `/pages/home/home`,
// })
},
//
toWeb() {
uni.navigateTo({
url: `/pages/index/webview?src=`,
})
},
//
submitWX() {},
//
toPhone() {
uni.navigateTo({
url: `/pages/index/phoneLogin`,
})
},
},
}
</script>
<style lang="scss" scoped>
.protocol {
padding: 0 30rpx;
position: fixed;
display: flex;
bottom: 60rpx;
margin-top: 80rpx;
align-items: center;
.protocolText {
display: flex;
margin-left: 16rpx;
font-size: 24rpx;
text {
color: #6678d7;
}
}
}
.logo_box {
display: flex;
align-items: center;
justify-content: center;
}
.center {
margin-top: 320rpx;
padding: 24rpx;
}
.btn {
height: 88rpx;
border-radius: 40rpx;
font-size: 28rpx;
text-align: center;
line-height: 88rpx;
border: 0;
}
.submit_weixin {
margin-top: 140rpx;
background-color: #3478ff;
color: white;
}
.submit_phone {
margin-top: 48rpx;
background-color: white;
border: 2rpx solid #d2d2d2;
}
uni-button:after {
border: 0;
}
button::after {
border: 0;
}
</style>

@ -0,0 +1,219 @@
<template>
<view class="phone_login">
<view class="center">
<view class="title">手机号登录/注册</view>
<view class="ipt_box">
<u-input
placeholder="请输入手机号"
v-model="phone"
border="bottom"
type="number"
fontSize="32rpx"
clearable
></u-input>
<view style="margin-top: 50rpx">
<u-input
placeholder="请输入密码"
v-model="password"
border="bottom"
type="password"
fontSize="32rpx"
clearable
></u-input>
<!-- <u-input
border="bottom"
clearable
placeholder="请输入验证码"
v-model="value"
fontSize="32rpx"
>
<template slot="suffix">
<u-code
ref="uCode"
@change="codeChange"
seconds="60"
changeText="Xs"
></u-code>
<u-button
@tap="getCode"
:text="tips"
class="custom-style"
:plain="true"
size="mini"
></u-button>
</template>
</u-input> -->
</view>
</view>
<view class="btn_box" @tap="submit">
<button class="btn">登录</button>
</view>
<view class="login_tips">未注册的账号第一次登陆时自动注册账号</view>
<view class="protocol">
<image
v-if="!isChoose"
src="../../static/login_xuanze.png"
mode="scaleToFill"
style="width: 40rpx; height: 40rpx"
@tap="isChoose = !isChoose"
/>
<image
v-if="isChoose"
src="../../static/login_xuanze_true.png"
mode="scaleToFill"
style="width: 40rpx; height: 40rpx"
@tap="isChoose = !isChoose"
/>
<view class="protocolText" @tap.stop="isChoose = !isChoose">
我已阅读并同意
<view @tap.stop="toWeb(1)" style="color: #62afed">用户协议</view>
<view @tap.stop="toWeb(2)" style="color: #62afed">隐私政策</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
tips: '',
//
value: '',
//
phone: '',
//
isChoose: true,
//
value1: '',
password: '',
}
},
methods: {
//
codeChange(text) {
this.tips = text
},
//
getCode() {
if (this.$refs.uCode.canGetCode) {
if (this.phone) {
//
uni.showLoading({
title: '正在获取验证码',
})
setTimeout(() => {
uni.hideLoading()
// this.start()
uni.$u.toast('验证码已发送')
//
this.$refs.uCode.start()
}, 2000)
this.$api.post('/login/sendSms', { phone: this.phone })
} else {
uni.$u.toast('请先输入手机号')
}
} else {
uni.$u.toast('倒计时结束后再发送')
}
},
submit() {
if (this.isChoose) {
if (this.phone && this.password) {
this.$cache.set('gupiao_phone',this.phone )
this.$api
.post('/user/login/smsCodeLogin', {
phone: this.phone,
createWay: 1,
})
.then(r => {
if (r) {
let re = r
this.$cache.set('token', re)
uni.switchTab({
url: `/pages/home/home`,
})
}
})
// console.log(res.code)
//
} else {
uni.$u.toast('请先输入手机号和密码')
}
} else {
uni.$u.toast('请先同意协议')
}
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 0 24rpx;
}
.title {
margin-top: 120rpx;
font-size: 44rpx;
font-weight: bold;
}
.ipt_box {
margin-top: 100rpx;
}
.custom-style {
color: #6195fe;
text-align: center;
}
/deep/.u-button--plain.u-button--info {
color: #6195fe !important;
border: 0 !important;
font-size: 26rpx;
}
/deep/.u-button--mini {
font-size: 32rpx !important;
}
/deep/.u-input--no-radius {
padding: 24rpx 18rpx !important;
}
.btn_box {
margin-top: 96rpx;
}
.btn {
height: 88rpx;
border-radius: 40rpx;
font-size: 28rpx;
text-align: center;
line-height: 88rpx;
border: 0;
background-color: #3478ff;
color: white;
}
.protocol {
padding: 0 30rpx;
position: fixed;
display: flex;
bottom: 60rpx;
margin-top: 80rpx;
align-items: center;
.protocolText {
display: flex;
margin-left: 16rpx;
font-size: 24rpx;
text {
color: #6678d7;
}
}
}
.login_tips {
color: #999999;
font-size: 24rpx;
margin-top: 24rpx;
text-align: center;
}
/deep/.u-number-box {
align-items: start !important;
}
</style>

@ -0,0 +1,776 @@
<template>
<view class="trade">
<view class="head">
<view class="head_left">
<view class="head_date">
<image
src="../../static/home_left.png"
class="date_icon"
mode="scaleToFill"
@tap="beforeDay(date)"
/>
<input
type="text"
v-model="date"
disabled
class="ipt_date"
@tap="selectDate"
/>
<image
src="../../static/home_right.png"
class="date_icon"
mode="scaleToFill"
@tap="afterDay(date)"
/>
</view>
<view class="select_days" @tap="RangeSelect">
<view>{{ timeRange }}</view>
<image
src="../../static/jiangxu_false.png"
class="select_days_icon"
mode="scaleToFill"
/>
</view>
</view>
<image
@tap="selectSift"
src="../../static/home_sift.png"
class="head_icon"
mode="scaleToFill"
/>
</view>
<view class="table_head">
<view class="table_head_left">
<view class="table_head_name">名称/时间</view>
<view class="table_head_clinchMoney">成交价</view>
<view class="table_head_clinchNum">成交量</view>
</view>
<view>类别/金额</view>
</view>
<view class="table_center">
<view v-if="list.length > 0">
<view
class="table_main"
v-for="(item, index) in list"
:key="index"
@tap="toDetail(item.id)"
>
<view class="table_left">
<view class="table_name_date">
<view class="table_name">{{ item.securityName }}</view>
<view class="table_date">{{ item.transactionDate }}</view>
</view>
<view class="table_clinchMoney">
{{ item.transactionPrice }}
</view>
<view class="table_clinchNum">
{{ item.volume }}
</view>
</view>
<view class="table_type_money">
<view>{{ item.securityType }}</view>
<view class="table_money">{{ item.transactionAmount }}</view>
</view>
</view>
</view>
<view v-else>
<u-empty
mode="data"
icon="http://cdn.uviewui.com/uview/empty/data.png"
marginTop="50"
>
</u-empty>
</view>
</view>
<view class="add_icon_box" @tap="addInfo">
<u-icon name="plus" color="#ffffff" size="28"></u-icon>
</view>
<!-- 筛选弹出层 -->
<u-popup :show="showSift" mode="top">
<view class="sift_show_type">
<view>交易类型</view>
<view class="show_trade_type">
<view
class="trade_type"
:class="{ trade_type1: isSecurities }"
@tap="isSecurities = true"
>
证券买入
</view>
<view
class="trade_type"
:class="{ trade_type1: !isSecurities }"
@tap="isSecurities = false"
>
证券卖出
</view>
</view>
</view>
<view class="sift_show_date">
<view style="font-weight: bold">时间段</view>
<view class="show_date_range">
<u-input
placeholder="请选择开始日期"
disabled
border="surround"
v-model="startTime"
inputAlign="center"
fontSize="12"
disabledColor="#ffffff"
@tap="selectStartTime"
></u-input>
<u-icon name="minus" size="12" style="padding: 0 16rpx"></u-icon>
<u-input
disabled
placeholder="请选择截至日期"
disabledColor="#ffffff"
border="surround"
v-model="endTime"
inputAlign="center"
fontSize="12"
@tap="selectEndTime"
></u-input>
</view>
</view>
<view class="show_securities_code">
<view style="font-weight: bold">证券代码</view>
<view class="securities_code">
<u-input
placeholder="请输入证券代码"
border="surround"
v-model="securitiesCode"
fontSize="12"
></u-input>
</view>
</view>
<view class="show_btn_box">
<view class="btn show_cancel" @tap="cancelShowSift"></view>
<view class="btn show_confirm" @tap="confirmShowSift"></view>
</view>
</u-popup>
<!-- 筛选/开始时间选择 -->
<u-datetime-picker
:show="startTimeShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="startTimeShow = false"
@confirm="confirmStartTime"
></u-datetime-picker>
<!-- 筛选/结束时间选择 -->
<u-datetime-picker
:show="endTimeShow"
v-model="date"
mode="date"
:minDate="minDate"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="endTimeShow = false"
@confirm="confirmEndTime"
></u-datetime-picker>
<!-- 录入信息弹出层 -->
<u-popup :show="showInput" mode="bottom">
<view class="show_input_list" @tap="toInfo"> </view>
<view class="show_input_list" @tap="daoru"> </view>
<view
class="show_input_list"
style="background-color: #f6f6f6"
@tap="cancelInput"
>
取消
</view>
</u-popup>
<!-- 时间段选择 -->
<u-picker
:show="timeRangeShow"
:columns="columns"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelRange"
@confirm="confirmRange"
></u-picker>
<!-- 选择时间 -->
<u-datetime-picker
:show="dateShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="cancelDate"
@confirm="confirmDate"
></u-datetime-picker>
</view>
</template>
<script>
import config from '@/config'
export default {
data() {
return {
//
dateShow: false,
date: '',
//
timeRangeShow: false,
timeRange: '近7天',
columns: [['近7天', '近30天']],
//
showInput: false,
//
showSift: false,
// or
isSecurities: true,
// /
startTime: '',
//
startTimeShow: false,
//
endTimeShow: false,
//
minDate: null,
// /
endTime: '',
//
securitiesCode: '',
list: [],
pagenum: 1,
last_page: null,
}
},
onLoad(options) {
this.date = this.getTime(Date.parse(new Date()))
},
onShow() {
this.rending()
},
onReachBottom() {
if (this.pagenum < this.last_page) {
this.getnewGoods()
}
},
methods: {
daoru() {
let that = this
wx.chooseMessageFile({
count: 1, //
type: 'file', //,all
//type:'video',//
//type:'image',//
success(res) {
console.log(res)
res.tempFiles.forEach((item, index) => {
let str = item.path
let i = str.indexOf('.')
let result = str.substr(i + 1, str.length)
console.log(result)
if (result == 'xlsx' || result == 'xls') {
uni.uploadFile({
url: config.server + '/import/transactionRecord',
filePath: item.path,
name: 'file',
// header: {
// "X-Token": "Bearer " + store.state.app.token,
// },
// formData: {
// month: that.date,
// },
success: uploadFileRes => {
that.rending()
that.showInput = false
uni.showTabBar({})
uni.showToast({
title: '导入成功',
icon: 'none',
})
},
fail: err => {
console.log(err)
},
})
} else {
uni.showToast({
title: '暂只支持excel文件',
icon: 'none',
})
}
})
},
})
},
rending() {
this.$api
.post('/transaction/findPage', {
endTime: this.endTime,
keyWord: this.securitiesCode,
num: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
startTime: this.startTime,
transactionCategory: this.isSecurities ? '证券买入' : '证券卖出',
transactionDate: this.date,
})
.then(r => {
if (r) {
this.list = r.list
this.last_page = r.totalPage
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
rending1() {
this.$api
.post('/transaction/findPage', {
endTime: this.endTime,
keyWord: this.securitiesCode,
num: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
startTime: this.startTime,
transactionCategory: this.isSecurities ? '证券买入' : '证券卖出',
transactionDate: this.endTime ? this.date : '',
})
.then(r => {
if (r) {
this.list = [...this.list, ...r.list]
this.last_page = r.totalPage
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
//
selectDate() {
this.dateShow = true
uni.hideTabBar({})
},
//
cancelDate() {
this.dateShow = false
uni.showTabBar({})
},
//
confirmDate(e) {
this.pagenum = 1
this.$nextTick(() => {
this.date = this.getTime(e.value)
this.rending()
})
this.dateShow = false
uni.showTabBar({})
},
//
selectSift() {
uni.hideTabBar({})
this.showSift = true
},
//
cancelShowSift() {
this.startTimeShow = false
this.endTimeShow = false
uni.showTabBar({})
this.showSift = false
},
//
confirmShowSift() {
this.pagenum = 1
this.$api
.post('/transaction/findPage', {
endTime: this.endTime,
keyWord: this.securitiesCode,
num: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
startTime: this.startTime,
transactionCategory: this.isSecurities ? '证券买入' : '证券卖出',
transactionDate: '',
})
.then(r => {
if (r) {
this.list = r.list
uni.showTabBar({})
this.showSift = false
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
//
confirmStartTime(e) {
this.$nextTick(() => {
this.minDate = new Date(e.value).getTime()
console.log(this.minDate)
this.startTime = this.getTime(e.value)
})
this.startTimeShow = false
},
//
confirmEndTime(e) {
this.$nextTick(() => {
this.endTime = this.getTime(e.value)
})
this.endTimeShow = false
},
//
selectStartTime() {
if (!this.endTimeShow) {
this.startTimeShow = true
}
},
//
selectEndTime() {
if (this.startTime) {
if (!this.startTimeShow) {
this.endTimeShow = true
}
} else {
uni.showToast({
title: '请先选择开始时间',
icon: 'none',
})
}
},
//
addInfo() {
uni.hideTabBar({})
this.showInput = true
},
//
cancelInput() {
this.showInput = false
uni.showTabBar({})
},
//
RangeSelect() {
uni.hideTabBar({})
this.timeRangeShow = true
},
//
confirmRange(e) {
this.timeRange = e.value[0]
this.$api
.post('/transaction/findPage', {
endTime: '',
keyWord: '',
num: this.timeRange == '近7天' ? 7 : 30,
pageModel: {
pageNo: 1,
pageSize: 20,
sortField: '',
sortWay: '',
},
startTime: '',
transactionCategory: '',
transactionDate: '',
})
.then(r => {
if (r) {
this.list = r.list
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
this.timeRangeShow = false
uni.showTabBar({})
},
//
cancelRange() {
this.timeRangeShow = false
uni.showTabBar({})
},
//
toDetail(id) {
uni.navigateTo({
url: `/pages/trade/tradeDateil?id=${id}`,
})
},
//
toInfo() {
this.showInput = false
uni.showTabBar({})
uni.navigateTo({
url: '/pages/trade/tradeInfo',
})
},
//
beforeDay(date) {
this.pagenum = 1
this.endTime = ''
this.startTime = ''
this.date = this.getTime(new Date(date).getTime() - 24 * 60 * 60 * 1000)
this.rending()
},
//
afterDay(date) {
this.pagenum = 1
this.endTime = ''
this.startTime = ''
this.date = this.getTime(new Date(date).getTime() + 24 * 60 * 60 * 1000)
this.rending()
},
getnewGoods() {
this.pagenum = this.pagenum + 1
// 1.loading
uni.showLoading({
title: '数据加载中...',
})
// 2.
this.isLoading = true
// 3.
this.rending1()
//
// 4.loading
uni.hideLoading()
// 5.
this.isLoading = false
},
},
}
</script>
<style lang="scss" scoped>
.head {
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.head_left {
display: flex;
align-items: center;
.head_date {
padding: 16rpx 32rpx;
border-radius: 8rpx;
border: 2rpx solid #ec7c00;
display: flex;
align-items: center;
.ipt_date {
color: #ec7c00;
width: 180rpx;
font-size: 24rpx;
text-align: center;
}
.date_icon {
width: 24rpx;
height: 24rpx;
}
}
.select_days {
margin-left: 40rpx;
padding: 16rpx 32rpx;
border-radius: 8rpx;
border: 2rpx solid #999999;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.select_days_icon {
margin-left: 40rpx;
width: 18rpx;
height: 10rpx;
}
}
}
.head_icon {
height: 40rpx;
width: 40rpx;
}
}
.sift_show_type {
font-size: 28rpx;
font-weight: bold;
padding: 16rpx 24rpx;
}
.show_trade_type {
display: flex;
align-items: center;
flex-shrink: 0;
.trade_type {
padding: 12rpx 40rpx;
border: 2rpx solid #999999;
border-radius: 8rpx;
margin-right: 40rpx;
font-size: 24rpx;
color: #999999;
font-weight: 500;
margin-top: 16rpx;
}
.trade_type1 {
border-color: #ec7c00;
color: #ec7c00;
background-color: #fffcf9;
}
}
.sift_show_date {
padding: 24rpx;
font-size: 28rpx;
.show_date_range {
margin-top: 16rpx;
display: flex;
align-items: center;
}
}
/deep/.u-icon--right {
padding: 0 16rpx !important;
}
.show_securities_code {
padding: 0 24rpx;
font-size: 28rpx;
.securities_code {
margin-top: 16rpx;
margin-bottom: 80rpx;
}
}
.show_btn_box {
height: 88rpx;
display: flex;
align-items: center;
.btn {
width: 374rpx;
height: 88rpx;
line-height: 88rpx;
text-align: center;
font-size: 28rpx;
}
.show_cancel {
border-top: 2rpx solid #f6f6f6;
}
.show_confirm {
width: 378rpx;
background-color: #ec7c00;
color: white;
}
}
.table_head {
padding: 20rpx 24rpx;
background-color: #fff9f3;
display: flex;
align-items: center;
// justify-content: space-between;
font-size: 24rpx;
font-weight: bold;
justify-content: space-between;
.table_head_left {
display: flex;
align-items: center;
.table_head_name {
width: 200rpx;
}
.table_head_clinchMoney {
width: 170rpx;
text-align: center;
}
.table_head_clinchNum {
width: 170rpx;
text-align: center;
}
}
}
.table_center {
padding: 0 24rpx;
.table_main {
padding: 24rpx 0;
font-size: 28rpx;
padding-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
.table_left {
display: flex;
align-items: center;
}
.table_name_date {
.table_date {
font-size: 24rpx;
color: #999999;
margin-top: 10rpx;
}
}
.table_name {
width: 200rpx;
}
.table_type_money {
text-align: center;
.table_money {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
}
.table_clinchMoney {
width: 170rpx;
text-align: center;
}
.table_clinchNum {
width: 170rpx;
text-align: center;
}
}
}
.add_icon_box {
width: 104rpx;
height: 104rpx;
background: linear-gradient(132deg, #ffb564 0%, #ec7c00 100%);
position: fixed;
border-radius: 104rpx;
bottom: 56rpx;
right: 24rpx;
display: flex;
align-items: center;
justify-content: center;
}
.show_input_list {
padding: 40rpx 0rpx;
border-bottom: 2rpx solid #f6f6f6;
text-align: center;
font-size: 28rpx;
}
</style>

@ -0,0 +1,152 @@
<template>
<view class="trade_dateil">
<view class="securities_info">
<view class="list">
<view class="list_left">证券名称</view>
<view>{{ data.securityName }}</view>
</view>
<view class="list">
<view class="list_left">证券代码</view>
<view>{{ data.securityCode }}</view>
</view>
</view>
<view class="clinch_info">
<view class="list">
<view class="list_left">交易类别</view>
<view>{{ data.securityType }}</view>
</view>
<view class="list">
<view class="list_left">成交价格</view>
<view>{{ data.transactionPrice }}</view>
</view>
<view class="list">
<view class="list_left">成交数量</view>
<view>{{ data.volume }}</view>
</view>
<view class="list">
<view class="list_left">成交金额</view>
<view>{{ data.transactionAmount }}</view>
</view>
<view class="list">
<view class="list_left" style="margin-right: 140rpx">手续费</view>
<view>{{ data.premium }}</view>
</view>
<view class="list">
<view class="list_left">手续费率</view>
<view>{{ data.premiumRatio }}%</view>
</view>
<view class="list">
<view class="list_left">成交日期</view>
<view>{{ data.transactionDate }}</view>
</view>
<view class="list">
<view class="list_left">成交时间</view>
<view>{{ data.transactionTime }}</view>
</view>
</view>
<view class="footer">
<button class="btn" @tap="del"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
data: {},
}
},
onLoad(options) {
this.rending(options.id)
},
methods: {
rending(id) {
this.$api
.get('/transaction/getDetailById/' + id)
.then(r => {
if (r) {
this.data = r
console.log(r, '获取数据')
}
})
.catch(fall => {
console.log(fall)
})
},
del() {
this.$api
.post('/transaction/delByIds', {
ids: this.data.id,
})
.then(r => {
if (r) {
uni.showToast({
title: '删除成功',
icon: 'success',
duration: 1000,
})
setTimeout(() => {
uni.navigateBack({
delta: 1,
})
}, 1000)
}
})
.catch(fall => {
console.log(fall)
})
// delByIds
},
},
}
</script>
<style lang="scss" scoped>
.securities_info {
padding: 32rpx 24rpx 0 24rpx;
background-color: white;
margin-top: 20rpx;
}
.list {
display: flex;
align-items: center;
font-size: 28rpx;
padding-bottom: 32rpx;
.list_left {
color: #666666;
margin-right: 112rpx;
}
}
.clinch_info {
padding: 32rpx 24rpx 0 24rpx;
background-color: white;
margin-top: 20rpx;
}
.footer {
position: fixed;
bottom: 64rpx;
width: 702rpx;
height: 88rpx;
left: 24rpx;
}
.btn {
border-radius: 44rpx;
border: 2rpx solid #ec7c00;
margin: 0;
padding: 0;
text-align: center;
height: 88rpx;
line-height: 88rpx;
font-size: 28rpx;
color: #ec7c00;
}
button::after {
border: 0;
}
</style>
<style lang="scss">
page {
background-color: #f7f7f7;
}
</style>

@ -0,0 +1,373 @@
<template>
<view class="trade_info">
<view class="center">
<view class="list">
<view>证券名称</view>
<input
type="text"
v-model="data.name"
placeholder="请输入"
class="ipt"
/>
</view>
<view class="list">
<view>证券代码</view>
<input
type="text"
v-model="data.code"
placeholder="请输入"
class="ipt"
/>
</view>
<view class="list" @tap="showType = true">
<view>交易类别</view>
<view class="list_right">
<input
type="number"
v-model="data.type"
placeholder="请输入"
class="ipt"
disabled
/>
<image
src="../../static/right_all.png"
class="right_icon"
mode="scaleToFill"
/>
</view>
</view>
<view class="list">
<view>成交价格</view>
<input
type="digit"
v-model="data.clinchPrice"
placeholder="请输入"
class="ipt"
@input="changePrice"
/>
</view>
<view class="list">
<view>成交数量</view>
<input
type="digit"
v-model="data.clinchNum"
placeholder="请输入"
class="ipt"
@input="changeNum"
/>
</view>
<view class="list">
<view>成交金额</view>
<input
type="text"
disabled
v-model="data.clinchMoney"
placeholder="请输入"
class="ipt"
/>
</view>
<view class="list">
<view>手续费</view>
<input
type="digit"
disabled
v-model="data.formalitiesFee"
placeholder="请输入"
class="ipt"
/>
</view>
<view class="list">
<view>手续费率</view>
<view class="list_right">
<input
type="digit"
v-model="data.formalitiesRates"
placeholder="请输入"
class="ipt"
@input="changeRates"
/>
<view>%</view>
</view>
</view>
<view class="list" @tap="showDate = true">
<view>成交日期</view>
<view class="list_right">
<input
type="number"
v-model="data.date"
placeholder="请选择"
class="ipt"
disabled
/>
<image
src="../../static/right_all.png"
class="right_icon"
mode="scaleToFill"
/>
</view>
</view>
<view class="list" @tap="showTime = true">
<view>成交时间</view>
<view class="list_right">
<input
type="number"
v-model="data.time"
placeholder="请选择"
class="ipt"
disabled
/>
<image
src="../../static/right_all.png"
class="right_icon"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view class="footer">
<button class="btn" @tap="submit"></button>
</view>
<!-- 交易类别 -->
<u-picker
:show="showType"
:columns="columns"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showType = false"
@confirm="confirmType"
></u-picker>
<!-- 成交日期 -->
<u-datetime-picker
:show="showDate"
v-model="data.date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showDate = false"
@confirm="confirmDate"
></u-datetime-picker>
<!-- 成交时间 -->
<u-datetime-picker
:show="showTime"
v-model="data.time"
mode="time"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showTime = false"
@confirm="confirmTime"
></u-datetime-picker>
</view>
</template>
<script>
export default {
data() {
return {
//
showDate: false,
//
showTime: false,
//
showType: false,
columns: [['证券买入', '证券卖出']],
data: {
name: '',
code: '',
type: '',
clinchPrice: '',
//
clinchNum: '',
//
clinchMoney: '',
//
formalitiesFee: '',
//
formalitiesRates: '5',
//
date: '',
//
time: '',
},
}
},
methods: {
//
confirmType(e) {
this.data.type = e.value[0]
this.showType = false
},
//
confirmDate(e) {
this.$nextTick(() => {
this.data.date = this.getTime(e.value)
})
this.showDate = false
},
//
confirmTime(e) {
this.showTime = false
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
getTime1(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${h}:${mm}:${s}`
},
//
changePrice(e) {
if (this.data.clinchNum) {
this.data.clinchMoney = this.data.clinchPrice * this.data.clinchNum
this.data.clinchMoney = this.data.clinchMoney.toFixed(2)
if (this.data.formalitiesRates) {
this.data.formalitiesFee =
this.data.clinchMoney * this.data.formalitiesRates
this.data.formalitiesFee = this.data.formalitiesFee.toFixed(2)
}
}
},
//
changeNum(e) {
if (this.data.clinchPrice) {
this.data.clinchMoney = this.data.clinchPrice * this.data.clinchNum
this.data.clinchMoney = this.data.clinchMoney.toFixed(2)
if (this.data.formalitiesRates) {
this.data.formalitiesFee =
this.data.clinchMoney * this.data.formalitiesRates
this.data.formalitiesFee = this.data.formalitiesFee.toFixed(2)
}
}
},
//
changeRates() {
if (this.data.clinchMoney) {
this.data.formalitiesFee =
this.data.clinchMoney * this.data.formalitiesRates
this.data.formalitiesFee = this.data.formalitiesFee / 100
this.data.formalitiesFee = this.data.formalitiesFee.toFixed(2)
console.log(this.formalitiesFee)
}
},
submit() {
this.$api
.post('/transaction/saveOrUpdate', {
createTime: '',
id: 0,
premium: this.data.formalitiesFee,
premiumRatio: this.data.formalitiesRates,
securityCode: this.data.code,
securityName: this.data.name,
securityType: '',
transactionAmount: this.data.clinchMoney,
transactionCategory: this.data.type,
transactionDate: this.data.date,
transactionPrice: this.data.clinchPrice,
transactionTime: this.data.date + ' ' + this.data.time + ':00',
userId: 0,
volume: this.data.clinchNum,
})
.then(r => {
if (r) {
uni.showToast({
title: '添加成功',
icon: 'success',
duration: 1000,
})
uni.navigateBack({
delta: 1,
})
}
})
.catch(fall => {
console.log(fall)
})
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 40rpx 24rpx;
}
.list {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
padding-bottom: 32rpx;
.ipt {
text-align: right;
}
.list_right {
display: flex;
align-items: center;
}
.right_icon {
width: 24rpx;
height: 24rpx;
margin-left: 10rpx;
}
}
.footer {
position: fixed;
bottom: 64rpx;
width: 702rpx;
height: 88rpx;
left: 24rpx;
.btn {
border-radius: 44rpx;
background-color: #ec7c00;
color: white;
padding: 0;
margin: 0;
text-align: center;
line-height: 88rpx;
font-size: 28rpx;
}
}
</style>

@ -0,0 +1,348 @@
<template>
<view class="all_breakeven">
<view class="center">
<view class="private_serch" @tap="toSerch">
<view class="private_serch_left">
<u-icon name="search" size="20"></u-icon>
<input
type="text"
placeholder="请输入请输入个股代码、板块或名称"
class="private_serch_ipt"
style="margin-left: 8rpx"
v-model="serchValue"
/>
</view>
<view @tap="submitSerch"></view>
</view>
<view class="private_screening">
<view class="private_screening_list" @tap="showPrivateMarket = true">
<view>{{ currentMarket }}</view>
<image
src="../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/>
</view>
<!-- <view class="private_screening_list" @tap="showPrivatePlate = true">
<view>{{ currentPlate }}</view>
<image
src="../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/>
</view> -->
<view class="private_screening_list" @tap="showPrivatePrice = true">
<view>{{ currentPrice }}</view>
<image
src="../../static/jiangxu_false.png"
class="private_screening_icon"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view class="private_table_head">
<view class="private_table_head_left">
<view class="private_head_name">股票代码</view>
<view class="private_head_price">买入时间</view>
<view class="private_head_gains">卖出时间</view>
</view>
<view class="private_table_head_right" @tap="privateBelong">
<view>盈亏金额</view>
</view>
</view>
<view
class="private_table_list"
v-for="(item, index) in list"
:key="index"
@tap="toBreakevenDetail(item.securityCode, item.securityName)"
>
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.securityName }}</view>
<view class="table_list_code">{{ item.securityCode }}</view>
</view>
<view class="table_list_price">
{{ item.buyDate }}
</view>
<view class="table_list_gains">
{{ item.sellDate }}
</view>
</view>
<view
class="table_list_totalMoney"
:class="{ table_list_gains1: item.totalMoney < 0 }"
>{{ item.totalMoney }}</view
>
</view>
<!-- 个股筛选大盘 -->
<u-picker
:show="showPrivateMarket"
:columns="columnsMarket"
keyName="name"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showPrivateMarket = false"
@confirm="confirmPrivateMarket"
></u-picker>
<!-- 个股筛选板块 -->
<u-picker
:show="showPrivatePlate"
:columns="columnsPlate"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showPrivatePlate = false"
@confirm="confirmPrivatePlate"
></u-picker>
<!-- 个股筛选价格 -->
<u-picker
:show="showPrivatePrice"
:columns="columnsPrice"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="showPrivatePrice = false"
@confirm="confirmPrivatePrice"
></u-picker>
</view>
</template>
<script>
export default {
data() {
return {
//
showPrivatePrice: false,
currentPrice: '全部盈亏',
currentPriceIndex: '',
columnsPrice: [['全部盈亏', '盈利个股', '亏损个股']],
//
showPrivatePlate: false,
currentPlate: '全部板块',
columnsPlate: [
['全部板块', '上证指数', '深证指数', '创业板', '科创板'],
],
//
showPrivateMarket: false,
currentMarket: '全部大盘',
columnsMarket: [
[
{ name: '全部大盘', current: '' },
{ name: '上证指数', current: 'SZ' },
{ name: '深证指数', current: 'SH' },
{ name: '创业板', current: '30' },
{ name: '科创版', current: '688' },
],
],
currentMarketId: '',
list: [],
pagenum: 1,
last_page: null,
serchValue: '',
}
},
onLoad(options) {
this.rending()
},
onReachBottom() {
if (this.pagenum < this.last_page) {
this.getnewGoods()
}
},
methods: {
rending() {
this.$api
.post('/transaction/profitOrLoss', {
endDate: '',
keyWord: this.serchValue,
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
securityType: this.currentMarketId,
sortAmount: 1,
startDate: '',
type: this.currentPriceIndex,
})
.then(r => {
if (r) {
// this.data = r
this.list = r.list
}
})
.catch(fall => {
console.log(fall)
})
},
//
confirmPrivateMarket(e) {
this.pagenum = 1
this.currentMarket = e.value[0].name
this.currentMarketId = e.value[0].current
this.rending()
this.showPrivateMarket = false
},
//
confirmPrivatePlate(e) {
this.currentPlate = e.value[0]
this.showPrivatePlate = false
},
//
confirmPrivatePrice(e) {
this.pagenum = 1
this.currentPrice = e.value[0]
if (this.currentPrice == '全部盈亏') {
this.currentPriceIndex = ''
} else if (this.currentPrice == '盈利个股') {
this.currentPriceIndex = 1
} else {
this.currentPriceIndex = 2
}
this.rending()
this.showPrivatePrice = false
},
//
getnewGoods() {
this.pagenum = this.pagenum + 1
this.rending1()
// 1.loading
uni.showLoading({
title: '数据加载中...',
})
// 2.
this.isLoading = true
// 3.
//
// 4.loading
uni.hideLoading()
// 5.
this.isLoading = false
},
//
toBreakevenDetail(id, name) {
uni.navigateTo({
url: `/pages/user/breakevenDetail?id=${id}&name=${name}`,
})
},
submitSerch() {
this.rending()
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 24rpx 24rpx;
}
.private_serch {
padding: 24rpx 32rpx;
border: 2rpx solid #dedede;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24rpx;
border-radius: 12rpx;
color: #ec7c00;
.private_serch_ipt {
width: 400rpx;
font-size: 24rpx;
}
.private_serch_left {
display: flex;
align-items: center;
}
}
.private_screening {
padding: 32rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24rpx;
.private_screening_list {
display: flex;
align-items: center;
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 150rpx;
}
.private_head_price {
width: 180rpx;
text-align: center;
}
.private_head_gains {
width: 180rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 150rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 180rpx;
text-align: center;
}
.table_list_totalMoney {
color: #d9001b;
}
.table_list_gains {
width: 180rpx;
text-align: center;
}
.table_list_gains1 {
color: #6fbb60;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.table_list_totalMoney {
color: #d9001b;
}
.table_list_gains1 {
color: #6fbb60;
}
</style>

@ -0,0 +1,525 @@
<template>
<u-loading-page v-if="load" :loading="load"></u-loading-page>
<view class="trade_stats" v-else>
<view class="head" :class="{ head1: totalEarnings < 0 }">
<view class="head_top">
<view class="all_breakeven">{{ name }}</view>
<view class="all_money">{{ totalProfit }}</view>
<view>收益率 {{ totalEarnings.toFixed(2) }}%</view>
</view>
<view class="head_bottom">
<view
v-for="(item, index) in nav"
:key="index"
class="head_bottom_list"
@tap="selectNav(item.name)"
>
<view :class="{ bottom_list: item.is }">{{ item.name }}</view>
<image
v-if="item.is"
src="../../static/collection_select.png"
class="select_icon"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view class="main">
<view class="main_date" v-if="nav[3].is == true">
<input
type="text"
class="main_date_ipt"
disabled
placeholder="请选择开始日期"
v-model="startDate"
@tap="selectStartDate"
/>
<u-icon name="minus" size="20" style="padding: 0 20rpx"></u-icon>
<input
type="text"
disabled
class="main_date_ipt"
placeholder="请选择截至日期"
v-model="endDate"
@tap="selectEndDate"
/>
<view class="main_date_serch">搜索</view>
</view>
<view class="main_nav">
<view
:class="{ main_nav_color: isEarnings }"
@tap="selectMainNav(true)"
>
收益率
</view>
<view
style="margin-left: 72rpx"
:class="{ main_nav_color: !isEarnings }"
@tap="selectMainNav(false)"
>
盈亏金额
</view>
</view>
<view style="height: 600rpx; width: 100%; padding-top: 60rpx">
<l-echart ref="chart"></l-echart>
</view>
</view>
<!-- 筛选/开始时间选择 -->
<u-datetime-picker
:show="startDateShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="startDateShow = false"
@confirm="confirmStartDate"
></u-datetime-picker>
<!-- 筛选/结束时间选择 -->
<u-datetime-picker
:show="endDateShow"
v-model="date"
mode="date"
:minDate="minDate"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="endDateShow = false"
@confirm="confirmEndDate"
></u-datetime-picker>
</view>
</template>
<script>
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
export default {
data() {
return {
totalProfit: '',
totalEarnings: '',
bgcColor: {
background: '',
},
nav: [
{
name: '本月',
is: true,
current: 0,
},
{
name: '近一月',
is: false,
current: 1,
},
{
name: '近三月',
is: false,
current: 2,
},
{
name: '自定义',
is: false,
current: 0,
},
],
navIndex: 0,
// or
isEarnings: true,
//
startDate: '',
//
startDateShow: false,
//
endDate: '',
//
endDateShow: false,
minDate: null,
name: '',
load: true,
}
},
onLoad(options) {
this.name = options.name
this.code = options.id
this.rending()
},
mounted() {
this.$nextTick(() => {
// echarts
this.initEchartsZ()
})
},
methods: {
//
selectNav(name) {
this.nav.forEach(item => {
if (item.name === name) {
item.is = true
this.navIndex = item.current
this.initEchartsZ()
} else {
item.is = false
}
})
},
// or
selectMainNav(is) {
this.isEarnings = is
},
//
confirmStartDate(e) {
this.$nextTick(() => {
this.minDate = new Date(e.value).getTime()
console.log(this.minDate)
this.startDate = this.getTime(e.value)
})
this.startDateShow = false
},
//
confirmEndDate(e) {
this.$nextTick(() => {
this.endDate = this.getTime(e.value)
})
this.endDateShow = false
},
//
selectStartDate() {
if (!this.endDateShow) {
this.startDateShow = true
}
},
//
selectEndDate() {
if (this.startDate) {
if (!this.startDateShow) {
this.endDateShow = true
}
} else {
uni.showToast({
title: '请先选择开始时间',
icon: 'none',
})
}
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
rending() {
this.$api
.post('/transaction/totalEarnings', {
securityCode: this.code,
})
.then(r => {
if (r) {
// this.data = r
this.totalProfit = r.totalEarnings
this.totalEarnings = r.earningsRate
if (r.earningsRate > 0) {
setTimeout(() => {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#F93938',
})
}, 100)
} else {
setTimeout(() => {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#568EFF',
})
}, 100)
}
this.load = false
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
initEchartsZ() {
this.$api
.post('/transaction/earningsLine', {
endDate: this.endDate,
securityCode: '',
startDate: this.startDate,
timeType: this.navIndex,
type: this.isEarnings ? 1 : 2,
})
.then(r => {
if (r) {
console.log(r)
// this.data = r
this.$refs.chart.init(echarts, chart => {
let option = {
tooltip: {
trigger: 'axis',
position: function (pt) {
return [pt[0], '10%']
},
},
title: {
left: 'center',
text: 'Large Ara Chart',
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none',
},
restore: {},
saveAsImage: {},
},
},
xAxis: {
type: 'time',
boundaryGap: false,
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
show: false,
start: 0,
end: 100,
},
],
series: [
{
name: '数据',
type: 'line',
smooth: true,
symbol: 'none',
//
// areaStyle: {},
data: r,
},
],
}
chart.setOption(option)
})
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
},
}
</script>
<style lang="scss" scoped>
.head {
height: 300rpx;
color: white;
background: linear-gradient(180deg, #f93938 0%, #fa4c0d 100%);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.head_top {
text-align: center;
font-size: 28rpx;
.all_breakeven {
color: rgba(255, 255, 255, 0.7);
}
.all_money {
margin: 20rpx 0;
font-size: 60rpx;
font-weight: bold;
}
}
.head_bottom {
padding: 0 24rpx;
font-size: 28rpx;
display: flex;
align-items: center;
color: rgba(255, 255, 255, 0.7);
.head_bottom_list {
position: relative;
display: flex;
margin-right: 64rpx;
padding-bottom: 24rpx;
justify-content: center;
}
.bottom_list {
color: white;
}
.select_icon {
position: absolute;
bottom: 0;
width: 24rpx;
height: 14rpx;
}
}
.head1 {
background: linear-gradient(180deg, #568eff 0%, #4479eb 100%);
}
.main {
margin-top: 32rpx;
.main_date {
display: flex;
align-items: center;
font-size: 24rpx;
padding: 0 24rpx;
.main_date_ipt {
width: 170rpx;
padding: 10rpx 46rpx;
border: 2rpx solid #999999;
border-radius: 8rpx;
height: 36rpx;
text-align: center;
}
.main_date_serch {
color: #ec7c00;
margin-left: 32rpx;
}
/deep/.u-icon--right {
padding: 0 16rpx !important;
}
}
.main_nav {
margin-top: 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #999999;
}
.main_nav_color {
color: #ec7c00;
}
}
.line {
height: 20rpx;
background-color: #f6f6f6;
}
.footer {
.footer_nav {
padding: 32rpx 24rpx;
display: flex;
font-weight: bold;
align-items: center;
justify-content: space-between;
.footer_nav_right {
display: flex;
align-items: center;
font-size: 24rpx;
color: #999999;
font-weight: 500;
}
.right_icon {
width: 24rpx;
height: 24rpx;
margin-left: 10rpx;
}
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 150rpx;
}
.private_head_price {
width: 180rpx;
text-align: center;
}
.private_head_gains {
width: 180rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 150rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 180rpx;
text-align: center;
}
.table_list_gains {
width: 180rpx;
text-align: center;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.see_more {
padding: 32rpx 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
color: #ec7c00;
}
.more_icon {
width: 22rpx;
height: 22rpx;
margin-left: 10rpx;
}
}
</style>

@ -0,0 +1,363 @@
<template>
<view class="collection">
<view class="nav center">
<view>
<text :class="{ nav_select: !isPrivate }" @tap="selectNav(false)">
指数/板块
</text>
<text :class="{ nav_select: isPrivate }" @tap="selectNav(true)">
个股
</text>
</view>
</view>
<view class="center" style="padding-top: 0">
<view class="private_serch">
<view class="private_serch_left">
<u-icon name="search" size="20"></u-icon>
<input
type="text"
v-model="serchValue"
placeholder="请输入请输入个股代码、板块或名称"
class="private_serch_ipt"
style="margin-left: 8rpx"
/>
</view>
<view @tap="submit"></view>
</view>
</view>
<view v-if="!showLoad">
<view class="private_table_head">
<view class="private_table_head_left">
<view class="private_head_name">股票名称</view>
<view class="private_head_price">价格</view>
<view class="private_head_gains">涨幅</view>
</view>
<view class="private_table_head_right" @tap="privateBelong">
<view>关注日期</view>
</view>
</view>
<view
class="private_table_list"
v-for="(item, index) in list"
@tap="to(item.securityName, item.securityCode)"
:key="index"
>
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.securityName }}</view>
<view class="table_list_code">{{ item.securityCode }}</view>
</view>
<view
class="table_list_price"
:class="{ table_list_price1: item.riseLossesCurrentDay < 0 }"
>
{{ item.closingPrice }}
</view>
<view
class="table_list_gains"
:class="{ table_list_gains1: item.riseLossesCurrentDay < 0 }"
>
<span v-if="item.riseLossesCurrentDay"
>{{ item.riseLossesCurrentDay.toFixed(2) }}%</span
>
</view>
</view>
<view>{{ item.collectDate }}</view>
</view>
</view>
<view v-else class="show_load">
<u-loading-icon></u-loading-icon>
</view>
</view>
</template>
<script>
export default {
data() {
return {
showLoad: false,
// /or
isPrivate: false,
list: [],
pagenum: 1,
last_page: null,
serchValue: '',
}
},
onLoad(options) {
this.rending()
},
onReachBottom() {
if (this.pagenum < this.last_page) {
this.getnewGoods()
}
},
methods: {
//
// toSerch() {
// uni.navigateTo({
// url: `/pages/user/collectionSerch`,
// })
// },
submit() {
this.isPrivate ? this.privateRending() : this.rending()
},
selectNav(is) {
this.pagenum = 1
this.showLoad = true
this.isPrivate = is
this.serchValue = ''
if (is) {
this.privateRending()
} else {
this.rending()
}
},
//
privateRending() {
// /collect/query
this.$api
.post('/collect/query', {
businessDate: '',
keyWord: this.serchValue,
market: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
plateOrA: 2,
})
.then(r => {
if (r) {
this.list = r.list
console.log(this.list)
this.last_page = r.totalPage
this.showLoad = false
}
})
.catch(fall => {
console.log(fall)
})
},
privateRending1() {
this.showLoad = false
// /collect/query
this.$api
.post('/collect/query', {
businessDate: '',
keyWord: this.serchValue,
market: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
plateOrA: 2,
})
.then(r => {
if (r) {
this.list = [...this.list, ...r.list]
this.last_page = r.totalPage
}
})
.catch(fall => {
console.log(fall)
})
},
rending() {
this.$api
.post('/collect/query', {
businessDate: '',
keyWord: this.serchValue,
market: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
plateOrA: 1,
})
.then(r => {
if (r) {
this.list = r.list
this.last_page = r.totalPage
this.showLoad = false
}
})
.catch(fall => {
console.log(fall)
})
},
rending1() {
this.$api
.post('/collect/query', {
businessDate: '',
keyWord: this.serchValue,
market: '',
pageModel: {
pageNo: this.pagenum,
pageSize: 20,
sortField: '',
sortWay: '',
},
plateOrA: 1,
})
.then(r => {
if (r) {
this.list = [...this.list, ...r.list]
this.last_page = r.totalPage
this.showLoad = false
}
})
.catch(fall => {
console.log(fall)
})
},
//
getnewGoods() {
this.pagenum = this.pagenum + 1
if (this.isPrivate) {
this.privateRending1()
} else {
this.rending1()
}
// 1.loading
uni.showLoading({
title: '数据加载中...',
})
// 2.
this.isLoading = true
// 3.
//
// 4.loading
uni.hideLoading()
// 5.
this.isLoading = false
},
to(name, id) {
if (this.isPrivate) {
uni.navigateTo({
url: `/pages/home/private/privateDetail?name=${name}&id=${id}`,
})
}
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 32rpx 24rpx;
}
.nav {
font-size: 24rpx;
color: #999999;
display: flex;
justify-content: space-between;
align-items: center;
}
.nav text {
margin-right: 32rpx;
}
.nav_select {
font-weight: bold;
font-size: 32rpx;
color: #ec7c00;
}
.private_serch {
padding: 24rpx 32rpx;
border: 2rpx solid #dedede;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 24rpx;
border-radius: 12rpx;
color: #ec7c00;
.private_serch_ipt {
width: 400rpx;
font-size: 24rpx;
}
.private_serch_left {
display: flex;
align-items: center;
}
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 200rpx;
}
.private_head_price {
width: 150rpx;
text-align: center;
}
.private_head_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 200rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 150rpx;
text-align: center;
color: #d9001b;
}
.table_list_price1 {
color: #8fc320;
}
.table_list_gains {
width: 150rpx;
text-align: center;
color: #d9001b;
}
.table_list_gains1 {
color: #8fc320;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.show_load {
margin-top: 100rpx;
}
</style>

@ -0,0 +1,242 @@
<template>
<view class="collection_serch">
<view class="center">
<view class="serch">
<u-input
placeholder="请输入个股代码或名称"
v-model="serchValue"
prefixIcon="search"
prefixIconStyle="font-size: 22px;color: #909399"
shape="circle"
@input="change"
fontSize="24rpx"
></u-input>
<view class="serch_text">搜索</view>
</view>
<view
class="serch_list"
v-for="(item, index) in serchList"
:key="index"
@tap="detail(item)"
>
<image
src="../../static/serch.png"
mode="scaleToFill"
style="width: 26rpx; height: 26rpx"
/>
<view style="margin-left: 10rpx">{{ item.name }}</view>
</view>
</view>
<view class="private_table_head" v-if="list.length > 0">
<view class="private_table_head_left">
<view class="private_head_name">股票名称</view>
<view class="private_head_price">价格</view>
<view class="private_head_gains">涨幅</view>
</view>
<view class="private_table_head_right" @tap="privateBelong">
<view>关注日期</view>
</view>
</view>
<view class="private_table_list" v-for="(item, index) in list" :key="index">
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.name }}</view>
<view class="table_list_code">{{ item.code }}</view>
</view>
<view class="table_list_price" :style="{ color: item.color }">
{{ item.price }}
</view>
<view class="table_list_gains" :style="{ color: item.color }">
{{ item.gains }}
</view>
</view>
<view>{{ item.suoshu }}</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
serchValue: '',
serchList: [],
list: [],
}
},
methods: {
change() {
this.list = []
// this.$api
// .post('/getHomeInfo', {
// keyword: this.serchValue,
// })
// .then(r => {
// if (r) {
this.serchList = [
{
name: '长城汽车',
},
{
name: '长城汽车',
},
{
name: '长城汽车',
},
]
// }
// })
if (this.serchValue.length == 0) {
this.serchList = []
}
},
detail(item) {
this.serchList = []
// this.$api.post('/getHomeInfo', {}).then(r => {
// if (r) {
this.list = [
{
code: '601633',
name: '长城汽车',
price: '33.21',
gains: '10.12%',
date: '2023-04-10',
},
{
code: '601633',
name: '泰永长征',
price: '33.21',
gains: '10.12%',
date: '2023-04-10',
},
]
// this.list = r
// this.list.forEach(item => {})
// this.list = [...this.list]
// this.showLoad = false
// }
// })
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 0 24rpx;
}
.serch {
position: relative;
}
.serch_text {
position: absolute;
right: 0;
top: 0;
width: 120rpx;
height: 75rpx;
background-color: #ec7c00;
color: white;
border-radius: 36rpx;
text-align: center;
line-height: 75rpx;
font-size: 28rpx;
font-weight: bold;
}
/deep/.u-border {
border-color: #ec7c00 !important;
}
.serch_list {
padding: 32rpx 0;
display: flex;
align-items: center;
font-size: 24rpx;
border-bottom: 1px solid #cfcfcf;
}
.table_head {
padding: 20rpx 24rpx;
background-color: #fff9f3;
font-size: 24rpx;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 34rpx;
}
.table_head view {
width: 140rpx;
text-align: center;
}
.table_list {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 24rpx 0 24rpx;
font-size: 28rpx;
}
.table_list view {
text-align: center;
width: 140rpx;
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 200rpx;
}
.private_head_price {
width: 150rpx;
text-align: center;
}
.private_head_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 200rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 150rpx;
text-align: center;
}
.table_list_gains {
width: 150rpx;
text-align: center;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
</style>

@ -0,0 +1,61 @@
<template>
<view class="user_info">
<view class="center">
<u-input
placeholder="请输入名称"
border="bottom"
clearable
v-model="value"
></u-input>
<button class="btn" @tap="submit"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
value: '',
}
},
onLoad(options) {
this.value = options.value
},
methods: {
submit() {
if (this.value) {
uni.showToast({
title: '修改成功',
icon: 'success',
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: '请输入名称',
icon: 'none',
})
}
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 40rpx 24rpx;
.btn {
height: 88rpx;
border-radius: 40rpx;
font-size: 28rpx;
text-align: center;
line-height: 88rpx;
border: 0;
margin-top: 140rpx;
background-color: #ec7c00;
color: white;
}
}
</style>

@ -0,0 +1,132 @@
<template>
<view class="edit_phone">
<view class="center">
<view class="ipt_box">
<u-input
placeholder="请输入新手机号"
v-model="phone"
border="bottom"
type="number"
fontSize="32rpx"
clearable
></u-input>
<view style="margin-top: 50rpx">
<u-input
border="bottom"
clearable
placeholder="请输入验证码"
v-model="value"
fontSize="32rpx"
>
<template slot="suffix">
<u-code
ref="uCode"
@change="codeChange"
seconds="60"
changeText="Xs"
></u-code>
<u-button
@tap="getCode"
:text="tips"
class="custom-style"
:plain="true"
size="mini"
></u-button>
</template>
</u-input>
</view>
</view>
<button class="btn" @tap="submit"></button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
tips: '',
//
value: '',
//
phone: '',
}
},
methods: {
//
codeChange(text) {
this.tips = text
},
getCode() {
if (this.$refs.uCode.canGetCode) {
if (this.phone) {
//
uni.showLoading({
title: '正在获取验证码',
})
setTimeout(() => {
uni.hideLoading()
// this.start()
uni.$u.toast('验证码已发送')
//
this.$refs.uCode.start()
}, 2000)
this.$api.post('/login/sendSms', { phone: this.phone })
} else {
uni.$u.toast('请先输入手机号')
}
} else {
uni.$u.toast('倒计时结束后再发送')
}
},
submit() {
if (this.phone && this.value) {
uni.showToast({
title: '修改成功',
icon: 'success',
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.$u.toast('请先输入手机号和验证码')
}
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 60rpx 24rpx;
}
// .ipt_box {
// margin-top: 100rpx;
// }
.custom-style {
color: #6195fe;
text-align: center;
}
/deep/.u-button--plain.u-button--info {
color: #ec7c00 !important;
border: 0 !important;
font-size: 26rpx;
}
/deep/.u-input--no-radius {
padding: 24rpx 18rpx !important;
}
.btn {
height: 88rpx;
border-radius: 40rpx;
font-size: 28rpx;
text-align: center;
line-height: 88rpx;
border: 0;
margin-top: 140rpx;
background-color: #ec7c00;
color: white;
}
/deep/.u-button__text {
font-size: 28rpx !important;
}
</style>

@ -0,0 +1,144 @@
<template>
<view class="edit_user">
<view class="center">
<view class="avatar_box" @tap="editAvatar">
<view>头像</view>
<view class="avatar_right">
<image
src="https://upload-bbs.mihoyo.com/upload/2021/07/10/278678644/00185141732cb0f85adcf0ee68754554_8318448679343513426.jpg"
mode="scaleToFill"
class="avatar"
/>
<image
src="../../../static/right_all.png"
mode="scaleToFill"
style="width: 24rpx; height: 24rpx"
/>
</view>
</view>
<view class="name_phone">
<view class="list" @tap="to('editName', data.name)">
<view>用户昵称</view>
<view class="list_right">
<view style="color: #333333">微信用户</view>
<image
src="../../../static/right_all.png"
mode="scaleToFill"
style="width: 24rpx; height: 24rpx"
/>
</view>
</view>
<view class="list" @tap="to('editPhone')">
<view>手机号</view>
<view class="list_right">
<view style="color: #333333">130****8745</view>
<image
src="../../../static/right_all.png"
mode="scaleToFill"
style="width: 24rpx; height: 24rpx"
/>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
data: {
avatar: '',
name: '微信用户微信用户微信用户',
},
}
},
methods: {
to(url, value) {
uni.navigateTo({
url: `/pages/user/edit/${url}?value=${value}`,
})
},
//
editAvatar() {
let that = this
uni.chooseImage({
count: 1,
sourceType: ['album'],
sizeType: ['compressed'],
success(res) {
console.log(res)
res.tempFilePaths.forEach((item, index) => {
uni.uploadFile({
url: config.server + '/uploadGoods',
filePath: item,
name: 'file',
header: {
'ssdmn-token': cache.get('token'),
},
success: uploadFileRes => {
//
let r = JSON.parse(uploadFileRes.data)
that.$set(that.data, 'avatar', r.data.file)
},
fail: err => {
console.log(err)
},
})
})
},
})
},
},
}
</script>
<style lang="scss" scoped>
.center {
padding: 24rpx;
}
.avatar_box {
padding: 24rpx;
background-color: white;
border-radius: 16rpx;
font-size: 28rpx;
color: #666666;
display: flex;
align-items: center;
justify-content: space-between;
.avatar_right {
display: flex;
align-items: center;
.avatar {
width: 70rpx;
height: 70rpx;
border-radius: 70rpx;
margin-right: 10rpx;
}
}
}
.name_phone {
padding: 24rpx 24rpx 0 24rpx;
background-color: white;
margin-top: 24rpx;
border-radius: 16rpx;
}
.list {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
color: #666666;
padding-bottom: 30rpx;
}
.list_right {
display: flex;
align-items: center;
}
</style>
<style lang="scss">
page {
background-color: #f7f7f7;
}
</style>

@ -0,0 +1,725 @@
<template>
<u-loading-page v-if="load" :loading="load"></u-loading-page>
<view class="trade_stats" v-else>
<view class="head" :class="{ head1: totalEarnings < 0 }">
<view class="head_top">
<view class="all_breakeven">总盈亏</view>
<view class="all_money">{{ totalProfit }}</view>
<view>收益率 {{ totalEarnings.toFixed(2) }}%</view>
</view>
<view class="head_bottom">
<view
v-for="(item, index) in nav"
:key="index"
class="head_bottom_list"
@tap="selectNav(item.name)"
>
<view :class="{ bottom_list: item.is }">{{ item.name }}</view>
<image
v-if="item.is"
src="../../static/collection_select.png"
class="select_icon"
mode="scaleToFill"
/>
</view>
</view>
</view>
<view class="main">
<view class="main_date" v-if="nav[3].is == true">
<input
type="text"
class="main_date_ipt"
disabled
placeholder="请选择开始日期"
v-model="startDate"
@tap="selectStartDate"
/>
<u-icon name="minus" size="20" style="padding: 0 20rpx"></u-icon>
<input
type="text"
disabled
class="main_date_ipt"
placeholder="请选择截至日期"
v-model="endDate"
@tap="selectEndDate"
/>
<view class="main_date_serch">搜索</view>
</view>
<view class="main_nav">
<view
:class="{ main_nav_color: isEarnings }"
@tap="selectMainNav(true)"
>
收益率
</view>
<view
style="margin-left: 72rpx"
:class="{ main_nav_color: !isEarnings }"
@tap="selectMainNav(false)"
>
盈亏金额
</view>
</view>
</view>
<view style="height: 600rpx; width: 100%">
<l-echart ref="chart"></l-echart>
</view>
<view class="footer">
<view class="footer_nav" @tap="toAllBreakeven">
<view>个股盈亏统计</view>
<view class="footer_nav_right">
<view>查看所有</view>
<image
src="../../static/right_all.png"
class="right_icon"
mode="scaleToFill"
/>
</view>
</view>
<view class="private_table_head">
<view class="private_table_head_left">
<view class="private_head_name">股票代码</view>
<view class="private_head_price">买入时间</view>
<view class="private_head_gains">卖出时间</view>
</view>
<view class="private_table_head_right" @tap="privateBelong">
<view>盈亏金额</view>
</view>
</view>
<view
class="private_table_list"
v-for="(item, index) in list"
:key="index"
@tap="toBreakevenDetail(item.securityCode, item.securityName)"
>
<view class="private_table_list_left">
<view class="table_list_name">
<view>{{ item.securityName }}</view>
<view class="table_list_code">{{ item.securityCode }}</view>
</view>
<view class="table_list_price">
{{ item.buyDate }}
</view>
<view class="table_list_gains">
{{ item.sellDate }}
</view>
</view>
<view
class="table_list_totalMoney"
:class="{ table_list_gains1: item.totalMoney < 0 }"
>{{ item.totalMoney }}</view
>
</view>
<view class="see_more" v-if="list.length > 5" @tap="toAllBreakeven">
<view>查看更多</view>
<image
src="../../static/chakangengduo.png"
class="more_icon"
mode="scaleToFill"
/>
</view>
</view>
<!-- 筛选/开始时间选择 -->
<u-datetime-picker
:show="startDateShow"
v-model="date"
mode="date"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="startDateShow = false"
@confirm="confirmStartDate"
></u-datetime-picker>
<!-- 筛选/结束时间选择 -->
<u-datetime-picker
:show="endDateShow"
v-model="date"
mode="date"
:minDate="minDate"
cancelColor="#EC7C00"
confirmColor="#EC7C00"
@cancel="endDateShow = false"
@confirm="confirmEndDate"
></u-datetime-picker>
</view>
</template>
<script>
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
export default {
data() {
return {
//
totalProfit: '',
//
totalEarnings: '',
bgcColor: {
background: '',
},
nav: [
{
name: '本月',
is: true,
current: 0,
},
{
name: '近三月',
is: false,
current: 1,
},
{
name: '近一年',
is: false,
current: 2,
},
{
name: '自定义',
is: false,
current: 0,
},
],
navIndex: 0,
list: [
{
name: '长城汽车',
code: '601633',
price: '2023-04-10',
gains: '2023-04-10',
suoshu: '5422.12万',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
{
name: '长城汽车',
code: '601633',
price: '33.21',
gains: '10%',
suoshu: '电子设备制造',
color: '#D9001B',
},
],
// or
isEarnings: true,
//
startDate: '',
//
startDateShow: false,
//
endDate: '',
//
endDateShow: false,
minDate: null,
load: true,
}
},
onLoad(options) {
this.rending()
},
mounted() {
this.$nextTick(() => {
// echarts
this.initEchartsZ()
})
},
methods: {
//
selectNav(name) {
this.nav.forEach(item => {
if (item.name == name) {
item.is = true
this.navIndex = item.current
this.$nextTick(() => {
// echarts
this.initEchartsZ()
console.log('执行方法')
})
} else {
item.is = false
}
})
},
// or
selectMainNav(is) {
this.isEarnings = is
this.$nextTick(() => {
// echarts
this.initEchartsZ()
})
},
//
confirmStartDate(e) {
this.$nextTick(() => {
this.minDate = new Date(e.value).getTime()
console.log(this.minDate)
this.startDate = this.getTime(e.value)
})
this.startDateShow = false
},
//
confirmEndDate(e) {
this.$nextTick(() => {
this.endDate = this.getTime(e.value)
})
this.endDateShow = false
},
//
selectStartDate() {
if (!this.endDateShow) {
this.startDateShow = true
}
},
//
selectEndDate() {
if (this.startDate) {
if (!this.startDateShow) {
this.endDateShow = true
}
} else {
uni.showToast({
title: '请先选择开始时间',
icon: 'none',
})
}
},
//
toAllBreakeven() {
uni.navigateTo({
url: '/pages/user/allBreakeven',
})
},
//
toBreakevenDetail(id, name) {
uni.navigateTo({
url: `/pages/user/breakevenDetail?id=${id}&name=${name}`,
})
},
//
getTime(date) {
let time = new Date(date)
let y = time.getFullYear()
let m = time.getMonth() + 1
let d = time.getDate()
let h = time.getHours()
let mm = time.getMinutes()
let s = time.getSeconds()
if (s < 10) {
s = '0' + s
}
if (h < 10) {
h = '0' + h
}
if (mm < 10) {
mm = '0' + mm
}
if (m < 10) {
m = '0' + m
}
if (d < 10) {
d = '0' + d
}
return `${y}-${m}-${d}`
},
rending() {
this.$api
.post('/transaction/totalEarnings', {
securityCode: '',
})
.then(r => {
if (r) {
// this.data = r
this.totalProfit = r.totalEarnings
this.totalEarnings = r.earningsRate
if (r.earningsRate > 0) {
setTimeout(() => {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#F93938',
})
}, 100)
} else {
setTimeout(() => {
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#568EFF',
})
}, 100)
}
this.load = false
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
this.$api
.post('/transaction/profitOrLoss', {
endDate: '',
keyWord: '',
pageModel: {
pageNo: 0,
pageSize: 10,
sortField: '',
sortWay: '',
},
securityType: '',
sortAmount: 1,
startDate: '',
type: '',
})
.then(r => {
if (r) {
// this.data = r
this.list = r.list
}
})
.catch(fall => {
console.log(fall)
})
},
initEchartsZ() {
console.log('执行函数')
this.$api
.post('/transaction/earningsLine', {
endDate: this.endDate,
securityCode: '',
startDate: this.startDate,
timeType: this.navIndex,
type: this.isEarnings ? '1' : '2',
})
.then(r => {
if (r) {
console.log(r)
// this.data = r
this.$refs.chart.init(
echarts,
chart => {
let option = {
// tooltip: {
// trigger: 'axis',
// position: function (pt) {
// return [pt[0], '10%']
// },
// },
// title: {
// left: 'center',
// text: 'Large Ara Chart',
// },
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none',
},
restore: {},
saveAsImage: {},
},
},
xAxis: {
type: 'time',
boundaryGap: false,
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
show: false,
start: 0,
end: 100,
},
],
series: [
{
name: '数据',
type: 'line',
smooth: true,
symbol: 'none',
//
// areaStyle: {},
data: r,
},
],
}
chart.setOption(option)
},
{ locale: 'ZH' }
)
console.log(r)
}
})
.catch(fall => {
console.log(fall)
})
},
},
}
</script>
<style lang="scss" scoped>
.head {
height: 300rpx;
color: white;
background: linear-gradient(180deg, #f93938 0%, #fa4c0d 100%);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.head_top {
text-align: center;
font-size: 28rpx;
.all_breakeven {
color: rgba(255, 255, 255, 0.7);
}
.all_money {
margin: 20rpx 0;
font-size: 60rpx;
font-weight: bold;
}
}
.head_bottom {
padding: 0 24rpx;
font-size: 28rpx;
display: flex;
align-items: center;
color: rgba(255, 255, 255, 0.7);
.head_bottom_list {
position: relative;
display: flex;
margin-right: 64rpx;
padding-bottom: 24rpx;
justify-content: center;
}
.bottom_list {
color: white;
}
.select_icon {
position: absolute;
bottom: 0;
width: 24rpx;
height: 14rpx;
}
}
.head1 {
background: linear-gradient(180deg, #568eff 0%, #4479eb 100%);
}
.main {
margin-top: 32rpx;
.main_date {
display: flex;
align-items: center;
font-size: 24rpx;
padding: 0 24rpx;
.main_date_ipt {
width: 170rpx;
padding: 10rpx 46rpx;
border: 2rpx solid #999999;
border-radius: 8rpx;
height: 36rpx;
text-align: center;
}
.main_date_serch {
color: #ec7c00;
margin-left: 32rpx;
}
/deep/.u-icon--right {
padding: 0 16rpx !important;
}
}
.main_nav {
margin-top: 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #999999;
}
.main_nav_color {
color: #ec7c00;
}
}
.line {
height: 20rpx;
background-color: #f6f6f6;
}
.footer {
.footer_nav {
padding: 32rpx 24rpx;
display: flex;
font-weight: bold;
align-items: center;
justify-content: space-between;
.footer_nav_right {
display: flex;
align-items: center;
font-size: 24rpx;
color: #999999;
font-weight: 500;
}
.right_icon {
width: 24rpx;
height: 24rpx;
margin-left: 10rpx;
}
}
.private_table_head {
display: flex;
align-items: center;
font-size: 24rpx;
font-weight: bold;
background-color: #fff9f3;
padding: 20rpx 24rpx;
justify-content: space-between;
.private_table_head_right {
display: flex;
align-items: center;
}
.private_table_head_left {
display: flex;
align-items: center;
.private_head_name {
width: 150rpx;
}
.private_head_price {
width: 180rpx;
text-align: center;
}
.private_head_gains {
width: 180rpx;
text-align: center;
}
}
}
.private_table_list {
padding: 24rpx 24rpx;
border-bottom: 2rpx solid #f6f6f6;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.private_table_list_left {
display: flex;
align-items: center;
.table_list_name {
width: 150rpx;
}
.table_list_code {
margin-top: 10rpx;
font-size: 24rpx;
color: #999999;
}
.table_list_price {
width: 180rpx;
text-align: center;
}
.table_list_gains {
width: 180rpx;
text-align: center;
}
}
}
.private_screening_icon {
width: 18rpx;
height: 10rpx;
margin-left: 24rpx;
}
.see_more {
padding: 32rpx 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
color: #ec7c00;
}
.more_icon {
width: 22rpx;
height: 22rpx;
margin-left: 10rpx;
}
}
.table_list_totalMoney {
color: #d9001b;
}
.table_list_gains1 {
color: #6fbb60;
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save