[Image box for saving]
This commit is contained in:
parent
1680f6582f
commit
403ea01769
|
@ -7,15 +7,18 @@ const auth = app.auth();
|
||||||
|
|
||||||
async function login() {
|
async function login() {
|
||||||
await auth.signInAnonymously();
|
await auth.signInAnonymously();
|
||||||
// const loginState = await auth.getLoginState();
|
const loginState = await auth.getLoginState();
|
||||||
|
isLogin = loginState
|
||||||
}
|
}
|
||||||
|
|
||||||
login();
|
login();
|
||||||
|
|
||||||
|
let isLogin;
|
||||||
const db = app.database();
|
const db = app.database();
|
||||||
const _ = db.command
|
const _ = db.command
|
||||||
|
|
||||||
export function increaseDownloadData(value) {
|
export function increaseDownloadData(value) {
|
||||||
|
if (!isLogin) return;
|
||||||
db.collection('QRCounter').where({
|
db.collection('QRCounter').where({
|
||||||
value: _.eq(value)
|
value: _.eq(value)
|
||||||
}).get().then(res => {
|
}).get().then(res => {
|
||||||
|
@ -25,21 +28,20 @@ export function increaseDownloadData(value) {
|
||||||
}).update({
|
}).update({
|
||||||
count: _.inc(1),
|
count: _.inc(1),
|
||||||
date: new Date().toString()
|
date: new Date().toString()
|
||||||
}).then(res => {
|
}).catch(console.error)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
db.collection('QRCounter').add({
|
db.collection('QRCounter').add({
|
||||||
value: value,
|
value: value,
|
||||||
count: 1,
|
count: 1,
|
||||||
date: new Date().toString()
|
date: new Date().toString()
|
||||||
}).then(res => {
|
}).catch(console.error)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordDownloadDetail({text, value, type, params, history}) {
|
export function recordDownloadDetail({text, value, type, params, history}) {
|
||||||
|
if (!isLogin) return;
|
||||||
db.collection('QRDownloadData').add({
|
db.collection('QRDownloadData').add({
|
||||||
date: new Date().toString(),
|
date: new Date().toString(),
|
||||||
text: text,
|
text: text,
|
||||||
|
@ -47,6 +49,5 @@ export function recordDownloadDetail({text, value, type, params, history}) {
|
||||||
type: type,
|
type: type,
|
||||||
params: params,
|
params: params,
|
||||||
history: history
|
history: history
|
||||||
}).then(res => {
|
}).catch(console.error)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,50 @@
|
||||||
import React from 'react';
|
import React, {useState} from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import DownloadSvg from "../../containers/download/DownloadSvg";
|
import PropTypes from 'prop-types';
|
||||||
import DownloadJpg from "../../containers/download/DownloadJpg";
|
|
||||||
import {isWeiXin} from "../../utils/util";
|
import {isWeiXin} from "../../utils/util";
|
||||||
|
|
||||||
const WxMessage = () => {
|
const WxMessage = () => {
|
||||||
if (isWeiXin()) {
|
if (isWeiXin()) {
|
||||||
return <div className="note-font" id="wx-message-inner">当前客户端不支持下载,请在浏览器中打开。</div>
|
return <div className="note-font" id="wx-message-inner">当前客户端不支持下载,请长按图片保存。</div>
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartDownload = ({ value }) => (
|
const PartDownload = ({ value, onSvgDownload, onJpgDownload }) => {
|
||||||
<div className="Qr-titled">
|
const [imgData, setImgData] = useState('');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="Qr-titled">
|
||||||
<div className="Qr-Centered title-margin">
|
<div className="Qr-Centered title-margin">
|
||||||
<div className="Qr-s-title">Downloads</div>
|
<div className="Qr-s-title">Downloads</div>
|
||||||
<p className="Qr-s-subtitle">下载二维码 — {value}</p>
|
<p className="Qr-s-subtitle">下载二维码 — {value}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
<div className="div-btn">
|
<div className="div-btn">
|
||||||
<DownloadSvg/>
|
<button className="dl-btn" onClick={onSvgDownload}>SVG</button>
|
||||||
<DownloadJpg/>
|
<button className="dl-btn" onClick={() => {
|
||||||
|
onJpgDownload().then(res => setImgData(res));
|
||||||
|
}}>
|
||||||
|
JPG
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="wx-message">
|
<div id="wx-message">
|
||||||
<WxMessage/>
|
<WxMessage/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
imgData.length > 0 ? <img src={imgData} width={300} height={300} alt="点击JPG下载" /> : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PartDownload.propTypes = {
|
||||||
|
value: PropTypes.string.isRequired,
|
||||||
|
onSvgDownload: PropTypes.func.isRequired,
|
||||||
|
onJpgDownload: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
export default PartDownload;
|
export default PartDownload;
|
||||||
|
|
|
@ -7,14 +7,16 @@ const PartStyles = ({ setParamInfo }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoaded(true);
|
setLoaded(true);
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const styleList = React.createElement(StyleListViewer({setParamInfo}))
|
const styleList = React.createElement(StyleListViewer({setParamInfo}))
|
||||||
|
console.log(loaded)
|
||||||
|
|
||||||
return (<div className="Qr-titled">
|
return (<div className="Qr-titled">
|
||||||
<div className="Qr-Centered title-margin">
|
<div className="Qr-Centered title-margin">
|
||||||
<div className="Qr-s-title">Styles</div>
|
<div className="Qr-s-title">Styles</div>
|
||||||
<p className="Qr-s-subtitle">点击选择样式</p>
|
<p className="Qr-s-subtitle">点击选择样式</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="Qr-s">
|
<div className="Qr-s" style={{visibility: loaded ? "visible" :"hidden"}}>
|
||||||
{styleList}
|
{styleList}
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
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;
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import '../Qrcode.css';
|
import '../Qrcode.css';
|
||||||
import logo from "../../qrbtf-logo.svg";
|
import logo from "../../qrbtf-logo.svg";
|
||||||
import InputText from "../../containers/InputText";
|
import InputText from "../../containers/app/InputText";
|
||||||
|
|
||||||
const logoStyle = {
|
const logoStyle = {
|
||||||
background: `url(${logo})`,
|
background: `url(${logo})`,
|
||||||
|
|
|
@ -2,13 +2,13 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import '../Qrcode.css';
|
import '../Qrcode.css';
|
||||||
|
|
||||||
const ParamText = ({ rendererIndex, paramIndex, value, onBlur, onKeyPress }) => (
|
const ParamText = ({ rendererIndex, paramIndex, value, info, onBlur, onKeyPress }) => (
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
key={"input_" + rendererIndex + "_" + paramIndex}
|
key={"input_" + rendererIndex + "_" + paramIndex}
|
||||||
className="Qr-input small-input"
|
className="Qr-input small-input"
|
||||||
placeholder={value}
|
placeholder={info.default}
|
||||||
defaultValue={value}
|
defaultValue={String(value)}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
onKeyPress={onKeyPress}
|
onKeyPress={onKeyPress}
|
||||||
/>
|
/>
|
||||||
|
@ -17,7 +17,8 @@ const ParamText = ({ rendererIndex, paramIndex, value, onBlur, onKeyPress }) =>
|
||||||
ParamText.propTypes = {
|
ParamText.propTypes = {
|
||||||
rendererIndex: PropTypes.number.isRequired,
|
rendererIndex: PropTypes.number.isRequired,
|
||||||
paramIndex: PropTypes.number.isRequired,
|
paramIndex: PropTypes.number.isRequired,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.number.isRequired,
|
||||||
|
info: PropTypes.object.isRequired,
|
||||||
onBlur: PropTypes.func.isRequired,
|
onBlur: PropTypes.func.isRequired,
|
||||||
onKeyPress: PropTypes.func.isRequired
|
onKeyPress: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import {genQRInfo} from "../actions";
|
import {genQRInfo} from "../../actions";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const InputText = ({dispatch}) => (
|
const InputText = ({dispatch}) => (
|
||||||
|
@ -8,7 +8,10 @@ const InputText = ({dispatch}) => (
|
||||||
placeholder="Input your URL here"
|
placeholder="Input your URL here"
|
||||||
onBlur={e => dispatch(genQRInfo(e.target.value))}
|
onBlur={e => dispatch(genQRInfo(e.target.value))}
|
||||||
onKeyPress={(e) => {
|
onKeyPress={(e) => {
|
||||||
if (e.key === 'Enter') dispatch(genQRInfo(e.target.value))
|
if (e.key === 'Enter') {
|
||||||
|
dispatch(genQRInfo(e.target.value));
|
||||||
|
e.target.blur();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
|
@ -1,8 +1,41 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PartDownload from "../../components/app/PartDownload";
|
import PartDownload from "../../components/app/PartDownload";
|
||||||
|
import React from "react";
|
||||||
|
import {saveImg, saveSvg} from "../../utils/downloader";
|
||||||
|
import ReactDOMServer from "react-dom/server";
|
||||||
|
import {increaseDownloadData, recordDownloadDetail} from "../../api/db";
|
||||||
|
import {getParamDetailedValue} from "../../utils/util";
|
||||||
|
|
||||||
|
function saveEl(state, type) {
|
||||||
|
const el = React.createElement(state.rendererType, {
|
||||||
|
qrcode: state.qrcode,
|
||||||
|
params: state.paramValue[state.selectedIndex],
|
||||||
|
setParamInfo: () => {}
|
||||||
|
});
|
||||||
|
increaseDownloadData(state.value)
|
||||||
|
recordDownloadDetail({
|
||||||
|
text: state.textUrl,
|
||||||
|
value: state.value,
|
||||||
|
type: type,
|
||||||
|
params: state.paramInfo[state.selectedIndex].map((item, index) => {
|
||||||
|
return {
|
||||||
|
key: item.key,
|
||||||
|
value: getParamDetailedValue(item, state.paramValue[state.selectedIndex][index])
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
history: state.history
|
||||||
|
});
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
value: state.value
|
value: state.value,
|
||||||
|
onSvgDownload: () => {
|
||||||
|
saveSvg(state.value, ReactDOMServer.renderToString(saveEl(state, 'svg')))
|
||||||
|
},
|
||||||
|
onJpgDownload: () => {
|
||||||
|
return saveImg(state.value, ReactDOMServer.renderToString(saveEl(state, 'jpg')), 1500, 1500)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(PartDownload)
|
export default connect(mapStateToProps, null)(PartDownload)
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
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)
|
|
|
@ -1,34 +0,0 @@
|
||||||
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)
|
|
|
@ -5,7 +5,8 @@ import {changeParam} from "../../actions";
|
||||||
const mapStateToProps = (state, ownProps) => ({
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
rendererIndex: ownProps.rendererIndex,
|
rendererIndex: ownProps.rendererIndex,
|
||||||
paramIndex: ownProps.paramIndex,
|
paramIndex: ownProps.paramIndex,
|
||||||
value: String(state.paramValue[ownProps.rendererIndex][ownProps.paramIndex])
|
value: state.paramValue[ownProps.rendererIndex][ownProps.paramIndex],
|
||||||
|
info: state.paramInfo[ownProps.rendererIndex][ownProps.paramIndex]
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, ownProps) => ({
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import {increaseDownloadData} from "../api/db";
|
|
||||||
|
|
||||||
const svgHead = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n " +
|
const svgHead = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n " +
|
||||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
|
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
|
||||||
|
|
||||||
|
@ -17,8 +15,6 @@ export function saveSvg(value, content) {
|
||||||
a.download = filename
|
a.download = filename
|
||||||
a.hidden = true
|
a.hidden = true
|
||||||
a.click()
|
a.click()
|
||||||
|
|
||||||
increaseDownloadData(value, new Date().toString())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveImg(value, content, width, height) {
|
export function saveImg(value, content, width, height) {
|
||||||
|
@ -43,26 +39,26 @@ export function saveImg(value, content, width, height) {
|
||||||
canvas.setAttribute('height', height);
|
canvas.setAttribute('height', height);
|
||||||
|
|
||||||
let ctx = canvas.getContext('2d');
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
|
|
||||||
|
|
||||||
img.onload = () => {
|
|
||||||
ctx.fillStyle = 'white'
|
|
||||||
ctx.fillRect(0, 0, width, height)
|
|
||||||
ctx.drawImage(img, 0, 0, width, height);
|
|
||||||
// `download` attr is not well supported
|
|
||||||
// Will result in a download popup for chrome and the
|
|
||||||
// image opening in a new tab for others.
|
|
||||||
|
|
||||||
let a = document.createElement('a');
|
|
||||||
a.setAttribute('href', canvas.toDataURL('image/jpeg', 0.8))
|
|
||||||
a.setAttribute('target', 'download')
|
|
||||||
a.setAttribute('download', filename);
|
|
||||||
a.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(svgData));
|
img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(svgData));
|
||||||
|
|
||||||
increaseDownloadData(value, new Date().toString())
|
return new Promise(resolve => {
|
||||||
|
img.onload = () => {
|
||||||
|
ctx.fillStyle = 'white'
|
||||||
|
ctx.fillRect(0, 0, width, height)
|
||||||
|
ctx.drawImage(img, 0, 0, width, height);
|
||||||
|
// `download` attr is not well supported
|
||||||
|
// Will result in a download popup for chrome and the
|
||||||
|
// image opening in a new tab for others.
|
||||||
|
|
||||||
|
let a = document.createElement('a');
|
||||||
|
let data = canvas.toDataURL('image/jpeg', 0.8);
|
||||||
|
a.setAttribute('href', data)
|
||||||
|
a.setAttribute('target', 'download')
|
||||||
|
a.setAttribute('download', filename);
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
resolve(data)
|
||||||
|
};
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue