Migrate to Vue, slightly redesign labels to fit more text
This commit is contained in:
parent
f2d207e540
commit
a239e2dd6e
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
trailingComma: es5
|
||||||
|
singleQuote: true
|
||||||
|
jsxBracketSameLine: true
|
13
App.vue
Normal file
13
App.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<ToolLabels />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component } from 'vue-property-decorator';
|
||||||
|
import ToolLabels from './ToolLabels.vue';
|
||||||
|
|
||||||
|
@Component({ components: { ToolLabels } })
|
||||||
|
export default class App extends Vue {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
142
ComputerLabel.vue
Normal file
142
ComputerLabel.vue
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<article class="label">
|
||||||
|
<div class="content">
|
||||||
|
<img class="qrcode" :src="qrcode_dataURL" />
|
||||||
|
<span class="text-content">
|
||||||
|
<div class="name">{{ name }}</div>
|
||||||
|
<div class="hostname">{{ asset.name }}</div>
|
||||||
|
<div class="mac">{{ mac }}</div>
|
||||||
|
<div class="mac">{{ mac2 }}</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<span class="scanme">Scan the QR code to learn more!</span>
|
||||||
|
<span class="barcode-tag">
|
||||||
|
<img class="barcode" ref="barcode" />
|
||||||
|
<div class="tag">{{ asset.asset_tag }}</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop } from 'vue-property-decorator';
|
||||||
|
import JsBarcode from 'jsbarcode';
|
||||||
|
import { toWords as numberToWords } from 'number-to-words';
|
||||||
|
import QRCode from 'qrcode';
|
||||||
|
|
||||||
|
import snipeit from './snipeit';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class ComputerLabel extends Vue {
|
||||||
|
QRCODE_BASE = 'https://inv.claremontmakerspace.org/';
|
||||||
|
|
||||||
|
@Prop(Object) readonly asset: snipeit.Hardware;
|
||||||
|
|
||||||
|
qrcode_dataURL: string | null = null;
|
||||||
|
|
||||||
|
async mounted() {
|
||||||
|
this.qrcode_dataURL = await QRCode.toDataURL(
|
||||||
|
this.QRCODE_BASE + this.asset.asset_tag,
|
||||||
|
{
|
||||||
|
margin: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
JsBarcode(this.$refs.barcode, this.asset.asset_tag, {
|
||||||
|
displayValue: false,
|
||||||
|
margin: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return numberToWords(this.asset.name.match(/[0-9]+$/)[0]).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
get mac() {
|
||||||
|
return this.asset.custom_fields['MAC Address']?.value;
|
||||||
|
}
|
||||||
|
get mac2() {
|
||||||
|
return this.asset.custom_fields['MAC Address 2']?.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
size: calc(146.64pt - 4.32pt) calc(69.12pt - 4.08pt);
|
||||||
|
margin: 1mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
background-size: cover;
|
||||||
|
page-break-after: always;
|
||||||
|
clear: both;
|
||||||
|
width: calc(146.64pt - 4.32pt);
|
||||||
|
height: calc(69.12pt - 4.08pt);
|
||||||
|
position: relative;
|
||||||
|
padding-top: 1.9mm;
|
||||||
|
|
||||||
|
/* overflow: hidden; */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen {
|
||||||
|
.label {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
height: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-content {
|
||||||
|
margin-left: 1ex;
|
||||||
|
font-family: monospace;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 30;
|
||||||
|
line-height: 0.8;
|
||||||
|
margin-bottom: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mac {
|
||||||
|
font-size: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
margin-top: 2%;
|
||||||
|
display: flex;
|
||||||
|
height: 26%;
|
||||||
|
padding-right: 1.2mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scanme {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.barcode-tag {
|
||||||
|
width: 90%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.barcode {
|
||||||
|
width: 90%;
|
||||||
|
height: 60%;
|
||||||
|
}
|
||||||
|
</style>
|
23
ToolLabels.vue
Normal file
23
ToolLabels.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ComputerLabel
|
||||||
|
v-for="asset in assets.rows.filter(t => t.name !== '')"
|
||||||
|
:asset="asset"
|
||||||
|
:key="asset.id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import snipeit from './snipeit';
|
||||||
|
import ComputerLabel from './ComputerLabel.vue';
|
||||||
|
|
||||||
|
import assets from './computers.json';
|
||||||
|
|
||||||
|
@Component({ components: { ComputerLabel } })
|
||||||
|
export default class ToolLabels extends Vue {
|
||||||
|
assets: { rows: [snipeit.Hardware]; total: number } = assets;
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,58 +0,0 @@
|
|||||||
@page {
|
|
||||||
size: calc(146.64pt - 4.32pt) calc(69.12pt - 4.08pt);
|
|
||||||
margin: 1mm;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
background-size: cover;
|
|
||||||
page-break-after: always;
|
|
||||||
clear: both;
|
|
||||||
width: calc(146.64pt - 4.32pt);
|
|
||||||
height: calc(69.12pt - 4.08pt);
|
|
||||||
position: relative;
|
|
||||||
padding-top: 1.9mm;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen {
|
|
||||||
.label {
|
|
||||||
border: 1px solid red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
height: 70%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.qrcode {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-content {
|
|
||||||
margin-left: 1ex;
|
|
||||||
font-family: monospace;
|
|
||||||
line-height: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
font-size: 30;
|
|
||||||
line-height: 0.8;
|
|
||||||
margin-bottom: .1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mac {
|
|
||||||
font-size: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.barcode {
|
|
||||||
margin-top: 2%;
|
|
||||||
bottom: 0;
|
|
||||||
width: 90%;
|
|
||||||
height: 24%;
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="computerLabel.css" />
|
|
||||||
<script src="computerLabel.js"></script>
|
|
||||||
|
|
||||||
<template id="labelTemplate">
|
|
||||||
<article class="label">
|
|
||||||
<div class="content">
|
|
||||||
<img class="qrcode" />
|
|
||||||
<span class="text-content">
|
|
||||||
<div class="name"></div>
|
|
||||||
<div class="hostname"></div>
|
|
||||||
<div class="mac"></div>
|
|
||||||
<div class="tag"></div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<img class="barcode" />
|
|
||||||
</article>
|
|
||||||
</template>
|
|
@ -1,39 +0,0 @@
|
|||||||
import JsBarcode from "jsbarcode";
|
|
||||||
import { toWords as numberToWords } from "number-to-words";
|
|
||||||
import QRCode from "qrcode";
|
|
||||||
|
|
||||||
import data from "./export-computers-assets-2020-01-30.json";
|
|
||||||
|
|
||||||
async function renderLabels() {
|
|
||||||
const template = document.querySelector("#labelTemplate");
|
|
||||||
|
|
||||||
const URL_BASE = "https://inv.claremontmakerspace.org/";
|
|
||||||
|
|
||||||
for (const asset of data.data) {
|
|
||||||
const {
|
|
||||||
"Asset Tag": assetTag,
|
|
||||||
"Asset Name": assetName,
|
|
||||||
"MAC Address": mac
|
|
||||||
} = asset;
|
|
||||||
let clone = document.importNode(template.content, true);
|
|
||||||
|
|
||||||
let qrcode = await QRCode.toDataURL(URL_BASE + assetTag, { margin: 0 });
|
|
||||||
clone.querySelector(".qrcode").src = qrcode;
|
|
||||||
|
|
||||||
JsBarcode(clone.querySelector(".barcode"), assetTag, {
|
|
||||||
displayValue: false,
|
|
||||||
margin: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
let name = numberToWords(assetName.match(/[0-9]+$/)[0]).toUpperCase();
|
|
||||||
|
|
||||||
clone.querySelector(".name").textContent = name;
|
|
||||||
clone.querySelector(".hostname").textContent = assetName;
|
|
||||||
clone.querySelector(".mac").textContent = mac;
|
|
||||||
clone.querySelector(".tag").textContent = assetTag;
|
|
||||||
|
|
||||||
document.body.appendChild(clone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", renderLabels);
|
|
31
getAssets.py
Executable file
31
getAssets.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
BASE_URL = 'https://inventory.claremontmakerspace.org/api/v1/'
|
||||||
|
|
||||||
|
token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjlmODA4ZDhlNGNiNTExNDJhZmZkNzc3YzVmYmFjOTAzN2U4ZGVkMmJhNWMxZDY2M2YzODhhOWQ3ODQ1MWFhMDIwN2E1NWVmNDNlNTlkZTRlIn0.eyJhdWQiOiIxIiwianRpIjoiOWY4MDhkOGU0Y2I1MTE0MmFmZmQ3NzdjNWZiYWM5MDM3ZThkZWQyYmE1YzFkNjYzZjM4OGE5ZDc4NDUxYWEwMjA3YTU1ZWY0M2U1OWRlNGUiLCJpYXQiOjE1ODM4NTg3ODIsIm5iZiI6MTU4Mzg1ODc4MiwiZXhwIjoxNjE1Mzk4MzgyLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.RaUpwGEQOyQHKF9toXgtI2gMetCXpokux6SeLlF-6OXMpGPv64YPIWYFWfpwF8PrKTKIJiEW_gOyg15sHdEs1VLchQLYUrO7Fv9jK8_S3jj1PkXx_OQpork7nO19hEJUpi64d5RPuyyprTgR2Yu9VAi37bwTjBz2TbpggOaqWjH1gpX7BvZqpFFgTgg-A-KO9TCYurPst4GrNpR4DG0SYxqDCOlpQoMa6bnzlZ3ZbW0Xt2Z8E8JiEWjZ6FalNs3EoQAyGIyW_f66qiouR0EzFqa9-EHt0TdZvr_n6KG0Rdq4RBmKGG0-b4l3VIDbCKe9DeSVZa8oZOamfAiwBIhADOMIXrNJNov7-T25c9h2PznuaXLZrh1JydJxreFpoWwvME4G-HBQWHL9EVY3Kdi-6gB8Bh0kWdfoEkFFcio-40iE4eL5h5AnE-nyMKSFeqrhw_A1mhNaGgJixIzD0gDxnVBNT1RpjEDxBFXV1_bQd8pWOG6gWP263PY8fWf4vGE8_WPt95F-DYYrOJ7QsmZ1iTy4FKHo5CvuIgvExMXg3eLol7Rc0P6e1MA-OITi6taT7GG4T26R9_fukXJYe15vVyV-sR8_wBE9CeYIQLoW69R4vzAzKXwBJ5zrjFAog13iq5Vmyy9koY1vRGOvKuXIO5TZxlQTznZSJFy86FoANww'
|
||||||
|
|
||||||
|
categories = {
|
||||||
|
"tools": "4",
|
||||||
|
"computers": "5"
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer ' + token,
|
||||||
|
'Accept': "application/json",
|
||||||
|
'Content-Type': "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.get(
|
||||||
|
BASE_URL + "hardware/",
|
||||||
|
params={
|
||||||
|
"limit": "1000",
|
||||||
|
"category_id": categories[sys.argv[1]]
|
||||||
|
},
|
||||||
|
headers=headers)
|
||||||
|
|
||||||
|
with open(sys.argv[1] + '.json', 'w') as f:
|
||||||
|
f.write(r.text)
|
4
index.html
Normal file
4
index.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="index.ts"></script>
|
||||||
|
</body>
|
7
index.ts
Normal file
7
index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
let app = new Vue({
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app');
|
10
package.json
10
package.json
@ -6,6 +6,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsbarcode": "^3.11.0",
|
"jsbarcode": "^3.11.0",
|
||||||
"number-to-words": "^1.2.4",
|
"number-to-words": "^1.2.4",
|
||||||
"qrcode": "^1.4.4"
|
"qrcode": "^1.4.4",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-hot-reload-api": "^2.3.4",
|
||||||
|
"vue-property-decorator": "^8.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/component-compiler-utils": "^3.1.1",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
63
snipeit.d.ts
vendored
Normal file
63
snipeit.d.ts
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
export interface Hardware {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
asset_tag: string;
|
||||||
|
serial: string;
|
||||||
|
model: IdName;
|
||||||
|
model_number: string;
|
||||||
|
eol?: string; // TODO
|
||||||
|
status_label: IdName & {
|
||||||
|
status_type: 'deployable' | 'pending' | 'undeployable' | 'archived';
|
||||||
|
status_meta: 'deployed' | 'pending'; // TODO
|
||||||
|
};
|
||||||
|
category: IdName;
|
||||||
|
manufacturer: IdName;
|
||||||
|
supplier?: IdName;
|
||||||
|
notes?: string;
|
||||||
|
order_number?: string;
|
||||||
|
company?: IdName; // TODO
|
||||||
|
location?: IdName;
|
||||||
|
rtd_location?: IdName;
|
||||||
|
image: string;
|
||||||
|
assigned_to: IdName & { type: string };
|
||||||
|
warranty_months?: string;
|
||||||
|
warranty_expires?: string;
|
||||||
|
created_at: DatetimeFormatted;
|
||||||
|
updated_at: DatetimeFormatted;
|
||||||
|
last_audit_date?: DatetimeFormatted;
|
||||||
|
next_audit_date?: DatetimeFormatted;
|
||||||
|
deleted_at?: DatetimeFormatted;
|
||||||
|
purchase_date: DatetimeFormatted;
|
||||||
|
last_checkout: DatetimeFormatted;
|
||||||
|
expected_checkin: DatetimeFormatted;
|
||||||
|
purchase_cost: number;
|
||||||
|
checkin_counter: number;
|
||||||
|
checkout_counter: number;
|
||||||
|
requests_counter: number;
|
||||||
|
user_can_checkout: boolean;
|
||||||
|
custom_fields: {
|
||||||
|
[key: string]: {
|
||||||
|
field: string;
|
||||||
|
value?: string;
|
||||||
|
field_format: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
available_actions: {
|
||||||
|
checkout: boolean;
|
||||||
|
checkin: boolean;
|
||||||
|
clone: boolean;
|
||||||
|
restore: boolean;
|
||||||
|
update: boolean;
|
||||||
|
delete: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IdName {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DatetimeFormatted {
|
||||||
|
datetime: string;
|
||||||
|
formatted: string;
|
||||||
|
}
|
8
tsconfig.json
Normal file
8
tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"strict": true,
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node"
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user