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 = PLUGIN_TOOLS.lock().unwrap();
460        let tools = tools.get("tools").unwrap().clone();
461        tools
462    }
463    /// 使用配置
464    fn config(&mut self, name: &str) -> JsonValue {
465        if CONFIG.lock().unwrap().get(name).is_none() {
466            object! {}
467        } else {
468            CONFIG.lock().unwrap().get(name).unwrap().clone()
469        }
470    }
471    /// 按钮信息
472    /// * cnd 显示条件 vec![vec!["xxx","=","yyy"],vec!["zzz","=","eee"]]
473    fn btn(&mut self) -> Btn {
474        let mut btn = Btn::new(self.api().as_str());
475        btn.fields(self.params().clone());
476        btn.tags(self.tags());
477        btn.icon(self.icon());
478        btn.desc(self.description());
479        btn.auth(self.auth());
480        btn.public(self.public());
481        btn.title(self.title());
482        btn.btn_type(BtnType::Api);
483        btn.btn_color(BtnColor::Primary);
484        btn.path(self.api().clone().replace(".", "/").as_str());
485        btn.pass(false);
486        btn.addon();
487        btn
488    }
489    /// 设置全局变量
490    fn set_global_data(&mut self, key: &str, value: JsonValue) {
491        GLOBAL_DATA.with(|data| {
492            data.borrow_mut()[key] = value;
493        });
494    }
495    /// 获取全局变量数据
496    fn get_global_data(&mut self) -> JsonValue {
497        GLOBAL_DATA.with(|data| {
498            data.borrow().clone()
499        })
500    }
501    /// 获取全局变量指定字段数据
502    fn get_global_data_key(&mut self, key: &str) -> JsonValue {
503        GLOBAL_DATA.with(|data| {
504            data.borrow()[key].clone()
505        })
506    }
507}
508#[derive(Debug, Clone)]
509pub struct Btn {
510    api: String,
511    title: String,
512    desc: String,
513    tags: &'static [&'static str],
514    auth: bool,
515    public: bool,
516    btn_type: BtnType,
517    color: BtnColor,
518    icon: String,
519    cnd: Vec<JsonValue>,
520    url: String,
521    path: String,
522    fields: JsonValue,
523    addon: String,
524    version: usize,
525    /// 是否需要密码
526    pass: bool,
527}
528impl Btn {
529    pub fn new(api: &str) -> Self {
530        Self {
531            api: api.to_string(),
532            title: "".to_string(),
533            desc: "".to_string(),
534            btn_type: BtnType::Api,
535            color: BtnColor::Primary,
536            icon: "".to_string(),
537            auth: false,
538            public: false,
539            cnd: vec![],
540            url: "".to_string(),
541            path: "".to_string(),
542            fields: object! {},
543            tags: &[],
544            pass: false,
545            addon: "".to_string(),
546            version: 0,
547        }
548    }
549
550    pub fn addon(&mut self) -> &mut Self {
551        self.addon = self.api.split('.').nth(0).unwrap().to_string();
552        self
553    }
554    pub fn path(&mut self, path: &str) -> &mut Self {
555        self.path = path.to_string();
556        self
557    }
558    pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
559        self.cnd = cnd;
560        self
561    }
562    pub fn version(&mut self, version: usize) -> &mut Self {
563        self.version = version;
564        self
565    }
566    pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
567        self.btn_type = btn_type;
568        self
569    }
570    pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
571        self.color = btn_color;
572        self
573    }
574    pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
575        self.fields = fields;
576        self
577    }
578    pub fn pass(&mut self, pass: bool) -> &mut Self {
579        self.pass = pass;
580        self
581    }
582    pub fn url(&mut self, url: &str) -> &mut Self {
583        self.url = url.to_string();
584        self
585    }
586    pub fn title(&mut self, title: &str) -> &mut Self {
587        self.title = title.to_string();
588        self
589    }
590    pub fn desc(&mut self, desc: &str) -> &mut Self {
591        self.desc = desc.to_string();
592        self
593    }
594    pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
595        self.tags = tags;
596        self
597    }
598    pub fn public(&mut self, public: bool) -> &mut Self {
599        self.public = public;
600        self
601    }
602    pub fn auth(&mut self, auth: bool) -> &mut Self {
603        self.auth = auth;
604        self
605    }
606    pub fn icon(&mut self, icon: &str) -> &mut Self {
607        self.icon = icon.to_string();
608        self
609    }
610    pub fn json(&mut self) -> JsonValue {
611        let color = match self.version {
612            0 => self.color.clone().str(),
613            _ => self.color.clone().str_v_1()
614        };
615        object! {
616            addon:self.addon.to_string() ,
617            api:self.api.clone(),
618            title:self.title.clone(),
619            desc:self.desc.clone(),
620            auth:self.auth,
621            public:self.public,
622            btn_type:self.btn_type.clone().str(),
623            color:color,
624            icon:self.icon.clone(),
625            cnd:self.cnd.clone(),
626            url:self.url.clone(),
627            path:self.path.clone(),
628            fields:self.fields.clone(),
629            tags:self.tags,
630            pass:self.pass,
631        }
632    }
633}
634
635/// 接口类型
636#[derive(Debug, Clone)]
637pub enum InterfaceType {
638    API,
639    BTN,
640    MENU,
641    OPENAPI,
642}
643
644impl InterfaceType {
645    pub fn str(&self) -> &'static str {
646        match self {
647            InterfaceType::API => "api",
648            InterfaceType::BTN => "btn",
649            InterfaceType::MENU => "menu",
650            InterfaceType::OPENAPI => "openapi",
651        }
652    }
653    pub fn types() -> Vec<&'static str> {
654        vec!["api", "btn", "menu", "openapi"]
655    }
656}
657
658/// 按钮类型
659#[derive(Debug, Clone)]
660pub enum BtnType {
661    /// 表单
662    Form,
663    /// 表单下载
664    FormDownload,
665    /// 表单自定义
666    FormCustom,
667    FormData,
668    /// 外部跳转
669    Url,
670    /// api请求
671    Api,
672    /// 下载
673    Download,
674    /// 内部跳转
675    Path,
676    /// 弹窗-定制页面
677    DialogCustom,
678    /// 表单->API->弹出自定义窗口
679    FormApiDialogCustom,
680    /// 预览
681    Preview,
682}
683
684impl BtnType {
685    fn str(self) -> &'static str {
686        match self {
687            BtnType::Form => "form",
688            BtnType::FormDownload => "form_download",
689            BtnType::FormCustom => "form_custom",
690            BtnType::FormData => "form_data",
691            BtnType::Api => "api",
692            BtnType::Download => "download",
693            BtnType::Url => "url",
694            BtnType::Path => "path",
695            BtnType::DialogCustom => "dialog_custom",
696            BtnType::FormApiDialogCustom => "form_api_dialog_custom",
697            BtnType::Preview => "preview",
698        }
699    }
700}
701/// 按钮颜色
702#[derive(Debug, Clone)]
703pub enum BtnColor {
704    Primary,
705    Red,
706    Yellow,
707    Green,
708}
709
710impl BtnColor {
711    fn str(self) -> &'static str {
712        match self {
713            BtnColor::Primary => "primary",
714            BtnColor::Red => "negative",
715            BtnColor::Yellow => "warning",
716            BtnColor::Green => "positive",
717        }
718    }
719    fn str_v_1(self) -> &'static str {
720        match self {
721            BtnColor::Primary => "normal",
722            BtnColor::Red => "danger",
723            BtnColor::Yellow => "warning",
724            BtnColor::Green => "success",
725        }
726    }
727}
728
729
730pub struct Dashboard {
731    /// 名称
732    title: String,
733    /// 数据
734    data: JsonValue,
735    /// 显示样式
736    model: DashboardModel,
737    /// 渲染样式
738    class: String,
739    /// 图标
740    icon: String,
741    /// 描述
742    desc: String,
743    ///数据请求接口
744    api: String,
745    ///用户选项,同时也是api接收的参数
746    options: JsonValue,
747}
748impl Dashboard {
749    pub fn new(title: &str) -> Dashboard {
750        Dashboard {
751            title: title.to_string(),
752            data: JsonValue::Null,
753            model: DashboardModel::Number,
754            class: "col-4".to_string(),
755            icon: "".to_string(),
756            desc: "".to_string(),
757            api: "".to_string(),
758            options: JsonValue::Null,
759        }
760    }
761    pub fn options(&mut self, options: JsonValue) -> &mut Self {
762        self.options = options;
763        self
764    }
765    pub fn api(&mut self, api: &str) -> &mut Self {
766        self.api = api.to_string();
767        self
768    }
769    pub fn data(&mut self, data: JsonValue) -> &mut Self {
770        self.data = data;
771        self
772    }
773    pub fn class(&mut self, name: &str) -> &mut Self {
774        self.class = name.to_string();
775        self
776    }
777    pub fn icon(&mut self, name: &str) -> &mut Self {
778        self.icon = name.to_string();
779        self
780    }
781    pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
782        self.model = dashboard_model;
783        self
784    }
785    pub fn desc(&mut self, desc: &str) -> &mut Self {
786        self.desc = desc.to_string();
787        self
788    }
789    pub fn json(&self) -> JsonValue {
790        object! {
791            title: self.title.clone(),
792            data: self.data.clone(),
793            class: self.class.clone(),
794            icon: self.icon.clone(),
795            model: self.model.str(),
796            desc: self.desc.clone(),
797            api: self.api.clone(),
798            options:self.options.clone(),
799        }
800    }
801}
802
803pub enum DashboardModel {
804    /// 数字
805    Number,
806    /// 柱状图
807    EchartsBar,
808    /// 堆叠柱状图
809    EchartsStackedBar,
810    /// 动态排序的柱状图
811    EchartsBarRace,
812    /// 饼图
813    EchartsPie,
814    /// 中空饼图
815    EchartsDoughnut,
816    /// 堆叠折线图
817    EchartsStackedLine,
818    /// 面积填充的堆叠折线图
819    EchartsStackedLineArea,
820    /// 地图
821    EchartsGeoGraph,
822}
823
824impl DashboardModel {
825    pub fn str(&self) -> &'static str {
826        match self {
827            Self::Number => "number",
828            Self::EchartsBar => "echarts-bar",
829            Self::EchartsStackedBar => "echarts-stacked_bar",
830            Self::EchartsBarRace => "echarts-bar_race",
831            Self::EchartsPie => "echarts-pie",
832            Self::EchartsDoughnut => "echarts-doughnut",
833            Self::EchartsStackedLine => "echarts-stacked_line",
834            Self::EchartsStackedLineArea => "echarts-stacked_line_area",
835            Self::EchartsGeoGraph => "echarts-geo_graph",
836        }
837    }
838}