Ztree使用教程

这两天项目需要写一个树形帮助,学习了我们项目组的老师的Ztree的树的写法,实现了这个帮助,下面来总结一下Ztree的用法。

(也是参考的一篇csdn上的博客了)

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。被广泛应用在系统的权限管理中,本文讲解zTree的一般应用

zTree 官网 http://www.treejs.cn/v3/main.php#_zTreeInfo

1、zTree 官网下载 ztree

 

下载好后放到项目相关目录下

2、编写相关代码

引入相关js 、 css 文件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
        <link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
        <script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
    </head>
    <body>
         
    </body>
</html>

上述代码中的 css 还可以引入如下两种、它们分别具有不同的样式

1
<link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />

 或

1
<link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />

 快速实现一个简单的树,请看如下代码,相关配置说明已写在代码中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html>
   <head>
     <meta charset="utf-8" />
     <title></title>
     <script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
     <link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
     <!--
     其他两种css风格样式
     <link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
     <link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
      -->
      <script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
    </head>
    <body>
        <div>
           <ul id="treeDemo" class="ztree"></ul>
        </div>
        <script>
           var settingss = {
                            data: {
                              simpleData: {
                                enable: true//true 、 false 分别表示 使用 、 不使用 简单数据模式
                                idKey: "id"//节点数据中保存唯一标识的属性名称
                                pIdKey: "parentId",    //节点数据中保存其父节点唯一标识的属性名称 
                                rootPId: -1  //用于修正根节点父节点数据,即 pIdKey 指定的属性值
                                          },
                              key: {
                                name: "menuName"  //zTree 节点数据保存节点名称的属性名称  默认值:"name"
                                   }
                                  },
                            check:{
                                enable:true//true 、 false 分别表示 显示 、不显示 复选框或单选框
                                nocheckInherit:true  //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
                                  }
                            };
                     
            //数据
            var zNodes = [
               //注意,数据中的 menuName 必须与 settingss 中key 中定义的name一致,否则找不到
               {menuName:"父节点1", open:true, children:[
                   {menuName:"子节点1"}, {menuName:"子节点2"}]},
               {menuName:"父节点2", open:true, children:[
                   {menuName:"子节点3"}, {menuName:"子节点4"}]}
               ];
                     
            zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, zNodes); //初始化树
            zTreeObj.expandAll(true);    //true 节点全部展开、false节点收缩
       </script>
   </body>
</html>

  运行效果如下图

3、使用ajax获取数据

实际项目开发中,数据往往是从后台服务器获取的,而不是在前端写死的。如何实现ajax获取数据,请看如下代码

数据库表结构及数据如下

后台接口代码如下

mapper层

1
2
3
4
5
6
7
8
9
10
import java.util.List;
import org.apache.ibatis.annotations.Select;
import com.che.pri.bean.MenuTest;
  
public interface MenuTestMapper {
     
    @Select("select id as id, parent_id as parentId, menu_name as menuName from menu_test")
    List<MenuTest> getMenuTestList();
  
}

controller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.che.pri.mapper.MenuTestMapper;
@Controller
public class MenuTestController {
     
    @Autowired
    private MenuTestMapper menuTestMapper;
  
    @ResponseBody
    @RequestMapping("/getMenuTestList")
    public Object getMenuTestList() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("menulists", menuTestMapper.getMenuTestList());
        return map;
    
}

html代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <title></title>
      <script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
      <link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
      <!--
      其他两种css风格样式
      <link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
      <link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
      -->
      <script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
  </head>
      <body>
        <div>
            <ul id="treeDemo" class="ztree"></ul>
        </div>
        <script>
            var settingss = {
                data: {
                    simpleData: {
                        enable: true//true 、 false 分别表示 使用 、 不使用 简单数据模式
                        idKey: "id",   //节点数据中保存唯一标识的属性名称
                        pIdKey: "parentId",    //节点数据中保存其父节点唯一标识的属性名称
                        rootPId: -1  //用于修正根节点父节点数据,即 pIdKey 指定的属性值
                                },
                    key: {
                        name: "menuName"  //zTree 节点数据保存节点名称的属性名称  默认值:"name"
                         }
                       },
                check:{
                       enable:true//true 、 false 分别表示 显示 、不显示 复选框或单选框
                       nocheckInherit:true   //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
                      }
                            };
                             
            $(document).ready(function(){
               $.ajax({
                    type:"get",
                    url:"http://localhost:8089/getMenuTestList",
                    async:true,
                    success:function(res){
                         
                     zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, res.menulists); //初始化树
                     zTreeObj.expandAll(true);   //true 节点全部展开、false节点收缩
                                         }
                    });
            });                
       </script>
   </body>
</html>

 运行效果如下

4、设置默认选中节点

