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