wcj 6 سال پیش
والد
کامیت
ed12fd7715

+ 173 - 1
src/jy/admin/version.go

@@ -285,13 +285,15 @@ func init() {
 			if flag && len(*list) == 1 {
 				index = qu.IntAllDef((*list)[0]["index"], 1) - 1
 			}
+			unix := time.Now().Unix()
 			status = Mgo.Save("block_info", bson.M{
 				"delete":       false,
 				"index":        index,
 				"block_reg":    block_reg,
 				"title_reg":    title_reg,
 				"vid":          vid,
-				"l_createtime": time.Now().Unix(),
+				"l_createtime": unix,
+				"l_updatetime": unix,
 				"s_username":   sessions.Default(c).Get("username"),
 			}) != ""
 		}
@@ -315,6 +317,176 @@ func init() {
 		status := Mgo.UpdateById("block_info", _id, bson.M{"$set": bson.M{"delete": true}})
 		c.JSON(http.StatusOK, gin.H{"status": status})
 	})
+	//块的信息分类
+	Admin.GET("/version/blockclassify", func(c *gin.Context) {
+		vid := c.Query("vid")
+		c.HTML(http.StatusOK, "blockclassify.html", gin.H{"vid": vid})
+	})
+	Admin.POST("/version/blockclassify_delete", func(c *gin.Context) {
+		_id, _ := c.GetPostForm("_id")
+		status := Mgo.UpdateById("block_classify", _id, bson.M{"$set": bson.M{"delete": true}})
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_save", func(c *gin.Context) {
+		status := false
+		_id, _ := c.GetPostForm("_id")
+		name, _ := c.GetPostForm("name")
+		if _id != "" {
+			status = Mgo.UpdateById("block_classify", _id, bson.M{
+				"$set": bson.M{
+					"l_updatetime": time.Now().Unix(),
+					"name":         name,
+				},
+			})
+		} else {
+			vid, _ := c.GetPostForm("vid")
+			unix := time.Now().Unix()
+			status = Mgo.Save("block_classify", bson.M{
+				"delete":       false,
+				"name":         name,
+				"vid":          vid,
+				"l_createtime": unix,
+				"l_updatetime": unix,
+				"s_username":   sessions.Default(c).Get("username"),
+			}) != ""
+		}
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_list", func(c *gin.Context) {
+		vid, _ := c.GetPostForm("vid")
+		data, _ := Mgo.Find("block_classify", bson.M{"vid": vid, "delete": false}, `{"l_updatetime":-1}`, `{"name":1,"l_updatetime":1}`, false, -1, -1)
+		for _, v := range *data {
+			v["id"] = qu.BsonIdToSId(v["_id"])
+			l_updatetime := v["l_updatetime"]
+			v["l_updatetime"] = qu.FormatDateWithObj(&l_updatetime, qu.Date_Full_Layout)
+		}
+		c.JSON(http.StatusOK, gin.H{"data": data})
+	})
+	//块分类
+	Admin.GET("/version/blockclassify_info", func(c *gin.Context) {
+		pid := c.Query("pid")
+		vid := c.Query("vid")
+		c.HTML(http.StatusOK, "blockclassify_info.html", gin.H{"vid": vid, "pid": pid})
+	})
+	Admin.POST("/version/blockclassify_info_delete", func(c *gin.Context) {
+		_id, _ := c.GetPostForm("_id")
+		status := Mgo.UpdateById("block_classify_info", _id, bson.M{"$set": bson.M{"delete": true}})
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_info_save", func(c *gin.Context) {
+		status := 0
+		_id, _ := c.GetPostForm("_id")
+		name, _ := c.GetPostForm("name")
+		code, _ := c.GetPostForm("code")
+		if _id != "" {
+			if Mgo.UpdateById("block_classify_info", _id, bson.M{
+				"$set": bson.M{
+					"l_updatetime": time.Now().Unix(),
+					"name":         name,
+					"code":         code,
+				},
+			}) {
+				status = 1
+			}
+		} else {
+			vid, _ := c.GetPostForm("vid")
+			pid, _ := c.GetPostForm("pid")
+			unix := time.Now().Unix()
+			if Mgo.Count("block_classify_info", map[string]interface{}{
+				"delete": false,
+				"$or": []map[string]interface{}{
+					map[string]interface{}{
+						"name": name,
+					},
+					map[string]interface{}{
+						"code": code,
+					},
+				},
+			}) == 1 {
+				status = -1
+			} else {
+				if Mgo.Save("block_classify_info", bson.M{
+					"delete":       false,
+					"name":         name,
+					"code":         code,
+					"vid":          vid,
+					"pid":          pid,
+					"l_createtime": unix,
+					"l_updatetime": unix,
+					"s_username":   sessions.Default(c).Get("username"),
+				}) != "" {
+					status = 1
+				}
+			}
+		}
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_info_list", func(c *gin.Context) {
+		pid, _ := c.GetPostForm("pid")
+		data, _ := Mgo.Find("block_classify_info", bson.M{"pid": pid, "delete": false}, `{"l_updatetime":-1}`, `{"name":1,"code":1,"l_updatetime":1}`, false, -1, -1)
+		for _, v := range *data {
+			v["id"] = qu.BsonIdToSId(v["_id"])
+			l_updatetime := v["l_updatetime"]
+			v["l_updatetime"] = qu.FormatDateWithObj(&l_updatetime, qu.Date_Full_Layout)
+		}
+		c.JSON(http.StatusOK, gin.H{"data": data})
+	})
+	//块标签
+	Admin.GET("/version/blockclassify_tag", func(c *gin.Context) {
+		pid := c.Query("pid")
+		vid := c.Query("vid")
+		c.HTML(http.StatusOK, "blockclassify_tag.html", gin.H{"vid": vid, "pid": pid})
+	})
+	Admin.POST("/version/blockclassify_tag_delete", func(c *gin.Context) {
+		_id, _ := c.GetPostForm("_id")
+		status := Mgo.UpdateById("block_classify_tag", _id, bson.M{"$set": bson.M{"delete": true}})
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_tag_save", func(c *gin.Context) {
+		status := 0
+		_id, _ := c.GetPostForm("_id")
+		name, _ := c.GetPostForm("name")
+		if _id != "" {
+			if Mgo.UpdateById("block_classify_tag", _id, bson.M{
+				"$set": bson.M{
+					"l_updatetime": time.Now().Unix(),
+					"name":         name,
+				},
+			}) {
+				status = 1
+			}
+		} else {
+			vid, _ := c.GetPostForm("vid")
+			pid, _ := c.GetPostForm("pid")
+			unix := time.Now().Unix()
+			if Mgo.Count("block_classify_tag", map[string]interface{}{"delete": false, "name": name, "pid": pid}) == 1 {
+				status = -1
+			} else {
+				if Mgo.Save("block_classify_tag", bson.M{
+					"delete":       false,
+					"name":         name,
+					"vid":          vid,
+					"pid":          pid,
+					"l_createtime": unix,
+					"l_updatetime": unix,
+					"s_username":   sessions.Default(c).Get("username"),
+				}) != "" {
+					status = 1
+				}
+			}
+		}
+		c.JSON(http.StatusOK, gin.H{"status": status})
+	})
+	Admin.POST("/version/blockclassify_tag_list", func(c *gin.Context) {
+		pid, _ := c.GetPostForm("pid")
+		data, _ := Mgo.Find("block_classify_tag", bson.M{"pid": pid, "delete": false}, `{"l_updatetime":-1}`, `{"name":1,"l_updatetime":1}`, false, -1, -1)
+		for _, v := range *data {
+			v["id"] = qu.BsonIdToSId(v["_id"])
+			l_updatetime := v["l_updatetime"]
+			v["l_updatetime"] = qu.FormatDateWithObj(&l_updatetime, qu.Date_Full_Layout)
+		}
+		c.JSON(http.StatusOK, gin.H{"data": data})
+	})
 }
 
 //克隆版本通用属性

