Compare commits
10 Commits
f1908d1fc4
...
49499a88b3
Author | SHA1 | Date | |
---|---|---|---|
49499a88b3 | |||
3dc2b3d432 | |||
61b2edca36 | |||
db54dc28c0 | |||
a72344e7cc | |||
3ce29dcd2b | |||
e059757766 | |||
b2de036c61 | |||
8a12c47a1f | |||
3ead5ce0b6 |
35
Cargo.lock
generated
35
Cargo.lock
generated
@ -286,6 +286,15 @@ dependencies = [
|
|||||||
"cmake",
|
"cmake",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fltk-theme"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3539d27a815514b56af2afa6b8e7c6d6b9274a103239487d5a60daa6340a4868"
|
||||||
|
dependencies = [
|
||||||
|
"fltk",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fluid-parser"
|
name = "fluid-parser"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
@ -376,6 +385,12 @@ dependencies = [
|
|||||||
"mach2",
|
"mach2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.69"
|
||||||
@ -769,6 +784,12 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -816,6 +837,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.120"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serialport"
|
name = "serialport"
|
||||||
version = "4.4.0"
|
version = "4.4.0"
|
||||||
@ -1104,11 +1136,14 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"fl2rust",
|
"fl2rust",
|
||||||
"fltk",
|
"fltk",
|
||||||
|
"fltk-theme",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
"log",
|
"log",
|
||||||
"once_cell 0.1.8",
|
"once_cell 0.1.8",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"serialport",
|
"serialport",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "^1.0.86"
|
anyhow = "^1.0.86"
|
||||||
fltk = { version = "^1.4", features = ["fltk-bundled"] }
|
fltk = { version = "^1.4", features = ["fltk-bundled"] }
|
||||||
|
fltk-theme = "0.7.2"
|
||||||
calamine = "0.25.0"
|
calamine = "0.25.0"
|
||||||
serialport = "4.4.0"
|
serialport = "4.4.0"
|
||||||
rusqlite = "0.25.4"
|
rusqlite = "0.25.4"
|
||||||
@ -16,6 +17,13 @@ chrono = "0.4.38"
|
|||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
once_cell = "0.1.8"
|
once_cell = "0.1.8"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
serde= { version = "1.0.203", features = ["derive"] }
|
||||||
|
serde_json="1.0.120"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
fl2rust = "0.5.19"
|
fl2rust = "0.5.19"
|
||||||
|
|
||||||
|
[package.metadata.windows]
|
||||||
|
# For windows subsystem
|
||||||
|
link-args = ["/SUBSYSTEM:windows", "/ENTRY:mainCRTStartup"]
|
||||||
|
subsystem = "windows"
|
BIN
IMEI_SN_INDEX.xlsx
Normal file
BIN
IMEI_SN_INDEX.xlsx
Normal file
Binary file not shown.
@ -1,10 +1,13 @@
|
|||||||
use fltk::{prelude::*, window::Window, *};
|
use fltk::{*};
|
||||||
use crate::services::ui_service::UiService;
|
use crate::services::ui_service::UiService;
|
||||||
|
use fltk_theme::{WidgetTheme, ThemeType};
|
||||||
mod services;
|
mod services;
|
||||||
mod models;
|
mod models;
|
||||||
mod ui;
|
mod ui;
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = app::App::default();
|
let app = app::App::default();
|
||||||
|
let widget_theme = WidgetTheme::new(ThemeType::Metro);
|
||||||
|
widget_theme.apply();
|
||||||
let mut ui_service = UiService::new();
|
let mut ui_service = UiService::new();
|
||||||
ui_service.init_components();
|
ui_service.init_components();
|
||||||
app.run().unwrap();
|
app.run().unwrap();
|
||||||
|
18
src/models/config_model.rs
Normal file
18
src/models/config_model.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub(crate) struct ConfigModel{
|
||||||
|
pub current_line: usize,
|
||||||
|
pub excel_path: String,
|
||||||
|
pub last_com: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ConfigModel {
|
||||||
|
fn default() -> Self {
|
||||||
|
ConfigModel {
|
||||||
|
current_line: 0,
|
||||||
|
excel_path: "".to_string(),
|
||||||
|
last_com: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub(crate) mod work_model;
|
pub(crate) mod work_model;
|
||||||
|
pub(crate) mod config_model;
|
21
src/services/config_service.rs
Normal file
21
src/services/config_service.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::models::config_model::ConfigModel;
|
||||||
|
|
||||||
|
pub(crate) struct ConfigService;
|
||||||
|
|
||||||
|
impl ConfigService {
|
||||||
|
pub fn save_config(model: ConfigModel) ->Result<()> {
|
||||||
|
let json = serde_json::to_string(&model)?;
|
||||||
|
fs::write("config.json", json)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config() -> Result<ConfigModel> {
|
||||||
|
let json = fs::read_to_string("config.json")?;
|
||||||
|
let model: ConfigModel = serde_json::from_str(&json)?;
|
||||||
|
Ok(model)
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,10 @@
|
|||||||
use std::fs::File;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use calamine::{Reader, open_workbook, Xlsx, Data, DataType};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use calamine::{Data, DataType, open_workbook, Reader, Xlsx};
|
||||||
|
|
||||||
use crate::models::work_model::WorkModel;
|
use crate::models::work_model::WorkModel;
|
||||||
|
|
||||||
pub(crate) struct ExcelService {
|
pub(crate) struct ExcelService {
|
||||||
current_line: usize,
|
current_line: usize,
|
||||||
work_book: Xlsx<BufReader<File>>,
|
|
||||||
sheet: calamine::Range<Data>,
|
sheet: calamine::Range<Data>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,6 @@ impl ExcelService {
|
|||||||
};
|
};
|
||||||
let mut service = ExcelService {
|
let mut service = ExcelService {
|
||||||
current_line: 0,
|
current_line: 0,
|
||||||
work_book,
|
|
||||||
sheet,
|
sheet,
|
||||||
};
|
};
|
||||||
service.current_line = service.find_first_useful_line();
|
service.current_line = service.find_first_useful_line();
|
||||||
@ -52,6 +49,15 @@ impl ExcelService {
|
|||||||
current_line
|
current_line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_current_line(&mut self, line: usize)->Result<(), String>{
|
||||||
|
self.current_line = line;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn roll_back(&mut self){
|
||||||
|
self.current_line -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_next_work_model(&mut self) -> Result<WorkModel, String> {
|
pub fn get_next_work_model(&mut self) -> Result<WorkModel, String> {
|
||||||
let mut work_model = WorkModel::default();
|
let mut work_model = WorkModel::default();
|
||||||
if let Some(imei) = self.sheet.get((self.current_line, 0)) {
|
if let Some(imei) = self.sheet.get((self.current_line, 0)) {
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use chrono::Local;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use log::{Level, Metadata, Record, SetLoggerError};
|
||||||
|
|
||||||
|
type LogCallback = Box<dyn Fn(&str) + Send + Sync>;
|
||||||
|
|
||||||
|
pub struct FltkLogger {
|
||||||
|
callback: Arc<Mutex<Option<LogCallback>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FltkLogger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FltkLogger {
|
||||||
|
callback: Arc::new(Mutex::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_callback<F>(&self, callback: F)
|
||||||
|
where
|
||||||
|
F: Fn(&str) + 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
let mut cb = self.callback.lock().unwrap();
|
||||||
|
*cb = Some(Box::new(callback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl log::Log for FltkLogger {
|
||||||
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||||
|
metadata.level() <= Level::Info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &Record) {
|
||||||
|
if self.enabled(record.metadata()) {
|
||||||
|
if let Some(callback) = self.callback.lock().unwrap().as_ref() {
|
||||||
|
callback(&format!("{}: {} - {}\r\n",Local::now().format("%Y-%m-%d %H:%M:%S"), record.level(), record.args()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref LOGGER: FltkLogger = FltkLogger::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_logger() -> Result<(), SetLoggerError> {
|
||||||
|
log::set_logger(&*LOGGER)
|
||||||
|
.map(|()| log::set_max_level(log::LevelFilter::Info))
|
||||||
|
}
|
@ -3,4 +3,5 @@ pub(crate) mod sqlite_service;
|
|||||||
pub(crate) mod excel_service;
|
pub(crate) mod excel_service;
|
||||||
pub(crate) mod ui_service;
|
pub(crate) mod ui_service;
|
||||||
pub(crate) mod work_service;
|
pub(crate) mod work_service;
|
||||||
pub(crate) mod log_service;
|
pub(crate) mod log_service;
|
||||||
|
pub(crate) mod config_service;
|
@ -1,21 +1,23 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use serialport::*;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use serialport::*;
|
||||||
|
|
||||||
pub struct SerialService {
|
pub struct SerialService {
|
||||||
port: Box<dyn SerialPort>,
|
port: Box<dyn SerialPort>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl SerialService {
|
impl SerialService {
|
||||||
pub fn new(port_name: &str) -> Result<Box<Self>> {
|
pub fn new(port_name: &str) -> Result<Box<Self>> {
|
||||||
let port = serialport::new(port_name, 115_200)
|
let port = new(port_name, 115_200)
|
||||||
.timeout(Duration::from_millis(200))
|
.timeout(Duration::from_millis(200))
|
||||||
.open()?;
|
.open()?;
|
||||||
Ok(Box::new(SerialService { port }))
|
Ok(Box::new(SerialService { port }))
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_ports() -> Result<Vec<String>> {
|
pub fn get_ports() -> Result<Vec<String>> {
|
||||||
let portinfos = serialport::available_ports()?;
|
let portinfos = serialport::available_ports()?;
|
||||||
let mut portnames: Vec<String> = Vec::new();
|
let mut portnames: Vec<String> = Vec::new();
|
||||||
@ -54,6 +56,10 @@ impl SerialService {
|
|||||||
Err(err) => Err(err)
|
Err(err) => Err(err)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn close_serial(&mut self)->Result<()>{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crate::models::work_model::*;
|
|
||||||
use rusqlite::{Connection};
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
use rusqlite::Connection;
|
||||||
|
|
||||||
|
use crate::models::work_model::*;
|
||||||
|
|
||||||
pub(crate) struct SqliteService {
|
pub(crate) struct SqliteService {
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
@ -19,7 +20,9 @@ impl Default for SqliteService {
|
|||||||
impl SqliteService {
|
impl SqliteService {
|
||||||
pub fn new(conn_str: String) -> Result<Self> {
|
pub fn new(conn_str: String) -> Result<Self> {
|
||||||
let conn = Connection::open(conn_str)?;
|
let conn = Connection::open(conn_str)?;
|
||||||
Ok(Self { conn })
|
let this = Self { conn };
|
||||||
|
this.create_table()?;
|
||||||
|
return Ok(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_table(&self) -> Result<()> {
|
pub fn create_table(&self) -> Result<()> {
|
||||||
@ -45,20 +48,14 @@ impl SqliteService {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_sn(&self, sn: &str) -> Result<bool> {
|
pub fn check_sn_has_insert(&self, sn: &str) -> Result<bool> {
|
||||||
let mut stmt = self.conn.prepare("SELECT sn FROM write_results WHERE sn = ?1")?;
|
let mut stmt = self.conn.prepare("SELECT sn FROM write_results WHERE sn = ?1")?;
|
||||||
let mut rows = stmt.query(&[&sn])?;
|
let mut rows = stmt.query(&[&sn])?;
|
||||||
Ok(rows.next()?.is_some())
|
Ok(rows.next()?.is_some())
|
||||||
}
|
}
|
||||||
pub fn check_imei(&self, imei: &str) -> Result<bool> {
|
pub fn check_imei_has_insert(&self, imei: &str) -> Result<bool> {
|
||||||
let mut stmt = self.conn.prepare("SELECT sn FROM write_results WHERE sn = ?1")?;
|
let mut stmt = self.conn.prepare("SELECT imei FROM write_results WHERE imei = ?1")?;
|
||||||
let mut rows = stmt.query(&[&imei])?;
|
let mut rows = stmt.query(&[&imei])?;
|
||||||
Ok(rows.next()?.is_some())
|
Ok(rows.next()?.is_some())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn create_sql_service_test() {
|
|
||||||
let service = SqliteService::default();
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use fltk::prelude::{InputExt, WidgetExt};
|
use std::sync::{Arc, Mutex};
|
||||||
use crate::models::work_model::WorkModel;
|
use fltk::prelude::{DisplayExt, InputExt, MenuExt, WidgetExt};
|
||||||
use crate::services::excel_service::ExcelService;
|
use fltk::text::TextBuffer;
|
||||||
use crate::services::serial_service::SerialService;
|
|
||||||
|
use crate::services::log_service::LOGGER;
|
||||||
use crate::services::work_service::WorkService;
|
use crate::services::work_service::WorkService;
|
||||||
use crate::ui::main_ui;
|
use crate::ui::main_ui;
|
||||||
use crate::ui::main_ui::*;
|
use crate::ui::main_ui::*;
|
||||||
@ -11,27 +14,106 @@ use crate::ui::main_ui::*;
|
|||||||
pub(crate) struct UiService {
|
pub(crate) struct UiService {
|
||||||
ui: Rc<RefCell<UserInterface>>,
|
ui: Rc<RefCell<UserInterface>>,
|
||||||
work_service: Rc<RefCell<WorkService>>,
|
work_service: Rc<RefCell<WorkService>>,
|
||||||
current_com: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiService {
|
impl UiService {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
|
// Create the Rc<RefCell<>> instances
|
||||||
let ui = Rc::new(RefCell::new(main_ui::UserInterface::make_window()));
|
let ui = Rc::new(RefCell::new(main_ui::UserInterface::make_window()));
|
||||||
UiService { ui, work_service: Rc::new(RefCell::new(WorkService::new())), current_com: "".to_string() }
|
let work_service_rc = Rc::new(RefCell::new(WorkService::new()));
|
||||||
|
|
||||||
|
// Clone the Rc<RefCell<>> to avoid moving them
|
||||||
|
let work_service_clone = Rc::clone(&work_service_rc);
|
||||||
|
let current_com;
|
||||||
|
let should_current_line;
|
||||||
|
let comports = WorkService::get_port_names();
|
||||||
|
for com in comports {
|
||||||
|
ui.borrow_mut().com_choice.add_choice(&com);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let work_service = work_service_clone.borrow_mut();
|
||||||
|
current_com = work_service.config_model.last_com.clone();
|
||||||
|
should_current_line = work_service.config_model.current_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Path::exists(work_service_rc.borrow().config_model.excel_path.as_ref()) {
|
||||||
|
ui.borrow_mut().excel_file_textbox.set_value(&work_service_rc.borrow().config_model.excel_path);
|
||||||
|
ui.borrow_mut().current_line_textbox.set_value(&work_service_rc.borrow().config_model.current_line.to_string());
|
||||||
|
let index = ui.borrow().com_choice.find_index(¤t_com);
|
||||||
|
ui.borrow_mut().com_choice.set_value(index);
|
||||||
|
|
||||||
|
work_service_rc.borrow_mut().excel_service.as_mut().unwrap().set_current_line(should_current_line).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let ui_service = UiService {
|
||||||
|
ui,
|
||||||
|
work_service: work_service_rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
ui_service
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init_components(&mut self) {
|
pub(crate) fn init_components(&mut self) {
|
||||||
self.init_excel();
|
self.init_excel();
|
||||||
self.init_start_btn();
|
self.init_start_btn();
|
||||||
|
self.init_set_line_btn();
|
||||||
|
self.init_log();
|
||||||
|
self.init_refresh_com_button();
|
||||||
|
self.init_exit_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_start_btn(&mut self) {
|
fn init_refresh_com_button(&mut self) {
|
||||||
let ui_rc = Rc::clone(&self.ui);
|
let ui_rc = Rc::clone(&self.ui);
|
||||||
let ui_rc_clone = Rc::clone(&ui_rc);
|
self.ui.borrow_mut().refresh_com_btn.set_callback(move |_| {
|
||||||
|
let comports = WorkService::get_port_names();
|
||||||
|
let mut ui = ui_rc.borrow_mut();
|
||||||
|
ui.com_choice.clear();
|
||||||
|
for com in comports {
|
||||||
|
ui.com_choice.add_choice(&com);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn init_exit_callback(&mut self) {
|
||||||
let work_service_rc = Rc::clone(&self.work_service);
|
let work_service_rc = Rc::clone(&self.work_service);
|
||||||
ui_rc.borrow_mut().start_btn.set_callback(move |_| {
|
self.ui.borrow_mut().main_window.set_callback(move |_| {
|
||||||
|
let work_service = work_service_rc.borrow_mut();
|
||||||
|
work_service.save_config();
|
||||||
|
process::exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_set_line_btn(&mut self) {
|
||||||
|
let ui_rc = Rc::clone(&self.ui);
|
||||||
|
let work_service_rc = Rc::clone(&self.work_service);
|
||||||
|
self.ui.borrow_mut().set_lines_btn.set_callback(move |_| {
|
||||||
|
let ui_clone = ui_rc.clone();
|
||||||
|
let mut set_dialog = UserInterface1::make_set_line_window();
|
||||||
|
let work_service_rc_clone = work_service_rc.clone();
|
||||||
|
set_dialog.ok_btn.set_callback(move |_| {
|
||||||
|
if let Ok(line) = set_dialog.line_textbox.value().parse::<usize>() {
|
||||||
|
match work_service_rc_clone.borrow_mut().set_current_line(line) {
|
||||||
|
Ok(_) => {
|
||||||
|
ui_clone.borrow_mut().current_line_textbox.set_value(&line.to_string());
|
||||||
|
}
|
||||||
|
Err(msg) => fltk::dialog::message_default(&msg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fltk::dialog::message_default(&"Only Support Number")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_start_btn(&mut self) {
|
||||||
|
let ui_rc_clone = Rc::clone(&self.ui);
|
||||||
|
let work_service_rc = Rc::clone(&self.work_service);
|
||||||
|
self.ui.borrow_mut().start_btn.set_callback(move |_| {
|
||||||
let mut ui = ui_rc_clone.borrow_mut();
|
let mut ui = ui_rc_clone.borrow_mut();
|
||||||
let mut work_service = work_service_rc.borrow_mut();
|
let mut work_service = work_service_rc.borrow_mut();
|
||||||
|
if let Some(mut buffer) = ui.log_content.buffer() {
|
||||||
|
buffer.set_text("");
|
||||||
|
}
|
||||||
match work_service.excel_service {
|
match work_service.excel_service {
|
||||||
None => {
|
None => {
|
||||||
fltk::dialog::message_default("Please Select Excel File First;");
|
fltk::dialog::message_default("Please Select Excel File First;");
|
||||||
@ -39,44 +121,54 @@ impl UiService {
|
|||||||
}
|
}
|
||||||
Some(_) => {}
|
Some(_) => {}
|
||||||
}
|
}
|
||||||
let selected_com = ui.com_textbox.value();
|
let selected_com = ui.com_choice.choice().unwrap();
|
||||||
if let Err(msg) = work_service.init_serial_service(selected_com) {
|
if let Err(msg) = work_service.init_serial_service(selected_com) {
|
||||||
fltk::dialog::message_default(&msg);
|
fltk::dialog::message_default(&msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(mut model) = work_service.get_next_work_model() {
|
if let Some(model) = work_service.get_next_work_model() {
|
||||||
ui.current_write_model.set_value(&format!("{}: {}_{}", &model.line_number, &model.imei, &model.sn));
|
ui.current_write_model.set_value(&format!("{}: {}_{}", &model.line_number, &model.imei, &model.sn));
|
||||||
match work_service.write_and_check(model) {
|
match work_service.write_and_check(model) {
|
||||||
Ok(_) => {}
|
Ok(_) => {
|
||||||
Err(msg) => { fltk::dialog::message_default(&msg) }
|
let current_line = &work_service.get_current_line().to_string();
|
||||||
|
ui.current_line_textbox.set_value(current_line);
|
||||||
|
}
|
||||||
|
Err(msg) => {
|
||||||
|
work_service.roll_back();
|
||||||
|
fltk::dialog::message_default(&msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_log(&mut self) {
|
||||||
|
let text_buffer = TextBuffer::default();
|
||||||
|
self.ui.borrow_mut().log_content.set_buffer(text_buffer.clone());
|
||||||
|
let text_buffer_arc = Arc::new(Mutex::new(text_buffer));
|
||||||
|
LOGGER.set_callback(move |msg| {
|
||||||
|
let mut text_buffer = text_buffer_arc.lock().unwrap();
|
||||||
|
text_buffer.append(&msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn init_excel(&mut self) {
|
fn init_excel(&mut self) {
|
||||||
let ui_rc = Rc::new(&self.ui);
|
let ui_rc = Rc::clone(&self.ui);
|
||||||
let ui_clone = Rc::clone(&self.ui);
|
|
||||||
let work_service_clone = Rc::clone(&self.work_service);
|
let work_service_clone = Rc::clone(&self.work_service);
|
||||||
ui_rc.borrow_mut().select_file_btn.set_callback(move |_| {
|
self.ui.borrow_mut().select_file_btn.set_callback(move |_| {
|
||||||
let mut ui = ui_clone.borrow_mut();
|
let mut ui = ui_rc.borrow_mut();
|
||||||
let mut work_service = work_service_clone.borrow_mut();
|
let mut work_service = work_service_clone.borrow_mut();
|
||||||
let mut dialog = fltk::dialog::FileDialog::new(fltk::dialog::FileDialogType::BrowseFile);
|
let mut dialog = fltk::dialog::FileDialog::new(fltk::dialog::FileDialogType::BrowseFile);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
let binding = dialog.filename();
|
let binding = dialog.filename();
|
||||||
let path = binding.to_str().unwrap();
|
let path = binding.to_str().unwrap();
|
||||||
let current_line = &work_service.get_current_line().to_string();
|
if path == "" { return; }
|
||||||
work_service.init_excel_service(path.to_string()).unwrap();
|
work_service.init_excel_service(path.to_string()).unwrap();
|
||||||
|
let current_line = &work_service.get_current_line().to_string();
|
||||||
|
work_service.config_model.excel_path = path.to_string();
|
||||||
|
work_service.config_model.current_line = current_line.parse::<usize>().unwrap();
|
||||||
ui.excel_file_textbox.set_value(path);
|
ui.excel_file_textbox.set_value(path);
|
||||||
ui.current_line_textbox.set_value(current_line);
|
ui.current_line_textbox.set_value(current_line);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_serial_service(&mut self) {
|
|
||||||
let port_name = self.ui.borrow().com_textbox.value();
|
|
||||||
match self.work_service.borrow_mut().init_serial_service(port_name) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(_) => { fltk::dialog::message_default("Cant Open serial") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,21 +1,34 @@
|
|||||||
use std::ptr::null;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::models::config_model::ConfigModel;
|
||||||
use crate::models::work_model::WorkModel;
|
use crate::models::work_model::WorkModel;
|
||||||
use crate::services::{serial_service::SerialService, sqlite_service::SqliteService, excel_service::ExcelService};
|
use crate::services::{config_service::ConfigService, excel_service::ExcelService, serial_service::SerialService, sqlite_service::SqliteService};
|
||||||
|
use crate::services::log_service::{init_logger};
|
||||||
|
|
||||||
pub struct WorkService {
|
pub struct WorkService {
|
||||||
pub(crate) serial_service: Option<SerialService>,
|
pub(crate) serial_service: Option<SerialService>,
|
||||||
sqlite_service: SqliteService,
|
|
||||||
pub(crate) excel_service: Option<ExcelService>,
|
pub(crate) excel_service: Option<ExcelService>,
|
||||||
|
sqlite_service: SqliteService,
|
||||||
|
pub(crate) config_model: ConfigModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkService {
|
impl WorkService {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
WorkService {
|
init_logger().unwrap();
|
||||||
|
let config = WorkService::load_config().unwrap_or_else(|_| ConfigModel::default());
|
||||||
|
let mut this = WorkService {
|
||||||
serial_service: Option::None,
|
serial_service: Option::None,
|
||||||
sqlite_service: SqliteService::new("data.db".to_string()).unwrap(),
|
sqlite_service: SqliteService::new("data.db".to_string()).unwrap(),
|
||||||
excel_service: Option::None,
|
excel_service: Option::None,
|
||||||
|
config_model: config,
|
||||||
|
};
|
||||||
|
if this.config_model.excel_path != "" {
|
||||||
|
this.init_excel_service(this.config_model.excel_path.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_port_names() -> Vec<String> {
|
pub fn get_port_names() -> Vec<String> {
|
||||||
//maybe should not use unwrap
|
//maybe should not use unwrap
|
||||||
return SerialService::get_ports().unwrap();
|
return SerialService::get_ports().unwrap();
|
||||||
@ -24,6 +37,7 @@ impl WorkService {
|
|||||||
pub fn init_excel_service(&mut self, path: String) -> Result<bool, String> {
|
pub fn init_excel_service(&mut self, path: String) -> Result<bool, String> {
|
||||||
return if let Ok(excel_service) = ExcelService::new(&path) {
|
return if let Ok(excel_service) = ExcelService::new(&path) {
|
||||||
self.excel_service = Some(excel_service);
|
self.excel_service = Some(excel_service);
|
||||||
|
self.config_model.excel_path = path;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Err("Cant Init ExcelService".to_string())
|
Err("Cant Init ExcelService".to_string())
|
||||||
@ -31,7 +45,51 @@ impl WorkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_and_check(&mut self, model: WorkModel) -> Result<bool, String> {
|
pub fn write_and_check(&mut self, model: WorkModel) -> Result<bool, String> {
|
||||||
fltk::dialog::message_default(&format!("{}:{}:{}", model.imei, model.sn, model.line_number));
|
log::info!("Write Start");
|
||||||
|
match self.sqlite_service.check_imei_has_insert(&model.imei) {
|
||||||
|
Ok(true) => {
|
||||||
|
log::error!("Imei Exist: {}", model.imei);
|
||||||
|
self.serial_service = None;
|
||||||
|
return Err("Imei Exist".to_string());
|
||||||
|
}
|
||||||
|
_ => {log::info!("Check Imei From Db Pass")}
|
||||||
|
}
|
||||||
|
match self.sqlite_service.check_sn_has_insert(&model.sn) {
|
||||||
|
Ok(true) => {
|
||||||
|
log::error!("Imei Exist: {}", model.sn);
|
||||||
|
self.serial_service = None;
|
||||||
|
return Err("Imei Exist".to_string());
|
||||||
|
}
|
||||||
|
_ => {log::info!("Check Sn From Db Pass")}
|
||||||
|
}
|
||||||
|
if let Err(msg) = self.write_imei(model.imei.clone()) {
|
||||||
|
log::error!("Write Imei Error:{}", msg);
|
||||||
|
return Err(msg);
|
||||||
|
}
|
||||||
|
log::info!("Write Imei:{}", model.imei);
|
||||||
|
if let Err(msg) = self.write_sn(model.sn.clone()) {
|
||||||
|
log::error!("Write Sn Error:{}", msg);
|
||||||
|
return Err(msg);
|
||||||
|
}
|
||||||
|
log::info!("Write Imei:{}", model.sn);
|
||||||
|
log::info!("Write End");
|
||||||
|
log::info!("Check Start");
|
||||||
|
if let Err(msg) = self.check_imei(&model.imei) {
|
||||||
|
log::error!("Check Imei Error:{}", msg);
|
||||||
|
return Err(msg);
|
||||||
|
}
|
||||||
|
log::info!("Check Imei:{}", model.imei);
|
||||||
|
if let Err(msg) = self.check_sn(&model.sn) {
|
||||||
|
log::error!("Check Sn Error:{}", msg);
|
||||||
|
return Err(msg);
|
||||||
|
}
|
||||||
|
log::info!("Check Sn:{}", model.sn);
|
||||||
|
log::info!("Check End");
|
||||||
|
self.serial_service = None;
|
||||||
|
match self.sqlite_service.insert(model) {
|
||||||
|
Err(msg) => { log::error!("Insert Error:{}",msg); }
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,15 +100,31 @@ impl WorkService {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_current_line(&mut self, line: usize) -> Result<(), String> {
|
||||||
|
if let Some(service) = &mut self.excel_service {
|
||||||
|
return service.set_current_line(line);
|
||||||
|
} else {
|
||||||
|
Err("Cant Set Line".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_next_work_model(&mut self) -> Option<WorkModel> {
|
pub fn get_next_work_model(&mut self) -> Option<WorkModel> {
|
||||||
if let Some(service) = &mut self.excel_service {
|
if let Some(service) = &mut self.excel_service {
|
||||||
if let Ok(model) = service.get_next_work_model() {
|
if let Ok(model) = service.get_next_work_model() {
|
||||||
|
self.config_model.current_line = service.get_current_line();
|
||||||
return Some(model);
|
return Some(model);
|
||||||
} else { return None; }
|
} else { return None; }
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn roll_back(&mut self) {
|
||||||
|
return if let Some(service) = &mut self.excel_service {
|
||||||
|
service.roll_back();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn init_sqlite_service(&mut self, db_path: String) -> Result<bool, String> {
|
pub fn init_sqlite_service(&mut self, db_path: String) -> Result<bool, String> {
|
||||||
return if let Ok(sqlite_service) = SqliteService::new(db_path) {
|
return if let Ok(sqlite_service) = SqliteService::new(db_path) {
|
||||||
self.sqlite_service = sqlite_service;
|
self.sqlite_service = sqlite_service;
|
||||||
@ -63,6 +137,7 @@ impl WorkService {
|
|||||||
pub fn init_serial_service(&mut self, port_name: String) -> Result<bool, String> {
|
pub fn init_serial_service(&mut self, port_name: String) -> Result<bool, String> {
|
||||||
return if let Ok(serial_service) = SerialService::new(&port_name) {
|
return if let Ok(serial_service) = SerialService::new(&port_name) {
|
||||||
self.serial_service = Some(*serial_service);
|
self.serial_service = Some(*serial_service);
|
||||||
|
self.config_model.last_com = port_name;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Err("Cant Init SerialService".to_string())
|
Err("Cant Init SerialService".to_string())
|
||||||
@ -99,4 +174,12 @@ impl WorkService {
|
|||||||
}
|
}
|
||||||
return Err("Cant Init ServialService".to_string());
|
return Err("Cant Init ServialService".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save_config(&self) {
|
||||||
|
ConfigService::save_config(self.config_model.clone()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_config() -> Result<ConfigModel> {
|
||||||
|
return ConfigService::load_config();
|
||||||
|
}
|
||||||
}
|
}
|
68
src/ui/main.fl
Normal file
68
src/ui/main.fl
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# data file for the Fltk User Interface Designer (fluid)
|
||||||
|
version 1.0400
|
||||||
|
header_name {.h}
|
||||||
|
code_name {.cxx}
|
||||||
|
class UserInterface {open
|
||||||
|
} {
|
||||||
|
Function {make_window()} {open
|
||||||
|
} {
|
||||||
|
Fl_Window main_window {
|
||||||
|
label WriteTool_RS open
|
||||||
|
xywh {721 399 693 467} type Double visible
|
||||||
|
} {
|
||||||
|
Fl_Output current_write_model {
|
||||||
|
label LastImeiAndSn
|
||||||
|
xywh {135 107 375 35}
|
||||||
|
}
|
||||||
|
Fl_Output excel_file_textbox {
|
||||||
|
label {CurrentExcelFile:}
|
||||||
|
xywh {135 20 375 35}
|
||||||
|
}
|
||||||
|
Fl_Button select_file_btn {
|
||||||
|
label SelectFile
|
||||||
|
xywh {535 20 90 30}
|
||||||
|
}
|
||||||
|
Fl_Output current_line_textbox {
|
||||||
|
label CurrentLine
|
||||||
|
xywh {135 62 375 35}
|
||||||
|
}
|
||||||
|
Fl_Button set_lines_btn {
|
||||||
|
label SetLines
|
||||||
|
xywh {535 60 90 30}
|
||||||
|
}
|
||||||
|
Fl_Button start_btn {
|
||||||
|
label Start
|
||||||
|
xywh {532 156 138 35} shortcut 0xff0d color 51 labeltype ENGRAVED_LABEL labelsize 18
|
||||||
|
}
|
||||||
|
Fl_Text_Display log_content {selected
|
||||||
|
xywh {10 210 670 250}
|
||||||
|
}
|
||||||
|
Fl_Choice com_choice {
|
||||||
|
label {Com:} open
|
||||||
|
xywh {135 156 235 35} down_box BORDER_BOX
|
||||||
|
} {}
|
||||||
|
Fl_Button refresh_com_btn {
|
||||||
|
label Refresh
|
||||||
|
xywh {390 156 120 35}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserInterface1 {open
|
||||||
|
} {
|
||||||
|
Function {make_set_line_window()} {} {
|
||||||
|
Fl_Window {} {open
|
||||||
|
xywh {1171 275 228 43} type Double visible
|
||||||
|
} {
|
||||||
|
Fl_Input line_textbox {
|
||||||
|
label {Line:}
|
||||||
|
xywh {40 5 130 35}
|
||||||
|
}
|
||||||
|
Fl_Button ok_btn {
|
||||||
|
label ok
|
||||||
|
xywh {175 5 45 35}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
test_excel.xlsx
BIN
test_excel.xlsx
Binary file not shown.
Loading…
Reference in New Issue
Block a user