在开发中,有时我们需要默认选中一些节点。比如修改用户角色或权限时,就会有这样的需求,如何对ztree的节点进行默认选中,请看如下代码

1
2
var node = zTreeObj.getNodeByParam("id", 7);
zTreeObj.checkNode(node, true, false);

通过每一条节点数据的 id 进行设置

具体看如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <title></title>
      <script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
      <link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
      <!--
      其他两种css风格样式
      <link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
      <link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
      -->
      <script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
  </head>
      <body>
        <div>
            <ul id="treeDemo" class="ztree"></ul>
        </div>
        <script>
            var settingss = {
                data: {
                    simpleData: {
                        enable: true//true 、 false 分别表示 使用 、 不使用 简单数据模式
                        idKey: "id",   //节点数据中保存唯一标识的属性名称
                        pIdKey: "parentId",    //节点数据中保存其父节点唯一标识的属性名称
                        rootPId: -1  //用于修正根节点父节点数据,即 pIdKey 指定的属性值
                                },
                    key: {
                        name: "menuName"  //zTree 节点数据保存节点名称的属性名称  默认值:"name"
                         }
                       },
                check:{
                       enable:true//true 、 false 分别表示 显示 、不显示 复选框或单选框
                       nocheckInherit:true   //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
                      }
                            };
                             
            $(document).ready(function(){
               $.ajax({
                    type:"get",
                    url:"http://localhost:8089/getMenuTestList",
                    async:true,
                    success:function(res){
                         
                     zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, res.menulists); //初始化树
                     zTreeObj.expandAll(true);   //true 节点全部展开、false节点收缩
  
                     //设置选中节点
                     var node = zTreeObj.getNodeByParam("id", 7);
                     zTreeObj.checkNode(node, true, false);
                          
                     var node = zTreeObj.getNodeByParam("id", 1);
                     zTreeObj.checkNode(node, true, false);
                          
                     var node = zTreeObj.getNodeByParam("id", 4);
                     zTreeObj.checkNode(node, true, false);
                                         }
                    });
            });                
       </script>
   </body>
</html>

  运行效果

 

 

 其他内容可参考官网API

在这里声明一下版权

————————————————
版权声明:本文为CSDN博主「悟世君子」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wsjzzcbq/article/details/83029532

 

以上都是学习人家写的内容了,我介绍一下我在项目中对Ztree的一些理解。

首先,我需要写一个js让我跳到我想选择的树的页面里面去,并且从树的页面里面获取到我所需要的返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 选择员工
function selectDeviceType() {
    var msg = "选择人员";
    $.dialog({
        type: 'iframe',
        url: context + "/jsp/genersoft/public/health/HealthRyDepartment.jsp",
        title: msg,
        width: 580,
        height: 400,
        onclose: function () {
            var nodes = this.returnValue;
            $("#healthUserId").val(nodes[0].ORGAN_ID);
            $("#username").val(nodes[0].ORGAN_NAME);
            $("#healthOrgId").val(nodes[0].GRANDPA_ID);
            $("#departmentname").val(nodes[0].GRANDPA_NAME);
            $("#username").change();
        }
    });
 }

  接下来,就是我们选择帮助的页面,在这个页面里,需要初始化一下Ztree,构造一下Ztree的数据属性,写个ajax,给他一个后台的url,让他查数据,返回到前台来,再构造这个树。

事先需要引一些js

