From 9f631dcfef8ebd10a4ad8e6859814e3760477590 Mon Sep 17 00:00:00 2001 From: Shikai Liu Date: Sat, 16 Dec 2023 20:10:18 +0800 Subject: [PATCH] Update the image of codemagic! --- LICENSE | 201 +++++++++++++++++++ README.md | 30 ++- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/common_tools/cmd.rs | 91 +++++++++ src-tauri/src/common_tools/code_full_half.rs | 28 +++ src-tauri/src/common_tools/mod.rs | 2 + src-tauri/src/common_tools/resort_menu.rs | 1 + src-tauri/src/common_tools/sql_lite.rs | 143 +++++++++++++ src-tauri/src/main.rs | 29 +-- src-tauri/src/sql_lite/connection.rs | 28 +++ src-tauri/src/sql_lite/mod.rs | 1 + src-tauri/src/vojo/menu_config.rs | 8 + src-tauri/src/vojo/mod.rs | 1 + src/dashboard/components/sidebar.tsx | 108 ++++++++-- src/dashboard/page.tsx | 185 ++++++++++------- src/dashboard/page/base64ImagePage.tsx | 4 +- src/dashboard/page/base64Page.tsx | 12 +- src/dashboard/page/diffViewerPage.tsx | 24 ++- src/dashboard/page/formatJsonPage.tsx | 2 + src/dashboard/page/formatXmlPage.tsx | 1 + src/dashboard/page/formatYamlPage.tsx | 1 + src/dashboard/page/halfFullPage.tsx | 57 ++++++ src/dashboard/page/qrcodePage.tsx | 2 +- 24 files changed, 851 insertions(+), 112 deletions(-) create mode 100644 LICENSE create mode 100644 src-tauri/src/common_tools/code_full_half.rs create mode 100644 src-tauri/src/common_tools/resort_menu.rs create mode 100644 src-tauri/src/common_tools/sql_lite.rs create mode 100644 src-tauri/src/sql_lite/connection.rs create mode 100644 src-tauri/src/sql_lite/mod.rs create mode 100644 src-tauri/src/vojo/menu_config.rs create mode 100644 src-tauri/src/vojo/mod.rs create mode 100644 src/dashboard/page/halfFullPage.tsx diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index f4f4854..96491df 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # CodeMagic +## 主要功能 本地离线工具集合,包含以下功能: - base64转码/解码:文本转base64,base64转文本,图片转base64,base64转图片 -- 格式化:格式化json/yaml +- 格式化:格式化json/yaml/xml - urlEncode/urlDecode - 摘要算法:计算文本的md5,sha256。计算多个文件的md5,sha256 - 时间戳: 时间戳转时间,时间转时间戳 @@ -9,3 +10,30 @@ - 调色板 - 文本对比工具 - 国密算法(SM2,SM3,SM4) + +## relase 下载地址 +https://github.com/lsk569937453/code-magic-public/releases +## 一些截图 +### 正常模式 +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-192959.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-193041.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-193052.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-193110.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-193152.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16%20-193212.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16-%20192905.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16-%20193014.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16-%20193028.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16-%20193229.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/light/2023-12-16192843.png) +### 暗黑模式 +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16%20-193405.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16%20-193414.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16%20-193424.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16%20-193438.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16%20-193450.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16-%20193310.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16-%20193330.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16-%20193341.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16-%20193354.png) +![alt tag](https://raw.githubusercontent.com/lsk569937453/image_repo/main/code_magic/dark/2023-12-16--193249.png) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 4fad0a2..086c01d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -403,7 +403,7 @@ dependencies = [ [[package]] name = "code_magic" -version = "0.0.17" +version = "0.0.18" dependencies = [ "aes", "anyhow", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 44fe6f7..4b9ef3e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "code_magic" -version = "0.0.17" +version = "0.0.18" description = "A development tools" authors = ["lsk"] license = "MIT" diff --git a/src-tauri/src/common_tools/cmd.rs b/src-tauri/src/common_tools/cmd.rs index 1960592..3070a44 100644 --- a/src-tauri/src/common_tools/cmd.rs +++ b/src-tauri/src/common_tools/cmd.rs @@ -4,6 +4,8 @@ use crate::common_tools::base64::base64_encode_of_image_with_error; use crate::common_tools::base64::base64_encode_with_error; use crate::common_tools::base64::base64_save_image_with_error; use crate::common_tools::base_response::BaseResponse; +use crate::common_tools::code_full_half::to_cdb_with_error; +use crate::common_tools::code_full_half::to_dbc_with_error; use crate::common_tools::crypto_algorithm::get_sm2_keypair_with_error; use crate::common_tools::crypto_algorithm::sm2_decrypt_with_error; use crate::common_tools::crypto_algorithm::sm2_encrypt_with_error; @@ -20,11 +22,17 @@ use crate::common_tools::qrcode::export_barcode_with_error; use crate::common_tools::qrcode::export_qrcode_with_error; use crate::common_tools::qrcode::get_barcode_with_error; use crate::common_tools::qrcode::get_qrcode_with_error; +use crate::common_tools::sql_lite::get_menu_config_with_error; +use crate::common_tools::sql_lite::set_menu_index_with_error; +use crate::common_tools::sql_lite::GetMenuConfigReq; use crate::common_tools::timestamp::format_datetime_to_timestamp_with_error; use crate::common_tools::timestamp::format_timestamp_to_datetime_with_error; use crate::common_tools::timestamp::get_current_timestamp_with_error; use crate::common_tools::urlencode::url_decode_with_error; use crate::common_tools::urlencode::url_encode_with_error; + +use crate::sql_lite::connection::{SqlLite, SqlLiteState}; +use tauri::State; #[tauri::command] pub fn base64_encode(source_string: String) -> String { match base64_encode_with_error(source_string) { @@ -64,6 +72,44 @@ pub fn base64_decode(source_string: String) -> String { } } #[tauri::command] +pub fn to_cdb(source_string: String) -> String { + match to_cdb_with_error(source_string) { + Ok(item) => { + let res = BaseResponse { + response_code: 0, + response_msg: item, + }; + serde_json::to_string(&res).unwrap() + } + Err(e) => { + let res = BaseResponse { + response_code: 1, + response_msg: e.to_string(), + }; + serde_json::to_string(&res).unwrap() + } + } +} +#[tauri::command] +pub fn to_dbc(source_string: String) -> String { + match to_dbc_with_error(source_string) { + Ok(item) => { + let res = BaseResponse { + response_code: 0, + response_msg: item, + }; + serde_json::to_string(&res).unwrap() + } + Err(e) => { + let res = BaseResponse { + response_code: 1, + response_msg: e.to_string(), + }; + serde_json::to_string(&res).unwrap() + } + } +} +#[tauri::command] pub fn base64_encode_of_image(source_string: String) -> String { match base64_encode_of_image_with_error(source_string) { Ok(item) => { @@ -488,3 +534,48 @@ pub fn get_about_version() -> String { } } } +#[tauri::command] +pub fn get_menu_config( + state: State, + get_menu_config_reqs: Vec, +) -> String { + match get_menu_config_with_error(state, get_menu_config_reqs) { + Ok(item) => { + let res = BaseResponse { + response_code: 0, + response_msg: item, + }; + serde_json::to_string(&res).unwrap() + } + Err(e) => { + let res = BaseResponse { + response_code: 1, + response_msg: e.to_string(), + }; + serde_json::to_string(&res).unwrap() + } + } +} +#[tauri::command] +pub fn set_menu_index( + state: State, + source_index: i32, + dst_menu_index: i32, +) -> String { + match set_menu_index_with_error(state, source_index, dst_menu_index) { + Ok(item) => { + let res = BaseResponse { + response_code: 0, + response_msg: item, + }; + serde_json::to_string(&res).unwrap() + } + Err(e) => { + let res = BaseResponse { + response_code: 1, + response_msg: e.to_string(), + }; + serde_json::to_string(&res).unwrap() + } + } +} diff --git a/src-tauri/src/common_tools/code_full_half.rs b/src-tauri/src/common_tools/code_full_half.rs new file mode 100644 index 0000000..faee50d --- /dev/null +++ b/src-tauri/src/common_tools/code_full_half.rs @@ -0,0 +1,28 @@ +//全角转半角 +pub fn to_cdb_with_error(str: String) -> Result { + let mut tmp = String::new(); + for ch in str.chars() { + let unicode = ch as u32; + if unicode > 65248 && unicode < 65375 { + tmp.push(std::char::from_u32(unicode - 65248).ok_or(anyhow::anyhow!(""))?); + } else { + tmp.push(ch); + } + } + Ok(tmp) +} +//半角转全角 +pub fn to_dbc_with_error(txtstring: String) -> Result { + let mut tmp = String::new(); + for c in txtstring.chars() { + match c { + ' ' => tmp.push(char::from_u32(12288).ok_or(anyhow!(""))?), + _ if c.is_ascii() => { + let ch = c as u32; + tmp.push(char::from_u32(ch + 65248).ok_or(anyhow!(""))?); + } + _ => {} + } + } + Ok(tmp) +} diff --git a/src-tauri/src/common_tools/mod.rs b/src-tauri/src/common_tools/mod.rs index c384023..fa4c9b3 100644 --- a/src-tauri/src/common_tools/mod.rs +++ b/src-tauri/src/common_tools/mod.rs @@ -2,9 +2,11 @@ pub mod about; pub mod base64; pub mod base_response; pub mod cmd; +pub mod code_full_half; pub mod crypto_algorithm; pub mod format; pub mod md5; pub mod qrcode; +pub mod sql_lite; pub mod timestamp; pub mod urlencode; diff --git a/src-tauri/src/common_tools/resort_menu.rs b/src-tauri/src/common_tools/resort_menu.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src-tauri/src/common_tools/resort_menu.rs @@ -0,0 +1 @@ + diff --git a/src-tauri/src/common_tools/sql_lite.rs b/src-tauri/src/common_tools/sql_lite.rs new file mode 100644 index 0000000..e38190a --- /dev/null +++ b/src-tauri/src/common_tools/sql_lite.rs @@ -0,0 +1,143 @@ +use crate::sql_lite::connection::{SqlLite, SqlLiteState}; +use crate::vojo::menu_config::MenuConfig; +use rusqlite::{params, Connection, Result}; +use serde::Deserialize; +use serde::Serialize; +use tauri::State; +#[derive(Serialize, Deserialize, Clone)] + +pub struct GetMenuConfigReq { + pub menu_index: i32, + pub source_index: i32, +} +pub fn get_menu_config_with_error( + state: State, + get_menu_config_reqs: Vec, +) -> Result, anyhow::Error> { + let sql_lite = state.0.lock().map_err(|e| anyhow!("lock error"))?; + + let connection = &sql_lite.connection; + let mut statement = connection.prepare("SELECT id,menu_index,source_index FROM menu_config")?; + let rows: Vec<_> = statement + .query_map([], |row| { + Ok(MenuConfig { + id: row.get(0)?, + menu_index: row.get(1)?, + source_index: row.get(2)?, + }) + })? + .collect(); + let mut menu_configs: Vec = vec![]; + for name_result in rows { + menu_configs.push(name_result?); + } + if menu_configs.is_empty() || menu_configs.len() != get_menu_config_reqs.len() { + connection.execute("delete from menu_config", params![])?; + for get_menu_config_req in get_menu_config_reqs { + connection.execute( + "insert into menu_config (menu_index,source_index) values (?1,?2)", + params![ + get_menu_config_req.menu_index, + get_menu_config_req.source_index + ], + )?; + } + let mut statement = + connection.prepare("SELECT id,menu_index,source_index FROM menu_config")?; + let rows: Vec<_> = statement + .query_map([], |row| { + Ok(MenuConfig { + id: row.get(0)?, + menu_index: row.get(1)?, + source_index: row.get(2)?, + }) + })? + .collect(); + for name_result in rows { + menu_configs.push(name_result?); + } + menu_configs.sort_by_key(|item| item.menu_index); + Ok(menu_configs) + } else { + menu_configs.sort_by_key(|item| item.menu_index); + + Ok(menu_configs) + } +} +pub fn set_menu_index_with_error( + state: State, + source_index: i32, + dst_menu_index: i32, +) -> Result<(), anyhow::Error> { + info!( + "souce_index:{},dst_menu_index:{}", + source_index, dst_menu_index + ); + let sql_lite = state.0.lock().map_err(|e| anyhow!("lock error"))?; + + let connection = &sql_lite.connection; + let mut statement = connection.prepare("SELECT id,menu_index,source_index FROM menu_config")?; + let rows: Vec<_> = statement + .query_map([], |row| { + Ok(MenuConfig { + id: row.get(0)?, + menu_index: row.get(1)?, + source_index: row.get(2)?, + }) + })? + .collect(); + let mut menu_configs: Vec = vec![]; + let mut source_menu_index = 0; + for name_result in rows { + let item = name_result?; + if item.source_index == source_index { + source_menu_index = item.menu_index; + } + menu_configs.push(item); + } + ensure!(!menu_configs.is_empty(), "menu_config is empty"); + let start = if source_menu_index < dst_menu_index { + source_menu_index + } else { + dst_menu_index + }; + let end = if source_menu_index > dst_menu_index { + source_menu_index + } else { + dst_menu_index + }; + let move_forward = source_menu_index > dst_menu_index; + + info!( + "start:{},end:{},move_forward:{},source_menu_index:{},dst_menu_index:{}", + start, end, move_forward, source_menu_index, dst_menu_index + ); + menu_configs.sort_by_key(|item: &MenuConfig| item.menu_index); + for item in menu_configs.iter_mut() { + if move_forward { + if item.menu_index == end { + item.menu_index = start; + } else if item.menu_index >= start && item.menu_index < end { + item.menu_index += 1; + } + } else if item.menu_index == start { + item.menu_index = end; + } else if item.menu_index > start && item.menu_index <= end { + item.menu_index -= 1; + } + + info!("aa"); + } + + info!("menu_configs:{}", serde_json::to_string(&menu_configs)?); + for menu_config in menu_configs { + connection.execute( + "update menu_config set menu_index=(?1) where source_index=(?2) ", + params![menu_config.menu_index, menu_config.source_index], + )?; + } + // 1 2 3 4 5 6 7 8 2->7 + // 1 2 3 4 5 6 7 8 7->2 + + Ok(()) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a259320..5d3070b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,26 +1,23 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +use std::sync::Mutex; use std::time::Duration; mod common_tools; - +mod sql_lite; +mod vojo; use crate::common_tools::cmd::*; -// Prevents additional console window on Windows in release, DO NOT REMOVE!! use log::LevelFilter; #[macro_use] extern crate anyhow; #[macro_use] extern crate log; +use crate::sql_lite::connection::{SqlLite, SqlLiteState}; +use std::sync::RwLock; use tauri::Manager; use tauri::SystemTray; -use tauri::{CustomMenuItem, Menu, Submenu, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem}; +use tauri::{CustomMenuItem, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem}; use tokio::time::sleep; - -#[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} - -fn main() { +fn main() -> Result<(), anyhow::Error> { let quit = CustomMenuItem::new("quit".to_string(), "退出"); let show = CustomMenuItem::new("show".to_string(), "显示"); let tray_menu = SystemTrayMenu::new() @@ -28,8 +25,10 @@ fn main() { .add_native_item(SystemTrayMenuItem::Separator) .add_item(quit); let system_tray = SystemTray::new().with_menu(tray_menu); - + let sql_lite = SqlLite::new()?; + let sql_lite_state = SqlLiteState(Mutex::new(sql_lite)); tauri::Builder::default() + .manage(sql_lite_state) .plugin( tauri_plugin_log::Builder::default() .level(LevelFilter::Info) @@ -86,11 +85,12 @@ fn main() { _ => {} }) .invoke_handler(tauri::generate_handler![ - greet, base64_encode, base64_decode, base64_encode_of_image, base64_save_image, + to_cdb, + to_dbc, url_encode, url_decode, get_current_timestamp, @@ -110,8 +110,11 @@ fn main() { format_pretty_json, format_pretty_yaml, format_pretty_xml, - get_about_version + get_about_version, + get_menu_config, + set_menu_index ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); + Ok(()) } diff --git a/src-tauri/src/sql_lite/connection.rs b/src-tauri/src/sql_lite/connection.rs new file mode 100644 index 0000000..75b3107 --- /dev/null +++ b/src-tauri/src/sql_lite/connection.rs @@ -0,0 +1,28 @@ +use rusqlite::{params, Connection, Result}; +use std::env; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::RwLock; +pub struct SqlLite { + pub connection: Connection, +} + +pub struct SqlLiteState(pub Mutex); + +impl SqlLite { + pub fn new() -> Result { + let home_dir = dirs::home_dir().ok_or(anyhow!("failed to get home directory"))?; + let db_path = home_dir.join(".codemagic.db"); + let connection = Connection::open(db_path)?; + connection.execute( + "CREATE TABLE IF NOT EXISTS menu_config ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + menu_index INTEGER NOT NULL, + source_index INTEGER NOT NULL + )", + params![], + )?; + + Ok(SqlLite { connection }) + } +} diff --git a/src-tauri/src/sql_lite/mod.rs b/src-tauri/src/sql_lite/mod.rs new file mode 100644 index 0000000..b3b606b --- /dev/null +++ b/src-tauri/src/sql_lite/mod.rs @@ -0,0 +1 @@ +pub mod connection; diff --git a/src-tauri/src/vojo/menu_config.rs b/src-tauri/src/vojo/menu_config.rs new file mode 100644 index 0000000..ccb8fd1 --- /dev/null +++ b/src-tauri/src/vojo/menu_config.rs @@ -0,0 +1,8 @@ +use serde::Deserialize; +use serde::Serialize; +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MenuConfig { + pub id: i32, + pub menu_index: i32, + pub source_index: i32, +} diff --git a/src-tauri/src/vojo/mod.rs b/src-tauri/src/vojo/mod.rs new file mode 100644 index 0000000..b54c4de --- /dev/null +++ b/src-tauri/src/vojo/mod.rs @@ -0,0 +1 @@ +pub mod menu_config; diff --git a/src/dashboard/components/sidebar.tsx b/src/dashboard/components/sidebar.tsx index de87f11..8af832e 100644 --- a/src/dashboard/components/sidebar.tsx +++ b/src/dashboard/components/sidebar.tsx @@ -2,6 +2,9 @@ import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { ScrollArea } from "@/components/ui/scroll-area" import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { invoke } from "@tauri-apps/api/tauri"; + import { Dialog, DialogClose, @@ -12,16 +15,28 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog" -import React, { useState } from "react"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import React, { useEffect, useState } from "react"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, } from "@/components/ui/context-menu" +import { useToast } from "@/components/ui/use-toast" + interface MenuItem { label: string; menuIndex: number; + sourceIndex: number; } interface SidebarProps extends React.HTMLAttributes { menuList: MenuItem[]; @@ -29,16 +44,61 @@ interface SidebarProps extends React.HTMLAttributes { } const Sidebar = ({ menuList, onButtonClick }: SidebarProps) => { + const [currentMenuList, setCurrentMenuList] = useState([]); const [selectedIndex, setSelectedIndex] = useState(0); + const [clickedSourceIndex, setClickedSourceIndex] = useState(0); + const [changedMenuIndex, setChangedMenuIndex] = useState(""); + const { toast } = useToast() + + useEffect(() => { + setCurrentMenuList(menuList); + }, [menuList]); const handleButtonClick = (index: number) => { onButtonClick(index); setSelectedIndex(index); } const [showDialog, setShowDialog] = useState(false); - const handleRightClick = (e: any) => { + const handleRightClick = async (e: any, index: number) => { + setClickedSourceIndex(index); + const aa = menuList.filter(item => item.sourceIndex === index)[0].menuIndex; + console.log("aa is :" + aa.toString) + setChangedMenuIndex(aa.toString()); setShowDialog(true); e.preventDefault() } + const handleChangeMenuIndexClick = async () => { + const sourceMenuIndex = menuList.filter(item => item.sourceIndex === clickedSourceIndex)[0].menuIndex; + if (sourceMenuIndex == parseInt(changedMenuIndex)) { + toast({ + variant: "destructive", + title: "错误信息", + description: "修改后的菜单号和修改前的一样!", + }) + return; + } + + const { response_code, response_msg } = JSON.parse(await invoke("set_menu_index", { sourceIndex: clickedSourceIndex, dstMenuIndex: parseInt(changedMenuIndex) })); + console.log(response_code); + console.log(response_msg); + setShowDialog(false); + + if (response_code === 0) { + window.location.reload(); + + } + + } + const dialogGetSourceIndex = () => { + console.log("m:" + JSON.stringify(menuList)); + console.log("c:" + clickedSourceIndex); + const index = menuList.filter(item => item.sourceIndex === clickedSourceIndex)[0].menuIndex; + console.log("i:" + index); + + let res = (index === undefined) ? 0 : index; + + console.log("r:" + res.toString()); + return res.toString(); + } return (
@@ -49,18 +109,34 @@ const Sidebar = ({ menuList, onButtonClick }: SidebarProps) => { - 更新菜单排列 - - This action cannot be undone. Are you sure you want to permanently - delete this file from our servers? - + 更新菜单序号 - - - - +
+ +
+ + +
** 如果当前是2号菜单与7号菜单项交换,则2号变为7号菜单,3,4,5,6号菜单变为2,3,4,5号菜单
+
+
+ + +
@@ -70,11 +146,11 @@ const Sidebar = ({ menuList, onButtonClick }: SidebarProps) => { {menuList.map((item, index) => (
diff --git a/src/dashboard/page.tsx b/src/dashboard/page.tsx index 505ec49..4cf1532 100644 --- a/src/dashboard/page.tsx +++ b/src/dashboard/page.tsx @@ -29,87 +29,136 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" +import { invoke } from "@tauri-apps/api/tauri"; + import Sidebar from "./components/sidebar" -import { useState } from "react" +import { useState, useEffect } from "react" import Base64TextPage from "./page/base64Page" import UrlEncodePage from "./page/urlencodePage" -import DigestPage from "./page/digestPage" +import DigestPage from "./page/digestPage" import TimestampPage from "./page/timestampPage" import QrcodePage from "./page/qrcodePage" import FormatPage from "./page/formatPage" import ColorPalettePage from "./page/colorPalettePage" import DiffViewerPage from "./page/diffViewerPage" -import CryptoPage from "./page/cryptoPage" +import CryptoPage from "./page/cryptoPage" +const constMenulist = [ + { + label: "转换工具", + menuIndex: 0, + sourceIndex: 0, + + render: + + }, + { + label: "格式化", + menuIndex: 1, + sourceIndex: 1, + render: + + }, { + label: "UrlEncode/UrlDecode", + menuIndex: 2, + sourceIndex: 2, + + render: + + }, + { + label: "摘要算法(MD5,SHA)", + menuIndex: 3, + sourceIndex: 3, + + render: + + }, + { + label: " 时间戳", + menuIndex: 4, + sourceIndex: 4, + render: + + }, + { + label: "二维码", + menuIndex: 5, + sourceIndex: 5, + + render: + + }, + { + label: "调色器", + menuIndex: 6, + sourceIndex: 6, + + render: + + }, { + label: "文本对比", + menuIndex: 7, + sourceIndex: 7, + render: + } + , { + label: "加密算法", + menuIndex: 8, + sourceIndex: 8, + + render: + } +]; export default function DashboardPage() { const [selectedIndex, setSelectedIndex] = useState(1); - const menulist = [ - { - label: "Base64转码/解码", - menuIndex: 1, - sourceIndex: 1, - - render: - - }, - { - label: "格式化", - menuIndex: 2, - sourceIndex:2, - render: - - }, { - label: "UrlEncode/UrlDecode", - menuIndex: 3, - sourceIndex:3, - - render: - - }, - { - label: "摘要算法(MD5,SHA)", - menuIndex: 4, - sourceIndex:4, - - render: - - }, - { - label: " 时间戳", - menuIndex: 5, - sourceIndex:5, - render: - - }, - { - label: "二维码", - menuIndex: 6, - sourceIndex:6, - - render: - - }, - { - label: "调色器", - menuIndex: 7, - sourceIndex:7, - - render: - - },{ - label: "文本对比", - menuIndex: 8, - sourceIndex:8, - render: - } - ,{ - label: "加密算法", - menuIndex: 9, - sourceIndex:9, + const [menulist, setMenulist] = useState(constMenulist); + useEffect(() => { + loadData(); + }, []) + + const loadData = async () => { + const getMenuConfigReqs = constMenulist.map(item => { + return { + menu_index: item.menuIndex, + source_index: item.sourceIndex + } + }); + const { response_code, response_msg } = JSON.parse(await invoke("get_menu_config", { getMenuConfigReqs: getMenuConfigReqs })); + + console.log(response_code); + console.log("get_menu_config:"+JSON.stringify(response_msg)); + if (response_code == 0) { + const contacts = new Map(); + response_msg.forEach((item: { id: any, menu_index: any, source_index: any }) => { + const { id, menu_index, source_index } = item; + contacts.set(source_index, menu_index); + }); + + const newMenulist = constMenulist.map(item => { + const menu_index = contacts.get(item.sourceIndex); + return { + ...item, + menuIndex: menu_index + } + }); + //sort 内部写法 + newMenulist.sort(function (a, b) { //callback + const {menuIndex:menu_index}=a; + const {menuIndex: bmenu_index}=b; + + if (menu_index > bmenu_index) { // a b 分别是Arr中的 56 21 + return 1 //返回正数 ,b排列在a之前 + } else { + return -1 //返回负数 ,a排列在b之前 + } + }) + console.log("convert to:" + JSON.stringify(newMenulist)); + + setMenulist(newMenulist); - render: } - ]; + } const handleMenuClick = (index: number) => { setSelectedIndex(index); } diff --git a/src/dashboard/page/base64ImagePage.tsx b/src/dashboard/page/base64ImagePage.tsx index cbea75f..823fdfa 100644 --- a/src/dashboard/page/base64ImagePage.tsx +++ b/src/dashboard/page/base64ImagePage.tsx @@ -93,10 +93,10 @@ export function Base64ImagePage() {
diff --git a/src/dashboard/page/base64Page.tsx b/src/dashboard/page/base64Page.tsx index 4a91f77..affec66 100644 --- a/src/dashboard/page/base64Page.tsx +++ b/src/dashboard/page/base64Page.tsx @@ -3,17 +3,21 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import {Base64TextPage}from "./base64TextPage"; import { Base64ImagePage } from './base64ImagePage'; - +import { HalfToFullPage } from "./halfFullPage"; export default function Base64Page() { return ( - - 文本 - 图片 + + Base64文本 + Base64图片 + 全角/半角 + + + ); } \ No newline at end of file diff --git a/src/dashboard/page/diffViewerPage.tsx b/src/dashboard/page/diffViewerPage.tsx index 7ed0750..2ffd377 100644 --- a/src/dashboard/page/diffViewerPage.tsx +++ b/src/dashboard/page/diffViewerPage.tsx @@ -38,7 +38,7 @@ export default function DiffViewerPage() { handlFormatPrettyJsonClick(); } else if (currentFormat === "yaml") { handlFormatPrettyYamlClick(); - } else { + } else if (currentFormat === "xml") { handlFormatPrettyXmlClick(); } @@ -46,16 +46,21 @@ export default function DiffViewerPage() { const handlFormatPrettyJsonClick = async () => { const oldResult = invoke("format_pretty_json", { sourceString: differValue[0] }).then((result: any) => { const { response_code, response_msg } = JSON.parse(result); + console.log(response_msg); if (response_code === 0) { return response_msg; - + } else { + return differValue[0]; } }); const newResult = invoke("format_pretty_json", { sourceString: differValue[1] }).then((result: any) => { const { response_code, response_msg } = JSON.parse(result); + console.log(response_msg); + if (response_code === 0) { return response_msg; - + } else { + return differValue[1]; } });; @@ -69,7 +74,8 @@ export default function DiffViewerPage() { const { response_code, response_msg } = JSON.parse(result); if (response_code === 0) { return response_msg; - + } else { + return differValue[0]; } }); const newResult = invoke("format_pretty_yaml", { sourceString: differValue[1] }).then((result: any) => { @@ -78,6 +84,9 @@ export default function DiffViewerPage() { return response_msg; } + else { + return differValue[1]; + } });; // Begin second call and store promise without waiting @@ -92,6 +101,8 @@ export default function DiffViewerPage() { console.log(response_msg); if (response_code === 0) { return response_msg; + } else { + return differValue[0]; } }); const newResult = invoke("format_pretty_xml", { sourceString: differValue[1] }).then((result: any) => { @@ -101,7 +112,10 @@ export default function DiffViewerPage() { if (response_code === 0) { return response_msg; } - });; + else { + return differValue[1]; + } + }); const finalResult = [await oldResult, await newResult]; setDifferValue(finalResult); diff --git a/src/dashboard/page/formatJsonPage.tsx b/src/dashboard/page/formatJsonPage.tsx index 4fb1eb8..a1c998a 100644 --- a/src/dashboard/page/formatJsonPage.tsx +++ b/src/dashboard/page/formatJsonPage.tsx @@ -6,6 +6,7 @@ import { Card } from "@/components/ui/card" import AceEditor from "react-ace"; import { useTheme } from "next-themes" import { useToast } from "@/components/ui/use-toast" + import "ace-builds/src-noconflict/snippets/xml"; import "ace-builds/src-noconflict/mode-json"; import "ace-builds/src-noconflict/theme-github"; @@ -74,6 +75,7 @@ export default function FormatJsonPage() { enableSnippets: false, showLineNumbers: true, tabSize: 2, + useWorker: false }} /> diff --git a/src/dashboard/page/formatXmlPage.tsx b/src/dashboard/page/formatXmlPage.tsx index 5b573d4..6f40c2b 100644 --- a/src/dashboard/page/formatXmlPage.tsx +++ b/src/dashboard/page/formatXmlPage.tsx @@ -73,6 +73,7 @@ export default function FormatXmlPage() { enableSnippets: false, showLineNumbers: true, tabSize: 2, + useWorker: false }} /> diff --git a/src/dashboard/page/formatYamlPage.tsx b/src/dashboard/page/formatYamlPage.tsx index bbe1993..9882773 100644 --- a/src/dashboard/page/formatYamlPage.tsx +++ b/src/dashboard/page/formatYamlPage.tsx @@ -73,6 +73,7 @@ export default function FormatYamlPage() { enableSnippets: false, showLineNumbers: true, tabSize: 2, + useWorker: false }} /> diff --git a/src/dashboard/page/halfFullPage.tsx b/src/dashboard/page/halfFullPage.tsx new file mode 100644 index 0000000..1c53bb9 --- /dev/null +++ b/src/dashboard/page/halfFullPage.tsx @@ -0,0 +1,57 @@ +import { Textarea } from "@/components/ui/textarea" +import { useState } from "react" +import { invoke } from "@tauri-apps/api/tauri"; +import { Button } from "@/components/ui/button" +import { useToast } from "@/components/ui/use-toast" +export function HalfToFullPage() { + const [currentInput, setCurrentInput] = useState(); + const { toast } = useToast() + + const base64Encode = async () => { + if (currentInput === undefined || currentInput === "") { + toast({ + variant: "destructive", + title: "错误信息", + description: "请输入需要转换的文本。", + }) + return; + } + const { response_code, response_msg } = JSON.parse(await invoke("to_dbc", { sourceString: currentInput })); + console.log(response_code); + console.log(response_msg); + + if (response_code === 0) { + setCurrentInput(response_msg); + } + } + const base64Decode = async () => { + if (currentInput === undefined || currentInput === "") { + toast({ + variant: "destructive", + title: "错误信息", + description: "请输入需要转换的文本。", + }) + return; + } + const { response_code, response_msg } = JSON.parse(await invoke("to_cdb", { sourceString: currentInput })); + console.log(response_code); + console.log(response_msg); + + if (response_code === 0) { + setCurrentInput(response_msg); + } + } + const handleValueChange = (e: any) => { + setCurrentInput(e.target.value); + } + return ( + <> +