Merge branch 'release/v0.1.0'
This commit is contained in:
commit
6589a64321
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
node_modules
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
config.json
|
||||
config.default.json
|
@ -1,51 +1,58 @@
|
||||
const EventEmitter = require('events')
|
||||
const EventEmitter = require('events') // eslint-disable-line
|
||||
const escpos = require('escpos')
|
||||
const config = require('./config.json')
|
||||
// const config = require('./config.json')
|
||||
const fs = require('fs')
|
||||
const iconv = require('iconv-lite')
|
||||
|
||||
class PrinterDevice {
|
||||
constructor() {
|
||||
class PrinterDevice extends EventEmitter {
|
||||
constructor () {
|
||||
super()
|
||||
this._serial = ''
|
||||
this._feed = 8
|
||||
this._isOpen = false
|
||||
this._device = null
|
||||
this._printer = null
|
||||
this._type = null // type = serial or console
|
||||
this._count = 0
|
||||
this._lastPrint = ''
|
||||
}
|
||||
|
||||
encodeStr(str){
|
||||
if(!str || typeof str != 'string') return false
|
||||
encodeStr (str) {
|
||||
if (!str || typeof str !== 'string') return false
|
||||
return iconv.encode(str, 'big5')
|
||||
}
|
||||
|
||||
async connect() {
|
||||
async connect () {
|
||||
let self = this
|
||||
let chkSerial = await new Promise((resolve, reject) => {
|
||||
fs.access(config.printer.serial, err => {
|
||||
fs.access(self._serial, err => {
|
||||
if (err) return resolve(false)
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
if (chkSerial) {
|
||||
this._device = new escpos.Serial(config.printer.serial)
|
||||
this._device = new escpos.Serial(this._serial)
|
||||
this._type = 'serial'
|
||||
} else {
|
||||
this._device = new escpos.Console()
|
||||
this._type = 'console'
|
||||
}
|
||||
this._printer = new escpos.Printer(this._device)
|
||||
this.openSerial()
|
||||
await this.openSerial()
|
||||
}
|
||||
|
||||
async openSerial() {
|
||||
if (!this._device || this._type != 'serial') return
|
||||
async openSerial () {
|
||||
let self = this
|
||||
if (!this._device || this._type !== 'serial') return
|
||||
this._isOpen = await new Promise((resolve, reject) => {
|
||||
this._device.open(err => {
|
||||
self._device.open(err => {
|
||||
if (err) return resolve(false)
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async printerString(str) {
|
||||
async printerString (str) {
|
||||
if (!this._isOpen || !this._printer) return false
|
||||
|
||||
this._printer.font('a')
|
||||
@ -66,8 +73,8 @@ class PrinterDevice {
|
||||
case 's':
|
||||
let size = tmp.substring(2)
|
||||
let sarr = size.trim().split(',')
|
||||
if (sarr.length != 2) break
|
||||
if(!isFinite(sarr[0]) || !isFinite(sarr[1])) break
|
||||
if (sarr.length !== 2) break
|
||||
if (!isFinite(sarr[0]) || !isFinite(sarr[1])) break
|
||||
sarr = sarr.map(t => Math.floor(t))
|
||||
this._printer.size(sarr[0], sarr[1])
|
||||
break
|
||||
@ -77,26 +84,74 @@ class PrinterDevice {
|
||||
}
|
||||
}
|
||||
|
||||
this._printer.cut(true, config.printer.cutFeed || 4)
|
||||
this._printer.cut(true, this._feed || 4)
|
||||
|
||||
this._lastPrint = str
|
||||
this.addCount()
|
||||
this.emit('printDone')
|
||||
return true
|
||||
}
|
||||
|
||||
async close() {
|
||||
async printTestPage () {
|
||||
await this.connect()
|
||||
if (!this._isOpen) return false
|
||||
this._printer.align('ct')
|
||||
this._printer.size(1, 2)
|
||||
this._printer.text('Print Test Page')
|
||||
this._printer.align('lt')
|
||||
this._printer.size(1, 1)
|
||||
this._printer.text('Test Page Content')
|
||||
this._printer.cut(true, this._feed)
|
||||
await this.close()
|
||||
return true
|
||||
}
|
||||
|
||||
async close () {
|
||||
if (!this._device) return
|
||||
if (this._type == 'serial') {
|
||||
if (this._type === 'serial') {
|
||||
let self = this
|
||||
await new Promise((resolve, reject) => {
|
||||
self._printer.close(() => {
|
||||
self._printer = null
|
||||
self._isOpen = false
|
||||
resolve(1)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
get isOpen() {
|
||||
return this._isOpen ? true : false
|
||||
addCount () {
|
||||
this._count++
|
||||
}
|
||||
|
||||
get isOpen () {
|
||||
return !!this._isOpen
|
||||
}
|
||||
|
||||
set serial (str) {
|
||||
this._serial = str
|
||||
}
|
||||
|
||||
get serial () {
|
||||
return this._serial
|
||||
}
|
||||
|
||||
set feed (str) {
|
||||
if (!isFinite(str)) return
|
||||
this._feed = Math.floor(parseInt(str))
|
||||
}
|
||||
|
||||
get feed () {
|
||||
return this._feed
|
||||
}
|
||||
|
||||
get count () {
|
||||
return this._count
|
||||
}
|
||||
|
||||
get lastPrint () {
|
||||
return this._lastPrint || ''
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new PrinterDevice()
|
||||
module.exports = new PrinterDevice()
|
||||
|
63
app.js
63
app.js
@ -1,59 +1,10 @@
|
||||
const bleno = require('bleno')
|
||||
const config = require('./config.json')
|
||||
const adapterName = 'BLE_Printer'
|
||||
const serverUUID = config.uuid.main
|
||||
const localEvent = require('./localEvent')
|
||||
const fs = require('fs')
|
||||
const MainService = require('./main-service')
|
||||
// set global env
|
||||
process.env.PROJECT_ROOT = __dirname
|
||||
|
||||
const printer = require('./PrinterDev')
|
||||
require('top-level-await')
|
||||
|
||||
async function initSystem(){
|
||||
try{
|
||||
await printer.connect()
|
||||
}catch(err){
|
||||
throw err
|
||||
}
|
||||
try {
|
||||
require('./server')
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
|
||||
initSystem()
|
||||
|
||||
bleno.on('stateChange', state => {
|
||||
console.log(`bt device state ${state}`)
|
||||
if (state == 'poweredOn') {
|
||||
|
||||
bleno.startAdvertising(adapterName, [serverUUID], (error) => {
|
||||
|
||||
})
|
||||
} else {
|
||||
bleno.stopAdvertising()
|
||||
}
|
||||
})
|
||||
|
||||
bleno.on('advertisingStart', function (error) {
|
||||
console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
|
||||
|
||||
if (!error) {
|
||||
bleno.setServices([new MainService()], error => {
|
||||
console.log('set service', error)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
localEvent.on('print', async (str) => {
|
||||
let status = false
|
||||
if (printer.isOpen) {
|
||||
try {
|
||||
status = await printer.printerString(str)
|
||||
} catch (err) {
|
||||
status = false
|
||||
}
|
||||
}
|
||||
|
||||
localEvent.emit('printResult', status)
|
||||
})
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
printer.close()
|
||||
process.exit(0)
|
||||
})
|
@ -1,6 +1,6 @@
|
||||
const bleno = require('bleno')
|
||||
const config = require('./config.json')
|
||||
const localEvent = require('./localEvent')
|
||||
const config = require('../config.json')
|
||||
const localEvent = require('../localEvent')
|
||||
|
||||
var tmp = []
|
||||
var idx = 0
|
||||
@ -12,9 +12,9 @@ const notifyDesciptor = new bleno.Descriptor({
|
||||
})
|
||||
|
||||
class DataCharacteristic extends bleno.Characteristic {
|
||||
constructor() {
|
||||
constructor () {
|
||||
super({
|
||||
uuid: config.uuid.service.func.data,
|
||||
uuid: config.ble.uuid.characteristic,
|
||||
properties: ['write', 'writeWithoutResponse', 'notify'],
|
||||
descriptors: [
|
||||
notifyDesciptor
|
||||
@ -23,15 +23,15 @@ class DataCharacteristic extends bleno.Characteristic {
|
||||
this._notifyFunc = null
|
||||
}
|
||||
|
||||
onWriteRequest(data, offset, withoutResponse, callback) {
|
||||
onWriteRequest (data, offset, withoutResponse, callback) {
|
||||
console.log(`offset :: ${offset} , withoutRes :: ${withoutResponse}`)
|
||||
console.log(`get data`, data)
|
||||
|
||||
if (data.length == 1 && data[0] == 0x00) {
|
||||
if (data.length === 1 && data[0] === 0x00) {
|
||||
tmp = []
|
||||
idx = 0
|
||||
failFlag = false
|
||||
} else if (data.length == 1 && data[0] == 0xff) {
|
||||
} else if (data.length === 1 && data[0] === 0xff) {
|
||||
console.log(Buffer.from(tmp).toString())
|
||||
if (!failFlag) {
|
||||
localEvent.emit('print', Buffer.from(tmp).toString())
|
||||
@ -53,17 +53,17 @@ class DataCharacteristic extends bleno.Characteristic {
|
||||
}
|
||||
}
|
||||
|
||||
sendNotidy(str) {
|
||||
sendNotidy (str) {
|
||||
if (!this._notifyFunc) return
|
||||
this._notifyFunc(Buffer.from(str))
|
||||
}
|
||||
|
||||
onSubscribe(maxValueSize, cb) {
|
||||
onSubscribe (maxValueSize, cb) {
|
||||
console.log(maxValueSize)
|
||||
this._notifyFunc = cb
|
||||
}
|
||||
|
||||
onUnsubscribe() {
|
||||
onUnsubscribe () {
|
||||
this._notifyFunc = null
|
||||
}
|
||||
}
|
24
ble/index.js
Normal file
24
ble/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
const config = require('../config.json')
|
||||
const bleno = require('bleno')
|
||||
const adapterName = 'BLE_Printer'
|
||||
const serverUUID = config.ble.uuid.main
|
||||
const MainService = require('./main-service')
|
||||
|
||||
bleno.on('stateChange', state => {
|
||||
console.log(`bt device state ${state}`)
|
||||
if (state === 'poweredOn') {
|
||||
bleno.startAdvertising(adapterName, [serverUUID])
|
||||
} else {
|
||||
bleno.stopAdvertising()
|
||||
}
|
||||
})
|
||||
|
||||
bleno.on('advertisingStart', function (error) {
|
||||
console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'))
|
||||
|
||||
if (!error) {
|
||||
bleno.setServices([new MainService()], error => {
|
||||
console.log('set service', error)
|
||||
})
|
||||
}
|
||||
})
|
@ -1,14 +1,14 @@
|
||||
const bleno = require('bleno')
|
||||
const config = require('./config.json')
|
||||
const localEvent = require('./localEvent')
|
||||
const config = require('../config.json')
|
||||
const localEvent = require('../localEvent')
|
||||
|
||||
const GdataCharacteristic = require('./gdata-characteristic')
|
||||
const dataCharacteristic = new GdataCharacteristic()
|
||||
|
||||
class MainService extends bleno.PrimaryService {
|
||||
constructor() {
|
||||
constructor () {
|
||||
super({
|
||||
uuid: config.uuid.service.id,
|
||||
uuid: config.ble.uuid.service,
|
||||
characteristics: [
|
||||
dataCharacteristic
|
||||
]
|
15
config.json
15
config.json
@ -1,15 +0,0 @@
|
||||
{
|
||||
"uuid":{
|
||||
"main": "930da73d-1b80-4d3e-a8b6-d9b4e7e771bd",
|
||||
"service":{
|
||||
"id":"dd535b71-8f05-4e30-beb0-6fa7ea3dfc3e",
|
||||
"func":{
|
||||
"data":"00000001-8f05-4e30-beb0-6fa7ea3dfc3e"
|
||||
}
|
||||
}
|
||||
},
|
||||
"printer": {
|
||||
"serial": "/dev/ttyUSB0",
|
||||
"cutFeed": 8
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
const EventEmitter = require('events')
|
||||
const util = require('util')
|
||||
const util = require('util') //eslint-disable-line
|
||||
|
||||
class LocalEvent extends EventEmitter {
|
||||
constructor(){
|
||||
constructor () { // eslint-disable-line
|
||||
super()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new LocalEvent()
|
||||
module.exports = new LocalEvent()
|
||||
|
18
package.json
18
package.json
@ -3,10 +3,26 @@
|
||||
"version": "0.0.1",
|
||||
"main": "app.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"check": "standard --fix --verbose"
|
||||
},
|
||||
"dependencies": {
|
||||
"bleno": "^0.4.2",
|
||||
"escpos": "^2.4.3",
|
||||
"iconv-lite": "^0.4.18",
|
||||
"uuid": "^3.1.0"
|
||||
"kcors": "^2.2.1",
|
||||
"koa": "^2.3.0",
|
||||
"koa-body": "^2.3.0",
|
||||
"koa-ejs": "^4.1.0",
|
||||
"koa-morgan": "^1.0.1",
|
||||
"koa-mount": "^3.0.0",
|
||||
"koa-router": "^7.2.1",
|
||||
"koa-static": "^4.0.1",
|
||||
"top-level-await": "^1.1.0",
|
||||
"uuid": "^3.1.0",
|
||||
"ws": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"standard": "^10.0.3"
|
||||
}
|
||||
}
|
||||
|
25
public/css/main.css
Normal file
25
public/css/main.css
Normal file
@ -0,0 +1,25 @@
|
||||
html, body{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.t-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#qr img {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
.clearfix {
|
||||
*zoom: 1; /*For IE 6&7 only*/
|
||||
}
|
364
public/css/semantic.min.css
vendored
Executable file
364
public/css/semantic.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
4
public/js/jquery-3.2.1.min.js
vendored
Normal file
4
public/js/jquery-3.2.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/jquery-3.2.1.min.map
Normal file
1
public/js/jquery-3.2.1.min.map
Normal file
File diff suppressed because one or more lines are too long
1
public/js/qrcode.min.js
vendored
Normal file
1
public/js/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
19
public/js/semantic.min.js
vendored
Executable file
19
public/js/semantic.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
139
route/dashboard.js
Normal file
139
route/dashboard.js
Normal file
@ -0,0 +1,139 @@
|
||||
/* eslint-disable no-throw-literal */
|
||||
/* eslint-disable */
|
||||
const KoaRouter = require('koa-router')
|
||||
const router = new KoaRouter()
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const Printer = require('../PrinterDev')
|
||||
const KoaBody = require('koa-body')
|
||||
const uuid = require('uuid')
|
||||
const config = require('../config.json')
|
||||
/* eslint-enable */
|
||||
|
||||
router.use(async (c, n) => {
|
||||
c.data = {
|
||||
title: 'Printer System Dashboard'
|
||||
}
|
||||
let status = 1
|
||||
try {
|
||||
await n()
|
||||
} catch (err) {
|
||||
status = 0
|
||||
if (typeof err === 'string') {
|
||||
c.body = err
|
||||
} else {
|
||||
c.body = err.toString()
|
||||
}
|
||||
}
|
||||
|
||||
if (c.async) {
|
||||
c.body = {
|
||||
status,
|
||||
msg: c.body
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/', async (c, n) => {
|
||||
c.data.route = 'index'
|
||||
await c.render('dashboard/index', c.data)
|
||||
})
|
||||
|
||||
router.get('/setting', async (c, n) => {
|
||||
c.data.route = 'setting'
|
||||
|
||||
let ttys = await new Promise((resolve, reject) => {
|
||||
fs.readdir(path.resolve('/dev'), (err, list) => {
|
||||
if (err) return resolve([])
|
||||
let arr = []
|
||||
for (let it of list) {
|
||||
if (/^tty[A-z]/.test(it)) {
|
||||
arr.push(path.resolve('/dev', it))
|
||||
}
|
||||
}
|
||||
resolve(arr)
|
||||
})
|
||||
})
|
||||
c.data.ttys = ttys
|
||||
|
||||
c.data.defConfig = config
|
||||
|
||||
await c.render('dashboard/index', c.data)
|
||||
})
|
||||
|
||||
router.post('/api/print', KoaBody(), async (c, n) => {
|
||||
c.async = true
|
||||
let arr = c.request.body
|
||||
if (!arr.data) throw 'print data empty'
|
||||
if (config.api.secret && !arr.key) throw 'access key enpty'
|
||||
if (config.api.secret !== arr.key.trim()) throw 'access key error'
|
||||
|
||||
let status = await Printer.printerString(arr.data)
|
||||
|
||||
if (!status) throw 'printer fail'
|
||||
|
||||
c.body = 'print success'
|
||||
})
|
||||
|
||||
.post('/api/printer_test', KoaBody(), async (c, n) => {
|
||||
c.async = true
|
||||
let arr = c.request.body
|
||||
if (!arr.device) throw '請輸入印表機連接埠'
|
||||
let device = arr.device
|
||||
let feed = arr.feed || 8
|
||||
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||
|
||||
let oriDev = Printer.serial
|
||||
let oriFeed = Printer.feed
|
||||
|
||||
if (Printer.isOpen) {
|
||||
await Printer.close()
|
||||
}
|
||||
|
||||
Printer.serial = device
|
||||
Printer.feed = feed
|
||||
|
||||
let status = await Printer.printTestPage()
|
||||
|
||||
if (!status) c.body = '測試失敗'
|
||||
else c.body = '測試成功'
|
||||
|
||||
Printer.serial = oriDev
|
||||
Printer.feed = oriFeed
|
||||
await Printer.connect()
|
||||
})
|
||||
.post('/api/write_config', KoaBody(), async (c, n) => {
|
||||
c.async = true
|
||||
let arr = c.request.body
|
||||
if (!arr.tty) throw '請輸入印表機連接埠'
|
||||
if (!arr.ble || (arr.ble !== 'yes' && arr.ble !== 'no')) throw '請輸入藍牙啟用設定'
|
||||
let feed = arr.feed || 8
|
||||
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||
|
||||
let json = Object.assign({}, config)
|
||||
|
||||
json.ble.enable = arr.ble === 'yes'
|
||||
|
||||
json.printer.serial = arr.tty
|
||||
json.printer.feed = feed
|
||||
|
||||
json.api.secret = arr.secret || ''
|
||||
|
||||
let wconfig = await new Promise((resolve, reject) => {
|
||||
fs.writeFile(path.resolve(process.env.PROJECT_ROOT, 'config.json'), JSON.stringify(json, null, 2), {
|
||||
mode: 0o664,
|
||||
encoding: 'utf8',
|
||||
flag: 'w'
|
||||
}, err => {
|
||||
if (err) return resolve(false)
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
|
||||
if (!wconfig) throw '設定檔寫入失敗'
|
||||
c.body = '設定檔寫入成功'
|
||||
})
|
||||
|
||||
module.exports = router
|
124
route/install.js
Normal file
124
route/install.js
Normal file
@ -0,0 +1,124 @@
|
||||
/* eslint-disable no-throw-literal */
|
||||
const KoaRouter = require('koa-router')
|
||||
const router = new KoaRouter()
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const Printer = require('../PrinterDev')
|
||||
const KoaBody = require('koa-body')
|
||||
const uuid = require('uuid')
|
||||
|
||||
router.use(async (c, n) => {
|
||||
c.data = {
|
||||
title: 'Printer System Setup'
|
||||
}
|
||||
let status = 1
|
||||
try {
|
||||
await n()
|
||||
} catch (err) {
|
||||
status = 0
|
||||
if (typeof err === 'string') {
|
||||
c.body = err
|
||||
} else {
|
||||
c.body = err.toString()
|
||||
}
|
||||
}
|
||||
|
||||
if (c.async) {
|
||||
c.body = {
|
||||
status,
|
||||
msg: c.body
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router
|
||||
.get('/', async (c, n) => {
|
||||
c.redirect('/install')
|
||||
})
|
||||
.get('/install', async (c, n) => {
|
||||
// get ttys
|
||||
let ttys = await new Promise((resolve, reject) => {
|
||||
fs.readdir(path.resolve('/dev'), (err, list) => {
|
||||
if (err) return resolve([])
|
||||
let arr = []
|
||||
for (let it of list) {
|
||||
if (/^tty[A-z]/.test(it)) {
|
||||
arr.push(path.resolve('/dev', it))
|
||||
}
|
||||
}
|
||||
resolve(arr)
|
||||
})
|
||||
})
|
||||
c.data.ttys = ttys
|
||||
await c.render('install/index', c.data)
|
||||
})
|
||||
.post('/install/printer_test', KoaBody(), async (c, n) => {
|
||||
c.async = true
|
||||
let arr = c.request.body
|
||||
if (!arr.device) throw '請輸入印表機連接埠'
|
||||
let device = arr.device
|
||||
let feed = arr.feed || 8
|
||||
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||
|
||||
Printer.serial = device
|
||||
Printer.feed = feed
|
||||
|
||||
let status = await Printer.printTestPage()
|
||||
|
||||
if (!status) c.body = '測試失敗'
|
||||
else c.body = '測試成功'
|
||||
})
|
||||
.post('/install/write_config', KoaBody(), async (c, n) => {
|
||||
c.async = true
|
||||
let arr = c.request.body
|
||||
if (!arr.tty) throw '請輸入印表機連接埠'
|
||||
if (!arr.ble || (arr.ble !== 'yes' && arr.ble !== 'no')) throw '請輸入藍牙啟用設定'
|
||||
let feed = arr.feed || 8
|
||||
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||
|
||||
let json = {
|
||||
ble: {
|
||||
enable: false,
|
||||
uuid: {
|
||||
main: '',
|
||||
service: '',
|
||||
characteristic: ''
|
||||
}
|
||||
},
|
||||
printer: {
|
||||
serial: '',
|
||||
feed: 8
|
||||
},
|
||||
api: {
|
||||
secret: ''
|
||||
}
|
||||
}
|
||||
|
||||
json.ble.enable = arr.ble === 'yes'
|
||||
json.ble.uuid.main = uuid.v4()
|
||||
json.ble.uuid.service = uuid.v4()
|
||||
json.ble.uuid.characteristic = uuid.v4()
|
||||
|
||||
json.printer.serial = arr.tty
|
||||
json.printer.feed = feed
|
||||
|
||||
json.api.secret = arr.secret || ''
|
||||
|
||||
let wconfig = await new Promise((resolve, reject) => {
|
||||
fs.writeFile(path.resolve(process.env.PROJECT_ROOT, 'config.json'), JSON.stringify(json, null, 2), {
|
||||
mode: 0o664,
|
||||
encoding: 'utf8',
|
||||
flag: 'w'
|
||||
}, err => {
|
||||
if (err) return resolve(false)
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
|
||||
if (!wconfig) throw '設定檔寫入失敗'
|
||||
c.body = '設定檔寫入成功'
|
||||
})
|
||||
|
||||
module.exports = router
|
164
server.js
Normal file
164
server.js
Normal file
@ -0,0 +1,164 @@
|
||||
const Koa = require('koa')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const localEvent = require('./localEvent')
|
||||
const WebSocket = require('ws')
|
||||
const exec = require('child_process').exec
|
||||
const Printer = require('./PrinterDev')
|
||||
|
||||
// koa middleware
|
||||
const KoaLogger = require('koa-morgan')
|
||||
const KoaEjs = require('koa-ejs')
|
||||
const KoaMount = require('koa-mount')
|
||||
const KoaStatic = require('koa-static')
|
||||
const KoaRouter = require('koa-router')
|
||||
const Kcors = require('kcors')
|
||||
|
||||
const app = new Koa()
|
||||
|
||||
let config = {}
|
||||
let setupMode = false
|
||||
|
||||
try {
|
||||
let chk = new Promise((resolve, reject) => {
|
||||
fs.access(path.resolve(process.env.PROJECT_ROOT, 'config.json'), (err) => {
|
||||
if (err) {
|
||||
setupMode = true
|
||||
resolve(0)
|
||||
return
|
||||
}
|
||||
config = require('./config.json')
|
||||
resolve(1)
|
||||
})
|
||||
})
|
||||
await chk //eslint-disable-line
|
||||
} catch (err) {
|
||||
setupMode = true
|
||||
}
|
||||
|
||||
const server = app.listen(config.port || 10230, () => {
|
||||
console.log(`Server start on port ${server.address().port}`)
|
||||
})
|
||||
|
||||
const ws = new WebSocket.Server({ server })
|
||||
|
||||
app.use(Kcors())
|
||||
app.use(KoaLogger('short'))
|
||||
app.use(KoaStatic(path.resolve(__dirname, 'public')))
|
||||
KoaEjs(app, {
|
||||
root: path.resolve(__dirname, 'views'),
|
||||
layout: false,
|
||||
viewExt: 'ejs',
|
||||
cache: false,
|
||||
debug: false
|
||||
})
|
||||
|
||||
let router = null
|
||||
|
||||
if (setupMode) {
|
||||
console.log(`start setup mode`)
|
||||
router = require('./route/install')
|
||||
} else {
|
||||
console.log(`start normal mode`)
|
||||
router = require('./route/dashboard')
|
||||
|
||||
Printer.serial = config.printer.serial
|
||||
Printer.feed = config.printer.feed
|
||||
await Printer.connect()
|
||||
|
||||
if (config.ble.enable) {
|
||||
require('./ble')
|
||||
}
|
||||
}
|
||||
|
||||
if (router !== null) {
|
||||
// set Route
|
||||
app.use(router.routes())
|
||||
app.use(router.allowedMethods())
|
||||
|
||||
router.put('/reboot_sys', async (c, n) => {
|
||||
setTimeout(function () {
|
||||
process.exit(1)
|
||||
}, 2000)
|
||||
c.body = '1'
|
||||
})
|
||||
}
|
||||
|
||||
// listen print event
|
||||
localEvent.on('print', async str => {
|
||||
let chk = await Printer.printerString(str)
|
||||
localEvent.emit('printResult', chk)
|
||||
})
|
||||
|
||||
let systemStatus = {
|
||||
ble: {
|
||||
enable: false,
|
||||
mac: '',
|
||||
service: '',
|
||||
characteristic: ''
|
||||
},
|
||||
printer: {
|
||||
connect: false,
|
||||
serial: '',
|
||||
feed: 0
|
||||
},
|
||||
pcount: 0,
|
||||
lastprint: '',
|
||||
secret: ''
|
||||
}
|
||||
|
||||
systemStatus.ble.enable = config.ble.enable
|
||||
systemStatus.secret = config.api.secret
|
||||
if (config.ble.enable) {
|
||||
systemStatus.ble.mac = await getBTAddr()
|
||||
systemStatus.ble.service = config.ble.uuid.service
|
||||
systemStatus.ble.characteristic = config.ble.uuid.characteristic
|
||||
}
|
||||
function getPrinterStatus() {
|
||||
systemStatus.printer.connect = Printer.isOpen
|
||||
systemStatus.printer.serial = Printer.serial
|
||||
systemStatus.printer.feed = Printer.feed
|
||||
systemStatus.pcount = Printer.count
|
||||
systemStatus.lastprint = Printer.lastPrint
|
||||
}
|
||||
getPrinterStatus()
|
||||
|
||||
ws.on('connection', async (client, req) => {
|
||||
|
||||
getPrinterStatus()
|
||||
client.send(JSON.stringify({ type: 'status', data: systemStatus }))
|
||||
|
||||
Printer.on('printDone', () => {
|
||||
getPrinterStatus()
|
||||
client.send(JSON.stringify({ type: 'status', data: systemStatus }))
|
||||
})
|
||||
|
||||
client.on('message', msg => {
|
||||
let m = {}
|
||||
try {
|
||||
m = JSON.parse(msg)
|
||||
} catch (err) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (m.type) {
|
||||
case 'status':
|
||||
client.send(JSON.stringify({ type: 'status', data: systemStatus }))
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
async function getBTAddr() {
|
||||
let address = await new Promise((resolve, reject) => {
|
||||
exec('bt-adapter -i | grep -i address', (err, sout, serr) => {
|
||||
if (err) return resolve('')
|
||||
resolve(sout)
|
||||
})
|
||||
})
|
||||
|
||||
address = address.trim()
|
||||
let arr = address.split(' ')
|
||||
if (arr.length !== 2) return ''
|
||||
return arr[1].trim()
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
const bleno = require('bleno')
|
||||
const config = require('./config.json')
|
||||
|
||||
class TimeCharacteristic extends bleno.Characteristic {
|
||||
constructor() {
|
||||
super({
|
||||
uuid: config.uuid.service.func.time,
|
||||
properties: ['read'],
|
||||
descriptors: [
|
||||
new bleno.Descriptor({
|
||||
uuid: '88ff',
|
||||
value: 'Now Time'
|
||||
})
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
onReadRequest(offset, callback) {
|
||||
console.log(`offset :: ${offset}`)
|
||||
callback(this.RESULT_SUCCESS, new Buffer(`${Date.now()}`))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TimeCharacteristic
|
28
views/dashboard/index.ejs
Normal file
28
views/dashboard/index.ejs
Normal file
@ -0,0 +1,28 @@
|
||||
<%- include ../includes/header.ejs %>
|
||||
|
||||
<div class="ui container" style="padding-top: 20px;">
|
||||
<div class="ui grid">
|
||||
<div class="row">
|
||||
<div class="three wide column">
|
||||
<div class="ui vertical menu">
|
||||
<a href="/" class="item">Dashboard</a>
|
||||
<div class="item">
|
||||
<div class="header">系統功能</div>
|
||||
<div class="menu">
|
||||
<a href="/setting" class="item <%= route == 'setting' ? 'active' : '' %>">修改設定</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="thirteen wide column">
|
||||
<% if(route == 'index'){ %>
|
||||
<%- include statusview.ejs %>
|
||||
<% } else { %>
|
||||
<%- include setting.ejs %>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include ../includes/footer.ejs %>
|
131
views/dashboard/setting.ejs
Normal file
131
views/dashboard/setting.ejs
Normal file
@ -0,0 +1,131 @@
|
||||
|
||||
<div class="ui container" style="padding-top: 20px;">
|
||||
<h1 class="ui header">系統安裝設定</h1>
|
||||
<form id="setup" class="ui form">
|
||||
<h3 class="ui dividing header">印表機設定</h3>
|
||||
<div class="field">
|
||||
<label for="tty">印表機連接埠</label>
|
||||
<select name="tty" id="tty">
|
||||
<option value="">選擇裝置</option>
|
||||
<% for(let i of ttys) { %>
|
||||
<option value="<%= i %>" <%= i == defConfig.printer.serial ? 'selected' : '' %>><%= i %></option>
|
||||
<% } %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="feed">切紙前空行</label>
|
||||
<input type="text" name="feed" value="<%= defConfig.printer.feed %>" id="feed">
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui button mini" type="button" id="test-printer">測試印表機</button>
|
||||
</div>
|
||||
|
||||
<h3 class="ui dividing header">藍芽列印設定</h3>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" class="hidden" id="en-ble" <%= defConfig.ble.enable ? 'checked' : '' %>>
|
||||
<label for="en-ble">啟用藍芽</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="ui dividing header">WebAPI設定</h3>
|
||||
<div class="field">
|
||||
<label for="api-secret">API密鑰</label>
|
||||
<input type="text" name="api-secret" value="<%= defConfig.api.secret %>" placeholder="請輸入密鑰,空白不設定" id="api-secret">
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px; text-align: right;">
|
||||
<button class="ui button blue" type="submit">送出設定</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="ui dimmer" id="loader">
|
||||
<div class="ui loader text">Rebooting...</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function getValue(obj){
|
||||
if(!obj || !('value' in obj)) return ''
|
||||
return obj.value
|
||||
}
|
||||
|
||||
$('#test-printer').click(function(){
|
||||
let json = {
|
||||
device: '',
|
||||
feed: 0
|
||||
}
|
||||
let dev = getValue(document.querySelector('select#tty'))
|
||||
let feed = getValue(document.querySelector('input#feed'))
|
||||
|
||||
if(!dev) return alert('請選擇印表機連接埠')
|
||||
if (!isFinite(feed) || feed < 0) return alert('切紙前空行請輸入整數')
|
||||
|
||||
json.device = dev
|
||||
json.feed = Math.floor(parseInt(feed))
|
||||
|
||||
$.ajax({
|
||||
url: '/api/printer_test',
|
||||
type: 'post',
|
||||
data: json,
|
||||
success: function(e){
|
||||
alert(e.msg || '資料傳送失敗')
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
$('form#setup').submit(function(e) {
|
||||
e.preventDefault()
|
||||
|
||||
let json = {
|
||||
tty: '',
|
||||
feed: 0,
|
||||
ble: '',
|
||||
secret: ''
|
||||
}
|
||||
let dev = getValue(document.querySelector('select#tty'))
|
||||
let feed = getValue(document.querySelector('input#feed'))
|
||||
let elBle = document.querySelector('input#en-ble')
|
||||
let ble = ''
|
||||
if(elBle != null && 'checked' in elBle) ble = elBle.checked ? 'yes' : 'no'
|
||||
|
||||
if(!dev) return alert('請選擇印表機連接埠')
|
||||
if (!isFinite(feed) || feed < 0) return alert('切紙前空行請輸入整數')
|
||||
|
||||
let secret = getValue(document.querySelector('input#api-secret'))
|
||||
|
||||
json.tty = dev
|
||||
json.feed = Math.floor(parseInt(feed))
|
||||
json.ble = ble
|
||||
json.secret = secret
|
||||
|
||||
$.ajax({
|
||||
url: '/api/write_config',
|
||||
type: 'post',
|
||||
data: json,
|
||||
success: function(e){
|
||||
if(e.status != 1) {
|
||||
alert(e.msg || '寫入失敗')
|
||||
return
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/reboot_sys',
|
||||
type: 'put',
|
||||
success: function(){
|
||||
setTimeout(function(){
|
||||
location.replace('/')
|
||||
}, 30000)
|
||||
$('#loader').addClass('active')
|
||||
},
|
||||
error: function(){
|
||||
alert('系統重新啟動失敗')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
})
|
||||
</script>
|
152
views/dashboard/statusview.ejs
Normal file
152
views/dashboard/statusview.ejs
Normal file
@ -0,0 +1,152 @@
|
||||
<div class="ui container">
|
||||
<div class="ui grid">
|
||||
<div class="column sixteen wide t-right">
|
||||
<div class="ui segment">
|
||||
<button class="ui button mini" type="button" id="gen-api-qr">Generate API QR</button>
|
||||
<button class="ui button mini" type="button" id="gen-ble-qr">Generate BLE QR</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column sixteen wide">
|
||||
<div class="segment ui">
|
||||
<h4 class="ui header dividing">系統狀態</h4>
|
||||
<div class="ui divided list">
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">API Key</div>
|
||||
<div class="description t-right" id="apikey"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column eight wide">
|
||||
<div class="segment ui">
|
||||
<h4 class="ui header dividing">藍芽狀態</h4>
|
||||
<div class="ui divided list">
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">啟用狀態</div>
|
||||
<div class="description t-right" id="en-ble">On</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">Mac Address</div>
|
||||
<div class="description t-right" id="ble-mac">00:11:22:33:44:55:66</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">ServiceUUID</div>
|
||||
<div class="description t-right" id="ble-service">37B2975E-1A4B-4975-9211-9D47142B8183</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">CharacteristicUUID</div>
|
||||
<div class="description t-right" id="ble-character">37B2975E-1A4B-4975-9211-9D47142B8183</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column eight wide">
|
||||
<div class="segment ui">
|
||||
<h4 class="ui header dividing">印表機狀態</h4>
|
||||
<div class="ui divided list">
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">連線狀態</div>
|
||||
<div class="description t-right" id="prt-con">Disconnected</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">連接埠</div>
|
||||
<div class="description t-right" id="prt-port">/dev/ttyUSB0</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">切紙前空行</div>
|
||||
<div class="description t-right" id="prt-feed">8</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column eight wide">
|
||||
<div class="segment ui">
|
||||
<h4 class="ui header dividing">列印計數器</h4>
|
||||
<div class="ui divided list">
|
||||
<div class="item">
|
||||
<div class="ui horizontal label basic">列印次數</div>
|
||||
<div class="description t-right" id="prt-count">0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column eight wide">
|
||||
<div class="segment ui">
|
||||
<h4 class="ui header dividing">最後列印內容</h4>
|
||||
<div id="prt-last"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui page dimmer" id="qr-dimmer">
|
||||
<div class="content">
|
||||
<div class="center" id="qr"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var setting = {
|
||||
mac: '',
|
||||
service: '',
|
||||
characteristic: ''
|
||||
}
|
||||
|
||||
var apikey = ''
|
||||
|
||||
var ws = new WebSocket('ws://' + location.host)
|
||||
ws.onmessage = msg => {
|
||||
// console.log(msg)
|
||||
let data = {}
|
||||
try {
|
||||
data = JSON.parse(msg.data)
|
||||
} catch (err) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case 'status':
|
||||
console.log(data)
|
||||
let d = data.data
|
||||
$('#en-ble').text(d.ble.enable ? 'On' : 'Off')
|
||||
$('#ble-mac').text(d.ble.mac)
|
||||
$('#ble-service').text(d.ble.service)
|
||||
$('#ble-character').text(d.ble.characteristic)
|
||||
|
||||
setting.mac = d.ble.mac
|
||||
setting.service = d.ble.service
|
||||
setting.characteristic = d.ble.characteristic
|
||||
|
||||
apikey = d.secret
|
||||
$('#apikey').text(apikey)
|
||||
|
||||
$('#prt-con').text(d.printer.connect ? 'Connected' : 'Disconnected')
|
||||
$('#prt-port').text(d.printer.serial)
|
||||
$('#prt-feed').text(d.printer.feed)
|
||||
|
||||
$('#prt-count').text(d.pcount)
|
||||
|
||||
$('#prt-last').text(d.lastprint)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$('#gen-ble-qr, #gen-api-qr').click(function () {
|
||||
let qrdiv = document.querySelector('div#qr')
|
||||
qrdiv.innerHTML = ''
|
||||
let qr = new QRCode(qrdiv, {
|
||||
text: this.id === 'gen-ble-qr' ? JSON.stringify(setting, null, 2) : JSON.stringify({apikey}, null, 2),
|
||||
colorDark: "#000000",
|
||||
colorLight: "#ffffff",
|
||||
correctLevel: QRCode.CorrectLevel.L
|
||||
})
|
||||
// qr.makeCode(JSON.stringify(setting, null, 2))
|
||||
$('#qr-dimmer').dimmer('show')
|
||||
})
|
||||
|
||||
</script>
|
2
views/includes/footer.ejs
Normal file
2
views/includes/footer.ejs
Normal file
@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
14
views/includes/header.ejs
Normal file
14
views/includes/header.ejs
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title><%- title %></title>
|
||||
<link rel="stylesheet" href="/css/semantic.min.css">
|
||||
<link rel="stylesheet" href="/css/main.css">
|
||||
<script src="/js/jquery-3.2.1.min.js"></script>
|
||||
<script src="/js/semantic.min.js"></script>
|
||||
<script src="/js/qrcode.min.js"></script>
|
||||
</head>
|
||||
<body>
|
134
views/install/index.ejs
Normal file
134
views/install/index.ejs
Normal file
@ -0,0 +1,134 @@
|
||||
<%- include ../includes/header.ejs %>
|
||||
|
||||
<div class="ui container" style="padding-top: 20px;">
|
||||
<h1 class="ui header">系統安裝設定</h1>
|
||||
<form id="setup" class="ui form">
|
||||
<h3 class="ui dividing header">印表機設定</h3>
|
||||
<div class="field">
|
||||
<label for="tty">印表機連接埠</label>
|
||||
<select name="tty" id="tty">
|
||||
<option value="">選擇裝置</option>
|
||||
<% for(let i of ttys) { %>
|
||||
<option value="<%= i %>"><%= i %></option>
|
||||
<% } %>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="feed">切紙前空行</label>
|
||||
<input type="text" name="feed" value="8" id="feed">
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui button mini" type="button" id="test-printer">測試印表機</button>
|
||||
</div>
|
||||
|
||||
<h3 class="ui dividing header">藍芽列印設定</h3>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" class="hidden" id="en-ble">
|
||||
<label for="en-ble">啟用藍芽</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="ui dividing header">WebAPI設定</h3>
|
||||
<div class="field">
|
||||
<label for="api-secret">API密鑰</label>
|
||||
<input type="text" name="api-secret" placeholder="請輸入密鑰,空白不設定" id="api-secret">
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 40px; text-align: right;">
|
||||
<button class="ui button blue" type="submit">送出設定</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="ui dimmer" id="loader">
|
||||
<div class="ui loader text">Rebooting...</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function getValue(obj){
|
||||
if(!obj || !('value' in obj)) return ''
|
||||
return obj.value
|
||||
}
|
||||
|
||||
$('#test-printer').click(function(){
|
||||
let json = {
|
||||
device: '',
|
||||
feed: 0
|
||||
}
|
||||
let dev = getValue(document.querySelector('select#tty'))
|
||||
let feed = getValue(document.querySelector('input#feed'))
|
||||
|
||||
if(!dev) return alert('請選擇印表機連接埠')
|
||||
if (!isFinite(feed) || feed < 0) return alert('切紙前空行請輸入整數')
|
||||
|
||||
json.device = dev
|
||||
json.feed = Math.floor(parseInt(feed))
|
||||
|
||||
$.ajax({
|
||||
url: '/install/printer_test',
|
||||
type: 'post',
|
||||
data: json,
|
||||
success: function(e){
|
||||
alert(e.msg || '資料傳送失敗')
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
$('form#setup').submit(function(e) {
|
||||
e.preventDefault()
|
||||
|
||||
let json = {
|
||||
tty: '',
|
||||
feed: 0,
|
||||
ble: '',
|
||||
secret: ''
|
||||
}
|
||||
let dev = getValue(document.querySelector('select#tty'))
|
||||
let feed = getValue(document.querySelector('input#feed'))
|
||||
let elBle = document.querySelector('input#en-ble')
|
||||
let ble = ''
|
||||
if(elBle != null && 'checked' in elBle) ble = elBle.checked ? 'yes' : 'no'
|
||||
|
||||
if(!dev) return alert('請選擇印表機連接埠')
|
||||
if (!isFinite(feed) || feed < 0) return alert('切紙前空行請輸入整數')
|
||||
|
||||
let secret = getValue(document.querySelector('input#api-secret'))
|
||||
|
||||
json.tty = dev
|
||||
json.feed = Math.floor(parseInt(feed))
|
||||
json.ble = ble
|
||||
json.secret = secret
|
||||
|
||||
$.ajax({
|
||||
url: '/install/write_config',
|
||||
type: 'post',
|
||||
data: json,
|
||||
success: function(e){
|
||||
if(e.status != 1) {
|
||||
alert(e.msg || '寫入失敗')
|
||||
return
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/reboot_sys',
|
||||
type: 'put',
|
||||
success: function(){
|
||||
setTimeout(function(){
|
||||
location.replace('/')
|
||||
}, 30000)
|
||||
$('#loader').addClass('active')
|
||||
},
|
||||
error: function(){
|
||||
alert('系統重新啟動失敗')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
})
|
||||
</script>
|
||||
|
||||
<%- include ../includes/footer.ejs %>
|
Loading…
Reference in New Issue
Block a user