[Image box for saving]

This commit is contained in:
CPunisher 2020-05-14 13:07:16 +08:00
parent 1680f6582f
commit 403ea01769
12 changed files with 104 additions and 133 deletions

View File

@ -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)
})
} }

View File

@ -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;

View File

@ -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>)

View File

@ -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;

View File

@ -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})`,

View File

@ -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
} }

View File

@ -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();
}
}} }}
/> />
) )

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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) => ({

View File

@ -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)
};
})
} }