HanvonAttendanceService/device-api-dump/userlist.html

1571 lines
60 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>user list</title>
<link href="resources/plugins/bootstrap-3.3.0/css/bootstrap.min.css" rel="stylesheet"/>
<link href="resources/plugins/material-design-iconic-font-2.2.0/css/material-design-iconic-font.min.css" rel="stylesheet"/>
<link href="resources/plugins/bootstrap-table-1.17.0/bootstrap-table.min.css" rel="stylesheet"/>
<link href="resources/plugins/waves-0.7.5/waves.min.css" rel="stylesheet"/>
<link href="resources/plugins/jquery-confirm/jquery-confirm.min.css" rel="stylesheet"/>
<link href="resources/css/common.css" rel="stylesheet"/>
<style>
.progress {
position: relative;
width: 100%; /* 确保进度条宽度适合 */
}
.progress-bar {
position: relative;
height: 20px; /* 设置进度条高度 */
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: inline-block;
color: #000; /* 默认颜色为黑色 */
transition: color 0.3s; /* 平滑过渡 */
white-space: nowrap; /* 防止文字换行 */
font-size: 14px; /* 可以根据需要调整字体大小 */
z-index: 1; /* 确保文字在进度条之上 */
}
/* 当进度超过50%时改变文字颜色 */
.progress-bar > .progress-text {
color: white;
}
.zmdi {
margin-right: 10px; /* 调整图标右侧间距 */
}
</style>
</head>
<body>
<div id="main">
<div id="toolbar">
<a class="waves-effect waves-button" href="javascript:;" onclick="createAction()"><i class="zmdi zmdi-account-add"></i><span class="lang" key="UISTR_USER_ADD">add user</span></a>
<a class="waves-effect waves-button" href="javascript:;" onclick="deleteAction()"><i class="zmdi zmdi-close"></i><span class="lang" key="UISTR_USER_DELETE">delete user</span></a>
<a class="waves-effect waves-button optional-btn" href="javascript:;" onclick="saveasexcelAction()"><i class="zmdi zmdi-case-download"></i><span class="lang" key="UISTR_SAVEASEXCEL">Save as Excel</span></a>
<a class="waves-effect waves-button optional-btn" href="javascript:;" onclick="importfromexcelAction()"><i class="zmdi zmdi-file-plus"></i><span class="lang" key="UISTR_IMPORTFROMEXCEL">Import from Excel</span></a>
<a class="waves-effect waves-button optional-btn" href="javascript:;" onclick="downloadImagesFromPhotouri()"><i class="zmdi zmdi-download"></i><span class="lang" key="UISTR_DOWNLOAD_PHOTOS">download all photos</span></a>
<a class="waves-effect waves-button optional-btn" href="javascript:;" onclick="uploadZIPAction()"><i class="zmdi zmdi-upload"></i><span class="lang" key="UISTR_UPLOAD_PHOTOS">upload photos from Zip</span></a>
<a id="downloadfingerprints" class="waves-effect waves-button optional-btn" href="javascript:;" onclick="downloadfingerprints()"><i class="zmdi zmdi-download"></i><span class="lang" key="UISTR_DOWNLOAD_FINGER">download all finger/palm</span></a>
<a id="uploadfingerprints" class="waves-effect waves-button optional-btn" href="javascript:;" onclick="uploadfingerprints()"><i class="zmdi zmdi-upload"></i><span class="lang" key="UISTR_UPLOAD_FINGER">upload finger/palm from CSV</span></a>
</div>
<table id="table"></table>
</div>
<!-- 添加模态窗口 -->
<div class="modal fade" id="uploadModal" tabindex="-1" role="dialog" aria-labelledby="uploadModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="uploadModalLabel">Upload Users</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p><span id="uploading" class="lang" key="UISTR_UPLOADING">Uploading</span></p>
<p><span id="uploaded" class="lang" key="UISTR_UPLOADED">Uploaded</span></p>
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<span class="progress-text">0%</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="lang btn btn-secondary" data-dismiss="modal" key="UISTR_CLOSE">Close</button>
</div>
</div>
</div>
</div>
<script src="resources/plugins/jquery.1.12.4.min.js"></script>
<script src="resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
<script src="resources/plugins/bootstrap-table-1.17.0/bootstrap-table.min.js"></script>
<script src="resources/plugins/waves-0.7.5/waves.min.js"></script>
<script src="resources/plugins/jquery-confirm/jquery-confirm.min.js"></script>
<script src="resources/plugins/jquery.cookie.js"></script>
<script src="resources/js/notify.js"></script>
<script src="resources/js/lang.js"></script>
<script src="resources/js/common.js"></script>
<script src="resources/js/admin.js"></script>
<script src="resources/js/xlsx.full.min.js"></script>
<script src="resources/js/jszip.min.js"></script>
<script src="resources/js/FileSaver.min.js"></script>
<script>
let hasFpsize = $.cookie("fpsize") !== undefined && $.cookie("fpsize") !== "0";
let hasPalmsize = $.cookie("palmsize") !== undefined && $.cookie("palmsize") !== "0";
let deviceid = $.cookie("deviceid") || "1";
let hasElevator = $.cookie("elevator_control") !== undefined && $.cookie("elevator_control") !== "0";
let DI_CARD_DISP_FORMAT = parseInt($.cookie("CARD_DISP_FORMAT")) || 0;
let DI_DATE_FORMAT = parseInt($.cookie("DATE_FORMAT")) || 0;
let DI_USERID_FORMAT = parseInt($.cookie("USERID_FORMAT")) || 0;
let hasFacetemplate = $.cookie("facetemplate") !== undefined && $.cookie("facetemplate") !== "0";
let poithide = $.cookie("manufacturer") !== undefined && $.cookie("manufacturer")==="Piot Robotics";
check_permission();
async function initializeApp() {
try {
// 1. 并行执行 lang_load() 和 format_get()
await Promise.all([lang_load()]);
// 2. 顺序执行后续操作
await get_userlist();
// 3. 批量设置标题(同步操作)
const titleMappings = [
['id', lang.UISTR_ENROLL_ID],
['name', lang.UISTR_UserName],
['department', lang.UISTR_Department],
['shift', lang.UISTR_UserShift],
['admin', lang.UISTR_Privilege],
['face', lang.UISTR_FACE_ENROLL],
['palm', lang.UISTR_PALM_ENROLL],
['fingerprint', lang.UISTR_FINGER_ENROLL],
['password', lang.UISTR_PASSWORD_ENROLL],
['card', lang.UISTR_CARD_ENROLL],
['weekzone', lang.UISTR_MAINMENU_PASSTIMEID],
['group', hasElevator ? lang.UISTR_DIRECT_FLOOR : lang.UISTR_MAINMENU_GROUPID],
['access_times', lang.UISTR_ACCESS_TIMES],
['verifymode', lang.UISTR_PERSON_VERIFY_MODE],
['birthday', lang.UISTR_BIRTHDAY],
['starttime', lang.UISTR_START],
['endtime', lang.UISTR_END],
['userprofile', lang.UISTR_USER_PROFILE],
['photouri', lang.UISTR_Photo_Url],
['action', lang.UISTR_EDITUSER]
];
titleMappings.forEach(([id, text]) => changetitle(id, text));
changeSearchPlaceholder();
} catch (error) {
console.error('初始化失败:', error);
// 可选:显示错误提示给用户
alert('初始化失败: ' + error.message);
}
}
// 执行入口
initializeApp();
const channel = new BroadcastChannel('userlist_channel');
channel.onmessage = async (e) => {
const { action,id} = e.data;
get_userinfo(id)
};
if (!hasFpsize && !hasPalmsize) {
$('#downloadfingerprints').hide(); // 或者使用 .remove() 删除
$('#uploadfingerprints').hide(); // 或者使用 .remove() 删除
}
function convertEnrollId(strid) {
if (typeof strid === 'number') {
return strid > 0xFFFFFFFF ? strid.toString() : strid;
}
if (typeof strid === 'string' && /^\d+$/.test(strid) && DI_USERID_FORMAT != 2) {
const num = Number(strid);
return Number.isSafeInteger(num) ? num : strid;
}
return strid;
}
function formatCard(card, dispFormat) {
if (card === null || card === undefined || card === "") {
return "";
}
const dispCard = BigInt(card);
const bits = dispCard.toString(2).length;
const byteLen = Math.ceil(bits / 8);
if (dispFormat === 1) {
if (byteLen <= 3 || byteLen === 4) {
if (byteLen <3) {
const number = dispCard & 0xFFFFFn;
return `0,${number.toString().padStart(5, '0')}`;
} else {
const area = (dispCard >> 16n) & 0xFFFFn;
const number = dispCard & 0xFFFFn;
return `${area},${number.toString().padStart(5, '0')}`;
}
} else {
return dispCard.toString();
}
} else if (dispFormat === 2) {
return `0x${dispCard.toString(16).toUpperCase()}`;
} else {
return dispCard.toString();
}
}
function parseCardInput(input) {
if (!input) return 0;
const str = input.trim().toUpperCase();
if (!str) return 0; // 默认返回0Number类型
try {
let value;
if (str.includes(',')) {
const [areaStr, numberStr] = str.split(',');
const area = BigInt(areaStr);
const number = BigInt(numberStr);
value = (area << 16n) + number;
}
else if (str.startsWith('0X')) {
value = BigInt(`0x${str.slice(2)}`);
}
else {
value = BigInt(str);
}
const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
const MIN_SAFE = BigInt(Number.MIN_SAFE_INTEGER);
if (value >= MIN_SAFE && value <= MAX_SAFE) {
return Number(value);
} else {
return value.toString();
}
} catch (e) {
return 0; // 解析失败返回0
}
}
function formatDateTimeByType(dateStr, dateType) {
if (!dateStr) return "";
const [datePart, timePart] = dateStr.split(' ');
const [year, month, day] = datePart.split('-');
let formattedDate;
switch (dateType) {
case 1: // MDY格式月/日/年)
formattedDate = `${month.padStart(2, '0')}/${day}/${year}`;
break;
case 2: // DMY格式日/月/年)
formattedDate = `${day}/${month.padStart(2, '0')}/${year}`;
break;
default: // YMD格式年/月/日)
formattedDate = `${year}/${month.padStart(2, '0')}/${day}`;
}
return `${formattedDate} ${timePart}`;
}
function formatMonthDay(dateStr, dateType = 0) {
if (!dateStr) return "";
if (!/^\d{1,2}-\d{1,2}\**$/.test(dateStr)) {
return "";
}
const [datePart, asterisk = ""] = dateStr.split(/(\d{1,2}-\d{1,2})/).filter(Boolean);
const [inputMonth, inputDay] = datePart.split('-');
const month = inputMonth.padStart(2, '0');
const day = inputDay.padStart(2, '0');
switch (dateType) {
case 1: // MDY月/日)
return `${month}/${day}${asterisk.replace(/[^*]/g, '')}`; // [2](@ref)
case 2: // DMY日/月)
return `${day}/${month}${asterisk.replace(/[^*]/g, '')}`; // [2](@ref)
default: // 默认保持原格式
return `${month}/${day}${asterisk.replace(/[^*]/g, '')}`; // [2](@ref)
}
}
function getVerfymodeString(index) {
const verifyModeLangMap = {
0: "UISTR_DEVICE_VERIFY_MODE",
20: "UISTR_ANY",
10: "UISTR_VERIFY_CARD_ADD_FACE",
9: "UISTR_VERIFY_FACE_ADD_PWD",
14: "UISTR_VERIFY_FACE_ADD_CARD_PWD",
8: "UISTR_FACE_ONLY",
21: "UISTR_PALMANDFACE",
22: "UISTR_FPANDPALM",
23: "UISTR_CARDANDPALM",
24: "UISTR_PALMANDPWD",
16: "UISTR_ONLYPALM",
12: "UISTR_VERIFY_FP_ADD_FACE",
5: "UISTR_VERIFY_FP_ADD_CARD",
4: "UISTR_SET_LIST_FP",
1: "UISTR_FINGER_ONLY",
11: "UISTR_SET_LIST_CP",
3: "UISTR_CARD_ONLY",
2: "UISTR_PASSWORD_ONLY"
};
return lang[verifyModeLangMap[index]] || "";
}
function reverseVerifyMode(str) {
const reverseMap = {
[lang.UISTR_DEVICE_VERIFY_MODE]: 0,
[lang.UISTR_ANY]: 20,
[lang.UISTR_VERIFY_CARD_ADD_FACE]: 10,
[lang.UISTR_VERIFY_FACE_ADD_PWD]: 9,
[lang.UISTR_VERIFY_FACE_ADD_CARD_PWD]: 14,
[lang.UISTR_FACE_ONLY]: 8,
[lang.UISTR_PALMANDFACE]: 21,
[lang.UISTR_FPANDPALM]: 22,
[lang.UISTR_CARDANDPALM]: 23,
[lang.UISTR_PALMANDPWD]: 24,
[lang.UISTR_ONLYPALM]: 16,
[lang.UISTR_VERIFY_FP_ADD_FACE]: 12,
[lang.UISTR_VERIFY_FP_ADD_CARD]: 5,
[lang.UISTR_SET_LIST_FP]: 4,
[lang.UISTR_FINGER_ONLY]: 1,
[lang.UISTR_SET_LIST_CP]: 11,
[lang.UISTR_CARD_ONLY]: 3,
[lang.UISTR_PASSWORD_ONLY]: 2
};
return reverseMap[str] ??parseInt(str, 10);
}
function getAdminString(index) {
const AdminLangMap = {
0: "UISTR_USER",
1: "UISTR_ENROLL_MANAGER",
2: "UISTR_ENROLL_SUPER_USER",
};
return lang[AdminLangMap[index]] || "";
}
function reverseAdmin(str) {
const reverseMap = {
[lang.UISTR_USER]: 0,
[lang.UISTR_ENROLL_MANAGER]: 1,
[lang.UISTR_ENROLL_SUPER_USER]: 2
};
return reverseMap[str] ?? parseInt(str, 10);
}
function formatUserprofileContent(userprofile) {
if (userprofile === null || userprofile === undefined || userprofile === "") return "";
if (typeof userprofile === 'object') {
return Object.entries(userprofile)
.map(([key, value]) => `${key}:${value}`)
.join(',');
}
if (typeof userprofile === 'string') {
try {
const parsed = JSON.parse(userprofile);
return Object.entries(parsed)
.map(([key, value]) => `${key}:${value}`)
.join(',');
} catch (e) {
return userprofile;
}
}
return String(userprofile);
}
function get_userinfo(enrollid) {
let send = new Object()
send["password"] = $.cookie("pwd")
send["cmd"] = 'getuserinfo'
send["enrollid"] = enrollid
console.log(send)
$.ajax({
url: debugserver+'/api',
type: 'POST',
contentType:"application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function() {
},
success: function(json){
console.log("done", json)
if (json.result) {
const transformedRecord = {
id: json.enrollid || "",
name: json.name || "",
department: json.department || "",
shift: json.shiftid || "",
admin: getAdminString(json.admin)|| "",
fingerprint: json.fpcnt || "",
palm: json.palmcnt || "",
face: json.faceflag || "",
password: json.pwd || "",
card: formatCard(json.card,DI_CARD_DISP_FORMAT)|| "",
weekzone: json.zoneid || "",
group: json.groupid || "",
access_times: json.access_times || "",
verifymode: getVerfymodeString(json.verifymode) || "",
birthday: formatMonthDay(json.birthday,DI_DATE_FORMAT),
starttime: formatDateTimeByType(json.starttime,DI_DATE_FORMAT),
endtime: formatDateTimeByType(json.endtime,DI_DATE_FORMAT),
userprofile: formatUserprofileContent(json.userprofile),
photouri: json.photourl || ""
};
const $table = $('#table');
$table.bootstrapTable('refresh');
const currentData = $table.bootstrapTable('getData');
const row = $table.bootstrapTable('getRowByUniqueId', json.enrollid);
if (row) {
$table.bootstrapTable('updateByUniqueId', {
id: json.enrollid,
row: transformedRecord
});
} else {
$table.bootstrapTable('append', transformedRecord);
}
$table.bootstrapTable('scrollTo', {
unit: 'rows',
value: rowIndex >= 0 ? rowIndex : $table.bootstrapTable('getData').length - 1,
scrollSpeed: 'fast'
});
} else {
console.log("error", json);
}
},
error: function(error){
console.log("error::::",error);
}
});
}
function get_userlist(stn = 1) {
let send = {
password: $.cookie("pwd"),
cmd: 'getuserlist',
stn: stn
};
$.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function() {},
success: function(json) {
console.log("done", json);
let records = json.record;
let transformedData = [];
for (let record of records) {
let transformedRecord = {
id: record.id || "",
name: record.name || "",
department: record.department || "",
shift: record.shift || "",
admin: getAdminString(record.admin)|| "",
fingerprint: record.fingerprint || "",
palm: record.palm || "",
face: record.face || "",
password: record.password || "",
card: formatCard(record.card,DI_CARD_DISP_FORMAT)|| "",
weekzone: record.weekzone || "",
group: record.group || "",
access_times: record.access_times || "",
verifymode: getVerfymodeString(record.verifymode) || "",
birthday: formatMonthDay(record.birthday,DI_DATE_FORMAT),
starttime: formatDateTimeByType(record.starttime,DI_DATE_FORMAT),
endtime: formatDateTimeByType(record.endtime,DI_DATE_FORMAT),
userprofile: formatUserprofileContent(record.userprofile),
photouri: record.photourl || ""
};
transformedData.push(transformedRecord);
}
// Load or append data into the table
if (stn === 1) {
$table.bootstrapTable('load', transformedData);
} else {
$table.bootstrapTable('append', transformedData);
}
// Check if more data needs to be fetched
if (json.count > 0 && json.to !== undefined && json.to < json.count) {
// 递归调用来获取更多数据
get_userlist(0); // stn = 0 for subsequent requests
}
},
error: function(error) {
console.log("error::::", error);
}
});
}
var $table = $('#table');
$(function() {
$(document).on('focus', 'input[type="text"]', function() {
$(this).parent().find('label').addClass('active');
}).on('blur', 'input[type="text"]', function() {
if ($(this).val() == '') {
$(this).parent().find('label').removeClass('active');
}
});
// bootstrap table初始化
// http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/
var columns = [
{field: 'state', checkbox: true},
{field: 'id', title:'id', sortable: true, halign: 'center', align: 'center'},
{field: 'name', title: 'name', sortable: true, halign: 'center', align: 'center'},
{field: 'department', title: 'department', sortable: true, halign: 'center', align: 'center'},
{field: 'shift', title: 'shift', sortable: true, halign: 'center', align: 'center'},
{field: 'admin', title: 'admin', sortable: true, halign: 'center', align: 'center'},
{field: 'face', title: 'face', sortable: true, halign: 'center' , formatter: 'actionfaceFormatter', align: 'center'},
hasPalmsize ? {field: 'palm', title: 'palm', sortable: true, halign: 'center', align: 'center'} : null,
hasFpsize ? {field: 'fingerprint', title: 'fp', sortable: true, halign: 'center', align: 'center'} : null,
{field: 'password', title: 'pwd', sortable: true, halign: 'center', align: 'center'},
{field: 'card', title: 'card', sortable: true, halign: 'center', align: 'center'},
{field: 'weekzone', title: 'weekzone', sortable: true, halign: 'center', align: 'center'},
{field: 'group', title: 'group', sortable: true, halign: 'center', align: 'center'},
{field: 'access_times', title: 'access_times', sortable: true, halign: 'center', align: 'center'},
{field: 'verifymode', title: 'verifymode', sortable: true, halign: 'center', align: 'center'},
{field: 'birthday', title: 'birthday', sortable: false, halign: 'center', align: 'center'},
{field: 'starttime', title: 'starttime', sortable: true, halign: 'center', align: 'center'},
{field: 'endtime', title: 'endtime', sortable: true, halign: 'center', align: 'center'},
{field: 'userprofile', title: 'userprofile', sortable: false, halign: 'center', align: 'center'},
{field: 'photouri', title: 'photouri', visible: false},
{field: 'action', title: 'action', halign: 'center', align: 'center', formatter: 'actionFormatter', events: 'actionEvents', clickToSelect: false}
].filter(Boolean);
$table.bootstrapTable({
data: [],
height: getHeight(),
striped: true,
search: true,
searchOnEnterKey: true,
showRefresh: true,
//showToggle: true,
showColumns: true,
minimumCountColumns: 2,
//showPaginationSwitch: true,
clickToSelect: true,
detailView: true,
detailFormatter: 'detailFormatter',
pagination: true,
pageSize: 15,
pageList: [10, 15, 30, 50, 100],
paginationLoop: false,
classes: 'table table-hover table-no-bordered',
//sidePagination: 'server',
//silentSort: false,
smartDisplay: false,
uniqueId: 'id',
idField: 'id',
sortName: 'department',
sortOrder: 'asc',
escape: true,
searchOnEnterKey: true,
maintainSelected: true,
toolbar: '#toolbar',
columns: columns
}).on('all.bs.table', function (e, name, args) {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();
});
});
function changeSearchPlaceholder() {
const options = $table.bootstrapTable('getOptions');
options.formatSearch = () => lang.UISTR_USER_FIND || 'Search...';
options.formatRefresh = () => lang.UISTR_Refresh || 'Refresh';
options.formatRefreshButton = (icon, text) =>
`<i class="${icon}"></i> ${text || lang.UISTR_Refresh || 'Refresh'}`;
options.formatColumns = () => lang.UISTR_Columns || 'Columns'; // [4](@ref)
options.formatColumnsButton = (icon, text) =>
`<i class="${icon}"></i> ${text || lang.UISTR_Columns || 'Columns'}`;
options.formatToggle = () => lang.UISTR_Toggle || 'Toggle'; // 悬浮提示Tooltip
options.formatToggleButton = (icon, text) =>
`<i class="${icon}"></i> ${text || lang.UISTR_Toggle || 'Toggle'}`; // 按钮文本
options.formatNoMatches = () => lang.UISTR_NoMatches || 'No matching records found';
options.formatShowingRows = (from, to, total) => {
const template = lang.UISTR_ShowingRows
|| 'Showing #1 to #2 of #3 rows';
return template
.replace(/#1/g, from)
.replace(/#2/g, to)
.replace(/#3/g, total);
};
options.formatRecordsPerPage = (pageSize) => {
const template = lang.UISTR_RecordsPerPage
|| '#3 rows per page';
return template.replace(/#3/g, pageSize);
};
// 强制刷新配置
$table.bootstrapTable('refreshOptions', options);
}
function changetitle(field, newTitle) {
var columns = $table.bootstrapTable('getOptions').columns[0];
for (var i = 0; i < columns.length; i++) {
if (columns[i].field === field) {
columns[i].title = newTitle;
break;
}
}
$table.bootstrapTable('refreshOptions', {columns: columns});
}
$table.on('refresh.bs.table', function () {
$table.bootstrapTable('removeAll');
get_userlist();
});
function actionFormatter(value, row, index) {
const editTitle = lang.UISTR_EDITUSER || 'Edit';
const removeTitle = lang.UISTR_USER_DELETE || 'Remove';
return [
'<a class="edit ml10" href="javascript:void(0)" data-toggle="tooltip" title="' + editTitle + '">',
'<i class="glyphicon glyphicon-edit"></i></a> ',
'<a class="remove ml10" href="javascript:void(0)" data-toggle="tooltip" title="' + removeTitle + '">',
'<i class="glyphicon glyphicon-remove"></i></a>'
].join('');
}
function actionfaceFormatter(value, row, index) {
return value ? `<i class="glyphicon glyphicon-user"></i>` : '';
}
window.actionEvents = {
'click .face': function (e, value, row, index) {
console.log(value, row, index);
},
'click .edit': function (e, value, row, index) {
console.log(value, row, index);
if (window.parent && window.parent.Tab && typeof window.parent.Tab.addTab === 'function') {
var url = 'add_member.html?id=' + encodeURIComponent(row.id);
window.parent.Tab.addTab(lang.UISTR_USER_EDIT, url);
} else {
console.error('Tab object or addTab method is not accessible.');
}
},
'click .remove': function (e, value, row, index) {
e.preventDefault();
$.confirm({
type: 'red',
title: false,
content: lang.UISTR_DELETE_QMARK,
buttons: {
confirm: {
text: lang.UISTR_YES_OK,
btnClass: 'waves-effect waves-button',
action: function () {
let data = {
cmd: "deleteusers",
list: [row.id],
password: $.cookie("pwd")
};
$.ajax({
url: debugserver+'/api',
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
success: function (response) {
if (response.ret == "deleteusers" && response.result == true) {
$('#table').bootstrapTable('remove', {
field: 'id',
values: [row.id]
});
$.alert(lang.UISTR_DELETE_OK);
onUploadSuccess();
} else {
$.alert(lang.UISTR_ERRNONESUCCESS);
}
},
error: function (xhr, status, error) {
console.error('Error:', error);
$.alert(lang.UISTR_CONNECT_FAILED);
}
});
}
},
cancel: {
text: lang.UISTR_NO_ESC,
btnClass: 'waves-effect waves-button'
}
}
});
}
};
function detailFormatter(index, row) {
var html = [];
var detailsHtml = [];
// Manually add the information you want to display
detailsHtml.push('<p><b>'+lang.UISTR_ENROLL_ID+'</b>' + row.id + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_UserName+'</b>' + row.name + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_Privilege+'</b>' + row.admin + '</p>');
if(!poithide)
{
detailsHtml.push('<p><b>'+lang.UISTR_Department+'</b>' + row.department + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_UserShift+'</b>' + row.shift + '</p>');
if(hasPalmsize)
detailsHtml.push('<p><b>'+lang.UISTR_PALM_ENROLL+'</b>' + row.palm + '</p>');
if(hasFpsize)
detailsHtml.push('<p><b>'+lang.UISTR_FINGER_ENROLL+'</b>' + row.fingerprint + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_PASSWORD_ENROLL+'</b>' + row.password + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_CARD_ENROLL+'</b>' + row.card + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_MAINMENU_PASSTIMEID+'</b>' + row.weekzone + '</p>');
}
if(hasElevator)
detailsHtml.push('<p><b>'+lang.UISTR_DIRECT_FLOOR+'</b>' + row.group + '</p>');
else
detailsHtml.push('<p><b>'+lang.UISTR_MAINMENU_GROUPID+'</b>' + row.group + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_PERSON_VERIFY_MODE+'</b>' + row.verifymode + '</p>');
if(!poithide)
{
detailsHtml.push('<p><b>'+lang.UISTR_ACCESS_TIMES+'</b>' + row.access_times + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_BIRTHDAY+'</b>' + row.birthday + '</p>');
}
detailsHtml.push('<p><b>'+lang.UISTR_START+'</b>' + row.starttime + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_END+'</b>' + row.endtime + '</p>');
detailsHtml.push('<p><b>'+lang.UISTR_USER_PROFILE+'</b>' + row.userprofile + '</p>');
html.push('<div class="row">');
html.push(' <div class="col-md-8 col-sm-8">');
html.push(' <div class="row">');
html.push(' <div class="col-md-6 col-sm-6">' + detailsHtml.slice(0, Math.ceil(detailsHtml.length / 2)).join('') + '</div>');
html.push(' <div class="col-md-6 col-sm-6">' + detailsHtml.slice(Math.ceil(detailsHtml.length / 2)).join('') + '</div>');
html.push(' </div>');
html.push(' </div>');
html.push(' <div class="col-md-4 col-sm-4 d-flex justify-content-end">');
var imageUrl = debugserver + row.photouri;
if (imageUrl && imageUrl.trim()) {
html.push(' <a href="' + imageUrl+'?t=' + new Date().getTime() + '" target="_blank">');
html.push(' <img src="' + imageUrl+'?t=' + new Date().getTime() + '" alt="User Image" style="max-height:200px; max-width:100%;" />');
html.push(' </a>');
}
html.push(' </div>');
html.push('</div>');
return html.join('');
}
function createAction() {
if (window.parent && window.parent.Tab && typeof window.parent.Tab.addTab === 'function') {
window.parent.Tab.addTab(lang.UISTR_USER_ENROLL, 'add_member.html');
} else {
console.error('Tab object or addTab method is not accessible.');
}
}
function updateAction() {
var rows = $table.bootstrapTable('getSelections');
if (rows.length === 0) {
$.confirm({
title: false,
content: '请至少选择一条记录!',
autoClose: 'cancel|3000',
backgroundDismiss: true,
buttons: {
cancel: {
text: lang.UISTR_NO_ESC,
btnClass: 'waves-effect waves-button'
}
}
});
} else if (rows.length > 1) {
$.confirm({
title: false,
content: '请选择单条记录进行编辑!',
autoClose: 'cancel|3000',
backgroundDismiss: true,
buttons: {
cancel: {
text: lang.UISTR_NO_ESC,
btnClass: 'waves-effect waves-button'
}
}
});
} else {
if (window.parent && window.parent.Tab && typeof window.parent.Tab.addTab === 'function') {
var url = 'add_member.html?id=' + encodeURIComponent(rows[0].id);
window.parent.Tab.addTab(lang.UISTR_EDITUSER, url);
} else {
console.error('Tab object or addTab method is not accessible.');
}
}
}
function deleteAction() {
var rows = $table.bootstrapTable('getSelections');
if (rows.length == 0) {
$.confirm({
title: false,
content: '请至少选择一条记录!',
autoClose: 'cancel|3000',
backgroundDismiss: true,
buttons: {
cancel: {
text: lang.UISTR_NO_ESC,
btnClass: 'waves-effect waves-button'
}
}
});
} else {
$.confirm({
type: 'red',
animationSpeed: 300,
title: false,
content: lang.UISTR_DELETE_QMARK,
buttons: {
confirm: {
text: lang.UISTR_YES_OK,
btnClass: 'waves-effect waves-button',
action: function () {
var ids = [];
for (var i in rows) {
ids.push(rows[i].id);
}
let send = new Object();
send["password"] = $.cookie("pwd");
send["cmd"] = 'deleteusers';
send["list"] = ids;
$.ajax({
url: debugserver+'/api',
type: 'POST',
data: JSON.stringify(send),
contentType: 'application/json',
success: function (response) {
if (response.ret === "deleteusers" && response.result === true) {
$table.bootstrapTable('remove', {
field: 'id',
values: ids
});
$.alert(lang.UISTR_DELETE_OK);
onUploadSuccess();
}
else if(response.result === false)
{
$.alert(lang.UISTR_ERRNONESUCCESS);
}
},
error: function (xhr, status, error) {
console.log('Error: ' + error);
}
});
}
},
cancel: {
text: lang.UISTR_NO_ESC,
btnClass: 'waves-effect waves-button'
}
}
});
}
}
/////////////////////////////////////////////down all photos
function extractFileNameFromPath(path) {
const parts = path.split('/');
return parts[parts.length - 1];
}
function updateProgressBar(total, uploaded,fileName=null,isdownload=false) {
const progressBar = $('.progress-bar');
var percentage = (uploaded / total) * 100;
progressBar.css('width', `${percentage}%`).attr('aria-valuenow', percentage);
var textuploaded=lang.UISTR_UPLOADED;
var textuploading=lang.UISTR_UPLOADING;
if(isdownload)
{
textuploaded=lang.UISTR_DOWNLOADED;
textuploading=lang.UISTR_DOWNLOADING;
}
$('#uploaded').text(textuploaded+': '+uploaded+' / '+total);
if(fileName)
$('#uploading').text(textuploading+': '+fileName);
else
$('#uploading').text(textuploading+': --');
// 更新进度条中的文字
const progressText = $('.progress-text');
progressText.text(`${Math.round(percentage)}%`);
// 根据进度调整文字颜色
if (percentage > 52) {
progressText.css('color', 'white');
} else {
progressText.css('color', 'black');
}
}
// 新增全局ZIP对象和配置
let zip = null;
let zipFileName = `EnrollPhoto_${deviceid}.zip`;
function downloadImagesFromPhotouri(batchSize = 5) {
const allRows = $table.bootstrapTable('getData');
const filteredRows = allRows.filter(row => row.photouri !== null && row.photouri !== "");
const totalRows = filteredRows.length;
let currentIndex = 0;
let uploadedCount = 0;
// 初始化ZIP实例
zip = new JSZip();
$('#uploadModalLabel').text(lang.UISTR_DOWNLOAD_PHOTOS);
$('#uploadModal').modal('show');
async function downloadBatch() {
const endIndex = Math.min(currentIndex + batchSize, totalRows);
const batch = filteredRows.slice(currentIndex, endIndex);
try {
await Promise.all(batch.map(async row => {
const imageUrl = debugserver + row.photouri + `?random=${Math.random()}`;
const fileName = extractFileNameFromPath(row.photouri);
const blob = await fetch(imageUrl)
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.blob();
});
zip.file(fileName, blob, { binary: true });
uploadedCount++;
updateProgressBar(totalRows, uploadedCount,fileName,true);
}));
currentIndex = endIndex;
if (currentIndex < totalRows) {
setTimeout(downloadBatch, 1000);
} else {
const content = await zip.generateAsync({ type: "blob" });
saveAs(content, zipFileName);
$('#uploadModal').modal('hide');
zip = null;
}
} catch (error) {
console.error('Batch error:', error);
$('#uploadModal').modal('hide');
}
}
downloadBatch();
}
// 处理单个图片文件
async function post_image(file, index, totalPhotos, successCount, failCount) {
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onload = function(event) {
// 获取Base64编码数据去除头部
const base64String = event.target.result.split(',')[1];
const fileName = file.name;
const enrollId = validateFileName(fileName);
if (enrollId !== null) {
set_image(enrollId, base64String, index, totalPhotos, successCount, failCount)
.then((result) => resolve(result))
.catch((error) => reject(error));
} else {
console.warn(`Invalid file name: ${fileName}`);
reject({ success: false, message: `Invalid file name: ${fileName}` });
}
};
reader.readAsDataURL(file);
});
}
// 验证文件名
function validateFileName(fileName) {
const regex = /^LF(\d{1,8})\.jpg$|^LF(\d{9,64})\.jpg$|^CF_([\w-]+)\.jpg$/;
const match = fileName.match(regex);
if (match) {
if (match[1]) {
return parseInt(match[1], 10);
}
else if (match[2]) {
return BigInt(match[2]);
}
else if (match[3]) {
return match[3];
}
}
return null;
}
async function set_image(enrollId, base64String, index, totalPhotos, successCount, failCount) {
let send = new Object();
send["password"] = $.cookie("pwd");
send["cmd"] = 'setuserinfo';
send["enrollid"] = enrollId;
if (base64String) {
send["face"] = base64String;
}
console.log(send);
return new Promise((resolve, reject) => {
$.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function() {
},
success: function(json) {
console.log("done", json);
if (json.ret === "setuserinfo" && json.result === true) {
resolve({ success: true });
} else {
reject({ success: false, message: `Upload failed for ${enrollId}: ${json.message}` });
}
},
error: function(error) {
console.log("error::::", error);
reject({ success: false, message: `Error uploading image: ${error.responseText}` });
}
});
});
}
//////////////////////////////////////////////////////////
function uploadZIPAction() {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.zip'; // 限制只允许ZIP文件[8](@ref)
fileInput.onchange = async (e) => {
const zipFile = e.target.files[0];
if (!zipFile) return;
$('#uploadModalLabel').text(lang.UISTR_UPLOAD_PHOTOS);
$('#uploadModal').modal('show');
try {
const zip = await JSZip.loadAsync(zipFile);
const entries = Object.values(zip.files);
// 过滤目录并统计有效图片数量[4](@ref)
const imageEntries = entries.filter(entry =>
!entry.dir && entry.name.match(/\.(jpg|jpeg|png)$/i)
);
const totalPhotos = imageEntries.length;
let successCount = 0, failCount = 0;
// 批量处理ZIP内图片
for (const [index, entry] of imageEntries.entries()) {
try {
const blob = await entry.async('blob');
const file = new File([blob], entry.name.split('/').pop(), {
type: 'image/jpeg'
});
await post_image(file, index, totalPhotos);
successCount++;
updateProgressBar(totalPhotos, successCount, entry.name);
} catch (error) {
console.error(`文件上传失败: ${entry.name}`, error);
failCount++;
}
}
} catch (error) {
console.error('ZIP处理失败:', error);
alert(`ZIP文件处理失败: ${error.message}`);
} finally {
$('#uploadModal').modal('hide');
}
};
fileInput.click();
}
///////////////////////////////////////////excel
function saveasexcelAction() {
var allRows = $table.bootstrapTable('getData');
var workbook = XLSX.utils.book_new();
var exceldata = [];
exceldata.push([lang.UISTR_STAFF]);
exceldata.push([lang.UISTR_USERLIST_NOTE]);
var columnNames = [
lang.UISTR_ENROLL_ID,
lang.UISTR_UserName,
lang.UISTR_Department,
lang.UISTR_UserShift,
lang.UISTR_ENROLL_MANAGER,
hasPalmsize ? lang.UISTR_PALM_ENROLL : null,
hasFpsize ? lang.UISTR_FINGER_ENROLL : null,
lang.UISTR_FACE_ENROLL,
lang.UISTR_PASSWORD_ENROLL,
lang.UISTR_CARD_ENROLL,
lang.UISTR_LOCK_TIMEZONE,
lang.UISTR_MAINMENU_GROUPID,
lang.UISTR_ACCESS_TIMES,
lang.UISTR_VERIFY_mode,
lang.UISTR_BIRTHDAY,
lang.UISTR_START,
lang.UISTR_END,
lang.UISTR_USER_PROFILE
];
columnNames = columnNames.filter(columnName => columnName !== null);
exceldata.push(columnNames);
allRows.forEach(function(row) {
var rowData = [
row.id,
row.name,
row.department,
row.shift,
reverseAdmin(row.admin),
hasPalmsize ? row.palm : null,
hasFpsize ? row.fingerprint : null,
row.face,
row.password,
parseCardInput(row.card),
row.weekzone,
row.group,
row.access_times,
reverseVerifyMode(row.verifymode),
row.birthday,
row.starttime,
row.endtime,
row.userprofile
];
rowData = rowData.filter(value => value !== null);
exceldata.push(rowData);
});
var worksheet = XLSX.utils.aoa_to_sheet(exceldata);
var fontStyle = {
font: {
bold: true,
color: { rgb: [255, 0, 0] },
sz: 14,
family: 2,
name: 'Arial'
}
};
var alignmentStyle = {
wrapText: true,
vertical: 'center',
horizontal: 'center'
};
worksheet['A1'].f = fontStyle;
worksheet['A1'].s = alignmentStyle;
worksheet['A2'].f = fontStyle;
worksheet['A2'].s = alignmentStyle;
worksheet['!merges'] = [
{ s: { r: 0, c: 0 }, e: { r: 0, c: columnNames.length - 1 } },
{ s: { r: 1, c: 0 }, e: { r: 1, c: columnNames.length - 1 } }
];
XLSX.utils.book_append_sheet(workbook, worksheet, lang.UISTR_STAFF);
XLSX.writeFile(workbook, lang.UISTR_STAFF + '.xls', { bookType: 'xls' });
let field = window.lang.UISTR_DOWNLOAD_OK;
notify(field);
}
////////////////////////////////////////down finger/palm
function downloadfingerprints() {
var allRows = $table.bootstrapTable('getData');
const filteredRows = allRows.filter(row =>
(typeof row.palm === 'string' ? parseInt(row.palm, 10) : row.palm) > 0 ||
(hasFacetemplate&&(typeof row.face === 'string' ? parseInt(row.face, 10) : row.face)> 0) ||
(typeof row.fingerprint === 'string' ? parseInt(row.fingerprint, 10) : row.fingerprint) > 0
);
// 计算总的行数,包括所有的手指和手掌数据
const totalRows = filteredRows.reduce((sum, row) => {
const palm = typeof row.palm === 'string' ? parseInt(row.palm, 10) : row.palm;
const face =hasFacetemplate?(typeof row.face === 'string' ? parseInt(row.face, 10) : row.face):0;
const fingerprint = typeof row.fingerprint === 'string' ? parseInt(row.fingerprint, 10) : row.fingerprint;
return sum + (isNaN(palm) ? 0 : palm)+ (isNaN(face) ? 0 : face) + (isNaN(fingerprint) ? 0 : fingerprint);
}, 0);
let currentIndex = 0;
let dataForCsv = [];
let havesetcsv=false;
let allcount=0;
currentIndex=0;
havesetcsv=false;
// 显示模态对话框
$('#uploadModalLabel').text(lang.UISTR_DOWNLOAD_FINGER);
$('#uploadModal').modal('show');
function processRow(row) {
if (row.fingerprint > 0) {
for (let i = 0; i < row.fingerprint; i++) {
get_userinfo(row.id, i).then(fingerprintData => {
// 将指纹数据添加到 dataForCsv 数组中
dataForCsv.push({
index: allcount++,
deviceid: deviceid,
userid: row.id,
backupnumber: i,
data: fingerprintData
});
currentIndex++;
updateProgressBar(totalRows, currentIndex,row.id,true);
checkIfAllDataCollected(currentIndex);
}).catch(error => {
console.error('Error getting fingerprint data:', error);
currentIndex++;
checkIfAllDataCollected(currentIndex);
});
}
}
if (row.palm > 0) {
for (let i = 0; i < row.palm; i++) {
get_userinfo(row.id, i + 40).then(palmData => {
dataForCsv.push({
index: allcount++,
deviceid: deviceid,
userid: row.id,
backupnumber: i + 40,
data: palmData
});
currentIndex++;
updateProgressBar(totalRows, currentIndex,row.id,true);
checkIfAllDataCollected(currentIndex);
}).catch(error => {
console.error('Error getting palm data:', error);
currentIndex++;
checkIfAllDataCollected(currentIndex);
});
}
}
if(hasFacetemplate&&row.face){
get_userinfo(row.id, 51).then(facedata => {
dataForCsv.push({
index: allcount++,
deviceid: deviceid,
userid: row.id,
backupnumber: 51,
data: facedata
});
currentIndex++;
updateProgressBar(totalRows, currentIndex,row.id,true);
checkIfAllDataCollected(currentIndex);
}).catch(error => {
console.error('Error getting palm data:', error);
currentIndex++;
checkIfAllDataCollected(currentIndex);
});
}
}
function checkIfAllDataCollected(ncurrentIndex) {
if (ncurrentIndex >= totalRows) {
if (!havesetcsv) {
generateAndDownloadCsv(dataForCsv);
havesetcsv = true;
}
}
}
function generateAndDownloadCsv(data) {
let header = `${allcount}\tTMNo\tEnNo\tBackupNum\tData\t\r\n`;
const csvContent = "data:text/csv;charset=utf-8,"
+ header
+ data.map(row => [
row.index,
row.deviceid,
row.userid,
row.backupnumber,
row.data
].join("\t") + "\r\n").join(''); // 确保每行数据后都有换行符
const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
let paddedDeviceId = String(deviceid).padStart(3, '0');
link.setAttribute("href", encodedUri);
link.setAttribute("download", `CFP_${paddedDeviceId}.CSV`);
document.body.appendChild(link);
link.click();
}
function get_userinfo(userid, backupnum) {
return new Promise((resolve, reject) => {
let send = new Object();
let enrollid;
if (/^\d+$/.test(userid)) {
const isSafe = Number(userid) <= Number.MAX_SAFE_INTEGER;
enrollid = isSafe ? Number(userid) : userid;
}
else {
enrollid = userid;
}
send["password"] = $.cookie("pwd");
send["cmd"] = 'getuserinfo'
send["enrollid"] = enrollid;
send["backupnum"] = backupnum;
console.log(send);
$.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function () { },
success: function (json) {
if (json.result) {
resolve(json.record);
} else {
reject(json);
}
},
error: function (error) {
reject(error);
}
});
});
}
// 开始处理每一行
filteredRows.forEach(processRow);
}
function uploadfingerprints() {
// 创建一个文件输入元素
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.CSV';
// 当文件被选中时触发
fileInput.onchange = function(event) {
const file = event.target.files[0];
if (file) {
// 使用 FileReader 读取文件内容
const reader = new FileReader();
reader.onload = function(e) {
const csvContent = e.target.result;
processDataFromCSV(csvContent);
};
reader.readAsText(file);
}
};
// 触发文件选择框
fileInput.click();
}
function processDataFromCSV(csvContent) {
var allRows = [];
var lines = csvContent.split('\n');
// 跳过标题行
var headerLine = lines.shift();
for (var i = 0; i < lines.length; i++) {
var columns = lines[i].split('\t');
if (columns.length >= 5) {
var row = {
id: convertEnrollId(columns[2]),
backupnumber: Number(columns[3]),
record: columns[4].replace(/\r/g, '')
};
allRows.push(row);
}
}
const totalRows = allRows.length;
let currentIndex = 0;
// 显示模态对话框
$('#uploadModalLabel').text(lang.UISTR_UPLOAD_FINGER);
$('#uploadModal').modal('show');
function processRow(row) {
set_fingerprint(row).then(() => {
currentIndex++;
updateProgressBar(totalRows, currentIndex);
if (currentIndex < totalRows) {
processRow(allRows[currentIndex]);
} else {
// 所有数据处理完成
$('#uploadModal').modal('hide');
}
}).catch(error => {
console.error('Error setting user info:', error);
currentIndex++;
if (currentIndex < totalRows) {
processRow(allRows[currentIndex]);
} else {
// 所有数据处理完成
$('#uploadModal').modal('hide');
}
});
}
// 开始处理第一行
if (allRows.length > 0) {
processRow(allRows[0]);
}
}
function set_fingerprint(row) {
return new Promise((resolve, reject) => {
let send = new Object();
send["password"] = $.cookie("pwd");
send["cmd"] = 'setuserinfo';
send["enrollid"] = convertEnrollId(row.id);
send["backupnum"] = row.backupnumber;
send["record"] = row.record;
console.log(send);
$.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function () { },
success: function (json) {
if (json.ret === "setuserinfo" && json.result === true) {
resolve(); // 成功时解析
} else {
reject(json); // 结果为 false 时拒绝
}
},
error: function (error) {
reject(error); // AJAX 请求失败时拒绝
}
});
});
}
//////////////////////////////////////////////////////
function importfromexcelAction() {
// 创建一个文件输入元素
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.xls';
// 当文件被选中时触发
fileInput.onchange = function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, { type: 'binary' });
var sheet_name_list = workbook.SheetNames;
var first_worksheet = workbook.Sheets[sheet_name_list[0]];
var excel_data = XLSX.utils.sheet_to_json(first_worksheet, { header: 1 });
handleExcelData(excel_data);
};
reader.readAsBinaryString(file);
}
};
fileInput.click();
}
function handleExcelData(data) {
// 显示模态对话框
$('#uploadModalLabel').text(lang.UISTR_IMPORTFROMEXCEL);
$('#uploadModal').modal('show');
// 移除标题行和列名校验行
data.shift(); // 移除第一行
data.shift(); // 移除第二行
// 从第三行读取列名
var columnNames = data[0]; // 第三行
var columnMapping = {};
for (var i = 0; i < columnNames.length; i++) {
var columnName = columnNames[i];
if (columnName) {
columnMapping[columnName.trim()] = i;
}
}
// 移除已经读取的第三行
data.shift(); // 移除第三行
// 初始化进度条
var filteredData = data.filter(row => !isEmptyRow(row));
var totalRows = filteredData.length;
var currentRow = 0;
// 定义一个异步函数来处理每一行数据
async function processRow(row) {
let send = {
password: $.cookie("pwd"),
cmd: 'setuserinfo'
};
var showname=null;
// 根据列名处理数据
if (row[columnMapping[lang.UISTR_ENROLL_ID.trim()]]) {
send["enrollid"] = convertEnrollId(row[columnMapping[lang.UISTR_ENROLL_ID.trim()]]);
showname=send["enrollid"];
}
if (row[columnMapping[lang.UISTR_UserName.trim()]]) {
send["name"] = row[columnMapping[lang.UISTR_UserName.trim()]];
showname=send["name"];
}
if (row[columnMapping[lang.UISTR_Department.trim()]]) {
send["department"] = row[columnMapping[lang.UISTR_Department.trim()]];
}
if (row[columnMapping[lang.UISTR_UserShift.trim()]]) {
send["shiftid"] = parseInt(row[columnMapping[lang.UISTR_UserShift.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_ENROLL_MANAGER.trim()]]) {
send["admin"] = reverseAdmin(row[columnMapping[lang.UISTR_ENROLL_MANAGER.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_PASSWORD_ENROLL.trim()]]) {
send["pwd"] = parseInt(row[columnMapping[lang.UISTR_PASSWORD_ENROLL.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_CARD_ENROLL.trim()]]) {
send["card"] = parseInt(row[columnMapping[lang.UISTR_CARD_ENROLL.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_LOCK_TIMEZONE.trim()]]) {
send["zoneid"] = parseInt(row[columnMapping[lang.UISTR_LOCK_TIMEZONE.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_MAINMENU_GROUPID.trim()]]) {
send["groupid"] = parseInt(row[columnMapping[lang.UISTR_MAINMENU_GROUPID.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_ACCESS_TIMES.trim()]]) {
send["access_times"] = parseInt(row[columnMapping[lang.UISTR_ACCESS_TIMES.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_VERIFY_mode.trim()]]) {
send["verifymode"] = reverseVerifyMode(row[columnMapping[lang.UISTR_VERIFY_mode.trim()]], 10);
}
if (row[columnMapping[lang.UISTR_BIRTHDAY.trim()]]) {
send["birthday"] = row[columnMapping[lang.UISTR_BIRTHDAY.trim()]];
}
if (row[columnMapping[lang.UISTR_START.trim()]]) {
send["starttime"] = row[columnMapping[lang.UISTR_START.trim()]];
}
if (row[columnMapping[lang.UISTR_END.trim()]]) {
send["endtime"] = row[columnMapping[lang.UISTR_END.trim()]];
}
if (row[columnMapping[lang.UISTR_USER_PROFILE.trim()]]) {
send["userprofile"] = row[columnMapping[lang.UISTR_USER_PROFILE.trim()]];
}
// 更新进度条
updateProgressBar(totalRows,currentRow + 1,showname);
// 发送请求
return new Promise((resolve, reject) => {
sendToServer(send)
.then(() => resolve())
.catch(error => reject(error));
});
}
// 检查是否是空行
function isEmptyRow(row) {
return row.every(cell => {
if (typeof cell === 'string') {
return cell.trim() === '';
}
return !cell; // 对于非字符串类型,只要值为 false、null、undefined 或者 0 都视为空
});
}
// 使用 async/await 循环处理每一行数据
(async () => {
for (let row of filteredData) {
try {
await processRow(row);
currentRow++; // 增加当前行计数
} catch (error) {
console.error("Error processing row:", error);
break; // 如果发生错误,停止处理
}
}
})();
}
// 修改 sendToServer 函数以返回 Promise
function sendToServer(send) {
return new Promise((resolve, reject) => {
$.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(send),
beforeSend: function() {
},
success: function(json) {
console.log("done", json);
if (json.ret === "setuserinfo" && json.result === true) {
resolve(); // 成功处理
} else {
reject(new Error("Failed to set user info")); // 处理失败
}
},
error: function(error) {
console.log("error::::", error);
reject(error);
}
});
});
}
function onUploadSuccess() {
const homeChannel = new BroadcastChannel('home_refresh_channel');
homeChannel.postMessage({type: 'refresh_home'});
homeChannel.close();
}
//////////////////////////////////////////
$(document).ready(function() {
$('#uploadModal').on('hidden.bs.modal', function () {
get_userlist();
onUploadSuccess();
});
if(poithide)
{
document.querySelectorAll('.optional-btn').forEach(el => {
el.style.display = 'none';
});
const hideColumns = ['department', 'shift', 'face','password', 'card', 'weekzone','access_times','birthday','fingerprint','palm'];
hideColumns.forEach(col => {
$table.bootstrapTable('hideColumn', col);
});
}
});
</script>
</body>
</html>