+ 52 - 0
src/jy/extract/extractInit.go

@@ -1211,5 +1211,57 @@ func (e *ExtractTask) InitBlockRule() {
 	e.RuleBlock = &ju.RuleBlock{
 		BlockRegs: brs,
 		TitleRegs: trs,
+		Classify:  e.InitBlockClassify(),
+	}
+}
+
+//加载分块规则
+func (e *ExtractTask) InitBlockClassify() *ju.BlockClassify {
+	classify, _ := db.Mgo.Find("block_classify", map[string]interface{}{
+		"vid":    e.TaskInfo.VersionId,
+		"delete": false,
+	}, nil, `{"name":1}`, false, -1, -1)
+	classify_info, _ := db.Mgo.Find("block_classify_info", map[string]interface{}{
+		"vid":    e.TaskInfo.VersionId,
+		"delete": false,
+	}, nil, `{"name":1,"code":1,"pid":1}`, false, -1, -1)
+	classify_tag, _ := db.Mgo.Find("block_classify_tag", map[string]interface{}{
+		"vid":    e.TaskInfo.VersionId,
+		"delete": false,
+	}, nil, `{"name":1,"pid":1}`, false, -1, -1)
+	tag_map := map[string]ju.Tags{}
+	for _, v := range *classify_tag {
+		pid := qu.ObjToString(v["pid"])
+		tag_map[pid] = append(tag_map[pid], &ju.Tag{Value: qu.ObjToString(v["name"])})
+	}
+	//
+	info_map := map[string][]*ju.NameCode{}
+	info_tag := map[string]*ju.TagFile{}
+	for _, v := range *classify_info {
+		pid := qu.ObjToString(v["pid"])
+		_id := qu.BsonIdToSId(v["_id"])
+		name := qu.ObjToString(v["name"])
+		info_tag[name] = &ju.TagFile{
+			Name:  name,
+			Items: tag_map[_id],
+		}
+		info_map[pid] = append(info_map[pid], &ju.NameCode{
+			Name: name,
+			Code: qu.ObjToString(v["code"]),
+		})
+	}
+	classify_map := map[string][]*ju.NameCode{}
+	for _, v := range *classify {
+		_id := qu.BsonIdToSId(v["_id"])
+		if info_map[_id] == nil {
+			continue
+		}
+		for _, vv := range strings.Split(qu.ObjToString(v["name"]), ",") {
+			classify_map[vv] = append(classify_map[vv], info_map[_id]...)
+		}
+	}
+	return &ju.BlockClassify{
+		Type:     classify_map,
+		Classify: info_tag,
 	}
 }

+ 4 - 4
src/jy/pretreated/analystep.go

@@ -28,13 +28,13 @@ func AnalyStart(job *util.Job) {
 			ration = newration
 		}
 	}
-	blockArrays, _ := DivideBlock(con, 1, job.RuleBlock) //分块
-	if len(blockArrays) > 0 {                            //有分块
+	blockArrays, _ := DivideBlock(job.CategorySecond, con, 1, job.RuleBlock) //分块
+	if len(blockArrays) > 0 {                                                //有分块
 		//从块里面找分包
 		job.BlockPackage = FindPackageFromBlocks(&blockArrays, job.Title) //从块里面找分包
 		for _, bl := range blockArrays {
 			if len([]rune(bl.Text)) > 80 {
-				bl.Block, _ = DivideBlock(bl.Text, 1, job.RuleBlock)
+				bl.Block, _ = DivideBlock(job.CategorySecond, bl.Text, 1, job.RuleBlock)
 			}
 			//块中再查找表格(块,处理完把值赋到块)
 			t1, _ := ComputeConRatio(bl.Text, 2)
@@ -225,7 +225,7 @@ func processTableResult(tabres *TableResult, block *util.Block, job *util.Job) {
 //ration==1 遍历所有tabs,ration!=1 tabs只有一个
 func tableDivideBlock(con string, ration float32, tabs []*goquery.Selection) string {
 	if len(tabs) != 1 {
-		return ""//5c2aca5ea5cb26b9b7a8229b
+		return "" //5c2aca5ea5cb26b9b7a8229b
 	}
 	for _, tab := range tabs {
 		content := ""

+ 5 - 5
src/jy/pretreated/analytable.go

@@ -1440,7 +1440,7 @@ func (table *Table) FindKV() {
 							}
 							if len(td.SortKV.Map) > 0 {
 								for tdk, tdv := range td.SortKV.Map {
-									if tdv == nil || tdv == "" {//value为空或者null不再添加到table.SortKV
+									if tdv == nil || tdv == "" { //value为空或者null不再添加到table.SortKV
 										continue
 									}
 									table.SortKV.AddKey(tdk, tdv)
@@ -1804,7 +1804,7 @@ func (table *Table) FindTdVal(td *TD, direct, vdirect int) (b bool) {
 			tkey := fmtkey("k", near.TR.RowPos, near.ColPos)
 			table.SortKV.ReplaceKey(key, val, tkey)
 		} else {
-			if val == nil || val == "" ||key=="采购项目预算金额"{
+			if val == nil || val == "" || key == "采购项目预算金额" {
 				return
 			}
 			table.SortKV.AddKey(key, val)
@@ -1982,7 +1982,7 @@ func (tn *Table) CheckMultiPackageByTable() (b bool, index []string) {
 }
 
 //多包处理,处理不同情况下的分包
-func (tn *Table) manyPackageProcessByIndex(index []string, standIndex_pos []int, ) (isGoonNext bool) {
+func (tn *Table) manyPackageProcessByIndex(index []string, standIndex_pos []int) (isGoonNext bool) {
 	if len(index) == 1 { //是一个的情况
 		if len(tn.SortKV.Keys) < 10 && tn.ColNum < 10 && tn.RowNum < 4 { //table带排序的KV值小于10并且小于10列和小于4行
 			beq := true
@@ -2519,7 +2519,7 @@ L:
 			//和|以?及|与|、多个词和在一起
 			jumpNextTd, thisTrHasMatch = tn.tdsMultipleWords(jumpNextTd, td, td_index, tr, thisTrHasMatch, indexMap)
 			//分块之后的kv
-			thisTdKvs := kvAfterDivideBlock(td.Text, 3, tn.TableResult.RuleBlock)
+			thisTdKvs := kvAfterDivideBlock("", td.Text, 3, tn.TableResult.RuleBlock)
 			if len(thisTdKvs) == 0 {
 				thisTdKvs = tn.tdkv(td) //获取冒号kv
 			}
@@ -3147,7 +3147,7 @@ func initLineMapLineMapArr(table *Table) (lineMapArr map[string]*SortMap, lineMa
 	for _, key := range table.SortKV.Keys { //遍历table.SortKV.Keys而不是直接遍历table.SortKV.Map是为了得到table头的顺序
 		val := table.SortKV.Map[key]
 		key = regReplAllSpace.ReplaceAllString(key, "")
-		key = strings.Replace(key, "", "", -1) //处理一个特殊的采购量 经上层处理空格后未处理掉
+		key = strings.Replace(key, "", "", -1)    //处理一个特殊的采购量 经上层处理空格后未处理掉
 		if realTypeVal, ok := val.([]string); ok { //val为数组 {"数量":["1","2","3"]}
 			/*
 				{

+ 11 - 8
src/jy/pretreated/division.go

@@ -68,7 +68,7 @@ var (
 )
 
 //分块
-func DivideBlock(content string, from int, ruleBlock *util.RuleBlock) ([]*util.Block, int) {
+func DivideBlock(tp, content string, from int, ruleBlock *util.RuleBlock) ([]*util.Block, int) {
 	defer qutil.Catch()
 	returnValue := 0
 	var blocks []*util.Block
@@ -81,10 +81,10 @@ func DivideBlock(content string, from int, ruleBlock *util.RuleBlock) ([]*util.B
 	tdIndexs := regReplAllTd.FindAllStringSubmatchIndex(content, -1)
 	var regContenSerialTitle *regexp.Regexp
 	var regSerialTitleIndex int
-	if ruleBlock!=nil && len(ruleBlock.BlockRegs)>0{
+	if ruleBlock != nil && len(ruleBlock.BlockRegs) > 0 {
 		regContenSerialTitle, regSerialTitleIndex = getSerialType(contentTemp, ruleBlock.BlockRegs)
-	}else {
-		regContenSerialTitle, regSerialTitleIndex = getSerialType(contentTemp,  regSerialTitles_1)
+	} else {
+		regContenSerialTitle, regSerialTitleIndex = getSerialType(contentTemp, regSerialTitles_1)
 	}
 	//没有分块
 	if regSerialTitleIndex == -1 {
@@ -97,9 +97,9 @@ func DivideBlock(content string, from int, ruleBlock *util.RuleBlock) ([]*util.B
 	}
 	//匹配序号和标题
 	var regSerialTitle *regexp.Regexp
-	if ruleBlock != nil && len(ruleBlock.TitleRegs)>0{
+	if ruleBlock != nil && len(ruleBlock.TitleRegs) > 0 {
 		regSerialTitle = ruleBlock.TitleRegs[regSerialTitleIndex]
-	}else {
+	} else {
 		regSerialTitle = regSerialTitles_2[regSerialTitleIndex]
 	}
 	indexs := regContenSerialTitle.FindAllStringIndex(content, -1)
@@ -233,6 +233,7 @@ func DivideBlock(content string, from int, ruleBlock *util.RuleBlock) ([]*util.B
 			End:    nextStart,
 		}
 
+		titles := []string{}
 		for _, sv := range splitTitles {
 			if sv == "" || titleIsExists[sv] {
 				continue
@@ -242,8 +243,10 @@ func DivideBlock(content string, from int, ruleBlock *util.RuleBlock) ([]*util.B
 			if len([]rune(sv)) >= 2 && len([]rune(sv)) <= 10 {
 				//打标签
 				block.Tags = append(block.Tags, util.GetBlockTags(sv))
+				titles = append(titles, sv)
 			}
 		}
+		block.Classify = ruleBlock.Classify.GetClassify(tp, titles)
 		tagsToBlocks(blocks, block)
 		//log.Println(index, sv, splitTitles)
 		//log.Println(blockText)
@@ -801,8 +804,8 @@ func interceptText(indexs []int, indexPkgMap map[int]string, pkgIndexMap map[str
 }
 
 //分块之后的kv
-func kvAfterDivideBlock(text string, from int, ruleBlock *util.RuleBlock) []*util.Kv {
-	blocks, _ := DivideBlock(text, from, ruleBlock)
+func kvAfterDivideBlock(tp, text string, from int, ruleBlock *util.RuleBlock) []*util.Kv {
+	blocks, _ := DivideBlock(tp, text, from, ruleBlock)
 	kvs := []*util.Kv{}
 	for _, v := range blocks {
 		//util.Debug(v.Text)

+ 1 - 1
src/jy/pretreated/tablev2.go

@@ -237,7 +237,7 @@ func (td *TD) tdIsHb(tr *TR, table *Table, bsontable bool) {
 	//经过处理的td内容长度大于50,划块,分包
 	if lenval > 50 { //看是否划块
 		//u.Debug(txt)
-		ub, _ = DivideBlock(td.Text, 2, table.TableResult.RuleBlock) //对td的原始值
+		ub, _ = DivideBlock("", td.Text, 2, table.TableResult.RuleBlock) //对td的原始值
 		//看是否划块
 		if len(ub) > 0 {
 			colonKvWeight := map[string]int{}

+ 42 - 11
src/jy/util/article.go

@@ -25,6 +25,7 @@ type Job struct {
 	Winnerorder    []map[string]interface{}          //中标候选人排序
 	PackageInfo    map[string]map[string]interface{} //分包信息
 	RuleBlock      *RuleBlock                        //分块规则
+	BlockClassify  *BlockClassify                    //块分类
 	BrandData      [][]map[string]string             //
 	HasTable       int                               //有table
 	HasKey         int                               //是否匹配到table中的标题
@@ -37,16 +38,16 @@ type Job struct {
 }
 
 type ExtField struct {
-	BlockTag  map[string]bool         //块标签
-	Field     string                  //属性
-	Code      string                  //匹配标签(字符串、正则)、正则或lua代码
-	RuleText  string                  //内容
-	Type      string                  //kv(细类:colon1,colon2,space,table)、正则(regexp)
-	MatchType string                  //匹配类型:1:标签库类型(tag_string,tag_regexp),2:全文正则regcontent
-	ExtFrom   string                  //抽取来源(title,detail)
-	Value     interface{}             //抽取结果
-	Score     float64                 //得分
-	ScoreItem []*ScoreItem //打分项
+	BlockTag  map[string]bool //块标签
+	Field     string          //属性
+	Code      string          //匹配标签(字符串、正则)、正则或lua代码
+	RuleText  string          //内容
+	Type      string          //kv(细类:colon1,colon2,space,table)、正则(regexp)
+	MatchType string          //匹配类型:1:标签库类型(tag_string,tag_regexp),2:全文正则regcontent
+	ExtFrom   string          //抽取来源(title,detail)
+	Value     interface{}     //抽取结果
+	Score     float64         //得分
+	ScoreItem []*ScoreItem    //打分项
 }
 
 //打分项
@@ -65,6 +66,7 @@ type ScoreItem struct {
 type RuleBlock struct {
 	BlockRegs []*regexp.Regexp
 	TitleRegs []*regexp.Regexp
+	Classify  *BlockClassify
 }
 
 //块
@@ -82,7 +84,7 @@ type Block struct {
 	BPackage    *BlockPackage            //分包信息
 	Tag         map[string]bool          //块标签
 	Block       []*Block                 //子块
-	Category    string                   //块分类
+	Classify    []string                 //块分类
 	Winnerorder []map[string]interface{} //块中,中标候选人排序
 }
 
@@ -166,3 +168,32 @@ func NewJobKv() *JobKv {
 		KvTag: map[string]*Tag{},
 	}
 }
+
+type NameCode struct {
+	Name string
+	Code string
+}
+
+type BlockClassify struct {
+	Type     map[string][]*NameCode
+	Classify map[string]*TagFile
+}
+
+func (b *BlockClassify) GetClassify(tp string, src []string) []string {
+	exists := map[string]bool{}
+	ret := []string{}
+	for _, v := range src {
+		v = TrimLRAll(v, "")
+		for _, vv := range b.Type[tp] {
+			if ok, _ := b.Classify[vv.Name].Match(v); ok {
+				if exists[vv.Code] {
+					break
+				}
+				exists[vv.Code] = true
+				ret = append(ret, vv.Code)
+				break
+			}
+		}
+	}
+	return ret
+}

+ 149 - 0
src/web/templates/admin/blockclassify.html

@@ -0,0 +1,149 @@
+{{template "inc"}}
+<!-- Main Header -->
+{{template "header"}}
+<!-- Left side column. 权限菜单 -->
+{{template "memu"}}
+
+<!-- Content Wrapper. Contains page content -->
+<div class="content-wrapper">
+	<section class="content-header">
+		<h1>
+			<small><a class="btn btn-primary opr" opr="new">新增分类</a></small>
+		</h1>
+		<ol class="breadcrumb">
+		  <li><a href="/admin/version"><i class="fa fa-dashboard"></i>抽取版本</a></li>
+		  <li class="active"><a href="/admin/version/blockinfo?vid={{.vid}}">分块配置</a></li>
+		</ol>
+    </section>
+  <!-- Main content -->
+  <section class="content">
+      <div class="row">
+	      <div class="col-xs-12">
+	        <div class="box">
+		        <div class="box-body">
+		            <table id="dataTable" class="table table-striped table-bordered table-hover">
+		              <thead>
+		              <tr>
+						<th>信息类型(二级分类)</th>
+						<th>时间</th>
+						<th>操作</th>
+		              </tr>
+		              </thead>
+		            </table>
+		        </div>
+	          <!-- /.box-body -->
+	        </div>
+        <!-- /.box -->
+		</div>
+	</div>
+  </section>
+</div>
+	
+<!-- footer -->
+{{template "dialog"}}
+{{template "footer"}}
+<script>
+menuActive("version")
+$(function () {
+	ttable=$('#dataTable').DataTable({
+		"ordering"    : false,
+		"paging"      : false,
+		"lengthChange": false,
+		"searching"   : false,
+		"info"        : true,
+		"autoWidth"   : false,
+		"language": {
+            "url": "/res/dist/js/dataTables.chinese.lang"
+        },
+		"ajax": {
+			"url": "/admin/version/blockclassify_list",
+			"type": "post",
+			"data":{"vid":{{.vid}}}
+		},
+		"columns": [
+			{"data": "name","width":"50%",render:function(val,a,row){
+				return '<a href="/admin/version/blockclassify_info?pid='+row["_id"]+'&vid={{.vid}}">'+val+'</a>';
+			}},
+			{"data": "l_updatetime","width":"25%"},
+			{"data":"_id","width":"20%",render:function(val,a,row){
+				return '<a class="btn btn-sm btn-primary opr" opr="edit">编辑</a>&nbsp;<a class="btn btn-sm btn-danger" href="#" onclick="del(\''+val+'\')">删除</a>';
+			}}
+       	]
+	});
+	ttable.on('init.dt', function () {
+		$(".opr").click(function(){
+			var n=$(this).attr("opr")
+			var _tit="",htmlObj={},obj,tag=[]
+			switch(n){
+			case "classify":
+				window.location.href = "/admin/version/blockclassify?vid={{.vid}}";
+				break
+			case "edit":	
+                obj=ttable.row($(this).closest("tr")).data();
+			case "new":
+                tag=[
+						{label:"名称",s_label:"name",type:"tpl_input",placeholder:"分类名称,多个逗号隔开",must:true},
+                        {s_label:"_id",type:"tpl_hidden"},
+					]
+				
+				if(n=="new"){
+					_tit="新增分类"
+					obj={}
+				}else{
+					_tit="编辑分类"
+				}
+				htmlObj={
+					title:_tit,
+					tag:tag,
+					bts:[
+						{label:"保存",class:"btn-primary",
+							fun:function(){
+								var name = $.trim($("#name").val());
+								var bcon=true;
+								if(name==""){
+									bcon=false;
+								}
+								if (bcon){
+									var obj={
+										_id:$("#_id").val(),
+										name:name,
+										vid:{{.vid}}
+									}
+                                    //console.log(obj)							
+									$.post("/admin/version/blockclassify_save",obj,function(data){
+										if(data.status){
+											window.location.href="/admin/version/blockclassify?vid={{.vid}}";	
+										}else{
+											showTip("保存失败!",1000)
+										}
+									},'json')
+								}else{
+									alert("红色标签的表单不能为空!")
+								}
+							}
+						}
+					]
+				}
+			OpenDialog(htmlObj,obj)
+			break;
+			}
+		});
+	});
+})
+function del(_id){
+	showConfirm("确定删除?", function() {
+		$.ajax({
+			url:"/admin/version/blockclassify_delete",
+			type:"post",
+			data:{"_id":_id},
+			success:function(r){
+				if(r.status){				
+					ttable.ajax.reload();
+				}else{
+					showTip("删除失败", 1000, function() {});
+				}
+			}
+		})
+	});
+}
+</script>

+ 161 - 0
src/web/templates/admin/blockclassify_info.html

@@ -0,0 +1,161 @@
+{{template "inc"}}
+<!-- Main Header -->
+{{template "header"}}
+<!-- Left side column. 权限菜单 -->
+{{template "memu"}}
+
+<!-- Content Wrapper. Contains page content -->
+<div class="content-wrapper">
+	<section class="content-header">
+		<h1>
+			<small><a class="btn btn-primary opr" opr="new">新增块分类</a></small>
+		</h1>
+		<ol class="breadcrumb">
+		  <li><a href="/admin/version"><i class="fa fa-dashboard"></i>抽取版本</a></li>
+		  <li class="active"><a href="/admin/version/blockinfo?vid={{.vid}}">分块配置</a></li>
+		</ol>
+    </section>
+  <!-- Main content -->
+  <section class="content">
+      <div class="row">
+	      <div class="col-xs-12">
+	        <div class="box">
+		        <div class="box-body">
+		            <table id="dataTable" class="table table-striped table-bordered table-hover">
+		              <thead>
+		              <tr>
+						<th>序号</th>
+						<th>分类名称</th>
+						<th>分类代码</th>
+						<th>时间</th>
+						<th>操作</th>
+		              </tr>
+		              </thead>
+		            </table>
+		        </div>
+	          <!-- /.box-body -->
+	        </div>
+        <!-- /.box -->
+		</div>
+	</div>
+  </section>
+</div>
+	
+<!-- footer -->
+{{template "dialog"}}
+{{template "footer"}}
+<script>
+menuActive("version")
+$(function () {
+	ttable=$('#dataTable').DataTable({
+		"ordering"    : false,
+		"paging"      : false,
+		"lengthChange": false,
+		"searching"   : false,
+		"info"        : true,
+		"autoWidth"   : false,
+		"language": {
+            "url": "/res/dist/js/dataTables.chinese.lang"
+        },
+		"ajax": {
+			"url": "/admin/version/blockclassify_info_list",
+			"type": "post",
+			"data":{"pid":{{.pid}}}
+		},
+		"columns": [
+			{"width":"10%",render:function(val,a,row){
+				return '';
+			}},
+			{"data": "name","width":"30%",render:function(val,a,row){
+				return '<a href="/admin/version/blockclassify_tag?pid='+row["_id"]+'&vid={{.vid}}">'+val+'</a>';
+			}},
+			{"data": "code","width":"25%"},
+			{"data": "l_updatetime","width":"15%"},
+			{"data":"_id","width":"20%",render:function(val,a,row){
+				return '<a class="btn btn-sm btn-primary opr" opr="edit">编辑</a>&nbsp;<a class="btn btn-sm btn-danger" href="#" onclick="del(\''+val+'\')">删除</a>';
+			}}
+       	]
+	});
+	ttable.on('init.dt', function () {
+		$(".opr").click(function(){
+			var n=$(this).attr("opr")
+			var _tit="",htmlObj={},obj,tag=[]
+			switch(n){
+			case "edit":	
+                obj=ttable.row($(this).closest("tr")).data();
+			case "new":
+                tag=[
+						{label:"分类名称",s_label:"name",type:"tpl_input",placeholder:"分类名称",must:true},
+						{label:"分类代码",s_label:"code",type:"tpl_input",placeholder:"分类代码",must:true},
+                        {s_label:"_id",type:"tpl_hidden"},
+					]
+				
+				if(n=="new"){
+					_tit="新增块分类"
+					obj={}
+				}else{
+					_tit="编辑块分类"
+				}
+				htmlObj={
+					title:_tit,
+					tag:tag,
+					bts:[
+						{label:"保存",class:"btn-primary",
+							fun:function(){
+								var name = $.trim($("#name").val());
+								var code = $.trim($("#code").val());
+								var bcon=true;
+								if(name==""||code==""){
+									bcon=false;
+								}
+								if (bcon){
+									var obj={
+										_id:$("#_id").val(),
+										name:name,
+										code:code,
+										vid:{{.vid}},
+										pid:{{.pid}}
+									}
+                                    //console.log(obj)							
+									$.post("/admin/version/blockclassify_info_save",obj,function(data){
+										if(data.status==1){
+											window.location.reload();
+										}else if (data.status==-1){
+											showTip("已存在!",1000)
+										}else{
+											showTip("保存失败!",1000)
+										}
+									},'json')
+								}else{
+									alert("红色标签的表单不能为空!")
+								}
+							}
+						}
+					]
+				}
+			OpenDialog(htmlObj,obj)
+			break;
+			}
+		});
+		ttable.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
+            cell.innerHTML = i+1;
+        } );
+	});
+})
+function del(_id){
+	showConfirm("确定删除?", function() {
+		$.ajax({
+			url:"/admin/version/blockclassify_info_delete",
+			type:"post",
+			data:{"_id":_id},
+			success:function(r){
+				if(r.status){				
+					window.location.reload();
+				}else{
+					showTip("删除失败", 1000, function() {});
+				}
+			}
+		})
+	});
+}
+</script>

+ 153 - 0
src/web/templates/admin/blockclassify_tag.html

@@ -0,0 +1,153 @@
+{{template "inc"}}
+<!-- Main Header -->
+{{template "header"}}
+<!-- Left side column. 权限菜单 -->
+{{template "memu"}}
+
+<!-- Content Wrapper. Contains page content -->
+<div class="content-wrapper">
+	<section class="content-header">
+		<h1>
+			<small><a class="btn btn-primary opr" opr="new">新增标签</a></small>
+		</h1>
+		<ol class="breadcrumb">
+		  <li><a href="/admin/version"><i class="fa fa-dashboard"></i>抽取版本</a></li>
+		  <li class="active"><a href="/admin/version/blockinfo?id={{.vid}}">分块配置</a></li>
+		</ol>
+    </section>
+  <!-- Main content -->
+  <section class="content">
+      <div class="row">
+	      <div class="col-xs-12">
+	        <div class="box">
+		        <div class="box-body">
+		            <table id="dataTable" class="table table-striped table-bordered table-hover">
+		              <thead>
+		              <tr>
+						<th>标签名</th>
+						<th>时间</th>
+						<th>操作</th>
+		              </tr>
+		              </thead>
+		            </table>
+		        </div>
+	          <!-- /.box-body -->
+	        </div>
+        <!-- /.box -->
+		</div>
+	</div>
+  </section>
+</div>
+	
+<!-- footer -->
+{{template "dialog"}}
+{{template "footer"}}
+<script>
+menuActive("version")
+$(function () {
+	ttable=$('#dataTable').DataTable({
+		"ordering"    : false,
+		"paging"      : false,
+		"lengthChange": false,
+		"searching"   : false,
+		"info"        : true,
+		"autoWidth"   : false,
+		"language": {
+            "url": "/res/dist/js/dataTables.chinese.lang"
+        },
+		"ajax": {
+			"url": "/admin/version/blockclassify_tag_list",
+			"type": "post",
+			"data":{"pid":{{.pid}}}
+		},
+		"columns": [
+			{"width":"10%",render:function(val,a,row){
+				return '';
+			}},
+			{"data": "name","width":"50%"},
+			{"data": "l_updatetime","width":"20%"},
+			{"data":"_id","width":"20%",render:function(val,a,row){
+				return '<a class="btn btn-sm btn-primary opr" opr="edit">编辑</a>&nbsp;<a class="btn btn-sm btn-danger" href="#" onclick="del(\''+val+'\')">删除</a>';
+			}}
+       	]
+	});
+	ttable.on('init.dt', function () {
+		$(".opr").click(function(){
+			var n=$(this).attr("opr")
+			var _tit="",htmlObj={},obj,tag=[]
+			switch(n){
+			case "edit":	
+                obj=ttable.row($(this).closest("tr")).data();
+			case "new":
+                tag=[
+						{label:"标签名",s_label:"name",type:"tpl_input",placeholder:"标签名",must:true},
+                        {s_label:"_id",type:"tpl_hidden"},
+					]
+				
+				if(n=="new"){
+					_tit="新增标签"
+					obj={}
+				}else{
+					_tit="编辑标签"
+				}
+				htmlObj={
+					title:_tit,
+					tag:tag,
+					bts:[
+						{label:"保存",class:"btn-primary",
+							fun:function(){
+								var name = $.trim($("#name").val());
+								var bcon=true;
+								if(name==""){
+									bcon=false;
+								}
+								if (bcon){
+									var obj={
+										_id:$("#_id").val(),
+										name:name,
+										vid:{{.vid}},
+										pid:{{.pid}}
+									}
+                                    //console.log(obj)							
+									$.post("/admin/version/blockclassify_tag_save",obj,function(data){
+										if(data.status==1){
+											window.location.reload();
+										}else if (data.status==-1){
+											showTip("已存在!",1000)
+										}else{
+											showTip("保存失败!",1000)
+										}
+									},'json')
+								}else{
+									alert("红色标签的表单不能为空!")
+								}
+							}
+						}
+					]
+				}
+			OpenDialog(htmlObj,obj)
+			break;
+			}
+		});
+		ttable.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
+	            cell.innerHTML = i+1;
+	    } );
+	});
+})
+function del(_id){
+	showConfirm("确定删除?", function() {
+		$.ajax({
+			url:"/admin/version/blockclassify_tag_delete",
+			type:"post",
+			data:{"_id":_id},
+			success:function(r){
+				if(r.status){				
+					window.location.reload();
+				}else{
+					showTip("删除失败", 1000, function() {});
+				}
+			}
+		})
+	});
+}
+</script>

+ 5 - 1
src/web/templates/admin/blockinfo.html

@@ -9,6 +9,7 @@
 	<section class="content-header">
 		<h1>
 			<small><a class="btn btn-primary opr" opr="new">新增规则</a></small>
+			<small><a class="btn btn-primary opr" opr="classify">块分类</a></small>
 		</h1>
 		<ol class="breadcrumb">
 		  <li><a href="/admin/version"><i class="fa fa-dashboard"></i>抽取版本</a></li>
@@ -76,7 +77,7 @@ $(function () {
 		"ajax": {
 			"url": "/admin/version/blockinfo_list",
 			"type": "post",
-			"data":{"vid":{{ .vid}}}
+			"data":{"vid":{{.vid}}}
 		},
 		"columns": [
 			{"data": "index","orderable": false},
@@ -92,6 +93,9 @@ $(function () {
 			var n=$(this).attr("opr")
 			var _tit="",htmlObj={},obj,tag=[]
 			switch(n){
+			case "classify":
+				window.location.href = "/admin/version/blockclassify?vid=5b88f682752d50045860188a";
+				break
 			case "edit":	
                 obj=ttable.row($(this).closest("tr")).data();
 			case "new":