Skip to main content

br_addon/
action.rs

1use crate::request::{ContentType, Method, Request};
2use crate::{CONFIG, GLOBAL_DATA, PLUGIN_TOOLS};
3use crate::{ApiResponse, Tools};
4use br_fields::Field;
5use json::{object, JsonValue};
6use std::any::type_name;
7use crate::tables::Tables;
8
9/// 功能接口
10pub trait Action {
11    /// 功能名称
12    fn _name(&self) -> String {
13        type_name::<Self>().rsplit("::").next().unwrap().to_lowercase()
14    }
15    /// 模块名称
16    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    /// 插件名称
23    fn addon_name(&self) -> String {
24        let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
25        t[2].to_lowercase()
26    }
27    /// API 名称
28    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    /// 是否需要密钥
36    fn token(&self) -> bool {
37        true
38    }
39
40    fn sort(&self) -> usize {
41        99
42    }
43    /// 功能标题
44    fn title(&self) -> &'static str;
45    /// 功能描述
46    fn description(&self) -> &'static str {
47        ""
48    }
49    /// 请求地址路径
50    fn path(&self) -> &'static str {
51        ""
52    }
53    /// 请求地址参数
54    fn query(&self) -> JsonValue {
55        object! {}
56    }
57    /// 标签范围
58    fn tags(&self) -> &'static [&'static str] {
59        &[]
60    }
61    fn icon(&self) -> &'static str {
62        ""
63    }
64    /// 是否公开
65    fn public(&self) -> bool {
66        true
67    }
68    /// 是否权限组显示
69    fn auth(&self) -> bool {
70        true
71    }
72    /// 接口类型 btn api menu
73    fn interface_type(&self) -> InterfaceType {
74        InterfaceType::API
75    }
76    /// 允许的请求类型
77    fn method(&mut self) -> Method {
78        Method::Post
79    }
80    /// 请求类型
81    fn content_type(&mut self) -> ContentType {
82        ContentType::Json
83    }
84    /// 是否检查参数
85    fn params_check(&mut self) -> bool {
86        true
87    }
88    /// 请求body参数
89    fn params(&mut self) -> JsonValue {
90        object! {}
91    }
92    /// 成功响应
93    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    /// 失败响应
103    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    /// 外部入口
113    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    /// 入参验证
136    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                // 判断输入类型
148                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                                // 如果是数组,遍历每个元素
229                                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" | "url" | "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    /// 内部入口
418    fn index(&mut self, request: Request) -> ApiResponse;
419    #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
420    fn table_select(
421        &mut self,
422        request: JsonValue,
423        table_name: &str,
424        fields: Vec<&str>,
425    ) -> JsonValue {
426        self.table().main_select_fields(table_name, fields).params(request.clone()).get_table_select()
427    }
428
429
430    /// 列表表格渲染
431    /// * table_name 表名
432    /// * fields 全部模型字段集合
433    /// * hidd_field 需要隐藏的字段集合
434    /// * show_field 需要显示的字段集合
435    /// * search_fields 搜索字段集合
436    /// * filter_fields 高级搜索字段集合
437    #[allow(clippy::too_many_arguments)]
438    #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
439    fn table_list(
440        &mut self,
441        request: JsonValue,
442        table_name: &str,
443        fields: JsonValue,
444        hidd_field: Vec<&str>,
445        show_field: Vec<&str>,
446        search_fields: Vec<&str>,
447        filter_fields: Vec<&str>,
448    ) -> JsonValue {
449        self.table().main_table_fields(table_name, fields, hidd_field, show_field).search_fields(search_fields).filter_fields(filter_fields).params(request).get_table()
450    }
451    #[allow(clippy::too_many_arguments)]
452    #[cfg(any(feature = "sqlite", feature = "mssql", feature = "mysql", feature = "pgsql"))]
453    fn table(&mut self) -> Tables {
454        Tables::new(self.tools().db.clone())
455    }
456
457    /// 使用工具
458    fn tools(&mut self) -> Tools {
459        let tools_map = PLUGIN_TOOLS.lock().unwrap_or_else(|e| e.into_inner());
460        let tools = tools_map.get("tools").unwrap().clone();
461        tools
462    }
463    /// 使用配置
464    fn config(&mut self, name: &str) -> JsonValue {
465        let config_map = CONFIG.lock().unwrap_or_else(|e| e.into_inner());
466        if config_map.get(name).is_none() {
467            object! {}
468        } else {
469            config_map.get(name).unwrap().clone()
470        }
471    }
472    /// 按钮信息
473    /// * cnd 显示条件 vec![vec!["xxx","=","yyy"],vec!["zzz","=","eee"]]
474    fn btn(&mut self) -> Btn {
475        let mut btn = Btn::new(self.api().as_str());
476        btn.fields(self.params().clone());
477        btn.tags(self.tags());
478        btn.icon(self.icon());
479        btn.desc(self.description());
480        btn.auth(self.auth());
481        btn.public(self.public());
482        btn.title(self.title());
483        btn.btn_type(BtnType::Api);
484        btn.btn_color(BtnColor::Primary);
485        btn.path(self.api().clone().replace(".", "/").as_str());
486        btn.pass(false);
487        btn.addon();
488        btn
489    }
490    /// 设置全局变量
491    fn set_global_data(&mut self, key: &str, value: JsonValue) {
492        GLOBAL_DATA.with(|data| {
493            data.borrow_mut()[key] = value;
494        });
495    }
496    /// 获取全局变量数据
497    fn get_global_data(&mut self) -> JsonValue {
498        GLOBAL_DATA.with(|data| {
499            data.borrow().clone()
500        })
501    }
502    /// 获取全局变量指定字段数据
503    fn get_global_data_key(&mut self, key: &str) -> JsonValue {
504        GLOBAL_DATA.with(|data| {
505            data.borrow()[key].clone()
506        })
507    }
508}
509#[derive(Debug, Clone)]
510pub struct Btn {
511    api: String,
512    title: String,
513    desc: String,
514    tags: &'static [&'static str],
515    auth: bool,
516    public: bool,
517    btn_type: BtnType,
518    color: BtnColor,
519    icon: String,
520    cnd: Vec<JsonValue>,
521    url: String,
522    path: String,
523    fields: JsonValue,
524    addon: String,
525    version: usize,
526    /// 是否需要密码
527    pass: bool,
528}
529impl Btn {
530    pub fn new(api: &str) -> Self {
531        Self {
532            api: api.to_string(),
533            title: "".to_string(),
534            desc: "".to_string(),
535            btn_type: BtnType::Api,
536            color: BtnColor::Primary,
537            icon: "".to_string(),
538            auth: false,
539            public: false,
540            cnd: vec![],
541            url: "".to_string(),
542            path: "".to_string(),
543            fields: object! {},
544            tags: &[],
545            pass: false,
546            addon: "".to_string(),
547            version: 0,
548        }
549    }
550
551    pub fn addon(&mut self) -> &mut Self {
552        self.addon = self.api.split('.').nth(0).unwrap().to_string();
553        self
554    }
555    pub fn path(&mut self, path: &str) -> &mut Self {
556        self.path = path.to_string();
557        self
558    }
559    pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
560        self.cnd = cnd;
561        self
562    }
563    pub fn version(&mut self, version: usize) -> &mut Self {
564        self.version = version;
565        self
566    }
567    pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
568        self.btn_type = btn_type;
569        self
570    }
571    pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
572        self.color = btn_color;
573        self
574    }
575    pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
576        self.fields = fields;
577        self
578    }
579    pub fn pass(&mut self, pass: bool) -> &mut Self {
580        self.pass = pass;
581        self
582    }
583    pub fn url(&mut self, url: &str) -> &mut Self {
584        self.url = url.to_string();
585        self
586    }
587    pub fn title(&mut self, title: &str) -> &mut Self {
588        self.title = title.to_string();
589        self
590    }
591    pub fn desc(&mut self, desc: &str) -> &mut Self {
592        self.desc = desc.to_string();
593        self
594    }
595    pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
596        self.tags = tags;
597        self
598    }
599    pub fn public(&mut self, public: bool) -> &mut Self {
600        self.public = public;
601        self
602    }
603    pub fn auth(&mut self, auth: bool) -> &mut Self {
604        self.auth = auth;
605        self
606    }
607    pub fn icon(&mut self, icon: &str) -> &mut Self {
608        self.icon = icon.to_string();
609        self
610    }
611    pub fn json(&mut self) -> JsonValue {
612        let color = match self.version {
613            0 => self.color.clone().str(),
614            _ => self.color.clone().str_v_1()
615        };
616        object! {
617            addon:self.addon.to_string() ,
618            api:self.api.clone(),
619            title:self.title.clone(),
620            desc:self.desc.clone(),
621            auth:self.auth,
622            public:self.public,
623            btn_type:self.btn_type.clone().str(),
624            color:color,
625            icon:self.icon.clone(),
626            cnd:self.cnd.clone(),
627            url:self.url.clone(),
628            path:self.path.clone(),
629            fields:self.fields.clone(),
630            tags:self.tags,
631            pass:self.pass,
632        }
633    }
634}
635
636/// 接口类型
637#[derive(Debug, Clone)]
638pub enum InterfaceType {
639    API,
640    BTN,
641    MENU,
642    OPENAPI,
643}
644
645impl InterfaceType {
646    pub fn str(&self) -> &'static str {
647        match self {
648            InterfaceType::API => "api",
649            InterfaceType::BTN => "btn",
650            InterfaceType::MENU => "menu",
651            InterfaceType::OPENAPI => "openapi",
652        }
653    }
654    pub fn types() -> Vec<&'static str> {
655        vec!["api", "btn", "menu", "openapi"]
656    }
657}
658
659/// 按钮类型
660#[derive(Debug, Clone)]
661pub enum BtnType {
662    /// 表单
663    Form,
664    /// 表单下载
665    FormDownload,
666    /// 表单自定义
667    FormCustom,
668    FormData,
669    /// 外部跳转
670    Url,
671    /// api请求
672    Api,
673    /// 下载
674    Download,
675    /// 内部跳转
676    Path,
677    /// 弹窗-定制页面
678    DialogCustom,
679    /// 表单->API->弹出自定义窗口
680    FormApiDialogCustom,
681    /// 预览
682    Preview,
683}
684
685impl BtnType {
686    fn str(self) -> &'static str {
687        match self {
688            BtnType::Form => "form",
689            BtnType::FormDownload => "form_download",
690            BtnType::FormCustom => "form_custom",
691            BtnType::FormData => "form_data",
692            BtnType::Api => "api",
693            BtnType::Download => "download",
694            BtnType::Url => "url",
695            BtnType::Path => "path",
696            BtnType::DialogCustom => "dialog_custom",
697            BtnType::FormApiDialogCustom => "form_api_dialog_custom",
698            BtnType::Preview => "preview",
699        }
700    }
701}
702/// 按钮颜色
703#[derive(Debug, Clone)]
704pub enum BtnColor {
705    Primary,
706    Red,
707    Yellow,
708    Green,
709}
710
711impl BtnColor {
712    fn str(self) -> &'static str {
713        match self {
714            BtnColor::Primary => "primary",
715            BtnColor::Red => "negative",
716            BtnColor::Yellow => "warning",
717            BtnColor::Green => "positive",
718        }
719    }
720    fn str_v_1(self) -> &'static str {
721        match self {
722            BtnColor::Primary => "normal",
723            BtnColor::Red => "danger",
724            BtnColor::Yellow => "warning",
725            BtnColor::Green => "success",
726        }
727    }
728}
729
730
731pub struct Dashboard {
732    /// 名称
733    title: String,
734    /// 数据
735    data: JsonValue,
736    /// 显示样式
737    model: DashboardModel,
738    /// 渲染样式
739    class: String,
740    /// 图标
741    icon: String,
742    /// 描述
743    desc: String,
744    ///数据请求接口
745    api: String,
746    ///用户选项,同时也是api接收的参数
747    options: JsonValue,
748}
749impl Dashboard {
750    pub fn new(title: &str) -> Dashboard {
751        Dashboard {
752            title: title.to_string(),
753            data: JsonValue::Null,
754            model: DashboardModel::Number,
755            class: "col-4".to_string(),
756            icon: "".to_string(),
757            desc: "".to_string(),
758            api: "".to_string(),
759            options: JsonValue::Null,
760        }
761    }
762    pub fn options(&mut self, options: JsonValue) -> &mut Self {
763        self.options = options;
764        self
765    }
766    pub fn api(&mut self, api: &str) -> &mut Self {
767        self.api = api.to_string();
768        self
769    }
770    pub fn data(&mut self, data: JsonValue) -> &mut Self {
771        self.data = data;
772        self
773    }
774    pub fn class(&mut self, name: &str) -> &mut Self {
775        self.class = name.to_string();
776        self
777    }
778    pub fn icon(&mut self, name: &str) -> &mut Self {
779        self.icon = name.to_string();
780        self
781    }
782    pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
783        self.model = dashboard_model;
784        self
785    }
786    pub fn desc(&mut self, desc: &str) -> &mut Self {
787        self.desc = desc.to_string();
788        self
789    }
790    pub fn json(&self) -> JsonValue {
791        object! {
792            title: self.title.clone(),
793            data: self.data.clone(),
794            class: self.class.clone(),
795            icon: self.icon.clone(),
796            model: self.model.str(),
797            desc: self.desc.clone(),
798            api: self.api.clone(),
799            options:self.options.clone(),
800        }
801    }
802}
803
804pub enum DashboardModel {
805    /// 数字
806    Number,
807    /// 柱状图
808    EchartsBar,
809    /// 堆叠柱状图
810    EchartsStackedBar,
811    /// 动态排序的柱状图
812    EchartsBarRace,
813    /// 饼图
814    EchartsPie,
815    /// 中空饼图
816    EchartsDoughnut,
817    /// 堆叠折线图
818    EchartsStackedLine,
819    /// 面积填充的堆叠折线图
820    EchartsStackedLineArea,
821    /// 地图
822    EchartsGeoGraph,
823}
824
825impl DashboardModel {
826    pub fn str(&self) -> &'static str {
827        match self {
828            Self::Number => "number",
829            Self::EchartsBar => "echarts-bar",
830            Self::EchartsStackedBar => "echarts-stacked_bar",
831            Self::EchartsBarRace => "echarts-bar_race",
832            Self::EchartsPie => "echarts-pie",
833            Self::EchartsDoughnut => "echarts-doughnut",
834            Self::EchartsStackedLine => "echarts-stacked_line",
835            Self::EchartsStackedLineArea => "echarts-stacked_line_area",
836            Self::EchartsGeoGraph => "echarts-geo_graph",
837        }
838    }
839}