Get 2.6.22 ready for release
Get 2.6.22 ready for release
这个提交包含在:
当前提交
30fe639c79
共有 13 个文件被更改,包括 377 次插入 和 76 次删除
|
|
@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
|||
|
|
||||
*/
|
||||
|
||||
$config['migration_version'] = 203;
|
||||
$config['migration_version'] = 204;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -814,4 +814,129 @@ class API extends CI_Controller {
|
|||
$latlng = $this->qra->qra2latlong($qra);
|
||||
return $latlng;
|
||||
}
|
||||
|
||||
/**
|
||||
* API endpoint to get recent QSOs from a public logbook
|
||||
*
|
||||
* @api GET /api/recent_qsos/{public_slug}/{limit}
|
||||
*
|
||||
* @param string public_slug Required. Public slug identifier for the logbook
|
||||
* @param int limit Optional. Number of QSOs to return (default: 10, max: 50)
|
||||
*
|
||||
* @return json Returns JSON array with recent QSO data or error message
|
||||
*
|
||||
* @throws 404 Not Found - Logbook not found or empty logbook
|
||||
* @throws 400 Bad Request - Invalid limit parameter
|
||||
*
|
||||
* @example
|
||||
* Request: GET /api/recent_qsos/my-public-logbook/5
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* "qsos": [
|
||||
* {
|
||||
* "date": "2024-01-15",
|
||||
* "time": "14:30",
|
||||
* "callsign": "W1AW",
|
||||
* "mode": "SSB",
|
||||
* "band": "20M",
|
||||
* "rst_sent": "59",
|
||||
* "rst_rcvd": "59"
|
||||
* }
|
||||
* ],
|
||||
* "count": 1,
|
||||
* "logbook_slug": "my-public-logbook"
|
||||
* }
|
||||
*/
|
||||
function recent_qsos($public_slug = null, $limit = 10) {
|
||||
header('Content-type: application/json');
|
||||
|
||||
if($public_slug == null) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['status' => 'failed', 'reason' => 'missing public_slug parameter']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate and sanitize limit parameter
|
||||
$limit = intval($limit);
|
||||
if ($limit <= 0) {
|
||||
$limit = 10; // default
|
||||
}
|
||||
if ($limit > 50) {
|
||||
$limit = 50; // maximum
|
||||
}
|
||||
|
||||
$this->load->model('logbooks_model');
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
if($this->logbooks_model->public_slug_exists($public_slug)) {
|
||||
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($public_slug);
|
||||
if($logbook_id != false) {
|
||||
// Get associated station locations for mysql queries
|
||||
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
||||
|
||||
if (!$logbooks_locations_array) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['status' => 'failed', 'reason' => 'Empty Logbook']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get recent QSOs using existing method
|
||||
$recent_qsos_query = $this->logbook_model->get_last_qsos($limit, $logbooks_locations_array);
|
||||
|
||||
if ($recent_qsos_query == null) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['status' => 'failed', 'reason' => 'No QSOs found']);
|
||||
return;
|
||||
}
|
||||
|
||||
// Format the data for JSON response
|
||||
$qsos = array();
|
||||
foreach ($recent_qsos_query->result() as $row) {
|
||||
$qso = array(
|
||||
'date' => date('Y-m-d', strtotime($row->COL_TIME_ON)),
|
||||
'time' => date('H:i', strtotime($row->COL_TIME_ON)),
|
||||
'callsign' => strtoupper($row->COL_CALL),
|
||||
'mode' => $row->COL_SUBMODE ? $row->COL_SUBMODE : $row->COL_MODE,
|
||||
'band' => $row->COL_SAT_NAME ? $row->COL_SAT_NAME : $row->COL_BAND,
|
||||
'rst_sent' => $row->COL_RST_SENT,
|
||||
'rst_rcvd' => $row->COL_RST_RCVD
|
||||
);
|
||||
|
||||
// Add optional fields if they exist
|
||||
if ($row->COL_STX_STRING) {
|
||||
$qso['stx_string'] = $row->COL_STX_STRING;
|
||||
}
|
||||
if ($row->COL_SRX_STRING) {
|
||||
$qso['srx_string'] = $row->COL_SRX_STRING;
|
||||
}
|
||||
if ($row->COL_GRIDSQUARE) {
|
||||
$qso['gridsquare'] = $row->COL_GRIDSQUARE;
|
||||
}
|
||||
if ($row->COL_QTH) {
|
||||
$qso['qth'] = $row->COL_QTH;
|
||||
}
|
||||
if ($row->COL_NAME) {
|
||||
$qso['name'] = $row->COL_NAME;
|
||||
}
|
||||
|
||||
$qsos[] = $qso;
|
||||
}
|
||||
|
||||
http_response_code(200);
|
||||
echo json_encode([
|
||||
'qsos' => $qsos,
|
||||
'count' => count($qsos),
|
||||
'logbook_slug' => $public_slug
|
||||
], JSON_PRETTY_PRINT);
|
||||
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['status' => 'failed', 'reason' => $public_slug.' has no associated station locations']);
|
||||
}
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['status' => 'failed', 'reason' => 'logbook not found']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ class Qrz extends CI_Controller {
|
|||
// Return the structured error array here too for consistency
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
$url = 'http://logbook.qrz.com/api'; // Correct URL
|
||||
$url = 'https://logbook.qrz.com/api'; // Correct URL
|
||||
|
||||
$post_data['KEY'] = $qrz_api_key; // Correct parameter
|
||||
$post_data['ACTION'] = 'FETCH'; // Correct parameter
|
||||
|
|
@ -336,11 +336,35 @@ class Qrz extends CI_Controller {
|
|||
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1); // Okay
|
||||
curl_setopt( $ch, CURLOPT_HEADER, 0); // Correct - don't need response headers
|
||||
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true); // Correct - get response as string
|
||||
curl_setopt( $ch, CURLOPT_TIMEOUT, 300); // 5 minute timeout
|
||||
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 30); // 30 second connection timeout
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128000);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
|
||||
$content = curl_exec($ch); // Get raw content
|
||||
$curl_error = curl_error($ch); // Check for cURL errors
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Get HTTP response code
|
||||
curl_close($ch);
|
||||
|
||||
if ($curl_error) { // Check for cURL level errors first
|
||||
$error_message = "QRZ download cURL error: " . $curl_error;
|
||||
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
|
||||
if ($http_code !== 200) {
|
||||
$error_message = "QRZ download HTTP error: HTTP " . $http_code;
|
||||
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
|
||||
if ($content === false || $content === '') { // Check if curl_exec failed or returned empty
|
||||
$error_message = "QRZ download failed: No content received from QRZ.com.";
|
||||
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
|
||||
// Find the start of the ADIF data after "ADIF="
|
||||
$adif_start_pos = strpos($content, 'ADIF=');
|
||||
if ($adif_start_pos !== false) {
|
||||
|
|
@ -388,18 +412,6 @@ class Qrz extends CI_Controller {
|
|||
$content = substr($content, 0, $truncate_pos);
|
||||
}
|
||||
|
||||
if ($curl_error) { // Check for cURL level errors first
|
||||
$error_message = "QRZ download cURL error: " . $curl_error;
|
||||
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
|
||||
if ($content === false || $content === '') { // Check if curl_exec failed or returned empty
|
||||
$error_message = "QRZ download failed: No content received from QRZ.com.";
|
||||
log_message('error', $error_message . ' API Key used: ' . $qrz_api_key);
|
||||
return ['status' => 'error', 'message' => $error_message];
|
||||
}
|
||||
|
||||
// Check for QRZ API specific error messages
|
||||
if (strpos($content, 'STATUS=FAIL') !== false || strpos($content, 'STATUS=AUTH') !== false) {
|
||||
// Extract reason if possible, otherwise use full content
|
||||
|
|
@ -446,7 +458,7 @@ class Qrz extends CI_Controller {
|
|||
$config['qrz_rcvd_mark'] = 'Y';
|
||||
|
||||
ini_set('memory_limit', '-1');
|
||||
set_time_limit(0);
|
||||
set_time_limit(1800); // 30 minutes max execution time instead of unlimited
|
||||
|
||||
$this->load->library('adif_parser');
|
||||
|
||||
|
|
@ -475,8 +487,24 @@ class Qrz extends CI_Controller {
|
|||
$batch_data = [];
|
||||
$batch_size = 500; // Process 500 records at a time
|
||||
$record_count = 0; // Initialize record counter
|
||||
$max_records = 50000; // Safety limit to prevent runaway processing
|
||||
$start_time = time(); // Track processing time
|
||||
$max_processing_time = 1200; // 20 minutes max for processing
|
||||
|
||||
while ($record = $this->adif_parser->get_record()) {
|
||||
$record_count++; // Increment counter for each record read
|
||||
|
||||
// Safety checks to prevent runaway processing
|
||||
if ($record_count > $max_records) {
|
||||
log_message('error', 'QRZ download: Exceeded maximum record limit of ' . $max_records . ' records. Processing stopped.');
|
||||
break;
|
||||
}
|
||||
|
||||
if ((time() - $start_time) > $max_processing_time) {
|
||||
log_message('error', 'QRZ download: Exceeded maximum processing time of ' . $max_processing_time . ' seconds. Processing stopped at record ' . $record_count . '.');
|
||||
break;
|
||||
}
|
||||
|
||||
if ((!(isset($record['app_qrzlog_qsldate']))) || (!(isset($record['qso_date'])))) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -509,6 +537,12 @@ class Qrz extends CI_Controller {
|
|||
if (count($batch_data) >= $batch_size) {
|
||||
$table .= $this->logbook_model->process_qrz_batch($batch_data);
|
||||
$batch_data = []; // Reset batch
|
||||
|
||||
// Log progress every 1000 records to help monitor long-running processes
|
||||
if ($record_count % 1000 == 0) {
|
||||
$elapsed_time = time() - $start_time;
|
||||
log_message('info', 'QRZ download progress: ' . $record_count . ' records processed in ' . $elapsed_time . ' seconds.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -517,6 +551,10 @@ class Qrz extends CI_Controller {
|
|||
$table .= $this->logbook_model->process_qrz_batch($batch_data);
|
||||
}
|
||||
|
||||
// Log successful completion with statistics
|
||||
$processing_time = time() - $start_time;
|
||||
log_message('info', 'QRZ download completed successfully. Processed ' . $record_count . ' records in ' . $processing_time . ' seconds.');
|
||||
|
||||
if ($table != "") {
|
||||
$data['tableheaders'] = $tableheaders;
|
||||
$data['table'] = $table;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,13 @@ class QSO extends CI_Controller {
|
|||
$data['bands'] = $this->bands->get_user_bands_for_qso_entry();
|
||||
$data['user_default_band'] = $this->session->userdata('user_default_band');
|
||||
$data['sat_active'] = array_search("SAT", $this->bands->get_user_bands(), true);
|
||||
|
||||
// Set user's preferred date format
|
||||
if($this->session->userdata('user_date_format')) {
|
||||
$data['user_date_format'] = $this->session->userdata('user_date_format');
|
||||
} else {
|
||||
$data['user_date_format'] = $this->config->item('qso_date_format');
|
||||
}
|
||||
|
||||
$this->load->library('form_validation');
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ class Station extends CI_Controller {
|
|||
$this->load->view('station_profile/edit');
|
||||
$this->load->view('interface_assets/footer');
|
||||
} else {
|
||||
// Get all the posted data from the form and save it to log file
|
||||
|
||||
if ($this->stations->edit() !== false) {
|
||||
// [eQSL default msg] ADD to user options (option_type='eqsl_default_qslmsg'; option_name='key_station_id'; option_key=station_id; option_value=value) //
|
||||
$eqsl_default_qslmsg = xss_clean($this->input->post('eqsl_default_qslmsg', true));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
* Tag Cloudlog as 2.6.22
|
||||
*/
|
||||
|
||||
class Migration_tag_2_6_22 extends CI_Migration {
|
||||
|
||||
public function up()
|
||||
{
|
||||
|
||||
// Tag Cloudlog 2.6.22
|
||||
$this->db->where('option_name', 'version');
|
||||
$this->db->update('options', array('option_value' => '2.6.22'));
|
||||
|
||||
// Trigger Version Info Dialog
|
||||
$this->db->where('option_type', 'version_dialog');
|
||||
$this->db->where('option_name', 'confirmed');
|
||||
$this->db->update('user_options', array('option_value' => 'false'));
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->db->where('option_name', 'version');
|
||||
$this->db->update('options', array('option_value' => '2.6.21'));
|
||||
}
|
||||
}
|
||||
|
|
@ -8,10 +8,11 @@ class Logbook_model extends CI_Model
|
|||
{
|
||||
|
||||
$callsign = str_replace('Ø', '0', $this->input->post('callsign'));
|
||||
// Join date+time
|
||||
$datetime = date("Y-m-d", strtotime($this->input->post('start_date'))) . " " . $this->input->post('start_time');
|
||||
// Join date+time - Parse date according to user's format preference
|
||||
$parsed_date = $this->parse_user_date($this->input->post('start_date'));
|
||||
$datetime = $parsed_date . " " . $this->input->post('start_time');
|
||||
if ($this->input->post('end_time') != null) {
|
||||
$datetime_off = date("Y-m-d", strtotime($this->input->post('start_date'))) . " " . $this->input->post('end_time');
|
||||
$datetime_off = $parsed_date . " " . $this->input->post('end_time');
|
||||
// if time off < time on, and time off is on 00:xx >> add 1 day (concidering start and end are between 23:00 and 00:59) //
|
||||
$_tmp_datetime_off = strtotime($datetime_off);
|
||||
if (($_tmp_datetime_off < strtotime($datetime)) && (substr($this->input->post('end_time'), 0, 2) == "00")) {
|
||||
|
|
@ -4888,7 +4889,7 @@ class Logbook_model extends CI_Model
|
|||
foreach ($batch_data as $record) {
|
||||
$this->db->or_group_start(); // Start group for this record's AND conditions
|
||||
$this->db->where($this->config->item('table_name').'.COL_CALL', $record['call']);
|
||||
$this->db->where($this->config->item('table_name').'.COL_TIME_ON', $record['time_on']);
|
||||
$this->db->like($this->config->item('table_name').'.COL_TIME_ON', $record['time_on'], 'after');
|
||||
$this->db->where($this->config->item('table_name').'.COL_BAND', $record['band']);
|
||||
$this->db->group_end(); // End group for this record's AND conditions
|
||||
}
|
||||
|
|
@ -4901,7 +4902,8 @@ class Logbook_model extends CI_Model
|
|||
// Index DB results for faster lookup
|
||||
$indexed_results = [];
|
||||
foreach ($db_results as $row) {
|
||||
$key = $row['COL_CALL'] . '|' . $row['COL_TIME_ON'] . '|' . $row['COL_BAND'];
|
||||
$time = substr($row['COL_TIME_ON'], 0, 16);
|
||||
$key = $row['COL_CALL'] . '|' . $time . '|' . $row['COL_BAND'];
|
||||
$indexed_results[$key] = $row['COL_PRIMARY_KEY'];
|
||||
}
|
||||
|
||||
|
|
@ -4919,7 +4921,7 @@ class Logbook_model extends CI_Model
|
|||
$update_batch_data[] = [
|
||||
'COL_PRIMARY_KEY' => $primary_key,
|
||||
'COL_QRZCOM_QSO_DOWNLOAD_DATE' => $record['qsl_date'],
|
||||
'COL_QRZCOM_QSO_UPLOAD_STATUS' => $record['qsl_rcvd'] // Should be 'Y' if confirmed
|
||||
'COL_QRZCOM_QSO_DOWNLOAD_STATUS' => $record['qsl_rcvd'] // Should be 'Y' if confirmed
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -4942,6 +4944,42 @@ class Logbook_model extends CI_Model
|
|||
// Step 6: Return Table HTML
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse date from user input according to user's preferred date format
|
||||
* @param string $date_input The date string from user input
|
||||
* @param string $user_format The user's preferred date format (e.g., 'd/m/Y', 'Y-m-d')
|
||||
* @return string Returns date in Y-m-d format for database storage, or original input if parsing fails
|
||||
*/
|
||||
private function parse_user_date($date_input, $user_format = null) {
|
||||
if (empty($date_input)) {
|
||||
return $date_input;
|
||||
}
|
||||
|
||||
// If no user format provided, try to get it from session or config
|
||||
if ($user_format === null) {
|
||||
if ($this->session->userdata('user_date_format')) {
|
||||
$user_format = $this->session->userdata('user_date_format');
|
||||
} else {
|
||||
$user_format = $this->config->item('qso_date_format');
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse with the user's format first
|
||||
$date = DateTime::createFromFormat($user_format, $date_input);
|
||||
if ($date !== false) {
|
||||
return $date->format('Y-m-d');
|
||||
}
|
||||
|
||||
// Fallback to strtotime for formats it can handle (mostly Y-m-d, m/d/Y, etc.)
|
||||
$timestamp = strtotime($date_input);
|
||||
if ($timestamp !== false) {
|
||||
return date('Y-m-d', $timestamp);
|
||||
}
|
||||
|
||||
// If all parsing fails, return the original input and let the database handle it
|
||||
return $date_input;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to validate ADIF date format
|
||||
|
|
@ -4952,4 +4990,4 @@ function validateADIFDate($date, $format = 'Ymd')
|
|||
{
|
||||
$d = DateTime::createFromFormat($format, $date);
|
||||
return $d && $d->format($format) == $date;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ class Stations extends CI_Model {
|
|||
|
||||
// Check if the state is Canada and get the correct state
|
||||
if ($this->input->post('dxcc') == 1 && $this->input->post('station_ca_state') !="") {
|
||||
$state = $this->input->post('station_ca_state');
|
||||
$state = xss_clean($this->input->post('station_ca_state', true));
|
||||
} else {
|
||||
$state = $this->input->post('station_state');
|
||||
$state = xss_clean($this->input->post('station_state', true));
|
||||
}
|
||||
|
||||
// Create data array with field values
|
||||
|
|
@ -131,9 +131,9 @@ class Stations extends CI_Model {
|
|||
|
||||
// Check if the state is Canada and get the correct state
|
||||
if ($this->input->post('dxcc') == 1 && $this->input->post('station_ca_state') !="") {
|
||||
$state = $this->input->post('station_ca_state');
|
||||
$state = xss_clean($this->input->post('station_ca_state', true));
|
||||
} else {
|
||||
$state = $this->input->post('station_state');
|
||||
$state = xss_clean($this->input->post('station_state', true));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
|
|
|
|||
|
|
@ -102,48 +102,48 @@
|
|||
<div class="row">
|
||||
<div class="mb-3 col-md-3">
|
||||
<label for="callsign"><?php echo lang('gen_hamradio_callsign'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" id="callsign" name="callsign" required pattern="\S+" title="Whitespace is not allowed">
|
||||
<input type="text" class="form-control form-control-sm" id="callsign" name="callsign" required pattern="\S+" title="Whitespace is not allowed" tabindex="1">
|
||||
<small id="callsign_info" class="badge text-bg-danger"></small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-md-1">
|
||||
<label for="rst_sent"><?php echo lang('gen_hamradio_rsts'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" name="rst_sent" id="rst_sent" value="59">
|
||||
<input type="text" class="form-control form-control-sm" name="rst_sent" id="rst_sent" value="59" tabindex="2">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-1 serials">
|
||||
<label for="exch_serial_s"><?php echo lang('contesting_exchange_serial_s'); ?></label>
|
||||
<input type="number" class="form-control form-control-sm" name="exch_serial_s" id="exch_serial_s" value="">
|
||||
<input type="number" class="form-control form-control-sm" name="exch_serial_s" id="exch_serial_s" value="" tabindex="3">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-1 exchanges">
|
||||
<label for="exch_sent"><?php echo lang('gen_hamradio_exchange_sent_short'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" name="exch_sent" id="exch_sent" value="">
|
||||
<input type="text" class="form-control form-control-sm" name="exch_sent" id="exch_sent" value="" tabindex="3">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-2 gridsquares">
|
||||
<label for="exch_gridsquare_s"><?php echo lang('contesting_exchange_gridsquare_s'); ?></label>
|
||||
<input disabled type="text" class="form-control form-control-sm" name="exch_gridsquare_s" id="exch_gridsquare_s" value="<?php echo $my_gridsquare;?>">
|
||||
<input disabled type="text" class="form-control form-control-sm" name="exch_gridsquare_s" id="exch_gridsquare_s" value="<?php echo $my_gridsquare;?>" tabindex="-1">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-md-1">
|
||||
<label for="rst_rcvd"><?php echo lang('gen_hamradio_rstr'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" name="rst_rcvd" id="rst_rcvd" value="59">
|
||||
<input type="text" class="form-control form-control-sm" name="rst_rcvd" id="rst_rcvd" value="59" tabindex="4">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-1 serialr">
|
||||
<label for="exch_serial_r"><?php echo lang('contesting_exchange_serial_r'); ?></label>
|
||||
<input type="number" class="form-control form-control-sm" name="exch_serial_r" id="exch_serial_r" value="">
|
||||
<input type="number" class="form-control form-control-sm" name="exch_serial_r" id="exch_serial_r" value="" tabindex="5">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-1 exchanger">
|
||||
<label for="exch_rcvd"><?php echo lang('gen_hamradio_exchange_rcvd_short'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" name="exch_rcvd" id="exch_rcvd" value="">
|
||||
<input type="text" class="form-control form-control-sm" name="exch_rcvd" id="exch_rcvd" value="" tabindex="5">
|
||||
</div>
|
||||
|
||||
<div style="display:none" class="mb-3 col-md-2 gridsquarer">
|
||||
<label for="exch_gridsquare_r"><?php echo lang('contesting_exchange_gridsquare_r'); ?></label>
|
||||
<input type="text" class="form-control form-control-sm" name="locator" id="exch_gridsquare_r" value="">
|
||||
<input type="text" class="form-control form-control-sm" name="locator" id="exch_gridsquare_r" value="" maxlength="8" tabindex="6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ if ($qsos->result() != NULL) {
|
|||
|
||||
foreach ($qsos->result() as $qsl) {
|
||||
echo '<tr id="qslprint_'.$qsl->COL_PRIMARY_KEY.'">';
|
||||
echo '<td style=\'text-align: center\'><div class="form-check"><input class="form-check-input" type="checkbox" /></div></td>';
|
||||
echo '<td style=\'text-align: center\'><div class="form-check"><input class="form-check-input qso-checkbox" type="checkbox" value="'.$qsl->COL_PRIMARY_KEY.'" /></div></td>';
|
||||
?><td style='text-align: center'><span class="qso_call"><a id="edit_qso" href="javascript:displayQso(<?php echo $qsl->COL_PRIMARY_KEY; ?>);"><?php echo str_replace("0","Ø",strtoupper($qsl->COL_CALL)); ?></a><a target="_blank" href="https://www.qrz.com/db/<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/qrz.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on QRZ.com"></a> <a target="_blank" href="https://www.hamqth.com/<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/hamqth.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on HamQTH"></a> <a target="_blank" href="http://www.eqsl.cc/Member.cfm?<?php echo strtoupper($qsl->COL_CALL); ?>"><img width="16" height="16" src="<?php echo base_url(); ?>images/icons/eqsl.png" alt="Lookup <?php echo strtoupper($qsl->COL_CALL); ?> on eQSL.cc"></a></td><?php
|
||||
echo '<td style=\'text-align: center\'>'; $timestamp = strtotime($qsl->COL_TIME_ON); echo date($custom_date_format, $timestamp); echo '</td>';
|
||||
echo '<td style=\'text-align: center\'>'; $timestamp = strtotime($qsl->COL_TIME_ON); echo date('H:i', $timestamp); echo '</td>';
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@
|
|||
<input type="text" class="form-control form-control-sm input_date" name="start_date" id="start_date" value="<?php if (($this->session->userdata('start_date') != NULL && ((time() - $this->session->userdata('time_stamp')) < 24 * 60 * 60))) {
|
||||
echo $this->session->userdata('start_date');
|
||||
} else {
|
||||
echo date('d-m-Y');
|
||||
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required pattern="[0-3][0-9]-[0-1][0-9]-[0-9]{4}">
|
||||
echo date($user_date_format);
|
||||
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-md-3">
|
||||
|
|
@ -102,7 +102,7 @@
|
|||
<?php if ($_GET['manual'] == 0) { ?>
|
||||
<input class="input_start_time" type="hidden" id="start_time" name="start_time" value="<?php echo date('H:i:s'); ?>" />
|
||||
<input class="input_end_time" type="hidden" id="end_time" name="end_time" value="<?php echo date('H:i:s'); ?>" />
|
||||
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date('d-m-Y'); ?>" />
|
||||
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date($user_date_format); ?>" />
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
|
|
@ -113,8 +113,8 @@
|
|||
<input type="text" class="form-control form-control-sm input_date" name="start_date" id="start_date" value="<?php if (($this->session->userdata('start_date') != NULL && ((time() - $this->session->userdata('time_stamp')) < 24 * 60 * 60))) {
|
||||
echo $this->session->userdata('start_date');
|
||||
} else {
|
||||
echo date('d-m-Y');
|
||||
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required pattern="[0-3][0-9]-[0-1][0-9]-[0-9]{4}">
|
||||
echo date($user_date_format);
|
||||
} ?>" <?php echo ($_GET['manual'] == 0 ? "disabled" : ""); ?> required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-md-6">
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
|
||||
<?php if ($_GET['manual'] == 0) { ?>
|
||||
<input class="input_start_time" type="hidden" id="start_time" name="start_time" value="<?php echo date('H:i:s'); ?>" />
|
||||
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date('d-m-Y'); ?>" />
|
||||
<input class="input_date" type="hidden" id="start_date" name="start_date" value="<?php echo date($user_date_format); ?>" />
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
|
|
|||
|
|
@ -634,5 +634,7 @@ if ($('.table-responsive .dropdown-toggle').length>0) {
|
|||
}
|
||||
|
||||
function getDataTablesLanguageUrl() {
|
||||
return base_url + "/assets/json/datatables_languages/" + lang_datatables_language + ".json";
|
||||
// Check if lang_datatables_language is defined, otherwise use a default
|
||||
var language = (typeof lang_datatables_language !== 'undefined') ? lang_datatables_language : 'english';
|
||||
return base_url + "/assets/json/datatables_languages/" + language + ".json";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,20 +77,93 @@ $(".station_id").change(function(){
|
|||
type: 'post',
|
||||
data: {'station_id': station_id},
|
||||
success: function(html) {
|
||||
$('.resulttable').empty();
|
||||
$('.resulttable').append(html);
|
||||
try {
|
||||
// Destroy existing DataTable if it exists
|
||||
if ($.fn.DataTable.isDataTable('#qslprint_table')) {
|
||||
$('#qslprint_table').DataTable().destroy();
|
||||
}
|
||||
$('.resulttable').empty();
|
||||
$('.resulttable').append(html);
|
||||
// Reinitialize DataTable
|
||||
$('#qslprint_table').DataTable({
|
||||
"stateSave": true,
|
||||
paging: false,
|
||||
"language": {
|
||||
url: getDataTablesLanguageUrl(),
|
||||
},
|
||||
"drawCallback": function(settings) {
|
||||
// Re-attach event handlers after DataTable draws/redraws
|
||||
attachCheckboxEvents();
|
||||
}
|
||||
});
|
||||
// Attach checkbox events immediately after initialization
|
||||
attachCheckboxEvents();
|
||||
} catch (error) {
|
||||
console.error('Error reinitializing DataTable:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#qslprint_table').DataTable({
|
||||
"stateSave": true,
|
||||
paging: false,
|
||||
"language": {
|
||||
url: getDataTablesLanguageUrl(),
|
||||
// Initialize DataTable only if it exists and isn't already initialized
|
||||
$(document).ready(function() {
|
||||
try {
|
||||
if ($('#qslprint_table').length && !$.fn.DataTable.isDataTable('#qslprint_table')) {
|
||||
$('#qslprint_table').DataTable({
|
||||
"stateSave": true,
|
||||
paging: false,
|
||||
"language": {
|
||||
url: getDataTablesLanguageUrl(),
|
||||
},
|
||||
"drawCallback": function(settings) {
|
||||
// Re-attach event handlers after DataTable draws/redraws
|
||||
attachCheckboxEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
// Initial attachment of events
|
||||
attachCheckboxEvents();
|
||||
} catch (error) {
|
||||
console.error('Error initializing DataTable:', error);
|
||||
// Still try to attach checkbox events even if DataTable fails
|
||||
attachCheckboxEvents();
|
||||
}
|
||||
});
|
||||
|
||||
// Function to attach checkbox events
|
||||
function attachCheckboxEvents() {
|
||||
// Remove any existing handlers to prevent duplicates
|
||||
$('#checkBoxAll').off('change.qslprint');
|
||||
$('.qso-checkbox').off('click.qslprint');
|
||||
|
||||
// Attach select all functionality
|
||||
$('#checkBoxAll').on('change.qslprint', function (event) {
|
||||
var isChecked = this.checked;
|
||||
$('#qslprint_table tbody tr .qso-checkbox').each(function (i) {
|
||||
$(this).prop("checked", isChecked);
|
||||
if (isChecked) {
|
||||
$(this).closest('tr').addClass('activeRow');
|
||||
} else {
|
||||
$(this).closest('tr').removeClass('activeRow');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Attach individual checkbox functionality
|
||||
$(document).on('click.qslprint', '.qso-checkbox', function() {
|
||||
if ($(this).is(":checked")) {
|
||||
$(this).closest('tr').addClass('activeRow');
|
||||
} else {
|
||||
$(this).closest('tr').removeClass('activeRow');
|
||||
}
|
||||
|
||||
// Update the "select all" checkbox state
|
||||
var totalCheckboxes = $('#qslprint_table tbody tr .qso-checkbox').length;
|
||||
var checkedCheckboxes = $('#qslprint_table tbody tr .qso-checkbox:checked').length;
|
||||
$('#checkBoxAll').prop('checked', totalCheckboxes === checkedCheckboxes);
|
||||
});
|
||||
}
|
||||
|
||||
function showOqrs(id) {
|
||||
$.ajax({
|
||||
url: base_url + 'index.php/qslprint/show_oqrs',
|
||||
|
|
@ -135,30 +208,8 @@ function mark_qsl_sent(id, method) {
|
|||
});
|
||||
}
|
||||
|
||||
$('#checkBoxAll').change(function (event) {
|
||||
if (this.checked) {
|
||||
$('.qslprint tbody tr').each(function (i) {
|
||||
$(this).closest('tr').addClass('activeRow');
|
||||
$(this).closest('tr').find("input[type=checkbox]").prop("checked", true);
|
||||
});
|
||||
} else {
|
||||
$('.qslprint tbody tr').each(function (i) {
|
||||
$(this).closest('tr').removeClass('activeRow');
|
||||
$(this).closest('tr').find("input[type=checkbox]").prop("checked", false);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('.qslprint').on('click', 'input[type="checkbox"]', function() {
|
||||
if ($(this).is(":checked")) {
|
||||
$(this).closest('tr').addClass('activeRow');
|
||||
} else {
|
||||
$(this).closest('tr').removeClass('activeRow');
|
||||
}
|
||||
});
|
||||
|
||||
function markSelectedQsos() {
|
||||
var elements = $('.qslprint tbody input:checked');
|
||||
var elements = $('.qso-checkbox:checked');
|
||||
var nElements = elements.length;
|
||||
if (nElements == 0) {
|
||||
return;
|
||||
|
|
@ -179,18 +230,22 @@ function markSelectedQsos() {
|
|||
'method' : ''
|
||||
},
|
||||
success: function(data) {
|
||||
if (data !== []) {
|
||||
if (data && data.length > 0) {
|
||||
$.each(data, function(k, v) {
|
||||
$("#qslprint_"+this.qsoID).remove();
|
||||
});
|
||||
}
|
||||
$('.markallprinted').prop("disabled", false);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('Error marking QSOs as printed:', error);
|
||||
$('.markallprinted').prop("disabled", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeSelectedQsos() {
|
||||
var elements = $('.qslprint tbody input:checked');
|
||||
var elements = $('.qso-checkbox:checked');
|
||||
var nElements = elements.length;
|
||||
if (nElements == 0) {
|
||||
return;
|
||||
|
|
@ -213,12 +268,16 @@ function removeSelectedQsos() {
|
|||
'method' : ''
|
||||
},
|
||||
success: function(data) {
|
||||
if (data !== []) {
|
||||
if (data && data.length > 0) {
|
||||
$.each(data, function(k, v) {
|
||||
$("#qslprint_"+this.qsoID).remove();
|
||||
});
|
||||
}
|
||||
$('.removeall').prop("disabled", false);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('Error removing QSOs from queue:', error);
|
||||
$('.removeall').prop("disabled", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
正在加载…
在新工单中引用