Автоматизация создания установщика для Arch, доработка API

This commit is contained in:
2024-07-06 17:33:46 +07:00
parent c3c95a1d53
commit 84443bef49
16 changed files with 732 additions and 191 deletions
+3
View File
@@ -344,8 +344,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.5",
]
@@ -3212,6 +3214,7 @@ dependencies = [
"aes",
"block-modes",
"block-padding 0.3.3",
"chrono",
"hex",
"magic-crypt",
"rand 0.8.5",
+1
View File
@@ -22,6 +22,7 @@ hex = "0.4"
aes = "0.7.5"
block-modes = "0.8.1"
block-padding = "0.3.3"
chrono = "0.4.38"
[features]
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
+1 -1
View File
@@ -22,7 +22,7 @@ pub fn decrypt(key: &[u8], encrypted_data: &[u8]) -> String {
String::from_utf8(decrypted_ciphertext).unwrap() // Вывод результата в виде строки
}
/// Примеры
// Примеры
//println!("TEST ENC: {:?}", crate::aes_enc_dec::encrypt(&hex::decode(crate::multi_tcp_listener::get_token()).unwrap(), "{\"command\": \"status1\"}"));
//println!("TEST DEC: {:?}\n", crate::aes_enc_dec::decrypt(&hex::decode(crate::multi_tcp_listener::get_token()).unwrap(), &crate::aes_enc_dec::encrypt(&hex::decode(crate::multi_tcp_listener::get_token()).unwrap(), "{\"command\": \"status1\"}")));
+1 -1
View File
@@ -46,7 +46,7 @@ pub fn check_or_create_config_file(app_handle: tauri::AppHandle) {
let data = String::from(format!("{}\
\"port\": 49494,\
\"autostart\": true,\
\"autostart\": false,\
\"token\": \"{}\"\
{}", "{", token, "}"));
println!("{}", data);
+75
View File
@@ -0,0 +1,75 @@
use serde_json::Value;
use chrono::{DateTime, Local};
use crate::aes_enc_dec::encrypt;
use crate::tasks;
pub fn get_tasks_tcp(token: String) -> Vec<u8>{
encrypt(&hex::decode(token).unwrap(), tasks::get_tasks().to_string().as_str())
}
pub fn get_task_by_id_tcp(token: String, json: Value) -> Vec<u8> {
let tasks: Value = tasks::get_tasks();
let res;
if !json.get("id").is_none(){
res = encrypt(&hex::decode(token).unwrap(), tasks[json["id"].as_str().unwrap_or("")].to_string().as_str());
} else{
res = encrypt(&hex::decode(token).unwrap(), "400");
}
res
}
pub fn create_task_tcp(token: String, json: Value) -> Vec<u8> {
if json["task"].is_object(){
if json["task"]["name"].is_string(){
let current_datetime: DateTime<Local> = Local::now();
let date: String = current_datetime.format("%Y.%m.%d").to_string();
let time: String = current_datetime.format("%H:%M").to_string();
let name = json["task"]["name"].as_str().unwrap().to_string();
let description = json["task"]["description"].as_str().unwrap_or("").to_string();
let priority = json["task"]["priority"].as_str().unwrap_or("0").to_string();
encrypt(&hex::decode(token).unwrap(), tasks::add_task(date, time, name, description, priority).as_str())
} else{
encrypt(&hex::decode(token).unwrap(), "400")
}
} else{
encrypt(&hex::decode(token).unwrap(), "400")
}
}
pub fn edit_task_tcp(token: String, json: Value) -> Vec<u8> {
if json["task"].is_object(){
if json["task"]["id"].is_number(){
let id_task = json["task"]["id"].as_number().unwrap().to_string();
let name = json["task"]["name"].as_str().unwrap().to_string();
let description = json["task"]["description"].as_str().unwrap_or("").to_string();
let priority = json["task"]["priority"].as_str().unwrap_or("0").to_string();
if tasks::edit_task(id_task, name, description, priority) {
encrypt(&hex::decode(token).unwrap(), "200")
} else{
encrypt(&hex::decode(token).unwrap(), "400")
}
} else{
encrypt(&hex::decode(token).unwrap(), "400")
}
} else{
encrypt(&hex::decode(token).unwrap(), "400")
}
}
pub fn delete_task_tcp(token: String, json: Value) -> Vec<u8> {
let res;
if !json.get("id").is_none(){
if tasks::delete_task(json["id"].to_string()){
res = encrypt(&hex::decode(token).unwrap(), "200");
} else{
res = encrypt(&hex::decode(token).unwrap(), "400");
}
} else{
res = encrypt(&hex::decode(token).unwrap(), "400");
}
res
}
+27 -2
View File
@@ -6,7 +6,7 @@ use std::string::String;
use serde_json::Value;
use tauri::{AppHandle, Manager};
use crate::config_tcp;
use crate::{config_tcp, handler_commands};
use crate::enc_dec_file::decrypt_file;
use crate::aes_enc_dec::{encrypt, decrypt};
@@ -31,7 +31,7 @@ fn enc_hex_to_data(data: &str) -> String{
} // Расшифровка обёрнутых в HEX данных до строки
pub fn create_tcp_listener(app_handle: AppHandle) -> TcpListener{
fn create_tcp_listener(app_handle: AppHandle) -> TcpListener{
let path: PathBuf = [
app_handle.path_resolver().app_local_data_dir().unwrap(),
"ToDo".into(),
@@ -88,19 +88,44 @@ fn handle_connection(mut stream: TcpStream) {
let res = enc_hex_to_data(req.trim()); // Дешифрование
let json: Value = serde_json::from_str(res.as_str()).unwrap_or(serde_json::json!("")); // Попытка преобразования запроса в JSON
if json != serde_json::json!(""){
println!("JSON: {:?}", json);
println!("JSON command: {:?}", json["command"]);
match json["command"].as_str().unwrap() { // Сравнивание команд
"stop" => {
unsafe {
TCP_COMMAND = "stop";
}
let res = encrypt(&hex::decode(get_token()).unwrap(), "200");
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"status" => {
let res = encrypt(&hex::decode(get_token()).unwrap(), "200");
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"get_tasks" => {
let res = handler_commands::get_tasks_tcp(get_token());
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"get_task_by_id" => {
let res = handler_commands::get_task_by_id_tcp(get_token(), json);
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"create_task" => {
let res = handler_commands::create_task_tcp(get_token(), json);
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"edit_task" => {
let res = handler_commands::edit_task_tcp(get_token(), json);
stream.write(hex::encode(res).as_bytes()).unwrap();
},
"delete_task" => {
let res = handler_commands::delete_task_tcp(get_token(), json);
stream.write(hex::encode(res).as_bytes()).unwrap();
},
_ => {}
}
} else{
stream.write(hex::encode(encrypt(&hex::decode(get_token()).unwrap(), "400")).as_bytes()).unwrap();
}
}
},
+5 -5
View File
@@ -5,6 +5,7 @@ use std::thread;
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[path="api/multithread_tcp_listener.rs"] mod multi_tcp_listener;
#[path= "api/handler_commands.rs"] mod handler_commands;
#[path= "api/config_tcp.rs"] mod config_tcp;
#[path= "api/aes_enc_dec.rs"] mod aes_enc_dec;
@@ -24,22 +25,21 @@ fn open_api_window(app_handle: tauri::AppHandle){
.decorations(false)
.build() {
Ok(_) => {}
Err(err) => {
println!("{err}");
Err(_) => {
//println!("{err}");
}
}
});
}
fn main() {
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
tauri::Builder::default()
.setup(|app| {
let app_handle = app.handle();
if config_tcp::get_autostart(app_handle.clone()) {
thread::spawn(move || {
multi_tcp_listener::create_tcp_listener(app_handle);
});
multi_tcp_listener::start_tcp_server(app_handle);
}
Ok(())
+59 -64
View File
@@ -1,20 +1,29 @@
use std::fs::{read_to_string};
use std::path::Path;
use std::path::{Path, PathBuf};
use std::fs::File;
use serde_json::{Value, json};
use rust_fuzzy_search::fuzzy_search_best_n;
use crate::enc_dec_file::{encrypt_n_save_file, decrypt_file};
static mut PATH_CONFIG: Option<&'static str> = None;
#[tauri::command]
pub fn check_or_create_tasks_file(app_handle: tauri::AppHandle) {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
let path: PathBuf = [
app_handle.path_resolver().app_local_data_dir().unwrap(),
"ToDo".into(),
"tasks.enc".into(),
].iter().collect(); // Путь к конфиг файлу
path.set_extension("enc");
let path_str = Box::leak(Box::new(path.to_string_lossy().into_owned()));
let exist: bool = Path::new(&path).exists();
unsafe {
PATH_CONFIG = Some(path_str);
}
unsafe {
let exist: bool = Path::new(PATH_CONFIG.unwrap()).exists();
if exist{
let content = read_to_string(path);
return match content {
@@ -43,33 +52,25 @@ pub fn check_or_create_tasks_file(app_handle: tauri::AppHandle) {
Err(err) => println!("Не удалось создать файл! \n{}", err)
}
}
}
}
#[tauri::command]
pub fn get_tasks(app_handle: tauri::AppHandle) -> Value {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path);
pub fn get_tasks() -> Value {
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let data: Value = serde_json::from_str(content.as_str()).unwrap();
let res = &data["tasks"];
return res.clone();
}
}
#[tauri::command]
pub fn search_tasks(app_handle: tauri::AppHandle, value: String) -> Value {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path);
pub fn search_tasks(value: String) -> Value {
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let data: Value = serde_json::from_str(content.as_str()).unwrap();
let mut tasks = vec![];
@@ -81,9 +82,9 @@ pub fn search_tasks(app_handle: tauri::AppHandle, value: String) -> Value {
let tasks_str: Vec<&str> = tasks.iter().map(|s| &**s).collect();
let n : usize = 5;
let n: usize = 5;
let binding = value.to_lowercase();
let res : Vec<(&str, f32)> = fuzzy_search_best_n(&binding, &tasks_str, n);
let res: Vec<(&str, f32)> = fuzzy_search_best_n(&binding, &tasks_str, n);
let mut result = json!({});
@@ -101,17 +102,13 @@ pub fn search_tasks(app_handle: tauri::AppHandle, value: String) -> Value {
}
return result;
}
}
#[tauri::command]
pub fn add_task(app_handle: tauri::AppHandle, date: String, time: String, name: String, description: String, priority: String) {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path.clone());
pub fn add_task(date: String, time: String, name: String, description: String, priority: String) -> String {
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let mut data: Value = serde_json::from_str(content.as_str()).unwrap();
let pending = data.clone();
@@ -130,60 +127,58 @@ pub fn add_task(app_handle: tauri::AppHandle, date: String, time: String, name:
data["id"] = (id.as_i64().unwrap() + 1).into();
data["tasks"][id.to_string()] = task;
encrypt_n_save_file(path.into(), data.to_string());
encrypt_n_save_file(PathBuf::from(PATH_CONFIG.unwrap()), data.to_string());
return id.to_string();
}
}
#[tauri::command]
pub fn edit_task(app_handle: tauri::AppHandle, id_task: String, name: String, description: String, priority: String) {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path.clone());
pub fn edit_task(id_task: String, name: String, description: String, priority: String) -> bool{
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let mut data: Value = serde_json::from_str(content.as_str()).unwrap();
return if !data["tasks"][id_task.clone()].get("id").is_none(){
data["tasks"][id_task.clone()]["name"] = json!(name);
data["tasks"][id_task.clone()]["description"] = json!(description);
data["tasks"][id_task]["priority"] = json!(priority);
encrypt_n_save_file(path.into(), data.to_string());
encrypt_n_save_file(PathBuf::from(PATH_CONFIG.unwrap()), data.to_string());
true
} else{
false
}
}
}
#[tauri::command]
pub fn delete_task(app_handle: tauri::AppHandle, id_task: String) {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path.clone());
pub fn delete_task(id_task: String) -> bool{
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let mut data: Value = serde_json::from_str(content.as_str()).unwrap();
let tasks = data["tasks"].as_object_mut().unwrap();
let binding = tasks.clone();
for (key, value) in binding{
for (key, value) in binding {
if id_task == value["id"] {
tasks.remove(&key);
break;
}
}
data["tasks"] = json!(tasks);
encrypt_n_save_file(path.into(), data.to_string());
encrypt_n_save_file(PathBuf::from(PATH_CONFIG.unwrap()), data.to_string());
return true
}
}
false
}
}
#[tauri::command]
pub fn set_task_field(app_handle: tauri::AppHandle, id_task: String, field: String, value: String) {
let mut path = app_handle.path_resolver().app_local_data_dir().unwrap();
path.push("ToDo");
path.push("tasks");
path.set_extension("enc");
let content = decrypt_file(path.clone());
pub fn set_task_field(id_task: String, field: String, value: String) {
unsafe {
let content = decrypt_file(PathBuf::from(PATH_CONFIG.unwrap()));
let mut data: Value = serde_json::from_str(content.as_str()).unwrap();
data["tasks"][id_task][field] = json!(value);
encrypt_n_save_file(path.into(), data.to_string());
encrypt_n_save_file(PathBuf::from(PATH_CONFIG.unwrap()), data.to_string());
}
}
+28 -10
View File
@@ -8,10 +8,13 @@ import {invoke} from "@tauri-apps/api";
import ConfirmModal from "./api_components/ConfirmModal.vue";
import {listen} from "@tauri-apps/api/event";
import SettingsModal from "./api_components/SettingsModal.vue";
import PageHandler from "./api_wiki/PageHandler.vue";
const isDark = useDark();
const toggleDark = useToggle(isDark);
let wiki_open = ref(false);
let pending = ref(true);
let api_status = ref(false);
@@ -106,7 +109,11 @@ function select_input(event){
</script>
<template>
<div data-tauri-drag-region class="z-50 opacity-50 titlebar h-[30px] select-none fixed flex justify-end top-0 right-0 left-0 bg-gray-100 dark:bg-zinc-800">
<div data-tauri-drag-region class="z-50 titlebar h-[30px] select-none fixed flex justify-end top-0 right-0 left-0 bg-gray-100 dark:bg-zinc-800">
<p class="fixed left-2 top-0.5 text-lg dark:text-white">
<span v-if="!wiki_open">API</span>
<span v-else>API Wiki</span>
</p>
<div @click="appWindow.minimize()" class="titlebar-button hover:bg-gray-200 dark:hover:bg-gray-700 justify-center inline-flex w-[30px] h-[30px] items-center dark:text-white" id="titlebar-minimize">
<Icon class="" icon="mdi:window-minimize" width="20" height="20"/>
</div>
@@ -121,17 +128,17 @@ function select_input(event){
<Icon icon="line-md:loading-twotone-loop" width="96" height="96" class="text-green-500 absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]"/>
</div>
<div v-else>
<button class="absolute top-10 left-2" @click="open_settings">
<Icon icon="material-symbols:settings-outline" width="38" height="38" class="text-zinc-600 dark:text-zinc-200"/>
</button>
<button class="absolute top-10 right-2" @click="toggleDark()">
<Icon v-if="!isDark" class="group-hover:invert text-yellow-400" icon="flowbite:sun-solid" width="38" height="38"/>
<Icon v-else class="group-hover:invert text-blue-400" icon="ri:moon-fill" width="38" height="38"/>
</button>
<div v-if="!wiki_open">
<button class="absolute top-10 left-2" @click="open_settings">
<Icon icon="material-symbols:settings-outline" width="38" height="38" class="text-zinc-600 dark:text-zinc-200"/>
</button>
<div class="mt-8">
<p class="text-center dark:text-white">API</p>
<div class="grid grid-cols-1 grid-rows-1 sm:grid-cols-2 sm:grid-rows-2 mt-8 sm:mt-2 gap-2.5 dark:text-white md:mt-4 md:mx-16 lg:mt-8 lg:mx-24">
<div class="text-center shadow dark:shadow-white mx-4 sm:mx-0 sm:ml-4 rounded-lg p-1">
<div class="mt-[28vh] grid grid-cols-1 grid-rows-3 sm:grid-cols-2 sm:grid-rows-2 gap-2.5 dark:text-white md:mx-16 lg:mx-24">
<div class="text-center shadow dark:shadow-white mx-4 sm:mx-0 sm:ml-4 rounded-lg p-1 row-span-1">
<p class="mb-4">Статус</p>
<div v-if="!api_status" class="flex text-center align-middle items-center">
<Icon class="text-red-500" icon="oui:dot" width="36" height="36"/>
@@ -144,7 +151,7 @@ function select_input(event){
<button @click="stop_api" class="bg-green-500 text-white rounded-lg py-1 px-2 ml-2 hover:bg-green-600 transition-colors">Остановить</button>
</div>
</div>
<div class="grid text-center shadow dark:shadow-white mx-4 sm:mx-0 sm:mr-4 rounded-lg p-1 justify-center items-center">
<div class="grid text-center shadow dark:shadow-white mx-4 sm:mx-0 sm:mr-4 rounded-lg p-1 justify-center items-center row-start-2 sm:row-span-1">
<div v-if="api_status">
<p class="mb-2">Токен подключения</p>
<div>
@@ -158,12 +165,23 @@ function select_input(event){
</div>
<p v-else class="underline decoration-red-500 decoration-2 underline-offset-2">Нет подключения</p>
</div>
<div @click="wiki_open = true" class="cursor-pointer group mt-2 text-center shadow dark:shadow-white hover:shadow-md dark:hover:shadow-white ml-4 mr-6 sm:mr-4 rounded-lg p-1 col-start-1 col-end-3 row-start-3 sm:row-span-2">
<Icon class="mt-1 text-zinc-800 dark:text-zinc-100 mx-auto" icon="mingcute:question-line" width="48" height="48"/>
<p class="text-xl mt-1 mb-2.5 group-hover:underline">Как этим пользоваться?</p>
</div>
</div>
</div>
<div v-if="confirm_modal || settings_modal" class="bg-black w-[100vw] h-full fixed top-0 opacity-70 z-40"/>
<ConfirmModal v-if="confirm_modal" @close="confirm_modal = false" @yes="regen_token"/>
<SettingsModal v-if="settings_modal" @close="settings_modal = false" :autostart="settings_autostart" :port="settings_port"/>
</div>
<div v-else>
<button class="absolute top-10 left-2" @click="wiki_open = false">
<Icon icon="material-symbols:arrow-back" width="38" height="38" class="text-zinc-600 dark:text-zinc-200"/>
</button>
<PageHandler/>
</div>
</div>
</template>
<style>
@@ -178,7 +196,7 @@ function select_input(event){
line-height: 24px;
font-weight: 400;
background-color: rgb(246 247 248);
background-color: rgb(244 245 246);
font-synthesis: none;
text-rendering: optimizeLegibility;
@@ -188,6 +206,6 @@ function select_input(event){
}
:root.dark {
background-color: rgb(30, 30, 30);
background-color: rgb(35, 35, 35);
}
</style>
+3 -2
View File
@@ -147,7 +147,8 @@ async function open_api(){
<template>
<div data-tauri-drag-region class="z-50 opacity-50 titlebar h-[30px] select-none fixed flex justify-end top-0 right-0 left-0 bg-gray-100 dark:bg-zinc-800">
<div data-tauri-drag-region class="z-50 titlebar h-[30px] select-none fixed flex justify-end top-0 right-0 left-0 bg-gray-100 dark:bg-zinc-800">
<p class="fixed left-2 top-0.5 text-lg dark:text-white">To Do</p>
<div @click="appWindow.minimize()" class="titlebar-button hover:bg-gray-200 dark:hover:bg-gray-700 justify-center inline-flex w-[30px] h-[30px] items-center dark:text-white" id="titlebar-minimize">
<Icon class="" icon="mdi:window-minimize" width="20" height="20"/>
</div>
@@ -162,7 +163,7 @@ async function open_api(){
<Icon icon="line-md:loading-twotone-loop" width="96" height="96" class="text-green-500 absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]"/>
</div>
<div v-else>
<button class="absolute bottom-2 left-2" @click="open_api()">
<button class="absolute bottom-2 left-2 opacity-50 hover:opacity-100" @click="open_api()">
<Icon icon="icon-park-outline:earth" width="40" height="40" class="relative text-zinc-400 dark:text-zinc-300"/>
<Icon v-if="api_status" class="absolute bottom-4 left-4 text-green-500" icon="oui:dot" width="36" height="36"/>
<Icon v-else class="absolute bottom-4 left-4 text-red-500" icon="oui:dot" width="36" height="36"/>
+12
View File
@@ -0,0 +1,12 @@
<template>
<details class="group pt-1 text-md border-gray-400 open:border open:px-1 open:py-1">
<summary class="flex cursor-pointer flex-row items-center justify-between py-1 font-semibold text-gray-800 marker:[font-size:0px]">
<p class="mx-1 dark:text-gray-100 inline-flex items-center"><slot name="title"/></p>
<svg class="h-6 w-6 rotate-0 transform text-gray-400 group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path>
</svg>
</summary>
<p class="mx-2 text-gray-700 dark:text-gray-200"><slot name="body"/></p>
</details>
<hr class="border-gray-400">
</template>
+13
View File
@@ -0,0 +1,13 @@
<script setup>
import {Icon} from "@iconify/vue";
</script>
<template>
<div class="border-zinc-400 dark:border-zinc-200 border bg-zinc-300 dark:bg-zinc-700 rounded-2xl p-2 mx-1 my-2 dark:text-gray-100">
<div class="flex">
<Icon icon="material-symbols:code" width="26" height="26"/>
<p class="text-md ml-1 mt-0.5"><slot name="title"/></p>
</div>
<p class="text-lg m-1 dark:text-gray-100 whitespace-pre-wrap"><slot name="body"/></p>
</div>
</template>
+13
View File
@@ -0,0 +1,13 @@
<script setup>
import {Icon} from "@iconify/vue";
</script>
<template>
<div class="border-yellow-500 dark:border-yellow-600 border bg-yellow-50 dark:bg-gray-700 rounded-2xl p-2 m-2 text-yellow-600 dark:text-yellow-300">
<div class="flex">
<Icon icon="ic:round-warning" width="32" height="32"/>
<p class="text-xl ml-1 mt-0.5"><slot name="title"/></p>
</div>
<p class="text-lg m-1"><slot name="body"/></p>
</div>
</template>
+376
View File
@@ -0,0 +1,376 @@
<script setup>
import {ref} from "vue";
import {Icon} from "@iconify/vue";
import Warning from "../api_components/notes/Warning.vue";
import AccordionElement from "../api_components/AccordionElement.vue";
import Code from "../api_components/notes/Code.vue";
let page = ref('main');
</script>
<template>
<div class="absolute top-11 left-[50%] translate-x-[-50%] flex text-lg dark:text-white gap-6">
<div @click="page = 'main'" title="Основы" class="cursor-pointer border-b-2" :class="[page === 'main' ? 'border-b-black dark:border-b-white': 'border-b-transparent']">
<Icon icon="material-symbols:home" width="40" height="40"/>
</div>
<div @click="page = 'commands'" title="Команды" class="cursor-pointer border-b-2" :class="[page === 'commands' ? 'border-b-black dark:border-b-white': 'border-b-transparent']">
<Icon icon="ri:slash-commands-2" width="38" height="38"/>
</div>
<div @click="page = 'examples'" title="Примеры" class="cursor-pointer border-b-2" :class="[page === 'examples' ? 'border-b-black dark:border-b-white': 'border-b-transparent']">
<Icon icon="majesticons:list-box" width="40" height="40"/>
</div>
</div>
<div class="mt-24 mx-8 dark:text-white">
<div v-if="page === 'main'" class="lg:mx-12 lg:mt-32 xl:mx-24 xl:mt-48">
<p class="text-2xl ml-4 leading-9">Что это такое?</p>
<hr>
<p class="text-lg ml-2 mt-2 leading-8">
<span class="font-bold">API</span>(application programming interface) - описание способов, взаимодействия компьютерной программы с другими.
API (интерфейс программирования приложения) упрощает процесс программирования при создании приложений, предоставляя только объекты или действия, необходимые разработчику.
</p>
<Warning>
<template v-slot:title>Внимание!</template>
<template v-slot:body>
Эта программа предоставляет API с защищённым соединением с помощью AES256.
Подключение без защиты не удастся. Возможно будет добавлена поддержка незащищённого соединения.
</template>
</Warning>
<hr>
<p class="text-lg ml-2 mt-2 leading-10">
<span class="flex">Доступные команды описаны на вкладке "Команды" - <Icon class="ml-2" icon="ri:slash-commands-2" width="38" height="38"/></span>
<span class="flex">Примеры описаны на вкладке "Примеры" - <Icon class="ml-2" icon="majesticons:list-box" width="40" height="40"/></span>
</p>
</div>
<div v-if="page === 'commands'" class="lg:mx-12 lg:mt-32 xl:mx-24 xl:mt-48">
<p class="text-2xl ml-4 leading-9">Доступные команды</p>
<div class="px-3 mx-6 mt-0 grid grid-cols-1 gap-y-1">
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-blue-400 rounded-lg py-1 px-2 mr-2">GET</div>
status
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для проверки статуса сервера</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "status" <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
200 - сервер работает <br>
*нет доступа* - сервер не работает <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-blue-400 rounded-lg py-1 px-2 mr-2">GET</div>
get_tasks
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для получения всех задач</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "get_tasks" <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
JSON - список задач <br>
400 - неверные параметры запроса <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-blue-400 rounded-lg py-1 px-2 mr-2">GET</div>
get_task_by_id
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для получения задачи по id</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "get_task_by_id" <br>
&emsp;"id": "id задачи" <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span><br>
id <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;id задачи <span class="opacity-80">[String]</span><br>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
JSON - задача <br>
null - задача не найдена <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-green-500 rounded-lg py-1 px-2 mr-2">POST</div>
create_task
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для создания задачи</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "get_task_by_id" <br>
&emsp;"task": { <br>
&emsp;&emsp;"name": "Новая задача" <br>
&emsp;&emsp;"description": "Описание" <br>
&emsp;&emsp;"priority": "4" <br>
&emsp;} <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span><br>
task <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;задача <span class="opacity-80">[JSON Object]</span><br>
&ensp;name <span class="text-red-500 text-sm">*обязательно</span><br>
&ensp;&nbsp;название задачи <span class="opacity-80">[String]</span><br>
&ensp;description<br>
&ensp;&nbsp;описание задачи <span class="opacity-80">[String]</span><br>
&ensp;priority<br>
&ensp;&nbsp;проритет задачи (0-10) <span class="opacity-80">[String]</span><br>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
String - id, созданной задачи <br>
400 - неверный параметр запроса <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-yellow-500 rounded-lg py-1 px-2 mr-2">PUT</div>
edit_task
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для изменения задачи по id</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "edit_task" <br>
&emsp;"task": { <br>
&emsp;&emsp;"id": "2" <br>
&emsp;&emsp;"name": "Новая задача" <br>
&emsp;&emsp;"description": "Описание" <br>
&emsp;&emsp;"priority": "4" <br>
&emsp;} <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span><br>
task <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;задача <span class="opacity-80">[JSON Object]</span><br>
&ensp;id <span class="text-red-500 text-sm">*обязательно</span><br>
&ensp;&nbsp;id задачи <span class="opacity-80">[String]</span><br>
&ensp;name <span class="text-red-500 text-sm">*обязательно</span><br>
&ensp;&nbsp;название задачи <span class="opacity-80">[String]</span><br>
&ensp;description<br>
&ensp;&nbsp;описание задачи <span class="opacity-80">[String]</span><br>
&ensp;priority<br>
&ensp;&nbsp;проритет задачи (0-10) <span class="opacity-80">[String]</span><br>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
200 - задача изменена <br>
400 - неверный параметр запроса <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-red-400 rounded-lg py-1 px-2 mr-2">DELETE</div>
delete_task
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для удаления задачи по id</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "delete_task" <br>
&emsp;"id": "id задачи" <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span><br>
id <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;id задачи <span class="opacity-80">[String]</span><br>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
200 - задача удалена <br>
400 - неверный параметр запроса <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
<AccordionElement>
<template v-slot:title>
<div class="text-white bg-green-500 rounded-lg py-1 px-2 mr-2">POST</div>
stop
</template>
<template v-slot:body>
<span class="ml-6 text-lg">Функция для выключения API</span>
<Code>
<template v-slot:title>Структура запроса</template>
<template v-slot:body>
{ <br>
&emsp;"command": "stop" <br>
} <br>
</template>
</Code>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Параметры</p>
<hr>
<div class="mx-3">
<div class="my-3">
<p>
command <span class="text-red-500 text-sm">*обязательно</span><br>
&nbsp;название команды <span class="opacity-80">[String]</span><br>
</p>
</div>
</div>
</div>
<div class="border border-zinc-400 rounded-xl p-2 mx-1 my-2">
<p class="text-lg">Результат</p>
<hr>
<div class="mx-3">
<div class="my-2">
<p>
200 - API выключается <br>
</p>
</div>
</div>
</div>
</template>
</AccordionElement>
</div>
</div>
</div>
</template>
<style scoped>
</style>
+9 -6
View File
@@ -1,18 +1,17 @@
<script setup>
import {invoke} from "@tauri-apps/api";
import {ref} from "vue";
import {Icon} from "@iconify/vue";
let name = "";
let description = "";
let priority = 0;
let priority = ref(0);
let error = ref(" ");
async function create_task(){
if (name.replace(/ /g,'') === ""){
error.value = "Название задачи не может быть пустым!";
} else if(priority < 0 || priority > 10){
error.value = "Приоритет не может быть меньше 0 или больше 10";
} else{
let nowDateTime = new Date();
let date = nowDateTime.getFullYear() + "." + ('0' + (nowDateTime.getMonth()+1)).slice(-2) + '.'
@@ -24,7 +23,7 @@ async function create_task(){
time: time,
name: name,
description: description,
priority: priority.toString()
priority: priority.value.toString()
});
location.reload();
@@ -70,8 +69,12 @@ async function create_task(){
<div class="flex items-center justify-between">
<label for="priority" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Приоритет</label>
</div>
<div class="mt-2">
<input v-model="priority" type="number" step="1" id="priority" name="priority" class="px-2 py-1.5 block w-48 rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
<div class="mt-2 flex gap-3 ml-2">
<Icon @click="priority = 0" :class="[priority === 0 ? 'opacity-100' : 'opacity-50']" class="dark:text-white text-gray-500 cursor-pointer" icon="streamline:signal-none-solid" width="26" height="26"/>
<Icon @click="priority = 1" :class="[priority > 0 && priority < 4 ? 'opacity-100' : 'opacity-50']" class="text-orange-300 cursor-pointer" icon="streamline:signal-low-solid" width="26" height="26"/>
<Icon @click="priority = 5" :class="[priority >= 4 && priority < 7 ? 'opacity-100' : 'opacity-50']" class="text-amber-500 cursor-pointer" icon="streamline:signal-medium-solid" width="26" height="26"/>
<Icon @click="priority = 8" :class="[priority >= 7 && priority < 9 ? 'opacity-100' : 'opacity-50']" class="text-orange-600 cursor-pointer" icon="streamline:signal-full-solid" width="26" height="26"/>
<Icon @click="priority = 10" :class="[priority >= 9 ? 'opacity-100' : 'opacity-50']" class="text-red-500 cursor-pointer" icon="heroicons-solid:exclamation" width="32" height="32"/>
</div>
</div>
</div>
+10 -4
View File
@@ -1,5 +1,7 @@
<script setup>
import {invoke} from "@tauri-apps/api";
import {Icon} from "@iconify/vue";
import {ref} from "vue";
const props = defineProps({
task_id: String,
@@ -10,14 +12,14 @@ const props = defineProps({
let name = props.task_name;
let description = props.task_description;
let priority = parseInt(props.task_priority);
let priority = ref(parseInt(props.task_priority));
async function send_edited_task(){
await invoke('edit_task', {
idTask: props.task_id,
name: name,
description: description,
priority: priority.toString()
priority: priority.value.toString()
}).then(() => location.reload());
}
</script>
@@ -60,8 +62,12 @@ async function send_edited_task(){
<div class="flex items-center justify-between">
<label for="priority" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-200">Приоритет</label>
</div>
<div class="mt-2">
<input v-model="priority" type="number" required min="0" max="10" step="1" id="priority" name="priority" class="px-2 py-1.5 block w-48 rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-inset sm:text-sm sm:leading-6" />
<div class="mt-2 flex gap-3 ml-2">
<Icon @click="priority = 0" :class="[priority === 0 ? 'opacity-100' : 'opacity-50']" class="dark:text-white text-gray-500 cursor-pointer" icon="streamline:signal-none-solid" width="26" height="26"/>
<Icon @click="priority = 1" :class="[priority > 0 && priority < 4 ? 'opacity-100' : 'opacity-50']" class="text-orange-300 cursor-pointer" icon="streamline:signal-low-solid" width="26" height="26"/>
<Icon @click="priority = 5" :class="[priority >= 4 && priority < 7 ? 'opacity-100' : 'opacity-50']" class="text-amber-500 cursor-pointer" icon="streamline:signal-medium-solid" width="26" height="26"/>
<Icon @click="priority = 8" :class="[priority >= 7 && priority < 9 ? 'opacity-100' : 'opacity-50']" class="text-orange-600 cursor-pointer" icon="streamline:signal-full-solid" width="26" height="26"/>
<Icon @click="priority = 10" :class="[priority >= 9 ? 'opacity-100' : 'opacity-50']" class="text-red-500 cursor-pointer" icon="heroicons-solid:exclamation" width="32" height="32"/>
</div>
</div>
</div>