流程设计器jQuery + svg/vml(Demo6 - 增加结点属性及切换)

到目前流程设计器流程结点的拖拽操作已基本完成,接下来就到结点的属性开发了。前面已经开发过流程模板的属性了,结点属性跟模板属性类似,从属性模板定义copy一份,然后按各结点类型进行调整就ok。

1、先来回顾下流程模板属性,这里对流程模板属性稍微进行了调整,效果图如下:

  1 //定义流程模板属性
  2 TemplateProperty = function () {
  3     if (typeof TemplateProperty.defaults == "undefined") {
  4         /*第一次定义对象时为TemplateProperty类定义静态属性*/
  5         TemplateProperty.defaults = {
  6             data: {
  7                 RecNo: 0,
  8                 OrgNo: 0,
  9                 TemplateCode: "",
 10                 TemplateName: "",
 11                 InstanceName: "",
 12                 DesignWidth: 1000,
 13                 DesignHeight: 800,
 14                 Version: 0,
 15                 VerStatus: "设计",
 16                 DesignerName: "",
 17                 DesignTime: "",
 18                 PublisherName: "",
 19                 PublishTime: "",
 20                 TemplateMemo: ""
 21             }
 22         };
 23         /*第一次定义对象时定义实例共有方法*/
 24         var p = TemplateProperty.prototype;
 25         p.createTable = function () {
 26             this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0'></table>");
 27             this.$tbody = $("<tbody></tbody>");
 28             this.$table.append(this.$tbody);
 29             this.$propertyDiv.append(this.$table);
 30             //行0 - 基本属性(分组)
 31             this.$tbody.append(GoFlow.formatString(
 32                "<tr style='display:table-row;background-color:rgb(234, 229, 229);height:0px;' group='TemplateBasic'>{0}</tr>",
 33                "<td class='Expanded' group='TemplateBasic'></td><td style='width: 100%;height:0px;' colspan='3'>基本属性</td>"));
 34             //行1 - 流程编码
 35             this.$tbody.append(GoFlow.formatString(
 36                 "<tr group='TemplateBasic' property='TemplateCode'><td/><td>流程编码</td>{0}</tr>",
 37                 "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 38             //行2 - 流程名称
 39             this.$tbody.append(GoFlow.formatString(
 40                 "<tr group='TemplateBasic' property='TemplateName'><td/><td>流程名称</td>{0}</tr>",
 41                 "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 42             //行3 - 实例名称
 43             this.$tbody.append(GoFlow.formatString(
 44                 "<tr group='TemplateBasic' property='InstanceName'><td/><td>实例名称</td>{0}{1}</tr>",
 45                 "<td><input id='InstanceName' style='width:98.9%;' type='text' maxlength='50'/></td>",
 46                 "<td style='min-width:35px;'><input class='BizData' type='button' value='...'/></td>"));
 47 
 48             //行4 - 版本信息(分组)
 49             this.$tbody.append(GoFlow.formatString(
 50                "<tr style='display:table-row;background-color:rgb(234, 229, 229);height:0px;' group='TemplateVersion'>{0}</tr>",
 51                "<td class='Expanded' group='TemplateVersion'></td><td style='width: 100%;height:0px;' colspan='3'>版本信息</td>"));
 52             //行5 - 流程版本
 53             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='Version'>{0}</tr>",
 54                 "<td/><td>流程版本</td><td colspan='2' readonly='true'><div></div></td>"));
 55             //行6 - 版本状态
 56             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='VerStatus'>{0}</tr>",
 57                 "<td/><td>版本状态</td><td colspan='2' readonly='true'><div></div></td>"));
 58             //行7 - 修改人
 59             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='DesignerName'>{0}</tr>",
 60                 "<td/><td>修改人</td><td colspan='2' readonly='true'><div></div></td>"));
 61             //行8 - 修改时间
 62             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='DesignTime'>{0}</tr>",
 63                 "<td/><td>修改时间</td><td colspan='2' readonly='true'><div></div></td>"));
 64             //行9 - 发布人
 65             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='PublisherName'>{0}</tr>",
 66                 "<td/><td>发布人</td><td colspan='2' readonly='true'><div></div></td>"));
 67             //行10 - 发布时间
 68             this.$tbody.append(GoFlow.formatString("<tr group='TemplateVersion' property='PublishTime'>{0}</tr>",
 69                 "<td/><td>发布时间</td><td colspan='2' readonly='true'><div></div></td>"));
 70             //行11 - 其他设置(分组)
 71             this.$tbody.append(GoFlow.formatString(
 72                "<tr style='display:table-row;background-color:rgb(234, 229, 229);height:0px;' group='TemplateOther'>{0}</tr>",
 73                "<td class='Expanded' group='TemplateOther'></td><td style='width: 100%;height:0px;' colspan='3'>其他设置</td>"));
 74             //行12 - 设计区域宽度
 75             this.$tbody.append(GoFlow.formatString(
 76                "<tr group='TemplateOther' property='DesignWidth'><td/><td>设计宽度</td>{0}</tr>",
 77                "<td colspan='2'><input type='text' class='goflow-valid-int' maxlength='50'/></td>"));
 78             //行13 - 设计区域高度
 79             this.$tbody.append(GoFlow.formatString(
 80                "<tr group='TemplateOther' property='DesignHeight'><td/><td>设计高度</td>{0}</tr>",
 81                "<td colspan='2'><input type='text' class='goflow-valid-int' maxlength='50'/></td>"));
 82             //行14 - 备注
 83             this.$tbody.append(GoFlow.formatString(
 84                 "<tr group='TemplateOther' property='TemplateMemo'><td/><td>模板备注</td>{0}{1}</tr>",
 85                 "<td><div id='TemplateMemo' style='width:100%;word-break:break-all;word-wrap: break-word;'/></td>",
 86                 "<td style='min-width:35px;'><input class='BizData' type='button' value='...'/></td>"));
 87 
 88             //给控件赋值
 89             this.bindData();
 90             //绑定事件
 91             this.bindDelegate();
 92         };
 93         //把流程模板数据绑定到控件
 94         p.bindData = function (data) {
 95             var self = this;
 96             if (data) {
 97                 $.each(data, function (k, v) {
 98                     self.setData(k, v);
 99                 });
100             } else {
101                 $.each(self.$opts.data, function (k, v) {
102                     self.setValue(k, v);
103                 });
104             }
105         };
106         //绑定事件
107         p.bindDelegate = function () {
108             //展开/收缩属性组
109             this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
110                 var $templateProp = e.data.self;
111                 var fold = $(e.target).hasClass("Fold");
112                 $(e.target).toggleClass("Fold", !fold);
113                 $(e.target).toggleClass("Expanded", fold);
114                 var selector = GoFlow.formatString(
115                     "[group='{0}'][property]",
116                     $(e.target).attr("group"));
117                 $templateProp.$tbody.children(selector).toggle();
118             });
119         };
120         p.getData = function (key) {
121             return this.$opts.data[key];
122         };
123         p.setData = function (key, value) {
124             this.$opts.data[key] = value;
125             this.setValue(key, value);
126         };
127         p.getValue = function (key) {
128             switch (key) {
129                 case "TemplateCode":
130                     break;
131                 case "TemplateName":
132                     break;
133                 case "InstanceName":
134                     break;
135                 case "Version":
136                     break;
137                 case "VerStatus":
138                     break;
139                 case "DesignerName":
140                     break;
141                 case "DesignTime":
142                     break;
143                 case "PublisherName":
144                     break;
145                 case "PublishTime":
146                     break;
147                 case "Memo":
148                     break;
149                 default:
150                     break;
151             };
152         };
153         p.setValue = function (key, value) {
154             switch (key) {
155                 case "TemplateCode":
156                     this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
157                     break;
158                 case "TemplateName":
159                     this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
160                     break;
161                 case "InstanceName":
162                     this.$tbody.find("tr:eq(3) > td:eq(2)").children("input:first").val(value);
163                     break;
164                 case "Version":
165                     this.$tbody.find("tr:eq(5) > td:eq(2)").children("div:eq(0)").html(value);
166                     break;
167                 case "VerStatus":
168                     this.$tbody.find("tr:eq(6) > td:eq(2)").children("div:eq(0)").html(value);
169                     break;
170                 case "DesignerName":
171                     this.$tbody.find("tr:eq(7) > td:eq(2)").children("div:eq(0)").html(value);
172                     break;
173                 case "DesignTime":
174                     this.$tbody.find("tr:eq(8) > td:eq(2)").children("div:eq(0)").html(value);
175                     break;
176                 case "PublisherName":
177                     this.$tbody.find("tr:eq(9) > td:eq(2)").children("div:eq(0)").html(value);
178                     break;
179                 case "PublishTime":
180                     this.$tbody.find("tr:eq(10) > td:eq(2)").children("div:eq(0)").html(value);
181                     break;
182                 case "DesignWidth":
183                     this.$tbody.find("tr:eq(12) > td:eq(2)").children("input:first").val(value);
184                     break;
185                 case "DesignHeight":
186                     this.$tbody.find("tr:eq(13) > td:eq(2)").children("input:first").val(value);
187                     break;
188                 case "TemplateMemo":
189                     this.$tbody.find("tr:eq(14) > td:eq(2)").children("div:eq(0)").html(value);
190                     break;
191                 default:
192                     break;
193             };
194         };
195         //显示/隐藏
196         p.setVisible = function (bool, data) {
197             this.$table.css("display", bool ? "block" : "none");
198             if (bool && data) {
199                 this.bindData(data);
200             }
201         };
202     }
203 };
204 //初始化TemplateProperty对象
205 TemplateProperty.prototype.init = function (gf, pdiv, opts) {
206     this.$gf = gf;
207     this.$propertyDiv = pdiv;
208     this.$opts = opts;
209     this.createTable();
210 };
View Code

