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" | "tree" => {
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 {
421 params["page"] = br_fields::int::Int::new(false, "page", "页数", 10, 1).example(1.into()).field();
422 params["limit"] = br_fields::int::Int::new(false, "limit", "行数", 10, 10).example(10.into()).field();
423 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
424 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
425 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
426 params["params"] = br_fields::text::Object::new(false, "params", "关联数据参数", object! {}).example(object! {}).field();
427 params["field"] = br_fields::str::Str::new(false, "field", "显示字段", 50, "id").example("id".into()).field();
428 params
429 }
430 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
431 fn table_select(
432 &mut self,
433 request: JsonValue,
434 table_name: &str,
435 fields: Vec<&str>,
436 ) -> JsonValue {
437 let page = request["page"].as_i32().unwrap_or(1);
438 let limit = request["limit"].as_i32().unwrap_or(10);
439
440 let search = request["search"].as_str().unwrap_or("");
441
442 let field_id = request["field"].as_str().unwrap_or("id");
443
444 let where_or = request["where_or"].clone();
445 let where_and = request["where_and"].clone();
446
447 let mut tools = self.tools();
448 let db = tools.db.table(table_name);
449
450 if !search.is_empty() {
451 db.where_and(&fields.join("|"), "like", format!("%{search}%").into());
452 }
453
454 for (key, value) in where_or.entries() {
455 if value.is_empty() {
456 continue;
457 }
458 if value.is_array() {
459 db.where_or(key, "between", value.clone());
460 db.where_or(key, "in", value.clone());
461 } else if value.is_boolean() {
462 db.where_or(key, "=", value.clone());
463 } else {
464 db.where_or(key, "like", format!("%{value}%").into());
465 }
466 }
467
468 for value in where_and.members() {
469 db.where_and(
470 value[0].as_str().unwrap(),
471 value[1].as_str().unwrap(),
472 value[2].clone(),
473 );
474 }
475
476 let total = (db.clone().count().as_f64().unwrap() / f64::from(limit)).ceil() as i64;
477 let mut db_list = db.clone();
478
479 db_list.field(format!("{},{}", field_id, fields.join(",")).as_str());
480
481 let mut data = db_list.page(page, limit).select();
482 let mut list = array![];
483 for item in data.members_mut() {
484 let value = item[field_id].clone();
485 item.remove(field_id);
486
487 let label = item.entries().map(|(_, v)| v.to_string()).collect::<Vec<String>>();
488
489 list.push(object! {
490 value: value,
491 label: label.join(" | ").clone(),
492 }).unwrap();
493 }
494 object! {
495 total:total,
496 data:list,
497 }
498 }
499 fn params_table_tree_select(&mut self, mut params: JsonValue) -> JsonValue {
501 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
502 params["pid"] = br_fields::str::Str::new(false, "pid", "上级ID", 20, "").example("".into()).field();
503 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
504 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
505 params["params"] = br_fields::text::Object::new(false, "params", "关联数据参数", object! {}).example(object! {}).field();
506 params
507 }
508 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
509 fn table_tree_select(
510 &mut self,
511 request: JsonValue,
512 table_name: &str,
513 pid_field: &str,
514 label_field: &str,
515 fields: Vec<&str>,
516 ) -> JsonValue {
517 let search = request["search"].as_str().unwrap_or("");
518 let pid_id = request["pid"].as_str().unwrap_or("id");
519
520 let where_or = request["where_or"].clone();
521 let where_and = request["where_and"].clone();
522
523 let mut tools = self.tools();
524 let db = tools.db.table(table_name);
525
526 db.where_and(pid_field, "=", pid_id.into());
527
528 if !search.is_empty() {
529 db.where_and("id", "in", search.into());
530 }
531
532 for (key, value) in where_or.entries() {
533 if value.is_empty() {
534 continue;
535 }
536 if value.is_array() {
537 db.where_or(key, "between", value.clone());
538 db.where_or(key, "in", value.clone());
539 } else if value.is_boolean() {
540 db.where_or(key, "=", value.clone());
541 } else {
542 db.where_or(key, "like", format!("%{value}%").into());
543 }
544 }
545
546 for value in where_and.members() {
547 db.where_and(
548 value[0].as_str().unwrap(),
549 value[1].as_str().unwrap(),
550 value[2].clone(),
551 );
552 }
553
554 db.field(format!("id,{},{}", pid_field, fields.join(",")).as_str());
555
556 let mut data = db.select();
557 for item in data.members_mut() {
558 let children = self.tools().db.table(table_name).where_and(pid_field, "=", item["id"].clone()).select();
559 if children.is_empty() {
560 item["lazy"] = false.into();
561 } else {
562 item["lazy"] = true.into();
563 }
564 }
565 object! {
566 data:data,
567 label_field:label_field,
568 pid_field:pid_field
569 }
570 }
571 fn params_table_menu(&mut self, mut params: JsonValue) -> JsonValue {
573 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
574 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
575 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
576 params
577 }
578 #[allow(clippy::too_many_arguments)]
579 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
580 fn table_menu(
581 &mut self,
582 request: JsonValue,
583 table_name: &str,
584 label_field: &str,
585 fields: JsonValue,
586
587 hidd_field: Vec<&str>,
588 show_field: Vec<&str>,
589
590 search_fields: Vec<&str>,
591 _filter_fields: Vec<&str>,
592 ) -> JsonValue {
593 let search = request["search"].as_str().unwrap_or("");
594
595 let order = request["order"].clone();
596 let where_or = request["where_or"].clone();
597 let where_and = request["where_and"].clone();
598 let mut columns = array![];
599 let mut search_name = vec![];
600 let mut search_field = vec![];
601 let mut filter_columns = vec![];
602 let mut table_fields = object! {};
603 let mut table_field_json = vec![];
604
605 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
606 alls_field.retain(|x| !hidd_field.contains(x));
607 if !show_field.is_empty() {
608 alls_field.retain(|x| show_field.contains(x) || *x == "id");
609 }
610
611 for item in alls_field.iter() {
612 let row = &fields[item.to_string()];
613 let field = row["field"].to_string();
614 let title = row["title"].to_string();
615 let mode = row["mode"].to_string();
616
617 if search_fields.contains(&field.as_str()) {
618 search_name.push(title);
619 search_field.push(field.clone());
620 }
621 filter_columns.push(self.filter_column(row.clone()));
622 columns.push(self.table_column(row.clone())).unwrap();
623 let mut table_field_info = object! {};
624 match mode.as_str() {
625 "table" => table_field_info = row.clone(),
626 "array" => table_field_json.push(field.clone()),
627 _ => {}
628 }
629 if !table_field_info.is_empty() {
630 table_fields[field.as_str()] = table_field_info;
631 }
632 }
633
634 let mut tools = self.tools();
635 let db = tools.db.table(table_name);
636
637 if !search.is_empty() {
638 db.where_and(
639 &search_field.join("|"),
640 "like",
641 format!("%{search}%").into(),
642 );
643 }
644
645 for (key, value) in where_or.entries() {
646 if value.is_empty() {
647 continue;
648 }
649 if value.is_array() {
650 db.where_or(key, "between", value.clone());
651 db.where_or(key, "in", value.clone());
652 } else if value.is_boolean() {
653 db.where_or(key, "=", value.clone());
654 } else {
655 db.where_or(key, "like", format!("%{value}%").into());
656 }
657 }
658
659 for value in where_and.members() {
660 db.where_and(
661 value[0].as_str().unwrap(),
662 value[1].as_str().unwrap(),
663 value[2].clone(),
664 );
665 }
666
667 let mut db_list = db.clone();
668
669 for item in order.members() {
670 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
671 }
672
673 let t = alls_field.join(",");
674 db_list.field(t.as_str());
675
676 if !table_field_json.is_empty() {
677 db_list.json(&table_field_json.join(","));
678 }
679
680 let mut data = db_list.select();
681
682 let mut table_datas = object! {};
683 let mut ids = HashMap::new();
684
685 for item in data.members_mut() {
686 for (field, _) in table_fields.entries() {
687 if table_datas[field].is_empty() {
688 table_datas[field] = array![];
689 }
690 let _ = table_datas[field].push(item[field].clone());
691 }
692 }
693 for (field, info) in table_fields.entries_mut() {
694 let _ = info["fields"].push("id");
695 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
696 let table_name = info["table"].clone();
697 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();
698
699 for item in data_list.members_mut() {
700 let id = item["id"].as_str().unwrap_or("").to_string();
701 item.remove("id");
702 let label = item.entries().map(|(_, v)| v.as_str().unwrap()).collect::<Vec<&str>>();
703 ids.insert(
704 id.clone(),
705 object! {
706 value: id.clone(),
707 label:label.join(" | ").clone(),
708 },
709 );
710 }
711 }
712
713 for item in data.members_mut() {
714 for (field, _) in table_fields.entries() {
715 if item[field].is_empty() {
716 continue;
717 }
718 item[field] = ids[item[field].as_str().unwrap()].clone();
719 }
720 }
721
722 object! {
723 data:data,
724 columns:columns,
725 search_name:search_name.join("/"),
726 filter_columns:filter_columns,
727 label_field:label_field,
728 btn_all:array![],
729 btn_api:array![]
730 }
731 }
732 fn params_table_tree(&mut self, mut params: JsonValue) -> JsonValue {
734 params["pid"] = br_fields::str::Str::new(false, "pid", "上级ID", 50, "").example("".into()).field();
735 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
736 params["order"] = br_fields::text::Array::new(false, "order", "排序", array![]).example(array![array!["id", false]]).field();
737 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
738 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
739 params
740 }
741 #[allow(clippy::too_many_arguments)]
742 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
743 fn table_tree(
744 &mut self,
745 request: JsonValue,
746 table_name: &str,
747 pid_field: &str,
748 label_field: &str,
749 fields: JsonValue,
750 hidd_field: Vec<&str>,
751 show_field: Vec<&str>,
752 search_fields: Vec<&str>,
753 _filter_fields: Vec<&str>,
754 ) -> JsonValue {
755 let search = request["search"].as_str().unwrap_or("");
756
757 let pid = request["pid"].clone();
758
759 let order = request["order"].clone();
760 let where_or = request["where_or"].clone();
761 let where_and = request["where_and"].clone();
762 let mut columns = array![];
763 let mut search_name = vec![];
764 let mut search_field = vec![];
765 let mut filter_columns = vec![];
766 let mut table_field_json = vec![];
767 let mut table_fields = object! {};
768
769 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
770 alls_field.retain(|x| !hidd_field.contains(x));
771 if !show_field.is_empty() {
772 alls_field.retain(|x| show_field.contains(x) || *x == "id");
773 }
774
775 for item in alls_field.iter() {
776 let row = fields[item.to_string()].clone();
777 let field = row["field"].to_string();
778 let title = row["title"].to_string();
779 let mode = row["mode"].to_string();
780
781 if search_fields.contains(&field.as_str()) {
782 search_name.push(title);
783 search_field.push(field.clone());
784 }
785 filter_columns.push(self.filter_column(row.clone()));
786 columns.push(self.table_column(row.clone())).unwrap();
787 let mut table_field_info = object! {};
788 match mode.as_str() {
789 "table" => table_field_info = row.clone(),
790 "array" => table_field_json.push(field.clone()),
791 _ => {}
792 }
793 if !table_field_info.is_empty() {
794 table_fields[field.as_str()] = table_field_info;
795 }
796 }
797
798 let mut tools = self.tools();
799 let db = tools.db.table(table_name);
800 db.where_and(pid_field, "=", pid);
801 if !search.is_empty() {
802 db.where_and(
803 &search_field.join("|"),
804 "like",
805 format!("%{search}%").into(),
806 );
807 }
808
809 for (key, value) in where_or.entries() {
810 if value.is_empty() {
811 continue;
812 }
813 if value.is_array() {
814 db.where_or(key, "in", value.clone());
816 } else if value.is_boolean() {
817 db.where_or(key, "=", value.clone());
818 } else {
819 db.where_or(key, "like", format!("%{value}%").into());
820 }
821 }
822
823 for value in where_and.members() {
824 db.where_and(
825 value[0].as_str().unwrap(),
826 value[1].as_str().unwrap(),
827 value[2].clone(),
828 );
829 }
830
831 let mut db_list = db.clone();
832
833 for item in order.members() {
834 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
835 }
836 let t = alls_field.join(",");
837 db_list.field(t.as_str());
838 if !table_field_json.is_empty() {
839 db_list.json(&table_field_json.join(","));
840 }
841 let mut data = db_list.select();
842
843 let mut table_datas = object! {};
844 let mut ids = HashMap::new();
845
846 for item in data.members_mut() {
847 for (field, _) in table_fields.entries() {
848 if table_datas[field].is_empty() {
849 table_datas[field] = array![];
850 }
851 let _ = table_datas[field].push(item[field].clone());
852 }
853 }
854 for (field, info) in table_fields.entries_mut() {
855 let _ = info["fields"].push("id");
856 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
857 let table_name = info["table"].clone();
858 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();
859
860 for item in data_list.members_mut() {
861 let id = item["id"].as_str().unwrap_or("").to_string();
862 item.remove("id");
863 let label = item.entries().map(|(_, v)| v.as_str().unwrap()).collect::<Vec<&str>>();
864 ids.insert(
865 id.clone(),
866 object! {
867 value: id.clone(),
868 label:label.join(" | ").clone(),
869 },
870 );
871 }
872 }
873
874 let mut list = array![];
875 for item in data.members_mut() {
876 for (field, _) in table_fields.entries() {
877 if item[field].is_empty() {
878 continue;
879 }
880 item[field] = ids[item[field].as_str().unwrap()].clone();
881 }
882 let _ = list.push(object! {
883 id:item["id"].as_str().unwrap(),
884 code:item["code"].as_str().unwrap(),
885 label:item[label_field].as_str().unwrap(),
886 data:item.clone(),
887 });
888 }
889
890 object! {
891 data:list,
892 columns:columns,
893 search_name:search_name.join("/"),
894 filter_columns:filter_columns,
895 pid_field:pid_field,
896 btn_all:array![],
897 btn_api:array![]
898 }
899 }
900
901 #[allow(clippy::too_many_arguments)]
902 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
903 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 {
905 let search = request["search"].as_str().unwrap_or("");
906
907 let pid = request["pid"].clone();
908 let order = request["order"].clone();
909 let where_or = request["where_or"].clone();
910 let where_and = request["where_and"].clone();
911 let mut columns = array![];
912 let mut search_name = vec![];
913 let mut search_field = vec![];
914 let mut filter_columns = vec![];
915 let mut table_field_json = vec![];
916 let mut table_fields = object! {};
917
918 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
919 alls_field.retain(|x| !hidd_field.contains(x));
920 if !show_field.is_empty() {
921 alls_field.retain(|x| show_field.contains(x) || *x == "id");
922 }
923
924 for item in alls_field.iter() {
925 let row = fields[item.to_string()].clone();
926 let field = row["field"].to_string();
927 let title = row["title"].to_string();
928 let mode = row["mode"].to_string();
929
930 if search_fields.contains(&field.as_str()) {
931 search_name.push(title);
932 search_field.push(field.clone());
933 }
934 filter_columns.push(self.filter_column(row.clone()));
935 columns.push(self.table_column(row.clone())).unwrap();
936 let mut table_field_info = object! {};
937 match mode.as_str() {
938 "table" => table_field_info = row.clone(),
939 "array" => table_field_json.push(field.clone()),
940 _ => {}
941 }
942 if !table_field_info.is_empty() {
943 table_fields[field.as_str()] = table_field_info;
944 }
945 }
946
947 let mut tools = self.tools();
948 let db = tools.db.table(table_name);
949 db.where_and(pid_field, "=", pid);
950 if !search.is_empty() {
951 db.where_and(
952 &search_field.join("|"),
953 "like",
954 format!("%{search}%").into(),
955 );
956 }
957
958 for (key, value) in where_or.entries() {
959 if value.is_empty() {
960 continue;
961 }
962 if value.is_array() {
963 db.where_or(key, "in", value.clone());
964 } else if value.is_boolean() {
965 db.where_or(key, "=", value.clone());
966 } else {
967 db.where_or(key, "like", format!("%{value}%").into());
968 }
969 }
970
971 for value in where_and.members() {
972 db.where_and(
973 value[0].as_str().unwrap(),
974 value[1].as_str().unwrap(),
975 value[2].clone(),
976 );
977 }
978
979 let mut db_list = db.clone();
980
981 for item in order.members() {
982 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
983 }
984 let t = alls_field.join(",");
985 db_list.field(t.as_str());
986 if !table_field_json.is_empty() {
987 db_list.json(&table_field_json.join(","));
988 }
989 let mut data = db_list.select();
990
991 let mut table_datas = object! {};
992 let mut ids = HashMap::new();
993
994 for item in data.members_mut() {
995 for (field, _) in table_fields.entries() {
996 if table_datas[field].is_empty() {
997 table_datas[field] = array![];
998 }
999 let _ = table_datas[field].push(item[field].clone());
1000 }
1001 }
1002 for (field, info) in table_fields.entries_mut() {
1003 let _ = info["fields"].push("id");
1004 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
1005 let table_name = info["table"].clone();
1006 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();
1007
1008 for item in data_list.members_mut() {
1009 let id = item["id"].as_str().unwrap_or("").to_string();
1010 item.remove("id");
1011 let label = item.entries().map(|(_, v)| v.as_str().unwrap()).collect::<Vec<&str>>();
1012 ids.insert(
1013 id.clone(),
1014 object! {
1015 value: id.clone(),
1016 label:label.join(" | ").clone(),
1017 },
1018 );
1019 }
1020 }
1021
1022 for item in data.members_mut() {
1023 for (field, _) in table_fields.entries() {
1024 if item[field].is_empty() {
1025 continue;
1026 }
1027 item[field] = ids[item[field].as_str().unwrap()].clone();
1028 }
1029 }
1031
1032 object! {
1033 data:data,
1034 columns:columns,
1035 search_name:search_name.join("/"),
1036 label:label,
1037 btn_all:array![],
1038 btn_api:array![],
1039 btn_ids:array![]
1040 }
1041 }
1042
1043 fn params_table_list(&mut self, mut params: JsonValue) -> JsonValue {
1045 params["page"] = br_fields::int::Int::new(false, "page", "页数", 10, 1).example(1.into()).field();
1046 params["limit"] = br_fields::int::Int::new(false, "limit", "行数", 10, 10).example(10.into()).field();
1047 params["search"] = br_fields::str::Str::new(false, "search", "搜索", 200, "").example("".into()).field();
1048 params["order"] = br_fields::text::Array::new(false, "order", "排序", array![]).example(array![array!["id", false]]).field();
1049 params["where_or"] = br_fields::text::Array::new(false, "where_or", "查询条件", array![]).example(array![]).field();
1050 params["where_and"] = br_fields::text::Array::new(false, "where_and", "查询条件", array![]).example(array![]).field();
1051 params["field"] = br_fields::str::Str::new(false, "field", "显示字段", 20, "id").example("id".into()).field();
1052 params
1053 }
1054 #[allow(clippy::too_many_arguments)]
1062 #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
1063 fn table_list(
1064 &mut self,
1065 request: JsonValue,
1066 table_name: &str,
1067 fields: JsonValue,
1068 hidd_field: Vec<&str>,
1069 show_field: Vec<&str>,
1070 search_fields: Vec<&str>,
1071 filter_fields: Vec<&str>,
1072 ) -> JsonValue {
1073 let page = request["page"].as_i32().unwrap_or(1);
1074 let limit = request["limit"].as_i32().unwrap_or(10);
1075 let search = request["search"].as_str().unwrap_or("");
1076 let order = request["order"].clone();
1077 let where_or = request["where_or"].clone();
1078 let where_and = request["where_and"].clone();
1079 let mut columns = array![];
1080 let mut search_name = vec![];
1081 let mut search_field = vec![];
1082 let mut filter_columns = vec![];
1083
1084 let mut table_fields = object! {};
1086 let mut tree_fields = object! {};
1088
1089 let mut json_fields = vec![];
1091
1092 let mut alls_field = fields.entries().map(|(x, _)| x).collect::<Vec<&str>>();
1093 alls_field.retain(|x| !hidd_field.contains(x));
1094 if !show_field.is_empty() {
1095 alls_field.retain(|x| show_field.contains(x) || *x == "id");
1096 }
1097
1098 for item in alls_field.iter() {
1099 let key = item.to_string();
1100 let field = fields[key.clone()]["field"].as_str().unwrap();
1101 let title = fields[key.clone()]["title"].as_str().unwrap();
1102 let mode = fields[key.clone()]["mode"].as_str().unwrap();
1103
1104 if search_fields.contains(&field) {
1105 search_name.push(title);
1106 search_field.push(field);
1107 }
1108 if filter_fields.contains(&field) {
1109 filter_columns.push(self.filter_column(fields[key.clone()].clone()));
1110 }
1111 columns.push(self.table_column(fields[key.clone()].clone())).unwrap();
1112
1113 match mode {
1114 "table" => {
1115 let table_field_info = if mode == "table" {
1116 fields[key.clone()].clone()
1117 } else {
1118 JsonValue::Null
1119 };
1120 if !table_field_info.is_empty() {
1121 table_fields[field] = table_field_info;
1122 }
1123 }
1124 "tree" => {
1125 let table_field_info = if mode == "tree" {
1126 fields[key.clone()].clone()
1127 } else {
1128 JsonValue::Null
1129 };
1130 if !table_field_info.is_empty() {
1131 tree_fields[field] = table_field_info;
1132 }
1133 }
1134 "object" | "array" | "polygon" => {
1135 json_fields.push(field);
1136 }
1137 _ => {}
1138 }
1139 }
1140
1141 let mut tools = self.tools();
1142 let db = tools.db.table(table_name);
1143
1144 if !search.is_empty() {
1145 db.where_and(
1146 &search_field.join("|"),
1147 "like",
1148 format!("%{search}%").into(),
1149 );
1150 }
1151
1152 for (key, value) in where_or.entries() {
1153 if value.is_empty() {
1154 continue;
1155 }
1156 if value.is_array() {
1157 db.where_or(key, "in", value.clone());
1158 } else if value.is_boolean() {
1159 db.where_or(key, "=", value.clone());
1160 } else {
1161 db.where_or(key, "like", format!("%{value}%").into());
1162 }
1163 }
1164
1165 for value in where_and.members() {
1166 db.where_and(
1167 value[0].as_str().unwrap(),
1168 value[1].as_str().unwrap(),
1169 value[2].clone(),
1170 );
1171 }
1172
1173 let total = db.clone().count().as_f64().unwrap();
1174 let mut db_list = db.clone();
1175
1176 for item in order.members() {
1177 db_list.order(item[0].as_str().unwrap(), item[1].as_bool().unwrap());
1178 }
1179
1180 let t = alls_field.join(",");
1181 db_list.field(t.as_str());
1182 let mut data = db_list.page(page, limit).json(&json_fields.join(",")).select();
1183
1184 let mut table_data = object! {};
1185
1186 for item in data.members_mut() {
1187 if !table_fields.is_empty() {
1188 for (field, field_info) in table_fields.entries() {
1189 if item[field].is_empty() {
1190 continue;
1191 }
1192 let key = item[field].as_str().unwrap_or("");
1193 if key.is_empty() {
1194 continue;
1195 }
1196 if !table_data.has_key(field) {
1197 table_data[field] = object! {};
1198 }
1199 if !table_data[field].has_key(key) {
1200 let mut info = field_info.clone();
1201 let _ = info["fields"].push("id");
1202 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
1203 let mut find = self.tools().db.table(info["table"].as_str().unwrap()).where_and("id", "=", key.into()).field(&fields_k.join(",")).find();
1204 let id = find["id"].to_string();
1205 find.remove("id");
1206 let label = find.entries().map(|(_, v)| v.to_string()).collect::<Vec<String>>();
1207 table_data[field][key] = object! {
1208 value: id.clone(),
1209 label:label.join(" | ").clone(),
1210 };
1211 }
1212 item[field] = table_data[field][key].clone();
1213 }
1214 }
1215 if !tree_fields.is_empty() {
1216 for (field, field_info) in tree_fields.entries() {
1217 if item[field].is_empty() {
1218 continue;
1219 }
1220 let key = item[field].as_str().unwrap_or("");
1221 if key.is_empty() {
1222 continue;
1223 }
1224 if !table_data.has_key(field) {
1225 table_data[field] = object! {};
1226 }
1227 if !table_data[field].has_key(key) {
1228 let mut info = field_info.clone();
1229 let pid_field = info["pid_field"].clone().to_string();
1230 let _ = info["fields"].push("id");
1231 let _ = info["fields"].push(pid_field.clone());
1232 let fields_k = info["fields"].members().map(|x| x.as_str().unwrap()).collect::<Vec<&str>>();
1233 let mut find = self.tools().db.table(info["table"].as_str().unwrap()).where_and("id", "=", key.into()).field(&fields_k.join(",")).find();
1234 let id = find["id"].to_string();
1235 find.remove("id");
1236 find.remove(&pid_field);
1237 let label = find.entries().map(|(_, v)| v.to_string()).collect::<Vec<String>>();
1238 table_data[field][key] = object! {
1239 value: id.clone(),
1240 label:label.join(" | ").clone(),
1241 };
1242 }
1243 item[field] = table_data[field][key].clone();
1244 }
1245 }
1246 }
1247
1248 object! {
1249 total:total,
1250 data:data,
1251 columns:columns,
1252 search_name:search_name.join("/"),
1253 filter_columns:filter_columns,
1254 btn_all:array![],
1255 btn_api:array![],
1256 btn_ids:array![]
1257 }
1258 }
1259 fn table_column(&mut self, field: JsonValue) -> JsonValue {
1260 object! {
1261 name:field["field"].clone(),
1262 label:field["title"].clone(),
1263 align:"center",
1264 field:field["field"].clone(),
1265 sortable:true,
1266 mode:field["mode"].clone(),
1267 dec:field["dec"].clone(),
1268 fields:field["fields"].clone()
1269 }
1270 }
1271 fn filter_column(&mut self, field: JsonValue) -> JsonValue {
1272 object! {
1273 name:field["field"].clone(),
1274 label:field["title"].clone(),
1275 mode:field["mode"].clone(),
1276 option:field["option"].clone(),
1277 api:field["api"].clone(),
1278 fields:field["fields"].clone()
1279 }
1280 }
1281 fn tools(&mut self) -> Tools {
1283 let tools = PLUGIN_TOOLS.lock().unwrap();
1284 let tools = tools.get("tools").unwrap().clone();
1285 tools
1286 }
1287 fn config(&mut self, name: &str) -> JsonValue {
1289 if CONFIG.lock().unwrap().get(name).is_none() {
1290 object! {}
1291 } else {
1292 CONFIG.lock().unwrap().get(name).unwrap().clone()
1293 }
1294 }
1295 fn btn(&mut self) -> Btn {
1298 let mut btn = Btn::new(self.api().as_str());
1299 btn.fields(self.params().clone());
1300 btn.tags(self.tags());
1301 btn.icon(self.icon());
1302 btn.desc(self.description());
1303 btn.auth(self.auth());
1304 btn.public(self.public());
1305 btn.title(self.title());
1306 btn.btn_type(BtnType::Api);
1307 btn.btn_color(BtnColor::Primary);
1308 btn.path(self.api().clone().replace(".", "/").as_str());
1309 btn.pass(false);
1310 btn.addon();
1311 btn
1312 }
1313 fn set_global_data(&mut self, key: &str, value: JsonValue) {
1315 GLOBAL_DATA.with(|data| {
1316 data.borrow_mut()[key] = value;
1317 });
1318 }
1319 fn get_global_data(&mut self) -> JsonValue {
1321 GLOBAL_DATA.with(|data| {
1322 data.borrow().clone()
1323 })
1324 }
1325 fn get_global_data_key(&mut self, key: &str) -> JsonValue {
1327 GLOBAL_DATA.with(|data| {
1328 data.borrow()[key].clone()
1329 })
1330 }
1331}
1332#[derive(Debug, Clone)]
1333pub struct Btn {
1334 api: String,
1335 title: String,
1336 desc: String,
1337 tags: &'static [&'static str],
1338 auth: bool,
1339 public: bool,
1340 btn_type: BtnType,
1341 color: BtnColor,
1342 icon: String,
1343 cnd: Vec<JsonValue>,
1344 url: String,
1345 path: String,
1346 fields: JsonValue,
1347 addon: String,
1348 pass: bool,
1350}
1351impl Btn {
1352 pub fn new(api: &str) -> Self {
1353 Self {
1354 api: api.to_string(),
1355 title: "".to_string(),
1356 desc: "".to_string(),
1357 btn_type: BtnType::Api,
1358 color: BtnColor::Primary,
1359 icon: "".to_string(),
1360 auth: false,
1361 public: false,
1362 cnd: vec![],
1363 url: "".to_string(),
1364 path: "".to_string(),
1365 fields: object! {},
1366 tags: &[],
1367 pass: false,
1368 addon: "".to_string(),
1369 }
1370 }
1371
1372 pub fn addon(&mut self) -> &mut Self {
1373 self.addon = self.api.split('.').nth(0).unwrap().to_string();
1374 self
1375 }
1376 pub fn path(&mut self, path: &str) -> &mut Self {
1377 self.path = path.to_string();
1378 self
1379 }
1380 pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
1381 self.cnd = cnd;
1382 self
1383 }
1384 pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
1385 self.btn_type = btn_type;
1386 self
1387 }
1388 pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
1389 self.color = btn_color;
1390 self
1391 }
1392 pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
1393 self.fields = fields;
1394 self
1395 }
1396 pub fn pass(&mut self, pass: bool) -> &mut Self {
1397 self.pass = pass;
1398 self
1399 }
1400 pub fn url(&mut self, url: &str) -> &mut Self {
1401 self.url = url.to_string();
1402 self
1403 }
1404 pub fn title(&mut self, title: &str) -> &mut Self {
1405 self.title = title.to_string();
1406 self
1407 }
1408 pub fn desc(&mut self, desc: &str) -> &mut Self {
1409 self.desc = desc.to_string();
1410 self
1411 }
1412 pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
1413 self.tags = tags;
1414 self
1415 }
1416 pub fn public(&mut self, public: bool) -> &mut Self {
1417 self.public = public;
1418 self
1419 }
1420 pub fn auth(&mut self, auth: bool) -> &mut Self {
1421 self.auth = auth;
1422 self
1423 }
1424 pub fn icon(&mut self, icon: &str) -> &mut Self {
1425 self.icon = icon.to_string();
1426 self
1427 }
1428 pub fn json(&mut self) -> JsonValue {
1429 object! {
1430 addon:self.addon.to_string() ,
1431 api:self.api.clone(),
1432 title:self.title.clone(),
1433 desc:self.desc.clone(),
1434 auth:self.auth,
1435 public:self.public,
1436 btn_type:self.btn_type.clone().str(),
1437 color:self.color.clone().str(),
1438 icon:self.icon.clone(),
1439 cnd:self.cnd.clone(),
1440 url:self.url.clone(),
1441 path:self.path.clone(),
1442 fields:self.fields.clone(),
1443 tags:self.tags,
1444 pass:self.pass,
1445 }
1446 }
1447}
1448
1449#[derive(Debug, Clone)]
1451pub enum InterfaceType {
1452 API,
1453 BTN,
1454 MENU,
1455}
1456
1457impl InterfaceType {
1458 pub fn str(&self) -> &'static str {
1459 match self {
1460 InterfaceType::API => "api",
1461 InterfaceType::BTN => "btn",
1462 InterfaceType::MENU => "menu",
1463 }
1464 }
1465 pub fn types() -> Vec<&'static str> {
1466 vec!["api", "btn", "menu"]
1467 }
1468}
1469
1470#[derive(Debug, Clone)]
1472pub enum BtnType {
1473 Form,
1475 FormDownload,
1477 FormCustom,
1479 FormData,
1480 Url,
1482 Api,
1484 Download,
1486 Path,
1488 DialogCustom,
1490 FormApiDialogCustom,
1492 Preview,
1494}
1495
1496impl BtnType {
1497 fn str(self) -> &'static str {
1498 match self {
1499 BtnType::Form => "form",
1500 BtnType::FormDownload => "form_download",
1501 BtnType::FormCustom => "form_custom",
1502 BtnType::FormData => "form_data",
1503 BtnType::Api => "api",
1504 BtnType::Download => "download",
1505 BtnType::Url => "url",
1506 BtnType::Path => "path",
1507 BtnType::DialogCustom => "dialog_custom",
1508 BtnType::FormApiDialogCustom => "form_api_dialog_custom",
1509 BtnType::Preview => "preview",
1510 }
1511 }
1512}
1513#[derive(Debug, Clone)]
1515pub enum BtnColor {
1516 Primary,
1517 Red,
1518 Blue,
1519 Yellow,
1520 Green,
1521}
1522
1523impl BtnColor {
1524 fn str(self) -> &'static str {
1525 match self {
1526 BtnColor::Primary => "primary",
1527 BtnColor::Red => "negative",
1528 BtnColor::Blue => "info",
1529 BtnColor::Yellow => "warning",
1530 BtnColor::Green => "positive",
1531 }
1532 }
1533}
1534
1535
1536pub struct Dashboard {
1537 title: String,
1539 data: JsonValue,
1541 model: DashboardModel,
1543 class: String,
1545 icon: String,
1547 desc: String,
1549 api: String,
1551 options: JsonValue,
1553}
1554impl Dashboard {
1555 pub fn new(title: &str) -> Dashboard {
1556 Dashboard {
1557 title: title.to_string(),
1558 data: JsonValue::Null,
1559 model: DashboardModel::Number,
1560 class: "col-4".to_string(),
1561 icon: "".to_string(),
1562 desc: "".to_string(),
1563 api: "".to_string(),
1564 options: JsonValue::Null,
1565 }
1566 }
1567 pub fn options(&mut self, options: JsonValue) -> &mut Self {
1568 self.options = options;
1569 self
1570 }
1571 pub fn api(&mut self, api: &str) -> &mut Self {
1572 self.api = api.to_string();
1573 self
1574 }
1575 pub fn data(&mut self, data: JsonValue) -> &mut Self {
1576 self.data = data;
1577 self
1578 }
1579 pub fn class(&mut self, name: &str) -> &mut Self {
1580 self.class = name.to_string();
1581 self
1582 }
1583 pub fn icon(&mut self, name: &str) -> &mut Self {
1584 self.icon = name.to_string();
1585 self
1586 }
1587 pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
1588 self.model = dashboard_model;
1589 self
1590 }
1591 pub fn desc(&mut self, desc: &str) -> &mut Self {
1592 self.desc = desc.to_string();
1593 self
1594 }
1595 pub fn json(&self) -> JsonValue {
1596 object! {
1597 title: self.title.clone(),
1598 data: self.data.clone(),
1599 class: self.class.clone(),
1600 icon: self.icon.clone(),
1601 model: self.model.str(),
1602 desc: self.desc.clone(),
1603 api: self.api.clone(),
1604 options:self.options.clone(),
1605 }
1606 }
1607}
1608
1609pub enum DashboardModel {
1610 Number,
1612 EchartsBar,
1614 EchartsStackedBar,
1616 EchartsBarRace,
1618 EchartsPie,
1620 EchartsDoughnut,
1622 EchartsStackedLine,
1624 EchartsStackedLineArea,
1626 EchartsGeoGraph,
1628}
1629
1630impl DashboardModel {
1631 pub fn str(&self) -> &'static str {
1632 match self {
1633 Self::Number => "number",
1634 Self::EchartsBar => "echarts-bar",
1635 Self::EchartsStackedBar => "echarts-stacked_bar",
1636 Self::EchartsBarRace => "echarts-bar_race",
1637 Self::EchartsPie => "echarts-pie",
1638 Self::EchartsDoughnut => "echarts-doughnut",
1639 Self::EchartsStackedLine => "echarts-stacked_line",
1640 Self::EchartsStackedLineArea => "echarts-stacked_line_area",
1641 Self::EchartsGeoGraph => "echarts-geo_graph",
1642 }
1643 }
1644}