1use crate::request::{ContentType, Method, Request};
2use crate::{CONFIG, GLOBAL_DATA, PLUGIN_TOOLS};
3use crate::{ApiResponse, Tools};
4use br_fields::Field;
5use json::{array, object, JsonValue};
6use std::any::type_name;
7use std::collections::HashMap;
8use crate::tables::Tables;
9
10pub trait Action {
12 fn _name(&self) -> String {
14 type_name::<Self>().rsplit("::").next().unwrap().to_lowercase()
15 }
16 fn module_name(&self) -> String {
18 let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
19 let plugin = t[2].to_lowercase();
20 let module = t[3].to_lowercase();
21 format!("{plugin}.{module}")
22 }
23 fn addon_name(&self) -> String {
25 let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
26 t[2].to_lowercase()
27 }
28 fn api(&self) -> String {
30 let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
31 let plugin = t[2].to_lowercase();
32 let module = t[3].to_lowercase();
33 let action = t[4].to_lowercase();
34 format!("{plugin}.{module}.{action}")
35 }
36 fn token(&self) -> bool {
38 true
39 }
40
41 fn sort(&self) -> usize {
42 99
43 }
44 fn title(&self) -> &'static str;
46 fn description(&self) -> &'static str {
48 ""
49 }
50 fn path(&self) -> &'static str {
52 ""
53 }
54 fn query(&self) -> JsonValue {
56 object! {}
57 }
58 fn tags(&self) -> &'static [&'static str] {
60 &[]
61 }
62 fn icon(&self) -> &'static str {
63 ""
64 }
65 fn public(&self) -> bool {
67 true
68 }
69 fn auth(&self) -> bool {
71 true
72 }
73 fn interface_type(&self) -> InterfaceType {
75 InterfaceType::API
76 }
77 fn method(&mut self) -> Method {
79 Method::Post
80 }
81 fn content_type(&mut self) -> ContentType {
83 ContentType::Json
84 }
85 fn params_check(&mut self) -> bool {
87 true
88 }
89 fn params(&mut self) -> JsonValue {
91 object! {}
92 }
93 fn success(&mut self) -> ApiResponse {
95 let mut data = object! {};
96 data["code"] = br_fields::int::Int::new(true, "code", "编号", 10, 0).example(0.into()).swagger();
97 data["message"] = br_fields::str::Str::new(true, "message", "成功消息", 256, "").example("成功".into()).swagger();
98 data["data"] = br_fields::text::Json::new(true, "data", "返回数据", object! {}).swagger();
99 data["success"] = br_fields::int::Switch::new(true, "success", "成功状态", true).example(true.into()).swagger();
100 data["timestamp"] = br_fields::datetime::Timestamp::new(true, "timestamp", "时间戳", 0, 0.0).swagger();
101 ApiResponse::success(data, "请求成功")
102 }
103 fn error(&mut self) -> ApiResponse {
105 let mut data = object! {};
106 data["code"] = br_fields::int::Int::new(true, "code", "编号", 10, 1000).example(1000.into()).swagger();
107 data["message"] = br_fields::str::Str::new(true, "message", "错误消息", 256, "").example("失败".into()).swagger();
108 data["data"] = br_fields::text::Json::new(true, "data", "返回数据", object! {}).swagger();
109 data["success"] = br_fields::int::Switch::new(true, "success", "成功状态", false).example(false.into()).swagger();
110 data["timestamp"] = br_fields::datetime::Timestamp::new(true, "timestamp", "时间戳", 0, 0.0).swagger();
111 ApiResponse::error(data, "请求失败")
112 }
113 fn run(&mut self, mut request: Request) -> Result<ApiResponse, ApiResponse> {
115 if self.public() && !self.method().str().is_empty() && self.method().str().to_lowercase() != request.method.str().to_lowercase() {
116 return Err(ApiResponse::fail(
117 -1,
118 format!(
119 "Request type error: Actual [{}] Expected [{}]",
120 request.method.str(),
121 self.method().str()
122 ).as_str(),
123 ));
124 }
125 let params = self.params().clone();
126 if self.params_check() {
127 self.check(&mut request.query.clone(), self.query().clone())?;
128 self.check(&mut request.body, params)?;
129 }
130 let res = self.index(request.clone());
131 match res.success {
132 true => Ok(res),
133 false => Err(res),
134 }
135 }
136 fn check(&mut self, request: &mut JsonValue, params: JsonValue) -> Result<(), ApiResponse> {
138 let req = request.clone();
139 for (name, _) in req.entries() {
140 if !params.has_key(name) {
141 request.remove(name);
142 }
143 }
144 for (name, field) in params.entries() {
145 let require = field["require"].as_bool().unwrap_or(false);
146 let title = field["title"].as_str().unwrap_or("");
147 if request.has_key(name) {
148 match field["mode"].as_str().unwrap() {
150 "key" => {
151 if !request[name].is_string() {
152 return Err(ApiResponse::fail(
153 900_001,
154 format!(
155 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
156 name, field["mode"]
157 ).as_str(),
158 ));
159 }
160 if require && request[name].is_empty() {
161 return Err(ApiResponse::fail(
162 900014,
163 format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
164 ));
165 }
166 }
167 "text" | "table" | "tree" => {
168 if !request[name].is_string() {
169 return Err(ApiResponse::fail(
170 900002,
171 format!(
172 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
173 name, field["mode"]
174 ).as_str(),
175 ));
176 }
177 if require && request[name].is_empty() {
178 return Err(ApiResponse::fail(
179 900002,
180 format!("{title} 必填").as_str(),
181 ));
182 }
183 }
184 "file" => {
185 if !request[name].is_array() && !request[name].is_string() {
186 return Err(ApiResponse::fail(
187 900003,
188 format!("参数 [{}] 数据类型应为[{}]", name, field["mode"]).as_str(),
189 ));
190 }
191 if require && request[name].is_empty() {
192 return Err(ApiResponse::fail(
193 900002,
194 format!("{title} 必填").as_str(),
195 ));
196 }
197 }
198 "int" => {
199 if require && request[name].to_string().is_empty() {
200 return Err(ApiResponse::fail(
201 900_002,
202 format!("{title} 必填").as_str(),
203 ));
204 }
205 if !request[name].to_string().is_empty() {
206 match request[name].to_string().parse::<i64>() {
207 Ok(_) => {}
208 Err(_) => {
209 return Err(ApiResponse::fail(
210 900013,
211 format!(
212 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
213 name, field["mode"]
214 ).as_str(),
215 ));
216 }
217 }
218 }
219 }
220 "timestamp" => {
221 if require && request[name].to_string().is_empty() {
222 return Err(ApiResponse::fail(
223 900002,
224 format!("{title} 必填").as_str(),
225 ));
226 }
227 if !request[name].to_string().is_empty() {
228 if request[name].is_array() && request[name].len() == 2 {
229 for item in request[name].members() {
231 match item.to_string().parse::<f64>() {
232 Ok(_) => {}
233 Err(_) => {
234 return Err(ApiResponse::fail(
235 900_013,
236 format!(
237 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
238 name, field["mode"]
239 ).as_str(),
240 ));
241 }
242 }
243 }
244 } else {
245 match request[name].to_string().parse::<f64>() {
246 Ok(_) => {}
247 Err(_) => {
248 return Err(ApiResponse::fail(
249 900013,
250 format!(
251 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
252 name, field["mode"]
253 ).as_str(),
254 ));
255 }
256 }
257 }
258 }
259 }
260 "float" => {
261 if require && request[name].to_string().is_empty() {
262 return Err(ApiResponse::fail(
263 900002,
264 format!("{title} 必填").as_str(),
265 ));
266 }
267 if !request[name].to_string().is_empty() {
268 match request[name].to_string().parse::<f64>() {
269 Ok(_) => {}
270 Err(_) => {
271 return Err(ApiResponse::fail(
272 900023,
273 format!(
274 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
275 name, field["mode"]
276 ).as_str(),
277 ));
278 }
279 }
280 }
281 }
282 "string" | "url" | "time" | "code" | "pass" | "email" | "location" | "color" | "date" | "barcode" | "datetime" | "editor" | "tel" => {
283 if !request[name].is_string() {
284 return Err(ApiResponse::fail(
285 -1,
286 format!(
287 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
288 name, field["mode"]
289 ).as_str(),
290 ));
291 }
292 if require && request[name].is_empty() {
293 return Err(ApiResponse::fail(
294 900004,
295 format!("{title} 必填").as_str(),
296 ));
297 }
298 }
299 "dict" => {
300 if require && request[name].is_empty() {
301 return Err(ApiResponse::fail(
302 900005,
303 format!("{title} 必填").as_str(),
304 ));
305 }
306 }
307 "switch" => {
308 match request[name].to_string().parse::<bool>() {
309 Ok(e) => {
310 request[name] = e.into();
311 }
312 Err(_) => {
313 return Err(ApiResponse::fail(
314 -1,
315 format!("请求参数数据类型错误: 参数 [{name}] 数据类型应为[{}]", field["mode"]).as_str(),
316 ));
317 }
318 }
319 }
320 "select" => {
321 if !request[name].is_array() && !request[name].is_string() {
322 return Err(ApiResponse::fail(
323 -1,
324 format!(
325 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
326 name, field["mode"]
327 ).as_str(),
328 ));
329 }
330 let value = if request[name].is_array() {
331 request[name].members().map(|m| m.to_string()).collect::<Vec<String>>()
332 } else {
333 request[name].to_string().split(",").map(|x| x.to_string()).collect::<Vec<String>>()
334 };
335 let option = field["option"].members().map(|m| m.as_str().unwrap_or("")).collect::<Vec<&str>>();
336
337 let require = field["require"].as_bool().unwrap();
338 for item in value.clone() {
339 if !option.contains(&&*item.clone()) && (item.is_empty() && require) {
340 let option = field["option"].members().map(|m| m.as_str().unwrap_or("")).collect::<Vec<&str>>().join(",");
341 return Err(ApiResponse::fail(-1, format!("请求参数选项错误: 参数 [{item}] 数据类型应为[{option}]之内").as_str()));
342 }
343 }
344 request[name] = value.into();
345 }
346 "radio" => {
347 if !request[name].is_string() {
348 return Err(ApiResponse::fail(
349 -1,
350 format!(
351 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}] 实际为[{}]",
352 name, field["mode"], request[name]
353 ).as_str(),
354 ));
355 }
356 let option = field["option"].members().map(|m| m.as_str().unwrap_or("")).collect::<Vec<&str>>().join(",");
357 if request[name].is_string() && !field["option"].contains(request[name].as_str().unwrap_or(""))
358 {
359 return Err(ApiResponse::fail(
360 -1,
361 format!(
362 "请求参数选项错误: 参数 [{}] 数据 [{}] 应为 [{}] 之一",
363 name, request[name], option
364 ).as_str(),
365 ));
366 }
367 }
368 "array" | "polygon" => {
369 if !request[name].is_array() {
370 return Err(ApiResponse::fail(
371 900_009,
372 format!(
373 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
374 name, field["mode"]
375 ).as_str(),
376 ));
377 }
378 if require && request[name].is_empty() {
379 return Err(ApiResponse::fail(
380 900010,
381 format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
382 ));
383 }
384 }
385 "object" => {
386 if !request[name].is_object() {
387 return Err(ApiResponse::fail(
388 900009,
389 format!(
390 "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
391 name, field["mode"]
392 ).as_str(),
393 ));
394 }
395 if require && request[name].is_empty() {
396 return Err(ApiResponse::fail(
397 900006,
398 format!("{title} 必填").as_str(),
399 ));
400 }
401 }
402 _ => {
403 println!("检查未知类型: {}", field["mode"])
404 }
405 }
406 } else {
407 if require {
408 return Err(ApiResponse::fail(
409 900007,
410 format!("{title} 必填").as_str(),
411 ));
412 }
413 request[name] = field["def"].clone();
414 }
415 }
416 Ok(())
417 }
418 fn index(&mut self, request: Request) -> ApiResponse;
420 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
421 fn table_select(
422 &mut self,
423 request: JsonValue,
424 table_name: &str,
425 fields: Vec<&str>,
426 ) -> JsonValue {
427 self.table().main_select_fields(table_name, fields).params(request.clone()).get_table_select()
428 }
429 fn params_table_tree_select(&mut self, mut params: JsonValue) -> JsonValue {
431 params["ids"] = br_fields::text::Array::new(false, "ids", "加载已选中数据", array![]).field();
432 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
433 params["pid"] = br_fields::str::Str::new(false, "pid", "上级ID", 20, "").example("".into()).field();
434 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
435 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
436 params["params"] = br_fields::text::Object::new(false, "params", "关联数据参数", object! {}).example(object! {}).field();
437 params
438 }
439 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
440 fn table_tree_select(
441 &mut self,
442 request: JsonValue,
443 table_name: &str,
444 pid_field: &str,
445 label_field: &str,
446 fields: Vec<&str>,
447 ) -> JsonValue {
448 let ids = request["ids"].clone();
449 let search = request["search"].as_str().unwrap_or("");
450 let pid_id = request["pid"].as_str().unwrap_or("id");
451
452 let where_or = request["where_or"].clone();
453 let where_and = request["where_and"].clone();
454
455 let mut tools = self.tools();
456 let db = tools.db.table(table_name);
457
458 db.where_and(pid_field, "=", pid_id.into());
459
460 if !search.is_empty() {
461 db.where_and("id", "in", search.into());
462 }
463
464 for (key, value) in where_or.entries() {
465 if value.is_empty() {
466 continue;
467 }
468 if value.is_array() {
469 db.where_or(key, "between", value.clone());
470 db.where_or(key, "in", value.clone());
471 } else if value.is_boolean() {
472 db.where_or(key, "=", value.clone());
473 } else {
474 db.where_or(key, "like", format!("%{value}%").into());
475 }
476 }
477
478 for value in where_and.members() {
479 db.where_and(
480 value[0].as_str().unwrap(),
481 value[1].as_str().unwrap(),
482 value[2].clone(),
483 );
484 }
485
486 db.field(format!("id,{},{}", pid_field, fields.join(",")).as_str());
487
488 let mut data = db.select();
489 for item in data.members_mut() {
490 let children = self.tools().db.table(table_name).where_and(pid_field, "=", item["id"].clone()).select();
491 if children.is_empty() {
492 item["lazy"] = false.into();
493 } else {
494 item["lazy"] = true.into();
495 }
496 }
497
498 let ids_list = if ids.is_empty() {
499 vec![]
500 } else {
501 let list = self.tools().db.table(table_name).where_and("id", "in", ids).field(format!("id,{},{}", pid_field, fields.join(",")).as_str()).select();
502 let mut t = vec![];
503 for item in list.members() {
504 let mut v = vec![];
505 let mut pid = item[pid_field].to_string();
506 v.push(item[label_field].to_string());
507 loop {
508 if pid.is_empty() {
509 break;
510 }
511 let find = self.tools().db.table(table_name).where_and("id", "=", pid.into()).field(format!("id,{},{}", pid_field, fields.join(",")).as_str()).find();
512 pid = find[pid_field].to_string();
513 v.push(find[label_field].to_string());
514 }
515 v.reverse();
516 t.push(object! {
517 id:item["id"].clone(),
518 label:v.join("/"),
519 });
520 }
521 t
522 };
523
524
525 object! {
526 data:data,
527 label_field:label_field,
528 pid_field:pid_field,
529 ids:ids_list.clone()
530
531 }
532 }
533 #[allow(clippy::too_many_arguments)]
534 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
535 fn table_tree(
536 &mut self,
537 request: JsonValue,
538 table_name: &str,
539 pid_field: &str,
540 label_field: &str,
541 fields: JsonValue,
542 hidd_field: Vec<&str>,
543 show_field: Vec<&str>,
544 search_fields: Vec<&str>,
545 _filter_fields: Vec<&str>,
546 ) -> JsonValue {
547 let search = request["search"].as_str().unwrap_or("");
548
549 let pid = request["pid"].clone();
550
551 let order = request["order"].clone();
552 let where_or = request["where_or"].clone();
553 let where_and = request["where_and"].clone();
554 let mut columns = array![];
555 let mut search_name = vec![];
556 let mut search_field = vec![];
557 let mut filter_columns = vec![];
558 let mut table_field_json = vec![];
559 let mut table_fields = object! {};
560
561 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
562 alls_field.retain(|x| !hidd_field.contains(x));
563 if !show_field.is_empty() {
564 alls_field.retain(|x| show_field.contains(x) || *x == "id");
565 }
566
567 for item in alls_field.iter() {
568 let row = fields[item.to_string()].clone();
569 let field = row["field"].to_string();
570 let title = row["title"].to_string();
571 let mode = row["mode"].to_string();
572
573 if search_fields.contains(&field.as_str()) {
574 search_name.push(title);
575 search_field.push(field.clone());
576 }
577 filter_columns.push(self.filter_column(row.clone()));
578 columns.push(self.table_column(row.clone())).unwrap();
579 let mut table_field_info = object! {};
580 match mode.as_str() {
581 "table" => table_field_info = row.clone(),
582 "array" => table_field_json.push(field.clone()),
583 _ => {}
584 }
585 if !table_field_info.is_empty() {
586 table_fields[field.as_str()] = table_field_info;
587 }
588 }
589
590 let mut tools = self.tools();
591 let db = tools.db.table(table_name);
592 db.where_and(pid_field, "=", pid);
593 if !search.is_empty() {
594 db.where_and(
595 &search_field.join("|"),
596 "like",
597 format!("%{search}%").into(),
598 );
599 }
600
601 for (key, value) in where_or.entries() {
602 if value.is_empty() {
603 continue;
604 }
605 if value.is_array() {
606 db.where_or(key, "in", value.clone());
608 } else if value.is_boolean() {
609 db.where_or(key, "=", value.clone());
610 } else {
611 db.where_or(key, "like", format!("%{value}%").into());
612 }
613 }
614
615 for value in where_and.members() {
616 db.where_and(
617 value[0].as_str().unwrap(),
618 value[1].as_str().unwrap(),
619 value[2].clone(),
620 );
621 }
622
623 let mut db_list = db.clone();
624
625 for item in order.members() {
626 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
627 }
628 let t = alls_field.join(",");
629 db_list.field(t.as_str());
630 if !table_field_json.is_empty() {
631 db_list.json(&table_field_json.join(","));
632 }
633 let mut data = db_list.select();
634
635 let mut table_datas = object! {};
636 let mut ids = HashMap::new();
637
638 for item in data.members_mut() {
639 for (field, _) in table_fields.entries() {
640 if table_datas[field].is_empty() {
641 table_datas[field] = array![];
642 }
643 let _ = table_datas[field].push(item[field].clone());
644 }
645 }
646 for (field, info) in table_fields.entries_mut() {
647 let _ = info["fields"].push("id");
648 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
649 let table_name = info["table"].clone();
650 let mut data_list = self.tools().db.table(table_name.as_str().unwrap()).where_and("id", "in", table_datas[field].clone()).field(&fields_k.join(",")).select();
651
652 for item in data_list.members_mut() {
653 let id = item["id"].as_str().unwrap_or("").to_string();
654 item.remove("id");
655 let label = item.entries().map(|(_, v)| v.as_str().unwrap()).collect::<Vec<&str>>();
656 ids.insert(
657 id.clone(),
658 object! {
659 value: id.clone(),
660 label:label.join(" | ").clone(),
661 },
662 );
663 }
664 }
665
666 let mut list = array![];
667 for item in data.members_mut() {
668 for (field, _) in table_fields.entries() {
669 if item[field].is_empty() {
670 continue;
671 }
672 item[field] = ids[item[field].as_str().unwrap()].clone();
673 }
674 let _ = list.push(object! {
675 id:item["id"].as_str().unwrap(),
676 code:item["code"].as_str().unwrap(),
677 label:item[label_field].as_str().unwrap(),
678 data:item.clone(),
679 });
680 }
681
682 object! {
683 data:list,
684 columns:columns,
685 search_name:search_name.join("/"),
686 filter_columns:filter_columns,
687 pid_field:pid_field,
688 btn_all:array![],
689 btn_api:array![]
690 }
691 }
692
693 #[allow(clippy::too_many_arguments)]
694 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
695 fn tree(&mut self, request: JsonValue, table_name: &str, pid_field: &str, label: &str, fields: JsonValue, hidd_field: Vec<&str>, show_field: Vec<&str>, search_fields: Vec<&str>, _filter_fields: Vec<&str>) -> JsonValue {
697 let search = request["search"].as_str().unwrap_or("");
698
699 let pid = request["pid"].clone();
700 let order = request["order"].clone();
701 let where_or = request["where_or"].clone();
702 let where_and = request["where_and"].clone();
703 let mut columns = array![];
704 let mut search_name = vec![];
705 let mut search_field = vec![];
706 let mut filter_columns = vec![];
707 let mut table_field_json = vec![];
708 let mut table_fields = object! {};
709
710 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
711 alls_field.retain(|x| !hidd_field.contains(x));
712 if !show_field.is_empty() {
713 alls_field.retain(|x| show_field.contains(x) || *x == "id");
714 }
715
716 for item in alls_field.iter() {
717 let row = fields[item.to_string()].clone();
718 let field = row["field"].to_string();
719 let title = row["title"].to_string();
720 let mode = row["mode"].to_string();
721
722 if search_fields.contains(&field.as_str()) {
723 search_name.push(title);
724 search_field.push(field.clone());
725 }
726 filter_columns.push(self.filter_column(row.clone()));
727 columns.push(self.table_column(row.clone())).unwrap();
728 let mut table_field_info = object! {};
729 match mode.as_str() {
730 "table" => table_field_info = row.clone(),
731 "array" => table_field_json.push(field.clone()),
732 _ => {}
733 }
734 if !table_field_info.is_empty() {
735 table_fields[field.as_str()] = table_field_info;
736 }
737 }
738
739 let mut tools = self.tools();
740 let db = tools.db.table(table_name);
741 db.where_and(pid_field, "=", pid);
742 if !search.is_empty() {
743 db.where_and(
744 &search_field.join("|"),
745 "like",
746 format!("%{search}%").into(),
747 );
748 }
749
750 for (key, value) in where_or.entries() {
751 if value.is_empty() {
752 continue;
753 }
754 if value.is_array() {
755 db.where_or(key, "in", value.clone());
756 } else if value.is_boolean() {
757 db.where_or(key, "=", value.clone());
758 } else {
759 db.where_or(key, "like", format!("%{value}%").into());
760 }
761 }
762
763 for value in where_and.members() {
764 db.where_and(
765 value[0].as_str().unwrap(),
766 value[1].as_str().unwrap(),
767 value[2].clone(),
768 );
769 }
770
771 let mut db_list = db.clone();
772
773 for item in order.members() {
774 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
775 }
776 let t = alls_field.join(",");
777 db_list.field(t.as_str());
778 if !table_field_json.is_empty() {
779 db_list.json(&table_field_json.join(","));
780 }
781 let mut data = db_list.select();
782
783 let mut table_datas = object! {};
784 let mut ids = HashMap::new();
785
786 for item in data.members_mut() {
787 for (field, _) in table_fields.entries() {
788 if table_datas[field].is_empty() {
789 table_datas[field] = array![];
790 }
791 let _ = table_datas[field].push(item[field].clone());
792 }
793 }
794 for (field, info) in table_fields.entries_mut() {
795 let _ = info["fields"].push("id");
796 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
797 let table_name = info["table"].clone();
798 let mut data_list = self.tools().db.table(table_name.as_str().unwrap()).where_and("id", "in", table_datas[field].clone()).field(&fields_k.join(",")).select();
799
800 for item in data_list.members_mut() {
801 let id = item["id"].as_str().unwrap_or("").to_string();
802 item.remove("id");
803 let label = item.entries().map(|(_, v)| v.as_str().unwrap()).collect::<Vec<&str>>();
804 ids.insert(
805 id.clone(),
806 object! {
807 value: id.clone(),
808 label:label.join(" | ").clone(),
809 },
810 );
811 }
812 }
813
814 for item in data.members_mut() {
815 for (field, _) in table_fields.entries() {
816 if item[field].is_empty() {
817 continue;
818 }
819 item[field] = ids[item[field].as_str().unwrap()].clone();
820 }
821 }
823
824 object! {
825 data:data,
826 columns:columns,
827 search_name:search_name.join("/"),
828 label:label,
829 btn_all:array![],
830 btn_api:array![],
831 btn_ids:array![]
832 }
833 }
834
835 #[allow(clippy::too_many_arguments)]
843 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
844 fn table_list(
845 &mut self,
846 request: JsonValue,
847 table_name: &str,
848 fields: JsonValue,
849 hidd_field: Vec<&str>,
850 show_field: Vec<&str>,
851 search_fields: Vec<&str>,
852 filter_fields: Vec<&str>,
853 ) -> JsonValue {
854 self.table().main_table_fields(table_name, fields, hidd_field, show_field).search_fields(search_fields).filter_fields(filter_fields).params(request).get_table()
855 }
856 #[allow(clippy::too_many_arguments)]
857 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
858 fn table(&mut self) -> Tables {
859 Tables::new(self.tools().db.clone())
860 }
861 fn table_column(&mut self, field: JsonValue) -> JsonValue {
862 object! {
863 name:field["field"].clone(),
864 label:field["title"].clone(),
865 align:"center",
866 field:field["field"].clone(),
867 sortable:true,
868 mode:field["mode"].clone(),
869 dec:field["dec"].clone(),
870 fields:field["fields"].clone()
871 }
872 }
873 fn filter_column(&mut self, field: JsonValue) -> JsonValue {
874 object! {
875 name:field["field"].clone(),
876 label:field["title"].clone(),
877 mode:field["mode"].clone(),
878 option:field["option"].clone(),
879 api:field["api"].clone(),
880 fields:field["fields"].clone()
881 }
882 }
883 fn tools(&mut self) -> Tools {
885 let tools = PLUGIN_TOOLS.lock().unwrap();
886 let tools = tools.get("tools").unwrap().clone();
887 tools
888 }
889 fn config(&mut self, name: &str) -> JsonValue {
891 if CONFIG.lock().unwrap().get(name).is_none() {
892 object! {}
893 } else {
894 CONFIG.lock().unwrap().get(name).unwrap().clone()
895 }
896 }
897 fn btn(&mut self) -> Btn {
900 let mut btn = Btn::new(self.api().as_str());
901 btn.fields(self.params().clone());
902 btn.tags(self.tags());
903 btn.icon(self.icon());
904 btn.desc(self.description());
905 btn.auth(self.auth());
906 btn.public(self.public());
907 btn.title(self.title());
908 btn.btn_type(BtnType::Api);
909 btn.btn_color(BtnColor::Primary);
910 btn.path(self.api().clone().replace(".", "/").as_str());
911 btn.pass(false);
912 btn.addon();
913 btn
914 }
915 fn set_global_data(&mut self, key: &str, value: JsonValue) {
917 GLOBAL_DATA.with(|data| {
918 data.borrow_mut()[key] = value;
919 });
920 }
921 fn get_global_data(&mut self) -> JsonValue {
923 GLOBAL_DATA.with(|data| {
924 data.borrow().clone()
925 })
926 }
927 fn get_global_data_key(&mut self, key: &str) -> JsonValue {
929 GLOBAL_DATA.with(|data| {
930 data.borrow()[key].clone()
931 })
932 }
933}
934#[derive(Debug, Clone)]
935pub struct Btn {
936 api: String,
937 title: String,
938 desc: String,
939 tags: &'static [&'static str],
940 auth: bool,
941 public: bool,
942 btn_type: BtnType,
943 color: BtnColor,
944 icon: String,
945 cnd: Vec<JsonValue>,
946 url: String,
947 path: String,
948 fields: JsonValue,
949 addon: String,
950 version: usize,
951 pass: bool,
953}
954impl Btn {
955 pub fn new(api: &str) -> Self {
956 Self {
957 api: api.to_string(),
958 title: "".to_string(),
959 desc: "".to_string(),
960 btn_type: BtnType::Api,
961 color: BtnColor::Primary,
962 icon: "".to_string(),
963 auth: false,
964 public: false,
965 cnd: vec![],
966 url: "".to_string(),
967 path: "".to_string(),
968 fields: object! {},
969 tags: &[],
970 pass: false,
971 addon: "".to_string(),
972 version: 0,
973 }
974 }
975
976 pub fn addon(&mut self) -> &mut Self {
977 self.addon = self.api.split('.').nth(0).unwrap().to_string();
978 self
979 }
980 pub fn path(&mut self, path: &str) -> &mut Self {
981 self.path = path.to_string();
982 self
983 }
984 pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
985 self.cnd = cnd;
986 self
987 }
988 pub fn version(&mut self, version: usize) -> &mut Self {
989 self.version = version;
990 self
991 }
992 pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
993 self.btn_type = btn_type;
994 self
995 }
996 pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
997 self.color = btn_color;
998 self
999 }
1000 pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
1001 self.fields = fields;
1002 self
1003 }
1004 pub fn pass(&mut self, pass: bool) -> &mut Self {
1005 self.pass = pass;
1006 self
1007 }
1008 pub fn url(&mut self, url: &str) -> &mut Self {
1009 self.url = url.to_string();
1010 self
1011 }
1012 pub fn title(&mut self, title: &str) -> &mut Self {
1013 self.title = title.to_string();
1014 self
1015 }
1016 pub fn desc(&mut self, desc: &str) -> &mut Self {
1017 self.desc = desc.to_string();
1018 self
1019 }
1020 pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
1021 self.tags = tags;
1022 self
1023 }
1024 pub fn public(&mut self, public: bool) -> &mut Self {
1025 self.public = public;
1026 self
1027 }
1028 pub fn auth(&mut self, auth: bool) -> &mut Self {
1029 self.auth = auth;
1030 self
1031 }
1032 pub fn icon(&mut self, icon: &str) -> &mut Self {
1033 self.icon = icon.to_string();
1034 self
1035 }
1036 pub fn json(&mut self) -> JsonValue {
1037 let color = match self.version {
1038 0 => self.color.clone().str(),
1039 _ => self.color.clone().str_v_1()
1040 };
1041 object! {
1042 addon:self.addon.to_string() ,
1043 api:self.api.clone(),
1044 title:self.title.clone(),
1045 desc:self.desc.clone(),
1046 auth:self.auth,
1047 public:self.public,
1048 btn_type:self.btn_type.clone().str(),
1049 color:color,
1050 icon:self.icon.clone(),
1051 cnd:self.cnd.clone(),
1052 url:self.url.clone(),
1053 path:self.path.clone(),
1054 fields:self.fields.clone(),
1055 tags:self.tags,
1056 pass:self.pass,
1057 }
1058 }
1059}
1060
1061#[derive(Debug, Clone)]
1063pub enum InterfaceType {
1064 API,
1065 BTN,
1066 MENU,
1067 OPENAPI,
1068}
1069
1070impl InterfaceType {
1071 pub fn str(&self) -> &'static str {
1072 match self {
1073 InterfaceType::API => "api",
1074 InterfaceType::BTN => "btn",
1075 InterfaceType::MENU => "menu",
1076 InterfaceType::OPENAPI => "openapi",
1077 }
1078 }
1079 pub fn types() -> Vec<&'static str> {
1080 vec!["api", "btn", "menu", "openapi"]
1081 }
1082}
1083
1084#[derive(Debug, Clone)]
1086pub enum BtnType {
1087 Form,
1089 FormDownload,
1091 FormCustom,
1093 FormData,
1094 Url,
1096 Api,
1098 Download,
1100 Path,
1102 DialogCustom,
1104 FormApiDialogCustom,
1106 Preview,
1108}
1109
1110impl BtnType {
1111 fn str(self) -> &'static str {
1112 match self {
1113 BtnType::Form => "form",
1114 BtnType::FormDownload => "form_download",
1115 BtnType::FormCustom => "form_custom",
1116 BtnType::FormData => "form_data",
1117 BtnType::Api => "api",
1118 BtnType::Download => "download",
1119 BtnType::Url => "url",
1120 BtnType::Path => "path",
1121 BtnType::DialogCustom => "dialog_custom",
1122 BtnType::FormApiDialogCustom => "form_api_dialog_custom",
1123 BtnType::Preview => "preview",
1124 }
1125 }
1126}
1127#[derive(Debug, Clone)]
1129pub enum BtnColor {
1130 Primary,
1131 Red,
1132 Yellow,
1133 Green,
1134}
1135
1136impl BtnColor {
1137 fn str(self) -> &'static str {
1138 match self {
1139 BtnColor::Primary => "primary",
1140 BtnColor::Red => "negative",
1141 BtnColor::Yellow => "warning",
1142 BtnColor::Green => "positive",
1143 }
1144 }
1145 fn str_v_1(self) -> &'static str {
1146 match self {
1147 BtnColor::Primary => "normal",
1148 BtnColor::Red => "danger",
1149 BtnColor::Yellow => "warning",
1150 BtnColor::Green => "success",
1151 }
1152 }
1153}
1154
1155
1156pub struct Dashboard {
1157 title: String,
1159 data: JsonValue,
1161 model: DashboardModel,
1163 class: String,
1165 icon: String,
1167 desc: String,
1169 api: String,
1171 options: JsonValue,
1173}
1174impl Dashboard {
1175 pub fn new(title: &str) -> Dashboard {
1176 Dashboard {
1177 title: title.to_string(),
1178 data: JsonValue::Null,
1179 model: DashboardModel::Number,
1180 class: "col-4".to_string(),
1181 icon: "".to_string(),
1182 desc: "".to_string(),
1183 api: "".to_string(),
1184 options: JsonValue::Null,
1185 }
1186 }
1187 pub fn options(&mut self, options: JsonValue) -> &mut Self {
1188 self.options = options;
1189 self
1190 }
1191 pub fn api(&mut self, api: &str) -> &mut Self {
1192 self.api = api.to_string();
1193 self
1194 }
1195 pub fn data(&mut self, data: JsonValue) -> &mut Self {
1196 self.data = data;
1197 self
1198 }
1199 pub fn class(&mut self, name: &str) -> &mut Self {
1200 self.class = name.to_string();
1201 self
1202 }
1203 pub fn icon(&mut self, name: &str) -> &mut Self {
1204 self.icon = name.to_string();
1205 self
1206 }
1207 pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
1208 self.model = dashboard_model;
1209 self
1210 }
1211 pub fn desc(&mut self, desc: &str) -> &mut Self {
1212 self.desc = desc.to_string();
1213 self
1214 }
1215 pub fn json(&self) -> JsonValue {
1216 object! {
1217 title: self.title.clone(),
1218 data: self.data.clone(),
1219 class: self.class.clone(),
1220 icon: self.icon.clone(),
1221 model: self.model.str(),
1222 desc: self.desc.clone(),
1223 api: self.api.clone(),
1224 options:self.options.clone(),
1225 }
1226 }
1227}
1228
1229pub enum DashboardModel {
1230 Number,
1232 EchartsBar,
1234 EchartsStackedBar,
1236 EchartsBarRace,
1238 EchartsPie,
1240 EchartsDoughnut,
1242 EchartsStackedLine,
1244 EchartsStackedLineArea,
1246 EchartsGeoGraph,
1248}
1249
1250impl DashboardModel {
1251 pub fn str(&self) -> &'static str {
1252 match self {
1253 Self::Number => "number",
1254 Self::EchartsBar => "echarts-bar",
1255 Self::EchartsStackedBar => "echarts-stacked_bar",
1256 Self::EchartsBarRace => "echarts-bar_race",
1257 Self::EchartsPie => "echarts-pie",
1258 Self::EchartsDoughnut => "echarts-doughnut",
1259 Self::EchartsStackedLine => "echarts-stacked_line",
1260 Self::EchartsStackedLineArea => "echarts-stacked_line_area",
1261 Self::EchartsGeoGraph => "echarts-geo_graph",
1262 }
1263 }
1264}