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