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