<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BLE Printer Test</title>
<script src="https://cdn.jsdelivr.net/npm/iconv-lite-umd@0.6.10/lib/iconv-lite-umd.js"></script>
</head>
<body>
<h1>BLE Printer Test 123</h1>
<button id="printTestButton">Test Print</button>
<button id="printAgain">Print Again</button>
<pre id="log"></pre>
<script>
// Function to log messages on the page
function logMessage(message) {
const logElement = document.getElementById('log');
logElement.textContent += message + '\n';
}
var device;
var server;
var service;
var characteristic;
var name = 'T58_6752'; // 藍芽設備的名稱
var uuid = 0x1800; //service UUID (用 BLE Scanner 找到的)
var characteristicUuid = 0x2A00; // characteristic UUID (用 BLE Scanner 找到的)
// Function to connect to BLE printer and send test data
async function connectAndTestPrint() {
try {
logMessage("Requesting Bluetooth device...");
// Request the BLE device
device = await navigator.bluetooth.requestDevice({
//acceptAllDevices: true,
filters: [
{ name: name }
],
optionalServices: [uuid] // Replace with the correct service UUID
});
logMessage(`Device selected: ${device.name}`);
logMessage(`Device uuid: ${device.id}`);
await printAgain();
} catch (error) {
logMessage(`Error: ${error.message}`);
}
}
// 转码方法
function stringToGbk(str) {
const ranges = [
[0xA1, 0xA9, 0xA1, 0xFE],
[0xB0, 0xF7, 0xA1, 0xFE],
[0x81, 0xA0, 0x40, 0xFE],
[0xAA, 0xFE, 0x40, 0xA0],
[0xA8, 0xA9, 0x40, 0xA0],
[0xAA, 0xAF, 0xA1, 0xFE],
[0xF8, 0xFE, 0xA1, 0xFE],
[0xA1, 0xA7, 0x40, 0xA0],
]
const codes = new Uint16Array(23940)
let i = 0
for (const [b1Begin, b1End, b2Begin, b2End] of ranges) {
for (let b2 = b2Begin; b2 <= b2End; b2++) {
if (b2 !== 0x7F) {
for (let b1 = b1Begin; b1 <= b1End; b1++) {
codes[i++] = b2 << 8 | b1
}
}
}
}
const cstr = new TextDecoder('gbk').decode(codes)
// 编码表
const table = new Uint16Array(65536)
for (let i = 0; i < cstr.length; i++) {
table[cstr.charCodeAt(i)] = codes[i]
}
const buf = new Uint8Array(str.length * 2)
let n = 0
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i)
if (code < 0x80) {
buf[n++] = code
} else {
const gbk = table[code]
buf[n++] = gbk & 0xFF
buf[n++] = gbk >> 8
}
}
u8buf = buf.subarray(0, n)
// console.log(u8buf);
return u8buf
}
async function printAgain() {
// Connect to the GATT server
server = await device.gatt.connect();
logMessage("Connected to GATT server.");
// Get the printer service
service = await server.getPrimaryService(uuid); // Replace with your printer's service UUID
logMessage("Printer service retrieved.");
// Get the characteristic for writing data
characteristic = await service.getCharacteristic(characteristicUuid); // Replace with the correct characteristic UUID
logMessage("Printer characteristic retrieved.");
// Prepare test print data
const encoder = new TextEncoder();
const testData = encoder.encode("TEST PRINT: Hello from Web Bluetooth!\n");
const finalData = encoder.encode("--\n--\n \n \n");
const setFontSize = new Uint8Array([0x1D, 0x21, 0x11]); // GS ! n
const setFontSize2 = new Uint8Array([0x1D, 0x21, 0x22]); // GS ! n
const setFontSize3 = new Uint8Array([0x1D, 0x21, 0x33]); // GS ! n
// Write test data to the printer
logMessage("Sending test data to printer...");
await characteristic.writeValue(new Uint8Array([0x1D, 0x21, 0x00]));
await characteristic.writeValue(encoder.encode("1x1!\n"));
await characteristic.writeValue(setFontSize);
await characteristic.writeValue(encoder.encode("2x2!\n"));
await characteristic.writeValue(setFontSize2);
await characteristic.writeValue(encoder.encode("3x3!\n"));
await characteristic.writeValue(setFontSize3);
await characteristic.writeValue(encoder.encode("4x4!\n"));
const initPrinter = new Uint8Array([0x1B, 0x40]); // ESC @
await characteristic.writeValue(initPrinter);
// 3. 設置字符集為 GBK
const setGBK = new Uint8Array([0x1B, 0x74, 0x11]); // ESC t 0x11 (GBK)
await characteristic.writeValue(setGBK);
const text = "繁體中文測試\n \n";
const encodedText = stringToGbk(text);
await characteristic.writeValue(encodedText);
logMessage("Test data sent successfully!");
// QrCode 列印
const qrData = "https://example.com"; // Your QR code data
const qrDataLength = qrData.length + 3;
const pL = qrDataLength & 0xFF; // Low byte
const pH = (qrDataLength >> 8) & 0xFF; // High byte
const commands = [
0x1B, 0x40, // Initialize printer
0x1D, 0x28, 0x6B, pL, pH, 0x31, 0x50, 0x30, ...new TextEncoder().encode(qrData), // Store data
0x1D, 0x28, 0x6B, 0x03, 0x00, 0x31, 0x51, 0x30 // Print QR code
];
const buffer = new Uint8Array(commands);
await characteristic.writeValue(buffer);
logMessage("QrCode sent successfully!");
await characteristic.writeValue(finalData);
logMessage("finalData sent successfully!");
// Disconnect the GATT server
server.disconnect();
logMessage("Disconnected from printer.");
}
// Bind the function to the button
document.getElementById('printTestButton').addEventListener('click', connectAndTestPrint);
document.getElementById('printAgain').addEventListener('click', printAgain);
</script>
</body>
</html>
PromiseAll: async function (array) {
let taskList = [];
let propList = [];
for (let obj of array) {
for (let prop in obj) {
taskList.push(obj[prop]);
propList.push(prop);
}
}
let resp = await Promise.all(taskList);
let result = {};
let counter = 0;
for (let prop of propList) {
result[prop] = resp[counter];
counter += 1;
}
return result;
}
const taskList = [{
adPosition : BannerPositionDataService.GetList(),
big : BannerDataService.GetList(100),
smallTop : BannerDataService.GetOne(200),
smallBottom : BannerDataService.GetOne(300),
section2 : BannerDataService.GetList(400),
section3 : BannerDataService.GetList(500),
section4 : BannerDataService.GetList(600),
recommends : ProductDataService.GetRndList()
}];
let resps = await UJ.PromiseAll(taskList);
DeepBinding: function (vueData, data) {
if (Array.isArray(data)) {
if (!Array.isArray(vueData)) {
vueData = [];
} else {
vueData.splice(0);
}
for (let prop in data) {
vueData.push(data[prop]);
}
}
else if (typeof (data) === 'object') {
if (Object.keys(data).length === 0) {
return;
}
for (let prop in data) {
if (vueData[prop] === undefined || data[prop] === null ||
(!Array.isArray(vueData[prop] && vueData !== null && typeof (data) !== 'object'))) {
vueData[prop] = data[prop];
} else {
this.DeepBinding(vueData[prop], data[prop]);
}
}
} else {
vueData = data;
}
}
UJ.DeepBinding(this, resp);
var root = "C://wdqd/qwewq";
var addPath = @"//\\/fwef/qwf";
var addPath2 = @"5fwfef/qwf";
var addPath3 = @"//fwef/qwf";
var addPath4 = @"\\\fwef/qwf";
var addPath5 = @"\\\\\/fwef/qwf";
var result = root.AddPath(addPath, addPath2, addPath3, addPath4, addPath5);
Console.WriteLine(result);
public static class Helper
{
public static string AddPath(this string value, params string[] addPaths)
{
if (string.IsNullOrEmpty(value))
{
throw new Exception("起始目錄不可以為空字串");
}
if (value.Contains("..") || addPaths.Any(x => x.Contains("..")))
{
throw new Exception($"value: {value}, addPaths: {addPaths.Where(x => x.Contains("..")).ToOneString()} 檔名與路徑不可包含 ..");
}
var paths = addPaths.Select(x => x.Substring(x.FindLastContinuousCharPosition('/', '\\') + 1).SafeFilename()).ToList();
if (paths.Any(x => System.IO.Path.IsPathRooted(x)))
{
throw new Exception("不可併入完整路徑 ..");
}
paths.Insert(0, value.SafeFilename());
return System.IO.Path.Combine(paths.ToArray());
}
public static string ToOneString<T>(this IEnumerable<T> list, string separator = ",")
{
var strList = list.Select(x => x.ToString());
return string.Join(separator, strList);
}
public static int FindLastContinuousCharPosition(this string input, params char[] targets)
{
int lastPosition = -1;
for (int i = 0; i < input.Length; i++)
{
if (targets.Contains(input[i]))
{
lastPosition = i;
}
else
{
break;
}
}
return lastPosition;
}
public static string SafeFilename(this string value)
{
return GetValidFilename(value);
}
public static string GetValidFilename(string value)
{
string ValidFilenameCharacters = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\-_$.@:/# ";
if (value.Contains(".."))
{
throw new Exception("路徑中不可包含 .. ");
}
string newUrl = "";
for (int i = 0; i < value.Length; i++)
{
var c = value.Substring(i, 1);
int k = ValidFilenameCharacters.IndexOf(c);
if (k < 0)
{
throw new Exception($"檔名 '{value}' 中有非法的字元 '" + c + "'。");
}
newUrl += ValidFilenameCharacters.Substring(k, 1);
}
return newUrl;
}
}
/// <summary>
/// 會把物件 Parameter 的各 Property 帶入 SQL 中.
/// </summary>
/// <param name="dbct"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static async Task<int> ExecuteParameterSqlAsync(this DbContext dbct, string sql, object parameters)
{
return await dbct.Database.ExecuteSqlRawAsync(sql, parameters.ToSqlParamsArray());
}
public async Task<object> EfTest()
{
var dbct = Ds.NewContext.GvContext;
var insertSql = @"Insert into ProfileEvent(JobId,[Name],GvShoplineId,LiShoplineId,Phone,Email,LineId,GaClientId)
Values(@JobId, @Name, null , null , null , @Email, @GaClientId , @GaClientId )";
//執行 SQL 的原生寫法
await dbct.Database.ExecuteSqlRawAsync(insertSql, new object[]
{
new SqlParameter("@JobId", 10),
new SqlParameter("@Email", "XX'TT"),
new SqlParameter("@Name", "AA'BB"),
new SqlParameter("@GaClientId", "GaClientId"),
});
//執行 SQL 的擴充寫法
await dbct.ExecuteParameterSqlAsync(insertSql, new
{
JobId = 10,
Email = "XX'TT",
Name = "AA'BB",
GaClientId = "GaClientId"
});
//關於查詢
string name = "%'B%";
//原生寫法
var res1 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new object[]
{
new SqlParameter("@name", "%'B%")
})
.ToListAsync();
//擴充, object to SqlParameter array
var res2 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new { name }.ToSqlParamsArray())
.ToListAsync();
var res3 = await dbct.ProfileEvents.FromSql($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
var res4 = await dbct.ProfileEvents.FromSqlInterpolated($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
return new { res1, res2, res3, res4 };
}
string strPattern = @"^[\w\.-]{1,}@[a-zA-Z0-9][\w\.-]*\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex(strPattern);
string email = "darrenTEST@gmail.com";
Response.Write(email + " - > " + regEx.IsMatch(email) + "<br/>");
email = "darren_東@gmail.com";
Response.Write(email + " - > " + regEx.IsMatch(email) + "<br/>");
// darrenTEST@gmail.com - > True
// darren_東@gmail.com - > True
string strPattern = @"^[a-zA-Z0-9_\.-]{1,}@[a-zA-Z0-9][\w\.-]*\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex(strPattern);
string email = "darrenTEST@gmail.com";
Response.Write(email + " - > " + regEx.IsMatch(email) + "<br/>");
email = "darren_東@gmail.com";
Response.Write(email + " - > " + regEx.IsMatch(email) + "<br/>");
// darrenTEST@gmail.com - > True
// darren_東@gmail.com - > False
const regex = /^[\w\.-]{1,}@[a-zA-Z0-9][\w\.-]*\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/;
console.log(regex.test('darrenTEST@gmail.com')); // true
console.log(regex.test('darren_東@gmail.com')); // false
<script>
var thisPage = {
Init: function () {
thisPage.InitPageInput();
$("body")
;
thisPage.ChangeEvent();
},
ParameterByName: function (targetKey) {
var res = null;
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
for (const [key, value] of Object.entries(params)) {
if (targetKey.trim().toLocaleLowerCase() === key) {
res = value;
}
}
return res;
},
OriUrl: function () {
var arrayUrl = [];
arrayUrl.push(window.location.protocol);//https:
arrayUrl.push("//");
arrayUrl.push(window.location.hostname);//blog.uwinfo.com.tw
if (window.location.port.length > 0) {
//大多情況,不用特別指定port
arrayUrl.push(":");
arrayUrl.push(window.location.port);//80
}
arrayUrl.push(window.location.pathname);//post/Edit.aspx
//換一套寫法
//arrayUrl.push(window.location.search);//?Id=321
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
var ayyarQueryString = [];
//這邊可以加工增加額外的key值
for (const [key, value] of Object.entries(params)) {
if (value.trim().length > 0) {
//這邊要注意中文需要encode
ayyarQueryString.push(key + "=" + encodeURIComponent(value));
}
}
if (ayyarQueryString.length > 0) {
arrayUrl.push("?");
arrayUrl.push(ayyarQueryString.join('&'));
}
return arrayUrl.length > 0 ? arrayUrl.join('') : '';
},
InitPageInput: function () {
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
for (const [key, value] of Object.entries(params)) {
$('input[name=' + key + ']').val(value);
//這邊因為input有多種不同輸入方式,可以自行編輯
//$('select[name=' + key + ']').val(value);
//$('textarea[name=' + key + ']').html(value);
}
},
ChangeEvent: function () {
},
}
$(function () {
thisPage.Init();
});
</script>