676 lines
19 KiB
Vue
676 lines
19 KiB
Vue
<template>
|
|
<div class="hello">
|
|
<h3>Personnalisation du QRCode</h3>
|
|
<div class="row">
|
|
<div class="col-6 code-viewer">
|
|
<div
|
|
id="qr-code"
|
|
ref="div"
|
|
/>
|
|
<div class="download-group">
|
|
<select
|
|
v-model="extension"
|
|
class="form-select"
|
|
>
|
|
<option value="svg">
|
|
SVG
|
|
</option>
|
|
<option value="png">
|
|
PNG
|
|
</option>
|
|
<option value="jpeg">
|
|
JPEG
|
|
</option>
|
|
<option value="webp">
|
|
WEBP
|
|
</option>
|
|
</select>
|
|
<button
|
|
type="button"
|
|
@click="download"
|
|
class="btn btn-primary"
|
|
>
|
|
Download
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div
|
|
class="accordion"
|
|
id="accordionExample"
|
|
>
|
|
<div class="accordion-item">
|
|
<h2
|
|
class="accordion-header"
|
|
id="headingOne"
|
|
>
|
|
<button
|
|
class="accordion-button"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#collapseOne"
|
|
aria-expanded="true"
|
|
aria-controls="collapseOne"
|
|
>
|
|
Options principales
|
|
</button>
|
|
</h2>
|
|
<div
|
|
id="collapseOne"
|
|
class="accordion-collapse collapse show"
|
|
aria-labelledby="headingOne"
|
|
data-bs-parent="#accordionExample"
|
|
>
|
|
<div class="accordion-body">
|
|
<label
|
|
for="width"
|
|
class="form-label"
|
|
>Largeur</label>
|
|
<input
|
|
v-model="options.width"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
type="number"
|
|
id="width"
|
|
>
|
|
|
|
<label
|
|
for="height"
|
|
class="form-label"
|
|
>Hauteur</label>
|
|
<input
|
|
v-model="options.height"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
type="number"
|
|
id="height"
|
|
>
|
|
<label
|
|
for="margin"
|
|
class="form-label"
|
|
>Marge</label>
|
|
<input
|
|
v-model="options.margin"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
type="number"
|
|
id="margin"
|
|
>
|
|
|
|
<div class="row">
|
|
<div class="col-12 my-3">
|
|
<div class="form-check">
|
|
<label
|
|
for="backgroundOptions-transparency"
|
|
class="form-check-label"
|
|
>Transparent ?</label>
|
|
<input
|
|
v-model="isTransparent"
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
id="backgroundOptions-transparency"
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 d-flex justify-content-center">
|
|
<Vue3ColorPicker
|
|
v-show="!isTransparent"
|
|
v-model="pickerColor"
|
|
mode="solid"
|
|
type="HEX"
|
|
input-type="RGB"
|
|
:show-input-menu="false"
|
|
:show-picker-mode="false"
|
|
:show-color-list="false"
|
|
:show-alpha="false"
|
|
@on-change="changeColor"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item">
|
|
<h2
|
|
class="accordion-header"
|
|
id="headingTwo"
|
|
>
|
|
<button
|
|
class="accordion-button collapsed"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#collapseTwo"
|
|
aria-expanded="false"
|
|
aria-controls="collapseTwo"
|
|
>
|
|
Options des points
|
|
</button>
|
|
</h2>
|
|
<div
|
|
id="collapseTwo"
|
|
class="accordion-collapse collapse"
|
|
aria-labelledby="headingTwo"
|
|
data-bs-parent="#accordionExample"
|
|
>
|
|
<div class="accordion-body">
|
|
<label
|
|
for="dotsOptions-color"
|
|
class="form-label"
|
|
>Couleur des points</label>
|
|
<input
|
|
v-model="options.dotsOptions.color"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
id="dotsOptions-color"
|
|
>
|
|
|
|
<label
|
|
for="dotsOptions-type"
|
|
class="form-label"
|
|
>Forme des points</label>
|
|
<select
|
|
v-model="options.dotsOptions.type"
|
|
placeholder="Add data"
|
|
class="form-select"
|
|
id="dotsOptions-type"
|
|
>
|
|
<option value="rounded">
|
|
Rounded
|
|
</option>
|
|
<option value="dots">
|
|
Dots
|
|
</option>
|
|
<option value="classy">
|
|
Classy
|
|
</option>
|
|
<option value="classy-rounded">
|
|
Classy-Rounded
|
|
</option>
|
|
<option value="square">
|
|
Square
|
|
</option>
|
|
<option value="extra-rounded">
|
|
Extra-Rounded
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item">
|
|
<h2
|
|
class="accordion-header"
|
|
id="headingThree"
|
|
>
|
|
<button
|
|
class="accordion-button collapsed"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#collapseThree"
|
|
aria-expanded="false"
|
|
aria-controls="collapseThree"
|
|
>
|
|
Options des coins
|
|
</button>
|
|
</h2>
|
|
<div
|
|
id="collapseThree"
|
|
class="accordion-collapse collapse"
|
|
aria-labelledby="headingThree"
|
|
data-bs-parent="#accordionExample"
|
|
>
|
|
<div class="accordion-body">
|
|
<label
|
|
for="cornersSquareOptions-color"
|
|
class="form-label"
|
|
>Couleur des coins</label>
|
|
<input
|
|
v-model="options.cornersSquareOptions.color"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
id="cornersSquareOptions-color"
|
|
>
|
|
|
|
<label
|
|
for="cornersSquareOptions-type"
|
|
class="form-label"
|
|
>Forme des coins</label>
|
|
<select
|
|
v-model="options.cornersSquareOptions.type"
|
|
placeholder="Add data"
|
|
class="form-select"
|
|
id="cornersSquareOptions-type"
|
|
>
|
|
<option value="dots">
|
|
Dots
|
|
</option>
|
|
<option value="square">
|
|
Square
|
|
</option>
|
|
<option value="extra-rounded">
|
|
Extra-Rounded
|
|
</option>
|
|
</select>
|
|
|
|
<label
|
|
for="cornersDotOptions-color"
|
|
class="form-label"
|
|
>Couleur de l'intérieur des coins</label>
|
|
<input
|
|
v-model="options.cornersDotOptions.color"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
id="cornersDotOptions-color"
|
|
>
|
|
|
|
<label
|
|
for="cornersDotOptions-type"
|
|
class="form-label"
|
|
>Type de l'intérieur des coins</label>
|
|
<select
|
|
v-model="options.cornersDotOptions.type"
|
|
placeholder="Add data"
|
|
class="form-select"
|
|
id="cornersDotOptions-type"
|
|
>
|
|
<option value="dots">
|
|
Dots
|
|
</option>
|
|
<option value="square">
|
|
Square
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item">
|
|
<h2
|
|
class="accordion-header"
|
|
id="headingFour"
|
|
>
|
|
<button
|
|
class="accordion-button collapsed"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#collapseFour"
|
|
aria-expanded="false"
|
|
aria-controls="collapseFour"
|
|
>
|
|
Options de l'image
|
|
</button>
|
|
</h2>
|
|
<div
|
|
id="collapseFour"
|
|
class="accordion-collapse collapse"
|
|
aria-labelledby="headingFour"
|
|
data-bs-parent="#accordionExample"
|
|
>
|
|
<div class="accordion-body">
|
|
<label
|
|
for="imageOptions-hideBackgroundDots"
|
|
class="form-label"
|
|
>Cacher les points derrière l'image</label>
|
|
<input
|
|
v-model="options.imageOptions.hideBackgroundDots"
|
|
placeholder="Add data"
|
|
class="form-check"
|
|
type="checkbox"
|
|
id="imageOptions-hideBackgroundDots"
|
|
>
|
|
|
|
<label
|
|
for="imageOptions-imageSize"
|
|
class="form-label"
|
|
>Taille de l'image</label>
|
|
<input
|
|
v-model="options.imageOptions.imageSize"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
type="number"
|
|
step="0.1"
|
|
id="imageOptions-imageSize"
|
|
name="imageOptions-imageSize"
|
|
>
|
|
|
|
<label
|
|
for="imageOptions-margin"
|
|
class="form-label"
|
|
>Marge de l'image</label>
|
|
<input
|
|
v-model="options.imageOptions.margin"
|
|
placeholder="Add data"
|
|
class="form-control"
|
|
type="number"
|
|
id="imageOptions-margin"
|
|
>
|
|
|
|
<template v-if="imageLoaded">
|
|
<ImageInputComponent
|
|
v-model="options.image"
|
|
:id="'logo'"
|
|
:name="'logo'"
|
|
:helper="'L\'image qui va servir de vignette au produit, doit être de 500px (largeur) par 500px (hauteur) maximum'"
|
|
:width="100"
|
|
:height="100"
|
|
:required="false"
|
|
:value="options.image"
|
|
@image-file="updatePicture()"
|
|
/>
|
|
</template>
|
|
<input
|
|
type="hidden"
|
|
:value="`${ JSON.stringify(options) }`"
|
|
name="image_settings"
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import QRCodeStyling from "qr-code-styling";
|
|
import type {
|
|
DrawType,
|
|
TypeNumber,
|
|
Mode,
|
|
ErrorCorrectionLevel,
|
|
DotType,
|
|
CornerSquareType,
|
|
CornerDotType,
|
|
FileExtension,
|
|
} from "qr-code-styling";
|
|
import trans from "../../modules/trans";
|
|
import { defineComponent } from "vue";
|
|
import ImageInputComponent from "../../bo/components/ImageInputComponent.vue";
|
|
import {Vue3ColorPicker} from "@cyhnkckali/vue3-color-picker";
|
|
import "@cyhnkckali/vue3-color-picker/dist/style.css";
|
|
|
|
export default defineComponent({
|
|
name: "QrCodeComponent",
|
|
mixins: [trans],
|
|
mounted() {
|
|
const json = String(this.$attrs.json ?? "{}");
|
|
if (json.length) {
|
|
const data = JSON.parse(json);
|
|
if(data.baseUrlEnv) {
|
|
this.baseUrl = data.baseUrlEnv;
|
|
}
|
|
if(data.id) {
|
|
this.urlId = data.id;
|
|
this.urlInput = document.getElementById(data.id) as HTMLInputElement;
|
|
this.options.data = this.baseUrl + "/r/" + this.urlInput.value;
|
|
}
|
|
if(data.settings) {
|
|
this.options = data.settings;
|
|
}
|
|
if(data.logo !== "") {
|
|
this.options.image = "/" + data.logo;
|
|
} else {
|
|
this.options.image = "";
|
|
}
|
|
}
|
|
this.imageLoaded = true;
|
|
this.qrCode = new QRCodeStyling(this.options);
|
|
this.qrCode.append(this.$refs.div as HTMLElement);
|
|
this.isTransparent = this.options.backgroundOptions.color === "transparent";
|
|
},
|
|
components: {
|
|
ImageInputComponent,
|
|
Vue3ColorPicker
|
|
},
|
|
methods: {
|
|
download() {
|
|
this.qrCode.update(this.options);
|
|
this.qrCode.download({ extension: this.extension as FileExtension });
|
|
},
|
|
updatePicture() {
|
|
const el = document.getElementById("PreviewHelplogo")?.parentElement?.children[1] as HTMLElement;
|
|
if (el instanceof HTMLElement) {
|
|
this.options.image = el.getAttribute("src") as string;
|
|
this.qrCode.update(this.options);
|
|
}
|
|
},
|
|
changeColor(color: string) {
|
|
if (!this.isTransparent) {
|
|
this.options.backgroundOptions.color = color;
|
|
}
|
|
},
|
|
toggleTransparency() {
|
|
if (this.isTransparent) {
|
|
this.options.backgroundOptions.color = "transparent";
|
|
} else {
|
|
this.options.backgroundOptions.color = this.pickerColor;
|
|
}
|
|
}
|
|
},
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
baseUrlEnv: {
|
|
type: String,
|
|
default: null,
|
|
}
|
|
},
|
|
data(): {
|
|
baseUrl: string,
|
|
urlId: string,
|
|
urlInput: HTMLInputElement,
|
|
urlInputValue: string,
|
|
imageLoaded: boolean,
|
|
options: {
|
|
type: DrawType;
|
|
width: number;
|
|
height: number;
|
|
margin: number;
|
|
data: string;
|
|
image: string;
|
|
qrOptions: {
|
|
typeNumber: TypeNumber;
|
|
mode: Mode;
|
|
errorCorrectionLevel: ErrorCorrectionLevel;
|
|
};
|
|
imageOptions: {
|
|
hideBackgroundDots: boolean;
|
|
imageSize: number;
|
|
crossOrigin: string;
|
|
margin: number;
|
|
};
|
|
dotsOptions: {
|
|
type: DotType;
|
|
color: string;
|
|
};
|
|
cornersSquareOptions: {
|
|
type: CornerSquareType;
|
|
color: string;
|
|
};
|
|
cornersDotOptions: {
|
|
type: CornerDotType;
|
|
color: string;
|
|
};
|
|
backgroundOptions: {
|
|
color: string;
|
|
};
|
|
},
|
|
extension: FileExtension,
|
|
qrCode: QRCodeStyling,
|
|
isTransparent: boolean,
|
|
pickerColor: string,
|
|
} {
|
|
return {
|
|
baseUrl: "",
|
|
urlId: "",
|
|
urlInput: document.getElementById(this.urlInputId) as HTMLInputElement,
|
|
urlInputValue: "",
|
|
imageLoaded: false,
|
|
options: {
|
|
width: 300,
|
|
height: 300,
|
|
type: "svg",
|
|
data: "http://www.google.com",
|
|
image: "",
|
|
margin: 10,
|
|
qrOptions: {
|
|
typeNumber: 0,
|
|
mode: "Byte",
|
|
errorCorrectionLevel: "H"
|
|
},
|
|
imageOptions: {
|
|
hideBackgroundDots: true,
|
|
imageSize: 0.4,
|
|
margin: 10,
|
|
crossOrigin: "anonymous",
|
|
},
|
|
dotsOptions: {
|
|
color: "#000000",
|
|
type: "square",
|
|
},
|
|
backgroundOptions: {
|
|
color: "#ffffff",
|
|
},
|
|
cornersSquareOptions: {
|
|
color: "#000000",
|
|
type: "square",
|
|
},
|
|
cornersDotOptions: {
|
|
color: "#000000",
|
|
type: "square",
|
|
}
|
|
},
|
|
extension: "png",
|
|
qrCode: new QRCodeStyling(),
|
|
isTransparent: false,
|
|
pickerColor: "#ffffff",
|
|
};
|
|
},
|
|
watch: {
|
|
id() {
|
|
this.urlId = this.id;
|
|
},
|
|
urlId() {
|
|
if (!this.urlId) {
|
|
return;
|
|
}
|
|
this.$nextTick(() => {
|
|
const input = document.getElementById(this.urlId);
|
|
if (
|
|
!input ||
|
|
!(input instanceof HTMLInputElement)
|
|
) {
|
|
throw new Error(`${this.urlId} is not a input`);
|
|
}
|
|
this.urlInput = input;
|
|
});
|
|
},
|
|
urlInput() {
|
|
if (
|
|
!this.urlInput ||
|
|
!(
|
|
this.urlInput instanceof HTMLInputElement
|
|
)
|
|
) {
|
|
throw new Error(`${this.urlId} is not a input`);
|
|
}
|
|
this.urlInput.addEventListener("input", (e) => {
|
|
const el = e.target;
|
|
if (
|
|
!el ||
|
|
!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)
|
|
) {
|
|
throw new Error(`${this.urlId} is not a input or textarea`);
|
|
}
|
|
this.options.data = this.baseUrl + "/r/" + el.value.toLowerCase()
|
|
.trim()
|
|
.replace(/[^\w\s-]/g, "")
|
|
.replace(/[\s_-]+/g, "-")
|
|
.replace(/^-+|-+$/g, "");
|
|
});
|
|
this.qrCode.update(this.options);
|
|
},
|
|
isTransparent(newVal) {
|
|
if (newVal) {
|
|
this.options.backgroundOptions.color = "transparent";
|
|
} else {
|
|
this.options.backgroundOptions.color = this.pickerColor;
|
|
}
|
|
},
|
|
"options.data"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.height"() {
|
|
this.options.width = this.options.height;
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.width"() {
|
|
this.options.height = this.options.width;
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.margin"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.type"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.dotsOptions.color"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.dotsOptions.type"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.backgroundOptions.color"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.cornersSquareOptions.color"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.cornersSquareOptions.type"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.cornersDotOptions.color"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.cornersDotOptions.type"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.imageOptions.hideBackgroundDots"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.imageOptions.imageSize"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
"options.imageOptions.margin"() {
|
|
this.qrCode.update(this.options);
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
|
|
.code-viewer {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.download-group {
|
|
display: flex;
|
|
|
|
select,
|
|
button {
|
|
width: 10rem;
|
|
}
|
|
}
|
|
|
|
#qr-code {
|
|
// Apply a color to keep the dots visible when the background is transparent.
|
|
background-color: #aaa;
|
|
}
|
|
</style>
|