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()
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().clone();
147        if self.params_check() {
148            self.check(&mut request.query.clone(), self.query().clone())?;
149            self.check(&mut request.body, params)?;
150        }
151        let res = self.index(request.clone());
152        match res.success {
153            true => Ok(res),
154            false => Err(res),
155        }
156    }
157    /// 入参验证
158    fn check(&mut self, request: &mut JsonValue, params: JsonValue) -> Result<(), ApiResponse> {
159        let req = request.clone();
160        for (name, _) in req.entries() {
161            if !params.has_key(name) {
162                request.remove(name);
163            }
164        }
165        for (name, field) in params.entries() {
166            let require = field["require"].as_bool().unwrap_or(false);
167            let title = field["title"].as_str().unwrap_or("");
168            if request.has_key(name) {
169                // 判断输入类型
170                match field["mode"].as_str().unwrap() {
171                    "key" => {
172                        if !request[name].is_string() {
173                            return Err(ApiResponse::fail(
174                                900_001,
175                                format!(
176                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
177                                    name, field["mode"]
178                                )
179                                .as_str(),
180                            ));
181                        }
182                        if require && request[name].is_empty() {
183                            return Err(ApiResponse::fail(
184                                900014,
185                                format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
186                            ));
187                        }
188                    }
189                    "text" | "table" | "tree" => {
190                        if !request[name].is_string() {
191                            return Err(ApiResponse::fail(
192                                900002,
193                                format!(
194                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
195                                    name, field["mode"]
196                                )
197                                .as_str(),
198                            ));
199                        }
200                        if require && request[name].is_empty() {
201                            return Err(ApiResponse::fail(
202                                900002,
203                                format!("{title} 必填").as_str(),
204                            ));
205                        }
206                    }
207                    "file" => {
208                        if !request[name].is_array() && !request[name].is_string() {
209                            return Err(ApiResponse::fail(
210                                900003,
211                                format!("参数 [{}] 数据类型应为[{}]", name, field["mode"]).as_str(),
212                            ));
213                        }
214                        if require && request[name].is_empty() {
215                            return Err(ApiResponse::fail(
216                                900002,
217                                format!("{title} 必填").as_str(),
218                            ));
219                        }
220                    }
221                    "int" => {
222                        if require && request[name].to_string().is_empty() {
223                            return Err(ApiResponse::fail(
224                                900_002,
225                                format!("{title} 必填").as_str(),
226                            ));
227                        }
228                        if !request[name].to_string().is_empty() {
229                            match request[name].to_string().parse::<i64>() {
230                                Ok(_) => {}
231                                Err(_) => {
232                                    return Err(ApiResponse::fail(
233                                        900013,
234                                        format!(
235                                            "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
236                                            name, field["mode"]
237                                        )
238                                        .as_str(),
239                                    ));
240                                }
241                            }
242                        }
243                    }
244                    "timestamp" | "yearmonth" => {
245                        if require && request[name].to_string().is_empty() {
246                            return Err(ApiResponse::fail(
247                                900002,
248                                format!("{title} 必填").as_str(),
249                            ));
250                        }
251                        if !request[name].to_string().is_empty() {
252                            if request[name].is_array() && request[name].len() == 2 {
253                                // 如果是数组,遍历每个元素
254                                for item in request[name].members() {
255                                    match item.to_string().parse::<f64>() {
256                                        Ok(_) => {}
257                                        Err(_) => {
258                                            return Err(ApiResponse::fail(
259                                                900_013,
260                                                format!(
261                                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
262                                                    name, field["mode"]
263                                                ).as_str(),
264                                            ));
265                                        }
266                                    }
267                                }
268                            } else {
269                                match request[name].to_string().parse::<f64>() {
270                                    Ok(_) => {}
271                                    Err(_) => {
272                                        return Err(ApiResponse::fail(
273                                            900013,
274                                            format!(
275                                                "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
276                                                name, field["mode"]
277                                            )
278                                            .as_str(),
279                                        ));
280                                    }
281                                }
282                            }
283                        }
284                    }
285                    "float" => {
286                        if require && request[name].to_string().is_empty() {
287                            return Err(ApiResponse::fail(
288                                900002,
289                                format!("{title} 必填").as_str(),
290                            ));
291                        }
292                        if !request[name].to_string().is_empty() {
293                            match request[name].to_string().parse::<f64>() {
294                                Ok(_) => {}
295                                Err(_) => {
296                                    return Err(ApiResponse::fail(
297                                        900023,
298                                        format!(
299                                            "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
300                                            name, field["mode"]
301                                        )
302                                        .as_str(),
303                                    ));
304                                }
305                            }
306                        }
307                    }
308                    "string" | "url" | "time" | "code" | "pass" | "email" | "location"
309                    | "color" | "date" | "barcode" | "datetime" | "editor" | "tel" => {
310                        if !request[name].is_string() {
311                            return Err(ApiResponse::fail(
312                                -1,
313                                format!(
314                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
315                                    name, field["mode"]
316                                )
317                                .as_str(),
318                            ));
319                        }
320                        if require && request[name].is_empty() {
321                            return Err(ApiResponse::fail(
322                                900004,
323                                format!("{title} 必填").as_str(),
324                            ));
325                        }
326                    }
327                    "dict" => {
328                        if require && request[name].is_empty() {
329                            return Err(ApiResponse::fail(
330                                900005,
331                                format!("{title} 必填").as_str(),
332                            ));
333                        }
334                    }
335                    "switch" => match request[name].to_string().parse::<bool>() {
336                        Ok(e) => {
337                            request[name] = e.into();
338                        }
339                        Err(_) => {
340                            return Err(ApiResponse::fail(
341                                -1,
342                                format!(
343                                    "请求参数数据类型错误: 参数 [{name}] 数据类型应为[{}]",
344                                    field["mode"]
345                                )
346                                .as_str(),
347                            ));
348                        }
349                    },
350                    "select" => {
351                        if !request[name].is_array() && !request[name].is_string() {
352                            return Err(ApiResponse::fail(
353                                -1,
354                                format!(
355                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
356                                    name, field["mode"]
357                                )
358                                .as_str(),
359                            ));
360                        }
361                        let value = if request[name].is_array() {
362                            request[name]
363                                .members()
364                                .map(|m| m.to_string())
365                                .collect::<Vec<String>>()
366                        } else {
367                            request[name]
368                                .to_string()
369                                .split(",")
370                                .map(|x| x.to_string())
371                                .collect::<Vec<String>>()
372                        };
373                        let option = field["option"]
374                            .members()
375                            .map(|m| m.as_str().unwrap_or(""))
376                            .collect::<Vec<&str>>();
377
378                        let require = field["require"].as_bool().unwrap();
379                        for item in value.clone() {
380                            if !option.contains(&&*item.clone()) && (item.is_empty() && require) {
381                                let option = field["option"]
382                                    .members()
383                                    .map(|m| m.as_str().unwrap_or(""))
384                                    .collect::<Vec<&str>>()
385                                    .join(",");
386                                return Err(ApiResponse::fail(-1, format!("请求参数选项错误: 参数 [{item}] 数据类型应为[{option}]之内").as_str()));
387                            }
388                        }
389                        request[name] = value.into();
390                    }
391                    "radio" => {
392                        if !request[name].is_string() {
393                            return Err(ApiResponse::fail(
394                                -1,
395                                format!(
396                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}] 实际为[{}]",
397                                    name, field["mode"], request[name]
398                                )
399                                .as_str(),
400                            ));
401                        }
402                        let option = field["option"]
403                            .members()
404                            .map(|m| m.as_str().unwrap_or(""))
405                            .collect::<Vec<&str>>()
406                            .join(",");
407                        if request[name].is_string()
408                            && !field["option"].contains(request[name].as_str().unwrap_or(""))
409                        {
410                            return Err(ApiResponse::fail(
411                                -1,
412                                format!(
413                                    "请求参数选项错误: 参数 [{}] 数据 [{}] 应为 [{}] 之一",
414                                    name, request[name], option
415                                )
416                                .as_str(),
417                            ));
418                        }
419                    }
420                    "array" | "polygon" => {
421                        if !request[name].is_array() {
422                            return Err(ApiResponse::fail(
423                                900_009,
424                                format!(
425                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
426                                    name, field["mode"]
427                                )
428                                .as_str(),
429                            ));
430                        }
431                        if require && request[name].is_empty() {
432                            return Err(ApiResponse::fail(
433                                900010,
434                                format!("请求参数数据类型错误: 参数 [{name}] 不能为空").as_str(),
435                            ));
436                        }
437                    }
438                    "object" => {
439                        if !request[name].is_object() {
440                            return Err(ApiResponse::fail(
441                                900009,
442                                format!(
443                                    "请求参数数据类型错误: 参数 [{}] 数据类型应为[{}]",
444                                    name, field["mode"]
445                                )
446                                .as_str(),
447                            ));
448                        }
449                        if require && request[name].is_empty() {
450                            return Err(ApiResponse::fail(
451                                900006,
452                                format!("{title} 必填").as_str(),
453                            ));
454                        }
455                    }
456                    _ => {
457                        println!("检查未知类型: {}", field["mode"])
458                    }
459                }
460            } else {
461                if require {
462                    return Err(ApiResponse::fail(900007, format!("{title} 必填").as_str()));
463                }
464                request[name] = field["def"].clone();
465            }
466        }
467        Ok(())
468    }
469    /// 内部入口
470    fn index(&mut self, request: Request) -> ApiResponse;
471    #[cfg(any(
472        feature = "sqlite",
473        feature = "mssql",
474        feature = "mysql",
475        feature = "pgsql"
476    ))]
477    fn table_select(
478        &mut self,
479        request: JsonValue,
480        table_name: &str,
481        fields: Vec<&str>,
482    ) -> JsonValue {
483        self.table()
484            .main_select_fields(table_name, fields)
485            .params(request.clone())
486            .get_table_select()
487    }
488
489    /// 列表表格渲染
490    /// * table_name 表名
491    /// * fields 全部模型字段集合
492    /// * hidd_field 需要隐藏的字段集合
493    /// * show_field 需要显示的字段集合
494    /// * search_fields 搜索字段集合
495    /// * filter_fields 高级搜索字段集合
496    #[allow(clippy::too_many_arguments)]
497    #[cfg(any(
498        feature = "sqlite",
499        feature = "mssql",
500        feature = "mysql",
501        feature = "pgsql"
502    ))]
503    fn table_list(
504        &mut self,
505        request: JsonValue,
506        table_name: &str,
507        fields: JsonValue,
508        hidd_field: Vec<&str>,
509        show_field: Vec<&str>,
510        search_fields: Vec<&str>,
511        filter_fields: Vec<&str>,
512    ) -> JsonValue {
513        self.table()
514            .main_table_fields(table_name, fields, hidd_field, show_field)
515            .search_fields(search_fields)
516            .filter_fields(filter_fields)
517            .params(request)
518            .get_table()
519    }
520    #[allow(clippy::too_many_arguments)]
521    #[cfg(any(
522        feature = "sqlite",
523        feature = "mssql",
524        feature = "mysql",
525        feature = "pgsql"
526    ))]
527    fn table(&mut self) -> Tables {
528        Tables::new(self.tools().db.clone())
529    }
530
531    /// 使用工具
532    fn tools(&mut self) -> Tools {
533        let tools = PLUGIN_TOOLS.lock().unwrap();
534        let tools = tools.get("tools").unwrap().clone();
535        tools
536    }
537    /// 使用配置
538    fn config(&mut self, name: &str) -> JsonValue {
539        if CONFIG.lock().unwrap().get(name).is_none() {
540            object! {}
541        } else {
542            CONFIG.lock().unwrap().get(name).unwrap().clone()
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().clone());
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().clone().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    pub fn new(api: &str) -> Self {
600        Self {
601            api: api.to_string(),
602            title: "".to_string(),
603            desc: "".to_string(),
604            btn_type: BtnType::Api,
605            color: BtnColor::Primary,
606            icon: "".to_string(),
607            auth: false,
608            public: false,
609            cnd: vec![],
610            url: "".to_string(),
611            path: "".to_string(),
612            fields: object! {},
613            tags: &[],
614            pass: false,
615            addon: "".to_string(),
616            version: 0,
617        }
618    }
619
620    pub fn addon(&mut self) -> &mut Self {
621        self.addon = self.api.split('.').nth(0).unwrap().to_string();
622        self
623    }
624    pub fn path(&mut self, path: &str) -> &mut Self {
625        self.path = path.to_string();
626        self
627    }
628    pub fn cnd(&mut self, cnd: Vec<JsonValue>) -> &mut Self {
629        self.cnd = cnd;
630        self
631    }
632    pub fn version(&mut self, version: usize) -> &mut Self {
633        self.version = version;
634        self
635    }
636    pub fn btn_type(&mut self, btn_type: BtnType) -> &mut Self {
637        self.btn_type = btn_type;
638        self
639    }
640    pub fn btn_color(&mut self, btn_color: BtnColor) -> &mut Self {
641        self.color = btn_color;
642        self
643    }
644    pub fn fields(&mut self, fields: JsonValue) -> &mut Self {
645        self.fields = fields;
646        self
647    }
648    pub fn pass(&mut self, pass: bool) -> &mut Self {
649        self.pass = pass;
650        self
651    }
652    pub fn url(&mut self, url: &str) -> &mut Self {
653        self.url = url.to_string();
654        self
655    }
656    pub fn title(&mut self, title: &str) -> &mut Self {
657        self.title = title.to_string();
658        self
659    }
660    pub fn desc(&mut self, desc: &str) -> &mut Self {
661        self.desc = desc.to_string();
662        self
663    }
664    pub fn tags(&mut self, tags: &'static [&'static str]) -> &mut Self {
665        self.tags = tags;
666        self
667    }
668    pub fn public(&mut self, public: bool) -> &mut Self {
669        self.public = public;
670        self
671    }
672    pub fn auth(&mut self, auth: bool) -> &mut Self {
673        self.auth = auth;
674        self
675    }
676    pub fn icon(&mut self, icon: &str) -> &mut Self {
677        self.icon = icon.to_string();
678        self
679    }
680    pub fn json(&mut self) -> JsonValue {
681        let color = match self.version {
682            0 => self.color.clone().str(),
683            _ => self.color.clone().str_v_1(),
684        };
685        object! {
686            addon:self.addon.to_string() ,
687            api:self.api.clone(),
688            title:self.title.clone(),
689            desc:self.desc.clone(),
690            auth:self.auth,
691            public:self.public,
692            btn_type:self.btn_type.clone().str(),
693            color:color,
694            icon:self.icon.clone(),
695            cnd:self.cnd.clone(),
696            url:self.url.clone(),
697            path:self.path.clone(),
698            fields:self.fields.clone(),
699            tags:self.tags,
700            pass:self.pass,
701        }
702    }
703}
704
705/// 接口类型
706#[derive(Debug, Clone)]
707pub enum InterfaceType {
708    API,
709    BTN,
710    MENU,
711    OPENAPI,
712}
713
714impl InterfaceType {
715    pub fn str(&self) -> &'static str {
716        match self {
717            InterfaceType::API => "api",
718            InterfaceType::BTN => "btn",
719            InterfaceType::MENU => "menu",
720            InterfaceType::OPENAPI => "openapi",
721        }
722    }
723    pub fn types() -> Vec<&'static str> {
724        vec!["api", "btn", "menu", "openapi"]
725    }
726}
727
728/// 按钮类型
729#[derive(Debug, Clone)]
730pub enum BtnType {
731    /// 表单
732    Form,
733    /// 表单下载
734    FormDownload,
735    /// 表单自定义
736    FormCustom,
737    FormData,
738    /// 外部跳转
739    Url,
740    /// api请求
741    Api,
742    /// 下载
743    Download,
744    /// 内部跳转
745    Path,
746    /// 弹窗-定制页面
747    DialogCustom,
748    /// 表单->API->弹出自定义窗口
749    FormApiDialogCustom,
750    /// 预览
751    Preview,
752}
753
754impl BtnType {
755    fn str(self) -> &'static str {
756        match self {
757            BtnType::Form => "form",
758            BtnType::FormDownload => "form_download",
759            BtnType::FormCustom => "form_custom",
760            BtnType::FormData => "form_data",
761            BtnType::Api => "api",
762            BtnType::Download => "download",
763            BtnType::Url => "url",
764            BtnType::Path => "path",
765            BtnType::DialogCustom => "dialog_custom",
766            BtnType::FormApiDialogCustom => "form_api_dialog_custom",
767            BtnType::Preview => "preview",
768        }
769    }
770}
771/// 按钮颜色
772#[derive(Debug, Clone)]
773pub enum BtnColor {
774    Primary,
775    Red,
776    Yellow,
777    Green,
778}
779
780impl BtnColor {
781    fn str(self) -> &'static str {
782        match self {
783            BtnColor::Primary => "primary",
784            BtnColor::Red => "negative",
785            BtnColor::Yellow => "warning",
786            BtnColor::Green => "positive",
787        }
788    }
789    fn str_v_1(self) -> &'static str {
790        match self {
791            BtnColor::Primary => "normal",
792            BtnColor::Red => "danger",
793            BtnColor::Yellow => "warning",
794            BtnColor::Green => "success",
795        }
796    }
797}
798
799pub struct Dashboard {
800    /// 名称
801    title: String,
802    /// 数据
803    data: JsonValue,
804    /// 显示样式
805    model: DashboardModel,
806    /// 渲染样式
807    class: String,
808    /// 图标
809    icon: String,
810    /// 描述
811    desc: String,
812    ///数据请求接口
813    api: String,
814    ///用户选项,同时也是api接收的参数
815    options: JsonValue,
816}
817impl Dashboard {
818    pub fn new(title: &str) -> Dashboard {
819        Dashboard {
820            title: title.to_string(),
821            data: JsonValue::Null,
822            model: DashboardModel::Number,
823            class: "col-4".to_string(),
824            icon: "".to_string(),
825            desc: "".to_string(),
826            api: "".to_string(),
827            options: JsonValue::Null,
828        }
829    }
830    pub fn options(&mut self, options: JsonValue) -> &mut Self {
831        self.options = options;
832        self
833    }
834    pub fn api(&mut self, api: &str) -> &mut Self {
835        self.api = api.to_string();
836        self
837    }
838    pub fn data(&mut self, data: JsonValue) -> &mut Self {
839        self.data = data;
840        self
841    }
842    pub fn class(&mut self, name: &str) -> &mut Self {
843        self.class = name.to_string();
844        self
845    }
846    pub fn icon(&mut self, name: &str) -> &mut Self {
847        self.icon = name.to_string();
848        self
849    }
850    pub fn model(&mut self, dashboard_model: DashboardModel) -> &mut Self {
851        self.model = dashboard_model;
852        self
853    }
854    pub fn desc(&mut self, desc: &str) -> &mut Self {
855        self.desc = desc.to_string();
856        self
857    }
858    pub fn json(&self) -> JsonValue {
859        object! {
860            title: self.title.clone(),
861            data: self.data.clone(),
862            class: self.class.clone(),
863            icon: self.icon.clone(),
864            model: self.model.str(),
865            desc: self.desc.clone(),
866            api: self.api.clone(),
867            options:self.options.clone(),
868        }
869    }
870}
871
872pub enum DashboardModel {
873    /// 数字
874    Number,
875    /// 柱状图
876    EchartsBar,
877    /// 堆叠柱状图
878    EchartsStackedBar,
879    /// 动态排序的柱状图
880    EchartsBarRace,
881    /// 饼图
882    EchartsPie,
883    /// 中空饼图
884    EchartsDoughnut,
885    /// 堆叠折线图
886    EchartsStackedLine,
887    /// 面积填充的堆叠折线图
888    EchartsStackedLineArea,
889    /// 地图
890    EchartsGeoGraph,
891}
892
893impl DashboardModel {
894    pub fn str(&self) -> &'static str {
895        match self {
896            Self::Number => "number",
897            Self::EchartsBar => "echarts-bar",
898            Self::EchartsStackedBar => "echarts-stacked_bar",
899            Self::EchartsBarRace => "echarts-bar_race",
900            Self::EchartsPie => "echarts-pie",
901            Self::EchartsDoughnut => "echarts-doughnut",
902            Self::EchartsStackedLine => "echarts-stacked_line",
903            Self::EchartsStackedLineArea => "echarts-stacked_line_area",
904            Self::EchartsGeoGraph => "echarts-geo_graph",
905        }
906    }
907}