Explorar o código

Merge branch 'dev2.0' of http://192.168.3.207:8080/data_processing/data_validation into dev2.0

# Conflicts:
#	src/front/quality.go 处理
zhengkun %!s(int64=3) %!d(string=hai) anos
pai
achega
1bee2ea0e1

+ 13 - 8
src/front/front.go

@@ -24,6 +24,7 @@ type Front struct {
 	logout             xweb.Mapper `xweb:"/front/logout"`            //注销
 	updatePwd          xweb.Mapper `xweb:"/front/updatepwd"`         //更新密码
 	userGroup          xweb.Mapper `xweb:"/front/group"`             //查所有用户组
+	userAll            xweb.Mapper `xweb:"/front/user"`              //查询用户列表
 	userGroupNew       xweb.Mapper `xweb:"/front/group/new"`         //用户组新建
 	userGroupState     xweb.Mapper `xweb:"/front/group/state"`       //用户组状态
 	userGroupStateBulk xweb.Mapper `xweb:"/front/group/bulks_setup"` //批量修改用户组状态
@@ -33,6 +34,7 @@ type Front struct {
 	userDel            xweb.Mapper `xweb:"/front/group/user/del"`    //用户删除
 	userModify         xweb.Mapper `xweb:"/front/group/user/modify"` // 修改用户信息
 	groupList          xweb.Mapper `xweb:"/front/group/list"`        //用户组选择列表
+	userList           xweb.Mapper `xweb:"/front/group/user/list"`   //用户组的普通用户列表
 
 	//menu
 	menu           xweb.Mapper `xweb:"/front/menu"`            //查一级菜单
@@ -53,22 +55,25 @@ type Front struct {
 	roleSecondEdit xweb.Mapper `xweb:"/front/role/second/edit"` //二级权限编辑
 
 	//project
-	projectList           xweb.Mapper `xweb:"/front/project"`                //项目列表
-	projectSave           xweb.Mapper `xweb:"/front/project/save"`           //新增项目
-	projectTaskSave       xweb.Mapper `xweb:"/front/project/task/save"`      //用户组任务分发
-	projectTaskList       xweb.Mapper `xweb:"/front/project/task/list"`      //用户组任务分发列表
-	projectTaskRetrieve   xweb.Mapper `xweb:"/front/project/task/retrieve"`  //用户组任务收回
-	projectTaskRepulse    xweb.Mapper `xweb:"/front/project/task/repulse"`   //用户组任务打回
-	projectTaskClose      xweb.Mapper `xweb:"/front/project/task/close"`     //用户组任务关闭
-	projectGetEntnameList xweb.Mapper `xweb:"/front/project/getEntnameList"` //模糊查询公司名称
+	projectList              xweb.Mapper `xweb:"/front/project"`                   //项目列表
+	projectSave              xweb.Mapper `xweb:"/front/project/save"`              //新增项目
+	projectQualityAssessment xweb.Mapper `xweb:"/front/project/qualityAssessment"` //数据质量评估
+	projectTaskSave          xweb.Mapper `xweb:"/front/project/task/save"`         //用户组任务分发
+	projectTaskList          xweb.Mapper `xweb:"/front/project/task/list"`         //用户组任务分发列表
+	projectTaskRetrieve      xweb.Mapper `xweb:"/front/project/task/retrieve"`     //用户组任务收回
+	projectTaskRepulse       xweb.Mapper `xweb:"/front/project/task/repulse"`      //用户组任务打回
+	projectTaskClose         xweb.Mapper `xweb:"/front/project/task/close"`        //用户组任务关闭
+	projectGetEntnameList    xweb.Mapper `xweb:"/front/project/getEntnameList"`    //模糊查询公司名称
 
 	userTaskSave     xweb.Mapper `xweb:"/front/user/task/save"`     //用户任务分发
 	userTaskList     xweb.Mapper `xweb:"/front/user/task/list"`     //用户任务列表
 	userTaskRetrieve xweb.Mapper `xweb:"/front/user/task/retrieve"` //用户任务收回
+	userTaskClose    xweb.Mapper `xweb:"/front/user/task/close"`    //用户任务关闭
 
 	groupTaskListByAdmin xweb.Mapper `xweb:"/front/group/admin/task/list"` //用户组任务列表(系统管理员权限)
 	groupTaskListByGroup xweb.Mapper `xweb:"/front/group/task/list"`       //用户组任务列表(用户组权限)
 	groupTaskDeliver     xweb.Mapper `xweb:"/front/group/task/deliver"`    //用户组任务交付
+	groupTaskExport      xweb.Mapper `xweb:"/front/group/task/export"`     //用户组任务导出
 }
 
 func (f *Front) Index() {

+ 107 - 3
src/front/group.go

@@ -1,6 +1,9 @@
 package front
 
 import (
+	"fmt"
+	"github.com/tealeg/xlsx"
+	"os"
 	qu "qfw/util"
 	"strings"
 	"time"
@@ -28,7 +31,7 @@ func (f *Front) GroupTaskListByGroup() {
 				map[string]interface{}{"s_projectname": map[string]interface{}{"$regex": search}},
 			}
 		}
-		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, nil, nil, false, start, limit)
+		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, map[string]interface{}{"_id": -1}, nil, false, start, limit)
 		count := util.Mgo.Count(util.TASKCOLLNAME, query)
 		f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
 	} else {
@@ -55,13 +58,16 @@ func (f *Front) GroupTaskListByAdmin() {
 		if search != "" {
 			query["$or"] = []interface{}{
 				map[string]interface{}{"s_projectname": map[string]interface{}{"$regex": search}},
+				map[string]interface{}{"s_entname": map[string]interface{}{"$regex": search}},
+				map[string]interface{}{"s_rule": map[string]interface{}{"$regex": search}},
+				map[string]interface{}{"s_departname": map[string]interface{}{"$regex": search}},
 			}
 		}
 		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, nil, nil, false, start, limit)
 		count := util.Mgo.Count(util.TASKCOLLNAME, query)
 		f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
 	} else {
-		_ = f.Render("project/task_group_list.html")
+		_ = f.Render("project/task_list.html")
 	}
 }
 
@@ -69,7 +75,7 @@ func (f *Front) GroupTaskListByAdmin() {
 func (f *Front) GroupTaskDeliver() {
 	defer qu.Catch()
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"]) //当前登录用户
+	username := qu.ObjToString(user["s_login"]) //当前登录用户
 	success := true
 	msg := ""
 	taskId := f.GetString("taskid") //用户组任务id
@@ -110,3 +116,101 @@ func (f *Front) GroupTaskDeliver() {
 	}
 	f.ServeJson(map[string]interface{}{"success": success, "msg": msg})
 }
+
+var modelpath string = "web/model/任务详情%d.xlsx"
+
+// GroupTaskExport 用户组任务导出
+func (f *Front) GroupTaskExport() {
+	defer qu.Catch()
+	starttime, _ := f.GetInt("i_starttime")
+	completetime, _ := f.GetInt("i_completetime")
+	status := f.GetString("s_status")
+	searchStr := f.GetString("search[value]")
+	search := strings.TrimSpace(searchStr)
+	query := map[string]interface{}{
+		"s_stype": "group",
+	}
+	if status != "-1" { //任务状态
+		query["s_status"] = status
+	}
+	if search != "" {
+		query["$or"] = []interface{}{
+			map[string]interface{}{"s_entname": map[string]interface{}{"$regex": search}},
+		}
+	}
+	if starttime > 0 {
+		query["i_starttime"] = map[string]interface{}{
+			"$gte": starttime,
+		}
+	}
+	if completetime > 0 {
+		query["i_completetime"] = map[string]interface{}{
+			"$lte": completetime,
+		}
+	}
+	qu.Debug("Query:", query)
+	count := util.Mgo.Count(util.TASKCOLLNAME, query)
+	if count > 0 {
+		file, err := xlsx.OpenFile("taskexportmodel.xlsx")
+		if err != nil {
+			qu.Debug("Load Excel Model Error")
+			f.ServeJson("加载脚本失败")
+			return
+		}
+		sheet := file.Sheets[0]
+		fields := map[string]interface{}{
+			"s_entname":      1,
+			"s_departname":   1,
+			"s_rulename":     1,
+			"s_projectname":  1,
+			"s_groupname":    1,
+			"s_personname":   1,
+			"i_givenum":      1,
+			"i_starttime":    1,
+			"i_completetime": 1,
+		}
+		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, nil, fields, false, -1, -1)
+		for _, l := range *list {
+			row := sheet.AddRow()
+			entname := qu.ObjToString(l["s_entname"])
+			departname := qu.ObjToString(l["s_departname"])
+			rulename := qu.ObjToString(l["s_rulename"])
+			projectname := qu.ObjToString(l["s_projectname"])
+			groupname := qu.ObjToString(l["s_groupname"])
+			personname := qu.ObjToString(l["s_personname"])
+			givenum := qu.IntAll(l["i_givenum"])
+			starttimestr := ""
+			if starttime := qu.Int64All(l["i_starttime"]); starttime != 0 {
+				starttimestr = qu.FormatDateByInt64(&starttime, qu.Date_Full_Layout)
+			}
+			completetimestr := ""
+			if completetime := qu.Int64All(l["i_completetime"]); completetime != 0 {
+				completetimestr = qu.FormatDateByInt64(&completetime, qu.Date_Full_Layout)
+			}
+			row.AddCell().SetValue(entname)
+			row.AddCell().SetValue(departname)
+			row.AddCell().SetValue(rulename)
+			row.AddCell().SetValue(projectname)
+			row.AddCell().SetValue(groupname)
+			row.AddCell().SetValue(personname)
+			row.AddCell().SetValue(givenum)
+			row.AddCell().SetValue(starttimestr)
+			row.AddCell().SetValue(completetimestr)
+		}
+		fname := fmt.Sprintf(modelpath, time.Now().Unix())
+		qu.Debug("File Name:", fname)
+		err = file.Save(fname)
+		if err != nil {
+			qu.Debug("Save Excel" + fname + "Error")
+			f.ServeJson("导出失败")
+			return
+		}
+		f.ServeFile(fname)
+		go func(path string) {
+			time.Sleep(time.Minute * 10)
+			os.Remove(path)
+		}(fname)
+	} else {
+		f.ServeJson("没有数据")
+	}
+}

+ 328 - 255
src/front/project.go

@@ -6,11 +6,11 @@ import (
 	"github.com/tealeg/xlsx"
 	"go.mongodb.org/mongo-driver/bson/primitive"
 	"io/ioutil"
-	"math"
 	"mime/multipart"
 	"mongodb"
 	qu "qfw/util"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -66,7 +66,7 @@ func (f *Front) ProjectSave() {
 	importDataNum := 0      //查询数量
 	var s_rulename []string //规则
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])     //当前登录用户
+	username := qu.ObjToString(user["s_login"])    //当前登录用户
 	stype := f.GetString("s_type")                 //新建项目类型:数据库导入、excel导入
 	s_sourceinfoTmp := f.GetString("s_sourceinfo") //数据表
 	s_sourceinfo := "f_sourceinfo_" + s_sourceinfoTmp
@@ -98,17 +98,17 @@ func (f *Front) ProjectSave() {
 		}
 		//保存项目信息
 		set = map[string]interface{}{
-			"s_name":           s_name,                                //项目名称
-			"s_entname":        s_entname,                             //公司名称
-			"s_departname":     s_departname,                          //部门名称
-			"s_rulename":       strings.Join(s_rulename, ","),         //规则名称
-			"i_importnum":      importDataNum,                         //导入数量
-			"s_sourceinfo":     s_sourceinfo,                          //源数据表
-			"s_sourcetaskinfo": "s_sourcetaskinfo_" + s_sourceinfoTmp, //源数据表
-			"s_createname":     username,                              //创建人
-			"s_status":         "未开始",                                 //项目状态
-			"i_createtime":     time.Now().Unix(),                     //创建时间
-			"s_importtype":     "excel",                               //导入类型
+			"s_name":         s_name,                        //项目名称
+			"s_entname":      s_entname,                     //公司名称
+			"s_departname":   s_departname,                  //部门名称
+			"s_rulename":     strings.Join(s_rulename, ","), //规则名称
+			"i_importnum":    importDataNum,                 //导入数量
+			"s_sourceinfo":   s_sourceinfo,                  //源数据表
+			"s_createname":   username,                      //创建人
+			"s_status":       "未开始",                         //项目状态
+			"i_createtime":   time.Now().Unix(),             //创建时间
+			"s_importtype":   "excel",                       //导入类型
+			"b_isassessment": false,                         //是否进行了质量评估
 		}
 	} else if stype == "coll" { //数据库导入
 		historyid := f.GetString("s_historyid")
@@ -120,17 +120,18 @@ func (f *Front) ProjectSave() {
 		qu.Debug(s_departname, s_entname, s_rulename, importDataNum)
 		//保存项目信息
 		set = map[string]interface{}{
-			"s_name":       s_name,                        //项目名称
-			"s_entname":    s_entname,                     //公司名称
-			"s_departname": s_departname,                  //部门名称
-			"s_rulename":   strings.Join(s_rulename, ","), //规则名称
-			"i_importnum":  importDataNum,                 //导入数量
-			"s_sourceinfo": s_sourceinfo,                  //源数据表
-			"s_createname": username,                      //创建人
-			"s_status":     "未开始",                         //项目状态
-			"i_createtime": time.Now().Unix(),             //创建时间
-			"s_importtype": "coll",                        //导入类型
-			"s_historyid":  historyid,                     //源数据集标识
+			"s_name":         s_name,                        //项目名称
+			"s_entname":      s_entname,                     //公司名称
+			"s_departname":   s_departname,                  //部门名称
+			"s_rulename":     strings.Join(s_rulename, ","), //规则名称
+			"i_importnum":    importDataNum,                 //导入数量
+			"s_sourceinfo":   s_sourceinfo,                  //源数据表
+			"s_createname":   username,                      //创建人
+			"s_status":       "未开始",                         //项目状态
+			"i_createtime":   time.Now().Unix(),             //创建时间
+			"s_importtype":   "coll",                        //导入类型
+			"s_historyid":    historyid,                     //源数据集标识
+			"b_isassessment": false,                         //是否进行了质量评估
 		}
 	} else if stype == "edit" { //编辑保存
 		success = true
@@ -143,7 +144,7 @@ func (f *Front) ProjectSave() {
 		v_fields := map[string]interface{}{}
 		if err := json.Unmarshal([]byte(fields), &v_fields); err != nil {
 			qu.Debug("V_Filelds Unmarshal Failed:", err)
-			f.ServeJson(map[string]interface{}{"success": false})
+			f.ServeJson(map[string]interface{}{"success": false, "msg": err})
 			return
 		}
 		set = map[string]interface{}{
@@ -165,7 +166,7 @@ func (f *Front) ProjectSave() {
 		if !success { //保存项目失败
 			msg = "新建项目失败\n" + msg
 		} else {
-			msg = "新建项目成功\n" + msg
+			msg = "保存项目成功"
 		}
 	}
 	qu.Debug("Create Project:", success, "importnum:", importDataNum, "successnum:", successNum, "failnum:", int64(importDataNum)-successNum)
@@ -178,6 +179,45 @@ func (f *Front) ProjectSave() {
 	}
 }
 
+// ProjectQualityAssessment 数据质量评估
+func (f *Front) ProjectQualityAssessment() {
+	defer qu.Catch()
+	msg := ""
+	success := false
+	//质量评估
+	projectid := f.GetString("pid") //项目id
+	qu.Debug("Project Id:", projectid)
+	project, _ := util.Mgo.FindById(util.PROJECTCOLLNAME, projectid, map[string]interface{}{"b_isassessment": 1, "s_sourceinfo": 1, "v_fields": 1})
+	if project != nil && len(*project) > 0 {
+		if isAssessment, ok := (*project)["b_isassessment"].(bool); ok && !isAssessment {
+			if fields, ok := (*project)["v_fields"].(map[string]interface{}); ok && len(fields) > 0 {
+				var fieldsArr []string
+				for f, _ := range fields {
+					fieldsArr = append(fieldsArr, f)
+				}
+				sourceinfo := qu.ObjToString((*project)["s_sourceinfo"])
+				success = QuaFieldScore(fieldsArr, sourceinfo) //调用数据质量评估接口
+				if success {
+					//点击清洗更新项目状态为进行中
+					b := util.Mgo.UpdateById(util.PROJECTCOLLNAME, projectid, map[string]interface{}{"$set": map[string]interface{}{"b_isassessment": true, "s_status": "进行中", "i_starttime": time.Now().Unix()}})
+					qu.Debug("Update Porject:"+projectid+"	Status Success:", b)
+				} else {
+					msg = "质量评估失败"
+				}
+			} else {
+				msg = "项目标注字段查询失败"
+			}
+		} else if ok && isAssessment {
+			success = true
+		} else {
+			msg = "查询项目失败"
+		}
+	} else {
+		msg = "查询项目失败"
+	}
+	f.ServeJson(map[string]interface{}{"success": success, "msg": msg})
+}
+
 // ProjectTaskList 用户组任务分发列表
 func (f *Front) ProjectTaskList() {
 	defer qu.Catch()
@@ -202,15 +242,20 @@ func (f *Front) ProjectTaskList() {
 				map[string]interface{}{"s_groupname": map[string]interface{}{"$regex": search}},
 			}
 		}
-		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, nil, nil, false, start, limit)
+		qu.Debug("Query:", query)
+		list, _ := util.Mgo.Find(util.TASKCOLLNAME, query, map[string]interface{}{"_id": -1}, nil, false, start, limit)
 		count := util.Mgo.Count(util.TASKCOLLNAME, query)
 		for _, l := range *list {
 			if status := qu.ObjToString(l["s_status"]); status == "进行中" { //更新任务进度
-				groupId := qu.ObjToString(l["s_groupid"])
+				//groupId := qu.ObjToString(l["s_groupid"])
+				groupTaskId := mongodb.BsonIdToSId(l["_id"])
 				giveNum := qu.IntAll(l["i_givenum"])
 				sourceinfo := qu.ObjToString(l["s_sourceinfo"])
-				tagNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"s_groupid": groupId, "b_istag": true})
-				progress := fmt.Sprint(math.Ceil(float64(tagNum)/float64(giveNum))) + "%"
+				//tagNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_isgivegroup": true, "s_grouptaskid": groupTaskId, "b_istag": true})
+				tagNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_istag": true})
+				progressFloat := float64(tagNum) / float64(giveNum)
+				value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", progressFloat), 64)
+				progress := fmt.Sprint(value*100) + "%"
 				l["s_progress"] = progress
 				//同步数据库
 				util.Mgo.UpdateById(util.TASKCOLLNAME, l["_id"], map[string]interface{}{"$set": map[string]interface{}{"s_progress": progress}})
@@ -218,51 +263,46 @@ func (f *Front) ProjectTaskList() {
 		}
 		f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
 	} else {
-		project, _ := util.Mgo.FindById(util.PROJECTCOLLNAME, projectid, map[string]interface{}{"s_status": 1, "s_sourceinfo": 1})
+		project, _ := util.Mgo.FindById(util.PROJECTCOLLNAME, projectid, map[string]interface{}{"s_sourceinfo": 1})
 		if project != nil && len(*project) > 0 {
-			if status := qu.ObjToString((*project)["s_status"]); status == "未开始" {
-				//TODO:调用数据质量评估接口
-				//点击清洗更新项目状态为进行中
-				b := util.Mgo.UpdateById(util.PROJECTCOLLNAME, projectid, map[string]interface{}{"$set": map[string]interface{}{"s_status": "进行中", "i_starttime": time.Now().Unix()}})
-				qu.Debug("Update Porject:"+projectid+"	Status Success:", b)
-			}
-		}
-		sourceinfo := qu.ObjToString((*project)["s_sourceinfo"]) //数据源表
-		qu.Debug(sourceinfo)
-		okAllDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false})                           //达标数据总量
-		okIsGiveDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false, "b_isgivegroup": true}) //达标数据已分发量
-		okNotGiveDataNum := okAllDataNum - okIsGiveDataNum                                                                 //达标待分发量
-		okIsTagDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false, "b_istag": true})        //达标已标注量
+			sourceinfo := qu.ObjToString((*project)["s_sourceinfo"])                                                           //数据源表
+			okAllDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false})                           //达标数据总量
+			okIsGiveDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false, "b_isgivegroup": true}) //达标数据已分发量
+			okNotGiveDataNum := okAllDataNum - okIsGiveDataNum                                                                 //达标待分发量
+			okIsTagDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": false, "b_istag": true})        //达标已标注量
 
-		IsNoOkAllDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true})                           //未达标数据总量
-		IsNoOkIsGiveDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true, "b_isgivegroup": true}) //未达标数据已分发量
-		IsNotOkNotGiveDataNum := IsNoOkAllDataNum - IsNoOkIsGiveDataNum                                                       //未达标待分发量
-		IsNotOkIsTagDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true, "b_istag": true})       //未达标已标注量
+			IsNoOkAllDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true})                           //未达标数据总量
+			IsNoOkIsGiveDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true, "b_isgivegroup": true}) //未达标数据已分发量
+			IsNotOkNotGiveDataNum := IsNoOkAllDataNum - IsNoOkIsGiveDataNum                                                       //未达标待分发量
+			IsNotOkIsTagDataNum := util.Mgo.Count(sourceinfo, map[string]interface{}{"b_istagging": true, "b_istag": true})       //未达标已标注量
 
-		allGiveDataNum := okIsGiveDataNum + IsNoOkIsGiveDataNum      //总分发量
-		allNoGiveDataNum := okNotGiveDataNum + IsNotOkNotGiveDataNum //总待分发量
-		allIsTagDataNum := okIsTagDataNum + IsNotOkIsTagDataNum      //已标注总量
-		allDataNum := allGiveDataNum + allNoGiveDataNum
-		qu.Debug("数据总量:", allDataNum, "已分发总量:", allGiveDataNum, "待分发总量:", allNoGiveDataNum, "已标注总量:", allIsTagDataNum)
-		qu.Debug("达标量:", okAllDataNum, "达标已分发量:", okIsGiveDataNum, "达标待分发量:", okNotGiveDataNum, "达标已标注量:", okIsTagDataNum)
-		qu.Debug(" 未达标量:", IsNoOkAllDataNum, " 未达标已分发量:", IsNoOkIsGiveDataNum, " 未达标待分发量:", IsNotOkNotGiveDataNum, " 未达标已标注量:", IsNotOkIsTagDataNum)
-		f.T["s_projectid"] = projectid
-		f.T["s_sourceinfo"] = sourceinfo
-		f.T["allDataNum"] = allDataNum
-		f.T["okAllDataNum"] = okAllDataNum
-		f.T["okIsGiveDataNum"] = okIsGiveDataNum
-		f.T["okNotGiveDataNum"] = okNotGiveDataNum
-		f.T["IsNoOkAllDataNum"] = IsNoOkAllDataNum
-		f.T["IsNoOkIsGiveDataNum"] = IsNoOkIsGiveDataNum
-		f.T["IsNotOkNotGiveDataNum"] = IsNotOkNotGiveDataNum
-		f.T["allGiveDataNum"] = allGiveDataNum
-		f.T["allNoGiveDataNum"] = allNoGiveDataNum
-		f.T["allIsTagDataNum"] = allIsTagDataNum
-		f.T["okIsTagDataNum"] = okIsTagDataNum
-		f.T["IsNotOkIsTagDataNum"] = IsNotOkIsTagDataNum
-		_ = f.Render("project/project_clear.html", &f.T)
+			allGiveDataNum := okIsGiveDataNum + IsNoOkIsGiveDataNum      //总分发量
+			allNoGiveDataNum := okNotGiveDataNum + IsNotOkNotGiveDataNum //总待分发量
+			allIsTagDataNum := okIsTagDataNum + IsNotOkIsTagDataNum      //已标注总量
+			allDataNum := allGiveDataNum + allNoGiveDataNum
+			//qu.Debug("数据总量:", allDataNum, "已分发总量:", allGiveDataNum, "待分发总量:", allNoGiveDataNum, "已标注总量:", allIsTagDataNum)
+			//qu.Debug("达标量:", okAllDataNum, "达标已分发量:", okIsGiveDataNum, "达标待分发量:", okNotGiveDataNum, "达标已标注量:", okIsTagDataNum)
+			//qu.Debug(" 未达标量:", IsNoOkAllDataNum, " 未达标已分发量:", IsNoOkIsGiveDataNum, " 未达标待分发量:", IsNotOkNotGiveDataNum, " 未达标已标注量:", IsNotOkIsTagDataNum)
+			f.T["s_projectid"] = projectid
+			f.T["s_sourceinfo"] = sourceinfo
+			f.T["allDataNum"] = allDataNum
+			f.T["okAllDataNum"] = okAllDataNum
+			f.T["okIsGiveDataNum"] = okIsGiveDataNum
+			f.T["okNotGiveDataNum"] = okNotGiveDataNum
+			f.T["IsNoOkAllDataNum"] = IsNoOkAllDataNum
+			f.T["IsNoOkIsGiveDataNum"] = IsNoOkIsGiveDataNum
+			f.T["IsNotOkNotGiveDataNum"] = IsNotOkNotGiveDataNum
+			f.T["allGiveDataNum"] = allGiveDataNum
+			f.T["allNoGiveDataNum"] = allNoGiveDataNum
+			f.T["allIsTagDataNum"] = allIsTagDataNum
+			f.T["okIsTagDataNum"] = okIsTagDataNum
+			f.T["IsNotOkIsTagDataNum"] = IsNotOkIsTagDataNum
+			_ = f.Render("project/project_clear.html", &f.T)
+		} else {
+			qu.Debug("Project Find Error")
+			f.ServeJson("查询项目失败")
+		}
 	}
