EmployService.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. package service
  2. import (
  3. "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/date"
  5. elastic "app.yhyue.com/moapp/jybase/es"
  6. "app.yhyue.com/moapp/jybase/mongodb"
  7. "app.yhyue.com/moapp/jypkg/ent/util"
  8. "app.yhyue.com/moapp/jypkg/public"
  9. MC "bp.jydev.jianyu360.cn/CRM/application/api/common"
  10. "bp.jydev.jianyu360.cn/CRM/application/api/internal/types"
  11. "bp.jydev.jianyu360.cn/CRM/application/entity"
  12. "database/sql"
  13. "fmt"
  14. "github.com/RoaringBitmap/roaring"
  15. "go.mongodb.org/mongo-driver/bson"
  16. "log"
  17. "regexp"
  18. "strconv"
  19. "strings"
  20. "time"
  21. )
  22. const (
  23. BuyerIndex = "buyer" // 采购单位index
  24. BuyerType = "buyer"
  25. )
  26. type EmPloyService struct{}
  27. // 收录情况查询
  28. func (e *EmPloyService) InfoEmployinfo(in *types.InfoEmployinfoReq) []map[string]interface{} {
  29. data := []map[string]interface{}{}
  30. for _, v := range strings.Split(in.IdArr, ",") {
  31. vint := int64(0)
  32. table, findKey, employKey, source := EmployKeyFormat(in.EmployType)
  33. id := ""
  34. id = IdFormat(v, in.EmployType)
  35. if id == "" {
  36. log.Println(v, in.EmployType, "该信息查询不到数据")
  37. break
  38. }
  39. valueMap := map[string]interface{}{
  40. "id": v,
  41. }
  42. //有收录情况
  43. summaryMap := SummaryFormat(in.PositionId)
  44. //vint = mongodb.StringTOBsonId(id).Timestamp().Unix()
  45. vint = extractNumbers(id)
  46. valueMap["isEmploy"] = summaryMap[in.EmployType].Contains(uint32(vint))
  47. if len(strings.Split(in.IdArr, ",")) == 1 {
  48. //列表查询
  49. //是否忽略处理
  50. employData := MC.CrmMysql.FindOne(table, map[string]interface{}{
  51. employKey: id,
  52. "position_id": in.PositionId,
  53. "source": source,
  54. }, "", "")
  55. if employData != nil && len(*employData) > 0 {
  56. valueMap["isIgnore"] = common.If(common.Int64All((*employData)["is_ignore"]) == 1, true, false)
  57. //客户数量
  58. customCount := MC.CrmMysql.Count(entity.CUSTOM, map[string]interface{}{
  59. findKey: id,
  60. "position_id": in.PositionId,
  61. })
  62. valueMap["customCount"] = customCount
  63. if in.EmployType == 1 || in.EmployType == 4 {
  64. //销售线索数量
  65. clueCount := MC.CrmMysql.Count(entity.SALE_CLUE, map[string]interface{}{
  66. "employ_info_id": id,
  67. "position_id": in.PositionId,
  68. })
  69. valueMap["clueCount"] = clueCount
  70. //销售机会数量
  71. chanceCount := MC.CrmMysql.Count(entity.SALE_CHANCE, map[string]interface{}{
  72. "employ_info_id": id,
  73. "position_id": in.PositionId,
  74. })
  75. valueMap["chanceCount"] = chanceCount
  76. }
  77. } else {
  78. valueMap["chanceCount"] = 0
  79. valueMap["clueCount"] = 0
  80. valueMap["isIgnore"] = false
  81. valueMap["customCount"] = 0
  82. }
  83. }
  84. data = append(data, valueMap)
  85. }
  86. return data
  87. }
  88. // 收录操作
  89. func (e *EmPloyService) EmployOperate(in *types.EmployOperateReq) bool {
  90. //收录汇总表
  91. table, _, employKey, source := EmployKeyFormat(in.EmployType)
  92. summaryMap := SummaryFormat(in.PositionId)
  93. return MC.CrmMysql.ExecTx("收录操作", func(tx *sql.Tx) bool {
  94. fool := false
  95. for _, v1 := range strings.Split(in.IdArr, ",") {
  96. //id转中文
  97. id := ""
  98. findMap := map[string]interface{}{}
  99. findMap["position_id"] = in.PositionId
  100. id = IdFormat(v1, in.EmployType)
  101. findMap[employKey] = id
  102. if id == "" {
  103. log.Println(v1, in.EmployType, "该信息查询不到数据")
  104. break
  105. }
  106. if in.IsEmploy {
  107. if MC.CrmMysql.Count(table, findMap) > 0 {
  108. MC.CrmMysql.UpdateByTx(tx, table, findMap, map[string]interface{}{
  109. "status": 1,
  110. })
  111. } else {
  112. //收录新增
  113. data := map[string]interface{}{}
  114. if in.EmployType == 1 || in.EmployType == 4 {
  115. data = InfoFind(id, in.EmployType)
  116. data["employ_way"] = 1
  117. data["jybx_url"] = "/article/content/" + v1 + ".html"
  118. } else {
  119. data = CustomFind(id, in.EmployType)
  120. }
  121. data["position_id"] = in.PositionId
  122. data["ent_id"] = in.EntId
  123. data["source"] = source
  124. ok := MC.CrmMysql.InsertByTx(tx, table, data)
  125. if ok <= 0 {
  126. log.Println(v1, id, in.EmployType, "收录失败")
  127. break
  128. }
  129. }
  130. } else {
  131. //取消收录
  132. ok := MC.CrmMysql.UpdateByTx(tx, table, findMap, map[string]interface{}{
  133. "status": -1,
  134. })
  135. if !ok {
  136. log.Println(v1, id, in.EmployType, "取消收录失败")
  137. }
  138. }
  139. //收录汇总表处理
  140. vint := extractNumbers(id)
  141. if in.IsEmploy {
  142. summaryMap[in.EmployType].Add(uint32(vint))
  143. } else {
  144. summaryMap[in.EmployType].Remove(uint32(vint))
  145. }
  146. fool = true
  147. }
  148. if fool {
  149. return SummarySave(tx, in.PositionId, summaryMap)
  150. } else {
  151. return false
  152. }
  153. })
  154. }
  155. // 企业信息查询
  156. func CustomFind(id string, employType int64) map[string]interface{} {
  157. data := map[string]interface{}{}
  158. //company_id 企业id name户名称 address 地址
  159. if employType == 2 {
  160. //企业详情
  161. entinfo, _ := MC.MgoEnt.FindOneByField("qyxy_std", map[string]interface{}{"_id": id}, map[string]interface{}{
  162. "company_address": 1, //注册地
  163. "company_name": 1,
  164. })
  165. if entinfo != nil && len(*entinfo) > 0 {
  166. data["name"] = (*entinfo)["company_name"]
  167. data["address"] = (*entinfo)["company_address"]
  168. data["company_id"] = id
  169. }
  170. } else {
  171. //采购单位详情
  172. rs := elastic.Get(BuyerIndex, BuyerType, fmt.Sprintf(`{"query":{"bool":{"must":[{"terms":{"_id":["%s"]}}]}},"size":1,"_source":["buyer_name","city"]}`, id))
  173. if rs != nil && len(*rs) > 0 {
  174. data["name"] = (*rs)[0]["buyer_name"]
  175. data["address"] = (*rs)[0]["city"]
  176. data["company_id"] = id
  177. }
  178. }
  179. data["status"] = 1
  180. data["create_time"] = time.Now().Format(date.Date_Full_Layout)
  181. return data
  182. }
  183. // 标讯信息查询
  184. func InfoFind(id string, employType int64) map[string]interface{} {
  185. data := map[string]interface{}{}
  186. //source_id 信息id、项目id- title 标题-area 省 -city 市 -subtype 信息类型二级分类
  187. //buyerclass 采购单位行业 -budget 预算 -bidamount 中标金额 buyer采购单位 annex有无附件 publishtime发布时间 projectname 项目时间
  188. //ownerclass 业主类型(拟在建搜索) expurasing_time 预计采购时间 jybx_url 标讯详情页
  189. if employType == 1 {
  190. //标讯信息
  191. obj := map[string]interface{}{}
  192. brobj, ok := MC.Mgo.Find("bidding_rec", bson.M{"s_id": id}, `{"l_recoverydate":-1}`, public.MgoBiddingFields, false, 0, 1)
  193. if ok && (*brobj) != nil && len(*brobj) == 1 && (*brobj)[0] != nil {
  194. obj = (*brobj)[0]
  195. } else {
  196. aobj, ok := MC.MgoBidding.FindById("bidding", id, public.MgoBiddingFields)
  197. if ok && (aobj == nil || *aobj == nil || len(*aobj) == 0) {
  198. aobj, ok = MC.MgoBidding.FindById("bidding_back", id, public.MgoBiddingFields)
  199. }
  200. obj = *aobj
  201. }
  202. if ok && obj != nil && len(obj) > 0 {
  203. titleTmp := common.ObjToString(obj["title"])
  204. if len([]rune(titleTmp)) > 100 {
  205. titleTmp = string([]rune(titleTmp)[:100]) + "..."
  206. }
  207. titleTmp = public.ClearHtml.ReplaceAllString(titleTmp, "")
  208. data["title"] = titleTmp
  209. data["city"] = obj["city"]
  210. data["area"] = obj["area"]
  211. data["subtype"] = obj["subtype"]
  212. data["buyerclass"] = obj["buyerclass"]
  213. data["budget"] = obj["budget"]
  214. data["bidamount"] = obj["bidamount"]
  215. data["annex"] = 0
  216. //类型处理
  217. toptype := common.InterfaceToStr(obj["toptype"])
  218. switch toptype {
  219. case "采购意向", "预告", "招标":
  220. data["type"] = 2
  221. case "其他", "结果":
  222. data["type"] = 3
  223. default:
  224. data["type"] = 1
  225. }
  226. //data["type"] = in.SourceType
  227. if obj["projectinfo"] != nil {
  228. projectinfo := common.ObjToMap(obj["projectinfo"])
  229. if (*projectinfo)["attachments"] != nil {
  230. data["annex"] = 1
  231. }
  232. }
  233. data["publishtime"] = time.Unix(common.Int64All(obj["publishtime"]), 0).Format(date.Date_Full_Layout)
  234. data["show_time"] = time.Unix(common.Int64All(obj["publishtime"]), 0).Format(date.Date_Full_Layout)
  235. data["projectname"] = obj["projectname"]
  236. procurementlist, _ := obj["procurementlist"].([]interface{})
  237. for _, vs := range procurementlist { //1.采购意向清单数据集打码处理
  238. vsMap, _ := vs.(map[string]interface{})
  239. if vsMap["expurasingtime"] != nil {
  240. data["expurasing_time"] = vsMap["expurasingtime"]
  241. break
  242. }
  243. }
  244. }
  245. }
  246. data["status"] = 1
  247. data["employ_way"] = 1
  248. data["source_id"] = id
  249. data["create_time"] = time.Now().Format(date.Date_Full_Layout)
  250. return data
  251. }
  252. func getBuyerIdByName(buyeName string) (buyerId string) {
  253. r := elastic.Get(BuyerIndex, BuyerType, fmt.Sprintf(`{"query":{"bool":{"must":[{"term":{"buyer_name":"%s"}}]}},"size":1,"_source":["city","id"]}`, buyeName))
  254. if r == nil || len(*r) == 0 {
  255. return
  256. }
  257. buyerId, _ = (*r)[0]["_id"].(string)
  258. return
  259. }
  260. func IdFormat(encryptionId string, employType int64) string {
  261. decryptId := ""
  262. switch employType {
  263. case 1, 2:
  264. decryptId = util.DecodeId(encryptionId)
  265. case 3:
  266. if len(encryptionId) > 0 && len([]rune(encryptionId)) == len(encryptionId) {
  267. //此数据是id
  268. //获取中文名字
  269. decryptId = util.DecodeId(encryptionId)
  270. } else {
  271. //次数据传的名字
  272. decryptId = getBuyerIdByName(encryptionId)
  273. }
  274. }
  275. return decryptId
  276. }
  277. func SummaryFormat(positionId int64) map[int64]*roaring.Bitmap {
  278. byte1 := []byte{}
  279. byte2 := []byte{}
  280. byte3 := []byte{}
  281. byte4 := []byte{}
  282. MC.CrmMysql.DB.QueryRow("select search_tencent, search_buyer, search_ent, search_nzj from employ_summary where position_id=?", positionId).Scan(&byte1, &byte3, &byte2, &byte4)
  283. rb1 := roaring.NewBitmap()
  284. rb2 := roaring.NewBitmap()
  285. rb3 := roaring.NewBitmap()
  286. rb4 := roaring.NewBitmap()
  287. data := map[int64]*roaring.Bitmap{}
  288. if byte1 != nil && len(byte1) > 0 {
  289. rb1.UnmarshalBinary(byte1)
  290. }
  291. if byte2 != nil && len(byte2) > 0 {
  292. rb2.UnmarshalBinary(byte2)
  293. }
  294. if byte3 != nil && len(byte3) > 0 {
  295. rb3.UnmarshalBinary(byte3)
  296. }
  297. if byte4 != nil && len(byte4) > 0 {
  298. rb4.UnmarshalBinary(byte4)
  299. }
  300. data[1] = rb1
  301. data[2] = rb2
  302. data[3] = rb3
  303. data[4] = rb4
  304. return data
  305. }
  306. func SummarySave(tx *sql.Tx, positionId int64, data map[int64]*roaring.Bitmap) bool {
  307. employSummaryData := MC.CrmMysql.FindOne(entity.EMPLOY_SUMMARY, map[string]interface{}{
  308. "position_id": positionId,
  309. }, "", "")
  310. if employSummaryData != nil && len(*employSummaryData) > 0 {
  311. //修改
  312. updateData := map[string]interface{}{}
  313. updateData["search_tencent"], _ = data[1].ToBytes()
  314. updateData["search_buyer"], _ = data[3].ToBytes()
  315. updateData["search_ent"], _ = data[2].ToBytes()
  316. updateData["search_nzj"], _ = data[4].ToBytes()
  317. ok := MC.CrmMysql.UpdateByTx(tx, entity.EMPLOY_SUMMARY, map[string]interface{}{
  318. "position_id": positionId,
  319. }, updateData)
  320. return ok
  321. } else {
  322. //新增
  323. insertData := map[string]interface{}{}
  324. insertData["position_id"] = positionId
  325. insertData["search_tencent"], _ = data[1].ToBytes()
  326. insertData["search_buyer"], _ = data[3].ToBytes()
  327. insertData["search_ent"], _ = data[2].ToBytes()
  328. insertData["search_nzj"], _ = data[4].ToBytes()
  329. ok := MC.CrmMysql.InsertByTx(tx, entity.EMPLOY_SUMMARY, insertData)
  330. return ok > 0
  331. }
  332. }
  333. // 根据收录类型 字段处理 table,findKey,employKey,source
  334. func EmployKeyFormat(employType int64) (string, string, string, int64) {
  335. table := ""
  336. employKey := "company_id"
  337. findKey := "employ_custom_id"
  338. source := int64(0)
  339. switch employType {
  340. case 1:
  341. table = entity.EMPLOY_INFO
  342. employKey = "source_id"
  343. findKey = "employ_info_id"
  344. source = 1
  345. case 2:
  346. table = entity.EMPLOY_CUSTOM
  347. source = 1
  348. case 3:
  349. table = entity.EMPLOY_CUSTOM
  350. source = 2
  351. case 4:
  352. table = entity.EMPLOY_INFO
  353. source = 2
  354. employKey = "source_id"
  355. findKey = "employ_info_id"
  356. }
  357. return table, findKey, employKey, source
  358. }
  359. // 忽略操作
  360. func (e *EmPloyService) IgnoreOperate(in *types.IgnoreOperateReq) {
  361. //
  362. table := ""
  363. switch in.EmployType {
  364. case 1, 4:
  365. table = entity.EMPLOY_INFO
  366. case 2, 3:
  367. table = entity.EMPLOY_CUSTOM
  368. }
  369. for _, v := range strings.Split(in.IdArr, ",") {
  370. id := IdFormat(v, in.EmployType)
  371. if id == "" {
  372. log.Println(v, id, in.EmployType, "忽略处理,id解析失败")
  373. break
  374. }
  375. findMap := map[string]interface{}{
  376. "position_id": in.PositionId,
  377. }
  378. if in.EmployType == 3 || in.EmployType == 2 {
  379. findMap["company_id"] = id
  380. } else {
  381. findMap["source_id"] = id
  382. }
  383. if MC.CrmMysql.Count(table, findMap) == 0 {
  384. log.Println(v, id, in.EmployType, "忽略处理,id所对应数据不存在")
  385. break
  386. }
  387. if in.IsIgnore {
  388. MC.CrmMysql.Update(table, findMap, map[string]interface{}{
  389. "is_ignore": 1,
  390. })
  391. } else {
  392. MC.CrmMysql.Update(table, findMap, map[string]interface{}{
  393. "is_ignore": 0,
  394. })
  395. }
  396. }
  397. }
  398. type PersonSmmary struct {
  399. EntUserId int64
  400. Summary map[int64]*roaring.Bitmap
  401. }
  402. // 分发操作
  403. func (e *EmPloyService) DistributePerson(in *types.EmployDistributeReq) bool {
  404. return MC.CrmMysql.ExecTx("收录操作", func(tx *sql.Tx) bool {
  405. personMap := map[int64]PersonSmmary{}
  406. //汇总表查询
  407. for _, person := range in.Person {
  408. personMap[person.PositionId] = PersonSmmary{
  409. EntUserId: person.EntUserId,
  410. Summary: SummaryFormat(person.PositionId),
  411. }
  412. }
  413. //分发数据处理
  414. infoMap := map[string]map[string]interface{}{}
  415. for positionId, personSmmary := range personMap {
  416. fool := false
  417. for _, v := range strings.Split(in.EmployIdArr, ",") {
  418. VMap := map[string]interface{}{}
  419. if infoMap[v] == nil {
  420. //新增记录
  421. infoData := MC.CrmMysql.FindOne(entity.EMPLOY_INFO, map[string]interface{}{
  422. "id": v,
  423. }, "", "")
  424. if infoData != nil && len(*infoData) > 0 {
  425. (*infoData)["dis_id"] = v
  426. (*infoData)["is_handle"] = 0
  427. (*infoData)["is_ignore"] = 0
  428. (*infoData)["is_dis"] = 0
  429. (*infoData)["is_create_clue"] = 0
  430. (*infoData)["is_create_chance"] = 0
  431. (*infoData)["is_create_custom"] = 0
  432. (*infoData)["create_time"] = time.Now().Format(date.Date_Full_Layout)
  433. delete((*infoData), "id")
  434. } else {
  435. log.Println(v, "查询不到改收录信息")
  436. break
  437. }
  438. //更改已分发状态
  439. if common.IntAll((*infoData)["is_dis"]) != 1 {
  440. MC.CrmMysql.UpdateByTx(tx, entity.EMPLOY_INFO, map[string]interface{}{
  441. "id": v,
  442. }, map[string]interface{}{
  443. "is_dis": 1,
  444. })
  445. }
  446. infoMap[v] = *infoData
  447. VMap = (*infoData)
  448. } else {
  449. VMap = infoMap[v]
  450. }
  451. //查询时候收录过
  452. findMap := map[string]interface{}{
  453. "position_id": positionId,
  454. "source_id": VMap["source_id"],
  455. }
  456. if MC.CrmMysql.Count(entity.EMPLOY_INFO, findMap) == 0 {
  457. //新增
  458. //
  459. VMap["ent_user_id"] = personSmmary.EntUserId
  460. VMap["position_id"] = positionId
  461. ok := MC.CrmMysql.InsertByTx(tx, entity.EMPLOY_INFO, VMap)
  462. if ok > 0 {
  463. employType := common.If(common.Int64All(VMap["source"]) == 1, 1, 4)
  464. personSmmary.Summary[common.Int64All(employType)].Add(uint32(mongodb.StringTOBsonId(common.InterfaceToStr(VMap["source_id"])).Timestamp().Unix()))
  465. fool = true
  466. }
  467. }
  468. if fool {
  469. if !SummarySave(tx, positionId, personSmmary.Summary) {
  470. return false
  471. }
  472. }
  473. }
  474. }
  475. return true
  476. })
  477. }
  478. // 提取字符串中的数字
  479. func extractNumbers(str string) int64 {
  480. re := regexp.MustCompile(`\d+`)
  481. matches := re.FindAllString(str, -1)
  482. numbers := make([]int, len(matches))
  483. for i, match := range matches {
  484. number, err := strconv.Atoi(match)
  485. if err == nil {
  486. numbers[i] = number
  487. }
  488. }
  489. result := 0
  490. for _, number := range numbers {
  491. result = result*10 + number
  492. }
  493. return int64(result)
  494. }