task.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. package main
  2. import (
  3. "encoding/json"
  4. "log"
  5. mu "mfw/util"
  6. "net"
  7. "qfw/util"
  8. "regexp"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/robfig/cron"
  13. )
  14. /**
  15. 任务入口
  16. 全量、增量合并
  17. 更新、插入,内存清理
  18. 转换成info对象
  19. **/
  20. //项目合并对象
  21. type ProjectTask struct {
  22. InitMinTime int64 //最小时间,小于0的处理一次
  23. name string
  24. thread int //线程数
  25. //查找锁
  26. findLock sync.Mutex
  27. wg sync.WaitGroup
  28. //map锁
  29. AllIdsMapLock sync.Mutex
  30. //对应的id
  31. AllIdsMap map[string]*ID
  32. //采购单位、项目名称、项目编号
  33. mapPb, mapPn, mapPc map[string]*Key
  34. // mapPbLock, mapPnLock, mapPcLock sync.Mutex
  35. //更新或新增通道
  36. updatePool chan []map[string]interface{}
  37. savePool chan map[string]interface{}
  38. saveSign, updateSign chan bool
  39. //表名
  40. coll string
  41. //当前状态是全量还是增量
  42. currentType string //当前是跑全量还是跑增量
  43. //
  44. clearContimes int
  45. //当前时间
  46. currentTime int64
  47. //保存长度
  48. saveSize int
  49. pici int64
  50. validTime int64
  51. // LockPool chan *sync.Mutex
  52. // LockPoolLock sync.Mutex
  53. // m1, m23, m4 map[int]int
  54. // l1, l23, l4 map[int]*sync.Mutex
  55. }
  56. //func (p *ProjectTask) ConCurrentLock(n1, n2, n3, n4 int) {
  57. // var lock *sync.Mutex
  58. // p.LockPoolLock.Lock()
  59. // if p.m1[n1] > 0 || p.m23[n2] > 0 || p.m23[n3] > 0 || p.m4[n4] > 0 {
  60. // if p.l1[n1] != nil {
  61. // lock = p.l1[n1]
  62. // } else if p.l23[n2] != nil {
  63. // lock = p.l23[n2]
  64. // } else if p.l23[n3] != nil {
  65. // lock = p.l23[n3]
  66. // } else if p.l4[n4] != nil {
  67. // lock = p.l4[n4]
  68. // }
  69. // } else {
  70. // lock = <-p.LockPool
  71. // }
  72. // if n1 > 0 {
  73. // p.m1[n1]++
  74. // p.l1[n1] = lock
  75. // }
  76. // if n2 > 0 {
  77. // p.m23[n2]++
  78. // p.l23[n2] = lock
  79. // }
  80. // if n3 > 0 {
  81. // p.m23[n3]++
  82. // p.l23[n3] = lock
  83. // }
  84. // if n4 > 0 {
  85. // p.m4[n4]++
  86. // p.l4[n4] = lock
  87. // }
  88. // p.LockPoolLock.Unlock()
  89. // lock.Lock()
  90. //}
  91. //func (p *ProjectTask) ConCurrentUnLock(n1, n2, n3, n4 int) {
  92. // var lock1 *sync.Mutex
  93. // p.LockPoolLock.Lock()
  94. // if p.l1[n1] != nil {
  95. // lock1 = p.l1[n1]
  96. // } else if p.l23[n2] != nil {
  97. // lock1 = p.l23[n2]
  98. // } else if p.l23[n3] != nil {
  99. // lock1 = p.l23[n3]
  100. // } else if p.l4[n4] != nil {
  101. // lock1 = p.l4[n4]
  102. // }
  103. // if p.m1[n1] > 0 {
  104. // p.m1[n1]--
  105. // if p.m1[n1] == 0 {
  106. // p.l1[n1] = nil
  107. // }
  108. // }
  109. // if p.m23[n2] > 0 {
  110. // p.m23[n2]--
  111. // if p.m23[n2] == 0 {
  112. // p.l23[n2] = nil
  113. // }
  114. // }
  115. // if p.m23[n3] > 0 {
  116. // p.m23[n3]--
  117. // if p.m23[n3] == 0 {
  118. // p.l23[n3] = nil
  119. // }
  120. // }
  121. // if p.m4[n4] > 0 {
  122. // p.m4[n4]--
  123. // if p.m4[n4] == 0 {
  124. // p.l4[n4] = nil
  125. // }
  126. // }
  127. // p.LockPoolLock.Unlock()
  128. // lock1.Unlock()
  129. //}
  130. func NewPT() *ProjectTask {
  131. p := &ProjectTask{
  132. InitMinTime: int64(1325347200),
  133. name: "全/增量对象",
  134. thread: 4,
  135. updatePool: make(chan []map[string]interface{}, 2000),
  136. savePool: make(chan map[string]interface{}, 2000),
  137. wg: sync.WaitGroup{},
  138. AllIdsMap: make(map[string]*ID, 10000000),
  139. mapPb: make(map[string]*Key, 2000000),
  140. mapPn: make(map[string]*Key, 5000000),
  141. mapPc: make(map[string]*Key, 5000000),
  142. saveSize: 200,
  143. saveSign: make(chan bool, 1),
  144. updateSign: make(chan bool, 1),
  145. coll: ProjectColl,
  146. validTime: 180 * 86400,
  147. // LockPool: make(chan *sync.Mutex, 200),
  148. // m1: map[int]int{},
  149. // m23: map[int]int{},
  150. // m4: map[int]int{},
  151. // l1: map[int]*sync.Mutex{}, l23: map[int]*sync.Mutex{}, l4: map[int]*sync.Mutex{},
  152. }
  153. // for i := 0; i < 200; i++ {
  154. // p.LockPool <- &sync.Mutex{}
  155. // }
  156. // go func() {
  157. // for {
  158. // p.LockPool <- &sync.Mutex{}
  159. // }
  160. // }()
  161. return p
  162. }
  163. var P_QL *ProjectTask
  164. //初始化全量合并对象
  165. func init() {
  166. P_QL = NewPT()
  167. go P_QL.updateAllQueue()
  168. // go P_QL.saveQueue()
  169. // go P_QL.updateQueue()
  170. go P_QL.clearMem()
  171. }
  172. func (p *ProjectTask) saveQueue() {
  173. arr := make([]map[string]interface{}, p.saveSize)
  174. indexs := 0
  175. for {
  176. select {
  177. case <-p.saveSign:
  178. if indexs > 0 {
  179. MongoTool.SaveBulk(p.coll, arr[:indexs]...)
  180. arr = make([]map[string]interface{}, p.saveSize)
  181. indexs = 0
  182. }
  183. p.updateSign <- true
  184. case v := <-p.savePool:
  185. arr[indexs] = v
  186. indexs++
  187. if indexs == p.saveSize {
  188. MongoTool.SaveBulk(p.coll, arr...)
  189. arr = make([]map[string]interface{}, p.saveSize)
  190. indexs = 0
  191. }
  192. case <-time.After(100 * time.Millisecond):
  193. if indexs > 0 {
  194. MongoTool.SaveBulk(p.coll, arr[:indexs]...)
  195. arr = make([]map[string]interface{}, p.saveSize)
  196. indexs = 0
  197. }
  198. }
  199. }
  200. }
  201. //项目保存和更新通道
  202. func (p *ProjectTask) updateQueue() {
  203. arru := make([][]map[string]interface{}, p.saveSize)
  204. indexu := 0
  205. for {
  206. select {
  207. case v := <-p.updatePool:
  208. arru[indexu] = v
  209. indexu++
  210. if indexu == p.saveSize {
  211. //更新之前先保存
  212. p.saveSign <- true
  213. <-p.updateSign
  214. MongoTool.UpdateBulk(p.coll, arru...)
  215. arru = make([][]map[string]interface{}, p.saveSize)
  216. indexu = 0
  217. }
  218. case <-time.After(100 * time.Millisecond):
  219. if indexu > 0 {
  220. p.saveSign <- true
  221. <-p.updateSign
  222. MongoTool.UpdateBulk(p.coll, arru[:indexu]...)
  223. arru = make([][]map[string]interface{}, p.saveSize)
  224. indexu = 0
  225. }
  226. }
  227. }
  228. }
  229. func (p *ProjectTask) updateAllQueue() {
  230. arru := make([][]map[string]interface{}, p.saveSize)
  231. indexu := 0
  232. sp := make(chan bool, 5)
  233. for {
  234. select {
  235. case v := <-p.updatePool:
  236. arru[indexu] = v
  237. indexu++
  238. if indexu == p.saveSize {
  239. sp <- true
  240. go func(arru [][]map[string]interface{}) {
  241. defer func() {
  242. <-sp
  243. }()
  244. MongoTool.UpSertBulk(p.coll, arru...)
  245. }(arru)
  246. arru = make([][]map[string]interface{}, p.saveSize)
  247. indexu = 0
  248. }
  249. case <-time.After(500 * time.Millisecond):
  250. if indexu > 0 {
  251. sp <- true
  252. go func(arru [][]map[string]interface{}) {
  253. defer func() {
  254. <-sp
  255. }()
  256. MongoTool.UpSertBulk(p.coll, arru...)
  257. }(arru[:indexu])
  258. //MongoTool.UpSertBulk(p.coll, arru[:indexu]...)
  259. arru = make([][]map[string]interface{}, p.saveSize)
  260. indexu = 0
  261. }
  262. }
  263. }
  264. }
  265. //项目合并内存更新
  266. func (p *ProjectTask) clearMem() {
  267. c := cron.New()
  268. //在内存中保留最近6个月的信息
  269. //跑全量时每4分钟跑一次,跑增量时400分钟跑一次
  270. c.AddFunc("50 0/15 * * * *", func() {
  271. if p.currentType == "ql" || p.clearContimes >= 60 {
  272. //跳过的次数清零
  273. p.clearContimes = 0
  274. //信息进入查找对比全局锁
  275. p.findLock.Lock()
  276. //defer p.findLock.Unlock()
  277. //合并进行的任务都完成
  278. p.wg.Wait()
  279. //遍历id
  280. //所有内存中的项目信息
  281. p.AllIdsMapLock.Lock()
  282. //清除计数
  283. clearNum := 0
  284. for k, v := range p.AllIdsMap {
  285. if p.currentTime-v.P.LastTime > p.validTime {
  286. clearNum++
  287. //删除id的map
  288. delete(p.AllIdsMap, k)
  289. //删除pb
  290. if v.P.Buyer != "" {
  291. ids := p.mapPb[v.P.Buyer]
  292. if ids != nil {
  293. ids.Lock.Lock()
  294. ids.Arr = deleteSlice(ids.Arr, k)
  295. if len(ids.Arr) == 0 {
  296. delete(p.mapPb, v.P.Buyer)
  297. }
  298. ids.Lock.Unlock()
  299. }
  300. }
  301. //删除mapPn
  302. for _, vn := range append([]string{v.P.ProjectName}, v.P.MPN...) {
  303. if vn != "" {
  304. ids := p.mapPn[vn]
  305. if ids != nil {
  306. ids.Lock.Lock()
  307. ids.Arr = deleteSlice(ids.Arr, k)
  308. if len(ids.Arr) == 0 {
  309. delete(p.mapPn, vn)
  310. }
  311. ids.Lock.Unlock()
  312. }
  313. }
  314. }
  315. //删除mapPc
  316. for _, vn := range append([]string{v.P.ProjectCode}, v.P.MPC...) {
  317. if vn != "" {
  318. ids := p.mapPc[vn]
  319. if ids != nil {
  320. ids.Lock.Lock()
  321. ids.Arr = deleteSlice(ids.Arr, k)
  322. if len(ids.Arr) == 0 {
  323. delete(p.mapPc, vn)
  324. }
  325. ids.Lock.Unlock()
  326. }
  327. }
  328. }
  329. v = nil
  330. }
  331. }
  332. p.AllIdsMapLock.Unlock()
  333. p.findLock.Unlock()
  334. log.Println("清除完成:", clearNum, len(p.AllIdsMap), len(p.mapPn), len(p.mapPc), len(p.mapPb))
  335. } else {
  336. p.clearContimes++
  337. }
  338. })
  339. c.Start()
  340. select {}
  341. }
  342. //全量合并
  343. func (p *ProjectTask) taskQl(udpInfo map[string]interface{}) {
  344. defer util.Catch()
  345. //1、检查pubilshtime索引
  346. db, _ := udpInfo["db"].(string)
  347. if db == "" {
  348. db = MongoTool.DbName
  349. }
  350. coll, _ := udpInfo["coll"].(string)
  351. if coll == "" {
  352. coll = ExtractColl
  353. }
  354. // sess := MongoTool.GetMgoConn()
  355. // bcon := false
  356. // if sess.DB(db).C(coll).EnsureIndexKey("publishtime_1", "publishtime_-1") == nil {
  357. // bcon = true
  358. // } else {
  359. // log.Println("publishtime_1索引不存在")
  360. // }
  361. // MongoTool.DestoryMongoConn(sess)
  362. thread := util.IntAllDef(udpInfo["thread"], 4)
  363. if thread > 0 {
  364. p.thread = thread
  365. }
  366. q, _ := udpInfo["query"].(map[string]interface{})
  367. if q == nil {
  368. q = map[string]interface{}{}
  369. lteid, _ := udpInfo["lteid"].(string)
  370. var idmap map[string]interface{}
  371. if len(lteid) > 15 {
  372. idmap = map[string]interface{}{
  373. "$lte": util.StringTOBsonId(lteid),
  374. }
  375. }
  376. gtid, _ := udpInfo["gtid"].(string)
  377. if len(gtid) > 15 {
  378. if idmap == nil {
  379. idmap = map[string]interface{}{}
  380. }
  381. idmap["$gt"] = util.StringTOBsonId(gtid)
  382. }
  383. if idmap != nil {
  384. q["_id"] = idmap
  385. }
  386. }
  387. //生成查询语句执行
  388. log.Println("查询语句:", q)
  389. p.enter(db, coll, q)
  390. }
  391. //增量合并
  392. func (p *ProjectTask) taskZl(udpInfo map[string]interface{}) {
  393. defer util.Catch()
  394. //1、检查pubilshtime索引
  395. db, _ := udpInfo["db"].(string)
  396. if db == "" {
  397. db = MongoTool.DbName
  398. }
  399. coll, _ := udpInfo["coll"].(string)
  400. if coll == "" {
  401. coll = ExtractColl
  402. }
  403. thread := util.IntAllDef(udpInfo["thread"], 3)
  404. if thread > 0 {
  405. p.thread = thread
  406. }
  407. //开始id和结束id
  408. q, _ := udpInfo["query"].(map[string]interface{})
  409. gtid := udpInfo["gtid"].(string)
  410. lteid := udpInfo["lteid"].(string)
  411. if q == nil {
  412. q = map[string]interface{}{
  413. "_id": map[string]interface{}{
  414. "$gt": util.StringTOBsonId(gtid), //util.StringTOBsonId(udpInfo["gtid"].(string)),
  415. "$lte": util.StringTOBsonId(lteid), //util.StringTOBsonId(udpInfo["lteid"].(string)),
  416. },
  417. }
  418. }
  419. if q != nil {
  420. //生成查询语句执行
  421. p.enter(db, coll, q)
  422. }
  423. nextNode(gtid, lteid, "project", p.pici)
  424. }
  425. //通知下个节点nextNode
  426. func nextNode(gtid, lteid, stype string, pici int64) {
  427. by, _ := json.Marshal(map[string]interface{}{
  428. "gtid": gtid,
  429. "lteid": lteid,
  430. "stype": stype,
  431. "query": map[string]interface{}{
  432. "pici": pici,
  433. },
  434. })
  435. log.Println("nextnode", string(by))
  436. for _, v := range NextNode {
  437. if node, ok := v.(map[string]interface{}); ok {
  438. udpclient.WriteUdp(by, mu.OP_TYPE_DATA, &net.UDPAddr{
  439. IP: net.ParseIP(node["addr"].(string)),
  440. Port: util.IntAll(node["port"]),
  441. })
  442. }
  443. }
  444. }
  445. func (p *ProjectTask) enter(db, coll string, q map[string]interface{}) {
  446. defer util.Catch()
  447. count, taskcount := 0, 0
  448. //var lastid interface{}
  449. // for {
  450. // if lastid != nil {
  451. // if q == nil {
  452. // q = map[string]interface{}{}
  453. // }
  454. // if q["_id"] == nil {
  455. // q["_id"] = map[string]interface{}{}
  456. // }
  457. // q["_id"].(map[string]interface{})["$gt"] = lastid
  458. // }
  459. pool := make(chan bool, p.thread)
  460. log.Println("start project", q)
  461. sess := MongoTool.GetMgoConn()
  462. defer MongoTool.DestoryMongoConn(sess)
  463. query := sess.DB(db).C(coll).Find(q).Sort("publishtime").Iter()
  464. // .Select(map[string]interface{}{
  465. // "blocks": 0,
  466. // "fieldall": 0,
  467. // }).Iter()
  468. //over := 0
  469. for tmp := make(map[string]interface{}); query.Next(tmp); count++ {
  470. if util.IntAll(tmp["repeat"]) == 0 {
  471. info := ParseInfo(tmp)
  472. if info != nil && !((info.pnbval == 1 && info.Buyer != "") || info.pnbval == 0) {
  473. pool <- true
  474. taskcount++
  475. go func(info *Info, tmp map[string]interface{}) {
  476. defer func() {
  477. p.currentTime = info.Publishtime
  478. <-pool
  479. }()
  480. p.startProjectMerge(info, tmp)
  481. }(info, tmp)
  482. } else {
  483. //信息错误,进行更新
  484. }
  485. }
  486. if count%1000 == 0 {
  487. log.Println("current", count)
  488. }
  489. // if taskcount > 0 && taskcount%50000 == 0 { //歇歇
  490. // log.Println("pause start..", taskcount)
  491. // for n := 0; n < p.thread; n++ {
  492. // pool <- true
  493. // }
  494. // for n := 0; n < p.thread; n++ {
  495. // <-pool
  496. // }
  497. // log.Println("pause over..")
  498. // }
  499. //lastid = tmp["_id"]
  500. tmp = make(map[string]interface{})
  501. // if count > 40000 {
  502. // query.Close()
  503. // break
  504. // }
  505. //over++
  506. }
  507. //阻塞
  508. for n := 0; n < p.thread; n++ {
  509. pool <- true
  510. }
  511. // if over == 0 {
  512. // break
  513. // }
  514. //}
  515. log.Println("所有线程执行完成...", count, taskcount)
  516. }
  517. var (
  518. //从标题获取项目编号
  519. titleGetPc = regexp.MustCompile("^([-0-9a-zA-Z第号采招政询电审竞#]{8,}[-0-9a-zA-Z#]+)")
  520. titleGetPc1 = regexp.MustCompile("[\\[【((](.{0,6}(编号|编码|项号|包号|代码|标段?号)[::为])?([-0-9a-zA-Z第号采招政询电审竞#]{5,}([\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+[\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+)?)[\\]】))]")
  521. titleGetPc2 = regexp.MustCompile("([-0-9a-zA-Z第号采政招询电审竞#]{8,}[-0-9a-zA-Z#]+)(.{0,5}公告)?$")
  522. //项目编号过滤
  523. pcReplace = regexp.MustCompile("([\\[【((〖〔《{﹝{](重|第?[二三四再]次.{0,4})[\\]】))〗〕》}﹞}])$|[\\[\\]【】()()〖〗〔〕《》{}﹝﹞-;{}–  ]+|(号|重|第?[二三四五再]次(招标)?)$|[ __]+|((采购)?项目|采购(项目)?)$")
  524. //项目编号只是数字或只是字母4个以下
  525. StrOrNum = regexp.MustCompile("^[0-9_-]{1,4}$|^[a-zA-Z_-]{1,4}$")
  526. //纯数字或纯字母
  527. StrOrNum2 = regexp.MustCompile("^[0-9_-]+$|^[a-zA-Z_-]+$")
  528. )
  529. func ParseInfo(tmp map[string]interface{}) (info *Info) {
  530. bys, _ := json.Marshal(tmp)
  531. var thisinfo *Info
  532. json.Unmarshal(bys, &thisinfo)
  533. if thisinfo == nil {
  534. return nil
  535. }
  536. if len(thisinfo.Topscopeclass) == 0 {
  537. thisinfo.Topscopeclass = []string{}
  538. }
  539. if len(thisinfo.Subscopeclass) == 0 {
  540. thisinfo.Subscopeclass = []string{}
  541. }
  542. //从标题中查找项目编号
  543. res := titleGetPc.FindStringSubmatch(thisinfo.Title)
  544. if len(res) > 1 && len(res[1]) > 6 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  545. thisinfo.PTC = res[1]
  546. } else {
  547. res = titleGetPc1.FindStringSubmatch(thisinfo.Title)
  548. if len(res) > 3 && len(res[3]) > 6 && thisinfo.ProjectCode != res[3] && !numCheckPc.MatchString(res[3]) && !_zimureg1.MatchString(res[3]) {
  549. thisinfo.PTC = res[3]
  550. } else {
  551. res = titleGetPc2.FindStringSubmatch(thisinfo.Title)
  552. if len(res) > 1 && len(res[1]) > 6 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  553. thisinfo.PTC = res[1]
  554. }
  555. }
  556. }
  557. if thisinfo.ProjectName != "" && len([]rune(thisinfo.ProjectName)) > 0 {
  558. thisinfo.ProjectName = pcReplace.ReplaceAllString(thisinfo.ProjectName, "")
  559. if thisinfo.ProjectName != "" {
  560. thisinfo.pnbval++
  561. }
  562. }
  563. if thisinfo.ProjectCode != "" || thisinfo.PTC != "" {
  564. if thisinfo.ProjectCode != "" {
  565. thisinfo.ProjectCode = pcReplace.ReplaceAllString(thisinfo.ProjectCode, "")
  566. if thisinfo.pnbval == 0 && len([]rune(thisinfo.ProjectCode)) < 5 {
  567. thisinfo.ProjectCode = StrOrNum.ReplaceAllString(thisinfo.ProjectCode, "")
  568. }
  569. } else {
  570. thisinfo.PTC = pcReplace.ReplaceAllString(thisinfo.PTC, "")
  571. if thisinfo.pnbval == 0 && len([]rune(thisinfo.PTC)) < 5 {
  572. thisinfo.PTC = StrOrNum.ReplaceAllString(thisinfo.PTC, "")
  573. }
  574. }
  575. if thisinfo.ProjectCode != "" || thisinfo.PTC != "" {
  576. thisinfo.pnbval++
  577. }
  578. }
  579. if thisinfo.ProjectCode == thisinfo.PTC || strings.Index(thisinfo.ProjectCode, thisinfo.PTC) > -1 {
  580. thisinfo.PTC = ""
  581. }
  582. if thisinfo.Buyer != "" && len([]rune(thisinfo.Buyer)) > 2 {
  583. thisinfo.pnbval++
  584. } else {
  585. thisinfo.Buyer = ""
  586. }
  587. //winners整理
  588. winner, _ := tmp["winner"].(string)
  589. m1 := map[string]bool{}
  590. winners := []string{}
  591. if winner != "" {
  592. m1[winner] = true
  593. winners = append(winners, winner)
  594. }
  595. if thisinfo.HasPackage {
  596. packageM, _ := tmp["package"].(map[string]interface{})
  597. for _, p := range packageM {
  598. pm, _ := p.(map[string]interface{})
  599. pw, _ := pm["winner"].(string)
  600. if pw != "" && !m1[pw] {
  601. m1[pw] = true
  602. winners = append(winners, pw)
  603. }
  604. }
  605. }
  606. thisinfo.Winners = winners
  607. thisinfo.LenPC = len([]rune(thisinfo.ProjectCode))
  608. thisinfo.LenPTC = len([]rune(thisinfo.PTC))
  609. thisinfo.LenPN = len([]rune(thisinfo.ProjectName))
  610. return thisinfo
  611. }
  612. //从数组中删除元素
  613. func deleteSlice(arr []string, v string) []string {
  614. for k, v1 := range arr {
  615. if v1 == v {
  616. return append(arr[:k], arr[k+1:]...)
  617. }
  618. }
  619. return arr
  620. }