-
 }
 
 // ProjectTaskSave 用户组任务分发
@@ -276,22 +316,21 @@ func (f *Front) ProjectTaskSave() {
 	success := false
 	msg := ""
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"]) //当前登录用户
-	projectid := f.GetString("s_projectid")    //项目标识
+	username := qu.ObjToString(user["s_login"]) //当前登录用户
+	projectid := f.GetString("s_projectid")     //项目标识
 	project, _ := util.Mgo.FindById(util.PROJECTCOLLNAME, projectid, nil)
-	projectname := qu.ObjToString((*project)["s_projectname"])       //项目名称
-	sourceinfo := qu.ObjToString((*project)["s_sourceinfo"])         //源数据表
-	sourcetaskinfo := qu.ObjToString((*project)["s_sourcetaskinfo"]) //任务日志表
+	projectname := qu.ObjToString((*project)["s_name"])      //项目名称
+	sourceinfo := qu.ObjToString((*project)["s_sourceinfo"]) //源数据表
 	group := f.GetString("s_group")
 	qu.Debug(group)
 	stype := f.GetString("s_type")
-	qu.Debug("项目id:", projectid, " 项目名称:", projectname, "sourcetaskinfo:", sourcetaskinfo)
+	qu.Debug("项目id:", projectid, " 项目名称:", projectname)
 	if err := json.Unmarshal([]byte(group), &groupArr); err != nil {
 		qu.Debug("GroupInfo Unmarshal Failed:", err)
 		msg = "用户组信息解析失败"
 	} else {
-		qu.Debug("用户组信息:", groupArr)
-		if stype == "notag" { //如果分发的是达标数据且进行了初步质检,将没有质检记录的字段从v_taginfo标注记录中删除
+		qu.Debug("用户组信息:", groupArr, stype)
+		if stype != "tag" { //如果分发的是达标数据或者全部数据且进行了初步质检,将没有质检记录的字段从v_taginfo标注记录中删除
 			DeleleDataTagInfo(sourceinfo)
 		}
 		for _, groupInfo := range groupArr {
@@ -307,24 +346,23 @@ func (f *Front) ProjectTaskSave() {
 			}
 			groupIdTask[groupTaskIdStr] = gt
 			groupTask := map[string]interface{}{
-				"_id":              groupTaskId,                                //生成任务id
-				"s_projectid":      projectid,                                  //项目标识
-				"s_projectname":    projectname,                                //项目名称
-				"s_status":         "未开始",                                      //任务状态
-				"s_personid":       qu.ObjToString(groupInfo["s_personid"]),    //任务负责人标识
-				"s_personname":     qu.ObjToString(groupInfo["s_personname"]),  //任务负责人
-				"s_groupname":      qu.ObjToString(groupInfo["s_groupname"]),   //用户组名称
-				"s_groupid":        groupId,                                    //用户组标识
-				"i_givenum":        givenum,                                    //分发数据量
-				"s_createname":     username,                                   //创建人
-				"i_createtime":     time.Now().Unix(),                          //创建时间
-				"s_progress":       "0%",                                       //完成进度
-				"s_sourceinfo":     sourceinfo,                                 //源数据表
-				"s_sourcetaskinfo": sourcetaskinfo,                             //任务日志表
-				"s_stype":          "group",                                    //任务类型
-				"s_entname":        qu.ObjToString((*project)["s_entname"]),    //公司名称
-				"s_departname":     qu.ObjToString((*project)["s_departname"]), //部门名称
-				"s_rulename":       qu.ObjToString((*project)["s_rulename"]),   //规则名称
+				"_id":           groupTaskId,                                //生成任务id
+				"s_projectid":   projectid,                                  //项目标识
+				"s_projectname": projectname,                                //项目名称
+				"s_status":      "未开始",                                      //任务状态
+				"s_personid":    qu.ObjToString(groupInfo["s_personid"]),    //任务负责人标识
+				"s_personname":  qu.ObjToString(groupInfo["s_personname"]),  //任务负责人
+				"s_groupname":   qu.ObjToString(groupInfo["s_groupname"]),   //用户组名称
+				"s_groupid":     groupId,                                    //用户组标识
+				"i_givenum":     givenum,                                    //分发数据量
+				"s_createname":  username,                                   //创建人
+				"i_createtime":  time.Now().Unix(),                          //创建时间
+				"s_progress":    "0%",                                       //完成进度
+				"s_sourceinfo":  sourceinfo,                                 //源数据表
+				"s_stype":       "group",                                    //任务类型
+				"s_entname":     qu.ObjToString((*project)["s_entname"]),    //公司名称
+				"s_departname":  qu.ObjToString((*project)["s_departname"]), //部门名称
+				"s_rulename":    qu.ObjToString((*project)["s_rulename"]),   //规则名称
 			}
 			taskArr = append(taskArr, groupTask)
 		}
@@ -347,7 +385,9 @@ func (f *Front) ProjectTaskSave() {
 			success = util.Mgo.SaveBulk(util.TASKCOLLNAME, taskArr...)
 			if success {
 				msg = "任务分发成功"
-				UpdateSourceinfo(sourceinfo, sourcetaskinfo, stype, groupIdTask) //用户组分发任务成功后,给数据源打上用户组标识,同时生成任务临时表
+				UpdateSourceinfo(sourceinfo, stype, groupIdTask) //用户组分发任务成功后,给数据源打上用户组标识,同时生成任务临时表
+			} else {
+				msg = "任务分发失败"
 			}
 		}
 	}
@@ -366,10 +406,15 @@ func (f *Front) ProjectGetEntnameList() {
 		},
 	}
 	list, _ := util.MgoJy.Find(util.JyUser, query, nil, map[string]interface{}{"username": 1}, false, -1, -1)
-	for _, l := range *list {
-		entnameList = append(entnameList, qu.ObjToString(l["username"]))
+	if len(*list) > 0 {
+		for _, l := range *list {
+			entnameList = append(entnameList, qu.ObjToString(l["username"]))
+		}
+		f.ServeJson(map[string]interface{}{"entname": entnameList})
+	} else {
+		f.ServeJson(map[string]interface{}{"entname": []string{}})
 	}
-	f.ServeJson(map[string]interface{}{"entname": entnameList})
+
 }
 
 // ProjectTaskRepulse 用户组任务打回
@@ -379,153 +424,195 @@ func (f *Front) ProjectTaskRepulse() {
 	success := false
 	msg := ""
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])
-	status := f.GetString("s_status")
-	taskId := f.GetString("id")
-	groupId := f.GetString("s_groupid")
+	username := qu.ObjToString(user["s_login"])
+	//status := f.GetString("s_status")
+	groupTaskId := f.GetString("taskid")
 	sourceinfo := f.GetString("s_sourceinfo")
-	sourcetaskinfo := f.GetString("s_sourcetaskinfo")
-	if status == "已完成" {
-		//更新数据状态
-		//1、更新源数据表
-		success1 := util.Mgo.Update(sourceinfo, map[string]interface{}{"s_groupid": groupId}, map[string]interface{}{
+	//更新数据源
+	success = util.Mgo.Update(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId}, map[string]interface{}{
+		"$set": map[string]interface{}{
+			"b_istag":      false,
+			"b_isgiveuser": false,
+			"i_updatetime": time.Now().Unix(),
+		},
+		"$unset": map[string]interface{}{
+			"s_userid":     "",
+			"s_usertaskid": "",
+		},
+	}, false, true)
+	if success {
+		//更新用户组任务 清除最迟完成时间,更新任务状态
+		success = util.Mgo.UpdateById(util.TASKCOLLNAME, groupTaskId, map[string]interface{}{
 			"$set": map[string]interface{}{
-				"b_istag":      false,
-				"i_updatetime": time.Now().Unix(),
+				"s_status":       "未开始",
+				"s_updateperson": username,
+				"i_updatetime":   time.Now().Unix(),
+				"s_progress":     "0%",
 			},
 			"$unset": map[string]interface{}{
-				"s_userid": "",
+				"i_completetime": "",
 			},
-		}, false, true)
-		//2、删除临时任务表中对应数据
-		success2 := util.Mgo.Del(sourcetaskinfo, map[string]interface{}{"s_groupid": groupId})
-		if success1 && success2 {
-			//清除最迟完成时间,更新任务状态
-			success = util.Mgo.UpdateById(util.TASKCOLLNAME, taskId, map[string]interface{}{
-				"$set": map[string]interface{}{
-					"s_status":       "未开始",
-					"s_updateperson": username,
-					"i_updatetime":   time.Now().Unix(),
-					"s_progress":     "0%",
-				},
-				"$unset": map[string]interface{}{
-					"i_completetime": "",
-				},
-			})
-			if !success {
-				msg += "更新任务:" + taskId + "失败"
-			}
-		} else {
-			qu.Debug("Update "+sourceinfo+":", success1, "	Delete "+sourcetaskinfo+":", success2)
-			if !success1 {
-				msg += "更新" + sourceinfo + "数据失败;"
-			}
-			if !success2 {
-				msg += "删除" + sourcetaskinfo + "数据失败;"
-			}
+		})
+		if !success {
+			msg = "更新用户组任务失败"
 		}
+	} else {
+		msg = "更新数据源信息失败"
 	}
 	qu.Debug("Task Repulse:", success, "	Msg:", msg)
 	f.ServeJson(map[string]interface{}{"success": success, "msg": msg})
 }
 
 // ProjectTaskRetrieve 用户组任务收回
-// TODO 关联用户组下所有用户任务的收回
 func (f *Front) ProjectTaskRetrieve() {
 	defer qu.Catch()
-	success := false
-	msg := ""
-	num := 0
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])
-	status := f.GetString("s_status")
-	taskId := f.GetString("id")
-	groupId := f.GetString("s_groupid")
-	sourceinfo := f.GetString("s_sourceinfo")
-	sourcetaskinfo := f.GetString("s_sourcetaskinfo")
-	if status == "已完成" {
-		count1 := util.Mgo.Count(sourceinfo, map[string]interface{}{"s_groupid": groupId, "b_istag": false})
-		count2 := util.Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_groupid": groupId, "b_iscomplete": false})
-		if count1 != count2 { //数据源表和临时表数量不一致
-			qu.Debug("Count Is Not Same:", sourceinfo+":", count1, sourceinfo+":", count2)
-		}
-		num = count1
-		if count1 == 0 { //收回数据量为0
-			success = true
-			//更新任务状态、完成时间
-			success = util.Mgo.UpdateById(util.TASKCOLLNAME, taskId, map[string]interface{}{
-				"$set": map[string]interface{}{
-					"s_status":       "已完成",
-					"s_updateperson": username,
-					"i_updatetime":   time.Now().Unix(),
-					"i_completetime": time.Now().Unix(),
-					"s_progress":     "100%",
-				},
-			})
-			if !success {
-				msg += "更新任务:" + taskId + "失败"
-			}
-		} else {
-			//1、更新源数据表
-			success1 := util.Mgo.Update(sourceinfo, map[string]interface{}{"s_groupid": groupId, "b_istag": false}, map[string]interface{}{
-				"$set": map[string]interface{}{
-					"b_isgivegroup": false,
-					"i_updatetime":  time.Now().Unix(),
-				},
-				"$unset": map[string]interface{}{
-					"s_groupid": "",
-				},
-			}, false, true)
-			//2、删除临时任务表中对应未完成数据
-			success2 := util.Mgo.Del(sourcetaskinfo, map[string]interface{}{"s_groupid": groupId, "b_iscomplete": false})
-			if success1 && success2 {
-				//更新任务状态、完成时间
-				success = util.Mgo.UpdateById(util.TASKCOLLNAME, taskId, map[string]interface{}{
-					"$set": map[string]interface{}{
-						"s_status":       "已完成",
-						"s_updateperson": username,
-						"i_updatetime":   time.Now().Unix(),
-						"i_completetime": time.Now().Unix(),
-					},
-				})
-				if !success {
-					msg += "更新任务:" + taskId + "失败"
-				}
-			} else {
-				qu.Debug("Update "+sourceinfo+":", success1, "	Delete "+sourcetaskinfo+":", success2)
-				if !success1 {
-					msg += "更新" + sourceinfo + "数据失败;"
+	username := qu.ObjToString(user["s_login"])
+	groupTaskId := f.GetString("taskid")
+	sourceInfo := f.GetString("s_sourceinfo")
+	status := f.GetString("s_status") //未开始、进行中
+	//giveNum, _ := f.GetInteger("i_givenum") //收回时要更新的分发数据量
+	msg := ""
+	success := false
+	count := 0
+	if status == "未开始" { //未开始的用户组任务,暂未给用户分发任务
+		success = true
+	} else { //进行中的用户组任务需更新其下用户信息
+		groupTask, _ := util.Mgo.FindById(util.TASKCOLLNAME, groupTaskId, map[string]interface{}{"v_sonids": 1})
+		if groupTask != nil && len(*groupTask) > 0 {
+			if sonIds, ok := (*groupTask)["v_sonids"].([]interface{}); ok && len(sonIds) > 0 { //更新所有用户任务信息
+				userTaskIdStatus := map[string]string{} //封装要回收的用户任务信息
+				for _, sId := range sonIds {
+					userTaskId := qu.ObjToString(sId)
+					userTask, _ := util.Mgo.FindById(util.TASKCOLLNAME, userTaskId, map[string]interface{}{"s_status": 1})
+					if userTask != nil && len(*userTask) > 0 {
+						if statusTmp := qu.ObjToString((*userTask)["s_status"]); statusTmp != "已完成" && statusTmp != "已关闭" { //已完成和已关闭的任务不收回
+							userTaskIdStatus[userTaskId] = statusTmp
+						}
+					} else {
+						qu.Debug("Find User Task:", userTaskId, "Error")
+					}
 				}
-				if !success2 {
-					msg += "删除" + sourcetaskinfo + "数据失败;"
+				qu.Debug("userTaskIdStatus:", len(userTaskIdStatus))
+				if len(userTaskIdStatus) > 0 { //收回用户组下所有用户信息
+					//用户组收回时,若已有用户任务在未开始时收回或关闭,调用RetrieveTaskByUser返回的总收回量count就遗漏了用户收回或关闭任务的量
+					msg, _, success = RetrieveCloseTaskByUser(sourceInfo, username, userTaskIdStatus) //用户信息收回
+				} else { //用户组下所有用户任务都已完成
+					success = true
 				}
+			} else { //没有分配给用户任务
+				success = true
 			}
+		} else {
+			msg = "用户组任务查找失败"
 		}
 	}
-	qu.Debug("Task Retrieve:", success, "	num:", num, "	Msg:", msg)
-	f.ServeJson(map[string]interface{}{"success": success, "msg": msg, "num": num})
+	if success { //所有用户信息收回成功后,更新用户组任务相关信息
+		count = util.Mgo.Count(sourceInfo, map[string]interface{}{ //统计该用户组任务下未标注的数据量
+			"s_grouptaskid": groupTaskId,
+			"b_istag":       false,
+		})
+		UpdateGroupTaskAndSourceInfo(groupTaskId, sourceInfo, username, status, count, &msg, &success)
+	}
+	qu.Debug(success, count, msg)
+	f.ServeJson(map[string]interface{}{"success": success, "msg": msg, "count": count})
 }
 
 // ProjectTaskClose 用户组任务关闭
 func (f *Front) ProjectTaskClose() {
 	defer qu.Catch()
-	success := false
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])
-	status := f.GetString("s_status")
-	taskId := f.GetString("id")
-	if status == "已完成" {
-		//更新任务状态
-		success = util.Mgo.UpdateById(util.TASKCOLLNAME, taskId, map[string]interface{}{
-			"$set": map[string]interface{}{
-				"s_status":       "已关闭",
-				"s_updateperson": username,
-				"i_updatetime":   time.Now().Unix(),
-				"s_progress":     "100%",
-			},
+	username := qu.ObjToString(user["s_login"])
+	groupTaskId := f.GetString("taskid")
+	sourceInfo := f.GetString("s_sourceinfo")
+	status := f.GetString("s_status") //未开始、进行中
+	msg := ""
+	success := false
+	count := 0
+	if status == "未开始" { //未开始的用户组任务,暂未给用户分发任务;已完成只更新用户组任务
+		success = true
+	} else { //进行中的用户组任务需更新其下用户信息
+		//groupTask, _ := util.Mgo.FindById(util.TASKCOLLNAME, groupTaskId, map[string]interface{}{"v_sonids": 1})
+		//if groupTask != nil && len(*groupTask) > 0 {
+		//	if sonIds, ok := (*groupTask)["v_sonids"].([]interface{}); ok && len(sonIds) > 0 { //更新所有用户任务信息
+		//		userTaskIdStatus := map[string]string{} //封装要关闭的用户任务信息
+		//		for _, sId := range sonIds {
+		//			userTaskId := qu.ObjToString(sId)
+		//			userTask, _ := util.Mgo.FindById(util.TASKCOLLNAME, userTaskId, map[string]interface{}{"s_status": 1})
+		//			if userTask != nil && len(*userTask) > 0 {
+		//				if statusTmp := qu.ObjToString((*userTask)["s_status"]); statusTmp == "已完成" && statusTmp != "已关闭" { //已关闭的任务不更新
+		//					userTaskIdStatus[userTaskId] = statusTmp
+		//				}
+		//			} else {
+		//				qu.Debug("Find User Task:", userTaskId, "Error")
+		//			}
+		//		}
+		//		if len(userTaskIdStatus) > 0 { //关闭用户组下所有用户信息
+		//			msg, _, success = RetrieveCloseTaskByUser(sourceInfo, username, userTaskIdStatus) //用户信息收回
+		//		} else { //用户组下所有用户任务都已关闭
+		//			success = true
+		//		}
+		//	} else { //没有分配给用户任务
+		//		success = true
+		//	}
+		//} else {
+		//	msg = "用户组任务查找失败"
+		//}
+	}
+	if success { //所有用户信息关闭成功后,更新用户组任务相关信息
+		count = util.Mgo.Count(sourceInfo, map[string]interface{}{ //统计该用户组任务下未标注的数据量
+			"s_grouptaskid": groupTaskId,
+			"b_istag":       false,
 		})
+		UpdateGroupTaskAndSourceInfo(groupTaskId, sourceInfo, username, status, count, &msg, &success)
+	}
+	qu.Debug(success, count, msg)
+	f.ServeJson(map[string]interface{}{"success": success, "msg": msg, "count": count})
+}
+
+// UpdateGroupTaskAndSourceInfo 更新用户组任务相关信息
+func UpdateGroupTaskAndSourceInfo(groupTaskId, sourceInfo, username, status string, count int, msg *string, success *bool) {
+	defer qu.Catch()
+	qu.Debug("GroupTaskStatus:", status, "	Count:", count)
+	if count != 0 { //更新数据源
+		query := map[string]interface{}{
+			"s_grouptaskid": groupTaskId,
+			"b_istag":       false,
+		}
+		set := map[string]interface{}{
+			"b_isgivegroup": false,
+			"i_updatetime":  time.Now().Unix(),
+		}
+		unset := map[string]interface{}{
+			"s_groupid":     "",
+			"s_grouptaskid": "",
+		}
+		*success = util.Mgo.Update(sourceInfo, query, map[string]interface{}{"$set": set, "$unset": unset}, false, true)
+	}
+	//更新用户组任务
+	if *success {
+		taskSet := map[string]interface{}{
+			"s_status":       "已完成",
+			"s_updateperson": username,
+			"i_updatetime":   time.Now().Unix(),
+			"i_completetime": time.Now().Unix(),
+			"s_progress":     "100%",
+		}
+
+		if status == "未开始" {
+			taskSet["i_starttime"] = time.Now().Unix()
+			taskSet["s_status"] = "已关闭"
+		}
+		inc := map[string]interface{}{
+			"i_givenum": -count,
+		}
+		*success = util.Mgo.UpdateById(util.TASKCOLLNAME, groupTaskId, map[string]interface{}{"$set": taskSet, "$inc": inc})
+		if !*success {
+			*msg = "更新用户组任务失败"
+		}
+	} else {
+		*msg = "更新数据源信息失败"
 	}
-	f.ServeJson(map[string]interface{}{"success": success})
 }
 
 // DeleleDataTagInfo 删除标注记录
@@ -561,19 +648,24 @@ func DeleleDataTagInfo(sourceinfo string) {
 			update = append(update, map[string]interface{}{"_id": tmp["_id"]})
 			tagInfo, _ := tmp["v_taginfo"].(map[string]interface{})
 			checkInfo, _ := tmp["v_check"].(map[string]interface{})
-			if len(tagInfo) == 0 || len(checkInfo) == 0 {
-				return
+			id := mongodb.BsonIdToSId(tmp["_id"])
+			if id == "60b99c2d72c25c51c492af6a" {
+				qu.Debug(tagInfo, checkInfo)
+			}
+			set := map[string]interface{}{
+				"b_cleartag": true,
 			}
-			for f, _ := range tagInfo {
-				if checkInfo[f] == nil {
-					delete(tagInfo, f)
+			if len(tagInfo) != 0 && len(checkInfo) != 0 {
+				for f, _ := range tagInfo {
+					if checkInfo[f] == nil {
+						delete(tagInfo, f)
+					}
 				}
+				set["v_taginfo"] = tagInfo
 			}
+
 			update = append(update, map[string]interface{}{
-				"$set": map[string]interface{}{
-					"v_taginfo":  tagInfo,
-					"b_cleartag": true,
-				},
+				"$set": set,
 			})
 			lock.Lock()
 			updateArr = append(updateArr, update)
@@ -597,8 +689,8 @@ func DeleleDataTagInfo(sourceinfo string) {
 	lock.Unlock()
 }
 
-// UpdateSourceinfo 用户组分发任务成功后,给数据源打上用户组标识,同时生成任务临时表
-func UpdateSourceinfo(sourceinfo, sourcetaskinfo, stype string, groupIdInfo map[string]util.Task) {
+// UpdateSourceinfo 用户组分发任务成功后,给数据源打上用户组标识
+func UpdateSourceinfo(sourceinfo, stype string, groupIdInfo map[string]util.Task) {
 	defer qu.Catch()
 	for groupTaskId, tInfo := range groupIdInfo {
 		groupId := tInfo.UserId
@@ -617,9 +709,8 @@ func UpdateSourceinfo(sourceinfo, sourcetaskinfo, stype string, groupIdInfo map[
 			query["b_istagging"] = true
 		}
 		fields := map[string]interface{}{
-			"title": 1,
+			"v_baseinfo": 1,
 		}
-		saveArr := []map[string]interface{}{}
 		updateArr := [][]map[string]interface{}{}
 		qu.Debug("Query:", query)
 		it := sess.DB(util.Mgo.DbName).C(sourceinfo).Find(&query).Select(&fields).Limit(int64(num)).Iter()
@@ -632,37 +723,23 @@ func UpdateSourceinfo(sourceinfo, sourcetaskinfo, stype string, groupIdInfo map[
 					<-ch
 					wg.Done()
 				}()
-				id := mongodb.BsonIdToSId(tmp["_id"])
-				title := qu.ObjToString(tmp["title"])
 				update := []map[string]interface{}{}
 				update = append(update, map[string]interface{}{"_id": tmp["_id"]})
 				update = append(update, map[string]interface{}{
 					"$set": map[string]interface{}{
 						"s_groupid":     groupId,
+						"s_grouptaskid": groupTaskId,
 						"b_isgivegroup": true,
 						"i_updatetime":  time.Now().Unix(),
 					},
 				})
-				save := map[string]interface{}{
-					"s_infoid":      id,
-					"s_infotitle":   title,
-					"s_groupid":     groupId,
-					"i_createtime":  time.Now().Unix(),
-					"b_iscomplete":  false,
-					"s_grouptaskid": groupTaskId,
-					"b_isgiveuser":  false,
-				}
 				lock.Lock()
 				updateArr = append(updateArr, update)
-				saveArr = append(saveArr, save)
+				//saveArr = append(saveArr, save)
 				if len(updateArr) > 500 {
 					util.Mgo.UpdateBulk(sourceinfo, updateArr...)
 					updateArr = [][]map[string]interface{}{}
 				}
-				if len(saveArr) > 500 {
-					util.Mgo.SaveBulk(sourcetaskinfo, saveArr...)
-					saveArr = []map[string]interface{}{}
-				}
 				lock.Unlock()
 			}(tmp)
 			if n%100 == 0 {
@@ -676,10 +753,6 @@ func UpdateSourceinfo(sourceinfo, sourcetaskinfo, stype string, groupIdInfo map[
 			util.Mgo.UpdateBulk(sourceinfo, updateArr...)
 			updateArr = [][]map[string]interface{}{}
 		}
-		if len(saveArr) > 0 {
-			util.Mgo.SaveBulk(sourcetaskinfo, saveArr...)
-			saveArr = []map[string]interface{}{}
-		}
 		lock.Unlock()
 	}
 }
@@ -960,10 +1033,10 @@ func GetDataById(idsInfo map[string]map[string]interface{}, importType, s_source
 					baseInfoMap["v_taginfo"] = tagInfoMap
 				}
 				baseInfoMap["i_createtime"] = time.Now().Unix()
-				baseInfoMap["b_isgivegroup"] = false //是否分配
+				baseInfoMap["b_isgivegroup"] = false //是否分配给用户组
 				baseInfoMap["b_istag"] = false       //是否已标注
 				baseInfoMap["b_cleartag"] = false    //是否清理标注信息
-
+				baseInfoMap["b_isgiveuser"] = false  //是否分配给用户
 				if util.Mgo.SaveByOriID(s_sourceinfo, baseInfoMap) {
 					atomic.AddInt64(successNum, 1) //保存成功计数
 				} else {

+ 23 - 28
src/front/quality.go

@@ -8,20 +8,18 @@ import (
 	"time"
 	u "util"
 )
-
 func (f *Front) QuaScoreData() {
 	defer qu.Catch()
-	coll_name := f.GetString("coll_name")
-	field_tag := f.GetSlice("field_tag")
-	rep := QuaFieldScore(field_tag,coll_name)
-	f.ServeJson(map[string]interface{}{
-		"rep": rep,
-	})
-}
 
-
-func QuaFieldScore(field_tag []string,coll_name string) bool {
-	if coll_name=="" || len(field_tag)<=0 {
+	//coll_name := f.GetString("coll_name")
+	//field_tag := f.GetSlice("field_tag")
+	//rep := QuaFieldScore(field_tag,coll_name)
+	//f.ServeJson(map[string]interface{}{
+	//	"rep": rep,
+	//})
+}
+func QuaFieldScore(field_tag []string, coll_name string) bool {
+	if coll_name == "" || len(field_tag) <= 0 {
 		return false
 	}
 	//查询标注表-临时测试-指定表
@@ -35,7 +33,7 @@ func QuaFieldScore(field_tag []string,coll_name string) bool {
 		if total%1000 == 0 {
 			log.Println("当前数量:", total)
 		}
-		update_dict := calculateFieldScore(tmp,field_tag)
+		update_dict := calculateFieldScore(tmp, field_tag)
 		updateFieldScore = append(updateFieldScore, []map[string]interface{}{
 			map[string]interface{}{"_id": tmp["_id"]},
 			update_dict,
@@ -46,10 +44,10 @@ func QuaFieldScore(field_tag []string,coll_name string) bool {
 		}
 		tmp = make(map[string]interface{})
 	}
-	if len(updateFieldScore) >0 {
+	if len(updateFieldScore) > 0 {
 		u.Mgo.UpSertBulk(coll_name, updateFieldScore...)
 	}
-	log.Printf("处理耗时:%d秒~数量:%d个\n", int(time.Now().Unix())-start,total)
+	log.Printf("处理耗时:%d秒~数量:%d个\n", int(time.Now().Unix())-start, total)
 
 	if total <= 0 {
 		return false
@@ -58,14 +56,14 @@ func QuaFieldScore(field_tag []string,coll_name string) bool {
 }
 
 //计算字段分
-func calculateFieldScore(tmp map[string]interface{},field_tag []string) (map[string]interface{}) {
+func calculateFieldScore(tmp map[string]interface{}, field_tag []string) map[string]interface{} {
 	source := *qu.ObjToMap(tmp["field_source"])
 	f_s := qua.FieldSourceScore(source) //打初始分
-	update_dict := make(map[string]interface{},0)
-	buyer_s := qua.BuyerFieldScore(tmp,f_s["buyer"])
-	budget_s := qua.BudgetFieldScore(tmp,f_s["budget"])
-	projectname_s := qua.ProjectnameFieldScore(tmp,f_s["projectname"])
-	projectcode_s := qua.ProjectcodeFieldScore(tmp,f_s["projectcode"])
+	update_dict := make(map[string]interface{}, 0)
+	buyer_s := qua.BuyerFieldScore(tmp, f_s["buyer"])
+	budget_s := qua.BudgetFieldScore(tmp, f_s["budget"])
+	projectname_s := qua.ProjectnameFieldScore(tmp, f_s["projectname"])
+	projectcode_s := qua.ProjectcodeFieldScore(tmp, f_s["projectcode"])
 
 	update_dict["buyer"] = buyer_s
 	update_dict["budget"] = budget_s
@@ -73,18 +71,17 @@ func calculateFieldScore(tmp map[string]interface{},field_tag []string) (map[str
 	update_dict["projectcode"] = projectcode_s
 
 	subtype := qu.ObjToString(tmp["subtype"])
-	if subtype=="中标"||subtype=="成交"||subtype=="合同" {
-		s_winner_s := qua.WinnerFieldScore(tmp,f_s["s_winner"])
+	if subtype == "中标" || subtype == "成交" || subtype == "合同" {
+		s_winner_s := qua.WinnerFieldScore(tmp, f_s["s_winner"])
 		update_dict["s_winner"] = s_winner_s
-		bidamount_s := qua.BidamountFieldScore(tmp,f_s["bidamount"])
+		bidamount_s := qua.BidamountFieldScore(tmp, f_s["bidamount"])
 		update_dict["bidamount"] = bidamount_s
 	}
 
-
 	//综合比对是否正确 field_tag   - 指定字段
 	isUse ,v_taginfo:= true,make(map[string]interface{},0)
 	b_isfield_tag := make(map[string]interface{},0)
-	for _,key :=range field_tag{
+	for _, key := range field_tag {
 		v_taginfo[key] = int64(1)
 		value := *qu.ObjToMap(update_dict[key])
 		score := qu.Int64All(value["score"])
@@ -103,10 +100,8 @@ func calculateFieldScore(tmp map[string]interface{},field_tag []string) (map[str
 			b_isfield_tag[k] = false
 		}
 	}
-
 	b_istagging := !isUse
 
-
 	//计算标的物-有效状态
 	b_isprchasing := calculatePrchasinglist(tmp)
 
@@ -203,4 +198,4 @@ func isUseAllPurchasing(isListUserArr []bool) bool{
 
 	}
 	return isUse
-}
+}

+ 191 - 73
src/front/user.go

@@ -2,6 +2,7 @@ package front
 
 import (
 	"encoding/json"
+	"fmt"
 	"github.com/dchest/captcha"
 	"github.com/gorilla/sessions"
 	"go.mongodb.org/mongo-driver/bson"
@@ -61,12 +62,12 @@ func (f *Front) Login() {
 		if user != nil && len(*user) > 0 {
 			checked = true
 			f.SetSession("user", map[string]interface{}{
-				//"s_groupid": (*user)["s_groupid"],
-				"s_name":  (*user)["s_name"],
-				"i_role":  (*user)["i_role"],
-				"s_pwd":   password,
-				"s_login": username,
-				"id":      mgo.BsonIdToSId((*user)["_id"]),
+				"s_groupid": (*user)["s_groupid"],
+				"s_name":    (*user)["s_name"],
+				"i_role":    (*user)["i_role"],
+				"s_pwd":     password,
+				"s_login":   username,
+				"id":        mgo.BsonIdToSId((*user)["_id"]),
 			})
 			UserMenu[username] = GetUserMenu(qu.IntAll((*user)["i_role"]))
 		}
@@ -79,7 +80,7 @@ func (f *Front) Login() {
 	}
 }
 
-// 获取图片验证码
+// Code 获取图片验证码
 func (f *Front) Code() {
 	id := captcha.NewLen(4)
 	//r := &http.Request{}
@@ -126,7 +127,6 @@ func (f *Front) UserGroup() {
 				bson.M{"s_name": bson.M{"$regex": search}},
 			}
 		}
-
 		data, _ := Mgo.Find("s_group", query, `{"i_createtime":-1}`, nil, false, start, limit)
 		count := Mgo.Count("s_group", query)
 		f.ServeJson(map[string]interface{}{
@@ -158,7 +158,7 @@ func (f *Front) UserGroupNew() {
 			m1["s_name"] = ""
 			m1["s_login"] = group["s_name"]
 			m1["s_password"] = qu.SE.EncodeString(qu.ObjToString(group["s_password"]))
-			m1["i_power"] = "1"
+			m1["i_role"] = group["i_role"]
 			m1["s_phone"] = ""
 			m1["i_createtime"] = currenttime
 			m1["i_updatetime"] = currenttime
@@ -172,7 +172,7 @@ func (f *Front) UserGroupNew() {
 				m["s_name"] = ""
 				m["s_login"] = qu.ObjToString(group["s_name"]) + "_zj_" + strconv.Itoa(i)
 				m["s_password"] = qu.SE.EncodeString(qu.ObjToString(user["u1_pwd"]))
-				m["i_power"] = "2"
+				m["i_role"] = "3"
 				m["s_phone"] = ""
 				m["i_createtime"] = currenttime
 				m["i_updatetime"] = currenttime
@@ -187,7 +187,7 @@ func (f *Front) UserGroupNew() {
 				m["s_name"] = ""
 				m["s_login"] = qu.ObjToString(group["s_name"]) + "_" + strconv.Itoa(i)
 				m["s_password"] = qu.SE.EncodeString(qu.ObjToString(user["u2_pwd"]))
-				m["i_power"] = "3"
+				m["i_role"] = "4"
 				m["s_phone"] = ""
 				m["i_createtime"] = currenttime
 				m["i_updatetime"] = currenttime
@@ -291,6 +291,44 @@ func (f *Front) UserState() {
 	}
 }
 
+func (f *Front) UserAll() {
+	defer qu.Catch()
+	if f.Method() == "POST" {
+
+		start, _ := f.GetInteger("start")
+		limit, _ := f.GetInteger("length")
+		draw, _ := f.GetInteger("draw")
+		searchStr := f.GetString("search[value]")
+		search := strings.TrimSpace(searchStr)
+		query := map[string]interface{}{
+			"b_delete": false,
+		}
+		user := f.GetSession("user").(map[string]interface{})
+		gid := qu.ObjToString(user["s_groupid"])
+		if user["i_role"] == "0" || user["i_role"] == "1" {
+
+		} else {
+			query["s_groupid"] = gid
+		}
+
+		if search != "" {
+			query["$or"] = []interface{}{
+				bson.M{"s_login": bson.M{"$regex": search}},
+			}
+		}
+		data, _ := Mgo.Find("s_user", query, `{"i_createtime":-1}`, nil, false, start, limit)
+		count := Mgo.Count("s_user", query)
+		f.ServeJson(map[string]interface{}{
+			"draw":            draw,
+			"data":            data,
+			"recordsFiltered": count,
+			"recordsTotal":    count,
+		})
+	} else {
+		_ = f.Render("user/user_list.html")
+	}
+}
+
 func (f *Front) UserDel() {
 	defer qu.Catch()
 	if f.Method() == "POST" {
@@ -315,7 +353,7 @@ func (f *Front) UserModify() {
 
 func (f *Front) GroupList() {
 	qu.Catch()
-	query := map[string]interface{}{"b_delete": false, "i_state": false}
+	query := map[string]interface{}{"b_delete": false, "i_state": true}
 	field := map[string]interface{}{"s_name": 1, "s_personname": 1}
 	info, b := Mgo.Find("s_group", query, nil, field, false, -1, -1)
 	if b && len(*info) > 0 {
@@ -326,11 +364,28 @@ func (f *Front) GroupList() {
 	}
 }
 
-//用户任务分发
+func (f *Front) UserList() {
+	qu.Catch()
+	if f.Method() == "POST" {
+		user := f.GetSession("user").(map[string]interface{})
+		gid := qu.ObjToString(user["s_groupid"])
+		query := map[string]interface{}{"s_groupid": gid, "b_delete": false, "i_state": true, "i_role": "3"}
+		field := map[string]interface{}{"s_login": 1, "s_groupid": 1, "s_name": 1}
+		info, b := Mgo.Find("s_user", query, nil, field, false, -1, -1)
+		if b && len(*info) > 0 {
+			f.ServeJson(map[string]interface{}{
+				"rep":  b,
+				"data": *info,
+			})
+		}
+	}
+}
+
+// UserTaskSave 用户任务分发
 func (f *Front) UserTaskSave() {
 	defer qu.Catch()
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])
+	username := qu.ObjToString(user["s_login"])
 	var taskArr []map[string]interface{}
 	var userTaskIdArr []string
 	userTaskIdInfo := map[string]Task{}
@@ -344,7 +399,7 @@ func (f *Front) UserTaskSave() {
 		f.ServeJson(map[string]interface{}{"success": false, "msg": msg})
 		return
 	}
-	sourcetaskinfo := qu.ObjToString((*groupTask)["s_sourcetaskinfo"])
+	sourceinfo := qu.ObjToString((*groupTask)["s_sourceinfo"])
 	userNums := f.GetString("usernums")
 	var userArr []map[string]interface{}
 	if err := json.Unmarshal([]byte(userNums), &userArr); err != nil {
@@ -353,7 +408,7 @@ func (f *Front) UserTaskSave() {
 	} else {
 		for _, userInfo := range userArr {
 			userid := qu.ObjToString(userInfo["s_userid"])
-			name := qu.ObjToString(userInfo["s_name"])
+			name := qu.ObjToString(userInfo["s_name"]) //可能为空
 			login := qu.ObjToString(userInfo["s_login"])
 			givenum := qu.IntAll(userInfo["i_givenum"])
 			userTaskId := primitive.NewObjectID()
@@ -365,23 +420,25 @@ func (f *Front) UserTaskSave() {
 			}
 			userTaskIdInfo[userTaskIdStr] = ut
 			userTask := map[string]interface{}{
-				"_id":              userTaskId,                                    //生成任务id
-				"s_projectid":      qu.ObjToString((*groupTask)["s_projectid"]),   //项目标识
-				"s_projectname":    qu.ObjToString((*groupTask)["s_projectname"]), //项目名称
-				"s_status":         "未开始",                                         //任务状态
-				"s_personid":       userid,                                        //任务负责人标识
-				"s_personname":     name,                                          //任务负责人
-				"s_login":          login,                                         //用户账号
-				"s_groupname":      qu.ObjToString((*groupTask)["s_groupname"]),   //用户组名称
-				"s_groupid":        qu.ObjToString((*groupTask)["s_groupid"]),     //用户组标识
-				"i_givenum":        givenum,                                       //分发数据量
-				"s_createname":     username,                                      //创建人
-				"i_createtime":     time.Now().Unix(),                             //创建时间
-				"s_progress":       "0%",                                          //完成进度
-				"s_sourceinfo":     qu.ObjToString((*groupTask)["s_sourceinfo"]),  //源数据表
-				"s_sourcetaskinfo": sourcetaskinfo,                                //任务日志表
-				"s_stype":          "user",                                        //任务类型
-				"s_parentid":       groupTaskId,                                   //父任务及用户组任务id
+				"_id":           userTaskId,                                    //生成任务id
+				"s_projectid":   qu.ObjToString((*groupTask)["s_projectid"]),   //项目标识
+				"s_projectname": qu.ObjToString((*groupTask)["s_projectname"]), //项目名称
+				"s_status":      "未开始",                                         //任务状态
+				"s_personid":    userid,                                        //任务负责人标识
+				"s_personname":  name,                                          //任务负责人
+				"s_login":       login,                                         //用户账号
+				"s_groupname":   qu.ObjToString((*groupTask)["s_groupname"]),   //用户组名称
+				"s_groupid":     qu.ObjToString((*groupTask)["s_groupid"]),     //用户组标识
+				"i_givenum":     givenum,                                       //分发数据量
+				"s_createname":  username,                                      //创建人
+				"i_createtime":  time.Now().Unix(),                             //创建时间
+				"s_progress":    "0%",                                          //完成进度
+				"s_sourceinfo":  sourceinfo,                                    //源数据表
+				"s_stype":       "user",                                        //任务类型
+				"s_parentid":    groupTaskId,                                   //父任务及用户组任务id
+				"s_entname":     qu.ObjToString((*groupTask)["s_entname"]),     //公司名称
+				"s_departname":  qu.ObjToString((*groupTask)["s_departname"]),  //部门名称
+				"s_rulename":    qu.ObjToString((*groupTask)["s_rulename"]),    //规则名称
 			}
 			taskArr = append(taskArr, userTask)
 		}
@@ -413,10 +470,11 @@ func (f *Front) UserTaskSave() {
 						}},
 					false, false)
 				msg = "任务分发成功"
-				UpdateSourceTaskInfo(sourcetaskinfo, groupTaskId, userTaskIdInfo) //用户分发任务成功后,同时更新任务临时
+				UpdateSourceInfo(sourceinfo, groupTaskId, userTaskIdInfo) //用户分发任务成功后,同时更新任务数据源
 			}
 		}
 	}
+	f.ServeJson(map[string]interface{}{"success": success, "msg": msg})
 }
 
 // UserTaskList 用户任务分发列表
@@ -424,15 +482,17 @@ func (f *Front) UserTaskList() {
 	defer qu.Catch()
 	//groupId := f.GetString("s_groupid") //用户组id
 	groupTaskId := f.GetString("grouptaskid") //用户组任务id
+	qu.Debug("groupTaskId:", groupTaskId)
 	if f.Method() == "POST" {
 		start, _ := f.GetInteger("start")
 		limit, _ := f.GetInteger("length")
 		draw, _ := f.GetInteger("draw")
-		status := f.GetString("status")
-		login := f.GetString("login")
+		status := f.GetString("s_status")
+		login := f.GetString("s_login")
 		//searchStr := f.GetString("search[value]")
 		//search := strings.TrimSpace(searchStr)
 		query := map[string]interface{}{
+			"s_stype":    "user",
 			"s_parentid": groupTaskId,
 		}
 		if status != "-1" { //任务状态
@@ -441,24 +501,41 @@ func (f *Front) UserTaskList() {
 		if login != "-1" { //用户账号
 			query["s_login"] = login
 		}
-		list, _ := Mgo.Find(TASKCOLLNAME, query, nil, nil, false, start, limit)
+		qu.Debug("Query:", query)
 		count := Mgo.Count(TASKCOLLNAME, query)
+		list, _ := Mgo.Find(TASKCOLLNAME, query, map[string]interface{}{"_id": -1}, nil, false, start, limit)
+		for _, l := range *list {
+			if status := qu.ObjToString(l["s_status"]); status == "进行中" { //更新任务进度
+				personid := qu.ObjToString(l["s_personid"])
+				giveNum := qu.IntAll(l["i_givenum"])
+				sourceinfo := qu.ObjToString(l["s_sourceinfo"])
+				tagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_userid": personid, "b_istag": true})
+				progressFloat := float64(tagNum) / float64(giveNum)
+				value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", progressFloat), 64)
+				progress := fmt.Sprint(value*100) + "%"
+				l["s_progress"] = progress
+				//同步数据库
+				Mgo.UpdateById(TASKCOLLNAME, l["_id"], map[string]interface{}{"$set": map[string]interface{}{"s_progress": progress}})
+			}
+		}
 		f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
 	} else {
-		sourcetaskinfo := f.GetString("s_sourcetaskinfo")
+		sourceinfo := f.GetString("s_sourceinfo")
+		qu.Debug(sourceinfo)
 		//统计数据量
-		isGiveNum := Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": true})     //已分发量
-		isNotGiveNum := Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": false}) //待分发量
-		isTagNum := Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_iscomplete": true})      //已标注数量
-		isNotTagNum := Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_iscomplete": false})  //未标注数量
-		allNum := Mgo.Count(sourcetaskinfo, map[string]interface{}{"s_grouptaskid": groupTaskId})                              //数据总量
+		isGiveNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": true})     //已分发量
+		isNotGiveNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_isgiveuser": false}) //待分发量
+		isTagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_istag": true})           //已标注数量
+		isNotTagNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId, "b_istag": false})       //未标注数量
+		allNum := Mgo.Count(sourceinfo, map[string]interface{}{"s_grouptaskid": groupTaskId})                              //数据总量
+		qu.Debug("数据总量:", allNum, "已分发量:", isGiveNum, "待分发量:", isNotGiveNum, "已标注量:", isTagNum, "未标注量:", isNotTagNum)
 		f.T["grouptaskid"] = groupTaskId
 		f.T["allNum"] = allNum
 		f.T["isGiveNum"] = isGiveNum
 		f.T["isNotGiveNum"] = isNotGiveNum
 		f.T["isTagNum"] = isTagNum
 		f.T["isNotTagNum"] = isNotTagNum
-		_ = f.Render("project/task_user_list.html", &f.T)
+		_ = f.Render("project/task_detail.html", &f.T)
 	}
 }
 
@@ -466,16 +543,33 @@ func (f *Front) UserTaskList() {
 func (f *Front) UserTaskRetrieve() {
 	defer qu.Catch()
 	user := f.GetSession("user").(map[string]interface{})
-	username := qu.ObjToString(user["s_name"])
-	userTaskId := f.GetString("taskid")               //用户任务id
-	sourceTaskInfo := f.GetString("s_sourcetaskinfo") //临时表
-	msg, count, success := RetrieveTaskByUser(sourceTaskInfo, username, userTaskId)
+	username := qu.ObjToString(user["s_login"])
+	userTaskId := f.GetString("taskid") //用户任务id
+	qu.Debug("User Task Id:", userTaskId)
+	sourceInfo := f.GetString("s_sourceinfo") //数据源表
+	status := f.GetString("s_status")
+	userTaskIdStatus := map[string]string{userTaskId: status}
+	msg, count, success := RetrieveCloseTaskByUser(sourceInfo, username, userTaskIdStatus)
 	//userTask, _ := Mgo.FindById(TASKCOLLNAME, userTaskId, nil)
 	f.ServeJson(map[string]interface{}{"success": success, "count": count, "msg": msg})
 }
 
-// UpdateSourceTaskInfo 用户分发任务成功后更新临时任务表
-func UpdateSourceTaskInfo(sourcetaskinfo, groupTaskId string, userTaskIdInfo map[string]Task) {
+// UserTaskClose 用户任务关闭
+func (f *Front) UserTaskClose() {
+	defer qu.Catch()
+	user := f.GetSession("user").(map[string]interface{})
+	username := qu.ObjToString(user["s_login"])
+	userTaskId := f.GetString("taskid") //用户任务id
+	qu.Debug("User Task Id:", userTaskId)
+	sourceInfo := f.GetString("s_sourceinfo") //数据源表
+	status := f.GetString("s_status")
+	userTaskIdStatus := map[string]string{userTaskId: status}
+	msg, count, success := RetrieveCloseTaskByUser(sourceInfo, username, userTaskIdStatus)
+	f.ServeJson(map[string]interface{}{"success": success, "count": count, "msg": msg})
+}
+
+// UpdateSourceInfo 用户分发任务成功后更新数据源表
+func UpdateSourceInfo(sourceinfo, groupTaskId string, userTaskIdInfo map[string]Task) {
 	defer qu.Catch()
 	for userTaskId, tInfo := range userTaskIdInfo {
 		userId := tInfo.UserId
@@ -485,13 +579,13 @@ func UpdateSourceTaskInfo(sourcetaskinfo, groupTaskId string, userTaskIdInfo map
 		ch := make(chan bool, 5)
 		wg := &sync.WaitGroup{}
 		lock := &sync.Mutex{}
-		query := map[string]interface{}{ //查找用户组任务id关联的临时数据
+		query := map[string]interface{}{
 			"s_grouptaskid": groupTaskId,
 			"b_isgiveuser":  false,
 		}
 		updateArr := [][]map[string]interface{}{}
 		qu.Debug("Query:", query)
-		it := sess.DB(Mgo.DbName).C(sourcetaskinfo).Find(&query).Limit(int64(num)).Iter()
+		it := sess.DB(Mgo.DbName).C(sourceinfo).Find(&query).Limit(int64(num)).Iter()
 		n := 0
 		for tmp := make(map[string]interface{}); it.Next(tmp); n++ {
 			ch <- true
@@ -514,7 +608,7 @@ func UpdateSourceTaskInfo(sourcetaskinfo, groupTaskId string, userTaskIdInfo map
 				lock.Lock()
 				updateArr = append(updateArr, update)
 				if len(updateArr) > 500 {
-					Mgo.UpdateBulk(sourcetaskinfo, updateArr...)
+					Mgo.UpdateBulk(sourceinfo, updateArr...)
 					updateArr = [][]map[string]interface{}{}
 				}
 				lock.Unlock()
@@ -527,55 +621,79 @@ func UpdateSourceTaskInfo(sourcetaskinfo, groupTaskId string, userTaskIdInfo map
 		wg.Wait()
 		lock.Lock()
 		if len(updateArr) > 0 {
-			Mgo.UpdateBulk(sourcetaskinfo, updateArr...)
+			Mgo.UpdateBulk(sourceinfo, updateArr...)
 			updateArr = [][]map[string]interface{}{}
 		}
 		lock.Unlock()
 	}
 }
 
-// RetrieveTaskByUser 用户收回任务
-func RetrieveTaskByUser(sourceTaskInfo, username string, userTaskIds ...string) (allMsg string, allCount int, allSuccess bool) {
+// RetrieveCloseTaskByUser 用户收回任务、关闭,更新数据源
+func RetrieveCloseTaskByUser(sourceInfo, username string, userTaskIdStatus map[string]string) (allMsg string, allCount int, allSuccess bool) {
 	defer qu.Catch()
 	allSuccess = true
-	for _, taskId := range userTaskIds {
+	for taskId, userTaskStatus := range userTaskIdStatus {
+		/*
+			收回时userTaskStatus:未开始、进行中
+			关闭时userTaskStatus:未开始
+		*/
+		qu.Debug(taskId, userTaskStatus)
+		//用户任务要更新的信息
+		taskSet := map[string]interface{}{
+			"s_status":       "已完成", //收回、关闭时默认任务状态已完成
+			"i_updatetime":   time.Now().Unix(),
+			"s_updateperson": username,
+			"s_progress":     "100%",
+			"i_completetime": time.Now().Unix(),
+		}
+		if userTaskStatus == "未开始" { //未开始的任务手动添加开始时间
+			taskSet["i_starttime"] = time.Now().Unix()
+			taskSet["s_status"] = "已关闭"
+		}
 		query := map[string]interface{}{
 			"s_usertaskid": taskId,
-			"b_isgiveuser": true,
-			"b_iscomplete": false,
+			"b_istag":      false,
 		}
-		count := Mgo.Count(sourceTaskInfo, query)
-		success := false
+		count := Mgo.Count(sourceInfo, query)
 		qu.Debug("Find Task Id:", taskId, " Retrieve Count:", count)
-		if count > 0 {
+		if count > 0 { //更新数据源信息
 			set := map[string]interface{}{
-				"b_isgiveuser": false,
 				"i_updatetime": time.Now().Unix(),
+				"b_isgiveuser": false,
 			}
 			unset := map[string]interface{}{
 				"s_usertaskid": "",
 				"s_userid":     "",
 			}
-			success = Mgo.Update(sourceTaskInfo, query, map[string]interface{}{"$set": set, "$unset": unset}, false, false)
-			qu.Debug("User Task", taskId, "Retrieve Data:", success)
+			success := Mgo.Update(sourceInfo, query, map[string]interface{}{"$set": set, "$unset": unset}, false, true)
+			qu.Debug("Update SourceInfo:", success)
 			if success {
 				allCount += count
 				//收回成功,更新task信息
-				Mgo.UpdateById(TASKCOLLNAME, taskId, map[string]interface{}{
-					"$set": map[string]interface{}{
-						"s_status":       "已完成",
-						"i_updatetime":   time.Now().Unix(),
-						"s_updateperson": username,
-						"s_progress":     "100%",
-					},
+				success = Mgo.UpdateById(TASKCOLLNAME, taskId, map[string]interface{}{
+					"$set": taskSet,
 					"$inc": map[string]interface{}{ //更新数据量
 						"i_givenum": -count,
 					},
 				})
+				if !success {
+					allMsg += "任务ID:" + taskId + "更新数据失败;"
+					allSuccess = false
+				}
+				qu.Debug("Update:", taskId, success)
 			} else {
-				allMsg += "任务ID:" + taskId + "更新失败"
+				allMsg += "任务ID:" + taskId + "更新数据源失败;"
+				allSuccess = false
+			}
+		} else { //没有要收回的数据,只更新任务信息
+			success := Mgo.UpdateById(TASKCOLLNAME, taskId, map[string]interface{}{
+				"$set": taskSet,
+			})
+			if !success {
+				allMsg += "任务ID:" + taskId + "更新数据失败;"
 				allSuccess = false
 			}
+			qu.Debug("Update:", taskId, success)
 		}
 	}
 	return

+ 55 - 76
src/qua/method.go

@@ -10,7 +10,6 @@ import (
 	u "util"
 )
 
-
 //单位
 var specHeadReg *regexp.Regexp = regexp.MustCompile("^([a-zA-Z]{1,2}[\u4e00-\u9fa5]{6,}|某部|州|自治区|自治州|街道|名称|省|市|县|区|业绩|资格|中标|项目|预算单位)")
 var unHanHeadReg *regexp.Regexp = regexp.MustCompile("^([\u4e00-\u9fa5])")
@@ -18,46 +17,42 @@ var unConReg *regexp.Regexp = regexp.MustCompile("(园|政府|集团|公司|有
 var unEndReg *regexp.Regexp = regexp.MustCompile("^.*(公司|学(校)?|博物馆|联合社|合作社|监狱|办公厅|电视台|集团|机构|企业|办公室|委员会|实验室|联社|厂|场|院|所|店|小|台|中心|局|站|城|馆|厅|处|行|科|部|队|联合(会|体)|工作室)$")
 var unenableReg1 *regexp.Regexp = regexp.MustCompile("^([\u4e00-\u9fa5]{1,2}(责任|有限|有限股份|有限责任|实业)公司|.*(某部|先生|女士|小姐)|工程技术处)$")
 var unenableReg2 *regexp.Regexp = regexp.MustCompile("(\\?|?|单位|#|xxxx|\\*\\*|%|万元|设计企业|免费|代表|代码标识|盖电子|测试测试|删除|错误|吊销|注销|发起人|待清理|&#|护照号|身份证号|\" +\n\t\"法人|&nbsp|国家拨入|借款|积累资金|认股人|--|、|&|`|美元)")
-//分词
-var GSE *gse.Segmenter  = &gse.Segmenter{}
 
+//分词
+var GSE *gse.Segmenter = &gse.Segmenter{}
 
 //编号
 var codeUnConReg *regexp.Regexp = regexp.MustCompile("(null|勘察|测试|设计|设备|项目|标段|工程|监理|范围|分包|月|日|天)")
 var codeUnLenReg *regexp.Regexp = regexp.MustCompile("([\u4e00-\u9fa5]{9,})")
 
-
-
-
 var classMoneyScope map[string]map[string]interface{}
 
-
-func init()  {
+func init() {
 	GSE.LoadDict("./web/qua_res/dictionary.txt")
 	//t>d>p
 	classMoneyScope = map[string]map[string]interface{}{
-		"建筑工程": {"min":10000,"max":10000000000},
-		"行政办公": {"min":100,"max":100000000},
-		"医疗卫生": {"min":1000,"max":100000000},
-		"服务采购": {"min":10,"max":100000000},
-		"机械设备": {"min":1000,"max":1000000000},
-		"水利水电": {"min":1000,"max":1000000000},
-		"能源化工": {"min":1000,"max":1000000000},
-		"弱电安防": {"min":1000,"max":1000000000},
-		"信息技术": {"min":100,"max":100000000},
-		"交通工程": {"min":1000,"max":10000000000},
-		"市政设施": {"min":1000,"max":10000000000},
-		"农林牧渔": {"min":100,"max":10000000},
+		"建筑工程": {"min": 10000, "max": 10000000000},
+		"行政办公": {"min": 100, "max": 100000000},
+		"医疗卫生": {"min": 1000, "max": 100000000},
+		"服务采购": {"min": 10, "max": 100000000},
+		"机械设备": {"min": 1000, "max": 1000000000},
+		"水利水电": {"min": 1000, "max": 1000000000},
+		"能源化工": {"min": 1000, "max": 1000000000},
+		"弱电安防": {"min": 1000, "max": 1000000000},
+		"信息技术": {"min": 100, "max": 100000000},
+		"交通工程": {"min": 1000, "max": 10000000000},
+		"市政设施": {"min": 1000, "max": 10000000000},
+		"农林牧渔": {"min": 100, "max": 10000000},
 	}
 }
 
 //行业金额校验
-func checkingClassMoney(money float64,class string) bool  {
-	data :=classMoneyScope[class]
-	if data!=nil {
+func checkingClassMoney(money float64, class string) bool {
+	data := classMoneyScope[class]
+	if data != nil {
 		min := qu.Float64All(data["min"])
 		max := qu.Float64All(data["max"])
-		if money>min && money<max {
+		if money > min && money < max {
 			return true
 		}
 	}
@@ -65,19 +60,20 @@ func checkingClassMoney(money float64,class string) bool  {
 }
 
 //企业库检测
-func qyNameIsExistsQYXY(name string) bool{
-	q := map[string]interface{}{"company_name": name,}
-	data,_ := u.Mgo_QY.FindOne("qyxy_std",q)
-	if len(*data)>2 && *data!=nil{
+func qyNameIsExistsQYXY(name string) bool {
+	q := map[string]interface{}{"company_name": name}
+	data, _ := u.Mgo_QY.FindOne("qyxy_std", q)
+	if len(*data) > 2 && *data != nil {
 		return false
 	}
 	return false
 }
+
 //采购单位库
-func buyerNameIsExists(name string) bool{
-	q := map[string]interface{}{"buyer_name": name,}
-	data,_ := u.Mgo_QY.FindOne("buyer_enterprise",q)
-	if len(*data)>2 && *data!=nil{
+func buyerNameIsExists(name string) bool {
+	q := map[string]interface{}{"buyer_name": name}
+	data, _ := u.Mgo_QY.FindOne("buyer_enterprise", q)
+	if len(*data) > 2 && *data != nil {
 		return false
 	}
 	return false
@@ -110,30 +106,30 @@ func isHan(str string) bool {
 //符号数量
 func isCharCount(str string) []int {
 	//中文,英文,数字,其他
-	c1,c2,c3,c4:=0,0,0,0
+	c1, c2, c3, c4 := 0, 0, 0, 0
 	for _, v := range str {
 		if unicode.Is(unicode.Han, v) {
 			c1++
-		}else if unicode.IsLetter(v){
+		} else if unicode.IsLetter(v) {
 			c2++
-		} else if unicode.IsNumber(v){
+		} else if unicode.IsNumber(v) {
 			c3++
-		}else {
+		} else {
 			c4++
 		}
 	}
-	return []int{c1,c2,c3,c4}
+	return []int{c1, c2, c3, c4}
 }
 
 //中文比例-1:3
 func isHanLenToLittle(str string) bool {
 	var count int
 	len := utf8.RuneCountInString(str)
-	min_count := len/3
+	min_count := len / 3
 	for _, v := range str {
 		if unicode.Is(unicode.Han, v) {
 			count++
-			if count>=min_count {
+			if count >= min_count {
 				return true
 			}
 		}
@@ -141,8 +137,6 @@ func isHanLenToLittle(str string) bool {
 	return false
 }
 
-
-
 //是否含字母数字
 func isAlphanumeric(str string) bool {
 	var count int
@@ -157,55 +151,40 @@ func isAlphanumeric(str string) bool {
 
 //连续数字
 func isRegTimeDateCode(str string) bool {
-	reg:=`\d{8}`
-	regx,_ := regexp.Compile(reg)
-	if regx.FindString(str)!="" {
+	reg := `\d{8}`
+	regx, _ := regexp.Compile(reg)
+	if regx.FindString(str) != "" {
 		return false
 	}
-	if utf8.RuneCountInString(str)==8 {
+	if utf8.RuneCountInString(str) == 8 {
 		return true
 	}
 	return false
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 //配置字段初始分
 func FieldSourceScore(source map[string]interface{}) map[string]int64 {
-	fieldArr := []string{"buyer","s_winner","budget","bidamount","projectname","projectcode"}
-	score := make(map[string]int64,0)
-	for _,v := range fieldArr{
+	fieldArr := []string{"buyer", "s_winner", "budget", "bidamount", "projectname", "projectcode"}
+	score := make(map[string]int64, 0)
+	for _, v := range fieldArr {
 		score[v] = int64(100)
 	}
-	for _,key := range fieldArr {
+	for _, key := range fieldArr {
 		ext := *qu.ObjToMap(source[key])
-		if ext!=nil{
-			ext_from:=qu.ObjToString(ext["ext_from"])
-			ext_type:=qu.ObjToString(ext["ext_type"])
+		if ext != nil {
+			ext_from := qu.ObjToString(ext["ext_from"])
+			ext_type := qu.ObjToString(ext["ext_type"])
 			//规范ext_from
 			ext_from = normalizedExtFromName(ext_from)
-			if ext_from=="winnerorder" || ext_from=="package" ||
-				ext_from=="jsondata" || ext_type=="" {
+			if ext_from == "winnerorder" || ext_from == "package" ||
+				ext_from == "jsondata" || ext_type == "" {
 				u.Qy_Lock.Lock()
 				score[key] = qu.Int64All(u.Ext_From[ext_from])
 				u.Qy_Lock.Unlock()
-			}else {
+			} else {
 				u.Qy_Lock.Lock()
-				s := qu.Int64All(u.Ext_From[ext_from])+qu.Int64All(u.Ext_Type[ext_type])
-				score[key] = s/2
+				s := qu.Int64All(u.Ext_From[ext_from]) + qu.Int64All(u.Ext_Type[ext_type])
+				score[key] = s / 2
 				u.Qy_Lock.Unlock()
 			}
 		}
@@ -217,12 +196,12 @@ func FieldSourceScore(source map[string]interface{}) map[string]int64 {
 
 //规范-抽取来源字符串
 func normalizedExtFromName(str string) string {
-	if strings.Contains(str,"order") {
+	if strings.Contains(str, "order") {
 		str = "winnerorder"
-	}else if strings.Contains(str,"JsonData") {
+	} else if strings.Contains(str, "JsonData") {
 		str = "jsondata"
-	}else {
+	} else {
 
 	}
 	return str
-}
+}

BIN=BIN
src/web/model/taskexportmodel.xlsx


+ 774 - 0
src/web/res/js/bootstrap3-typeahead.js

@@ -0,0 +1,774 @@
+/* =============================================================
+ * bootstrap3-typeahead.js v4.0.2
+ * https://github.com/bassjobsen/Bootstrap-3-Typeahead
+ * =============================================================
+ * Original written by @mdo and @fat
+ * =============================================================
+ * Copyright 2014 Bass Jobsen @bassjobsen
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================ */
+
+
+(function (root, factory) {
+
+    'use strict';
+
+    // CommonJS module is defined
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = factory(require('jquery'));
+    }
+    // AMD module is defined
+    else if (typeof define === 'function' && define.amd) {
+        define(['jquery'], function ($) {
+            return factory($);
+        });
+    } else {
+        factory(root.jQuery);
+    }
+
+}(this, function ($) {
+
+    'use strict';
+    // jshint laxcomma: true
+
+
+    /* TYPEAHEAD PUBLIC CLASS DEFINITION
+     * ================================= */
+
+    var Typeahead = function (element, options) {
+        this.$element = $(element);
+        this.options = $.extend({}, Typeahead.defaults, options);
+        this.matcher = this.options.matcher || this.matcher;
+        this.sorter = this.options.sorter || this.sorter;
+        this.select = this.options.select || this.select;
+        this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
+        this.highlighter = this.options.highlighter || this.highlighter;
+        this.render = this.options.render || this.render;
+        this.updater = this.options.updater || this.updater;
+        this.displayText = this.options.displayText || this.displayText;
+        this.itemLink = this.options.itemLink || this.itemLink;
+        this.itemTitle = this.options.itemTitle || this.itemTitle;
+        this.followLinkOnSelect = this.options.followLinkOnSelect || this.followLinkOnSelect;
+        this.source = this.options.source;
+        this.delay = this.options.delay;
+        this.theme = this.options.theme && this.options.themes && this.options.themes[this.options.theme] || Typeahead.defaults.themes[Typeahead.defaults.theme];
+        this.$menu = $(this.options.menu || this.theme.menu);
+        this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;
+        this.fitToElement = typeof this.options.fitToElement == 'boolean' ? this.options.fitToElement : false;
+        this.shown = false;
+        this.listen();
+        this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' || this.options.showHintOnFocus === 'all' ? this.options.showHintOnFocus : false;
+        this.afterSelect = this.options.afterSelect;
+        this.afterEmptySelect = this.options.afterEmptySelect;
+        this.addItem = false;
+        this.value = this.$element.val() || this.$element.text();
+        this.keyPressed = false;
+        this.focused = this.$element.is(':focus');
+        this.changeInputOnSelect = this.options.changeInputOnSelect || this.changeInputOnSelect;
+        this.changeInputOnMove = this.options.changeInputOnMove || this.changeInputOnMove;
+        this.openLinkInNewTab = this.options.openLinkInNewTab || this.openLinkInNewTab;
+        this.selectOnBlur = this.options.selectOnBlur || this.selectOnBlur;
+        this.showCategoryHeader = this.options.showCategoryHeader || this.showCategoryHeader;
+    };
+
+    Typeahead.prototype = {
+
+        constructor: Typeahead,
+
+
+        setDefault: function (val) {
+            // var val = this.$menu.find('.active').data('value');
+            this.$element.data('active', val);
+            if (this.autoSelect || val) {
+                var newVal = this.updater(val);
+                // Updater can be set to any random functions via "options" parameter in constructor above.
+                // Add null check for cases when updater returns void or undefined.
+                if (!newVal) {
+                    newVal = '';
+                }
+                this.$element
+                    .val(this.displayText(newVal) || newVal)
+                    .text(this.displayText(newVal) || newVal)
+                    .change();
+                this.afterSelect(newVal);
+            }
+            return this.hide();
+        },
+
+        select: function () {
+            var val = this.$menu.find('.active').data('value');
+
+            this.$element.data('active', val);
+            if (this.autoSelect || val) {
+                var newVal = this.updater(val);
+                // Updater can be set to any random functions via "options" parameter in constructor above.
+                // Add null check for cases when updater returns void or undefined.
+                if (!newVal) {
+                    newVal = '';
+                }
+
+                if (this.changeInputOnSelect) {
+                    this.$element
+                        .val(this.displayText(newVal) || newVal)
+                        .text(this.displayText(newVal) || newVal)
+                        .change();
+                }
+
+                if (this.followLinkOnSelect && this.itemLink(val)) {
+                    if (this.openLinkInNewTab) {
+                        window.open(this.itemLink(val), '_blank');
+                    } else {
+                        document.location = this.itemLink(val);
+                    }
+                    this.afterSelect(newVal);
+                } else if (this.followLinkOnSelect && !this.itemLink(val)) {
+                    this.afterEmptySelect(newVal);
+                } else {
+                    this.afterSelect(newVal);
+                }
+            } else {
+                this.afterEmptySelect();
+            }
+
+            return this.hide();
+        },
+
+        updater: function (item) {
+            return item;
+        },
+
+        setSource: function (source) {
+            this.source = source;
+        },
+
+        show: function () {
+            var pos = $.extend({}, this.$element.position(), {
+                height: this.$element[0].offsetHeight
+            });
+
+            var scrollHeight = typeof this.options.scrollHeight == 'function' ?
+                this.options.scrollHeight.call() :
+                this.options.scrollHeight;
+
+            var element;
+            if (this.shown) {
+                element = this.$menu;
+            } else if (this.$appendTo) {
+                element = this.$menu.appendTo(this.$appendTo);
+                this.hasSameParent = this.$appendTo.is(this.$element.parent());
+            } else {
+                element = this.$menu.insertAfter(this.$element);
+                this.hasSameParent = true;
+            }
+
+            if (!this.hasSameParent) {
+                // We cannot rely on the element position, need to position relative to the window
+                element.css('position', 'fixed');
+                var offset = this.$element.offset();
+                pos.top = offset.top;
+                pos.left = offset.left;
+            }
+            // The rules for bootstrap are: 'dropup' in the parent and 'dropdown-menu-right' in the element.
+            // Note that to get right alignment, you'll need to specify `menu` in the options to be:
+            // '<ul class="typeahead dropdown-menu" role="listbox"></ul>'
+            var dropup = $(element).parent().hasClass('dropup');
+            var newTop = dropup ? 'auto' : (pos.top + pos.height + scrollHeight);
+            var right = $(element).hasClass('dropdown-menu-right');
+            var newLeft = right ? 'auto' : pos.left;
+            // it seems like setting the css is a bad idea (just let Bootstrap do it), but I'll keep the old
+            // logic in place except for the dropup/right-align cases.
+            element.css({ top: newTop, left: newLeft }).show();
+
+            if (this.options.fitToElement === true) {
+                element.css('width', this.$element.outerWidth() + 'px');
+            }
+
+            this.shown = true;
+            return this;
+        },
+
+        hide: function () {
+            this.$menu.hide();
+            this.shown = false;
+            return this;
+        },
+
+        lookup: function (query) {
+            if (typeof(query) != 'undefined' && query !== null) {
+                this.query = query;
+            } else {
+                this.query = this.$element.val();
+            }
+
+            if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) {
+                return this.shown ? this.hide() : this;
+            }
+
+            var worker = $.proxy(function () {
+
+                // Bloodhound (since 0.11) needs three arguments.
+                // Two of them are callback functions (sync and async) for local and remote data processing
+                // see https://github.com/twitter/typeahead.js/blob/master/src/bloodhound/bloodhound.js#L132
+                if ($.isFunction(this.source) && this.source.length === 3) {
+                    this.source(this.query, $.proxy(this.process, this), $.proxy(this.process, this));
+                } else if ($.isFunction(this.source)) {
+                    this.source(this.query, $.proxy(this.process, this));
+                } else if (this.source) {
+                    this.process(this.source);
+                }
+            }, this);
+
+            clearTimeout(this.lookupWorker);
+            this.lookupWorker = setTimeout(worker, this.delay);
+        },
+
+        process: function (items) {
+            var that = this;
+
+            items = $.grep(items, function (item) {
+                return that.matcher(item);
+            });
+
+            items = this.sorter(items);
+
+            if (!items.length && !this.options.addItem) {
+                return this.shown ? this.hide() : this;
+            }
+
+            if (items.length > 0) {
+                this.$element.data('active', items[0]);
+            } else {
+                this.$element.data('active', null);
+            }
+
+            if (this.options.items != 'all') {
+                items = items.slice(0, this.options.items);
+            }
+
+            // Add item
+            if (this.options.addItem) {
+                items.push(this.options.addItem);
+            }
+
+            return this.render(items).show();
+        },
+
+        matcher: function (item) {
+            var it = this.displayText(item);
+            return ~it.toLowerCase().indexOf(this.query.toLowerCase());
+        },
+
+        sorter: function (items) {
+            var beginswith = [];
+            var caseSensitive = [];
+            var caseInsensitive = [];
+            var item;
+
+            while ((item = items.shift())) {
+                var it = this.displayText(item);
+                if (!it.toLowerCase().indexOf(this.query.toLowerCase())) {
+                    beginswith.push(item);
+                } else if (~it.indexOf(this.query)) {
+                    caseSensitive.push(item);
+                } else {
+                    caseInsensitive.push(item);
+                }
+            }
+
+            return beginswith.concat(caseSensitive, caseInsensitive);
+        },
+
+        highlighter: function (item) {
+            var text = this.query;
+            if (text === '') {
+                return item;
+            }
+            var matches = item.match(/(>)([^<]*)(<)/g);
+            var first = [];
+            var second = [];
+            var i;
+            if (matches && matches.length) {
+                // html
+                for (i = 0; i < matches.length; ++i) {
+                    if (matches[i].length > 2) {// escape '><'
+                        first.push(matches[i]);
+                    }
+                }
+            } else {
+                // text
+                first = [];
+                first.push(item);
+            }
+            text = text.replace((/[\(\)\/\.\*\+\?\[\]]/g), function (mat) {
+                return '\\' + mat;
+            });
+            var reg = new RegExp(text, 'g');
+            var m;
+            for (i = 0; i < first.length; ++i) {
+                m = first[i].match(reg);
+                if (m && m.length > 0) {// find all text nodes matches
+                    second.push(first[i]);
+                }
+            }
+            for (i = 0; i < second.length; ++i) {
+                item = item.replace(second[i], second[i].replace(reg, '<strong>$&</strong>'));
+            }
+            return item;
+        },
+
+        render: function (items) {
+            var that = this;
+            var self = this;
+            var activeFound = false;
+            var data = [];
+            var _category = that.options.separator;
+
+            $.each(items, function (key, value) {
+                // inject separator
+                if (key > 0 && value[_category] !== items[key - 1][_category]) {
+                    data.push({
+                        __type: 'divider'
+                    });
+                }
+
+                if (this.showCategoryHeader) {
+                    // inject category header
+                    if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])) {
+                        data.push({
+                            __type: 'category',
+                            name: value[_category]
+                        });
+                    }
+                }
+
+                data.push(value);
+            });
+
+            items = $(data).map(function (i, item) {
+                    if ((item.__type || false) == 'category'){
+                        return $(that.options.headerHtml || that.theme.headerHtml).text(item.name)[0];
+                    }
+
+                    if ((item.__type || false) == 'divider'){
+                        return $(that.options.headerDivider || that.theme.headerDivider)[0];
+                    }
+
+                    var text = self.displayText(item);
+                    i = $(that.options.item || that.theme.item).data('value', item);
+                    i.find(that.options.itemContentSelector || that.theme.itemContentSelector)
+                        .addBack(that.options.itemContentSelector || that.theme.itemContentSelector)
+                        .html(that.highlighter(text, item));
+                    if(that.options.followLinkOnSelect) {
+                        i.find('a').attr('href', self.itemLink(item));
+                    }
+                    i.find('a').attr('title', self.itemTitle(item));
+                    if (text == self.$element.val()) {
+                        i.addClass('active');
+                        self.$element.data('active', item);
+                        activeFound = true;
+                    }
+                    return i[0];
+                });
+
+            if (this.autoSelect && !activeFound) {
+                items.filter(':not(.dropdown-header)').first().addClass('active');
+                this.$element.data('active', items.first().data('value'));
+            }
+            this.$menu.html(items);
+            return this;
+        },
+
+        displayText: function (item) {
+            return typeof item !== 'undefined' && typeof item.name != 'undefined' ? item.name : item;
+        },
+
+        itemLink: function (item) {
+            return null;
+        },
+
+        itemTitle: function (item) {
+            return null;
+        },
+
+        next: function (event) {
+            var active = this.$menu.find('.active').removeClass('active');
+            var next = active.next();
+
+            if (!next.length) {
+                next = $(this.$menu.find($(this.options.item || this.theme.item).prop('tagName'))[0]);
+            }
+
+            while (next.hasClass('divider') || next.hasClass('dropdown-header')) {
+                next = next.next();
+            }
+
+            next.addClass('active');
+            // added for screen reader
+            var newVal = this.updater(next.data('value'));
+            if (this.changeInputOnMove) {
+                this.$element.val(this.displayText(newVal) || newVal);
+            }
+        },
+
+        prev: function (event) {
+            var active = this.$menu.find('.active').removeClass('active');
+            var prev = active.prev();
+
+            if (!prev.length) {
+                prev = this.$menu.find($(this.options.item || this.theme.item).prop('tagName')).last();
+            }
+
+            while (prev.hasClass('divider') || prev.hasClass('dropdown-header')) {
+                prev = prev.prev();
+            }
+
+            prev.addClass('active');
+            // added for screen reader
+            var newVal = this.updater(prev.data('value'));
+            if (this.changeInputOnMove) {
+                this.$element.val(this.displayText(newVal) || newVal);
+            }
+        },
+
+        listen: function () {
+            this.$element
+                .on('focus.bootstrap3Typeahead', $.proxy(this.focus, this))
+                .on('blur.bootstrap3Typeahead', $.proxy(this.blur, this))
+                .on('keypress.bootstrap3Typeahead', $.proxy(this.keypress, this))
+                .on('propertychange.bootstrap3Typeahead input.bootstrap3Typeahead', $.proxy(this.input, this))
+                .on('keyup.bootstrap3Typeahead', $.proxy(this.keyup, this));
+
+            if (this.eventSupported('keydown')) {
+                this.$element.on('keydown.bootstrap3Typeahead', $.proxy(this.keydown, this));
+            }
+
+            var itemTagName = $(this.options.item || this.theme.item).prop('tagName');
+            if ('ontouchstart' in document.documentElement && 'onmousemove' in document.documentElement) {
+		        this.$menu
+		            .on('touchstart', itemTagName, $.proxy(this.touchstart, this))
+		            .on('touchend', itemTagName, $.proxy(this.click, this))
+		            .on('click', $.proxy(this.click, this))
+		            .on('mouseenter', itemTagName, $.proxy(this.mouseenter, this))
+		            .on('mouseleave', itemTagName, $.proxy(this.mouseleave, this))
+		            .on('mousedown', $.proxy(this.mousedown,this));
+	        } else if ('ontouchstart' in document.documentElement) {
+		        this.$menu
+		            .on('touchstart', itemTagName, $.proxy(this.touchstart, this))
+		            .on('touchend', itemTagName, $.proxy(this.click, this));
+	        } else {
+                this.$menu
+                    .on('click', $.proxy(this.click, this))
+                    .on('mouseenter', itemTagName, $.proxy(this.mouseenter, this))
+                    .on('mouseleave', itemTagName, $.proxy(this.mouseleave, this))
+                    .on('mousedown', $.proxy(this.mousedown, this));
+            }
+        },
+
+        destroy: function () {
+            this.$element.data('typeahead', null);
+            this.$element.data('active', null);
+            this.$element
+                .unbind('focus.bootstrap3Typeahead')
+                .unbind('blur.bootstrap3Typeahead')
+                .unbind('keypress.bootstrap3Typeahead')
+                .unbind('propertychange.bootstrap3Typeahead input.bootstrap3Typeahead')
+                .unbind('keyup.bootstrap3Typeahead');
+
+            if (this.eventSupported('keydown')) {
+                this.$element.unbind('keydown.bootstrap3-typeahead');
+            }
+
+            this.$menu.remove();
+            this.destroyed = true;
+        },
+
+        eventSupported: function (eventName) {
+            var isSupported = eventName in this.$element;
+            if (!isSupported) {
+                this.$element.setAttribute(eventName, 'return;');
+                isSupported = typeof this.$element[eventName] === 'function';
+            }
+            return isSupported;
+        },
+
+        move: function (e) {
+            if (!this.shown) {
+                return;
+            }
+
+            switch (e.keyCode) {
+                case 9: // tab
+                case 13: // enter
+                case 27: // escape
+                    e.preventDefault();
+                    break;
+
+                case 38: // up arrow
+                    // with the shiftKey (this is actually the left parenthesis)
+                    if (e.shiftKey) {
+                        return;
+                    }
+                    e.preventDefault();
+                    this.prev();
+                    break;
+
+                case 40: // down arrow
+                    // with the shiftKey (this is actually the right parenthesis)
+                    if (e.shiftKey) {
+                        return;
+                    }
+                    e.preventDefault();
+                    this.next();
+                    break;
+            }
+        },
+
+        keydown: function (e) {
+            /**
+             * Prevent to make an ajax call while copying and pasting.
+             *
+             * @author Simone Sacchi
+             * @version 2018/01/18
+             */
+            if (e.keyCode === 17) { // ctrl
+                return;
+            }
+            this.keyPressed = true;
+            this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40, 38, 9, 13, 27]);
+            if (!this.shown && e.keyCode == 40) {
+                this.lookup();
+            } else {
+                this.move(e);
+            }
+        },
+
+        keypress: function (e) {
+            if (this.suppressKeyPressRepeat) {
+                return;
+            }
+            this.move(e);
+        },
+
+        input: function (e) {
+            // This is a fixed for IE10/11 that fires the input event when a placehoder is changed
+            // (https://connect.microsoft.com/IE/feedback/details/810538/ie-11-fires-input-event-on-focus)
+            var currentValue = this.$element.val() || this.$element.text();
+            if (this.value !== currentValue) {
+                this.value = currentValue;
+                this.lookup();
+            }
+        },
+
+        keyup: function (e) {
+            if (this.destroyed) {
+                return;
+            }
+            switch (e.keyCode) {
+                case 40: // down arrow
+                case 38: // up arrow
+                case 16: // shift
+                case 17: // ctrl
+                case 18: // alt
+                    break;
+
+                case 9: // tab
+                    if (!this.shown || (this.showHintOnFocus && !this.keyPressed)) {
+                        return;
+                    }
+                    this.select();
+                    break;
+                case 13: // enter
+                    if (!this.shown) {
+                        return;
+                    }
+                    this.select();
+                    break;
+
+                case 27: // escape
+                    if (!this.shown) {
+                        return;
+                    }
+                    this.hide();
+                    break;
+            }
+
+        },
+
+        focus: function (e) {
+            if (!this.focused) {
+                this.focused = true;
+                this.keyPressed = false;
+                if (this.options.showHintOnFocus && this.skipShowHintOnFocus !== true) {
+                    if (this.options.showHintOnFocus === 'all') {
+                        this.lookup('');
+                    } else {
+                        this.lookup();
+                    }
+                }
+            }
+            if (this.skipShowHintOnFocus) {
+                this.skipShowHintOnFocus = false;
+            }
+        },
+
+        blur: function (e) {
+            if (!this.mousedover && !this.mouseddown && this.shown) {
+                if (this.selectOnBlur) {
+                    this.select();
+                }
+                this.hide();
+                this.focused = false;
+                this.keyPressed = false;
+            } else if (this.mouseddown) {
+                // This is for IE that blurs the input when user clicks on scroll.
+                // We set the focus back on the input and prevent the lookup to occur again
+                this.skipShowHintOnFocus = true;
+                this.$element.focus();
+                this.mouseddown = false;
+            }
+        },
+
+        click: function (e) {
+            e.preventDefault();
+            this.skipShowHintOnFocus = true;
+            this.select();
+            this.$element.focus();
+            this.hide();
+        },
+
+        mouseenter: function (e) {
+            this.mousedover = true;
+            this.$menu.find('.active').removeClass('active');
+            $(e.currentTarget).addClass('active');
+        },
+
+        mouseleave: function (e) {
+            this.mousedover = false;
+            if (!this.focused && this.shown) {
+                this.hide();
+            }
+        },
+
+        /**
+         * We track the mousedown for IE. When clicking on the menu scrollbar, IE makes the input blur thus hiding the menu.
+         */
+        mousedown: function (e) {
+            this.mouseddown = true;
+            this.$menu.one('mouseup', function (e) {
+                // IE won't fire this, but FF and Chrome will so we reset our flag for them here
+                this.mouseddown = false;
+            }.bind(this));
+        },
+
+        touchstart: function (e) {
+            e.preventDefault();
+            this.$menu.find('.active').removeClass('active');
+            $(e.currentTarget).addClass('active');
+        },
+
+        touchend: function (e) {
+            e.preventDefault();
+            this.select();
+            this.$element.focus();
+        }
+
+    };
+
+
+    /* TYPEAHEAD PLUGIN DEFINITION
+     * =========================== */
+
+    var old = $.fn.typeahead;
+
+    $.fn.typeahead = function (option) {
+        var arg = arguments;
+        if (typeof option == 'string' && option == 'getActive') {
+            return this.data('active');
+        }
+        return this.each(function () {
+            var $this = $(this);
+            var data = $this.data('typeahead');
+            var options = typeof option == 'object' && option;
+            if (!data) {
+                $this.data('typeahead', (data = new Typeahead(this, options)));
+            }
+            if (typeof option == 'string' && data[option]) {
+                if (arg.length > 1) {
+                    data[option].apply(data, Array.prototype.slice.call(arg, 1));
+                } else {
+                    data[option]();
+                }
+            }
+        });
+    };
+
+    Typeahead.defaults = {
+        source: [],
+        items: 8,
+        minLength: 1,
+        scrollHeight: 0,
+        autoSelect: true,
+        afterSelect: $.noop,
+        afterEmptySelect: $.noop,
+        addItem: false,
+        followLinkOnSelect: false,
+        delay: 0,
+        separator: 'category',
+        changeInputOnSelect: true,
+        changeInputOnMove: true,
+        openLinkInNewTab: false,
+        selectOnBlur: true,
+        showCategoryHeader: true,
+        theme: "bootstrap3",
+        themes: {
+        bootstrap3: {
+            menu: '<ul class="typeahead dropdown-menu" role="listbox"></ul>',
+            item: '<li><a class="dropdown-item" href="#" role="option"></a></li>',
+            itemContentSelector: "a",
+            headerHtml: '<li class="dropdown-header"></li>',
+            headerDivider: '<li class="divider" role="separator"></li>'
+        },
+        bootstrap4: {
+            menu: '<div class="typeahead dropdown-menu" role="listbox"></div>',
+            item: '<button class="dropdown-item" role="option"></button>',
+            itemContentSelector: '.dropdown-item',
+            headerHtml: '<h6 class="dropdown-header"></h6>',
+            headerDivider: '<div class="dropdown-divider"></div>'
+        }
+    }
+};
+
+    $.fn.typeahead.Constructor = Typeahead;
+
+    /* TYPEAHEAD NO CONFLICT
+     * =================== */
+
+    $.fn.typeahead.noConflict = function () {
+        $.fn.typeahead = old;
+        return this;
+    };
+
+
+    /* TYPEAHEAD DATA-API
+     * ================== */
+
+    $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
+        var $this = $(this);
+        if ($this.data('typeahead')) {
+            return;
+        }
+        $this.typeahead($this.data());
+    });
+
+}));

+ 10 - 6
src/web/templates/com/header.html

@@ -82,15 +82,19 @@
 				    <label class="col-sm-2 control-label">角色:</label>
 				    <div class="col-sm-10">
 				     	<select id="t_role" class="form-control" disabled>
-							<option value={{(session "user").role}}>
+							<option value={{(session "user").i_role}}>
 							<script>
-								role={{(session "user").role}};
-								if(role===2){
-									document.write("开发员")
-								}else if(role=="1"){
+								role={{(session "user").i_role}}
+								if (role === "0") {
+									document.write("超级管理员")
+								}else if(role === "1"){
+									document.write("系统管理员")
+								}else if(role === "2"){
 									document.write("管理员")
+								}else if(role === "3"){
+									document.write("质检员")
 								}else{
-									document.write("系统管理员")
+									document.write("普通用户")
 								}
 							</script>
 							</option>

+ 1 - 0
src/web/templates/com/inc.html

@@ -38,5 +38,6 @@
 	<script src="/js/bootstrap-select.min.js"></script>
 	<script src="/js/model.js"></script>
 	<script src="/js/com.js"></script>
+	<script src="/js/bootstrap3-typeahead.js"></script>
 </head>
 <body class="hold-transition skin-blue sidebar-mini">

+ 163 - 82
src/web/templates/project/project_clear.html

@@ -22,48 +22,49 @@
 
                         <div class="form-horizontal">
                             <div class="box-body margin">
-                                <h3><i class="glyphicon glyphicon-exclamation-sign" style="margin-right: 6px"></i>数据情况
-                                </h3>
+                                <h4><i class="glyphicon glyphicon-exclamation-sign" style="margin-right: 6px"></i>数据情况</h4>
                                 <div class="form-group" style="margin-left: 15px">
                                     <span class="form-inline panel-body">分发总量/数据总量(条):
                                         <input type="text" class="form-control" readonly value="{{.T.allGiveDataNum}}/{{.T.allDataNum}}">
                                     </span>
                                 </div>
                                 <div class="form-group" style="margin-left: 10px">
-                                    <div class="col-xs-6" style="width: auto">
+                                    <div class="col-xs-3" style="width: auto">
                                         <label class="form-inline">数据总量:
                                         <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已分发:
+                                        <label class="form-inline" style="margin-left: 5px">已分发:
                                         <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">待分发:
+                                        <label class="form-inline" style="margin-left: 5px">待分发:
                                         <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allNoGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已标注:
+                                        <label class="form-inline" style="margin-left: 5px">已标注:
                                         <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allIsTagDataNum}}"></label>
                                     </div>
-                                    <div class="col-xs-3 form-group">
-                                        <label class="form-inline">操作:
-                                            <input type="button" class="btn btn-info" onclick="dispatchTak('all')" value="分发">
-                                            <input type="button" class="btn btn-primary" value="质检">
-                                            <input type="button" class="btn btn-success" value="质检结果">
+                                    <div class="col-xs-5 form-group">
+                                        <label class="form-inline">&nbsp;操作:
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="" value="标注">
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="dispatchTask('all')" value="分发">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检结果">
                                         </label>
                                     </div>
                                 </div>
                                 <div class="form-group" style="margin-left: 10px">
                                     <div class="col-xs-6" style="width: auto">
-                                        <label class="form-inline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;达标:
+                                        <label class="form-inline">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;达标:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.okAllDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已分发:
+                                        <label class="form-inline" style="margin-left: 5px">已分发:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.okIsGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">待分发:
+                                        <label class="form-inline" style="margin-left: 5px">待分发:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.okNotGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已标注:
+                                        <label class="form-inline" style="margin-left: 5px">已标注:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.okIsTagDataNum}}"></label>
                                     </div>
-                                    <div class="col-xs-3 form-group">
+                                    <div class="col-xs-5 form-group">
                                         <label class="form-inline">操作:
-                                            <input type="button" class="btn btn-info" onclick="dispatchTak('notag')" value="分发">
-                                            <input type="button" class="btn btn-primary" value="质检">
-                                            <input type="button" class="btn btn-success" value="质检结果">
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="" value="标注">
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="dispatchTask('notag')" value="分发">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检结果">
                                         </label>
                                     </div>
                                 </div>
@@ -71,25 +72,32 @@
                                     <div class="col-xs-6" style="width: auto">
                                         <label class="form-inline">&nbsp;&nbsp;&nbsp;&nbsp;未达标:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.IsNoOkAllDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已分发:
+                                        <label class="form-inline" style="margin-left: 5px">已分发:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.IsNoOkIsGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">待分发:
+                                        <label class="form-inline" style="margin-left: 5px">待分发:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.IsNotOkNotGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已标注:
+                                        <label class="form-inline" style="margin-left: 5px">已标注:
                                             <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.IsNotOkIsTagDataNum}}"></label>
                                     </div>
-                                    <div class="col-xs-3 form-group">
+                                    <div class="col-xs-5 form-group">
                                         <label class="form-inline">操作:
-                                            <input type="button" class="btn btn-info" onclick="dispatchTak('tag')" value="分发">
-                                            <input type="button" class="btn btn-primary" value="质检">
-                                            <input type="button" class="btn btn-success" value="质检结果">
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="" value="标注">
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="dispatchTask('tag')" value="分发">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检结果">
                                         </label>
                                     </div>
                                 </div>
 
                             </div>
                         </div>
-
+                        <div id="status-div" class="col-xs-1" style="width: auto;float:right;">
+                            <select class="form-control selectpicker" id="pushModelSelect">
+                                <option value=-1>全部</option>
+                                <option value=0>开启</option>
+                                <option value=1>关闭</option>
+                            </select>
+                        </div>
                         <hr>
                         <div class="form-horizontal">
                             <div class="box-body margin">
@@ -99,7 +107,7 @@
                                 <table id="dataTable" class="table table-bordered table-hover">
                                     <thead>
                                     <tr>
-                                        <th></th>
+                                        <th>序号</th>
                                         <th>项目名称</th>
                                         <th>用户组名称</th>
                                         <th>负责人</th>
@@ -138,25 +146,22 @@
                             <div class="modal-body modal-task">
                                 <div class="form-group margin-bottom" style="margin-left: 15px">
                                     <label class="control-label form-inline h4">待分发数据总量(条):
-                                        <span>0</span>
+                                        <span id="modal-num">0</span>
                                     </label>
                                 </div>
                                 <hr>
-                                <div style="margin-left: 15px;">
-                                    <label>分发信息:</label>
-                                    <input type="button" class="btn btn-info btn-sm" onclick="addTaskSelect()" value="新增">
-                                </div>
                                 <div></div>
                                 <div id="TaskDiv">
                                     <div id="itemDiv" class="form-group" style="margin-left: 10px;display: none">
                                         <select id="group-select-clone"></select>
                                         <label class="control-label form-inline" style="margin-left: 20px">数据量(条):
-                                            <input type="number" class="form-control" required></label>
+                                            <input type="number" class="form-control"></label>
                                     </div>
-                                    <div class="form-group itemDiv" style="margin-left: 10px;">
+                                    <div class="form-group group-item" style="margin-left: 10px;">
                                         <select class="selectpicker" id="group-select"></select>
                                         <label class="control-label form-inline" style="margin-left: 20px">数据量(条):
-                                            <input type="number" class="form-control by-use" required></label>
+                                            <input type="number" class="form-control"></label>
+                                        <input type="button" class="btn btn-info btn-sm" onclick="addTaskSelect()" value="新增">
                                     </div>
                                 </div>
                             </div>
@@ -206,26 +211,48 @@
                 });
             },
             "columns": [
-                {"data": "", width: "1%"},
-                {"data": "s_entname", width: "5%"},
-                {"data": "s_departname", width: "4%"},
-                {"data": "s_rulename", width: "4%"},
-                {"data": "s_name", width: "4%"},
+                {"data": null, width: "1%"},
+                {"data": "s_projectname", width: "5%"},
+                {"data": "s_groupname", width: "4%"},
                 {"data": "s_personname", width: "4%"},
-                {"data": "i_importnum", width: "4%"},
+                {"data": "i_givenum", width: "4%"},
                 {"data": "s_status", width: "4%"},
+                {"data": "s_progress", width: "4%"},
+                {
+                    "data": "_id", width: "4%", render: function (val, a, row) {
+                        let str = ""
+                        if (row['i_starttime'] === undefined) {
+                            str = "未开始"
+                        }else if (row['i_starttime'] && row['i_completetime'] === undefined) {
+                            let dt = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            str = dt.format("yyyy-MM-dd hh:mm:ss") + " - 未结束"
+                        }else {
+                            let dt = new Date()
+                            let ds = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            ds.setTime(parseInt(row["i_completetime"]) * 1000)
+                            str = dt.format("yyyy-MM-dd hh:mm:ss") + " - " + ds.format("yyyy-MM-dd hh:mm:ss")
+                        }
+                        return str
+                    }
+                },
                 {
                     "data": "_id", width: "11%", render: function (val, a, row, pos) {
                         tmp = '<div>' +
-                            '<a class="btn btn-sm btn-primary" onclick="editPro(\'' + pos.row + '\')">编辑</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-warning" href="/front/project/clear?pid=' + val + '">清洗</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-info" onclick="del(\'' + val + '\')">判重</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-default" href="">完成</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-primary" href="/front/user/task/list?grouptaskid=' + val + '&s_sourceinfo='+row.s_sourceinfo+'">查看</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-warning" onclick="retrieveTask(\''+val+'\',\''+row.s_sourceinfo+'\',\''+row.s_status+'\')">收回</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info">质检</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info" onclick="repulseTask(\''+val+'\',\''+row.s_sourceinfo+'\',\''+row.s_status+'\')">打回</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-default" onclick="closeTask(\'' + val + '\',\''+row.s_sourceinfo+'\',\'' + row.s_status + '\')">关闭</a>&nbsp;&nbsp;' +
                             '</div>';
                         return tmp
                     }
                 }
-            ]
+            ],
+            "initComplete": function () {
+                $("#dataTable_filter").append($('#status-div'))
+            }
         });
 
         $.ajax({
@@ -234,6 +261,7 @@
             data: {"pid": projectid},
             success: function (r) {
                 if (r.data.length > 0) {
+                    console.log(r.data)
                     ttable.fnClearTable();
                     ttable.fnAddData(r.data);
                 }
@@ -252,25 +280,16 @@
         })
     });
 
-    function del(id) {
-        showConfirm("确定删除该用户组?", function () {
-            $.ajax({
-                url: "",
-                type: 'POST',
-                data: {"id": id},
-                success: function (r) {
-                    if (r.rep) {
-
-                    } else {
-                        showTip("状态修改失败");
-                    }
-                }
-            })
-        })
-    }
-
-    function dispatchTak(val) {
+    function dispatchTask(val) {
+        console.log(val)
         stype = val
+        if (stype === "all") {
+            $('#modal-num').val({{.T.allGiveDataNum}})
+        }else if (stype === "notag") {
+            $('#modal-num').val({{.T.okNotGiveDataNum}})
+        }else {
+            $('#modal-num').val({{.T.IsNotOkNotGiveDataNum}})
+        }
         $('#modal-create-task').modal('show')
         for (var i in groupList) {
             var opt = document.createElement('option');
@@ -279,17 +298,16 @@
             $('#group-select')[0].appendChild(opt)
         }
         $("#group-select").selectpicker("refresh");
-        console.log(val)
     }
 
     function cancelModel() {
-        $('#TaskDiv .form-group .clone-template').remove()
+        $('#TaskDiv .group-item.clone-template').remove()
         $("#modal-create-task").modal('hide')
         document.getElementById("modal-form-task").reset();
     }
 
     function addTaskSelect() {
-        let tNode = $('#itemDiv').clone().addClass('clone-template').addClass('used').show()
+        let tNode = $('#itemDiv').clone().addClass('group-item').addClass('clone-template').show()
         let st = $(tNode).find('select')
         $(st).addClass('selectpicker')
         for (var i in groupList) {
@@ -303,24 +321,27 @@
     }
 
     function saveTask() {
-        console.log(stype)
-        $('#TaskDiv select').each(function () {
-            let ms = $(this).find("option:checked").val()
-            console.log(ms)
-        })
-
-        $('#TaskDiv input').each(function () {
-            let ms = $(this).val()
-            console.log(ms)
-        })
-
         let arr = []
-        arr.push({"s_groupid": "61a47d76c908d368871f5033", "s_groupname": "ceshi", "s_personname": "111", "i_givenum": 100})
-        console.log(JSON.stringify(arr))
+        $('.group-item').each(function () {
+            var selectId = $(this).find("select option:checked").val()
+            var inputVal = $(this).find("input").val()
+            let tmp = {}
+            for (let v in groupList) {
+                if (groupList[v]["_id"] === selectId) {
+                    tmp["s_groupid"] = selectId
+                    tmp["s_groupname"] = groupList[v]["s_name"]
+                    tmp["s_personname"] = groupList[v]["s_personname"]
+                    tmp["i_givenum"] = inputVal
+                    break
+                }
+            }
+            arr.push(tmp)
+        })
+        console.log(arr)
         $.ajax({
             url: "/front/project/task/save",
             type: 'POST',
-            data: {"s_projectid": projectid, "s_group": JSON.stringify(arr), "s_type": stype},
+                data: {"s_projectid": projectid, "s_group": JSON.stringify(arr), "s_type": stype},
             success: function (r) {
                 if (r.success) {
                     location.reload()
@@ -331,4 +352,64 @@
         })
     }
 
+    // 收回
+    function retrieveTask(id, sourceinfo, status,givenum) {
+        if (status === "未开始" || status === "进行中") {
+            $.ajax({
+                url: "/front/project/task/retrieve",
+                type: 'POST',
+                data: { "s_sourceinfo": sourceinfo, "taskid": id, "s_status": status,"i_givenum" :givenum},
+                success: function (r) {
+                    if (r.success) {
+                        location.reload()
+                    } else {
+                        showTip(r.msg);
+                    }
+                }
+            })
+        }else {
+            showTip("操作不允许")
+        }
+    }
+
+    // 打回
+    function repulseTask(id, sourceinfo,status) {
+        if (status === "已完成") {
+            $.ajax({
+                url: "/front/project/task/repulse",
+                type: 'POST',
+                data: {"s_sourceinfo": sourceinfo, "taskid": id, "s_tatus": status},
+                success: function (r) {
+                    if (r.success) {
+                        location.reload()
+                    } else {
+                        showTip(r.msg);
+                    }
+                }
+            })
+        }else {
+            showTip("操作不允许")
+        }
+    }
+
+    function closeTask(id, sourceinfo,status) {
+        if (status === "未开始") {
+            showConfirm("确认要关闭当前任务吗?", function () {
+                $.ajax({
+                    url: "/front/project/task/close",
+                    type: 'POST',
+                    data: {"s_sourceinfo": sourceinfo, "s_status": status, "taskid": id},
+                    success: function (r) {
+                        if (r.success) {
+                            location.reload()
+                        } else {
+                            showTip(r.msg);
+                        }
+                    }
+                })
+            })
+        }else {
+            showTip("操作不允许")
+        }
+    }
 </script>

+ 120 - 69
src/web/templates/project/project_list.html

@@ -19,16 +19,12 @@
                 <div class="box">
                     <div class="box-body">
 
-                        <div class="form-horizontal">
-                            <div class="box-body">
-                                <div class="form-group" style="margin-left: 20px">
-                                    <a class="btn btn-sm btn-success h4" onclick="createPro()"><i
-                                            class="fa fa-fw fa-plus fa-lg"></i>新建项目</a>
-                                </div>
-                            </div>
+                        <div class="form-group" style="margin-left: 20px">
+                            <a class="btn btn-sm btn-success h4" onclick="createPro()"><i
+                                    class="fa fa-fw fa-plus fa-lg"></i>新建项目</a>
                         </div>
-                        <div class="col-xs-12">
-                            <select class="selectpicker" id="pushModelSelect">
+                        <div id="status-div" class="col-xs-1" style="width: auto;float: right">
+                            <select class="form-control selectpicker" id="pushModelSelect">
                                 <option value=-1>全部</option>
                                 <option value=0>开启</option>
                                 <option value=1>关闭</option>
@@ -37,7 +33,7 @@
                         <table id="dataTable" class="table table-bordered table-hover">
                             <thead>
                             <tr>
-                                <th></th>
+                                <th>序号</th>
                                 <th>公司名称</th>
                                 <th>部门名称</th>
                                 <th>规则名称</th>
@@ -45,7 +41,6 @@
                                 <th>售后人员</th>
                                 <th>数据量</th>
                                 <th>项目状态</th>
-                                <th>完成进度</th>
                                 <th>项目时间</th>
                                 <th>操作</th>
                             </tr>
@@ -60,9 +55,8 @@
     </section>
 </div>
 
-
 <div class="modal fade" id="modal-create-project" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog" style="width: 30%">
+    <div class="modal-dialog" style="width: 50%">
         <div class="modal-content">
             <div class="modal-header">
                 <div class="modal-header">
@@ -121,11 +115,11 @@
                                     <h5><i class="glyphicon glyphicon-bookmark"
                                            style="color: #00c4ff;margin-right: 6px"></i>数据信息</h5>
                                     <div class="form-group">
-                                        <label class="col-sm-3 control-label"><span
-                                                style="color:red;">* </span>公司名称</label>
+                                        <label class="col-sm-3 control-label"><span style="color:red;">* </span>公司名称</label>
+                                        <ul class="dropdown-menu"> </ul>
                                         <div class="col-sm-6">
-                                            <input type="text" class="form-control" id="company-name"
-                                                   placeholder="公司名称">
+                                            <input type="text" class="form-control" id="company-name" autocomplete="off"
+                                                   data-provide="typeahead" placeholder="公司名称">
                                         </div>
                                     </div>
                                     <div class="form-group">
@@ -174,9 +168,8 @@
     </div><!-- /.modal -->
 </div>
 
-
 <div class="modal fade" id="modal-edit-project" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog" style="width: 30%">
+    <div class="modal-dialog" style="width: 50%">
         <div class="modal-content">
             <div class="modal-header">
                 <div class="modal-header">
@@ -233,7 +226,6 @@
     </div><!-- /.modal -->
 </div>
 
-
 {{include "com/footer.html"}}
 <script>
     menuActive("project");
@@ -273,34 +265,52 @@
                 });
             },
             "columns": [
-                {"data": "", width: "1%"},
+                {"data": null, width: "2%"},
                 {"data": "s_entname", width: "5%"},
                 {"data": "s_departname", width: "4%"},
                 {"data": "s_rulename", width: "4%"},
                 {"data": "s_name", width: "4%"},
-                {"data": "s_personname", width: "4%"},
-                {"data": "i_importnum", width: "4%"},
+                {"data": "s_personname", width: "3%", "defaultContent": ""},
+                {"data": "i_importnum", width: "2%"},
                 {"data": "s_status", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
+                {
+                    "data": "_id", width: "5%", render: function (val, a, row) {
+                        let str = ""
+                        if (row['i_starttime'] === undefined) {
+                            str = "未开始"
+                        }else if (row['i_starttime'] && row['i_completetime'] === undefined) {
+                            let dt = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            str = dt.format("yyyy-MM-dd hh:mm:ss") + " - 未结束"
+                        }else {
+                            let dt = new Date()
+                            let ds = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            ds.setTime(parseInt(row["i_completetime"]) * 1000)
+                            str = dt.format("yyyy-MM-dd hh:mm:ss") + " - " + ds.format("yyyy-MM-dd hh:mm:ss")
+                        }
+                        return str
+                    }
+                },
                 {
                     "data": "_id", width: "11%", render: function (val, a, row, pos) {
                         tmp = '<div>' +
                             '<a class="btn btn-sm btn-primary" onclick="editPro(\'' + pos.row + '\')">编辑</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-warning" href="/front/project/task/list?pid=' + val + '">清洗</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-info" onclick="del(\'' + val + '\')">判重</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-warning" onclick="clearPro(\''+ pos.row +'\')">清洗</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info" onclick="">质检</a>&nbsp;&nbsp;' +
                             '<a class="btn btn-sm btn-default" href="">完成</a>&nbsp;&nbsp;<br>' +
-                            '<div style="margin-top: 5px">' +
                             '<a class="btn btn-sm btn-primary" href="">上传</a>&nbsp;&nbsp;' +
                             '<a class="btn btn-sm btn-primary" href="">下载</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-primary" href="">扣费</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-danger" href="">删除</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-primary" href="">质检结果</a>&nbsp;&nbsp;' +
                             '</div></div>';
                         return tmp
                     }
                 }
-            ]
-        });
+            ],
+            "initComplete": function () {
+                $("#dataTable_filter").append($('#status-div'))
+            }
+        })
 
         $('input[type=radio][name=stype]').change(function () {
             if (this.value === 'coll') {
@@ -321,25 +331,20 @@
             $('#markFieldSelect')[0].appendChild(opt)
         }
         $("#markFieldSelect").selectpicker("refresh");
-    });
-
 
-    function del(id) {
-        showConfirm("确定删除该用户组?", function () {
-            $.ajax({
-                url: "",
-                type: 'POST',
-                data: {"id": id},
-                success: function (r) {
-                    if (r.rep) {
-                        ttable.ajax.reload();
-                    } else {
-                        showTip("状态修改失败");
-                    }
-                }
-            })
-        })
-    }
+        $("#company-name").typeahead({
+            source: function (query, process) {
+                return $.ajax({
+                    url: '/front/project/getEntnameList',
+                    type: 'post',
+                    data: {'entname': query},
+                    success: function (result) {
+                        return process(result.entname);
+                    },
+                });
+            }
+        });
+    });
 
     function createPro() {
        $("#modal-create-project").modal('show')
@@ -352,30 +357,43 @@
     }
 
     function importData() {
+        let sname = $('#project-name').val()
+        let dataid = $('#data-id').val()
+        let coll = $('#coll-save-name').val()
+        if (sname === "") {
+            alert("项目名称为必填项")
+        }
+        if (dataid === "") {
+            alert("数据导出ID为必填项")
+        }
+        if (coll === "") {
+            alert("数据导出ID为必填项")
+        }
         if (stype === "coll") {
-            projectmap["s_name"] = $('#project-name').val()
-            projectmap["s_sourceinfo"] = $('#coll-save-name').val()
+            projectmap["s_name"] = sname
+            projectmap["s_historyid"] = dataid
+            projectmap["s_sourceinfo"] = coll
+            if (projectmap["s_sourceinfo"] === "") {
+                alert("数据表名为必填项")
+            }
             projectmap["s_type"] = stype
-            projectmap["s_historyid"] = $('#data-id').val()
             $.ajax({
                 url: "/front/project/save",
                 type: 'POST',
                 data: projectmap,
                 success: function (r) {
                     if (r.success) {
-
                         $("#modal-create-project").modal('hide')
                         ttable.api().ajax.reload();
                     } else {
-
+                        showTip(r.msg)
                     }
                 }
             })
         } else if (stype === "excel") {
             let formData = new FormData();
-            formData.append("s_name", $('#project-name').val())
-            formData.append("s_sourceinfo", $('#coll-save-name').val())
-            formData.append("s_historyid", $('#data-id').val())
+            formData.append("s_name", sname)
+            formData.append("s_sourceinfo", coll)
             formData.append("s_entname", $('#company-name').val())
             formData.append("s_departname", $('#dpart-name').val())
             formData.append("s_rulename", $('#rule-name').val())
@@ -407,19 +425,29 @@
 
     function editPro(index) {
         projectmap = ttable.fnGetData()[index]
-        console.log(projectmap)
+        console.log(projectmap.v_fields)
         $('#modal-edit-project').modal('show')
         $('#company-edit-name').val(projectmap["s_entname"])
         $('#rule-edit-name').val(projectmap["s_rulename"])
         $('#dpart-edit-name').val(projectmap["s_departname"])
+        if (projectmap.v_fields !== undefined) {
+            $('#markFieldSelect option').each(function(){
+                let v = $(this).val()
+                if (projectmap.v_fields[v] !== undefined) {
+                    $(this)[0].selected = true
+                }
+            })
+            $("#markFieldSelect").selectpicker("refresh");
+        }
     }
 
     function saveData() {
         stype = "edit"
+        let s1 = JSON.stringify(projectmap)
         let tmp = projectmap
-        tmp["s_entname"] = $('#company-edit-name').val()
-        tmp["s_rulename"] = $('#rule-edit-name').val()
         tmp["s_departname"] = $('#dpart-edit-name').val()
+        tmp["s_rulename"] = $('#rule-edit-name').val()
+        tmp["s_personname"] = $('#edit-person').val()
 
         let fieldArr = $('#markFieldSelect').val();
         let m = {}
@@ -430,23 +458,46 @@
                 }
             }
         }
-        tmp["v_field"] = m
-        if (tmp !== projectmap) {
+        tmp["v_fields"] = JSON.stringify(m)
+        if (s1 === JSON.stringify(tmp)) {
+            showTip("未做修改");
+        } else {
             $.ajax({
-                url: "/front/project/task/save",
+                url: "/front/project/save",
                 type: 'POST',
-                data: projectmap,
+                data: {"s_type": stype, "s_departname": tmp["s_departname"], "s_personname": tmp["s_personname"],
+                    "s_rulename": tmp["s_rulename"], "v_fields": tmp["v_fields"], "s_name": tmp["s_name"]},
                 success: function (r) {
-                    if (r.rep) {
+                    if (r.success) {
+                        showTip("保存成功", 1000)
+                        cancelModel()
                         ttable.api().ajax.reload();
                     } else {
-                        showTip("保存失败");
+                        showTip(r.msg);
                     }
                 }
             })
-        } else {
-            showTip("未做修改");
         }
     }
 
+    function clearPro(val) {
+        let tmp = ttable.fnGetData()[val]
+        if (tmp["v_fields"] === undefined) {
+            showTip("请设置标注字段")
+        }else {
+            $.ajax({
+                url: "/front/project/qualityAssessment",
+                type: 'POST',
+                data: {"pid": tmp["_id"]},
+                success: function (r) {
+                    if (r.success) {
+                        window.location.href="/front/project/task/list?pid=" + tmp["_id"]
+                    } else {
+                        showTip(r.msg);
+                    }
+                }
+            })
+        }
+
+    }
 </script>

+ 416 - 0
src/web/templates/project/task_detail.html

@@ -0,0 +1,416 @@
+{{include "com/inc.html"}}
+<!-- Main Header -->
+{{include "com/header.html"}}
+<!-- Left side column. 权限菜单 -->
+{{include "com/menu.html"}}
+<div class="content-wrapper">
+    <section class="content-header">
+        <h1>
+            <small></small>
+        </h1>
+        <ol class="breadcrumb">
+            <li><a href="#"><i class="fa fa-dashboard"></i> 任务列表</a></li>
+        </ol>
+    </section>
+    <!-- Main content -->
+    <section class="content">
+        <div class="row">
+            <div class="col-xs-12">
+                <div class="box">
+                    <div class="box-body">
+
+                        <div class="form-horizontal">
+                            <div class="box-body margin">
+                                <h4><i class="glyphicon glyphicon-exclamation-sign" style="margin-right: 6px"></i>数据情况</h4>
+                                <div class="form-group" style="margin-left: 10px;margin-top: 10px">
+                                    <div class="col-xs-5" style="width: auto">
+                                        <label class="form-inline">数据总量:
+                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allNum}}"></label>
+                                        <label class="form-inline" style="margin-left: 5px">已分发:
+                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.isGiveNum}}"></label>
+                                        <label class="form-inline" style="margin-left: 5px">待分发:
+                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.isNotGiveNum}}"></label>
+                                        <label class="form-inline" style="margin-left: 5px">已标注:
+                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.isTagNum}}"></label>
+                                        <label class="form-inline" style="margin-left: 5px">未标注:
+                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.isNotTagNum}}"></label>
+                                    </div>
+                                    <div class="col-xs-4 form-group">
+                                        <label class="form-inline">操作:
+                                            <input type="button" class="btn btn-sm btn-primary" onclick="dispatchTask('0')" value="分发">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检">
+                                            <input type="button" class="btn btn-sm btn-primary" value="质检结果">
+                                        </label>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <hr>
+                        <div id="status-div" class="col-xs-1" style="width: auto;float: right">
+                            <select class="form-control selectpicker" id="pushModelSelect">
+                                <option value=-1>全部</option>
+                                <option value=0>开启</option>
+                                <option value=1>关闭</option>
+                            </select>
+                        </div>
+                        <div class="form-horizontal">
+                            <div class="box-body margin">
+                                <h4><i class="glyphicon glyphicon-tasks" style="margin-right: 6px"></i>数据清洗任务列表</h4>
+
+                                <table id="dataTable" class="table table-bordered table-hover">
+                                    <thead>
+                                    <tr>
+                                        <th></th>
+                                        <th>用户账号</th>
+                                        <th>项目名称</th>
+                                        <th>数据量</th>
+                                        <th>任务状态</th>
+                                        <th>完成进度</th>
+                                        <th>开始时间</th>
+                                        <th>完成时间</th>
+                                        <th>操作</th>
+                                    </tr>
+                                    </thead>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+                    <!-- /.box-body -->
+                </div>
+                <!-- /.box -->
+            </div>
+        </div>
+    </section>
+</div>
+
+
+<div class="modal fade" id="modal-create-task" tabindex="-1" role="dialog" aria-hidden="true">
+    <div class="modal-dialog" style="width: 60%">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                    <div class="edit-info">
+                        <span class="glyphicon glyphicon-tasks" aria-hidden="true"></span>
+                        <span class="h3">新建任务</span>
+                    </div>
+                    <div class="edit-form">
+                        <form id="modal-form-task" class="form-horizontal">
+                            <div class="modal-body modal-task">
+                                <div class="form-group margin-bottom" style="margin-left: 15px">
+                                    <label class="control-label form-inline h4">待分发数据总量(条):
+                                        <span id="modal-num">{{.T.isNotGiveNum}}</span>
+                                    </label>
+                                </div>
+                                <hr>
+                                <div class="form-group" style="margin-left: 15px">
+                                    <label class="radio-inline">
+                                        <input type="radio" name="stype" value="man" checked>手动分发
+                                    </label>
+                                    <label class="radio-inline">
+                                        <input type="radio" name="stype" value="auto">自动分发
+                                    </label>
+                                </div>
+                                <div id="task-man">
+                                    <div id="TaskDiv">
+                                        <div id="itemDiv" class="form-group" style="margin-left: 10px;display: none">
+                                            <select id="group-select-clone"></select>
+                                            <label class="control-label form-inline" style="margin-left: 20px">数据量(条):
+                                                <input type="number" class="form-control"></label>
+                                        </div>
+                                        <div class="form-group group-item" style="margin-left: 10px;">
+                                            <select class="selectpicker" id="group-select"></select>
+                                            <label class="control-label form-inline" style="margin-left: 20px">数据量(条):
+                                                <input type="number" class="form-control"></label>
+                                            <input type="button" class="btn btn-info btn-sm" onclick="addTaskSelect()" value="新增">
+                                        </div>
+                                    </div>
+                                </div>
+                                <div id="task-auto" style="display: none">
+                                    <label class="control-label form-inline" style="margin-left: 20px">用户数量:
+                                        <input type="number" class="form-control" id="modal-user-num"></label>
+                                    <label class="control-label form-inline" style="margin-left: 20px">分配总量(条):
+                                        <input type="number" class="form-control" id="modal-data-num"></label>
+                                </div>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <input type="button" onclick="saveTask()" class="btn btn-primary" value="保存">
+                <input type="button" onclick="cancelModel()" class="btn btn-default" value="取消">
+            </div>
+        </div>
+    </div><!-- /.modal -->
+</div>
+
+{{include "com/footer.html"}}
+<script>
+    menuActive("task/list");
+
+    let grouptaskid = {{ .T.grouptaskid }}
+    let isNotGiveNum = {{ .T.isNotGiveNum }}
+    let userList = []
+    let stype = "man"
+
+    $(function () {
+        ttable = $('#dataTable').dataTable({
+            "paging": true,
+            "lengthChange": false,
+            "searching": true,
+            "ordering": false,
+            "info": true,
+            "autoWidth": false,
+            "language": {
+                "url": "/dist/js/dataTables.chinese.lang"
+            },
+            "fnDrawCallback": function () {
+                $("ul.pagination").prepend("&nbsp;&nbsp;&nbsp;转到第 <input type='text' id='changePage'   style='width:20px;'> 页    <a type='text' href='javascript:void(0);' id='dataTable-btn' style='text-align:center'>GO</a>");
+                $('#dataTable-btn').click(function (e) {
+                    var redirectpage = 0
+                    if ($("#changePage").val() && $("#changePage").val() > 0) {
+                        var redirectpage = $("#changePage").val() - 1;
+                    }
+                    ttable.page(redirectpage).draw(false);
+                });
+                this.api().column(0).nodes().each(function (cell, i) {
+                    cell.innerHTML = i + 1;
+                });
+            },
+            "columns": [
+                {"data": null, width: "1%"},
+                {"data": "s_login", width: "5%"},
+                {"data": "s_projectname", width: "4%"},
+                {"data": "i_givenum", width: "4%"},
+                {"data": "s_status", width: "4%"},
+                {"data": "s_progress", width: "4%"},
+                {"data": "i_starttime", width: "4%", render: function (val) {
+                        if (val === undefined) {
+                            return "未开始"
+                        }else {
+                            var dt = new Date()
+                            dt.setTime(parseInt(val) * 1000);
+                            return dt.format("yyyy-MM-dd hh:mm:ss")
+                        }
+                    }},
+                {"data": "i_completetime", width: "4%", render: function (val) {
+                        if (val === undefined) {
+                            return "未完成"
+                        }else {
+                            var dt = new Date()
+                            dt.setTime(parseInt(val) * 1000);
+                            return dt.format("yyyy-MM-dd hh:mm:ss")
+                        }
+                    }},
+                {
+                    "data": "_id", width: "11%", render: function (val, a, row, pos) {
+                        tmp = '<div>' +
+                            '<a class="btn btn-sm btn-primary" onclick="retrieveTask(\''+val+'\',\''+row.s_sourceinfo+'\',\''+row.s_status+'\')">收回</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-warning">质检</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info" onclick="closeTask(\'' + val + '\',\'' + row.s_status + '\',\''+row.s_sourceinfo+'\')">关闭</a>&nbsp;&nbsp;' +
+                            '</div>';
+                        return tmp
+                    }
+                }
+            ],
+            "initComplete": function () {
+                $("#dataTable_filter").append($('#status-div'))
+            }
+        });
+
+        $.ajax({
+            url: "/front/user/task/list",
+            type: "POST",
+            data: {"grouptaskid": grouptaskid, "s_status": "-1", "s_login": "-1"},
+            success: function (r) {
+                if (r.data.length > 0) {
+                    console.log(r.data)
+                    ttable.fnClearTable();
+                    ttable.fnAddData(r.data);
+                }
+            }
+        })
+        $.ajax({
+            url: "/front/group/user/list",
+            type: "POST",
+            data: {},
+            success: function (r) {
+                if (r.rep) {
+                    userList = r.data
+                }
+            }
+        })
+        $('input[type=radio][name=stype]').change(function () {
+            if (this.value === 'man') {
+                stype = "man"
+                $("#task-man").attr("style", "display:block;")
+                $("#task-auto").attr("style", "display:none;")
+            } else if (this.value === 'auto') {
+                stype = "auto"
+                $("#task-man").attr("style", "display:none;")
+                $("#task-auto").attr("style", "display:block;")
+            }
+        });
+    });
+
+    function cancelModel() {
+        $('#TaskDiv .group-item.clone-template').remove()
+        $("#modal-create-task").modal('hide')
+        document.getElementById("modal-form-task").reset();
+    }
+
+    function dispatchTask() {
+        if (isNotGiveNum === 0) {
+            showTip("没有可分发的数据")
+            return
+        }
+        $('#modal-create-task').modal('show')
+        let text = document.getElementById("modal-user-num");
+        text.setAttribute("max", userList.length.toString())
+        text.onkeyup = function(){
+            this.value=this.value.replace(/\D/g,'');
+            if(text.value > userList.length){
+                text.value = userList.length;
+            }
+        }
+        for (var i in userList) {
+            var opt = document.createElement('option');
+            opt.innerText = userList[i]["s_login"];
+            opt.value = userList[i]["_id"];
+            $('#group-select')[0].appendChild(opt)
+        }
+        $("#group-select").selectpicker("refresh");
+    }
+
+    function addTaskSelect() {
+        let tNode = $('#itemDiv').clone().addClass('group-item').addClass('clone-template').show()
+        let st = $(tNode).find('select')
+        $(st).addClass('selectpicker')
+        for (var i in userList) {
+            var opt = document.createElement('option');
+            opt.innerText = userList[i]["s_login"];
+            opt.value = userList[i]["_id"];
+            $(st)[0].appendChild(opt)
+        }
+        $(st).selectpicker("refresh");
+        $('#TaskDiv').append($(tNode))
+    }
+
+    function saveTask() {
+        let arr = []
+        if (stype === "man") {
+            $('.group-item').each(function () {
+                var selectId = $(this).find("select option:checked").val()
+                var inputVal = $(this).find("input").val()
+                console.log(selectId, inputVal)
+                if (inputVal === "") {
+                    showTip("未设置分发条数")
+                    return
+                }
+                let tmp = {}
+                for (let v in userList) {
+                    if (userList[v]["_id"] === selectId) {
+                        tmp["s_userid"] = selectId
+                        tmp["s_login"] = userList[v]["s_login"]
+                        tmp["s_name"] = userList[v]["s_name"]
+                        tmp["i_givenum"] = inputVal
+                        break
+                    }
+                }
+                arr.push(tmp)
+            })
+        }else if (stype === "auto") {
+            let userNum = parseInt($('#modal-user-num').val())
+            let dataNum = parseInt($('#modal-data-num').val())
+            if (userNum > 0 && dataNum > 0 && dataNum >= userNum) {
+                if (dataNum%userNum === 0) {
+                    // 整除
+                    let avg = dataNum/userNum
+                    for (let i = 0; i < userNum; i++) {
+                        let tmp = {}
+                        tmp["s_userid"] = userList[i]["_id"]
+                        tmp["s_login"] = userList[i]["s_login"]
+                        tmp["s_name"] = userList[i]["s_name"]
+                        tmp["i_givenum"] = avg
+                        arr.push(tmp)
+                    }
+                }else {
+                    // 没有整除
+                    let quo =  Math.floor(dataNum/userNum)      // 商数
+                    let rem = dataNum%userNum                   // 余数
+                    console.log("quo---", quo, "rem---", rem)
+                    for (let i = 0; i < userNum; i++) {
+                        let tmp = {}
+                        tmp["s_userid"] = userList[i]["_id"]
+                        tmp["s_login"] = userList[i]["s_login"]
+                        tmp["s_name"] = userList[i]["s_name"]
+                        if (i === (userNum-1)) {
+                            tmp["i_givenum"] = quo + rem
+                        }else {
+                            tmp["i_givenum"] = quo
+                        }
+                        arr.push(tmp)
+                    }
+                }
+            }else {
+                showTip("请设置有效数字")
+                return;
+            }
+        }
+        console.log(arr)
+        $.ajax({
+            url: "/front/user/task/save",
+            type: "POST",
+            data: {"grouptaskid": grouptaskid, "usernums": JSON.stringify(arr)},
+            success: function (r) {
+                if (r.success) {
+                    console.log(r.data)
+                    location.reload()
+                }else {
+                    showTip(r.msg)
+                }
+            }
+        })
+    }
+
+    // 收回
+    function retrieveTask(id, sourceinfo, status) {
+        if (status === "未开始" || status === "进行中") {
+            $.ajax({
+                url: "/front/user/task/retrieve",
+                type: 'POST',
+                data: {"s_sourceinfo": sourceinfo, "taskid": id, "s_status": status},
+                success: function (r) {
+                    if (r.success) {
+                        location.reload()
+                    } else {
+                        showTip(r.msg);
+                    }
+                }
+            })
+        }else {
+            showTip("操作不允许")
+        }
+    }
+    function closeTask(id, status, sourceinfo) {
+        if (status === "未开始") {
+            showConfirm("确认要关闭当前任务吗?", function () {
+                $.ajax({
+                    url: "/front/user/task/close",
+                    type: 'POST',
+                    data: {"s_sourceinfo": sourceinfo, "taskid": id, "s_status": status},
+                    success: function (r) {
+                        if (r.success) {
+                            location.reload()
+                        } else {
+                            showTip(r.msg);
+                        }
+                    }
+                })
+            })
+        }else {
+            showTip("操作不允许")
+        }
+    }
+</script>

+ 28 - 148
src/web/templates/project/task_group_list.html

@@ -18,15 +18,15 @@
             <div class="col-xs-12">
                 <div class="box">
                     <div class="box-body">
-                        <hr>
+
                         <div class="form-horizontal">
                             <div class="box-body margin">
                                 <table id="dataTable" class="table table-bordered table-hover">
                                     <thead>
                                     <tr>
                                         <th></th>
-                                        <th>用户账号</th>
                                         <th>项目名称</th>
+                                        <th>负责人</th>
                                         <th>数据量</th>
                                         <th>任务状态</th>
                                         <th>完成进度</th>
@@ -83,19 +83,36 @@
             },
             "columns": [
                 {"data": "", width: "1%"},
-                {"data": "s_personname", width: "5%"},
-                {"data": "s_projectname", width: "4%"},
+                {"data": "s_projectname", width: "5%"},
+                {"data": "s_personname", width: "4%"},
                 {"data": "i_givenum", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
+                {"data": "s_status", width: "4%"},
+                {"data": "s_progress", width: "4%"},
+                {"data": "i_starttime", width: "4%", render: function (val) {
+                        if (val === undefined) {
+                            return "未开始"
+                        }else {
+                            var dt = new Date()
+                            dt.setTime(parseInt(val) * 1000);
+                            return dt.format("yyyy-MM-dd")
+                        }
+                    }},
+                {"data": "i_completetime", width: "4%", render: function (val) {
+                        if (val === undefined) {
+                            return "未完成"
+                        }else {
+                            var dt = new Date()
+                            dt.setTime(parseInt(val) * 1000);
+                            return dt.format("yyyy-MM-dd")
+                        }
+                    }},
                 {
                     "data": "_id", width: "11%", render: function (val, a, row, pos) {
                         tmp = '<div>' +
-                            '<a class="btn btn-sm btn-primary" onclick="editPro(\'' + pos.row + '\')">收回</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-warning" href="/front/project/clear?pid=' + val + '">质检</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-info" onclick="del(\'' + val + '\')">关闭</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-primary" href="/front/user/task/save?tid=' + val + '">查看</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-warning">分发</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info">质检</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info">交付</a>&nbsp;&nbsp;' +
                             '</div>';
                         return tmp
                     }
@@ -103,143 +120,6 @@
             ]
         });
 
-        $('input[type=radio][name=stype]').change(function () {
-            if (this.value === 'coll') {
-                stype = "coll"
-                $("#import-coll").attr("style", "display:block;")
-                $("#import-excel").attr("style", "display:none;")
-            } else if (this.value === 'excel') {
-                stype = "excel"
-                $("#import-coll").attr("style", "display:none;")
-                $("#import-excel").attr("style", "display:block;")
-            }
-        });
     });
 
-
-    function del(id) {
-        showConfirm("确定删除该用户组?", function () {
-            $.ajax({
-                url: "",
-                type: 'POST',
-                data: {"id": id},
-                success: function (r) {
-                    if (r.rep) {
-                        ttable.ajax.reload();
-                    } else {
-                        showTip("状态修改失败");
-                    }
-                }
-            })
-        })
-    }
-
-    function createPro() {
-       $("#modal-create-project").modal('show')
-    }
-
-    function cancelModel() {
-        document.getElementById("model-form-project").reset();
-        $("#modal-create-project").modal('hide')
-        $("#modal-edit-project").modal('hide')
-    }
-
-    function importData() {
-        if (stype === "coll") {
-            projectmap["s_name"] = $('#project-name').val()
-            projectmap["s_sourceinfo"] = $('#coll-save-name').val()
-            projectmap["s_type"] = stype
-            projectmap["s_historyid"] = $('#data-id').val()
-            $.ajax({
-                url: "/front/project/save",
-                type: 'POST',
-                data: projectmap,
-                success: function (r) {
-                    if (r.success) {
-
-                        $("#modal-create-project").modal('hide')
-                        ttable.api().ajax.reload();
-                    } else {
-
-                    }
-                }
-            })
-        } else if (stype === "excel") {
-            let formData = new FormData();
-            formData.append("s_name", $('#project-name').val())
-            formData.append("s_sourceinfo", $('#coll-save-name').val())
-            formData.append("s_historyid", $('#data-id').val())
-            formData.append("s_entname", $('#company-name').val())
-            formData.append("s_departname", $('#dpart-name').val())
-            formData.append("s_rulename", $('#rule-name').val())
-            formData.append("s_type", stype)
-            let file = $('#uploadfile')[0].files[0]
-            if (file) {
-                formData.append("xlsx", file)
-                $.ajax({
-                    url: "/front/project/save",
-                    type: 'POST',
-                    data: formData,
-                    cache: false,
-                    processData: false,
-                    contentType: false,
-                    success: function (r) {
-                        if (r.rep) {
-                            $("#modal-create-project").modal('hide')
-                            ttable.api().ajax.reload();
-                        } else {
-                            showTip("状态修改失败");
-                        }
-                    }
-                })
-            } else {
-                showTip("请选择上传文件");
-            }
-        }
-    }
-
-    function editPro(index) {
-        projectmap = ttable.fnGetData()[index]
-        console.log(projectmap)
-        $('#modal-edit-project').modal('show')
-        $('#company-edit-name').val(projectmap["s_entname"])
-        $('#rule-edit-name').val(projectmap["s_rulename"])
-        $('#dpart-edit-name').val(projectmap["s_departname"])
-    }
-
-    function saveData() {
-        stype = "edit"
-        let tmp = projectmap
-        tmp["s_entname"] = $('#company-edit-name').val()
-        tmp["s_rulename"] = $('#rule-edit-name').val()
-        tmp["s_departname"] = $('#dpart-edit-name').val()
-
-        let fieldArr = $('#markFieldSelect').val();
-        let m = {}
-        if (fieldArr.length > 0) {
-            for (const i in fields) {
-                if (fieldArr.indexOf(fields[i]["s_code"]) > -1) {
-                    m[fields[i]["s_code"]] = fields[i]["s_name"]
-                }
-            }
-        }
-        tmp["v_field"] = m
-        if (tmp !== projectmap) {
-            $.ajax({
-                url: "/front/project/save",
-                type: 'POST',
-                data: projectmap,
-                success: function (r) {
-                    if (r.rep) {
-                        ttable.api().ajax.reload();
-                    } else {
-                        showTip("保存失败");
-                    }
-                }
-            })
-        } else {
-            showTip("未做修改");
-        }
-    }
-
 </script>

+ 106 - 364
src/web/templates/project/task_list.html

@@ -19,59 +19,45 @@
                 <div class="box">
                     <div class="box-body">
 
-                        <div class="form-horizontal">
-                            <div class="box-body margin">
-                                <h3><i class="glyphicon glyphicon-exclamation-sign" style="margin-right: 6px"></i>数据情况
-                                </h3>
-                                <div class="form-group" style="margin-left: 15px">
-                                    <span class="form-inline panel-body">分发总量/数据总量(条):
-                                        <input type="text" class="form-control" readonly value="{{.T.allNoGiveDataNum}}/{{.T.allGiveDataNum}}">
-                                    </span>
-                                </div>
-                                <div class="form-group" style="margin-left: 10px">
-                                    <div class="col-xs-6" style="width: auto">
-                                        <label class="form-inline">数据总量:
-                                            <input type="text" class="form-control" style="width: 80px" readonly value="{{.T.allGiveDataNum}}"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已分发:
-                                            <input type="text" class="form-control" style="width: 80px" readonly value="0"></label>
-                                        <label class="form-inline" style="margin-left: 20px">待分发:
-                                            <input type="text" class="form-control" style="width: 80px" readonly value="0"></label>
-                                        <label class="form-inline" style="margin-left: 20px">已标注:
-                                            <input type="text" class="form-control" style="width: 80px" readonly value="0"></label>
-                                    </div>
-                                    <div class="col-xs-6 form-group">
-                                        <label class="form-inline">操作:
-                                            <input type="button" class="btn btn-info" onclick="dispatchTak('0')" value="分发">
-                                            <input type="button" class="btn btn-primary" value="质检">
-                                            <input type="button" class="btn btn-success" value="质检结果">
-                                        </label>
-                                    </div>
-                                </div>
-                            </div>
+                        <div id="status-div" class="col-xs-6 form-inline" style="width: auto;float: right">
+                            <select class="form-control selectpicker" id="pushModelSelect">
+                                <option value=-1>全部</option>
+                                <option value=0>开启</option>
+                                <option value=1>关闭</option>
+                            </select>
+                            <span class="input-group date date-picker" id="starttime">
+                                <input type="text" class="form-control form-filter input-sm" readonly name="starttime" placeholder="开始日期" />
+                                 <span class="input-group-addon">
+                                     <i class="fa fa-calendar"></i>
+                                  </span>
+                            </span>
+                            <span class="input-group date date-picker" id="endtime">
+                                <input type="text" class="form-control form-filter input-sm" readonly name="endtime" placeholder="结束日期" />
+                                 <span class="input-group-addon">
+                                     <i class="fa fa-calendar"></i>
+                                  </span>
+                            </span>
+                            <input type="button" class="btn btn-sm btn-primary" onclick="dispatchTask('0')" value="导出">
                         </div>
-                        <hr>
-                        <div class="form-horizontal">
-                            <div class="box-body margin">
-                                <h3><i class="glyphicon glyphicon-tasks" style="margin-right: 6px"></i>数据清洗任务列表
-                                </h3>
 
-                                <table id="dataTable" class="table table-bordered table-hover">
-                                    <thead>
-                                    <tr>
-                                        <th></th>
-                                        <th>用户账号</th>
-                                        <th>项目名称</th>
-                                        <th>数据量</th>
-                                        <th>任务状态</th>
-                                        <th>完成进度</th>
-                                        <th>开始时间</th>
-                                        <th>完成时间</th>
-                                        <th>操作</th>
-                                    </tr>
-                                    </thead>
-                                </table>
-                            </div>
-                        </div>
+                        <table id="dataTable" class="table table-bordered table-hover">
+                            <thead>
+                            <tr>
+                                <th></th>
+                                <th>公司名称</th>
+                                <th>部门名称</th>
+                                <th>规则名称</th>
+                                <th>项目名称</th>
+                                <th>用户组名称</th>
+                                <th>负责人</th>
+                                <th>清洗数据量</th>
+                                <th>任务状态</th>
+                                <th>完成进度</th>
+                                <th>任务时间</th>
+                                <th>操作</th>
+                            </tr>
+                            </thead>
+                        </table>
                     </div>
                     <!-- /.box-body -->
                 </div>
@@ -81,186 +67,9 @@
     </section>
 </div>
 
-
-<div class="modal fade" id="modal-create-project" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog" style="width: 30%">
-        <div class="modal-content">
-            <div class="modal-header">
-                <div class="modal-header">
-                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-                    <div class="edit-info">
-                        <span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
-                        <span class="h4">新建项目</span>
-                    </div>
-                    <div class="edit-form">
-                        <hr>
-                        <div class="form-group">
-                            <label class="radio-inline">
-                                <input type="radio" name="stype" value="coll" checked>数据库导入
-                            </label>
-                            <label class="radio-inline">
-                                <input type="radio" name="stype" value="excel">Excel表导入
-                            </label>
-                        </div>
-                        <form id="model-form-project" class="form-horizontal" enctype="multipart/form-data">
-                            <div class="box-body">
-                                <div class="form-group margin-bottom">
-                                    <label class="col-sm-3 control-label"><span style="color:red;">* </span>项目名称</label>
-                                    <div class="col-sm-5">
-                                        <input type="text" class="form-control" id="project-name" placeholder="项目名称">
-                                    </div>
-                                </div>
-                                <div id="import-coll">
-                                    <h5><i class="glyphicon glyphicon-bookmark"
-                                           style="color: #00c4ff;margin-right: 6px"></i>数据来源</h5>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label"><span
-                                                style="color:red;">* </span>数据库名</label>
-                                        <div class="col-sm-5">
-                                            <input type="text" class="form-control" id="db-name" value="jyqyfw"
-                                                   readonly>
-                                        </div>
-                                    </div>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label"><span
-                                                style="color:red;">* </span>数据表名</label>
-                                        <div class="col-sm-5">
-                                            <input type="text" class="form-control" id="coll-name"
-                                                   value="usermail_history" readonly>
-                                        </div>
-                                    </div>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label"><span
-                                                style="color:red;">* </span>数据导出ID</label>
-                                        <div class="col-sm-6">
-                                            <input type="text" class="form-control" id="data-id" placeholder="数据导出ID">
-                                        </div>
-                                    </div>
-                                </div>
-
-                                <div id="import-excel" style="display: none">
-                                    <h5><i class="glyphicon glyphicon-bookmark"
-                                           style="color: #00c4ff;margin-right: 6px"></i>数据信息</h5>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label"><span
-                                                style="color:red;">* </span>公司名称</label>
-                                        <div class="col-sm-6">
-                                            <input type="text" class="form-control" id="company-name"
-                                                   placeholder="公司名称">
-                                        </div>
-                                    </div>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label">部门名称</label>
-                                        <div class="col-sm-6">
-                                            <input type="text" class="form-control" id="dpart-name" placeholder="部门名称">
-                                        </div>
-                                    </div>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label">规则名称</label>
-                                        <div class="col-sm-6">
-                                            <input type="text" class="form-control" id="rule-name" placeholder="规则名称">
-                                        </div>
-                                    </div>
-                                    <div class="form-group">
-                                        <label class="col-sm-3 control-label">选择文件</label>
-                                        <div class="col-sm-6">
-                                            <input type="file" name="file" id="uploadfile">
-                                        </div>
-                                    </div>
-                                </div>
-                                <h5><i class="glyphicon glyphicon-bookmark"
-                                       style="color: #00c4ff;margin-right: 6px"></i>数据存储</h5>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label"><span style="color:red;">* </span>数据库名</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" class="form-control" value="jyqykhfw" readonly>
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label"><span style="color:red;">* </span>数据表名</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" class="form-control" id="coll-save-name" placeholder="数据表名">
-                                    </div>
-                                </div>
-                            </div>
-                        </form>
-                    </div>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <input type="button" onclick="importData()" class="btn btn-primary" value="导入">
-                <input type="button" onclick="cancelModel()" class="btn btn-default" value="取消">
-            </div>
-        </div>
-    </div><!-- /.modal -->
-</div>
-
-
-<div class="modal fade" id="modal-edit-project" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog" style="width: 30%">
-        <div class="modal-content">
-            <div class="modal-header">
-                <div class="modal-header">
-                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-                    <div class="edit-info">
-                        <span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
-                        <span class="h4">编辑项目</span>
-                    </div>
-                    <div class="edit-form">
-                        <hr>
-                        <form class="form-horizontal" enctype="multipart/form-data">
-                            <div class="box-body">
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label">公司名称</label>
-                                    <div class="col-sm-5">
-                                        <input type="text" class="form-control" id="company-edit-name" readonly>
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label">部门名称</label>
-                                    <div class="col-sm-5">
-                                        <input type="text" class="form-control" id="dpart-edit-name">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label">规则名称</label>
-                                    <div class="col-sm-5">
-                                        <input type="text" class="form-control" id="rule-edit-name">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label">售后人员</label>
-                                    <div class="col-sm-6">
-                                        <input type="text" class="form-control" id="edit-person">
-                                    </div>
-                                </div>
-                                <div class="form-group">
-                                    <label class="col-sm-3 control-label">选择标注字段</label>
-                                    <div class="col-sm-6">
-                                        <select class="form-control selectpicker" multiple
-                                                id="markFieldSelect"></select>
-                                    </div>
-                                </div>
-                            </div>
-                        </form>
-                    </div>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <input type="button" onclick="saveData()" class="btn btn-primary saveBtn" value="保存">
-                <input type="button" onclick="cancelModel()" class="btn btn-default" value="取消">
-            </div>
-        </div>
-    </div><!-- /.modal -->
-</div>
-
-
 {{include "com/footer.html"}}
 <script>
-    menuActive("task/list");
-
-    let stype = "coll";
-    let fields = {{ .T.fields }}
+    menuActive("/front/group/admin/task/list");
 
     $(function () {
         ttable = $('#dataTable').dataTable({
@@ -272,7 +81,7 @@
             "autoWidth": false,
             "serverSide": true,
             "ajax": {
-                "url": "",
+                "url": "/front/group/admin/task/list",
                 "type": "post",
                 "data": {"status": "-1"}
             },
@@ -293,171 +102,104 @@
                 });
             },
             "columns": [
-                {"data": "", width: "1%"},
-                {"data": "s_personname", width: "5%"},
+                {"data": null, width: "1%"},
+                {"data": "s_entname", width: "4%"},
+                {"data": "s_departname", width: "4%"},
+                {"data": "s_rulename", width: "4%"},
                 {"data": "s_projectname", width: "4%"},
+                {"data": "s_groupname", width: "4%"},
+                {"data": "s_personname", width: "4%"},
                 {"data": "i_givenum", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
-                {"data": "", width: "4%"},
+                {"data": "s_status", width: "4%"},
+                {"data": "s_progress", width: "4%"},
+                {
+                    "data": "_id", width: "4%", render: function (val, a, row) {
+                        let str = ""
+                        if (row['i_starttime'] === undefined) {
+                            str = "未开始"
+                        }else if (row['i_starttime'] && row['i_completetime'] === undefined) {
+                            let dt = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            str = dt.format("yyyy-MM-dd") + " - 未结束"
+                        }else {
+                            let dt = new Date()
+                            let ds = new Date()
+                            dt.setTime(parseInt(row['i_starttime']) * 1000);
+                            ds.setTime(parseInt(row["i_completetime"]) * 1000)
+                            str = dt.format("yyyy-MM-dd") + " - " + ds.format("yyyy-MM-dd")
+                        }
+                        return str
+                    }
+                },
                 {
                     "data": "_id", width: "11%", render: function (val, a, row, pos) {
                         tmp = '<div>' +
-                            '<a class="btn btn-sm btn-primary" onclick="editPro(\'' + pos.row + '\')">收回</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-warning" href="/front/project/clear?pid=' + val + '">质检</a>&nbsp;&nbsp;' +
-                            '<a class="btn btn-sm btn-info" onclick="del(\'' + val + '\')">关闭</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-primary" href="/front/user/task/list?grouptaskid=' + val + '&s_sourceinfo='+row.s_sourceinfo+'">查看</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-warning" onclick="retrieveTask(\'' + val + '\',\''+row.s_sourceinfo+'\',\'' + row.s_status + '\',\''+row.i_givenum+'\')">收回</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info">质检</a>&nbsp;&nbsp;' +
+                            '<a class="btn btn-sm btn-info" onclick="closeTask(\'' + val + '\',\''+row.s_sourceinfo+'\',\'' + row.s_status + '\',\''+row.i_givenum+'\')">关闭</a>&nbsp;&nbsp;' +
                             '</div>';
                         return tmp
                     }
                 }
-            ]
-        });
-
-        $('input[type=radio][name=stype]').change(function () {
-            if (this.value === 'coll') {
-                stype = "coll"
-                $("#import-coll").attr("style", "display:block;")
-                $("#import-excel").attr("style", "display:none;")
-            } else if (this.value === 'excel') {
-                stype = "excel"
-                $("#import-coll").attr("style", "display:none;")
-                $("#import-excel").attr("style", "display:block;")
+            ],
+            "initComplete": function () {
+                $("#dataTable_filter").append($('#status-div'))
             }
         });
 
-        for (var i in fields) {
-            var opt = document.createElement('option');
-            opt.innerText = fields[i]["s_name"];
-            opt.value = fields[i]["s_code"];
-            $('#markFieldSelect')[0].appendChild(opt)
-        }
-        $("#markFieldSelect").selectpicker("refresh");
-    });
-
-
-    function del(id) {
-        showConfirm("确定删除该用户组?", function () {
-            $.ajax({
-                url: "",
-                type: 'POST',
-                data: {"id": id},
-                success: function (r) {
-                    if (r.rep) {
-                        ttable.ajax.reload();
-                    } else {
-                        showTip("状态修改失败");
-                    }
-                }
-            })
+        $('.date-picker').datepicker({
+            language: 'zh-CN',
+            autoclose: true,
+            clearBtn: true, //清除按钮
+            todayBtn: false, //今日按钮
+            format: "yyyy-mm-dd"
+        });
+        $('#starttime').datepicker({ 'changeDate': function(e) {
+                console.log(e.data.toString())
+            }
         })
-    }
 
-    function createPro() {
-       $("#modal-create-project").modal('show')
-    }
-
-    function cancelModel() {
-        document.getElementById("model-form-project").reset();
-        $("#modal-create-project").modal('hide')
-        $("#modal-edit-project").modal('hide')
-    }
+        // $('#datetimepicker').datetimepicker('setStartDate', '2012-01-01');
+    });
 
-    function importData() {
-        if (stype === "coll") {
-            projectmap["s_name"] = $('#project-name').val()
-            projectmap["s_sourceinfo"] = $('#coll-save-name').val()
-            projectmap["s_type"] = stype
-            projectmap["s_historyid"] = $('#data-id').val()
+    // 收回
+    function retrieveTask(id, sourceinfo, status, giveNum) {
+        if (status === "未开始" || status === "进行中") {
             $.ajax({
-                url: "/front/project/save",
+                url: "/front/project/task/retrieve",
                 type: 'POST',
-                data: projectmap,
+                data: {"s_status": status, "taskid": id, "s_sourceinfo": sourceinfo, "i_givenum": giveNum},
                 success: function (r) {
                     if (r.success) {
-
-                        $("#modal-create-project").modal('hide')
-                        ttable.api().ajax.reload();
+                        ttable.api().ajax.reload()
                     } else {
-
+                        showTip(r.msg);
                     }
                 }
             })
-        } else if (stype === "excel") {
-            let formData = new FormData();
-            formData.append("s_name", $('#project-name').val())
-            formData.append("s_sourceinfo", $('#coll-save-name').val())
-            formData.append("s_historyid", $('#data-id').val())
-            formData.append("s_entname", $('#company-name').val())
-            formData.append("s_departname", $('#dpart-name').val())
-            formData.append("s_rulename", $('#rule-name').val())
-            formData.append("s_type", stype)
-            let file = $('#uploadfile')[0].files[0]
-            if (file) {
-                formData.append("xlsx", file)
+        }else {
+            showTip("操作不允许")
+        }
+    }
+    function closeTask(id, sourceinfo,status,givenum) {
+        if (status === "未开始") {
+            showConfirm("确认要关闭当前任务吗?", function () {
                 $.ajax({
-                    url: "/front/project/save",
+                    url: "/front/project/task/close",
                     type: 'POST',
-                    data: formData,
-                    cache: false,
-                    processData: false,
-                    contentType: false,
+                    data: {"s_sourceinfo": sourceinfo, "s_status": status, "taskid": id,"i_givenum":givenum},
                     success: function (r) {
-                        if (r.rep) {
-                            $("#modal-create-project").modal('hide')
-                            ttable.api().ajax.reload();
+                        if (r.success) {
+                            location.reload()
                         } else {
-                            showTip("状态修改失败");
+                            showTip(r.msg);
                         }
                     }
                 })
-            } else {
-                showTip("请选择上传文件");
-            }
-        }
-    }
-
-    function editPro(index) {
-        projectmap = ttable.fnGetData()[index]
-        console.log(projectmap)
-        $('#modal-edit-project').modal('show')
-        $('#company-edit-name').val(projectmap["s_entname"])
-        $('#rule-edit-name').val(projectmap["s_rulename"])
-        $('#dpart-edit-name').val(projectmap["s_departname"])
-    }
-
-    function saveData() {
-        stype = "edit"
-        let tmp = projectmap
-        tmp["s_entname"] = $('#company-edit-name').val()
-        tmp["s_rulename"] = $('#rule-edit-name').val()
-        tmp["s_departname"] = $('#dpart-edit-name').val()
-
-        let fieldArr = $('#markFieldSelect').val();
-        let m = {}
-        if (fieldArr.length > 0) {
-            for (const i in fields) {
-                if (fieldArr.indexOf(fields[i]["s_code"]) > -1) {
-                    m[fields[i]["s_code"]] = fields[i]["s_name"]
-                }
-            }
-        }
-        tmp["v_field"] = m
-        if (tmp !== projectmap) {
-            $.ajax({
-                url: "/front/project/save",
-                type: 'POST',
-                data: projectmap,
-                success: function (r) {
-                    if (r.rep) {
-                        ttable.api().ajax.reload();
-                    } else {
-                        showTip("保存失败");
-                    }
-                }
             })
-        } else {
-            showTip("未做修改");
+        }else {
+            showTip("操作不允许")
         }
     }
 

+ 1 - 1
src/web/templates/project/task_user_list.html

@@ -49,7 +49,7 @@
 
 {{include "com/footer.html"}}
 <script>
-    menuActive("user/task/list");
+    menuActive("/front/user/task/list");
 
     $(function () {
         ttable = $('#dataTable').dataTable({

+ 24 - 37
src/web/templates/user/user_group.html

@@ -19,35 +19,18 @@
                 <div class="box">
                     <div class="box-body">
 
-                        <div class="form-horizontal">
-                            <div class="box-body">
-                                <div class="form-group">
-                                    <label class="col-sm-1 control-label">用户组名称</label>
-                                    <div class="col-sm-2">
-                                        <input type="text" class="form-control" id="customername" placeholder="公司名称" required>
-                                    </div>
-                                    <label class="col-sm-1 control-label">状态</label>
-                                    <div class="col-sm-2">
-                                        <select class="form-control selectpicker" id="pushModelSelect">
-                                            <option value=-1>全部</option>
-                                            <option value=0>开启</option>
-                                            <option value=1>关闭</option>
-                                        </select>
-                                    </div>
-                                    <div class="col-sm-2">
-                                        <a class="btn btn-sm btn-success margin-r-5" onclick="">查询</a>
-                                        <a class="btn btn-sm btn-default" onclick="">取消</a>
-                                    </div>
-                                </div>
-
-                                <div class="form-group" style="margin-left: 20px">
-                                    <a class="btn btn-sm btn-success margin" href="/front/group/new"><i class="fa fa-fw fa-plus fa-lg"></i>新建用户组</a>
-                                    <a class="btn btn-sm btn-default margin" onclick="bulkSetup(true)">批量开启</a>
-                                    <a class="btn btn-sm btn-default margin" onclick="bulkSetup(false)">批量关闭</a>
-                                </div>
-                            </div>
+                        <div class="form-group" style="margin-left: 20px">
+                            <a class="btn btn-sm btn-success margin" href="/front/group/new"><i class="fa fa-fw fa-plus fa-lg"></i>新建用户组</a>
+                            <a class="btn btn-sm btn-default margin" onclick="bulkSetup(true)">批量开启</a>
+                            <a class="btn btn-sm btn-default margin" onclick="bulkSetup(false)">批量关闭</a>
+                        </div>
+                        <div id="status-div" class="col-xs-1" style="width: auto;float: right">
+                            <select class="form-control selectpicker" id="pushModelSelect">
+                                <option value=-1>全部</option>
+                                <option value=0>开启</option>
+                                <option value=1>关闭</option>
+                            </select>
                         </div>
-
                         <table id="dataTable" class="table table-bordered table-hover">
                             <thead>
                             <tr>
@@ -81,7 +64,7 @@
         ttable = $('#dataTable').dataTable({
             "paging": true,
             "lengthChange": false,
-            "searching": false,
+            "searching": true,
             "ordering": false,
             "info": true,
             "autoWidth": false,
@@ -89,7 +72,7 @@
             "ajax": {
                 "url": "/front/group",
                 "type": "post",
-                "data": {"ids": ""}
+                "data": {}
             },
             "language": {
                 "url": "/dist/js/dataTables.chinese.lang"
@@ -108,17 +91,17 @@
                 // });
             },
             "columns": [
-                {"data": "", width: "1%", render: function() {
+                    {"data": "", width: "1%", render: function() {
                         return `<input type="checkbox" name="ckb-keyid" onclick="singleSelect(this)" style="text-align: center">`
                     }},
-                {"data": "s_name", width: "15%"},
-                {"data": "s_personname", width: "9%"},
-                {"data": "i_createtime",width:"9%", render: function (val) {
+                {"data": "s_name", width: "10%"},
+                {"data": "s_personname", width: "5%"},
+                {"data": "i_createtime",width:"5%", render: function (val) {
                         var dt = new Date()
                         dt.setTime(parseInt(val) * 1000);
                         return dt.format("yyyy-MM-dd")
                     }},
-                {"data": "i_updatetime",width:"9%", render: function (val) {
+                {"data": "i_updatetime", width:"5%", render: function (val) {
                   var dt = new Date()
                   dt.setTime(parseInt(val) * 1000);
                   return dt.format("yyyy-MM-dd")
@@ -131,7 +114,7 @@
                             tmp="<a href='#' title='启用' onclick='setupState(\""+row._id+"\",true)'><i class='fa fa-fw fa-circle text-red'></i></a>未启用"
                         }
                         return tmp
-                    }, width: "10%" },
+                    }, width: "5%" },
                 {"data": "_id", width:"11%",render: function (val, a, row, pos) {
                       tmp = '<div>' +
                           '<a class="btn btn-sm btn-primary" href="/front/group/edit?id='+val+'">编辑</a>&nbsp;&nbsp;'+
@@ -140,8 +123,12 @@
                           '</div>';
                       return tmp
                 }}
-            ]
+            ],
+            "initComplete": function () {
+                $("#dataTable_filter").append($('#status-div'))
+            }
         });
+
     });
 
     function setupState(id, v) {

+ 53 - 40
src/web/templates/user/user_group_create.html

@@ -20,13 +20,13 @@
             <div class="box box-primary">
                 <div class="box-header with-border">
                     <i class="fa fa-group"></i>
-                    <h3 class="box-title">用户组信息</h3>
+                    <h4 class="box-title">用户组信息</h4>
                 </div>
                 <div class="box-body">
                     <div class="form-group" style="text-align: right;margin-right: 20px" >
 <!--                        <a class="btn btn-sm btn-success" onclick="addMember()"><i class="fa fa-fw fa-plus fa-lg"></i>添加成员信息</a>-->
                     </div>
-                    <div class="form-group margin-bottom">
+                    <div class="form-group">
                         <label class="col-sm-2 control-label"><span style="color:red;">* </span>用户组名称</label>
                         <div class="col-sm-3">
                             <input type="text" class="form-control" id="group-name" placeholder="用户组名称" required>
@@ -36,57 +36,74 @@
                             <input type="text" class="form-control" id="company-name" placeholder="公司名称" required>
                         </div>
                     </div>
-                    <div class="form-group margin-bottom">
-                        <label class="col-sm-2 control-label">负责人</label>
+                    <div class="form-group">
+                        <label class="col-sm-2 control-label"><span style="color:red;">* </span>负责人</label>
                         <div class="col-sm-3">
-                            <input type="text" class="form-control" id="leader" placeholder="负责人名称">
+                            <input type="text" class="form-control" id="leader" placeholder="负责人名称" required>
                         </div>
                         <label class="col-sm-2 control-label">联系方式</label>
                         <div class="col-sm-3">
                             <input type="text" class="form-control" id="contract" placeholder="联系方式:电话/邮箱">
                         </div>
                     </div>
+                    <div class="form-group">
+                        <label class="col-sm-2 control-label">用户组权限</label>
+                        <div class="col-sm-5 radio">
+                            <label class="margin-r-5">
+                                <input type="radio" name="role" value=1 checked>系统管理员
+                            </label>
+                            <label class="margin-r-5">
+                                <input type="radio" name="role" value=2 checked>管理员
+                            </label>
+                            <label class="margin-r-5">
+                                <input type="radio" name="role" value=3>质检员
+                            </label>
+                            <label>
+                                <input type="radio" name="role" value="4">普通用户
+                            </label>
+                        </div>
+                    </div>
                     <div class="form-group">
                         <label class="col-sm-2 control-label">登陆密码</label>
                         <div class="col-sm-2">
                             <input type="password" id="group-pwd" readonly="readonly" class="form-control" placeholder="手动输入密码">
                         </div>
-                        <div class="col-sm-2">
-                            <label class="col-sm-5 control-label" style="font-size: xx-small;width: auto">默认密码:</label>
+                        <div class="col-xs-3" style="width: auto">
+                            <label class="control-label" style="font-size: xx-small;width: auto">默认密码:</label>
                             <input id="group-switch-pwd" name="switch-pwd" type="checkbox">
                         </div>
-                        <label class="col-sm-1 control-label">服务时间</label>
+                        <label class="col-sm-1 control-label" style="width: auto">服务时间</label>
                         <div class="col-sm-3">
                             <input type="text" id="stratDate" class="col-sm-2 form-control" readonly="readonly" placeholder="开始日期 - 结束日期">
                         </div>
                     </div>
 
                     <div class="box-body">
-                        <div class="box-header with-border margin-bottom">
+                        <div class="box-header with-border">
                             <i class="fa fa-user"></i>
-                            <h3 class="box-title">质检员信息</h3>
+                            <h4 class="box-title">质检员信息</h4>
                         </div>
                         <h1></h1>
-                        <div class="form-group margin-bottom">
+                        <div class="form-group">
                             <label class="col-sm-2 control-label">用户账号</label>
-                            <div class="col-sm-2">
+                            <div class="col-sm-3">
                                 <input type="text" readonly="readonly" class="form-control" placeholder="默认用户组名称+zj+数字">
                             </div>
-                            <label class="col-sm-1 control-label">用户个数(个)</label>
-                            <div class="col-sm-1">
+                            <label class="col-sm-2 control-label">用户个数(个)</label>
+                            <div class="col-sm-3">
                                 <input type="number" id="u1-size" class="form-control" value="1" oninput="if(value<0)value=0;if(value>10)value=10">
                             </div>
-                            <label class="col-sm-1 control-label">登陆密码</label>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label">登陆密码</label>
                             <div class="col-sm-2">
                                 <input type="password" id="u1-pwd" readonly="readonly" class="form-control" placeholder="手动输入密码">
                             </div>
-                            <div class="col-sm-2">
-                                <label class="col-sm-5 control-label" style="font-size: xx-small;width: auto">默认密码:</label>
+                            <div class="col-xs-3" style="width: auto">
+                                <label class="control-label" style="font-size: xx-small;">默认密码:</label>
                                 <input id="u1-switch-pwd" name="switch-pwd" type="checkbox">
                             </div>
-                        </div>
-                        <div class="form-group margin-bottom">
-                            <label class="col-sm-2 control-label">用户状态</label>
+                            <label class="col-sm-1 control-label" style="width: auto">用户状态</label>
                             <div class="col-sm-3">
                                 <input id="u1-switch-state" name="switch-state" type="checkbox">
                             </div>
@@ -94,31 +111,31 @@
                     </div>
 
                     <div class="box-body">
-                        <div class="box-header with-border margin-bottom">
+                        <div class="box-header with-border">
                             <i class="fa fa-user"></i>
-                            <h3 class="box-title">成员信息</h3>
+                            <h4 class="box-title">成员信息</h4>
                         </div>
                         <h1></h1>
-                        <div class="form-group margin-bottom">
+                        <div class="form-group">
                             <label class="col-sm-2 control-label">用户账号</label>
-                            <div class="col-sm-2">
+                            <div class="col-sm-3">
                                 <input type="text" readonly="readonly" class="form-control" placeholder="默认用户组名称+数字">
                             </div>
-                            <label class="col-sm-1 control-label">用户个数(个)</label>
-                            <div class="col-sm-1">
+                            <label class="col-sm-2 control-label">用户个数(个)</label>
+                            <div class="col-sm-3">
                                 <input type="number" id="u2-size" class="form-control" value="1" oninput="if(value<0)value=0;if(value>30)value=30">
                             </div>
-                            <label class="col-sm-1 control-label">登陆密码</label>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label">登陆密码</label>
                             <div class="col-sm-2">
                                 <input type="password" readonly="readonly" id="u2-pwd" class="form-control" placeholder="手动输入密码">
                             </div>
-                            <div class="col-sm-2">
-                                <label class="col-sm-5 control-label" style="font-size: xx-small;width: auto">默认密码:</label>
+                            <div class="col-xs-3" style="width: auto">
+                                <label class="control-label" style="font-size: xx-small;width: auto">默认密码:</label>
                                 <input name="switch-pwd" id="u2-switch-pwd" type="checkbox">
                             </div>
-                        </div>
-                        <div class="form-group margin-bottom">
-                            <label class="col-sm-2 control-label">用户状态</label>
+                            <label class="col-sm-1 control-label" style="width: auto">用户状态</label>
                             <div class="col-sm-3">
                                 <input id="u2-switch-state" name="switch-state" type="checkbox">
                             </div>
@@ -199,23 +216,19 @@
     // 用户状态
     $("#u1-switch-state").bootstrapSwitch('onSwitchChange', function (event, state){user["u1_state"] = state})
     $("#u2-switch-state").bootstrapSwitch('onSwitchChange', function (event, state){user["u2_state"] = state})
-    // $("#stratDate").datepicker({
-    //     language: 'zh-CN',
-    //     autoclose: true,
-    //     clearBtn: true,
-    //     format: "yyyy-mm-dd"
-    // });
 
     function saveMethod() {
 
         const gname = $("#group-name").val();
         const company = $("#company-name").val()
-        if (gname == null || company == null) {
+        const lender = $("#leader").val()
+        if (gname === "" || company === "" || lender === "") {
             return
         }
+        group["i_role"] = $("input[name='role']:checked").val()
         group["s_name"] = gname
         group["s_entname"] = company
-        group["s_personname"] = $("#leader").val()
+        group["s_personname"] = lender
         group["s_personcontact"] = $("#contract").val()
         group["s_password"] = $("#group-pwd").val()
         user["u1_size"] = $("#u1-size").val()

+ 11 - 7
src/web/templates/user/user_list.html

@@ -9,7 +9,7 @@
             <small></small>
         </h1>
         <ol class="breadcrumb">
-            <li><a href="/front/group"><i class="fa fa-dashboard"></i> 用户组管理</a></li>
+            <li><a href="#"><i class="fa fa-dashboard"></i> 用户列表</a></li>
         </ol>
     </section>
     <!-- Main content -->
@@ -110,7 +110,7 @@
 </div>
 
 <script>
-    menuActive("group");
+    menuActive("/front/user");
     let gid = {{ .T.gid }}
     let selectIndex = [];               //选中的编号
     let keyTableChecked = false;        //关键词表格数据是否有选中
@@ -120,13 +120,13 @@
         ttable = $('#dataTable').dataTable({
             "paging": true,
             "lengthChange": false,
-            "searching": false,
+            "searching": true,
             "ordering": false,
             "info": true,
             "autoWidth": false,
             "serverSide": true,
             "ajax": {
-                "url": "/front/group/user",
+                "url": "/front/user",
                 "type": "post",
                 "data": {"gid": gid}
             },
@@ -153,9 +153,13 @@
                 {"data": "s_login", width: "9%"},
                 {"data": "s_name", width: "9%"},
                 {"data": "i_role", width:"9%", render: function (val) {
-                        if (val === "1") {
-                            return "管理员"
+                        if (val === "0") {
+                            return "超级管理员"
+                        }else if (val === "1") {
+                            return "系统管理员"
                         }else if (val === "2") {
+                            return "管理员"
+                        }else if (val === "3") {
                             return "质检员"
                         }else {
                             return "普通用户"
@@ -173,7 +177,7 @@
                 {"data": "i_createtime",width:"9%", render: function (val) {
                         var dt = new Date()
                         dt.setTime(parseInt(val) * 1000);
-                        return dt.format("yyyy-MM-dd")
+                        return dt.format("yyyy-MM-dd ")
                     }},
                 {"data": "i_updatetime",width:"9%", render: function (val) {
                         var dt = new Date()