Merge branch 'dev-redux' of https://github.com/ciaochaos/qrbtf into dev-redux
Conflicts: package-lock.json package.json public/index.html src/api/db.js src/components/Footer.js src/components/QrRendererBase.js src/components/QrRendererBlank.js src/components/Qrcode.js src/components/renderer/RendererDSJ.js src/components/renderer/RendererRandRect.js src/components/renderer/RendererRandRound.js src/components/renderer/RendererRound.js src/utils/util.js
This commit is contained in:
commit
71562c1142
|
@ -1074,12 +1074,14 @@
|
|||
"@cloudbase/adapter-interface": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@cloudbase/adapter-interface/download/@cloudbase/adapter-interface-0.4.0.tgz",
|
||||
"integrity": "sha1-xXk1tQPnv6zksVHfY6h9xWSumQc="
|
||||
"integrity": "sha1-xXk1tQPnv6zksVHfY6h9xWSumQc=",
|
||||
"dev": true
|
||||
},
|
||||
"@cloudbase/database": {
|
||||
"version": "0.9.11-rc.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@cloudbase/database/download/@cloudbase/database-0.9.11-rc.0.tgz",
|
||||
"integrity": "sha1-ev1zOIzpzmct1bbZTm5XCNmRQ70=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bson": "^4.0.2",
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
|
@ -1140,6 +1142,11 @@
|
|||
"@hapi/hoek": "^8.3.0"
|
||||
}
|
||||
},
|
||||
"@icons/material": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npm.taobao.org/@icons/material/download/@icons/material-0.2.4.tgz",
|
||||
"integrity": "sha1-6QyfcXaLNzbnbX3WeD/Gwq+oi8g="
|
||||
},
|
||||
"@jest/console": {
|
||||
"version": "24.9.0",
|
||||
"resolved": "https://registry.npm.taobao.org/@jest/console/download/@jest/console-24.9.0.tgz",
|
||||
|
@ -2404,6 +2411,7 @@
|
|||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npm.taobao.org/axios/download/axios-0.19.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.19.2.tgz",
|
||||
"integrity": "sha1-PqNsXYgY0NX4qKl6bTa4bNwAyyc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
},
|
||||
|
@ -2412,6 +2420,7 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
|
@ -2420,6 +2429,7 @@
|
|||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.5.10.tgz?cache=0&sync_timestamp=1585479417937&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
|
@ -2427,7 +2437,8 @@
|
|||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3150,6 +3161,7 @@
|
|||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npm.taobao.org/bson/download/bson-4.0.4.tgz",
|
||||
"integrity": "sha1-S9os7fKuehjRXLJO4e3ox5f47s8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer": "^5.1.0",
|
||||
"long": "^4.0.0"
|
||||
|
@ -3159,6 +3171,7 @@
|
|||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npm.taobao.org/buffer/download/buffer-5.6.0.tgz?cache=0&sync_timestamp=1588706716358&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbuffer%2Fdownload%2Fbuffer-5.6.0.tgz",
|
||||
"integrity": "sha1-oxdJ3H2B2E2wir+Te2uMQDP2J4Y=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4"
|
||||
|
@ -3523,6 +3536,7 @@
|
|||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npm.taobao.org/cloudbase-adapter-wx_mp/download/cloudbase-adapter-wx_mp-0.1.1.tgz",
|
||||
"integrity": "sha1-J1DtgUX4IWhB0lu7XWubSiFLhDg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cloudbase/adapter-interface": "^0.4.0"
|
||||
}
|
||||
|
@ -3890,7 +3904,8 @@
|
|||
"crypto-js": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npm.taobao.org/crypto-js/download/crypto-js-3.3.0.tgz?cache=0&sync_timestamp=1581508591511&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-3.3.0.tgz",
|
||||
"integrity": "sha1-hG3RzOL2iqz6FWyFePkmpgm3l2s="
|
||||
"integrity": "sha1-hG3RzOL2iqz6FWyFePkmpgm3l2s=",
|
||||
"dev": true
|
||||
},
|
||||
"css": {
|
||||
"version": "2.2.4",
|
||||
|
@ -5648,7 +5663,8 @@
|
|||
"fingerprintjs2": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npm.taobao.org/fingerprintjs2/download/fingerprintjs2-2.1.0.tgz",
|
||||
"integrity": "sha1-Idw/7ifTsZkFbvjrhz3rzNjgYyM="
|
||||
"integrity": "sha1-Idw/7ifTsZkFbvjrhz3rzNjgYyM=",
|
||||
"dev": true
|
||||
},
|
||||
"flat-cache": {
|
||||
"version": "2.0.1",
|
||||
|
@ -6172,6 +6188,14 @@
|
|||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npm.taobao.org/hoist-non-react-statics/download/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U=",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.8.tgz",
|
||||
|
@ -8252,7 +8276,8 @@
|
|||
"lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
|
@ -8262,7 +8287,8 @@
|
|||
"lodash.set": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash.set/download/lodash.set-4.3.2.tgz",
|
||||
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
|
||||
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.sortby": {
|
||||
"version": "4.7.0",
|
||||
|
@ -8294,7 +8320,8 @@
|
|||
"lodash.unset": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npm.taobao.org/lodash.unset/download/lodash.unset-4.5.2.tgz",
|
||||
"integrity": "sha1-Nw0dPoW3Kn4bDN8tJyEhMG8j5O0="
|
||||
"integrity": "sha1-Nw0dPoW3Kn4bDN8tJyEhMG8j5O0=",
|
||||
"dev": true
|
||||
},
|
||||
"loglevel": {
|
||||
"version": "1.6.8",
|
||||
|
@ -8304,7 +8331,8 @@
|
|||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz",
|
||||
"integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg="
|
||||
"integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=",
|
||||
"dev": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
|
@ -8392,6 +8420,11 @@
|
|||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"material-colors": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npm.taobao.org/material-colors/download/material-colors-1.2.6.tgz",
|
||||
"integrity": "sha1-bRlYhxEmmSzuzHL0vMTY8BCGX0Y="
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz",
|
||||
|
@ -10768,6 +10801,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"react-color": {
|
||||
"version": "2.18.1",
|
||||
"resolved": "https://registry.npm.taobao.org/react-color/download/react-color-2.18.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-color%2Fdownload%2Freact-color-2.18.1.tgz",
|
||||
"integrity": "sha1-LNqMyOBqnixSrTkaMN2tMZckcvQ=",
|
||||
"requires": {
|
||||
"@icons/material": "^0.2.4",
|
||||
"lodash": "^4.17.11",
|
||||
"material-colors": "^1.2.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"reactcss": "^1.2.0",
|
||||
"tinycolor2": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "10.2.1",
|
||||
"resolved": "https://registry.npm.taobao.org/react-dev-utils/download/react-dev-utils-10.2.1.tgz?cache=0&sync_timestamp=1584750310214&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dev-utils%2Fdownload%2Freact-dev-utils-10.2.1.tgz",
|
||||
|
@ -11022,6 +11068,18 @@
|
|||
"resolved": "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz",
|
||||
"integrity": "sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npm.taobao.org/react-redux/download/react-redux-7.2.0.tgz",
|
||||
"integrity": "sha1-+XD2IZKzmBZC/sRv0NsYoHT+h50=",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.9.0"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npm.taobao.org/react-scripts/download/react-scripts-3.4.1.tgz",
|
||||
|
@ -11082,6 +11140,14 @@
|
|||
"workbox-webpack-plugin": "4.3.1"
|
||||
}
|
||||
},
|
||||
"reactcss": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npm.taobao.org/reactcss/download/reactcss-1.2.3.tgz",
|
||||
"integrity": "sha1-wAATh15Vexzw39mjaKHD2rO1SN0=",
|
||||
"requires": {
|
||||
"lodash": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/read-pkg/download/read-pkg-3.0.0.tgz",
|
||||
|
@ -11184,6 +11250,36 @@
|
|||
"strip-indent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"redux": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npm.taobao.org/redux/download/redux-4.0.5.tgz?cache=0&sync_timestamp=1577154206919&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fredux%2Fdownload%2Fredux-4.0.5.tgz",
|
||||
"integrity": "sha1-TbXeWBbheJHeioDEJCMtBvBR2T8=",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"redux-devtools": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npm.taobao.org/redux-devtools/download/redux-devtools-3.5.0.tgz",
|
||||
"integrity": "sha1-1pq3bU8Pir320kvPWVTXoaoraCc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.2.0",
|
||||
"prop-types": "^15.5.7",
|
||||
"redux-devtools-instrument": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"redux-devtools-instrument": {
|
||||
"version": "1.9.6",
|
||||
"resolved": "https://registry.npm.taobao.org/redux-devtools-instrument/download/redux-devtools-instrument-1.9.6.tgz",
|
||||
"integrity": "sha1-a0EllfdLnUjP1OzBPlhbFYjtbn4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.2.0",
|
||||
"symbol-observable": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npm.taobao.org/regenerate/download/regenerate-1.4.0.tgz",
|
||||
|
@ -12631,6 +12727,11 @@
|
|||
"util.promisify": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npm.taobao.org/symbol-observable/download/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha1-wiaIrtTqs83C3+rLtWFmBWCgCAQ="
|
||||
},
|
||||
"symbol-tree": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz",
|
||||
|
@ -12678,6 +12779,7 @@
|
|||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npm.taobao.org/tcb-js-sdk/download/tcb-js-sdk-1.6.1.tgz",
|
||||
"integrity": "sha1-jaLnrtwR+iNYqtrr2YcSg4shFUM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cloudbase/adapter-interface": "^0.4.0",
|
||||
"@cloudbase/database": "0.9.11-rc.0",
|
||||
|
@ -12884,6 +12986,11 @@
|
|||
"resolved": "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz",
|
||||
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
|
||||
},
|
||||
"tinycolor2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npm.taobao.org/tinycolor2/download/tinycolor2-1.4.1.tgz",
|
||||
"integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz",
|
||||
|
|
11
package.json
11
package.json
|
@ -6,10 +6,13 @@
|
|||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"react-color": "^2.18.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-redux": "^7.2.0",
|
||||
"react-scripts": "3.4.1",
|
||||
"tcb-js-sdk": "^1.6.1"
|
||||
"redux": "^4.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
@ -32,5 +35,9 @@
|
|||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"homepage": "./"
|
||||
"homepage": "./",
|
||||
"devDependencies": {
|
||||
"redux-devtools": "^3.5.0",
|
||||
"tcb-js-sdk": "^1.6.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,42 +4,66 @@
|
|||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-165845289-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-165845289-1');
|
||||
gtag('config', 'UA-165845289-1');
|
||||
</script>
|
||||
<script>
|
||||
(function(){
|
||||
var bp = document.createElement('script');
|
||||
var curProtocol = window.location.protocol.split(':')[0];
|
||||
if (curProtocol === 'https') {
|
||||
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
|
||||
}
|
||||
else {
|
||||
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
|
||||
}
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(bp, s);
|
||||
})();
|
||||
(function(){
|
||||
var bp = document.createElement('script');
|
||||
var curProtocol = window.location.protocol.split(':')[0];
|
||||
if (curProtocol === 'https') {
|
||||
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
|
||||
}
|
||||
else {
|
||||
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
|
||||
}
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(bp, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<!--<meta name="viewport" content="width=device-width, initial-scale=1" />-->
|
||||
<meta content="yes" name="apple-mobile-web-app-capable">
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="theme-color" content="#000000" />
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="QRBTF 参数化二维码生成器 Parametric QR Code Generator"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>QRBTF 参数化二维码生成器</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
18
src/App.js
18
src/App.js
|
@ -1,18 +0,0 @@
|
|||
import React from 'react';
|
||||
import './App.css';
|
||||
import Layout from './containers/Layout'
|
||||
import Qrcode from "./components/Qrcode";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<Layout>
|
||||
<Qrcode></Qrcode>
|
||||
</Layout>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -1,9 +0,0 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
const { getByText } = render(<App />);
|
||||
const linkElement = getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
import {actionTypes} from "../constant/ActionTypes";
|
||||
|
||||
export const genQRInfo = text => ({
|
||||
type: actionTypes.GENERATE_QR_INFO,
|
||||
text
|
||||
})
|
||||
|
||||
export const changeStyle = (rendererIndex, rendererType, value) => ({
|
||||
type: actionTypes.CHANGE_STYLE,
|
||||
rendererIndex, rendererType, value
|
||||
})
|
||||
|
||||
export const changeCorrectLevel = (correctLevel) => ({
|
||||
type: actionTypes.CHANGE_CORRECT_LEVEL,
|
||||
correctLevel
|
||||
})
|
||||
|
||||
export const createParam = (paramInfo, paramValue) => ({
|
||||
type: actionTypes.CREATE_PARAM,
|
||||
paramInfo, paramValue
|
||||
})
|
||||
|
||||
export const changeParam = (rendererIndex, paramIndex, value) => ({
|
||||
type: actionTypes.CHANGE_PARAM,
|
||||
rendererIndex, paramIndex, value
|
||||
})
|
|
@ -7,7 +7,11 @@ const auth = app.auth();
|
|||
|
||||
async function login() {
|
||||
await auth.signInAnonymously();
|
||||
<<<<<<< HEAD
|
||||
const loginState = await auth.getLoginState()
|
||||
=======
|
||||
// const loginState = await auth.getLoginState();
|
||||
>>>>>>> 47e31499e13fa4a29b3e69e6551268f3badb67b2
|
||||
}
|
||||
|
||||
login();
|
||||
|
@ -15,7 +19,11 @@ login();
|
|||
const db = app.database();
|
||||
const _ = db.command
|
||||
|
||||
<<<<<<< HEAD
|
||||
export function increaseDownloadData(value, date) {
|
||||
=======
|
||||
export function increaseDownloadData(value) {
|
||||
>>>>>>> 47e31499e13fa4a29b3e69e6551268f3badb67b2
|
||||
db.collection('QRCounter').where({
|
||||
value: _.eq(value)
|
||||
}).get().then(res => {
|
||||
|
@ -24,7 +32,11 @@ export function increaseDownloadData(value, date) {
|
|||
value: _.eq(value)
|
||||
}).update({
|
||||
count: _.inc(1),
|
||||
<<<<<<< HEAD
|
||||
date: date
|
||||
=======
|
||||
date: new Date().toString()
|
||||
>>>>>>> 47e31499e13fa4a29b3e69e6551268f3badb67b2
|
||||
}).then(res => {
|
||||
})
|
||||
}
|
||||
|
@ -32,7 +44,11 @@ export function increaseDownloadData(value, date) {
|
|||
db.collection('QRCounter').add({
|
||||
value: value,
|
||||
count: 1,
|
||||
<<<<<<< HEAD
|
||||
date: date
|
||||
=======
|
||||
date: new Date().toString()
|
||||
>>>>>>> 47e31499e13fa4a29b3e69e6551268f3badb67b2
|
||||
}).then(res => {
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css';
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
class Footer extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="Qr-titled">
|
||||
<div className="Qr-Centered Qr-footer note-font">
|
||||
<div><strong>作者</strong> <a href="https://blog.ciaochaos.com/" rel="noopener noreferrer" target="_blank">ciaochaos</a> <a href="https://github.com/CPunisher/" rel="noopener noreferrer" target="_blank">CPunisher</a> 丨 <a href="https://www.yuque.com/qrbtf/docs/contact" rel="noopener noreferrer" target="_blank">联系我们</a></div>
|
||||
<div className="Gray">Copyright © {currentYear} QRBTF. 保留所有权利。</div>
|
||||
<div className="Gray"><a href="http://www.beian.miit.gov.cn/" rel="noopener noreferrer" target="_blank">浙 ICP 备 19005869 号 </a></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Footer
|
|
@ -1,41 +0,0 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
|
||||
function calClassName(props) {
|
||||
if (props.selected === true) return 'Qr-item Qr-item-selected';
|
||||
return 'Qr-item';
|
||||
}
|
||||
|
||||
export default class QrItem extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
this.props.onSelected(this.props.index);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState, nextContext) {
|
||||
return (nextProps.selected || this.props.selected) && (this.props.text == nextProps.text || this.props.text.length == 0)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={calClassName(this.props)} onClick={this.handleClick}>
|
||||
<div className="Qr-item-image">
|
||||
<div className="Qr-item-image-inner">
|
||||
{this.props.renderer}
|
||||
</div>
|
||||
</div>
|
||||
<div className="Qr-item-detail">
|
||||
{this.props.value}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {defaultViewBox} from "../utils/util";
|
||||
|
||||
export default class QrRendererBlank extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {getTypeTable, QRPointType} from "../utils/qrcodeHandler";
|
||||
import {rand, defaultRenderer, defaultViewBox} from "../utils/util";
|
||||
|
||||
function listPoint(props) {
|
||||
if (!props.qrcode) return []
|
||||
|
||||
const qrcode = props.qrcode;
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = new Array(nCount);
|
||||
|
||||
let type = props.params[0];
|
||||
let size = props.params[1] / 100;
|
||||
let opacity = props.params[2] / 100;
|
||||
let posType = props.params[3];
|
||||
let id = 0;
|
||||
|
||||
const vw = [3, -3];
|
||||
const vh = [3, -3];
|
||||
|
||||
if (size <= 0) size = 1.0
|
||||
|
||||
for (let x = 0; x < nCount; x++) {
|
||||
for (let y = 0; y < nCount; y++) {
|
||||
if (qrcode.isDark(x, y) == false) continue;
|
||||
|
||||
if (typeTable[x][y] == QRPointType.ALIGN_CENTER || typeTable[x][y] == QRPointType.ALIGN_OTHER || typeTable[x][y] == QRPointType.TIMING) {
|
||||
if (type == 0)
|
||||
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill="black" x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
|
||||
else if (type == 1)
|
||||
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill="black" cx={x + 0.5} cy={y + 0.5}/>)
|
||||
else if (type == 2)
|
||||
pointList.push(<circle key={id++} opacity={opacity} fill="black" cx={x + 0.5} cy={y + 0.5} r={size / 2} />)
|
||||
}
|
||||
else if (typeTable[x][y] == QRPointType.POS_CENTER) {
|
||||
if (posType == 0) {
|
||||
pointList.push(<rect width={1} height={1} key={id++} fill="black" x={x} y={y}/>);
|
||||
} else if (posType == 1) {
|
||||
pointList.push(<circle key={id++} fill="black" cx={x + 0.5} cy={y + 0.5} r={1.5} />)
|
||||
pointList.push(<circle key={id++} fill="none" strokeWidth="1" stroke="black" cx={x + 0.5} cy={y + 0.5} r={3} />)
|
||||
} else if (posType == 2) {
|
||||
pointList.push(<circle key={id++} fill="black" cx={x + 0.5} cy={y + 0.5} r={1.5} />)
|
||||
pointList.push(<circle key={id++} fill="none" strokeWidth="0.15" strokeDasharray="0.5,0.5" stroke="black" cx={x + 0.5} cy={y + 0.5} r={3} />)
|
||||
for (let w = 0; w < vw.length; w++) {
|
||||
pointList.push(<circle key={id++} fill="black" cx={x + vw[w] + 0.5} cy={y + 0.5} r={0.5} />)
|
||||
}
|
||||
for (let h = 0; h < vh.length; h++) {
|
||||
pointList.push(<circle key={id++} fill="black" cx={x + 0.5} cy={y + vh[h] + 0.5} r={0.5} />)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeTable[x][y] == QRPointType.POS_OTHER) {
|
||||
if (posType == 0) {
|
||||
pointList.push(<rect width={1} height={1} key={id++} fill="black" x={x} y={y}/>);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (type == 0)
|
||||
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill="black" x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
|
||||
else if (type == 1)
|
||||
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill="black" cx={x + 0.5} cy={y + 0.5}/>)
|
||||
else if (type == 2)
|
||||
pointList.push(<circle opacity={opacity} key={id++} fill="black" cx={x + 0.5} cy={y + 0.5} r={0.5 * rand(0.33,1.0)} />)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointList;
|
||||
}
|
||||
|
||||
export default class QrRendererRandRound extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (this.props.setParamInfo) {
|
||||
this.props.setParamInfo([
|
||||
{
|
||||
key: '信息点样式',
|
||||
default: 2,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: '信息点缩放',
|
||||
default: 80
|
||||
},
|
||||
{
|
||||
key: '信息点不透明度',
|
||||
default: 100,
|
||||
},
|
||||
{
|
||||
key: '定位点样式',
|
||||
default: 2,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoint(this.props)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -434,3 +434,7 @@ select:-moz-focusring {
|
|||
color: transparent;
|
||||
text-shadow: 0 0 0 #000;
|
||||
}
|
||||
|
||||
.Qr-color-picker {
|
||||
width: 200px;
|
||||
}
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
/*eslint-disable*/
|
||||
|
||||
import React from "react";
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import {getQrcodeData} from "../utils/qrcodeHandler";
|
||||
import {saveImg, saveSvg} from "../utils/downloader";
|
||||
import {isWeiXin} from "../utils/util";
|
||||
import './Qrcode.css';
|
||||
import logo from '../qrbtf-logo.svg';
|
||||
|
||||
import Footer from "./Footer";
|
||||
import QrItem from "./QrItem";
|
||||
import QrRendererBase from "./QrRendererBase";
|
||||
import QrRendererRound from "./QrRendererRound";
|
||||
import QrRendererRandRound from "./QrRendererRandRound";
|
||||
import QrRendererBlank from "./QrRendererBlank";
|
||||
import QrRendererRandRect from "./QrRendererRandRect";
|
||||
import QrRendererDSJ from "./QrRendererDSJ";
|
||||
import QrRenderer25D from "./QrRenderer25D";
|
||||
import QrRendererImage from "./QrRendererImage";
|
||||
import {recordDownloadDetail} from "../api/db";
|
||||
|
||||
const logoStyle = {
|
||||
background: `url(${logo})`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left'
|
||||
};
|
||||
|
||||
const styleList = [
|
||||
{value: "A1", renderer: QrRendererBase},
|
||||
{value: "A2", renderer: QrRendererRound},
|
||||
{value: "A3", renderer: QrRendererRandRound},
|
||||
{value: "SP — 1", renderer: QrRendererDSJ},
|
||||
{value: "SP — 2", renderer: QrRendererRandRect},
|
||||
{value: "B1", renderer: QrRenderer25D},
|
||||
{value: "C1", renderer: QrRendererImage},
|
||||
{value: "D1", renderer: QrRendererBlank},
|
||||
];
|
||||
|
||||
|
||||
class Qrcode extends React.Component {
|
||||
paramInfoBuffer;
|
||||
paramValueBuffer;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
text: '',
|
||||
selectedIndex: 0,
|
||||
options: {text: ''},
|
||||
qrcode: null,
|
||||
paramInfo: [],
|
||||
paramValue: [],
|
||||
correctLevel: 0,
|
||||
history: []
|
||||
};
|
||||
this.paramInfoBuffer = new Array(16).fill(new Array(16));
|
||||
this.paramValueBuffer = new Array(16).fill(new Array(16));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const text = 'https://qrbtf.com/';
|
||||
this.setState({
|
||||
paramInfo: this.paramInfoBuffer,
|
||||
paramValue: this.paramValueBuffer,
|
||||
text: text,
|
||||
options: {text: text},
|
||||
qrcode: getQrcodeData({text: text, correctLevel: this.state.correctLevel})
|
||||
});
|
||||
}
|
||||
|
||||
setParamInfo = (index) => {
|
||||
const _this = this;
|
||||
return function (params) {
|
||||
_this.paramInfoBuffer[index] = params;
|
||||
_this.paramValueBuffer[index] = params.map(p => {
|
||||
return p.default
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setParamValue = (valueIndex, value) => {
|
||||
const newValue = this.state.paramValue.slice();
|
||||
newValue[this.state.selectedIndex][valueIndex] = value;
|
||||
this.setState({paramValue: newValue});
|
||||
}
|
||||
|
||||
handleCreate = (e) => {
|
||||
let text = this.state.text
|
||||
if (text.length <= 0) text = 'https://qrbtf.com/';
|
||||
this.setState({text: text, options: {text: text}, qrcode: getQrcodeData({text: text, correctLevel: this.state.correctLevel})});
|
||||
if (e) e.target.blur();
|
||||
}
|
||||
|
||||
downloadSvg = (e) => {
|
||||
const selected = this.state.selectedIndex
|
||||
const style = styleList[selected]
|
||||
const el = React.createElement(style.renderer, {qrcode: this.state.qrcode, params: this.state.paramValue[selected]})
|
||||
saveSvg(style.value, ReactDOMServer.renderToString(el))
|
||||
recordDownloadDetail({
|
||||
text: this.state.text,
|
||||
value: styleList[selected],
|
||||
type: 'svg',
|
||||
params: this.state.paramInfo[selected].map((item, index) => {
|
||||
return {
|
||||
key: item.key,
|
||||
value: item.choices ? item.choices[this.state.paramValue[selected][index]] : this.state.paramValue[selected][index]
|
||||
}
|
||||
}),
|
||||
history: this.state.history
|
||||
});
|
||||
}
|
||||
|
||||
downloadImg = (e) => {
|
||||
const selected = this.state.selectedIndex
|
||||
const style = styleList[selected]
|
||||
const el = React.createElement(style.renderer, {qrcode: this.state.qrcode, params: this.state.paramValue[selected]})
|
||||
saveImg(style.value, ReactDOMServer.renderToString(el), 1500, 1500)
|
||||
recordDownloadDetail({
|
||||
text: this.state.text,
|
||||
value: styleList[selected],
|
||||
type: 'jpg',
|
||||
params: this.state.paramInfo[selected].map((item, index) => {
|
||||
return {
|
||||
key: item.key,
|
||||
value: item.choices ? item.choices[this.state.paramValue[selected][index]] : this.state.paramValue[selected][index]
|
||||
}
|
||||
}),
|
||||
history: this.state.history
|
||||
});
|
||||
}
|
||||
|
||||
renderParamEditor = (info, index) => {
|
||||
if (info.choices) {
|
||||
return (
|
||||
<select
|
||||
className="Qr-select"
|
||||
key={"select_" + this.state.selectedIndex + "_" + index}
|
||||
value={this.state.paramValue[this.state.selectedIndex][index]}
|
||||
onChange={(e) => this.setParamValue(index, e.target.value)}>
|
||||
{
|
||||
info.choices.map((choice, index) => {
|
||||
return (
|
||||
<option key={"option_" + this.state.selectedIndex + "_" + index}
|
||||
value={index}>
|
||||
{choice}
|
||||
</option>
|
||||
);
|
||||
})
|
||||
}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<input
|
||||
type="number"
|
||||
key={"input_" + this.state.selectedIndex + "_" + index}
|
||||
className="Qr-input small-input"
|
||||
placeholder="10"
|
||||
defaultValue={this.state.paramValue[this.state.selectedIndex][index]}
|
||||
onBlur={(e) => this.setParamValue(index, e.target.value)}
|
||||
onKeyPress={(e) => {if(e.key === 'Enter') {this.setParamValue(index, e.target.value); e.target.blur()}}}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderAdjustment = () => {
|
||||
const target = this.state.paramInfo[this.state.selectedIndex];
|
||||
if (target instanceof Array) {
|
||||
return target.map((info, index) => {
|
||||
return (
|
||||
<tr key={"tr_" + index}>
|
||||
<td key={"title_" + index}>{info.key}</td>
|
||||
<td key={"editor_" + index}>{this.renderParamEditor(info, index)}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
changeStyle = (index) => {
|
||||
const newHistory = this.state.history.slice();
|
||||
newHistory.push(styleList[index].value);
|
||||
this.setState({selectedIndex: index, history: newHistory})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="Qr-outer">
|
||||
<div className="Qr-Centered">
|
||||
<div style={logoStyle}>
|
||||
<h1 className="Qr-title"> </h1>
|
||||
</div>
|
||||
<p className="Qr-subtitle">参数化二维码生成器 <sup className="Gray">测试版</sup></p>
|
||||
<input
|
||||
className="Qr-input big-input"
|
||||
placeholder="Input your URL here"
|
||||
onChange={(e) => this.setState({text: e.target.value})}
|
||||
onBlur={this.handleCreate}
|
||||
onKeyPress={(e) => {if(e.key === 'Enter') this.handleCreate(e)}}
|
||||
/>
|
||||
</div>
|
||||
<div className="Qr-titled">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Styles</div>
|
||||
<p className="Qr-s-subtitle">点击选择样式</p>
|
||||
</div>
|
||||
<div className="Qr-s">
|
||||
<div className="Qr-box">
|
||||
{
|
||||
styleList.map((style, index) => {
|
||||
return <QrItem
|
||||
key={style.value}
|
||||
value={style.value}
|
||||
index={index}
|
||||
qrcode={this.state.qrcode}
|
||||
renderer={React.createElement(style.renderer, {
|
||||
qrcode: this.state.qrcode,
|
||||
params: this.state.paramValue[index],
|
||||
setParamInfo: this.setParamInfo(index)
|
||||
})}
|
||||
text={this.state.text}
|
||||
selected={index == this.state.selectedIndex}
|
||||
onSelected={this.changeStyle}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="Qr-titled-nobg">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Parameters</div>
|
||||
<p className="Qr-s-subtitle">参数调整</p>
|
||||
</div>
|
||||
<div className="Qr-Centered">
|
||||
<div className="Qr-div-table">
|
||||
<table className="Qr-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>容错率</td>
|
||||
<td>
|
||||
<select
|
||||
className="Qr-select"
|
||||
value={this.state.correctLevel}
|
||||
onChange={(e) => {
|
||||
this.setState({correctLevel: parseInt(e.target.value)}, () => this.handleCreate())
|
||||
}}>
|
||||
<option value={1}>7%</option>
|
||||
<option value={0}>15%</option>
|
||||
<option value={3}>25%</option>
|
||||
<option value={2}>30%</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
{this.renderAdjustment()}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="Qr-titled">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Downloads</div>
|
||||
<p className="Qr-s-subtitle">下载二维码 — {styleList[this.state.selectedIndex].value}</p>
|
||||
</div>
|
||||
<div className="Qr-Centered">
|
||||
<div className="div-btn">
|
||||
<button className="dl-btn" onClick={this.downloadSvg}>SVG</button>
|
||||
<button className="dl-btn" onClick={this.downloadImg}>JPG</button>
|
||||
</div>
|
||||
<div id="wx-message"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="Qr-titled-nobg">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">More</div>
|
||||
<p className="Qr-s-subtitle">更多</p>
|
||||
</div>
|
||||
<div className="Qr-Centered btn-row">
|
||||
<div className="div-btn">
|
||||
<a href="https://www.yuque.com/qrbtf/docs/donate" rel="noopener noreferrer" target="_blank">
|
||||
<button className="dl-btn">打赏 & 赞助</button>
|
||||
</a>
|
||||
<a href="https://www.yuque.com/qrbtf/topics" rel="noopener noreferrer" target="_blank">
|
||||
<button className="dl-btn">问题反馈</button>
|
||||
</a>
|
||||
</div>
|
||||
<div className="div-btn">
|
||||
<a href="https://www.yuque.com/qrbtf/docs/dev" rel="noopener noreferrer" target="_blank">
|
||||
<button className="dl-btn">开发与设计</button>
|
||||
</a>
|
||||
<a href="https://www.yuque.com/qrbtf/docs/coop" rel="noopener noreferrer" target="_blank">
|
||||
<button className="dl-btn">商业合作</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Qrcode;
|
||||
|
||||
window.onload = function(){
|
||||
if(isWeiXin()){
|
||||
const outer = document.getElementById("wx-message");
|
||||
const inner = document.createElement("div");
|
||||
inner.className = "note-font";
|
||||
inner.id = "wx-message-inner";
|
||||
inner.innerHTML = "当前客户端不支持下载,请在浏览器中打开。";
|
||||
outer.appendChild(inner);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import './App.css';
|
||||
import '../Qrcode.css';
|
||||
import Footer from "../footer/Footer";
|
||||
import Header from "../header/Header";
|
||||
import PartMore from "./PartMore";
|
||||
import PartParams from "./PartParams";
|
||||
import PartDownloadViewer from "../../containers/app/PartDownloadViewer";
|
||||
import PartStylesViewer from "../../containers/app/PartStylesViewer";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<div className="Layout">
|
||||
<div className="Qr-outer">
|
||||
<Header/>
|
||||
<PartStylesViewer/>
|
||||
<PartParams/>
|
||||
<PartDownloadViewer/>
|
||||
<PartMore/>
|
||||
<Footer/>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import './App.css';
|
||||
import DownloadSvg from "../../containers/download/DownloadSvg";
|
||||
import DownloadJpg from "../../containers/download/DownloadJpg";
|
||||
import {isWeiXin} from "../../utils/util";
|
||||
|
||||
const WxMessage = () => {
|
||||
if (isWeiXin()) {
|
||||
return <div className="note-font" id="wx-message-inner">当前客户端不支持下载,请在浏览器中打开。</div>
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const PartDownload = ({ value }) => (
|
||||
<div className="Qr-titled">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Downloads</div>
|
||||
<p className="Qr-s-subtitle">下载二维码 — {value}</p>
|
||||
</div>
|
||||
<div className="Qr-Centered">
|
||||
<div className="div-btn">
|
||||
<DownloadSvg/>
|
||||
<DownloadJpg/>
|
||||
</div>
|
||||
<div id="wx-message">
|
||||
<WxMessage/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default PartDownload;
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import './App.css';
|
||||
import LinkButton from "../link/LinkButton";
|
||||
|
||||
const PartMore = () => (
|
||||
<div className="Qr-titled-nobg">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">More</div>
|
||||
<p className="Qr-s-subtitle">更多</p>
|
||||
</div>
|
||||
<div className="Qr-Centered btn-row">
|
||||
<div className="div-btn">
|
||||
<LinkButton href={"https://www.yuque.com/qrbtf/docs/donate"} value={"打赏 & 赞助"} />
|
||||
<LinkButton href={"https://www.yuque.com/qrbtf/topics"} value={"问题反馈"} />
|
||||
</div>
|
||||
<div className="div-btn">
|
||||
<LinkButton href={"https://www.yuque.com/qrbtf/docs/dev"} value={"开发与设计"} />
|
||||
<LinkButton href={"https://www.yuque.com/qrbtf/docs/coop"} value={"商业合作"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default PartMore;
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import './App.css';
|
||||
import ParamListViewer from "../../containers/param/ParamListViewer";
|
||||
import ParamCorrectLevelViewer from "../../containers/param/ParamCorrectLevelViewer";
|
||||
|
||||
const PartParams = () => (
|
||||
<div className="Qr-titled-nobg">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Parameters</div>
|
||||
<p className="Qr-s-subtitle">参数调整</p>
|
||||
</div>
|
||||
<div className="Qr-Centered">
|
||||
<div className="Qr-div-table">
|
||||
<table className="Qr-table">
|
||||
<tbody>
|
||||
<ParamCorrectLevelViewer/>
|
||||
<ParamListViewer/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default PartParams;
|
|
@ -0,0 +1,23 @@
|
|||
import React, {useEffect, useState} from 'react';
|
||||
import './App.css';
|
||||
import StyleListViewer from "../../containers/style/StyleListViewer";
|
||||
|
||||
const PartStyles = ({ setParamInfo }) => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
useEffect(() => {
|
||||
setLoaded(true);
|
||||
}, [])
|
||||
const styleList = React.createElement(StyleListViewer({setParamInfo}))
|
||||
|
||||
return (<div className="Qr-titled">
|
||||
<div className="Qr-Centered title-margin">
|
||||
<div className="Qr-s-title">Styles</div>
|
||||
<p className="Qr-s-subtitle">点击选择样式</p>
|
||||
</div>
|
||||
<div className="Qr-s">
|
||||
{styleList}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default PartStyles;
|
|
@ -0,0 +1,16 @@
|
|||
import React from "react";
|
||||
import PropTypes from 'prop-types'
|
||||
import '../Qrcode.css';
|
||||
|
||||
const DownloadButton = ({ onClick, value }) => (
|
||||
<button className="dl-btn" onClick={onClick}>
|
||||
{value}
|
||||
</button>
|
||||
)
|
||||
|
||||
DownloadButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
value: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default DownloadButton;
|
|
@ -0,0 +1,36 @@
|
|||
import React from "react";
|
||||
import '../Qrcode.css';
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const Footer = () => (
|
||||
<div className="Qr-titled">
|
||||
<div className="Qr-Centered Qr-footer note-font">
|
||||
<div>
|
||||
<strong>作者</strong> 
|
||||
<a
|
||||
href="https://blog.ciaochaos.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank">ciaochaos
|
||||
</a> 
|
||||
<a href="https://github.com/CPunisher/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank">CPunisher
|
||||
</a> 丨 
|
||||
<a href="https://www.yuque.com/qrbtf/docs/contact" rel="noopener noreferrer" target="_blank">联系我们</a>
|
||||
</div>
|
||||
|
||||
<div className="Gray">
|
||||
Copyright © {currentYear} QRBTF. 保留所有权利。
|
||||
</div>
|
||||
<div className="Gray">
|
||||
<a href="http://www.beian.miit.gov.cn/" rel="noopener noreferrer" target="_blank">
|
||||
浙
|
||||
ICP 备 19005869 号
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Footer
|
|
@ -0,0 +1,22 @@
|
|||
import React from "react";
|
||||
import '../Qrcode.css';
|
||||
import logo from "../../qrbtf-logo.svg";
|
||||
import InputText from "../../containers/InputText";
|
||||
|
||||
const logoStyle = {
|
||||
background: `url(${logo})`,
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left'
|
||||
};
|
||||
|
||||
const Header = () => (
|
||||
<div className="Qr-Centered">
|
||||
<div style={logoStyle}>
|
||||
<h1 className="Qr-title"> </h1>
|
||||
</div>
|
||||
<p className="Qr-subtitle">参数化二维码生成器 <sup className="Gray">测试版</sup></p>
|
||||
<InputText/>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Header
|
|
@ -0,0 +1,16 @@
|
|||
import React from "react";
|
||||
import PropTypes from 'prop-types'
|
||||
import '../Qrcode.css';
|
||||
|
||||
const LinkButton = ({ href, value }) => (
|
||||
<a href={href} rel="noopener noreferrer" target="_blank">
|
||||
<button className="dl-btn">{value}</button>
|
||||
</a>
|
||||
)
|
||||
|
||||
LinkButton.propTypes = {
|
||||
href: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default LinkButton;
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {SliderPicker} from 'react-color';
|
||||
import '../Qrcode.css';
|
||||
|
||||
const ParamColor = ({ rendererIndex, paramIndex, value, onChange }) => (
|
||||
<SliderPicker
|
||||
key={"input_" + rendererIndex + "_" + paramIndex}
|
||||
className="Qr-color-picker"
|
||||
color={value}
|
||||
onChangeComplete={onChange}
|
||||
/>
|
||||
)
|
||||
|
||||
ParamColor.propTypes = {
|
||||
rendererIndex: PropTypes.number.isRequired,
|
||||
paramIndex: PropTypes.number.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default ParamColor;
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types'
|
||||
import '../Qrcode.css';
|
||||
|
||||
const ParamCorrectLevel = ({ value, onChange }) => (
|
||||
<tr>
|
||||
<td>容错率</td>
|
||||
<td>
|
||||
<select
|
||||
className="Qr-select"
|
||||
value={value}
|
||||
onChange={onChange}>
|
||||
<option value={1}>7%</option>
|
||||
<option value={0}>15%</option>
|
||||
<option value={3}>25%</option>
|
||||
<option value={2}>30%</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
||||
ParamCorrectLevel.propTypes = {
|
||||
value: PropTypes.number.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default ParamCorrectLevel;
|
|
@ -0,0 +1,50 @@
|
|||
import React from 'react';
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import PropTypes from "prop-types"
|
||||
import ParamTextViewer from "../../containers/param/ParamTextViewer";
|
||||
import ParamSelectViewer from "../../containers/param/ParamSelectViewer";
|
||||
import ParamColorViewer from "../../containers/param/ParamColorViewer";
|
||||
|
||||
const ParamList = ({ rendererIndex, paramInfo }) => (
|
||||
paramInfo.map((item, paramIndex) => {
|
||||
switch (item.type) {
|
||||
case ParamTypes.TEXT_EDITOR: {
|
||||
return (
|
||||
<tr key={"tr_" + rendererIndex + "_" + paramIndex}>
|
||||
<td>{item.key}</td>
|
||||
<td>
|
||||
<ParamTextViewer rendererIndex={rendererIndex} paramIndex={paramIndex}/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
case ParamTypes.SELECTOR: {
|
||||
return (
|
||||
<tr key={"tr_" + rendererIndex + "_" + paramIndex}>
|
||||
<td>{item.key}</td>
|
||||
<td>
|
||||
<ParamSelectViewer rendererIndex={rendererIndex} paramIndex={paramIndex}/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
case ParamTypes.COLOR_EDITOR: {
|
||||
return (
|
||||
<tr key={"tr_" + rendererIndex + "_" + paramIndex}>
|
||||
<td>{item.key}</td>
|
||||
<td>
|
||||
<ParamColorViewer rendererIndex={rendererIndex} paramIndex={paramIndex}/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
ParamList.propTypes = {
|
||||
rendererIndex: PropTypes.number.isRequired,
|
||||
paramInfo: PropTypes.array
|
||||
}
|
||||
|
||||
export default ParamList;
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types'
|
||||
import '../Qrcode.css';
|
||||
|
||||
const ParamList = ({ rendererIndex, paramIndex, value, info, onChange }) => (
|
||||
<select
|
||||
className="Qr-select"
|
||||
key={"select_" + rendererIndex + "_" + paramIndex}
|
||||
value={value}
|
||||
onChange={onChange}>
|
||||
{
|
||||
info.choices.map((choice, index) => {
|
||||
return (
|
||||
<option key={"option_" + rendererIndex + "_" + paramIndex + "_" + index } value={index}>
|
||||
{choice}
|
||||
</option>
|
||||
);
|
||||
})
|
||||
}
|
||||
</select>
|
||||
)
|
||||
|
||||
ParamList.propTypes = {
|
||||
rendererIndex: PropTypes.number.isRequired,
|
||||
paramIndex: PropTypes.number.isRequired,
|
||||
value: PropTypes.number.isRequired,
|
||||
info: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default ParamList;
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types'
|
||||
import '../Qrcode.css';
|
||||
|
||||
const ParamText = ({ rendererIndex, paramIndex, value, onBlur, onKeyPress }) => (
|
||||
<input
|
||||
type="number"
|
||||
key={"input_" + rendererIndex + "_" + paramIndex}
|
||||
className="Qr-input small-input"
|
||||
placeholder={value}
|
||||
defaultValue={value}
|
||||
onBlur={onBlur}
|
||||
onKeyPress={onKeyPress}
|
||||
/>
|
||||
)
|
||||
|
||||
ParamText.propTypes = {
|
||||
rendererIndex: PropTypes.number.isRequired,
|
||||
paramIndex: PropTypes.number.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onBlur: PropTypes.func.isRequired,
|
||||
onKeyPress: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default ParamText;
|
|
@ -0,0 +1,82 @@
|
|||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = new Array(nCount);
|
||||
|
||||
let size = 1.001;
|
||||
let size2 = 1.001;
|
||||
let height = params[0];
|
||||
let height2 = params[1];
|
||||
let id = 0;
|
||||
|
||||
const X = [-Math.sqrt(3)/2, 1/2];
|
||||
const Y = [ Math.sqrt(3)/2, 1/2];
|
||||
const Z = [0, 0];
|
||||
|
||||
const matrixString = 'matrix(' + String(X[0]) + ', ' + String(X[1]) + ', ' + String(Y[0]) + ', ' + String(Y[1]) + ', ' + String(Z[0]) + ', ' + String(Z[1]) + ')'
|
||||
|
||||
if (height <= 0) height = 1.0;
|
||||
if (height2 <= 0) height2 = 1.0;
|
||||
|
||||
for (let x = 0; x < nCount; x++) {
|
||||
for (let y = 0; y < nCount; y++) {
|
||||
if (qrcode.isDark(x, y) == false) continue;
|
||||
else if (typeTable[x][y] == QRPointType.POS_OTHER || typeTable[x][y] == QRPointType.POS_CENTER) {
|
||||
pointList.push(<rect width={size2} height={size2} key={id++} fill="#FF7F89" x={x + (1 - size2)/2} y={y + (1 - size2)/2} transform={matrixString}/>);
|
||||
pointList.push(<rect width={height2} height={size2} key={id++} fill="#FFEBF3" x={0} y={0} transform={matrixString+'translate('+String(x + (1 - size2)/2 + size2)+','+String(y + (1 - size2)/2)+') '+'skewY(45) '}/>);
|
||||
pointList.push(<rect width={size2} height={height2} key={id++} fill="#FFD7D9" x={0} y={0} transform={matrixString+'translate('+String(x + (1 - size2)/2)+','+String(y + size2 + (1 - size2)/2)+') '+'skewX(45) '}/>);
|
||||
}
|
||||
else {
|
||||
pointList.push(<rect width={size} height={size} key={id++} fill="#FF7F89" x={x + (1 - size)/2} y={y + (1 - size)/2} transform={matrixString}/>);
|
||||
pointList.push(<rect width={height} height={size} key={id++} fill="#FFEBF3" x={0} y={0} transform={matrixString+'translate('+String(x + (1 - size)/2 + size)+','+String(y + (1 - size)/2)+') '+'skewY(45) '}/>);
|
||||
pointList.push(<rect width={size} height={height} key={id++} fill="#FFD7D9" x={0} y={0} transform={matrixString+'translate('+String(x + (1 - size)/2)+','+String(y + size + (1 - size)/2)+') '+'skewX(45) '}/>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointList;
|
||||
}
|
||||
|
||||
function getParamInfo() {
|
||||
return [
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '柱体高度',
|
||||
default: 0.5,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '定位点柱体高度',
|
||||
default: 0.5,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function viewBox(qrcode) {
|
||||
if (!qrcode) return '0 0 0 0';
|
||||
|
||||
const nCount = qrcode.getModuleCount();
|
||||
return String(-nCount) + ' ' + String(-nCount / 2) + ' ' + String(nCount * 2) + ' ' + String(nCount * 2);
|
||||
}
|
||||
|
||||
const Renderer25D = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={viewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default Renderer25D
|
|
@ -0,0 +1,132 @@
|
|||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox, rand} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = new Array(nCount);
|
||||
|
||||
let type = params[0];
|
||||
let size = params[1] / 100;
|
||||
let opacity = params[2] / 100;
|
||||
let posType = params[3];
|
||||
let id = 0;
|
||||
let otherColor = params[4];
|
||||
let posColor = params[5];
|
||||
|
||||
const vw = [3, -3];
|
||||
const vh = [3, -3];
|
||||
|
||||
if (size <= 0) size = 1.0
|
||||
|
||||
for (let x = 0; x < nCount; x++) {
|
||||
for (let y = 0; y < nCount; y++) {
|
||||
if (qrcode.isDark(x, y) == false) continue;
|
||||
|
||||
if (typeTable[x][y] == QRPointType.ALIGN_CENTER || typeTable[x][y] == QRPointType.ALIGN_OTHER || typeTable[x][y] == QRPointType.TIMING) {
|
||||
if (type == 0)
|
||||
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
|
||||
else if (type == 1)
|
||||
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
|
||||
else if (type == 2)
|
||||
pointList.push(<circle key={id++} opacity={opacity} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={size / 2} />)
|
||||
}
|
||||
else if (typeTable[x][y] == QRPointType.POS_CENTER) {
|
||||
if (posType == 0) {
|
||||
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
|
||||
} else if (posType == 1) {
|
||||
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
|
||||
pointList.push(<circle key={id++} fill={posColor} strokeWidth="1" stroke="black" cx={x + 0.5} cy={y + 0.5} r={3} />)
|
||||
} else if (posType == 2) {
|
||||
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
|
||||
pointList.push(<circle key={id++} fill="none" strokeWidth="0.15" strokeDasharray="0.5,0.5" stroke="black" cx={x + 0.5} cy={y + 0.5} r={3} />)
|
||||
for (let w = 0; w < vw.length; w++) {
|
||||
pointList.push(<circle key={id++} fill={posColor} cx={x + vw[w] + 0.5} cy={y + 0.5} r={0.5} />)
|
||||
}
|
||||
for (let h = 0; h < vh.length; h++) {
|
||||
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + vh[h] + 0.5} r={0.5} />)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeTable[x][y] == QRPointType.POS_OTHER) {
|
||||
if (posType == 0) {
|
||||
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (type == 0)
|
||||
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
|
||||
else if (type == 1)
|
||||
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
|
||||
else if (type == 2)
|
||||
pointList.push(<circle opacity={opacity} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={0.5 * rand(0.33,1.0)} />)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointList;
|
||||
}
|
||||
|
||||
function getParamInfo() {
|
||||
return [
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '信息点样式',
|
||||
default: 0,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点缩放',
|
||||
default: 100
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点不透明度',
|
||||
default: 100,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '定位点样式',
|
||||
default: 0,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
{
|
||||
type: ParamTypes.COLOR_EDITOR,
|
||||
key: '信息点颜色',
|
||||
default: '#000000'
|
||||
},
|
||||
{
|
||||
type: ParamTypes.COLOR_EDITOR,
|
||||
key: '定位点点颜色',
|
||||
default: '#000000'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
const RendererBase = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RendererBase
|
|
@ -0,0 +1,25 @@
|
|||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox} from "../../utils/util";
|
||||
|
||||
function listPoints(qrcode, params) {
|
||||
return []
|
||||
}
|
||||
|
||||
function getParamInfo() {
|
||||
return [];
|
||||
}
|
||||
|
||||
const RenderBlank = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RenderBlank
|
|
@ -1,21 +1,20 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {getTypeTable, QRPointType} from "../utils/qrcodeHandler";
|
||||
import {defaultRenderer, defaultViewBox, rand} from "../utils/util";
|
||||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoint(props) {
|
||||
if (!props.qrcode) return []
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const qrcode = props.qrcode;
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = [];
|
||||
const g1 = [];
|
||||
const g2 = [];
|
||||
|
||||
let width2 = props.params[0] / 100;
|
||||
let width1 = props.params[1] / 100;
|
||||
let posType = props.params[2];
|
||||
let width2 = params[0] / 100;
|
||||
let width1 = params[1] / 100;
|
||||
let posType = params[2];
|
||||
let id = 0;
|
||||
|
||||
if (width2 <= 0) width2 = 70;
|
||||
|
@ -159,39 +158,41 @@ function listPoint(props) {
|
|||
return pointList;
|
||||
}
|
||||
|
||||
export default class QrRendererDSJ extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (this.props.setParamInfo) {
|
||||
this.props.setParamInfo([
|
||||
{
|
||||
key: '信息点缩放',
|
||||
default: 70,
|
||||
},
|
||||
{
|
||||
key: 'x 宽度',
|
||||
default: 70,
|
||||
},
|
||||
{
|
||||
key: '定位点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"DSJ",
|
||||
]
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoint(this.props)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
function getParamInfo() {
|
||||
return [
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点缩放',
|
||||
default: 70,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: 'x 宽度',
|
||||
default: 70,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '定位点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"DSJ",
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const RenderDSJ = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RenderDSJ
|
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {defaultRenderer, defaultViewBox, rand} from "../utils/util";
|
||||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox, rand} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoint(props) {
|
||||
if (!props.qrcode) return []
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const qrcode = props.qrcode;
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const pointList = [];
|
||||
let id = 0;
|
||||
|
@ -38,14 +38,21 @@ function listPoint(props) {
|
|||
return pointList;
|
||||
}
|
||||
|
||||
export default class QrRendererRandRect extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoint(this.props)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
function getParamInfo() {
|
||||
return []
|
||||
}
|
||||
|
||||
const RendererRandRect = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RendererRandRect
|
|
@ -1,20 +1,19 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {getTypeTable, QRPointType} from "../utils/qrcodeHandler";
|
||||
import {defaultRenderer, defaultViewBox, rand} from "../utils/util";
|
||||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox, rand} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoint(props) {
|
||||
if (!props.qrcode) return []
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const qrcode = props.qrcode;
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = new Array(nCount);
|
||||
|
||||
let type = props.params[0];
|
||||
let size = props.params[1] / 100;
|
||||
let opacity = props.params[2] / 100;
|
||||
let posType = props.params[3];
|
||||
let type = params[0];
|
||||
let size = params[1] / 100;
|
||||
let opacity = params[2] / 100;
|
||||
let posType = params[3];
|
||||
let id = 0;
|
||||
|
||||
const vw = [3, -3];
|
||||
|
@ -70,49 +69,52 @@ function listPoint(props) {
|
|||
return pointList;
|
||||
}
|
||||
|
||||
export default class QrRendererBase extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (this.props.setParamInfo) {
|
||||
this.props.setParamInfo([
|
||||
{
|
||||
key: '信息点样式',
|
||||
default: 0,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: '信息点缩放',
|
||||
default: 100
|
||||
},
|
||||
{
|
||||
key: '信息点不透明度',
|
||||
default: 100,
|
||||
},
|
||||
{
|
||||
key: '定位点样式',
|
||||
default: 0,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoint(this.props)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
function getParamInfo() {
|
||||
return [
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '信息点样式',
|
||||
default: 2,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点缩放',
|
||||
default: 80
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点不透明度',
|
||||
default: 100,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '定位点样式',
|
||||
default: 2,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const RendererRandRound = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RendererRandRound
|
|
@ -1,20 +1,19 @@
|
|||
import React from "react";
|
||||
import './Qrcode.css'
|
||||
import {getTypeTable, QRPointType} from "../utils/qrcodeHandler";
|
||||
import {defaultRenderer, defaultViewBox, rand} from "../utils/util";
|
||||
import React, { useEffect } from "react";
|
||||
import {defaultViewBox, rand} from "../../utils/util";
|
||||
import {ParamTypes} from "../../constant/ParamTypes";
|
||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||
|
||||
function listPoint(props) {
|
||||
if (!props.qrcode) return []
|
||||
function listPoints(qrcode, params) {
|
||||
if (!qrcode) return []
|
||||
|
||||
const qrcode = props.qrcode;
|
||||
const nCount = qrcode.getModuleCount();
|
||||
const typeTable = getTypeTable(qrcode);
|
||||
const pointList = new Array(nCount);
|
||||
|
||||
let type = props.params[0];
|
||||
let size = props.params[1] / 100;
|
||||
let opacity = props.params[2] / 100;
|
||||
let posType = props.params[3];
|
||||
let type = params[0];
|
||||
let size = params[1] / 100;
|
||||
let opacity = params[2] / 100;
|
||||
let posType = params[3];
|
||||
let id = 0;
|
||||
|
||||
const vw = [3, -3];
|
||||
|
@ -70,49 +69,52 @@ function listPoint(props) {
|
|||
return pointList;
|
||||
}
|
||||
|
||||
export default class QrRendererRound extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (this.props.setParamInfo) {
|
||||
this.props.setParamInfo([
|
||||
{
|
||||
key: '信息点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
key: '信息点缩放',
|
||||
default: 50
|
||||
},
|
||||
{
|
||||
key: '信息点不透明度',
|
||||
default: 30,
|
||||
},
|
||||
{
|
||||
key: '定位点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(this.props.qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoint(this.props)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
function getParamInfo() {
|
||||
return [
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '信息点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"随机"
|
||||
]
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点缩放',
|
||||
default: 50
|
||||
},
|
||||
{
|
||||
type: ParamTypes.TEXT_EDITOR,
|
||||
key: '信息点不透明度',
|
||||
default: 30,
|
||||
},
|
||||
{
|
||||
type: ParamTypes.SELECTOR,
|
||||
key: '定位点样式',
|
||||
default: 1,
|
||||
choices: [
|
||||
"矩形",
|
||||
"圆形",
|
||||
"行星",
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const RendererRound = ({ qrcode, params, setParamInfo}) => {
|
||||
useEffect(() => {
|
||||
setParamInfo(getParamInfo());
|
||||
}, [setParamInfo]);
|
||||
|
||||
return (
|
||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||
{listPoints(qrcode, params)}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default RendererRound
|
|
@ -0,0 +1,11 @@
|
|||
import React from "react";
|
||||
|
||||
const Renderer = ({ rendererType, ...other }) => (
|
||||
React.createElement(rendererType, other)
|
||||
)
|
||||
|
||||
function areEqual(prevProps, nextProps) {
|
||||
return !(prevProps.selected == true || nextProps.selected == true)
|
||||
}
|
||||
|
||||
export default React.memo(Renderer, areEqual)
|
|
@ -0,0 +1,30 @@
|
|||
import React from "react";
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
function calClassName(selected) {
|
||||
if (selected === true) return 'Qr-item Qr-item-selected';
|
||||
return 'Qr-item';
|
||||
}
|
||||
|
||||
const Style = ({ value, renderer, selected, onSelected }) => (
|
||||
<div className={calClassName(selected)}
|
||||
onMouseDown={onSelected}>
|
||||
<div className="Qr-item-image">
|
||||
<div className="Qr-item-image-inner">
|
||||
{renderer}
|
||||
</div>
|
||||
</div>
|
||||
<div className="Qr-item-detail">
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Style.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
renderer: PropTypes.object.isRequired,
|
||||
selected: PropTypes.bool.isRequired,
|
||||
onSelected: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default Style;
|
|
@ -0,0 +1,26 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Style from "./Style";
|
||||
|
||||
const StyleList = ({ styles, onSelected }) => (
|
||||
<div className="Qr-box">
|
||||
{styles.map((style, index) =>
|
||||
<Style
|
||||
key={style.value}
|
||||
{...style}
|
||||
onSelected={() => onSelected(index)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
StyleList.propTypes = {
|
||||
styles: PropTypes.arrayOf(PropTypes.shape({
|
||||
value: PropTypes.string.isRequired,
|
||||
renderer: PropTypes.object.isRequired,
|
||||
selected: PropTypes.bool.isRequired
|
||||
}).isRequired).isRequired,
|
||||
onSelected: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default StyleList;
|
|
@ -0,0 +1,7 @@
|
|||
export const actionTypes = {
|
||||
GENERATE_QR_INFO: 'GENERATE_QR_INFO',
|
||||
CHANGE_STYLE: 'CHANGE_STYLE',
|
||||
CHANGE_CORRECT_LEVEL: 'CHANGE_CORRECT_LEVEL',
|
||||
CREATE_PARAM: 'CREATE_PARAM',
|
||||
CHANGE_PARAM: 'CHANGE_PARAM'
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export const ParamTypes = {
|
||||
TEXT_EDITOR: 1,
|
||||
SELECTOR: 2,
|
||||
COLOR_EDITOR: 3,
|
||||
MULTI_CHECK: 4,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export const QRBTF_URL = 'https://qrbtf.com'
|
|
@ -0,0 +1,16 @@
|
|||
import {connect} from 'react-redux';
|
||||
import {genQRInfo} from "../actions";
|
||||
import React from "react";
|
||||
|
||||
const InputText = ({dispatch}) => (
|
||||
<input
|
||||
className="Qr-input big-input"
|
||||
placeholder="Input your URL here"
|
||||
onBlur={e => dispatch(genQRInfo(e.target.value))}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === 'Enter') dispatch(genQRInfo(e.target.value))
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
export default connect()(InputText);
|
|
@ -1,4 +0,0 @@
|
|||
.Layout {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
import React from "react";
|
||||
import './Layout.css'
|
||||
|
||||
const Layout = (props) => {
|
||||
return (
|
||||
<div className="Layout">
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Layout;
|
|
@ -0,0 +1,8 @@
|
|||
import { connect } from 'react-redux';
|
||||
import PartDownload from "../../components/app/PartDownload";
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: state.value
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, null)(PartDownload)
|
|
@ -0,0 +1,9 @@
|
|||
import {connect} from "react-redux";
|
||||
import PartStyles from "../../components/app/PartStyles";
|
||||
import {createParam} from "../../actions";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setParamInfo: (paramInfo, paramValue) => dispatch(createParam(paramInfo, paramValue))
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps)(PartStyles)
|
|
@ -0,0 +1,34 @@
|
|||
import { connect } from 'react-redux';
|
||||
import React from 'react';
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import DownloadButton from "../../components/download/DownloadButton";
|
||||
import {saveImg} from "../../utils/downloader";
|
||||
import {increaseDownloadData, recordDownloadDetail} from "../../api/db";
|
||||
import {getParamDetailedValue} from "../../utils/util";
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: 'JPG',
|
||||
onClick: () => {
|
||||
const el = React.createElement(state.rendererType, {
|
||||
qrcode: state.qrcode,
|
||||
params: state.paramValue[state.selectedIndex],
|
||||
setParamInfo: () => {}
|
||||
});
|
||||
saveImg(state.value, ReactDOMServer.renderToString(el), 1500, 1500);
|
||||
increaseDownloadData(state.value)
|
||||
recordDownloadDetail({
|
||||
text: state.textUrl,
|
||||
value: state.value,
|
||||
type: 'jpg',
|
||||
params: state.paramInfo[state.selectedIndex].map((item, index) => {
|
||||
return {
|
||||
key: item.key,
|
||||
value: getParamDetailedValue(item, state.paramValue[state.selectedIndex][index])
|
||||
}
|
||||
}),
|
||||
history: state.history
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(DownloadButton)
|
|
@ -0,0 +1,34 @@
|
|||
import { connect } from 'react-redux';
|
||||
import React from 'react';
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import DownloadButton from "../../components/download/DownloadButton";
|
||||
import {saveSvg} from "../../utils/downloader";
|
||||
import {increaseDownloadData, recordDownloadDetail} from "../../api/db";
|
||||
import {getParamDetailedValue} from "../../utils/util";
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: 'SVG',
|
||||
onClick: () => {
|
||||
const el = React.createElement(state.rendererType, {
|
||||
qrcode: state.qrcode,
|
||||
params: state.paramValue[state.selectedIndex],
|
||||
setParamInfo: () => {}
|
||||
});
|
||||
saveSvg(state.value, ReactDOMServer.renderToString(el));
|
||||
increaseDownloadData(state.value)
|
||||
recordDownloadDetail({
|
||||
text: state.textUrl,
|
||||
value: state.value,
|
||||
type: 'svg',
|
||||
params: state.paramInfo[state.selectedIndex].map((item, index) => {
|
||||
return {
|
||||
key: item.key,
|
||||
value: getParamDetailedValue(item, state.paramValue[state.selectedIndex][index])
|
||||
}
|
||||
}),
|
||||
history: state.history
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(DownloadButton)
|
|
@ -0,0 +1,17 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {changeParam} from "../../actions";
|
||||
import ParamColor from "../../components/param/ParamColor";
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
rendererIndex: ownProps.rendererIndex,
|
||||
paramIndex: ownProps.paramIndex,
|
||||
value: state.paramValue[ownProps.rendererIndex][ownProps.paramIndex]
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||
onChange: (color) => {
|
||||
dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, color.hex))
|
||||
}
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ParamColor);
|
|
@ -0,0 +1,15 @@
|
|||
import {changeCorrectLevel} from "../../actions";
|
||||
import ParamCorrectLevel from "../../components/param/ParamCorrectLevel";
|
||||
import {connect} from "react-redux";
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
value: state.correctLevel
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onChange: (e) => {
|
||||
dispatch(changeCorrectLevel(e.target.value));
|
||||
}
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ParamCorrectLevel)
|
|
@ -0,0 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ParamList from "../../components/param/ParamList";
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
rendererIndex: state.selectedIndex,
|
||||
paramInfo: state.paramInfo[state.selectedIndex]
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, null)(ParamList)
|
|
@ -0,0 +1,18 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {changeParam} from "../../actions";
|
||||
import ParamSelect from "../../components/param/ParamSelect";
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
rendererIndex: ownProps.rendererIndex,
|
||||
paramIndex: ownProps.paramIndex,
|
||||
value: state.paramValue[ownProps.rendererIndex][ownProps.paramIndex],
|
||||
info: state.paramInfo[ownProps.rendererIndex][ownProps.paramIndex],
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||
onChange: (e) => {
|
||||
dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, e.target.value))
|
||||
}
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ParamSelect);
|
|
@ -0,0 +1,21 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ParamText from "../../components/param/ParamText";
|
||||
import {changeParam} from "../../actions";
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
rendererIndex: ownProps.rendererIndex,
|
||||
paramIndex: ownProps.paramIndex,
|
||||
value: String(state.paramValue[ownProps.rendererIndex][ownProps.paramIndex])
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||
onBlur: (e) => dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, e.target.value)),
|
||||
onKeyPress: (e) => {
|
||||
if(e.key === 'Enter') {
|
||||
dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, e.target.value));
|
||||
e.target.blur()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ParamText);
|
|
@ -0,0 +1,18 @@
|
|||
import {connect} from 'react-redux';
|
||||
import Renderer from "../../components/style/Renderer";
|
||||
import {fillEmptyWith} from "../../utils/util";
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
rendererType: ownProps.rendererType,
|
||||
rendererIndex: ownProps.index,
|
||||
qrcode: state.qrcode,
|
||||
params: fillEmptyWith(state.paramValue[ownProps.index].slice(), 0),
|
||||
selected: state.selectedIndex == ownProps.index,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||
setParamInfo: (params) => ownProps.setParamInfo(ownProps.index, params)
|
||||
})
|
||||
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Renderer)
|
|
@ -0,0 +1,56 @@
|
|||
import {connect, useDispatch} from 'react-redux';
|
||||
import {changeStyle, createParam} from "../../actions";
|
||||
import StyleList from "../../components/style/StyleList";
|
||||
import RendererViewer from "./RendererViewer";
|
||||
import RendererBlank from "../../components/renderer/RendererBlank";
|
||||
import RendererBase from "../../components/renderer/RendererBase";
|
||||
import RendererDSJ from "../../components/renderer/RendererDSJ";
|
||||
import RendererRound from "../../components/renderer/RendererRound";
|
||||
import RendererRandRound from "../../components/renderer/RendererRandRound";
|
||||
import RendererRandRect from "../../components/renderer/RendererRandRect";
|
||||
import Renderer25D from "../../components/renderer/Renderer25D";
|
||||
import RendererImage from "../../components/renderer/RendererImage";
|
||||
import * as React from "react";
|
||||
|
||||
const styles = [
|
||||
{value: "A1", renderer: RendererBase},
|
||||
{value: "A2", renderer: RendererRound},
|
||||
{value: "A3", renderer: RendererRandRound},
|
||||
{value: "SP — 1", renderer: RendererDSJ},
|
||||
{value: "SP — 2", renderer: RendererRandRect},
|
||||
{value: "B1", renderer: Renderer25D},
|
||||
{value: "C1", renderer: RendererImage},
|
||||
{value: "D1", renderer: RendererBlank},
|
||||
]
|
||||
|
||||
const paramInfoBuffer = new Array(16).fill(new Array(16))
|
||||
const paramValueBuffer = new Array(16).fill(new Array(16))
|
||||
|
||||
const setParamInfo = (renderIndex, paramInfo) => {
|
||||
paramInfoBuffer[renderIndex] = paramInfo
|
||||
paramValueBuffer[renderIndex] = paramInfo.map(item => item.default)
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
styles: styles.map((style, index) => {
|
||||
return {
|
||||
value: style.value,
|
||||
selected: state.selectedIndex == index,
|
||||
renderer: <RendererViewer rendererType={style.renderer} index={index} setParamInfo={setParamInfo}/>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onSelected: rendererIndex => {
|
||||
dispatch(changeStyle(rendererIndex, styles[rendererIndex].renderer, styles[rendererIndex].value))
|
||||
}
|
||||
})
|
||||
|
||||
const StyleListViewer = ({setParamInfo}) => {
|
||||
let res = connect(mapStateToProps, mapDispatchToProps)(StyleList)
|
||||
setParamInfo(paramInfoBuffer, paramValueBuffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
export default StyleListViewer;
|
11
src/index.js
11
src/index.js
|
@ -1,12 +1,19 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import App from './components/app/App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
import { Provider } from 'react-redux';
|
||||
import rootReducer from './reducers';
|
||||
import {createStore} from "redux";
|
||||
|
||||
const store = createStore(rootReducer);
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import {getQrcodeData} from "../utils/qrcodeHandler";
|
||||
import {actionTypes} from "../constant/ActionTypes";
|
||||
import {QRBTF_URL} from "../constant/References";
|
||||
import RendererBase from "../components/renderer/RendererBase";
|
||||
|
||||
const initialState = {
|
||||
selectedIndex: 0,
|
||||
value: 'A1',
|
||||
rendererType: RendererBase,
|
||||
correctLevel: 0,
|
||||
textUrl: QRBTF_URL,
|
||||
history: [],
|
||||
qrcode: getQrcodeData({text: QRBTF_URL, correctLevel: 0}),
|
||||
paramInfo: new Array(16).fill(new Array(16)),
|
||||
paramValue: new Array(16).fill(new Array(16))
|
||||
}
|
||||
|
||||
export default function appReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case actionTypes.GENERATE_QR_INFO: {
|
||||
let text = action.text;
|
||||
if (!text || text.length == 0) text = QRBTF_URL;
|
||||
return Object.assign({}, state, {
|
||||
textUrl: text,
|
||||
qrcode: getQrcodeData({text: text, correctLevel: state.correctLevel})
|
||||
});
|
||||
}
|
||||
case actionTypes.CHANGE_STYLE: {
|
||||
return Object.assign({}, state, {
|
||||
value: action.value,
|
||||
rendererType: action.rendererType,
|
||||
selectedIndex: action.rendererIndex,
|
||||
history: state.history.slice().concat(action.value)
|
||||
});
|
||||
}
|
||||
case actionTypes.CHANGE_CORRECT_LEVEL: {
|
||||
return Object.assign({}, state, {
|
||||
correctLevel: parseInt(action.correctLevel),
|
||||
qrcode: getQrcodeData({text: state.textUrl, correctLevel: parseInt(action.correctLevel)})
|
||||
})
|
||||
}
|
||||
case actionTypes.CREATE_PARAM: {
|
||||
return Object.assign({}, state, {
|
||||
paramInfo: action.paramInfo,
|
||||
paramValue: action.paramValue
|
||||
})
|
||||
}
|
||||
case actionTypes.CHANGE_PARAM: {
|
||||
return Object.assign({}, state, {
|
||||
paramValue: state.paramValue.map((item, index) => {
|
||||
if (index != action.rendererIndex) {
|
||||
return item;
|
||||
}
|
||||
|
||||
const newItem = item.slice();
|
||||
newItem[action.paramIndex] = isNaN(action.value) ? action.value : parseInt(action.value);
|
||||
return newItem;
|
||||
})
|
||||
});
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
//---------------------------------------------------------------------
|
||||
// QR8bitByte
|
||||
//---------------------------------------------------------------------
|
||||
/* eslint-disable */
|
||||
|
||||
function QR8bitByte(data) {
|
||||
this.mode = QRMode.MODE_8BIT_BYTE;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import {ParamTypes} from "../constant/ParamTypes";
|
||||
|
||||
let seed = 0;
|
||||
|
||||
|
@ -22,6 +22,11 @@ export function defaultViewBox(qrcode) {
|
|||
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
|
||||
}
|
||||
|
||||
export function fillEmptyWith(arr, value) {
|
||||
for (let i = 0; i < arr.length; i++)
|
||||
if (!arr[i]) arr[i] = value;
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function isWeiXin(){
|
||||
const ua = window.navigator.userAgent.toLowerCase();
|
||||
|
@ -31,3 +36,8 @@ export function isWeiXin(){
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getParamDetailedValue(item, paramValue) {
|
||||
if (item.type == ParamTypes.SELECTOR) return item.choices[paramValue];
|
||||
return paramValue;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue