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