Skip to main content

br_addon/
action.rs

1use crate::request::{ContentType, Method, Request};
2use crate::tables::Tables;
3use crate::{ApiResponse, Tools};
4use crate::{CONFIG, GLOBAL_DATA, PLUGIN_TOOLS};
5use br_fields::Field;
6use json::{object, JsonValue};
7use std::any::type_name;
8
9/// 功能接口
10pub trait Action {
11    /// 功能名称
12    fn _name(&self) -> String {
13        type_name::<Self>()
14            .rsplit("::")
15            .next()
16            .unwrap_or_default()
17            .to_lowercase()
18    }
19    /// 模块名称
20    fn module_name(&self) -> String {
21        let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
22        let plugin = t[2].to_lowercase();
23        let module = t[3].to_lowercase();
24        format!("{plugin}.{module}")
25    }
26    /// 插件名称
27    fn addon_name(&self) -> String {
28        let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
29        t[2].to_lowercase()
30    }
31    /// API 名称
32    fn api(&self) -> String {
33        let t = type_name::<Self>().split("::").collect::<Vec<&str>>();
34        let plugin = t[2].to_lowercase();
35        let module = t[3].to_lowercase();
36        let action = t[4].to_lowercase();
37        format!("{plugin}.{module}.{action}")
38    }
39    /// 是否需要密钥
40    fn token(&self) -> bool {
41        true
42    }
43
44    fn sort(&self) -> usize {
45        99
46    }
47    /// 分组名称(用于菜单分组)
48    fn group_name(&self) -> &'static str {
49        ""
50    }
51    /// 功能标题
52    fn title(&self) -> &'static str;
53    /// 功能描述
54    fn description(&self) -> &'static str {
55        ""
56    }
57    /// 请求地址路径
58    fn path(&self) -> &'static str {
59        ""
60    }
61    /// 请求地址参数
62    fn query(&self) -> JsonValue {
63        object! {}
64    }
65    /// 标签范围
66    fn tags(&self) -> &'static [&'static str] {
67        &[]
68    }
69    fn icon(&self) -> &'static str {
70        ""
71    }
72    /// 是否公开
73    fn public(&self) -> bool {
74        true
75    }
76    /// 是否权限组显示
77    fn auth(&self) -> bool {
78        true
79    }
80    /// 接口类型 btn api menu
81    fn interface_type(&self) -> InterfaceType {
82        InterfaceType::Api
83    }
84    /// 允许的请求类型
85    fn method(&mut self) -> Method {
86        Method::Post
87    }
88    /// 请求类型
89    fn content_type(&mut self) -> ContentType {
90        ContentType::Json
91    }
92    /// 是否检查参数
93    fn params_check(&mut self) -> bool {
94        true
95    }
96    /// 请求body参数
97    fn params(&mut self) -> JsonValue {
98        object! {}
99    }
100    /// 成功响应
101    fn success(&mut self) -> ApiResponse {
102        let mut data = object! {};
103        data["code"] = br_fields::int::Int::new(true, "code", "编号", 10, 0)
104            .example(0.into())
105            .swagger();
106        data["message"] = br_fields::str::Str::new(true, "message", "成功消息", 256, "")
107            .example("成功".into())
108            .swagger();
109        data["data"] = br_fields::text::Object::new(true, "data", "返回数据", object! {}).swagger();
110        data["success"] = br_fields::int::Switch::new(true, "success", "成功状态", true)
111            .example(true.into())
112            .swagger();
113        data["timestamp"] =
114            br_fields::datetime::Timestamp::new(true, "timestamp", "时间戳", 0, 0.0).swagger();
115        ApiResponse::success(data, "请求成功")
116    }
117    /// 失败响应
118    fn error(&mut self) -> ApiResponse {
119        let mut data = object! {};
120        data["code"] = br_fields::int::Int::new(true, "code", "编号", 10, 1000)
121            .example(1000.into())
122            .swagger();
123        data["message"] = br_fields::str::Str::new(true, "message", "错误消息", 256, "")
124            .example("失败".into())
125            .swagger();
126        data["data"] = br_fields::text::Object::new(true, "data", "返回数据", object! {}).swagger();
127        data["success"] = br_fields::int::Switch::new(true, "success", "成功状态", false)
128            .example(false.into())
129            .swagger();
130        data["timestamp"] =
131            br_fields::datetime::Timestamp::new(true, "timestamp", "时间戳", 0, 0.0).swagger();
132        ApiResponse::error(data, "请求失败")
133    }
134    /// 外部入口
135    fn run(&mut self, mut request: Request) -> Result<ApiResponse, ApiResponse> {
136        if self.public()
137            && !self.method().str().is_empty()
138            && self.method().str().to_lowercase() != request.method.str().to_lowercase()
139        {
140            return Err(ApiResponse::fail(
141                -1,
142                format!(
143                    "Request type error: Actual [{}] Expected [{}]",
144                    request.method.str(),
145                    self.method().str()
146                )
147                .as_str(),
148            ));
149        }
150        let params = self.params();
151        if self.params_check() {
152            self.check(&mut request.query, self.query())?;
153            self.check(&mut request.body, params)?;
154        }
155        let res = self.index(request);
156        if res.success {
157            Ok(res)
158        } else {
159            Err(res)
160        }
161    }
162    /// 入参验证
163    fn check(&mut self, request: &mut JsonValue, params: JsonValue) -> Result<(), ApiResponse> {
164        let req = request.clone();
165        for (name, _) in req.entries() {
166            if !params.has_key(name) {
167                request.remove(name);
168            }
169        }
170        for (name, field) in params.entries() {
171            let require = field["require"].as_bool().unwrap_or(false);
172            let title = field["title"].as_str().unwrap_or("");
173            if request.has_key(name) {
174                // 判断输入类型
175                match field["mode"].as_str().unwrap_or("text") {
176                    "key" => {
177                        if !request[name].is_string() {
178                            return Err(ApiResponse::fail(
179                                900_001,
180                                format!(
181                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
182                                    name, field["mode"]
183                                )
184                                .as_str(),
185                            ));
186                        }
187                        if require && request[name].is_empty() {
188                            return Err(ApiResponse::fail(
189                                900_014,
190                                format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
191                            ));
192                        }
193                    }
194                    "text" | "table" | "tree" => {
195                        let is_multiple = field["multiple"].as_bool().unwrap_or(false);
196                        if is_multiple {
197                            if !request[name].is_array() {
198                                return Err(ApiResponse::fail(
199                                    900_009,
200                                    format!(
201                                        "请求参数数据类型错误: 参数 [{}] 数据类型应为数组",
202                                        name
203                                    )
204                                    .as_str(),
205                                ));
206                            }
207                            if require && request[name].is_empty() {
208                                return Err(ApiResponse::fail(
209                                    900_010,
210                                    format!("{title} 必填").as_str(),
211                                ));
212                            }
213                        } else {
214                            if !request[name].is_string() {
215                                return Err(ApiResponse::fail(
216                                    900_002,
217                                    format!(
218                                        "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
219                                        name, field["mode"]
220                                    )
221                                    .as_str(),
222                                ));
223                            }
224                            if require && request[name].is_empty() {
225                                return Err(ApiResponse::fail(
226                                    900_002,
227                                    format!("{title} 必填").as_str(),
228                                ));
229                            }
230                        }
231                    }
232                    "file" => {
233                        if !request[name].is_array() && !request[name].is_string() {
234                            return Err(ApiResponse::fail(
235                                900_003,
236                                format!("参数 [{}] 数据类型应为[{}]", name, field["mode"]).as_str(),
237                            ));
238                        }
239                        if require && request[name].is_empty() {
240                            return Err(ApiResponse::fail(
241                                900_002,
242                                format!("{title} 必填").as_str(),
243                            ));
244                        }
245                    }
246                    "int" => {
247                        if require && request[name].to_string().is_empty() {
248                            return Err(ApiResponse::fail(
249                                900_002,
250                                format!("{title} 必填").as_str(),
251                            ));
252                        }
253                        if !request[name].to_string().is_empty() {
254                            match request[name].to_string().parse::<i64>() {
255                                Ok(_) => {}
256                                Err(_) => {
257                                    return Err(ApiResponse::fail(
258                                        900_013,
259                                        format!(
260                                            "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
261                                            name, field["mode"]
262                                        )
263                                        .as_str(),
264                                    ));
265                                }
266                            }
267                        }
268                    }
269                    "timestamp" | "yearmonth" | "date" | "datetime" => {
270                        if require && request[name].to_string().is_empty() {
271                            return Err(ApiResponse::fail(
272                                900_002,
273                                format!("{title} 必填").as_str(),
274                            ));
275                        }
276                        if !request[name].to_string().is_empty() {
277                            if request[name].is_array() && request[name].len() == 2 {
278                                // 如果是数组,遍历每个元素
279                                for item in request[name].members() {
280                                    match item.to_string().parse::<f64>() {
281                                        Ok(_) => {}
282                                        Err(_) => {
283                                            return Err(ApiResponse::fail(
284                                                900_013,
285                                                format!(
286                                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
287                                                    name, field["mode"]
288                                                ).as_str(),
289                                            ));
290                                        }
291                                    }
292                                }
293                            } else {
294                                match request[name].to_string().parse::<f64>() {
295                                    Ok(_) => {}
296                                    Err(_) => {
297                                        return Err(ApiResponse::fail(
298                                            900_013,
299                                            format!(
300                                                "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
301                                                name, field["mode"]
302                                            )
303                                            .as_str(),
304                                        ));
305                                    }
306                                }
307                            }
308                        }
309                    }
310                    "float" => {
311                        if require && request[name].to_string().is_empty() {
312                            return Err(ApiResponse::fail(
313                                900_002,
314                                format!("{title} 必填").as_str(),
315                            ));
316                        }
317                        if !request[name].to_string().is_empty() {
318                            match request[name].to_string().parse::<f64>() {
319                                Ok(_) => {}
320                                Err(_) => {
321                                    return Err(ApiResponse::fail(
322                                        900_023,
323                                        format!(
324                                            "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
325                                            name, field["mode"]
326                                        )
327                                        .as_str(),
328                                    ));
329                                }
330                            }
331                        }
332                    }
333                    "string" | "url" | "time" | "code" | "pass" | "email" | "location"
334                    | "color" | "barcode" | "editor" | "tel" => {
335                        if !request[name].is_string() {
336                            return Err(ApiResponse::fail(
337                                -1,
338                                format!(
339                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
340                                    name, field["mode"]
341                                )
342                                .as_str(),
343                            ));
344                        }
345                        if require && request[name].is_empty() {
346                            return Err(ApiResponse::fail(
347                                900_004,
348                                format!("{title} 必填").as_str(),
349                            ));
350                        }
351                    }
352                    "dict" => {
353                        if require && request[name].is_empty() {
354                            return Err(ApiResponse::fail(
355                                900_005,
356                                format!("{title} 必填").as_str(),
357                            ));
358                        }
359                    }
360                    "switch" => match request[name].to_string().parse::<bool>() {
361                        Ok(e) => {
362                            request[name] = e.into();
363                        }
364                        Err(_) => {
365                            return Err(ApiResponse::fail(
366                                -1,
367                                format!(
368                                    "请求参数数据类型错误: 参数 [{name}] 数据类型应为[{}]",
369                                    field["mode"]
370                                )
371                                .as_str(),
372                            ));
373                        }
374                    },
375                    "select" => {
376                        if !request[name].is_array() && !request[name].is_string() {
377                            return Err(ApiResponse::fail(
378                                -1,
379                                format!(
380                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
381                                    name, field["mode"]
382                                )
383                                .as_str(),
384                            ));
385                        }
386                        let value = if request[name].is_array() {
387                            request[name]
388                                .members()
389                                .map(ToString::to_string)
390                                .collect::<Vec<String>>()
391                        } else {
392                            request[name]
393                                .to_string()
394                                .split(',')
395                                .map(ToString::to_string)
396                                .collect::<Vec<String>>()
397                        };
398                        let option = field["option"]
399                            .members()
400                            .map(|m| m.as_str().unwrap_or(""))
401                            .collect::<Vec<&str>>();
402
403                        let require = field["require"].as_bool().unwrap_or(false);
404                        for item in value.clone() {
405                            if !option.contains(&&*item.clone()) && (item.is_empty() && require) {
406                                let option = field["option"]
407                                    .members()
408                                    .map(|m| m.as_str().unwrap_or(""))
409                                    .collect::<Vec<&str>>()
410                                    .join(",");
411                                return Err(ApiResponse::fail(-1, format!("请求参数选项错误: 参数 [{item}] 数据类型应为[{option}]之内").as_str()));
412                            }
413                        }
414                        request[name] = value.into();
415                    }
416                    "radio" => {
417                        if !request[name].is_string() {
418                            return Err(ApiResponse::fail(
419                                -1,
420                                format!(
421                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}] 实际为[{}]",
422                                    name, field["mode"], request[name]
423                                )
424                                .as_str(),
425                            ));
426                        }
427                        let option = field["option"]
428                            .members()
429                            .map(|m| m.as_str().unwrap_or(""))
430                            .collect::<Vec<&str>>()
431                            .join(",");
432                        if request[name].is_string()
433                            && !field["option"].contains(request[name].as_str().unwrap_or(""))
434                        {
435                            return Err(ApiResponse::fail(
436                                -1,
437                                format!(
438                                    "请求参数选项错误: 参数 [{}] 数据 [{}] 应为 [{}] 之一",
439                                    name, request[name], option
440                                )
441                                .as_str(),
442                            ));
443                        }
444                    }
445                    "array" | "polygon" | "keys" | "table_multiple" => {
446                        if !request[name].is_array() {
447                            return Err(ApiResponse::fail(
448                                900_009,
449                                format!(
450                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
451                                    name, field["mode"]
452                                )
453                                .as_str(),
454                            ));
455                        }
456                        if require && request[name].is_empty() {
457                            return Err(ApiResponse::fail(
458                                900_010,
459                                format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
460                            ));
461                        }
462                    }
463                    "object" => {
464                        if !request[name].is_object() {
465                            return Err(ApiResponse::fail(
466                                900_009,
467                                format!(
468                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
469                                    name, field["mode"]
470                                )
471                                .as_str(),
472                            ));
473                        }
474                        if require && request[name].is_empty() {
475                            return Err(ApiResponse::fail(
476                                900_006,
477                                format!("{title} 必填").as_str(),
478                            ));
479                        }
480                    }
481                    _ => {
482                        log::warn!("检查未知类型: {}", field["mode"]);
483                    }
484                }
485            } else {
486                if require {
487                    return Err(ApiResponse::fail(900_007, format!("{title} 必填").as_str()));
488                }
489                request[name] = field["def"].clone();
490            }
491        }
492        Ok(())
493    }
494    /// 内部入口
495    fn index(&mut self, request: Request) -> ApiResponse;
496    #[cfg(any(
497        feature = "sqlite",
498        feature = "mssql",
499        feature = "mysql",
500        feature = "pgsql"
501    ))]
502    fn table_select(
503        &mut self,
504        request: JsonValue,
505        table_name: &str,
506        fields: Vec<&str>,
507    ) -> JsonValue {
508        self.table()
509            .main_select_fields(table_name, fields)
510            .params(request)
511            .get_table_select()
512    }
513
514    #[cfg(any(
515        feature = "sqlite",
516        feature = "mssql",
517        feature = "mysql",
518        feature = "pgsql"
519    ))]
520    fn table(&mut self) -> Tables {
521        Tables::new(self.tools().db)
522    }
523
524    /// 使用工具
525    fn tools(&mut self) -> Tools {
526        PLUGIN_TOOLS.get().expect("tools not initialized").clone()
527    }
528    /// 使用配置
529    fn config(&mut self, name: &str) -> JsonValue {
530        if let Ok(cfg) = CONFIG.lock() {
531            cfg.get(name).cloned().unwrap_or_else(|| object! {})
532        } else {
533            object! {}
534        }
535    }
536    /// 按钮信息
537    /// * cnd 显示条件 vec![vec!["xxx","=","yyy"],vec!["zzz","=","eee"]]
538    fn btn(&mut self) -> Btn {
539        let mut btn = Btn::new(self.api().as_str());
540        btn.fields(self.params());
541        btn.tags(self.tags());
542        btn.icon(self.icon());
543        btn.desc(self.description());
544        btn.auth(self.auth());
545        btn.public(self.public());
546        btn.title(self.title());
547        btn.btn_type(BtnType::Api);
548        btn.btn_color(BtnColor::Primary);
549        btn.path(self.api().replace('.', "/").as_str());
550        btn.pass(false);
551        btn.addon();
552        btn
553    }
554    /// 设置全局变量
555    fn set_global_data(&mut self, key: &str, value: JsonValue) {
556        GLOBAL_DATA.with(|data| {
557            data.borrow_mut()[key] = value;
558        });
559    }
560    /// 获取全局变量数据
561    fn get_global_data(&mut self) -> JsonValue {
562        GLOBAL_DATA.with(|data| data.borrow().clone())
563    }
564    /// 获取全局变量指定字段数据
565    fn get_global_data_key(&mut self, key: &str) -> JsonValue {
566        GLOBAL_DATA.with(|data| data.borrow()[key].clone())
567    }
568}
569#[derive(Debug, Clone)]
570pub struct Btn {
571    api: String,
572    title: String,
573    desc: String,
574    tags: &'static [&'static str],
575    auth: bool,
576    public: bool,
577    btn_type: BtnType,
578    color: BtnColor,
579    icon: String,
580    cnd: Vec<JsonValue>,
581    url: String,
582    path: String,
583    fields: JsonValue,
584    addon: String,
585    /// 是否需要密码
586    pass: bool,
587}
588impl Btn {
589    #[must_use]
590    pub fn new(api: &str) -> Self {
591        Self {
592            api: api.to_string(),
593            title: String::new(),
594            desc: String::new(),
595            btn_type: BtnType::Api,
596            color: BtnColor::Primary,
597            icon: String::new(),
598            auth: false,
599            public: false,
600            cnd: vec![],
601            url: String::new(),
602            path: String::new(),
603            fields: object! {},
604            tags: &[],
605            pass: false,
606            addon: String::new(),
607        }
608    }
609
610    pub fn addon(&mut self) -> &mut Self {
611        self.addon = self.api.split('.').next().unwrap_or_default().to_string();
612        self
613    }
614    pub fn path(&mut self, path: &str) -> &mut Self {
615        self.path = path.to_string();
616        self
617    }
618    pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
619        self.cnd = cnd;
620        self
621    }
622    pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
623        self.btn_type = btn_type;
624        self
625    }
626    pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
627        self.color = btn_color;
628        self
629    }
630    pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
631        self.fields = fields;
632        self
633    }
634    pub fn pass(&mut self, pass: bool) -> &mut Self {
635        self.pass = pass;
636        self
637    }
638    pub fn url(&mut self, url: &str) -> &mut Self {
639        self.url = url.to_string();
640        self
641    }
642    pub fn title(&mut self, title: &str) -> &mut Self {
643        self.title = title.to_string();
644        self
645    }
646    pub fn desc(&mut self, desc: &str) -> &mut Self {
647        self.desc = desc.to_string();
648        self
649    }
650    pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
651        self.tags = tags;
652        self
653    }
654    pub fn public(&mut self, public: bool) -> &mut Self {
655        self.public = public;
656        self
657    }
658    pub fn auth(&mut self, auth: bool) -> &mut Self {
659        self.auth = auth;
660        self
661    }
662    pub fn icon(&mut self, icon: &str) -> &mut Self {
663        self.icon = icon.to_string();
664        self
665    }
666    pub fn json(&mut self) -> JsonValue {
667        let color = self.color.clone().str();
668        object! {
669            addon:self.addon.to_string() ,
670            api:self.api.clone(),
671            title:self.title.clone(),
672            desc:self.desc.clone(),
673            auth:self.auth,
674            public:self.public,
675            btn_type:self.btn_type.clone().str(),
676            color:color,
677            icon:self.icon.clone(),
678            cnd:self.cnd.clone(),
679            url:self.url.clone(),
680            path:self.path.clone(),
681            fields:self.fields.clone(),
682            tags:self.tags,
683            pass:self.pass,
684        }
685    }
686}
687
688/// 接口类型
689#[derive(Debug, Clone)]
690pub enum InterfaceType {
691    Api,
692    Btn,
693    Menu,
694    MenuApp,
695    OpenApi,
696}
697
698impl InterfaceType {
699    pub fn str(&self) -> &'static str {
700        match self {
701            InterfaceType::Api => "api",
702            InterfaceType::Btn => "btn",
703            InterfaceType::Menu => "menu",
704            InterfaceType::MenuApp => "menu_app",
705            InterfaceType::OpenApi => "openapi",
706        }
707    }
708    pub fn types() -> Vec<&'static str> {
709        vec!["api", "btn", "menu", "menu_app", "openapi"]
710    }
711}
712
713/// 按钮类型
714#[derive(Debug, Clone)]
715pub enum BtnType {
716    /// 表单
717    Form,
718    /// 表单下载
719    FormDownload,
720    /// 表单自定义
721    FormCustom,
722    FormData,
723    /// 外部跳转
724    Url,
725    /// api请求
726    Api,
727    /// 下载
728    Download,
729    /// 内部跳转
730    Path,
731    /// 弹窗-定制页面
732    DialogCustom,
733    /// 表单->API->弹出自定义窗口
734    FormApiDialogCustom,
735    /// 预览
736    Preview,
737}
738
739impl BtnType {
740    fn str(self) -> &'static str {
741        match self {
742            BtnType::Form => "form",
743            BtnType::FormDownload => "form_download",
744            BtnType::FormCustom => "form_custom",
745            BtnType::FormData => "form_data",
746            BtnType::Api => "api",
747            BtnType::Download => "download",
748            BtnType::Url => "url",
749            BtnType::Path => "path",
750            BtnType::DialogCustom => "dialog_custom",
751            BtnType::FormApiDialogCustom => "form_api_dialog_custom",
752            BtnType::Preview => "preview",
753        }
754    }
755}
756/// 按钮颜色
757#[derive(Debug, Clone)]
758pub enum BtnColor {
759    Primary,
760    Red,
761    Yellow,
762    Green,
763    Blue,
764    Orange,
765    Purple,
766    Cyan,
767    Teal,
768    Grey,
769}
770
771impl BtnColor {
772    fn str(self) -> &'static str {
773        match self {
774            BtnColor::Primary => "primary",
775            BtnColor::Red => "negative",
776            BtnColor::Yellow => "warning",
777            BtnColor::Green => "positive",
778            BtnColor::Blue => "blue",
779            BtnColor::Orange => "orange",
780            BtnColor::Purple => "purple",
781            BtnColor::Cyan => "cyan",
782            BtnColor::Teal => "teal",
783            BtnColor::Grey => "grey",
784        }
785    }
786}
787
788pub struct Dashboard {
789    /// 名称
790    title: String,
791    /// 数据
792    data: JsonValue,
793    /// 显示样式
794    model: DashboardModel,
795    /// 渲染样式
796    class: String,
797    /// 图标
798    icon: String,
799    /// 描述
800    desc: String,
801    ///数据请求接口
802    api: String,
803    ///用户选项,同时也是api接收的参数
804    options: JsonValue,
805}
806impl Dashboard {
807    pub fn new(title: &str) -> Dashboard {
808        Dashboard {
809            title: title.to_string(),
810            data: JsonValue::Null,
811            model: DashboardModel::Number,
812            class: "col-4".to_string(),
813            icon: "".to_string(),
814            desc: "".to_string(),
815            api: "".to_string(),
816            options: JsonValue::Null,
817        }
818    }
819    pub fn options(&mut self, options: JsonValue) -> &mut Self {
820        self.options = options;
821        self
822    }
823    pub fn api(&mut self, api: &str) -> &mut Self {
824        self.api = api.to_string();
825        self
826    }
827    pub fn data(&mut self, data: JsonValue) -> &mut Self {
828        self.data = data;
829        self
830    }
831    pub fn class(&mut self, name: &str) -> &mut Self {
832        self.class = name.to_string();
833        self
834    }
835    pub fn icon(&mut self, name: &str) -> &mut Self {
836        self.icon = name.to_string();
837        self
838    }
839    pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
840        self.model = dashboard_model;
841        self
842    }
843    pub fn desc(&mut self, desc: &str) -> &mut Self {
844        self.desc = desc.to_string();
845        self
846    }
847    pub fn json(&self) -> JsonValue {
848        object! {
849            title: self.title.clone(),
850            data: self.data.clone(),
851            class: self.class.clone(),
852            icon: self.icon.clone(),
853            model: self.model.str(),
854            desc: self.desc.clone(),
855            api: self.api.clone(),
856            options:self.options.clone(),
857        }
858    }
859}
860
861pub enum DashboardModel {
862    /// 数字
863    Number,
864    /// 柱状图
865    EchartsBar,
866    /// 堆叠柱状图
867    EchartsStackedBar,
868    /// 动态排序的柱状图
869    EchartsBarRace,
870    /// 饼图
871    EchartsPie,
872    /// 中空饼图
873    EchartsDoughnut,
874    /// 堆叠折线图
875    EchartsStackedLine,
876    /// 面积填充的堆叠折线图
877    EchartsStackedLineArea,
878    /// 地图
879    EchartsGeoGraph,
880}
881
882impl DashboardModel {
883    pub fn str(&self) -> &'static str {
884        match self {
885            Self::Number => "number",
886            Self::EchartsBar => "echarts-bar",
887            Self::EchartsStackedBar => "echarts-stacked_bar",
888            Self::EchartsBarRace => "echarts-bar_race",
889            Self::EchartsPie => "echarts-pie",
890            Self::EchartsDoughnut => "echarts-doughnut",
891            Self::EchartsStackedLine => "echarts-stacked_line",
892            Self::EchartsStackedLineArea => "echarts-stacked_line_area",
893            Self::EchartsGeoGraph => "echarts-geo_graph",
894        }
895    }
896}