1
2
3
4
5
6
7
8
<script type="text/javascript" src="<l:asset path='jquery.js'/>"></script>
<script type="text/javascript" src="<l:asset path='bootstrap.js'/>"></script>
<script type="text/javascript" src="<l:asset path='form.js'/>"></script>
<script type="text/javascript" src="<l:asset path='ui.js'/>"></script>
<script type="text/javascript" src="<l:asset path='loushang-framework.js'/>"></script>
<script type="text/javascript" src="<l:asset path='i18n.js'/>"></script>
<script type="text/javascript" src="<l:asset path='ztree.js'/>"></script>
    

 然后,初始化Ztree,构造这个树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    <SCRIPT LANGUAGE="JavaScript">
        var context = "<l:assetcontext/>";
        var dialog = parent.dialog.get(window);
        var zTreeObj;
        var setting = {
 
            check: {
                enable: true,
                chkStyle: "radio",
                radioType: "all",
                chkboxType: {"Y": "s", "N": "s"}
            }
        };
 
        function filter(treeId, parentNode, childNodes) {
            if (!childNodes) return null;
            for (var i = 0, l = childNodes.length; i < l; i++) {
                childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
            }
            return childNodes;
        }
 
        // zTree 的数据属性,深入使用请参考 API 文档(zTreeNode 节点数据详解)
        var zNodes = [
            {
                name: "test1",
                open: true,
                children: [
                    {
                        name:"test1_1",
                        open:true,
                        children: [
                            {name: "test1_1_1"},
                            {name: "test1_1_2"}
                        ]
                    },
                    {
                        name:"test1_2",
                        open:true,
                        children: [
                            {name: "test1_2_1"},
                            {name: "test1_2_2"}
                        ]
                    },
                     
                ]
            },
            {
                name: "test2",
                open: true,
                children: [
                    {
                        name:"test2_1",
                        open:true,
                        children: [
                            {name: "test2_1_1"},
                            {name: "test2_1_2"}
                        ]
                    },
                    {
                        name:"test2_2",
                        open:true,
                        children: [
                            {name: "test2_2_1"},
                            {name: "test2_2_2"}
                        ]
                    },
                     
                ]
            },
        ];
 
        $(document).ready(function () {
            $.ajax({
                type: "POST",
                url: context + "/service/health/treeData2",
                data: {},
                dataType: "json",
                aysn: false,
                success: function (respMsg) {
                    zNodes = respMsg;
                    zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes);
                    var node = zTreeObj.getNodeByParam("name", '${param.name}', null);
                    if (node){//判断有查询到节点
                        //方法一:
                        // $("#"+node.tId+"_a").click();//点击查询到的节点
                        //方法二:
                        zTreeObj.selectNode(node,true);//选
                        // node.checked = true;
                        // zTreeObj.updateNode(node);
                }}
            });
            // var zTreeMenu = $.fn.zTree.getZTreeObj("treeDemo");//根据treeID(zTree的DOM容器的id)获取
            //zTree对象的方法,必须初始化zTree才可以使用此方法
            // var treeObj = $.fn.zTree.getZTreeObj("tree");
            // var node = zTreeObj.getNodeByParam("id", 1, null);
            // var node=zTreeObj.getNodeByParam('name',,null);
 
            // 确定按钮
            $("#confirm").click(function () {
                confirm();
            });
 
            // 取消按钮
            $("#clear").click(function () {
                clear();
            });
        });
 
        // 确定按钮
        function confirm() {
            var msg = L.getLocaleMessage("bsp.organ.053", "请选择单个节点!");
            var selectedNodes = zTreeObj.getCheckedNodes();
            if (selectedNodes.length != 1) {
                $.sticky(msg, {
                    autoclose: 1000,
                    position: "center",
                    style: "warning"
                });
                return false;
            }
            if(selectedNodes["0"].STRU_LEVEL!="4"){
                 $.sticky("请选择职工", {
                     autoclose: 1000,
                     position: "center",
                     style: "warning"
                 });
                 return false;
            }
 
            dialog.close(selectedNodes);
            dialog.remove();
        }
 
        // 取消
        function clear() {
            var dialog = parent.dialog.get(window);
            dialog.close("clear");
            dialog.remove();
            return false;
        }
    </SCRIPT>
</HEAD>
<BODY>
<div>
    <ul id="treeDemo" class="ztree"></ul>
    <div class="foot">
        <div class="btnGroup">
            <button id="confirm" type="button" class="btn ue-btn"><spring:message code="bsp.organ.046"
                                                                                          text="确定"/></button>
            <button id="clear" type="button" class="btn ue-btn"><spring:message code="bsp.organ.048"
                                                                                text="清除"/></button>
        </div>
    </div>
</div>
</BODY>
</HTML>

跳后台url,并对数据做一下拼接。

Contrller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
@RequestMapping(value = "/health")
public class HealthController {
    @Autowired
    private IHealthService healthService;
    /**
     * 列表跳转页面
     *
     * @return 列表页面
     */
    @RequestMapping
    public String queryHealth() {
        return "genersoft/public/health/healthQuery";
    }
     
    @RequestMapping({"/treeData2"})
    @ResponseBody
    public List treeData2(HttpServletRequest req) {
        return healthService.getTypeTreeData2("");
    }
 
}

Service层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
@Service("healthService")
public class HealthServiceImpl implements IHealthService{
 
