project.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package front
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/tealeg/xlsx"
  6. "io/ioutil"
  7. "mime/multipart"
  8. qu "qfw/util"
  9. "strings"
  10. "sync"
  11. "sync/atomic"
  12. "time"
  13. "util"
  14. )
  15. // ProjectList 项目列表
  16. func (f *Front) ProjectList() {
  17. defer qu.Catch()
  18. if f.Method() == "POST" {
  19. start, _ := f.GetInteger("start")
  20. draw, _ := f.GetInteger("draw")
  21. status := f.GetString("status")
  22. searchStr := f.GetString("search[value]")
  23. search := strings.TrimSpace(searchStr)
  24. //data := util.GetPostForm(f.Request)
  25. query := map[string]interface{}{}
  26. if status != "-1" {
  27. query["s_status"] = status
  28. }
  29. if search != "" {
  30. query["$or"] = []interface{}{
  31. map[string]interface{}{"s_name": map[string]interface{}{"$regex": search}},
  32. map[string]interface{}{"s_entname": map[string]interface{}{"$regex": search}},
  33. map[string]interface{}{"s_rule": map[string]interface{}{"$regex": search}},
  34. map[string]interface{}{"s_departname": map[string]interface{}{"$regex": search}},
  35. }
  36. }
  37. list, _ := util.Mgo.Find("f_project", query, nil, nil, false, start, draw)
  38. count := util.Mgo.Count("f_project", query)
  39. f.ServeJson(map[string]interface{}{"draw": draw, "data": *list, "recordsFiltered": count, "recordsTotal": count})
  40. } else {
  41. query := map[string]interface{}{"s_type": "tag"}
  42. info, _ := util.Mgo.Find("v_field", query, nil, map[string]interface{}{"s_name": 1, "s_code": 1}, false, -1, -1)
  43. f.T["fields"] = *info
  44. _ = f.Render("project/project_list.html", &f.T)
  45. }
  46. }
  47. // ProjectSave 项目保存
  48. func (f *Front) ProjectSave() {
  49. defer qu.Catch()
  50. success := false
  51. msg := ""
  52. successNum := int64(0)
  53. user := f.GetSession("user").(map[string]interface{})
  54. username := qu.ObjToString(user["s_name"]) //当前登录用户
  55. stype := f.GetString("s_type") //新建项目类型:数据库导入、excel导入
  56. s_name := f.GetString("s_name") //项目名称
  57. s_sourceinfo := f.GetString("s_sourceinfo") //数据表
  58. s_sourceinfo = "s_sourceinfo_" + s_sourceinfo
  59. s_departname, s_entname := "", ""
  60. importDataNum := 0
  61. var s_rulename []string
  62. query := map[string]interface{}{
  63. "s_name": s_name,
  64. }
  65. set := map[string]interface{}{}
  66. //导入数据
  67. if stype == "excel" { //excel导入
  68. s_entname = f.GetString("s_entname") //公司名称
  69. s_departname = f.GetString("s_departname") //部门名称
  70. rulename := f.GetString("s_rulename") //规则名称
  71. s_rulename = strings.Split(rulename, ",")
  72. mf, _, err := f.GetFile("xlsx")
  73. if err == nil {
  74. importDataNum = ImportDataByExcel(s_sourceinfo, mf, &success, &msg, &successNum)
  75. }
  76. //保存项目信息
  77. set = map[string]interface{}{
  78. "s_name": s_name, //项目名称
  79. "s_entname": s_entname, //公司名称
  80. "s_departname": s_departname, //部门名称
  81. "s_rulename": strings.Join(s_rulename, ","), //规则名称
  82. "i_importnum": importDataNum, //导入数量
  83. "s_sourceinfo": s_sourceinfo, //源数据表
  84. "s_createname": username, //创建人
  85. "s_status": "未开始", //项目状态
  86. "i_createtime": time.Now().Unix(), //创建时间
  87. }
  88. } else if stype == "coll" { //数据库导入
  89. historyid := f.GetString("s_historyid")
  90. s_departname, s_entname, s_rulename, importDataNum = ImportDataByColl(s_sourceinfo, historyid, &success, &msg, &successNum)
  91. qu.Debug(s_departname, s_entname, s_rulename)
  92. //保存项目信息
  93. set = map[string]interface{}{
  94. "s_name": s_name, //项目名称
  95. "s_entname": s_entname, //公司名称
  96. "s_departname": s_departname, //部门名称
  97. "s_rulename": strings.Join(s_rulename, ","), //规则名称
  98. "i_importnum": importDataNum, //导入数量
  99. "s_sourceinfo": s_sourceinfo, //源数据表
  100. "s_createname": username, //创建人
  101. "s_status": "未开始", //项目状态
  102. "i_createtime": time.Now().Unix(), //创建时间
  103. }
  104. } else if stype == "edit" { //编辑保存
  105. s_entname = f.GetString("s_entname") //公司名称
  106. s_departname = f.GetString("s_departname") //部门名称
  107. rulename := f.GetString("s_rulename") //规则名称
  108. s_rulename = strings.Split(rulename, ",")
  109. s_personname := f.GetString("s_personname")
  110. fields := f.GetString("v_fields")
  111. var v_fields []string
  112. if json.Unmarshal([]byte(fields), &v_fields) != nil {
  113. qu.Debug("标注字段解析失败")
  114. }
  115. set = map[string]interface{}{
  116. "s_name": s_name, //项目名称
  117. "s_entname": s_entname, //公司名称
  118. "s_departname": s_departname, //部门名称
  119. "s_rulename": strings.Join(s_rulename, ","), //规则名称
  120. "v_fields": v_fields, //标注字段
  121. "i_updatetime": username, //更新人
  122. "i_createtime": time.Now().Unix(), //更新时间
  123. "s_personname": s_personname, //售后人员
  124. //"i_starttime":,//开始时间
  125. //"i_completetime",//结束时间
  126. }
  127. }
  128. util.Mgo.Update("f_project", query, map[string]interface{}{"$set": set}, true, false)
  129. }
  130. //ImportDataByExcel 通过excel获取数据源
  131. func ImportDataByExcel(s_sourceinfo string, mf multipart.File, success *bool, msg *string, successNum *int64) (importDataNum int) {
  132. defer qu.Catch()
  133. binary, _ := ioutil.ReadAll(mf)
  134. xls, _ := xlsx.OpenBinary(binary)
  135. sheet := xls.Sheets[0]
  136. rows := sheet.Rows
  137. idcolnum := -1
  138. cellFieldName := map[int]string{} //记录客户需求字段所在的列
  139. idInfoMap := map[string]map[string]interface{}{} //记录数据id及需要保存的字段信息
  140. for rn, row := range rows {
  141. if rn == 0 {
  142. for index, cell := range row.Cells {
  143. title := cell.Value
  144. if fieldName := util.CustomerFieldMap_HE[title]; fieldName != "" { //客户需求字段
  145. cellFieldName[index] = fieldName
  146. }
  147. if title == "唯一标识" || title == "信息标识" { //id所在列
  148. idcolnum = index
  149. }
  150. }
  151. if idcolnum == -1 {
  152. break
  153. }
  154. continue
  155. }
  156. if len(row.Cells) < len(rows[0].Cells) {
  157. break
  158. }
  159. tmp := map[string]interface{}{}
  160. for index, f := range cellFieldName {
  161. if val := row.Cells[index].Value; val != "" {
  162. if f == "capital" { //注册资金(万元)
  163. cf, _ := row.Cells[index].Float()
  164. tmp[f] = cf
  165. } else if f == "createtime" { //创建时间
  166. ci, _ := row.Cells[index].Int64()
  167. tmp[f] = ci
  168. } else {
  169. tmp[f] = val
  170. }
  171. }
  172. }
  173. id := row.Cells[idcolnum].String() //加密的id
  174. if id == "" {
  175. break
  176. }
  177. id = util.SE.DecodeString(id) //解密后id
  178. idInfoMap[id] = tmp
  179. }
  180. importDataNum = len(idInfoMap)
  181. qu.Debug("共加载Excel数据:", importDataNum, "条")
  182. if importDataNum > 0 {
  183. GetDataById(idInfoMap, "excel", s_sourceinfo, success, msg, successNum)
  184. } else {
  185. *success = false
  186. *msg = "查询数据失败"
  187. }
  188. idInfoMap = map[string]map[string]interface{}{}
  189. return
  190. }
  191. //ImportDataByColl 通过表获取数据源
  192. func ImportDataByColl(s_sourceinfo, historyid string, success *bool, msg *string, successNum *int64) (departname, entname string, rulename []string, importDataNum int) {
  193. defer qu.Catch()
  194. sess := util.MgoJy.GetMgoConn()
  195. defer util.MgoJy.DestoryMongoConn(sess)
  196. ch := make(chan bool, 3)
  197. wg := &sync.WaitGroup{}
  198. lock := &sync.Mutex{}
  199. idInfoMap := map[string]map[string]interface{}{} //记录数据id及需要保存的字段信息
  200. query := map[string]interface{}{
  201. "historyId": historyid,
  202. }
  203. it := sess.DB(util.MgoJy.DbName).C(util.JyHistory).Find(&query).Iter()
  204. n := 0
  205. for tmp := make(map[string]interface{}); it.Next(tmp); n++ {
  206. ch <- true
  207. wg.Add(1)
  208. go func(tmp map[string]interface{}) {
  209. defer func() {
  210. <-ch
  211. wg.Done()
  212. }()
  213. id := qu.ObjToString(tmp["id"]) //bidding id
  214. appid := qu.ObjToString(tmp["appid"]) //根据appid查user表获取公司名称
  215. departname = qu.ObjToString(tmp["departname"]) //部门名称。所有数据都应部门名称,若不一致,随机取
  216. needField := map[string]interface{}{}
  217. for f, _ := range util.CustomerFieldMap_EH {
  218. if tmp[f] != nil {
  219. needField[f] = tmp[f]
  220. }
  221. }
  222. if entname == "" { //获取一次公司名称即可
  223. user, _ := util.MgoJy.FindOne(util.JyUser, map[string]interface{}{"appid": appid})
  224. entname = qu.ObjToString((*user)["username"]) //公司名称
  225. }
  226. lock.Lock()
  227. rulename = append(rulename, qu.ObjToString(tmp["rulename"])) //规则名称
  228. idInfoMap[id] = needField
  229. lock.Unlock()
  230. }(tmp)
  231. if n%1000 == 0 {
  232. qu.Debug("current:", n)
  233. }
  234. tmp = map[string]interface{}{}
  235. }
  236. wg.Wait()
  237. importDataNum = len(idInfoMap) //查询数据总数
  238. if importDataNum > 0 {
  239. GetDataById(idInfoMap, "coll", s_sourceinfo, success, msg, successNum)
  240. } else {
  241. *msg = "查询数据失败"
  242. }
  243. idInfoMap = map[string]map[string]interface{}{}
  244. return
  245. }
  246. //GetDataById 通过id集从bidding、extract、project获取数据所有信息
  247. func GetDataById(idsInfo map[string]map[string]interface{}, importType, s_sourceinfo string, success *bool, msg *string, successNum *int64) {
  248. *success = true
  249. wg := &sync.WaitGroup{}
  250. lock := &sync.Mutex{}
  251. ch := make(chan bool, 10)
  252. num := int64(0) //计数
  253. for id, info := range idsInfo {
  254. wg.Add(1)
  255. ch <- true
  256. go func(id string, tmp map[string]interface{}) {
  257. defer func() {
  258. wg.Done()
  259. <-ch
  260. }()
  261. /*
  262. 1.查bidding
  263. 2.查extract
  264. 3.extract合并到bidding(删除item字段与客户需要的item不是一个含义)
  265. 4.对比marked表,替换已标注过的字段值,补充标记
  266. 5.合并客户所需字段信息,补充id字段
  267. //6.若为同步时,删除原有id对应的信息,新增该id对应的_id信息
  268. 6.mgo查询项目信息
  269. */
  270. tagInfoMap := map[string]interface{}{} //记录数据已标注过的信息
  271. baseInfoMap := map[string]interface{}{} //记录其他信息
  272. //1.查bidding
  273. tmpBidColl := util.BidColl1 //bidding
  274. //查询bidding
  275. if id < util.BIDDINGSTARTID {
  276. tmpBidColl = util.BidColl2 //bidding_back
  277. }
  278. bidData, _ := util.MgoB.FindById(tmpBidColl, id, nil)
  279. if bidData != nil && len(*bidData) > 0 { //bidding表数据存在
  280. //2.查extract
  281. extData, _ := util.MgoE.FindById(util.ExtColl1, id, nil)
  282. if extData == nil || len(*extData) == 0 {
  283. extData, _ = util.MgoE.FindById(util.ExtColl2, id, nil)
  284. }
  285. //抽取表字段合并到bidding
  286. if extData != nil && len(*extData) > 0 {
  287. for k, v := range *extData {
  288. (*bidData)[k] = v
  289. }
  290. }
  291. //3.删除item
  292. //删除item
  293. delete((*bidData), "item")
  294. //4.对比marked表,对比marked表是否已标注该数据
  295. markData, _ := util.Mgo.FindById(util.AllToColl, id, nil)
  296. if markData != nil && len(*markData) > 0 {
  297. UpdateMarkColl(bidData, markData, &tagInfoMap, &baseInfoMap) //比对更新数据
  298. } else {
  299. baseInfoMap["i_ckdata"] = 0 //设置ck_data默认值0
  300. }
  301. //多包、中标候选人、标的信息是否抽取
  302. if packageMap, ok := (*bidData)["package"].(map[string]interface{}); ok && len(packageMap) > 0 {
  303. baseInfoMap["pkgisext"] = true
  304. } else {
  305. baseInfoMap["pkgisext"] = false
  306. }
  307. if winorderArr, ok := (*bidData)["winnerorder"].([]interface{}); ok && len(winorderArr) > 0 {
  308. baseInfoMap["wodrisext"] = true
  309. } else {
  310. baseInfoMap["wodrisext"] = false
  311. }
  312. if purchArr, ok := (*bidData)["purchasinglist"].([]interface{}); ok && len(purchArr) > 0 {
  313. baseInfoMap["pclisext"] = true
  314. } else {
  315. baseInfoMap["pclisext"] = false
  316. }
  317. //合并导入表中客户所需的字段
  318. if len(tmp) > 0 {
  319. for k, v := range tmp {
  320. (*bidData)[k] = v
  321. }
  322. }
  323. //补充id
  324. //(*bidData)["id"] = id
  325. //if stype == "syncoll" { //同步数据时删除原始数据
  326. // if util.MgoM.Delete(coll, `{"id":"`+id+`"}`) == 0 {
  327. // lock.Lock()
  328. // *msg += "同步未删除成功数据id:" + id + ";\n"
  329. // *success = false
  330. // lock.Unlock()
  331. // }
  332. //}
  333. // 处理 package winner_all
  334. if p, o1 := (*bidData)["package"].(map[string]interface{}); o1 {
  335. for _, v := range p {
  336. v1 := v.(map[string]interface{})
  337. t := make(map[string]interface{})
  338. if v1["winner"] != nil {
  339. t["winner"] = v1["winner"]
  340. }
  341. if v1["bidamount"] != nil {
  342. t["bidamount"] = qu.Float64All(v1["bidamount"])
  343. }
  344. if len(t) > 0 {
  345. v1["winner_all"] = append([]map[string]interface{}{}, t)
  346. }
  347. }
  348. }
  349. // 补充filetext
  350. (*bidData)["filetext"] = util.GetFileText(*bidData)
  351. // 6.es查询项目合并信息
  352. //esQ := `{"query":{"bool":{"must":[{"term":{"ids":"` + id + `"}}]}}}`
  353. //info := util.Es.Get("projectset", "projectset", esQ)
  354. projectId := qu.ObjToString((*bidData)["projectId"])
  355. project, _ := util.MgoE.FindById(util.ProjectColl, projectId, map[string]interface{}{"ids": 1})
  356. if project != nil && len(*project) > 0 {
  357. ids := qu.ObjArrToStringArr((*project)["ids"].([]interface{}))
  358. if len(ids) > 0 {
  359. var infolist []map[string]interface{}
  360. for _, v := range ids {
  361. if v == id { // 当前公告
  362. continue
  363. }
  364. if v < util.BIDDINGSTARTID {
  365. tmpBidColl = util.BidColl2 //bidding_back
  366. }
  367. bid, b := util.MgoB.FindById(tmpBidColl, v, nil)
  368. if b && len(*bid) > 0 {
  369. tmp := make(map[string]interface{})
  370. tmp["id"] = v
  371. tmp["title"] = (*bid)["title"]
  372. tmp["href"] = (*bid)["href"]
  373. tmp["toptype"] = (*bid)["toptype"]
  374. tmp["subtype"] = (*bid)["subtype"]
  375. tmp["publishtime"] = (*bid)["publishtime"]
  376. tmp["detail"] = (*bid)["detail"]
  377. tmp["filetext"] = util.GetFileText(*bid)
  378. infolist = append(infolist, tmp)
  379. }
  380. }
  381. (*bidData)["info"] = infolist
  382. }
  383. } else {
  384. qu.Debug("projectset find err", projectId)
  385. }
  386. baseInfoMap["id"] = id
  387. delete(*bidData, "id")
  388. //保存数据
  389. baseInfoMap["_id"] = (*bidData)["_id"]
  390. baseInfoMap["v_datainfo"] = bidData
  391. baseInfoMap["v_taginfo"] = tagInfoMap
  392. baseInfoMap["i_createtime"] = time.Now().Unix()
  393. baseInfoMap["b_isgive"] = false //是否分配
  394. baseInfoMap["b_istag"] = false //是否已标注
  395. if util.Mgo.SaveByOriID(s_sourceinfo, baseInfoMap) {
  396. atomic.AddInt64(successNum, 1) //保存成功计数
  397. } else {
  398. lock.Lock()
  399. *success = false
  400. if importType == "excel" {
  401. *msg += "第" + fmt.Sprint(num+2) + "行未保存成功数据_id:" + id + ";\n"
  402. } else {
  403. *msg += "未保存成功数据_id:" + id + ";\n"
  404. }
  405. lock.Unlock()
  406. }
  407. } else {
  408. lock.Lock()
  409. *success = false
  410. if importType == "excel" {
  411. *msg += "第" + fmt.Sprint(num+2) + "行未查询到数据:" + id + ";\n"
  412. } else {
  413. *msg += "未查询到数据_id:" + id + ";\n"
  414. }
  415. lock.Unlock()
  416. }
  417. }(id, info)
  418. }
  419. wg.Wait()
  420. }
  421. //更新数据
  422. func UpdateMarkColl(bidData, markData, tagInfoMap, baseInfoMap *map[string]interface{}) {
  423. defer qu.Catch()
  424. ckdata := qu.IntAll((*markData)["i_ckdata"])
  425. v_taginfo := (*markData)["v_taginfo"].(map[string]interface{}) //标注信息
  426. v_datainfo := (*markData)["v_datainfo"].(map[string]interface{}) //基本信息
  427. for fk, _ := range v_taginfo {
  428. if v_datainfo[fk] != nil {
  429. (*bidData)[fk] = v_datainfo[fk] //字段更新
  430. }
  431. }
  432. (*tagInfoMap)["v_taginfo"] = v_taginfo //marked中已有的标注信息保存到新数据上
  433. if ckdata == 2 { //某些字段已标注
  434. (*baseInfoMap)["i_ckdata"] = 0 //marked表中该条数据如果为字段验证,临时表ck_data:0;若为数据验证ck_data:1
  435. } else if ckdata == 1 {
  436. (*baseInfoMap)["i_ckdata"] = 1
  437. }
  438. }