use std::{env, fs};
use std::fs::{create_dir_all, File};
use std::io::Write;
use std::path::{Path, PathBuf};
use df_cache::Cache;
use df_db::db::{ModeDb, Request};
use df_fields::Field;
use df_kafka::Kafka;
use json::{array, JsonValue, object};
use crate::tests::test::test::TestAction;
use crate::tests::test::TestModel;
use crate::tests::TestPlugin;
pub mod tests;
pub fn plugins(name: &str) -> Box<dyn Plugin> {
match name {
_ => Box::new(TestPlugin {})
}
}
pub fn models(name: &str) -> Box<dyn Model> {
match name {
_ => Box::new(TestModel {})
}
}
pub fn actions(name: &str) -> Box<dyn Action> {
match name {
_ => Box::new(TestAction { model: TestModel {} })
}
}
pub fn plugin_create(path: &str, plugin: &str, plugin_title: &str, model: &str, model_title: &str, action: &str, action_title: &str) {
let root_path = PathBuf::from(path);
let plugin_path = root_path.join("plugin");
let plugin_path = plugin_path.join(plugin);
create_dir_all(plugin_path.as_os_str()).expect("创建目录失败");
let plugin_mod_path = plugin_path.join("mod.rs");
if !plugin_mod_path.is_file() {
let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let temp_plugin_mod_path = temp_plugin_mod_path.join("temp").join("plugin");
let temp_plugin_mod_data = fs::read_to_string(temp_plugin_mod_path).unwrap();
let plugin_1 = plugin[0..=0].to_uppercase();
let plugin_2 = plugin[1..].to_lowercase();
let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{plugin}}", &*format!("{}{}", plugin_1, plugin_2));
let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{title}}", plugin_title);
fs::write(plugin_mod_path, temp_plugin_mod_data).expect("写入插件mod错误");
}
if model != "" {
let model_path = plugin_path.join(model);
create_dir_all(model_path.as_os_str()).expect("创建模型目录失败");
let model_1 = model[0..=0].to_uppercase();
let model_2 = model[1..].to_lowercase();
let model_mod_path = model_path.join("mod.rs");
if !model_mod_path.is_file() {
let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let temp_model_mod_path = temp_plugin_mod_path.join("temp").join("model");
let temp_model_mod_data = fs::read_to_string(temp_model_mod_path).unwrap();
let temp_model_mod_data = temp_model_mod_data.replace("{{model}}", &*format!("{}{}", model_1, model_2));
let temp_model_mod_data = temp_model_mod_data.replace("{{plugin_model}}", &*format!("{}_{}", plugin, model));
let temp_model_mod_data = temp_model_mod_data.replace("{{title}}", model_title);
fs::write(model_mod_path, temp_model_mod_data).expect("写入模型mod错误");
}
if action != "" {
let action_path = model_path.join(format!("{}.rs", action));
if !action_path.is_file() {
let temp_action_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let temp_action_mod_path = temp_action_mod_path.join("temp").join("action");
let temp_action_mod_data = fs::read_to_string(temp_action_mod_path).unwrap();
let action_1 = action[0..=0].to_uppercase();
let action_2 = action[1..].to_lowercase();
let temp_action_mod_data = temp_action_mod_data.replace("{{action}}", &*format!("{}{}", action_1, action_2));
let temp_action_mod_data = temp_action_mod_data.replace("{{api}}", &*format!("{}.{}.{}", plugin, model, action));
let temp_action_mod_data = temp_action_mod_data.replace("{{model}}", &*format!("{}{}", model_1, model_2));
let temp_action_mod_data = temp_action_mod_data.replace("{{model_a}}", &*format!("{}", model));
let temp_action_mod_data = temp_action_mod_data.replace("{{plugin}}", &*format!("{}", plugin));
let temp_action_mod_data = temp_action_mod_data.replace("{{title}}", action_title);
fs::write(action_path, temp_action_mod_data).expect("写入动作文件错误");
}
}
}
}
pub trait Plugin {
fn model(&mut self, name: &str) -> Box<dyn Model>;
fn title(&mut self) -> String;
}
pub trait Model {
fn version(&mut self) -> String {
return "0.0.1".to_string();
}
fn table(&mut self) -> String;
fn title(&mut self) -> String;
fn fields(&mut self) -> JsonValue;
fn unique(&mut self) -> Vec<String> {
return vec![];
}
fn index(&mut self) -> Vec<Vec<String>> {
return vec![];
}
fn primary_key(&mut self) -> String {
return "id".to_string();
}
fn auto(&mut self) -> bool {
return false;
}
fn json(&mut self) -> ModelTable {
ModelTable {
version: self.version(),
table: self.table(),
title: self.title(),
primary_key: self.primary_key(),
auto: self.auto(),
unique: self.unique(),
index: self.index(),
fields: self.fields(),
}
}
fn create_json_file(&mut self, path: &str) -> bool {
let json = self.json();
let o = Path::new(path);
if !o.is_dir() {
fs::create_dir(path).unwrap();
}
env::set_current_dir(path).unwrap();
let dir = env::current_dir().unwrap();
let version = self.version();
let version = version.replace(".", "_");
let dir = dir.join(format!("{}_{}.json", self.table(), version));
let mut f = File::create(dir.to_str().unwrap()).unwrap();
match f.write_all(json.to_string().as_bytes()) {
Ok(_) => true,
Err(_) => false
}
}
fn action(&mut self, name: &str) -> Box<dyn Action>;
fn table_fields(&mut self) -> JsonValue {
let mut params = object! {};
params["load"] = df_fields::select::Radio::new(true, "load", "加载内容", vec!["col", "data"], "col").field();
params["page"] = df_fields::int::Int::new(true, "page", "页数", 15, 1).field();
params["limit"] = df_fields::int::Int::new(true, "limit", "记录数", 10, 25).field();
params["where"] = df_fields::text::Json::new(false, "where", "条件", object! {}).field();
params["filter"] = df_fields::text::Text::new(false, "filter", "模糊搜索", "").field();
return params;
}
fn tables(&mut self, request: JsonValue, mut tools: Tools, fields: Vec<&str>, query_fields: Vec<&str>, filter_fields: Vec<&str>) -> JsonValue {
let load = request["load"].as_str().unwrap();
let page = request["page"].as_i32().unwrap();
let limit = request["limit"].as_i32().unwrap();
let wheres = request["where"].clone();
let filter = request["filter"].to_string();
let data = {
let db = tools.db.table(self.table().as_str());
if filter_fields.len() > 0 && filter != "" {
db.where_or(filter_fields.join("|").as_str(), "like", format!("%{}%", filter).into());
}
if fields.len() > 0 {
db.field(fields.join(",").as_str().clone());
}
for item in wheres.members() {
db.where_and(item[0].as_str().unwrap(), item[1].as_str().unwrap(), item[2].clone());
}
db.page(page.clone(), limit.clone()).select()
};
let total = {
let db = tools.db.table(self.table().as_str());
if filter_fields.len() > 0 && filter != "" {
db.where_or(filter_fields.join("|").as_str(), "like", format!("%{}%", filter).into());
}
for item in wheres.members() {
db.where_and(item[0].as_str().unwrap(), item[1].as_str().unwrap(), item[2].clone());
}
db.count()
};
let mut table = object! {};
table["total_page"] = JsonValue::from((total as f64 / limit as f64).ceil() as i64);
table["total_data"] = total.into();
table["data"] = data.clone();
match load {
"col" => {
table["col"] = self.columns(fields.clone());
table["query_fields"] = self.query_fields(query_fields.clone());
table["filter_title"] = self.filter_title(filter_fields.clone()).into();
}
_ => {}
}
table
}
fn columns(&mut self, fields: Vec<&str>) -> JsonValue {
let columns = self.fields();
let mut data = array![];
for (key, field) in columns.entries() {
if fields.contains(&key) || fields.len() == 0 {
let mut row = field.clone();
row["name"] = field["field"].clone();
row["label"] = field["title"].clone();
row["align"] = "center".into();
row["sortable"] = match field["mode"].as_str().unwrap() {
"int" | "float" => {
true.into()
}
_ => {
false.into()
}
};
data.push(row.clone()).unwrap();
}
}
data
}
fn query_fields(&mut self, fields: Vec<&str>) -> JsonValue {
let columns = self.fields();
let mut data = array![];
for (key, field) in columns.entries() {
if fields.contains(&key) {
let mut row = field.clone();
row["require"] = JsonValue::from(false);
data.push(row.clone()).unwrap();
}
}
data
}
fn filter_title(&mut self, fields: Vec<&str>) -> String {
let columns = self.fields();
let mut data = vec![];
for (key, field) in columns.entries() {
if fields.contains(&key) {
data.push(field["title"].as_str().unwrap());
}
}
format!("搜索 {}", data.join(" "))
}
fn btn_data(&mut self, title: &str, mut action: Box<dyn Action>, mode: BtnMode, color: BtnColor, match_condition: Vec<Vec<&str>>) -> JsonValue {
let mut btn = object! {};
if title.is_empty() {
btn["title"] = action.title().into();
} else {
btn["title"] = title.into();
}
btn["api"] = action.name().into();
let mut params = array![];
for (_, item) in action.params().entries() {
params.push(item.clone()).unwrap();
}
btn["params"] = JsonValue::from(params);
btn["color"] = JsonValue::from(color.from());
btn["mode"] = JsonValue::from(mode.from());
btn["match_condition"] = match_condition.into();
return btn;
}
}
pub enum BtnColor {
Red,
Blue,
Yellow,
}
impl BtnColor {
fn from(self) -> &'static str {
match self {
BtnColor::Red => "red",
BtnColor::Blue => "blue",
BtnColor::Yellow => "yellow",
}
}
}
pub enum BtnMode {
Form,
Url,
Api,
}
impl BtnMode {
fn from(self) -> &'static str {
match self {
BtnMode::Form => "form",
BtnMode::Url => "url",
BtnMode::Api => "api",
}
}
}
pub trait Action {
fn title(&mut self) -> String;
fn name(&mut self) -> String;
fn token(&mut self) -> bool { true }
fn public(&mut self) -> bool { true }
fn extend(&mut self) -> Vec<&str> {
vec![]
}
fn params(&mut self) -> JsonValue { object! {} }
fn _check(&mut self, mut request: JsonValue) -> (bool, String, JsonValue) {
let params = self.params();
let mut new_request = object! {};
for (key, field) in params.entries() {
if request[key].is_null() && field["require"].as_bool().unwrap() {
return (false, format!("缺少参数 {}:{}", key, field["title"]), request);
}
if request[key].is_empty() && field["require"].as_bool().unwrap() {
request[key] = field["def"].clone().into()
}
new_request[key] = request[key].clone();
}
return (true, format!("验证通过"), new_request);
}
fn run(&mut self, header: JsonValue, request: JsonValue, tools: Tools) -> Response {
let (state, msg, request) = self._check(request.clone());
if !state {
return self.fail(msg.as_str().clone());
}
return self.index(header, request, tools);
}
fn index(&mut self, header: JsonValue, request: JsonValue, tools: Tools) -> Response;
fn success(&mut self, data: JsonValue, msg: &str) -> Response {
Response {
code: 0,
data,
msg: msg.to_string(),
}
}
fn fail(&mut self, msg: &str) -> Response {
Response {
code: -1,
data: object! {},
msg: msg.to_string(),
}
}
fn login(&mut self, msg: &str) -> Response {
Response {
code: 1000,
data: object! {},
msg: msg.to_string(),
}
}
}
pub struct Tools {
pub db: ModeDb,
pub cache: Cache,
pub kafka: Kafka,
}
pub struct Response {
code: i32,
data: JsonValue,
msg: String,
}
impl Response {
pub fn to_json(self) -> JsonValue {
let mut res = object! {};
res["code"] = self.code.into();
res["data"] = self.data.into();
res["msg"] = self.msg.into();
res
}
pub fn success(data: JsonValue) -> Self {
Self {
code: 0,
data,
msg: "成功".to_string(),
}
}
pub fn fail(msg: &str) -> Self {
Self {
code: -1,
data: object! {},
msg: msg.to_string(),
}
}
pub fn login() -> Self {
Self {
code: 1000,
data: object! {},
msg: "请登录".to_string(),
}
}
}
pub struct ModelTable {
pub version: String,
pub table: String,
pub title: String,
pub primary_key: String,
pub auto: bool,
pub unique: Vec<String>,
pub index: Vec<Vec<String>>,
pub fields: JsonValue,
}
impl ModelTable {
pub fn to_string(self) -> String {
let data = object! {
version:self.version,
table:self.table,
title:self.title,
primary_key:self.primary_key,
auto:self.auto,
unique:self.unique,
index:self.index,
fields:self.fields
};
data.to_string()
}
pub fn parse(mut data: JsonValue) -> ModelTable {
let mut unique = vec![];
for item in 0..data["unique"].len() {
let str = data["unique"][item].clone();
unique.push(str.to_string());
}
let mut index = vec![];
for item in data["index"].members_mut() {
let mut row = vec![];
for col in item.members_mut() {
row.push(col.to_string());
}
if row.len() > 0 {
index.push(row);
}
}
Self {
version: data["version"].to_string(),
table: data["table"].to_string(),
title: data["title"].to_string(),
primary_key: data["primary_key"].to_string(),
auto: data["auto"].as_bool().unwrap(),
unique,
index,
fields: data["fields"].clone(),
}
}
}