    @Autowired
    private HealthMapper healthMapper;
    @Override
    @Override
    public List getTypeTreeData2(String struId) {
        // TODO Auto-generated method stub
        List<Map<String,Object>> list = healthMapper.getTreeData2();
        List<Map> resList = new ArrayList<>();
        //单位list
        List<Map<String,Object>> UnitList=new ArrayList<Map<String,Object>>();
        //部门list
        List<Map<String,Object>> DepartmentList=new ArrayList<Map<String,Object>>();
        //岗位list
        List<Map<String,Object>> PostList=new ArrayList<Map<String,Object>>();
        //人员list
        List<Map<String,Object>> PersonList=new ArrayList<Map<String,Object>>();
        for(Map<String,Object> unit:list) {
            if(Integer.parseInt(String.valueOf(unit.get("STRU_LEVEL")))==1) {
                UnitList.add(unit);
            }
        }
        for(Map<String,Object> department:list) {
            if(Integer.parseInt(String.valueOf(department.get("STRU_LEVEL")))==2) {
                DepartmentList.add(department);
            }
        }
        for(Map<String,Object> post:list) {
            if(Integer.parseInt(String.valueOf(post.get("STRU_LEVEL")))==3) {
                PostList.add(post);
            }
        }
        for(Map<String,Object> person:list) {
            if(Integer.parseInt(String.valueOf(person.get("STRU_LEVEL")))==4) {
                PersonList.add(person);
            }
        }
        List<Map<String, Object>> temp1List=new  ArrayList<Map<String, Object>>();
        List<Map<String, Object>> temp3List=new  ArrayList<Map<String, Object>>();
        List<Map<String, Object>> temp5List=new  ArrayList<Map<String, Object>>();
        for(Map<String,Object> temp6:DepartmentList) {
        for(Map<String, Object> temp1:PostList) {
            List<Map<String,Object>> greatgrandsonList=new ArrayList<Map<String,Object>>();
            greatgrandsonList.clear();
            for(Map<String,Object> temp2:PersonList) {
                if(temp2.get("PARENT_ID").equals(temp1.get("ORGAN_ID"))) {
                    temp2.put("name",temp2.get("ORGAN_NAME"));
                    temp2.put("PARENT_NAME", temp1.get("ORGAN_NAME"));
                    if(temp1.get("PARENT_ID").equals(temp6.get("ORGAN_ID"))) {
                    temp2.put("GRANDPA_ID", temp6.get("ORGAN_ID"));
                    temp2.put("GRANDPA_NAME", temp6.get("ORGAN_NAME"));
                    }
                    greatgrandsonList.add(temp2);
                }
            }
            temp1.put("children", greatgrandsonList);
            temp1List.add(temp1);
        }
    }
        System.out.println(temp1List);
        System.out.println(1);
        for(Map<String,Object> temp3:DepartmentList) {
            List<Map<String,Object>> grandsonList=new ArrayList<Map<String,Object>>();
            grandsonList.clear();
            for(Map<String,Object> temp4:PostList) {
                if(temp4.get("PARENT_ID").equals(temp3.get("ORGAN_ID"))) {
                    temp4.put("name",temp4.get("ORGAN_NAME"));
                    temp4.put("PARENT_NAME", temp3.get("ORGAN_NAME"));
                    grandsonList.add(temp4);
                }
            }
            temp3.put("children", grandsonList);
            //System.out.println(temp3);
            temp3List.add(temp3);
        }
        System.out.println(temp3List);
        System.out.println(1);
        for(Map<String,Object> temp5:UnitList) {
            List<Map<String,Object>> sonList=new ArrayList<Map<String,Object>>();
            temp5.put("name",temp5.get("ORGAN_NAME"));
            sonList.clear();
            for(Map<String,Object> temp6:DepartmentList) {
                if(temp6.get("PARENT_ID").equals(temp5.get("ORGAN_ID"))) {
                    temp6.put("name",temp6.get("ORGAN_NAME"));
                    temp6.put("PARENT_NAME", temp5.get("ORGAN_NAME"));
                    sonList.add(temp6);
                }
            }
            temp5.put("children", sonList);
            //System.out.println(temp5);
            temp5List.add(temp5);
        }
        System.out.println(temp5List);
        resList.addAll(temp5List);
        return resList;
    }
}

这个地方有几个点需要注意一下:

1.让他返回成一个父亲节点带着一个子节点的数据格式,要对数据进行一个拼接,返回数据的格式是如下的形式

1
2
3
4
5
6
7
8
[{STRU_ID=1, ORGAN_ID=1,
children=[{STRU_ID=2, ORGAN_ID=2,
children=[{STRU_ID=3, ORGAN_ID=3,
children=[{STRU_ID=4, GRANDPA_ID=2, ORGAN_ID=4, PARENT_NAME=岗位, name=a, STRU_LEVEL=4, ORGAN_NAME=a,
PARENT_ID=3, GRANDPA_NAME=2}]
}]
}]
}]

 他的下一层规定写为children,这个是Ztree的数据属性,最好写死写成children。

2.在后台拼接的时候,需要给每个节点的name属性附上值

1
temp5.put("name",temp5.get("ORGAN_NAME"));

  如果不给name赋值,则在前台显示的时候会出现undefined的情况。

3.然后是获取选择节点的属性值的方法,如下:

1
var selectedNodes = zTreeObj.getCheckedNodes();

  其他的就没什么了,that's all,暂时写到这,想起来再补充。

posted @   leagueandlegends  阅读(39650)  评论(5编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示