1、开始节点属性

 1 //定义开始节点属性
 2 StartProperty = function () {
 3     if (typeof StartProperty.defaults == "undefined") {
 4         /*第一次定义对象时为StartProperty类定义静态属性*/
 5         StartProperty.defaults = {
 6             data: {
 7                 id: "",
 8                 title: ""
 9             }
10         };
11         /*第一次定义对象时定义实例共有方法*/
12         var p = StartProperty.prototype;
13         p.createTable = function () {
14             this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0'></table>").css("display", "none");
15             this.$tbody = $("<tbody></tbody>");
16             this.$table.append(this.$tbody);
17             this.$propertyDiv.append(this.$table);
18             //行0 - 基本属性(分组)
19             this.$tbody.append(GoFlow.formatString(
20                 "<tr style='display:table-row;background-color:rgb(234, 229, 229);height:0px;' group='StartBasic'>{0}</tr>",
21                 "<td class='Expanded' group='StartBasic'></td><td style='width: 100%;height:0px;' colspan='3'>基本属性</td>"));
22             //行1 - 结束节点编码
23             this.$tbody.append(GoFlow.formatString(
24                 "<tr group='StartBasic' property='NodeId'><td/><td>节点编码</td>{0}</tr>",
25                 "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
26             //行2 -  结束节点名称
27             this.$tbody.append(GoFlow.formatString(
28                 "<tr group='StartBasic' property='NodeTitle'><td/><td>节点名称</td>{0}</tr>",
29                 "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
30 
31             //给控件赋值
32             this.bindData();
33             //绑定事件
34             this.bindDelegate();
35         };
36         //把流程模板数据绑定到控件
37         p.bindData = function (data) {
38             var self = this;
39             if (data) self.$opts.data = data;
40             $.each(self.$opts.data, function (k, v) {
41                 self.setValue(k, v);
42             });
43         };
44         //绑定事件
45         p.bindDelegate = function () {
46             //展开/收缩属性组
47             this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
48                 var $startProp = e.data.self;
49                 var fold = $(e.target).hasClass("Fold");
50                 $(e.target).toggleClass("Fold", !fold);
51                 $(e.target).toggleClass("Expanded", fold);
52                 var selector = GoFlow.formatString(
53                     "[group='{0}'][property]",
54                     $(e.target).attr("group"));
55                 $startProp.$tbody.children(selector).toggle();
56             });
57         };
58         p.getData = function (key) {
59             return this.$opts.data[key];
60         };
61         p.setData = function (key, value) {
62             this.$opts.data[key] = value;
63             this.setValue(key, value);
64         };
65         p.setValue = function (key, value) {
66             switch (key) {
67                 case "id":
68                     this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
69                     break;
70                 case "title":
71                     this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
72                     break;
73                 default:
74                     break;
75             };
76         };
77         //显示/隐藏
78         p.setVisible = function (bool, data) {
79             this.$table.css("display", bool ? "block" : "none");
80             if (bool && data) {
81                 this.bindData(data);
82             }
83         };
84     }
85 };
86 //初始化StartProperty对象
87 StartProperty.prototype.init = function (pdiv, opts) {
88     this.$propertyDiv = pdiv;
89     this.$opts = opts;
90     this.createTable();
91 };
View Code

2、结束节点属性(跟开始结点比较类似,直接copy开始结点的)

 1 //定义结束节点属性
 2     EndProperty = function () {
 3         if (typeof EndProperty.defaults == "undefined") {
 4             /*第一次定义对象时为EndProperty类定义静态属性*/
 5             EndProperty.defaults = {
 6                 data: {
 7                     id: "",
 8                     title: ""
 9                 }
10             };
11             /*第一次定义对象时定义实例共有方法*/
12             var p = EndProperty.prototype;
13             p.createTable = function () {
14                 this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0'></table>").css("display", "none");
15                 this.$tbody = $("<tbody></tbody>");
16                 this.$table.append(this.$tbody);
17                 this.$propertyDiv.append(this.$table);
18                 //行0 - 基本属性(分组)
19                 this.$tbody.append(GoFlow.formatString(
20                    "<tr style='display:table-row;background-color:rgb(234, 229, 229);height:0px;' group='EndBasic'>{0}</tr>",
21                    "<td class='Expanded' group='EndBasic'></td><td style='width: 100%;height:0px;' colspan='3'>基本属性</td>"));
22                 //行1 - 结束节点编码
23                 this.$tbody.append(GoFlow.formatString(
24                     "<tr group='EndBasic' property='NodeId'><td/><td>节点编码</td>{0}</tr>",
25                     "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
26                 //行2 -  结束节点名称
27                 this.$tbody.append(GoFlow.formatString(
28                     "<tr group='EndBasic' property='NodeTitle'><td/><td>节点名称</td>{0}</tr>",
29                     "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
30 
31                 //给控件赋值
32                 this.bindData();
33                 //绑定事件
34                 this.bindDelegate();
35             };
36             //把流程模板数据绑定到控件
37             p.bindData = function (data) {
38                 var self = this;
39                 if (data) self.$opts.data = data;
40                 $.each(self.$opts.data, function (k, v) {
41                     self.setValue(k, v);
42                 });
43             };
44             //绑定事件
45             p.bindDelegate = function () {
46                 //展开/收缩属性组
47                 this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
48                     var $endProp = e.data.self;
49                     var fold = $(e.target).hasClass("Fold");
50                     $(e.target).toggleClass("Fold", !fold);
51                     $(e.target).toggleClass("Expanded", fold);
52                     var selector = GoFlow.formatString(
53                         "[group='{0}'][property]",
54                         $(e.target).attr("group"));
55                     $endProp.$tbody.children(selector).toggle();
56                 });
57             };
58             p.getData = function (key) {
59                 return this.$opts.data[key];
60             };
61             p.setData = function (key, value) {
62                 this.$opts.data[key] = value;
63                 this.setValue(key, value);
64             };
65             p.setValue = function (key, value) {
66                 switch (key) {
67                     case "id":
68                         this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
69                         break;
70                     case "title":
71                         this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
72                         break;
73                     default:
74                         break;
75                 };
76             };
77             //显示/隐藏
78             p.setVisible = function (bool, data) {
79                 this.$table.css("display", bool ? "block" : "none");
80                 if (bool && data) {
81                     this.bindData(data);
82                 }
83             };
84         }
85     };
86     //初始化EndProperty对象
87     EndProperty.prototype.init = function (pdiv, opts) {
88         this.$propertyDiv = pdiv;
89         this.$opts = opts;
90         this.createTable();
91     };
View Code

3、活动节点属性

  1 //定义活动节点属性
  2     ActivityProperty = function () {
  3         if (typeof ActivityProperty.defaults == "undefined") {
  4             /*第一次定义对象时为ActivityProperty类定义静态属性*/
  5             ActivityProperty.defaults = {
  6                 data: {
  7                     RecNo: 0,
  8                     TempNo: 0,
  9                     ElementNo: 0,
 10                     ActivityCode: "Activity1",
 11                     ActivityName: "活动1",
 12                     ActivityType: 1,/*1:串签;2:并签*/
 13                     ParallelRule: 1,/*1:一票否决;2:一票通过;3:少数服从多数*/
 14                     NoApprover: false, //无参与者(不做处理/审批通过)
 15                     IsWriter: false,  //是发起人(不做处理/审批通过)
 16                     IsPrior: false,  //前一活动参与(不做处理/审批通过)
 17                     IsApproved: false,  //参与过流程(不做处理/审批通过)
 18                     CanChange: false, //转处理人
 19                     CanHandling: false, //正在处理中
 20                     CanStop: false, //终止流程
 21                     CanCollect: false, //征询意见
 22                     CanHandRound: false, //传阅
 23                     CanReturnStart: false, //驳回开始
 24                     CanReturnPrior: false, //驳回上一步
 25                     CanReturnAny: false, //驳回任一步
 26                     AllowMail: true, //邮件通知
 27                     AllowMessage: true, //消息通知
 28                     Approvers: [] //参与者(多个)
 29                 }
 30             };
 31             /*第一次定义对象时定义实例共有方法*/
 32             var p = ActivityProperty.prototype;
 33             p.createTable = function () {
 34                 this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0' style='display:none;'></table>");
 35                 this.$tbody = $("<tbody></tbody>");
 36                 this.$table.append(this.$tbody);
 37                 this.$propertyDiv.append(this.$table);
 38                 //行0 - 基本属性(分组)
 39                 this.$trActivityBasic = $(GoFlow.formatString(
 40                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='ActivityBasic'>{0}</tr>",
 41                     "<td class='Expanded' group='ActivityBasic'></td><td style='width: 100%;' colspan='3'>基本属性</td>"));
 42                 this.$tbody.append(this.$trActivityBasic);
 43                 //行1 - 活动编码
 44                 this.$tbody.append(GoFlow.formatString(
 45                    "<tr group='ActivityBasic' property='ActivityCode'><td/><td>活动编码</td>{0}</tr>",
 46                    "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 47                 //行2 - 活动名称
 48                 this.$tbody.append(GoFlow.formatString(
 49                    "<tr group='ActivityBasic' property='ActivityName'><td/><td>活动名称</td>{0}</tr>",
 50                    "<td colspan='2'><input type='text' maxlength='50'/></td>"));
 51                 //行3 - 活动类型
 52                 this.$tbody.append(GoFlow.formatString(
 53                    "<tr group='ActivityBasic' property='ActivityType'><td/><td>活动类型</td><td colspan='2'>{0}{1}</td></tr>",
 54                    "<label for='ActivityType1'><input type='radio' id='ActivityType1' value='1' name='ActivityType'/>串签</label>",
 55                    "<label for='ActivityType2' style='padding-left:39px;'><input type='radio' id='ActivityType2' value='2' name='ActivityType'/>并签</label>"));
 56                 //行4 - 并签规则
 57                 this.$tbody.append(GoFlow.formatString(
 58                    "<tr group='ActivityBasic' property='ParallelRule'><td/><td>并签规则</td><td colspan='2'>{0}{1}{2}</td></tr>",
 59                    "<label for='ParallelRule1'><input type='radio' id='ParallelRule1' value='1' name='ParallelRule'/>一票通过</label>",
 60                    "<label for='ParallelRule2' style='padding-left:15px;'><input type='radio' id='ParallelRule2' value='2' name='ParallelRule'/>一票否决</label>",
 61                    "<label for='ParallelRule3' style='padding-left:15px;'><input type='radio' id='ParallelRule3' value='3' name='ParallelRule'/>少数服从多数</label>"));
 62                 //行5 - 参与者(分组)
 63                 this.$tbody.append(GoFlow.formatString(
 64                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='ActivityApprover'>{0}</tr>",
 65                     "<td class='Expanded' group='ActivityApprover'></td><td style='width: 100%;' colspan='3'>参与者</td>"));
 66                 //行6 - 参与者
 67                 this.$tbody.append(GoFlow.formatString(
 68                     "<tr group='ActivityApprover' property='Approvers'><td/><td>参与者</td>{0}{1}</tr>",
 69                     "<td><div id='Approvers' style='width:100%;'/></td>",
 70                     "<td style='min-width:35px;'><input class='BizData' type='button' value='...'/></td>"));
 71                 //行7 - 无参与者
 72                 this.$tbody.append(GoFlow.formatString(
 73                    "<tr group='ActivityApprover' property='NoApprover'><td/><td>无参与者</td><td colspan='2'>{0}{1}</td></tr>",
 74                    "<label for='NoApprover0'><input type='radio' id='NoApprover0' value='false' name='NoApprover'/>不做处理</label>",
 75                    "<label for='NoApprover1' style='padding-left:15px;'><input type='radio' id='NoApprover1' value='true' name='NoApprover'/>审批通过</label>"));
 76                 //行8 - 是发起人
 77                 this.$tbody.append(GoFlow.formatString(
 78                    "<tr group='ActivityApprover' property='IsWriter'><td/><td>是发起人</td><td colspan='2'>{0}{1}</td></tr>",
 79                    "<label for='IsWriter0'><input type='radio' id='IsWriter0' value='false' name='IsWriter'/>不做处理</label>",
 80                    "<label for='IsWriter1' style='padding-left:15px;'><input type='radio' id='IsWriter1' value='true' name='IsWriter'/>审批通过</label>"));
 81                 //行9 - 前一活动参与
 82                 this.$tbody.append(GoFlow.formatString(
 83                    "<tr group='ActivityApprover' property='IsPrior'><td/><td>前一活动参与</td><td colspan='2'>{0}{1}</td></tr>",
 84                    "<label for='IsPrior0'><input type='radio' id='IsPrior0' value='false' name='IsPrior'/>不做处理</label>",
 85                    "<label for='IsPrior1' style='padding-left:15px;'><input type='radio' id='IsPrior1' value='true' name='IsPrior'/>审批通过</label>"));
 86                 //行10 - 参与过流程
 87                 this.$tbody.append(GoFlow.formatString(
 88                    "<tr group='ActivityApprover' property='IsApproved'><td/><td>参与过流程</td><td colspan='2'>{0}{1}</td></tr>",
 89                    "<label for='IsApproved0'><input type='radio' id='IsApproved0' value='false' name='IsApproved'/>不做处理</label>",
 90                    "<label for='IsApproved1' style='padding-left:15px;'><input type='radio' id='IsApproved1' value='true' name='IsApproved'/>审批通过</label>"));
 91                 //行11 - 操作权限(分组)
 92                 this.$tbody.append(GoFlow.formatString(
 93                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='OperAuthority'>{0}</tr>",
 94                     "<td class='Expanded' group='OperAuthority'></td><td style='width: 100%;' colspan='3'>操作权限</td>"));
 95                 //行12 - 基本操作
 96                 this.$tbody.append(GoFlow.formatString(
 97                    "<tr group='OperAuthority' property='BaseOper'><td/><td>基本操作</td><td colspan='2'>{0}{1}{2}</td></tr>",
 98                    "<label for='CanChange'><input type='checkbox' id='CanChange'/>转处理人</label>",
 99                    "<label for='CanHandling' style='padding-left:15px;'><input type='checkbox' id='CanHandling'/>正在处理中</label>",
100                    "<label for='CanStop' style='padding-left:15px;'><input type='checkbox' id='CanStop'/>终止流程</label>"));
101                 //行13 - 协办操作
102                 this.$tbody.append(GoFlow.formatString(
103                    "<tr group='OperAuthority' property='AssistantOper'><td/><td>协办操作</td><td colspan='2'>{0}{1}</td></tr>",
104                    "<label for='CanCollect'><input type='checkbox' id='CanCollect'/>征询意见</label>",
105                    "<label for='CanHandRound' style='padding-left:15px;'><input type='checkbox' id='CanHandRound'/>传阅</label>"));
106                 //行14 - 驳回操作
107                 this.$tbody.append(GoFlow.formatString(
108                    "<tr group='OperAuthority' property='RejectOper'><td/><td>驳回操作</td><td colspan='2'>{0}{1}{2}</td></tr>",
109                    "<label for='CanReturnStart'><input type='checkbox' id='CanReturnStart'/>驳回开始</label>",
110                    "<label for='CanReturnPrior' style='padding-left:15px;'><input type='checkbox' id='CanReturnPrior'/>驳回上一步</label>",
111                    "<label for='CanReturnAny' style='padding-left:15px;'><input type='checkbox' id='CanReturnAny'/>驳回任一步</label>"));
112                 //行15 - 通知设置(分组)
113                 this.$tbody.append(GoFlow.formatString(
114                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='ActivityNotify'>{0}</tr>",
115                     "<td class='Expanded' group='ActivityNotify'></td><td style='width: 100%;' colspan='3'>通知设置</td>"));
116                 //行16 - 通知设置
117                 this.$tbody.append(GoFlow.formatString(
118                    "<tr group='ActivityNotify' property='ActivityNotify'><td/><td>通知设置</td><td colspan='2'>{0}{1}</td></tr>",
119                    "<label for='AllowMail'><input type='checkbox' id='AllowMail'/>邮件通知</label>",
120                    "<label for='AllowMessage' style='padding-left:15px;'><input type='checkbox' id='AllowMessage'/>消息通知</label>"));
121 
122                 //给控件赋值
123                 this.bindData();
124                 //绑定事件
125                 this.bindDelegate();
126             };
127             //把活动数据绑定到控件
128             p.bindData = function (data) {
129                 var self = this;
130                 if (data) self.$opts.data = data;
131                 $.each(self.$opts.data, function (k, v) {
132                     self.setValue(k, v);
133                 });
134             };
135             //绑定事件
136             p.bindDelegate = function () {
137                 //展开/收缩属性组
138                 this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
139                     var $activityProp = e.data.self;
140                     var fold = $(e.target).hasClass("Fold");
141                     $(e.target).toggleClass("Fold", !fold);
142                     $(e.target).toggleClass("Expanded", fold);
143                     var selector = GoFlow.formatString(
144                         "[group='{0}'][property]",
145                         $(e.target).attr("group"));
146                     $activityProp.$tbody.children(selector).toggle();
147                 });
148             };
149             p.getData = function (key) {
150                 return this.$opts.data[key];
151             };
152             p.setData = function (key, value) {
153                 this.$opts.data[key] = value;
154                 this.setValue(key, value);
155             };
156             p.getValue = function (key) {
157                 switch (key) {
158                     default:
159                         break;
160                 };
161             };
162             p.setValue = function (key, value) {
163                 switch (key) {
164                     case "ActivityCode":
165                         this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
166                         break;
167                     case "ActivityName":
168                         this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
169                         break;
170                     case "ActivityType":
171                         this.$tbody.find("tr:eq(3) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
172                         this.setParallelRuleReadonly(value == "1");
173                         break;
174                     case "ParallelRule":
175                         this.$tbody.find("tr:eq(4) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
176                         break;
177                     case "Approvers":
178                         var $divApprovers = this.$tbody.find("#Approvers").empty();
179                         $.each(value, function (idx, item) {
180                             $divApprovers.append(GoFlow.formatString(
181                                 "<div style='width:100%;padding:2px;'>{0} - {1}</div>", item.ApproveOrder, item.ApproverText));
182                         });
183                         break;
184                     case "NoApprover":
185                         this.$tbody.find("tr:eq(7) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
186                         break;
187                     case "IsWriter":
188                         this.$tbody.find("tr:eq(8) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
189                         break;
190                     case "IsPrior":
191                         this.$tbody.find("tr:eq(9) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
192                         break;
193                     case "IsApproved":
194                         this.$tbody.find("tr:eq(10) > td:eq(2)").find("input[value='" + value + "']").prop("checked", true);
195                         break;
196                     case "CanChange":
197                         this.$tbody.find("tr:eq(12) > td:eq(2)").find("input[id='CanChange']").prop("checked", value);
198                         break;
199                     case "CanHandling":
200                         this.$tbody.find("tr:eq(12) > td:eq(2)").find("input[id='CanHandling']").prop("checked", value);
201                         break;
202                     case "CanStop":
203                         this.$tbody.find("tr:eq(12) > td:eq(2)").find("input[id='CanStop']").prop("checked", value);
204                         break;
205                     case "CanCollect":
206                         this.$tbody.find("tr:eq(13) > td:eq(2)").find("input[id='CanCollect']").prop("checked", value);
207                         break;
208                     case "CanHandRound":
209                         this.$tbody.find("tr:eq(13) > td:eq(2)").find("input[id='CanHandRound']").prop("checked", value);
210                         break;
211                     case "CanReturnStart":
212                         this.$tbody.find("tr:eq(14) > td:eq(2)").find("input[id='CanReturnStart']").prop("checked", value);
213                         break;
214                     case "CanReturnPrior":
215                         this.$tbody.find("tr:eq(14) > td:eq(2)").find("input[id='CanReturnPrior']").prop("checked", value);
216                         break;
217                     case "CanReturnAny":
218                         this.$tbody.find("tr:eq(14) > td:eq(2)").find("input[id='CanReturnAny']").prop("checked", value);
219                         break;
220                     case "AllowMail":
221                         this.$tbody.find("tr:eq(16) > td:eq(2)").find("input[id='AllowMail']").prop("checked", value);
222                         break;
223                     case "AllowMessage":
224                         this.$tbody.find("tr:eq(16) > td:eq(2)").find("input[id='AllowMessage']").prop("checked", value);
225                         break;
226                     default:
227                         break;
228                 };
229             };
230             //设置并签规则是否只读
231             p.setParallelRuleReadonly = function (bool) {
232                 if (bool) {
233                     this.$tbody.find("tr:eq(4) > td:eq(2)").attr("readonly", "true")
234                     this.$tbody.find("tr:eq(4) > td:eq(2)").find("input").attr("disabled", "disabled");
235                 }
236                 else {
237                     this.$tbody.find("tr:eq(4) > td:eq(2)").removeAttr("readonly");
238                     this.$tbody.find("tr:eq(4) > td:eq(2)").find("input").removeAttr("disabled");
239                 }
240             };
241             //显示/隐藏
242             p.setVisible = function (bool, data) {
243                 this.$table.css("display", bool ? "block" : "none");
244                 if (bool && data) {
245                     this.bindData(data);
246                 }
247             };
248         }
249     };
250     //初始化ActivityProperty对象
251     ActivityProperty.prototype.init = function (gf, pdiv, opts) {
252         this.$gf = gf;
253         this.$propertyDiv = pdiv;
254         this.$opts = opts;
255         this.createTable();
256     };
View Code

4、连线属性

  1 //定义连线节点属性
  2     LineProperty = function () {
  3         if (typeof LineProperty.defaults == "undefined") {
  4             /*第一次定义对象时为LineProperty类定义静态属性*/
  5             LineProperty.defaults = {
  6                 data: {
  7                     RecNo: 0,
  8                     TempNo: 0,
  9                     ElementNo: 0,
 10                     LineCode: "Line_1",
 11                     LineTitle: "",
 12                     LineType: 'I',/*连线类型(I/Z/N)*/
 13                     FromElementCode: "",
 14                     FromElementName: '',
 15                     ToElementCode: "",
 16                     ToElementName: ''
 17                 }
 18             };
 19             /*第一次定义对象时定义实例共有方法*/
 20             var p = LineProperty.prototype;
 21             p.createTable = function () {
 22                 this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0' style='display:none;'></table>");
 23                 this.$tbody = $("<tbody></tbody>");
 24                 this.$table.append(this.$tbody);
 25                 this.$propertyDiv.append(this.$table);
 26                 //行0 - 基本属性(分组)
 27                 this.$trLineBasic = $(GoFlow.formatString(
 28                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='LineBasic'>{0}</tr>",
 29                     "<td class='Expanded' group='LineBasic'></td><td style='width: 100%;' colspan='3'>基本属性</td>"));
 30                 this.$tbody.append(this.$trLineBasic);
 31                 //行1 - 连线编码
 32                 this.$tbody.append(GoFlow.formatString(
 33                    "<tr group='LineBasic' property='LineCode'><td/><td>连线编码</td>{0}</tr>",
 34                    "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 35                 //行2 - 连线名称
 36                 this.$tbody.append(GoFlow.formatString(
 37                    "<tr group='LineBasic' property='LineTitle'><td/><td>连线名称</td>{0}</tr>",
 38                    "<td colspan='2'><input type='text' maxlength='50'/></td>"));
 39                 //行3 - 连接节点(分组)
 40                 this.$tbody.append(GoFlow.formatString(
 41                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='LineNode'>{0}</tr>",
 42                     "<td class='Expanded' group='LineNode'></td><td style='width: 100%;' colspan='3'>连接节点</td>"));
 43                 //行4 - 开始节点
 44                 this.$tbody.append(GoFlow.formatString(
 45                    "<tr group='LineNode' property='FromElementName'><td/><td>开始节点</td>{0}</tr>",
 46                    "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 47                 //行5 - 结束节点
 48                 this.$tbody.append(GoFlow.formatString(
 49                    "<tr group='LineNode' property='ToElementName'><td/><td>结束节点</td>{0}</tr>",
 50                    "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 51 
 52                 //给控件赋值
 53                 this.bindData();
 54                 //绑定事件
 55                 this.bindDelegate();
 56             };
 57             //把连线数据绑定到控件
 58             p.bindData = function (data) {
 59                 var self = this;
 60                 if (data) self.$opts.data = data;
 61                 $.each(self.$opts.data, function (k, v) {
 62                     self.setValue(k, v);
 63                 });
 64             };
 65             //绑定事件
 66             p.bindDelegate = function () {
 67                 //展开/收缩属性组
 68                 this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
 69                     var $lineProp = e.data.self;
 70                     var fold = $(e.target).hasClass("Fold");
 71                     $(e.target).toggleClass("Fold", !fold);
 72                     $(e.target).toggleClass("Expanded", fold);
 73                     var selector = GoFlow.formatString(
 74                         "[group='{0}'][property]",
 75                         $(e.target).attr("group"));
 76                     $lineProp.$tbody.children(selector).toggle();
 77                 });
 78             };
 79             p.getData = function (key) {
 80                 return this.$opts.data[key];
 81             };
 82             p.setData = function (key, value) {
 83                 this.$opts.data[key] = value;
 84                 this.setValue(key, value);
 85             };
 86             p.getValue = function (key) {
 87                 switch (key) {
 88                     default:
 89                         break;
 90                 };
 91             };
 92             p.setValue = function (key, value) {
 93                 switch (key) {
 94                     case "LineCode":
 95                         this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
 96                         break;
 97                     case "LineTitle":
 98                         this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
 99                         break;
100                     case "FromElementName":
101                         this.$tbody.find("tr:eq(4) > td:eq(2)").children("input:first").val(value);
102                         break;
103                     case "ToElementName":
104                         this.$tbody.find("tr:eq(5) > td:eq(2)").children("input:first").val(value);
105                         break;
106                     default:
107                         break;
108                 };
109             };
110             //显示/隐藏
111             p.setVisible = function (bool, data) {
112                 this.$table.css("display", bool ? "block" : "none");
113                 if (bool && data) {
114                     this.bindData(data);
115                 }
116             };
117         }
118     };
119     //初始化LineProperty对象
120     LineProperty.prototype.init = function (gf, pdiv, opts) {
121         this.$gf = gf;
122         this.$propertyDiv = pdiv;
123         this.$opts = opts;
124         this.createTable();
125     };
View Code

5、条件结点属性

  1 //定义条件节点属性
  2     ConditionProperty = function () {
  3         if (typeof ConditionProperty.defaults == "undefined") {
  4             /*第一次定义对象时为ConditionProperty类定义静态属性*/
  5             ConditionProperty.defaults = {
  6                 data: {
  7                     RecNo: 0,
  8                     TempNo: 0,
  9                     ElementNo: 0,
 10                     ConditionCode: "Condition_1",
 11                     ConditionTitle: "",
 12                     ElementCodeForTrue: "",
 13                     ElementNameForTrue: "",
 14                     ElementCodeForFalse: "",
 15                     ElementNameForFalse: "",
 16                     Expressions: [] //条件表达式(多个)
 17                 }
 18             };
 19             /*第一次定义对象时定义实例共有方法*/
 20             var p = ConditionProperty.prototype;
 21             p.createTable = function () {
 22                 this.$table = $("<table class='gf_prop_tb' cellpadding='0' cellspacing='0' style='display:none;'></table>");
 23                 this.$tbody = $("<tbody></tbody>");
 24                 this.$table.append(this.$tbody);
 25                 this.$propertyDiv.append(this.$table);
 26                 //行0 - 基本属性(分组)
 27                 this.$trConditionBasic = $(GoFlow.formatString(
 28                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='ConditionBasic'>{0}</tr>",
 29                     "<td class='Expanded' group='ConditionBasic'></td><td style='width: 100%;' colspan='3'>基本属性</td>"));
 30                 this.$tbody.append(this.$trConditionBasic);
 31                 //行1 - 条件编码
 32                 this.$tbody.append(GoFlow.formatString(
 33                    "<tr group='ConditionBasic' property='ConditionCode'><td/><td>条件编码</td>{0}</tr>",
 34                    "<td colspan='2' readonly='true'><input type='text' maxlength='50' readonly='readonly'/></td>"));
 35                 //行2 - 条件名称
 36                 this.$tbody.append(GoFlow.formatString(
 37                    "<tr group='ConditionBasic' property='ConditionTitle'><td/><td>条件名称</td>{0}</tr>",
 38                    "<td colspan='2'><input type='text' maxlength='50'/></td>"));
 39                 //行3 - 条件公式
 40                 this.$tbody.append(GoFlow.formatString(
 41                     "<tr group='ConditionBasic' property='Expressions'><td/><td>条件公式</td>{0}{1}</tr>",
 42                     "<td><div id='Expressions' style='width:100%;'/></td>",
 43                     "<td style='min-width:35px;'><input class='BizData' type='button' value='...'/></td>"));
 44                 //行4 - 连接节点(分组)
 45                 this.$tbody.append(GoFlow.formatString(
 46                     "<tr style='display:table-row;background-color:rgb(234, 229, 229);' group='ConditionNode'>{0}</tr>",
 47                     "<td class='Expanded' group='ConditionNode'></td><td style='width: 100%;' colspan='3'>连接节点</td>"));
 48                 //行5 - 条件为真
 49                 this.$tbody.append(GoFlow.formatString(
 50                    "<tr group='ConditionNode' property='ElementNameForTrue'><td/><td>条件为真</td>{0}{1}</tr>",
 51                    "<td readonly='true'><input id='ElementNameForTrue' style='width:100%;' type='text' maxlength='50' readonly='true'/></td>",
 52                    "<td style='min-width:35px;' readonly='true'><input class='BizData' type='button' value='...'/></td>"));
 53                 //行6 - 条件为假
 54                 this.$tbody.append(GoFlow.formatString(
 55                    "<tr group='ConditionNode' property='ElementNameForFalse'><td/><td>条件为假</td>{0}{1}</tr>",
 56                    "<td readonly='true'><input id='ElementNameForFalse' style='width:100%;' type='text' maxlength='50' readonly='true'/></td>",
 57                    "<td style='min-width:35px;' readonly='true'><input class='BizData' type='button' value='...'/></td>"));
 58 
 59                 //给控件赋值
 60                 this.bindData();
 61                 //绑定事件
 62                 this.bindDelegate();
 63             };
 64             //把条件数据绑定到控件
 65             p.bindData = function (data) {
 66                 var self = this;
 67                 if (data) self.$opts.data = data;
 68                 $.each(self.$opts.data, function (k, v) {
 69                     self.setValue(k, v);
 70                 });
 71             };
 72             //绑定事件
 73             p.bindDelegate = function () {
 74                 //展开/收缩属性组
 75                 this.$tbody.delegate("td[group].Fold,td[group].Expanded", "click", { self: this }, function (e) {
 76                     var $conditionProp = e.data.self;
 77                     var fold = $(e.target).hasClass("Fold");
 78                     $(e.target).toggleClass("Fold", !fold);
 79                     $(e.target).toggleClass("Expanded", fold);
 80                     var selector = GoFlow.formatString(
 81                         "[group='{0}'][property]",
 82                         $(e.target).attr("group"));
 83                     $conditionProp.$tbody.children(selector).toggle();
 84                 });
 85             };
 86             p.getData = function (key) {
 87                 return this.$opts.data[key];
 88             };
 89             p.setData = function (key, value) {
 90                 this.$opts.data[key] = value;
 91                 this.setValue(key, value);
 92             };
 93             p.getValue = function (key) {
 94                 switch (key) {
 95                     default:
 96                         break;
 97                 };
 98             };
 99             p.setValue = function (key, value) {
100                 switch (key) {
101                     case "ConditionCode":
102                         this.$tbody.find("tr:eq(1) > td:eq(2)").children("input:first").val(value);
103                         break;
104                     case "ConditionTitle":
105                         this.$tbody.find("tr:eq(2) > td:eq(2)").children("input:first").val(value);
106                         break;
107                     case "Expressions":
108                         var $divExpressions = this.$tbody.find("#Expressions").empty();
109                         $.each(value, function (idx, item) {
110                             $divExpressions.append(GoFlow.formatString(
111                                 "<div style='width:100%;padding:2px;'>{0} {1} {2} {3}</div>",
112                                 item.LeftValue, item.LogicalOper, item.RightValue, item.RelationOper));
113                         });
114                         break;
115                     case "ElementNameForTrue":
116                         this.$tbody.find("tr:eq(5) > td:eq(2)").children("input:first").val(value);
117                         break;
118                     case "ElementNameForFalse":
119                         this.$tbody.find("tr:eq(6) > td:eq(2)").children("input:first").val(value);
120                         break;
121                     default:
122                         break;
123                 };
124             };
125             //显示/隐藏
126             p.setVisible = function (bool, data) {
127                 this.$table.css("display", bool ? "block" : "none");
128                 if (bool && data) {
129                     this.bindData(data);
130                 }
131             };
132         }
133     };
134     //初始化ConditionProperty对象
135     ConditionProperty.prototype.init = function (gf, pdiv, opts) {
136         this.$gf = gf;
137         this.$propertyDiv = pdiv;
138         this.$opts = opts;
139         this.createTable();
140     };
View Code

6、切换属性方法

//切换属性显示
p.switchPropery = function (id, type) {
    type = type ? type : "template";
    this.setPropertyTitle(id, type);
    this.$templateProp.setVisible(type == "template");  //显示流程模板属性
    this.$startProp.setVisible(type == "start", type == "start" ? this.$nodeData[id] : null); //显示开始节点属性
    this.$endProp.setVisible(type == "end", type == "end" ? this.$nodeData[id] : null); //显示结束节点属性
    this.$lineProp.setVisible(type == "line", type == "line" ? this.$lineData[id].lineProperty : null);  //显示连线属性
    this.$activityProp.setVisible(type == "activity", type == "activity" ? this.$nodeData[id].activityProperty : null);  //显示活动节点属性
    this.$conditionProp.setVisible(type == "condition", type == "condition" ? this.$nodeData[id].conditionProperty : null);  //显示条件节点属性
};

7、切换属性标题显示方法

//设置属性标题
p.setPropertyTitle = function (id, type) {
    var text =
        type == "template" && "流程模板属性:" + this.$templateData.TemplateName
        || type == "start" && "开始节点属性:" + this.$nodeData[id].title
        || type == "end" && "结束节点属性:" + this.$nodeData[id].title
        || type == "line" && "连线属性:" + id
        || type == "activity" && "活动节点属性:" + this.$nodeData[id].title
        || type == "condition" && "条件节点属性:" + this.$nodeData[id].title
        || "";
    this.$propertyHeadDiv.children(".gf_p_head_inner").html(text);
}

8、goflow插件最新代码结构如下

(function ($, undefined) {
    //定义流程模板属性
    TemplateProperty = function () {
        
    };
    //初始化TemplateProperty对象
    TemplateProperty.prototype.init = function (gf, pdiv, opts) {
        
    };

    //定义开始节点属性
    StartProperty = function () {
        
    };
    //初始化StartProperty对象
    StartProperty.prototype.init = function (pdiv, opts) {
        
    };

    //定义结束节点属性
    EndProperty = function () {
        
    };
    //初始化EndProperty对象
    EndProperty.prototype.init = function (pdiv, opts) {
        
    };

    //定义活动节点属性
    ActivityProperty = function () {
        
    };
    //初始化ActivityProperty对象
    ActivityProperty.prototype.init = function (gf, pdiv, opts) {
        
    };

    //定义连线节点属性
    LineProperty = function () {
        
    };
    //初始化LineProperty对象
    LineProperty.prototype.init = function (gf, pdiv, opts) {
        
    };

    //定义条件节点属性
    ConditionProperty = function () {
        
    };
    //初始化ConditionProperty对象
    ConditionProperty.prototype.init = function (gf, pdiv, opts) {
        
    };

    //定义GoFlow类
    GoFlow = function () {
        
    };
    //初始化GoFlow对象(gfDiv:jQuery对象;opts:参数)
    GoFlow.prototype.init = function (gfDiv, opts) {
        
    };

    //插件的定义    
    $.fn.goflow = function (opts) {
        
    };
})(jQuery); //闭包结束

代码:GoFlow_06.zip

演示地址:Demo

微信演示公众号:

另:Silverlight版  

      Silverlight版Demo

posted @ 2015-10-26 16:12  Jimmy Cheung11  阅读(4019)  评论(13编辑  收藏  举报