Skip to main content

br_addon/
action.rs

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