participateStatistics.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. package service
  2. import (
  3. "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/encrypt"
  5. "app.yhyue.com/moapp/jybase/redis"
  6. "encoding/json"
  7. "fmt"
  8. "jyBXCore/rpc/bxcore"
  9. IC "jyBXCore/rpc/init"
  10. "jyBXCore/rpc/model/es"
  11. "log"
  12. "strconv"
  13. "strings"
  14. "time"
  15. )
  16. const (
  17. //角色
  18. Role_admin_system = 1 //系统管理员
  19. Role_admin_department = 2 //部门管理员
  20. )
  21. type ParticipateStatistics struct {
  22. PositionId int64
  23. EntId int64
  24. DeptId int64
  25. EntUserId int64
  26. }
  27. func (in *ParticipateStatistics) PushStatistics(entUserIdArr []string, startTime, endTime int64, source []int64) (result []*bxcore.PushStatisticsData) {
  28. //判断是企业、部门还是个人
  29. isAdmin, personArrStr, users := in.PersonHandle(entUserIdArr)
  30. //时间处理
  31. query := QueryHandle(isAdmin, startTime, endTime, personArrStr, source, 0)
  32. //推送数据查询
  33. dataList := IC.BaseMysql.SelectBySql(fmt.Sprintf("select * from participate_push_statistics where %s order by ymd", strings.Join(query, " and ")))
  34. if users != nil && len(*users) > 0 {
  35. result = PushHandle(dataList, users, isAdmin)
  36. }
  37. return
  38. }
  39. func (in *ParticipateStatistics) ProjectStatistics(entUserIdArr []string, startTime, endTime, bidWay int64) (result []*bxcore.ProjectStatisticsData) {
  40. //判断是企业、部门还是个人
  41. isAdmin, personArrStr, users := in.PersonHandle(entUserIdArr)
  42. query := QueryHandle(isAdmin, startTime, endTime, personArrStr, []int64{}, bidWay)
  43. //订阅推送数处理
  44. //推送数据查询
  45. // 调整为时间倒序 处理投标阶段的时候 只取最新的一条的数据
  46. dataList := IC.BaseMysql.SelectBySql(fmt.Sprintf("select * from participate_project_statistics where %s order by ymd desc ", strings.Join(query, "and ")))
  47. if users != nil && len(*users) > 0 {
  48. result = ProjectHandle(dataList, users, isAdmin)
  49. }
  50. return
  51. }
  52. var (
  53. SelectItemMap = map[int]string{
  54. 1: "个人订阅",
  55. 2: "企业自动分发",
  56. 3: "企业手动分发",
  57. }
  58. SourceMap = map[string]string{
  59. "1": "个人订阅",
  60. "2": "企业自动分发",
  61. "3": "企业手动分发",
  62. }
  63. )
  64. // GetSourceItem 获取标讯项目来源筛选项
  65. func (in *ParticipateStatistics) GetSourceItem(entId, positionId int) (result []*bxcore.SourceItem) {
  66. redisKey := "sourceItem%s_%s"
  67. query := "select distinct `source` from participate_push_statistics where "
  68. // 个人用户
  69. if entId == 0 {
  70. // 查职位id
  71. query += fmt.Sprintf(" position_id =%d", positionId)
  72. redisKey = fmt.Sprintf(redisKey, "personal", positionId)
  73. } else {
  74. // 企业用户 用企业id查
  75. query += fmt.Sprintf(" end =%d", entId)
  76. redisKey = fmt.Sprintf(redisKey, "ent", entId)
  77. }
  78. if data, err := redis.GetBytes("other", redisKey); err == nil && data != nil {
  79. err := json.Unmarshal(*data, &result)
  80. if err == nil {
  81. return result
  82. } else {
  83. log.Println("序列化失败", redisKey, err)
  84. }
  85. }
  86. //
  87. rs := IC.BaseMysql.SelectBySql(query)
  88. if rs == nil || len(*rs) == 0 {
  89. return
  90. }
  91. for i := 0; i < len(*rs); i++ {
  92. value := common.ObjToString((*rs)[i]["source"])
  93. if value == "" {
  94. continue
  95. }
  96. splitSource := strings.Split(value, ",")
  97. for j := 0; j < len(splitSource); j++ {
  98. sourceValue, err := strconv.Atoi(splitSource[j])
  99. if err != nil {
  100. log.Println("类型转换错误:", err, splitSource[j])
  101. continue
  102. }
  103. if name, ok := SelectItemMap[sourceValue]; ok {
  104. result = append(result, &bxcore.SourceItem{
  105. Name: name,
  106. Value: int64(sourceValue),
  107. })
  108. }
  109. }
  110. }
  111. if len(result) > 0 {
  112. // 存缓存
  113. rsByte, _ := json.Marshal(result)
  114. redis.PutBytes("other", redisKey, &rsByte, 60*60*2)
  115. }
  116. return
  117. }
  118. func (in *ParticipateStatistics) PersonHandle(entUserIdArr []string) (isAdmin bool, idStr string, users *[]map[string]interface{}) {
  119. userEnt := EntInfo(common.IntAll(in.EntId), common.IntAll(in.EntUserId))
  120. if len(entUserIdArr) > 0 {
  121. //查询所选人的部门以及人员信息
  122. users = GetUser(entUserIdArr)
  123. //返回所选人的信息
  124. isAdmin = true
  125. idStr = strings.Join(entUserIdArr, ",")
  126. } else {
  127. if userEnt.Role_admin_department || userEnt.Role_admin_system { //
  128. // 部门管理员 获取所有部门和子部门员工
  129. users = GetDisUsers(common.IntAll(in.EntId), userEnt.Dept.Id)
  130. var staffs []string
  131. if users != nil && len(*users) > 0 {
  132. for _, v := range *users {
  133. staffs = append(staffs, common.InterfaceToStr(v["id"]))
  134. }
  135. }
  136. isAdmin = true
  137. idStr = strings.Join(staffs, ",")
  138. } else {
  139. if userEnt.Dept.Id != 0 {
  140. entUserIdArr = append(entUserIdArr, common.InterfaceToStr(in.EntUserId))
  141. users = GetUser(entUserIdArr)
  142. //返回所选人的信息
  143. isAdmin = true
  144. idStr = strings.Join(entUserIdArr, ",")
  145. } else {
  146. isAdmin = false
  147. idStr = common.InterfaceToStr(in.PositionId)
  148. users = &[]map[string]interface{}{
  149. map[string]interface{}{
  150. "id": in.PositionId,
  151. "name": "个人",
  152. },
  153. }
  154. }
  155. }
  156. }
  157. return
  158. }
  159. type PushData struct {
  160. PersonName string
  161. entUserId string
  162. DepartmentName string
  163. PushNumb map[string]interface{}
  164. ParticipateNumb map[string]interface{}
  165. BidNumb map[string]interface{}
  166. WinNumb map[string]interface{}
  167. BrowseNumb map[string]interface{}
  168. }
  169. type ProjectData struct {
  170. PersonName string
  171. DepartmentName string
  172. entUserId string
  173. BidNumb map[string]interface{} //投标数量
  174. DirectBidNumb map[string]interface{} //直接投标数
  175. ChannelBidNumb map[string]interface{} //渠道投标数
  176. WinNumb map[string]interface{}
  177. DirectWinNumb map[string]interface{} //直接中标数
  178. ChannelWinNumb map[string]interface{} //渠道中标数
  179. NotBidNumber map[string]interface{} //未中标数量
  180. EndNumb map[string]interface{} //终止数量
  181. participateProjectNumb map[string]interface{} // 参标数量
  182. Stage map[string]map[string]interface{}
  183. }
  184. func PushHandle(data *[]map[string]interface{}, users *[]map[string]interface{}, isAdmin bool) []*bxcore.PushStatisticsData {
  185. result := &map[int64]*PushData{}
  186. for k, v := range *users {
  187. (*result)[common.Int64All(v["id"])] = &PushData{
  188. PersonName: fmt.Sprintf("%s_%d", common.InterfaceToStr(v["name"]), k),
  189. DepartmentName: common.InterfaceToStr(v["dept_name"]),
  190. entUserId: common.InterfaceToStr(v["id"]),
  191. }
  192. }
  193. if data != nil && len(*data) > 0 {
  194. for _, v := range *data {
  195. userId := int64(0)
  196. if isAdmin {
  197. userId = common.Int64All(v["ent_user_id"])
  198. } else {
  199. userId = common.Int64All(v["position_id"])
  200. }
  201. if (*result)[userId] != nil {
  202. //浏览总数处理处理
  203. project_id := common.InterfaceToStr(common.InterfaceToStr(v["project_id"]))
  204. if common.Int64All(v["isvisit"]) > 0 {
  205. (*result)[userId].BrowseNumb = DataHanle((*result)[userId].BrowseNumb, project_id)
  206. }
  207. //推送总数处理
  208. (*result)[userId].PushNumb = DataHanle((*result)[userId].PushNumb, project_id)
  209. //参标总数处理
  210. if common.Int64All(v["isparticipate"]) > 0 {
  211. (*result)[userId].ParticipateNumb = DataHanle((*result)[userId].ParticipateNumb, project_id)
  212. }
  213. //投标总数处理
  214. if common.Int64All(v["isbid"]) > 0 {
  215. (*result)[userId].BidNumb = DataHanle((*result)[userId].BidNumb, project_id)
  216. }
  217. //中标总数处理
  218. if common.Int64All(v["win_status"]) != 0 {
  219. win_status := common.Int64All(v["win_status"])
  220. if win_status == 1 {
  221. (*result)[userId].WinNumb = DataHanle((*result)[userId].WinNumb, project_id)
  222. } else {
  223. delete((*result)[userId].WinNumb, project_id)
  224. }
  225. }
  226. }
  227. }
  228. }
  229. pushStatisticsList := make([]*bxcore.PushStatisticsData, len(*result))
  230. for _, v := range *result {
  231. personName := strings.Split(v.PersonName, "_")[0]
  232. k := common.Int64All(strings.Split(v.PersonName, "_")[1])
  233. pushStatisticsList[k] = &bxcore.PushStatisticsData{
  234. PersonName: personName,
  235. DepartmentName: v.DepartmentName,
  236. EntUserId: encrypt.SE.Encode2Hex(v.entUserId),
  237. PushNumb: common.Int64All(len(v.PushNumb)),
  238. ParticipateNumb: common.Int64All(len(v.ParticipateNumb)),
  239. BidNumb: common.Int64All(len(v.BidNumb)),
  240. WinNumb: common.Int64All(len(v.WinNumb)),
  241. BrowseNumb: common.Int64All(len(v.BrowseNumb)),
  242. }
  243. }
  244. return pushStatisticsList
  245. }
  246. func ProjectHandle(data *[]map[string]interface{}, users *[]map[string]interface{}, isAdmin bool) []*bxcore.ProjectStatisticsData {
  247. result := &map[int64]*ProjectData{}
  248. for k, v := range *users {
  249. (*result)[common.Int64All(v["id"])] = &ProjectData{
  250. PersonName: fmt.Sprintf("%s_%d", common.InterfaceToStr(v["name"]), k),
  251. DepartmentName: common.InterfaceToStr(v["dept_name"]),
  252. entUserId: common.InterfaceToStr(v["id"]),
  253. }
  254. }
  255. if data != nil && len(*data) > 0 {
  256. // existProject 已经存在的项目 项目id_用户id
  257. existProject := map[string]struct{}{}
  258. for _, v := range *data {
  259. userId := int64(0)
  260. if isAdmin {
  261. userId = common.Int64All(v["ent_user_id"])
  262. } else {
  263. userId = common.Int64All(v["position_id"])
  264. }
  265. project_id := common.InterfaceToStr(common.InterfaceToStr(v["project_id"]))
  266. if (*result)[userId] != nil {
  267. // 参标数量
  268. (*result)[userId].participateProjectNumb = DataHanle((*result)[userId].participateProjectNumb, project_id)
  269. //投标数量
  270. if common.Int64All(v["isbid"]) > 0 {
  271. (*result)[userId].BidNumb = DataHanle((*result)[userId].BidNumb, project_id)
  272. }
  273. //终止参保统计
  274. if common.Int64All(v["isend"]) != 0 {
  275. (*result)[userId].EndNumb = DataHanle((*result)[userId].EndNumb, project_id)
  276. }
  277. /* p408 调整:
  278. 这里是因为participate_project_statistics 表的数据是多条的
  279. 统计各阶段数据的时候和中标总数的时候只以最新的为准
  280. 但是统计各阶段勾选数量时 重复统计后续删除不好处理 所以这里调整为
  281. 查询的时候根据时间倒序,同一个项目只统计第一条就可以了 每个项目第一条就是当前阶段内最新的
  282. 其他的直接跳过 不用重复统计后续再删除
  283. */
  284. existKey := fmt.Sprintf("%d_%s", userId, project_id)
  285. if _, ok := existProject[existKey]; !ok {
  286. existProject[existKey] = struct{}{}
  287. } else {
  288. continue
  289. }
  290. //直接投标数
  291. if common.Int64All(v["bid_way"]) > 0 {
  292. if common.Int64All(v["bid_way"]) == 2 {
  293. (*result)[userId].ChannelBidNumb = DataHanle((*result)[userId].ChannelBidNumb, project_id)
  294. delete((*result)[userId].DirectBidNumb, project_id)
  295. } else {
  296. (*result)[userId].DirectBidNumb = DataHanle((*result)[userId].DirectBidNumb, project_id)
  297. delete((*result)[userId].ChannelBidNumb, project_id)
  298. }
  299. }
  300. //中标总数处理
  301. if common.Int64All(v["win_status"]) != 0 {
  302. if common.Int64All(v["win_status"]) > 0 {
  303. //中标数量
  304. (*result)[userId].WinNumb = DataHanle((*result)[userId].WinNumb, project_id)
  305. delete((*result)[userId].NotBidNumber, project_id)
  306. } else {
  307. //未中标数量
  308. (*result)[userId].NotBidNumber = DataHanle((*result)[userId].NotBidNumber, project_id)
  309. delete((*result)[userId].WinNumb, project_id)
  310. }
  311. }
  312. //中标方式处理
  313. if common.Int64All(v["win_bidway"]) != 0 {
  314. if common.Int64All(v["win_bidway"]) == 1 {
  315. //直接投标数量
  316. (*result)[userId].DirectWinNumb = DataHanle((*result)[userId].DirectWinNumb, project_id)
  317. delete((*result)[userId].ChannelWinNumb, project_id)
  318. } else {
  319. //渠道投标数量
  320. (*result)[userId].ChannelWinNumb = DataHanle((*result)[userId].ChannelWinNumb, project_id)
  321. delete((*result)[userId].DirectWinNumb, project_id)
  322. }
  323. }
  324. // 阶段勾选数量统计 只统计第一条
  325. stage := common.ObjToString(v["bid_stage"])
  326. if stage != "" {
  327. stageSplit := strings.Split(stage, ",")
  328. if (*result)[userId].Stage == nil {
  329. (*result)[userId].Stage = map[string]map[string]interface{}{}
  330. }
  331. for i := 0; i < len(stageSplit); i++ {
  332. stageK := stageSplit[i]
  333. (*result)[userId].Stage[stageK] = DataHanle((*result)[userId].Stage[stageSplit[i]], project_id)
  334. }
  335. }
  336. }
  337. }
  338. }
  339. projectStatisticsList := make([]*bxcore.ProjectStatisticsData, len(*result))
  340. for _, v := range *result {
  341. personName := strings.Split(v.PersonName, "_")[0]
  342. k := common.Int64All(strings.Split(v.PersonName, "_")[1])
  343. tmpStage := map[string]int64{}
  344. for stageK, stageV := range v.Stage {
  345. tmpStage[stageK] = int64(len(stageV))
  346. }
  347. projectStatisticsList[k] = &bxcore.ProjectStatisticsData{
  348. PersonName: personName,
  349. DepartmentName: v.DepartmentName,
  350. EntUserId: encrypt.SE.Encode2Hex(v.entUserId),
  351. BidNumb: common.Int64All(len(v.BidNumb)),
  352. DirectBidNumb: common.Int64All(len(v.DirectBidNumb)),
  353. ChannelBidNumb: common.Int64All(len(v.ChannelBidNumb)),
  354. WinNumb: common.Int64All(len(v.WinNumb)),
  355. DirectWinNumb: common.Int64All(len(v.DirectWinNumb)),
  356. ChannelWinNumb: common.Int64All(len(v.ChannelWinNumb)),
  357. NotBidNumber: common.Int64All(len(v.NotBidNumber)),
  358. EndNumb: common.Int64All(len(v.EndNumb)),
  359. ParticipateProjectNumb: common.Int64All(len(v.participateProjectNumb)),
  360. Stage: tmpStage,
  361. }
  362. }
  363. return projectStatisticsList
  364. }
  365. func EntInfo(entId, entUserId int) *CurrentUser {
  366. currentUser := &CurrentUser{
  367. Dept: &Department{},
  368. }
  369. user := IC.MainMysql.SelectBySql(`SELECT a.name as user_name from entniche_user a INNER JOIN entniche_user_role b on (a.id=b.user_id) where a.id=? and b.role_id=? limit 1`, entUserId, Role_admin_system)
  370. if user != nil && len(*user) > 0 {
  371. currentUser.Role_admin_system = true
  372. currentUser.User_name, _ = (*user)[0]["user_name"].(string)
  373. currentUser.User_power = 1
  374. r := IC.MainMysql.SelectBySql(`SELECT id,name,subdis,nodiff from entniche_department where ent_id=? and pid=0 limit 1`, entId)
  375. if r != nil && len(*r) == 1 {
  376. department := JsonUnmarshal((*r)[0], &Department{}).(*Department)
  377. if department != nil {
  378. department.Pid = department.Id
  379. currentUser.Dept = department
  380. }
  381. }
  382. } else {
  383. //角色、权限
  384. r := IC.MainMysql.SelectBySql(`SELECT a.name as user_name,a.power as user_power,b.role_id,d.id as dept_id,d.name as dept_name,d.subdis as dept_subdis,d.nodiff as dept_nodiff,e.id as dept_pid from entniche_user a
  385. LEFT JOIN entniche_user_role b on (b.user_id=?)
  386. INNER JOIN entniche_department_user c on (a.id=? and a.id=c.user_id)
  387. INNER JOIN entniche_department d on (c.dept_id=d.id)
  388. INNER JOIN entniche_department e on (e.ent_id=? and e.pid=0)
  389. order by a.id desc limit 1`, entUserId, entUserId, entId)
  390. if r != nil && len(*r) == 1 {
  391. currentUser.User_name, _ = (*r)[0]["user_name"].(string)
  392. currentUser.User_power = common.IntAll((*r)[0]["user_power"])
  393. if common.IntAll((*r)[0]["role_id"]) == Role_admin_department {
  394. currentUser.Role_admin_department = true
  395. }
  396. currentUser.Dept.Id = common.IntAll((*r)[0]["dept_id"])
  397. currentUser.Dept.Pid = common.IntAll((*r)[0]["dept_pid"])
  398. currentUser.Dept.Name = common.ObjToString((*r)[0]["dept_name"])
  399. currentUser.Dept.Subdis = common.IntAll((*r)[0]["dept_subdis"])
  400. currentUser.Dept.Nodiff = common.IntAll((*r)[0]["dept_nodiff"])
  401. }
  402. }
  403. return currentUser
  404. }
  405. // map转结构体
  406. func JsonUnmarshal(m interface{}, s interface{}) interface{} {
  407. var b []byte
  408. if v, ok := m.(string); ok {
  409. b = []byte(v)
  410. } else if v, ok := m.([]byte); ok {
  411. b = v
  412. } else {
  413. b, _ = json.Marshal(m)
  414. }
  415. json.Unmarshal(b, &s)
  416. return s
  417. }
  418. // 获取部门下可以进行分发的人员(不包含部门名称和部门id)
  419. func GetDisUsers(entId, deptId int) *[]map[string]interface{} {
  420. r := IC.MainMysql.SelectBySql(`select DISTINCT c.id,c.name,c.phone,c.power,b.dept_id,d.name as dept_name
  421. from entniche_department_parent a
  422. INNER JOIN entniche_department_user b on (b.dept_id=? or (a.pid=? and a.id=b.dept_id))
  423. INNER JOIN entniche_user c on (c.ent_id=? and b.user_id=c.id)
  424. INNER JOIN entniche_department d on d.id=b.dept_id
  425. order by b.dept_id , convert(c.name using gbk) COLLATE gbk_chinese_ci asc`, deptId, deptId, entId)
  426. return r
  427. }
  428. func GetUser(entUserIdArr []string) *[]map[string]interface{} {
  429. r := IC.MainMysql.SelectBySql("SELECT DISTINCT a.id, a.name, a.phone, d.id AS dept_id, d.NAME AS dept_name " +
  430. "FROM entniche_user a " +
  431. " INNER JOIN entniche_department_user b ON FIND_IN_SET(a.id,'" + strings.Join(entUserIdArr, ",") +
  432. "') and b.user_id = a.id " +
  433. " INNER JOIN entniche_department d ON d.id = b.dept_id " +
  434. " ORDER BY d.id, CONVERT ( a.NAME USING gbk ) COLLATE gbk_chinese_ci ASC",
  435. )
  436. return r
  437. }
  438. type User struct {
  439. Id int
  440. Name string //员工姓名
  441. Mail string //邮箱
  442. Phone string //手机号
  443. Dept_id int //部门id
  444. Dept_name string //部门名称
  445. //Role string //角色
  446. Power int //权限
  447. }
  448. type CurrentUser struct {
  449. Role_admin_department bool //是否是部门管理员
  450. Role_admin_system bool //是否是系统管理员
  451. Dept *Department //部门信息
  452. BondPhone string //手机号
  453. NickName string //昵称
  454. HeadImageUrl string //头像
  455. PersonalAuth int //个人认证
  456. PersonalAuthReason string //个人认证不通过原因
  457. User_power int //是否分配权限
  458. User_name string //用户姓名
  459. }
  460. type Department struct {
  461. Id int
  462. Name string //部门名
  463. Pid int //上级部门id
  464. Pname string //上级部门名称
  465. Nodiff int //全员无差别接收 0:关闭 1:打开
  466. Subdis int //订阅分发 0:关闭 1:打开
  467. Aid int //管理员id
  468. Aname string //管理员姓名
  469. Rname string //角色名
  470. User_count int //该部门下员工的总数
  471. Dept_count int //该部门下子部门总数
  472. Ent_id int //公司id
  473. }
  474. func DataHanle(data map[string]interface{}, project_id string) map[string]interface{} {
  475. if data == nil {
  476. data = map[string]interface{}{project_id: 1}
  477. } else {
  478. data[project_id] = 1
  479. }
  480. return data
  481. }
  482. func QueryHandle(isAdmin bool, startTime, endTime int64, personArrStr string, source []int64, bidWay int64) []string {
  483. //时间处理
  484. query := []string{}
  485. if isAdmin {
  486. //是管理员
  487. query = append(query, fmt.Sprintf(" ent_user_id in (%s) ", personArrStr))
  488. } else {
  489. //不是管理员
  490. query = append(query, fmt.Sprintf(" position_id = %s ", personArrStr))
  491. }
  492. if startTime == 0 && endTime == 0 {
  493. //没有传时间,默认时间处理
  494. var start = time.Now().AddDate(0, 0, -30)
  495. query = append(query, fmt.Sprintf(" ymd >= %s ", start.Format("20060102")))
  496. }
  497. if startTime != 0 {
  498. query = append(query, fmt.Sprintf(" ymd >= %d ", startTime))
  499. }
  500. if endTime != 0 {
  501. query = append(query, fmt.Sprintf(" ymd <= %d ", endTime))
  502. }
  503. if len(source) > 0 {
  504. sourceValue := ""
  505. for i := 0; i < len(source); i++ {
  506. sourceValue += fmt.Sprint(source[i]) + ","
  507. }
  508. sourceValue = sourceValue[:len(sourceValue)-1]
  509. query = append(query, fmt.Sprintf(" FIND_IN_SET('%s', a.source)", sourceValue))
  510. }
  511. if bidWay != 0 {
  512. query = append(query, fmt.Sprintf("bid_way = %d", bidWay))
  513. }
  514. return query
  515. }
  516. func (in *ParticipateStatistics) ProjectDetails(entUserIdArr []string, detailReq *bxcore.ProjectDetailsReq) (result bxcore.DetailData) {
  517. //判断是企业、部门还是个人
  518. isAdmin, personArrStr, _ := in.PersonHandle(entUserIdArr)
  519. queryType := GetQueryType(detailReq)
  520. query, countQuery := GetDetailQuery(isAdmin, personArrStr, detailReq, queryType)
  521. totalCount := IC.BaseMysql.CountBySql(countQuery)
  522. if totalCount == 0 {
  523. return
  524. }
  525. // 处理数据 这里只是筛选出项目id和阶段信息
  526. dataList := IC.BaseMysql.SelectBySql(query)
  527. if dataList == nil || len(*dataList) == 0 {
  528. return
  529. }
  530. // 处理数据 补充项目名称、推送表字段 、格式化数据
  531. rs := ProjectDetailHandle(*dataList, in.EntId, int(detailReq.PositionId), int(detailReq.PositionType))
  532. result = bxcore.DetailData{
  533. List: rs,
  534. Total: totalCount,
  535. }
  536. // 处理数据
  537. return
  538. }
  539. // todo 查询条件待验证
  540. //
  541. // 这个查询只用查出符合筛选条件的项目id 以及该项目对应的stage
  542. // 查询类型 0空搜索 全连接 1查左边 连右表查stage 2只查右表 3内连接
  543. func GetDetailQuery(isAdmin bool, personArrStr string, req *bxcore.ProjectDetailsReq, queryType int) (string, string) {
  544. // 这是因为数据库中 0是未参标 1是已参标, 接收参数时和其他默认参数保持一致 0-全部 1 是未参标 2 是已参标
  545. req.IsParticipate -= 1
  546. if queryType == 0 {
  547. // 空搜索调整
  548. query1, query2, query3 := []string{}, []string{}, []string{}
  549. //没有传时间,默认时间处理
  550. var start = time.Now().AddDate(0, 0, -30)
  551. query1 = append(query1, fmt.Sprintf(" a.ymd >= %s ", start.Format("20060102")))
  552. query2 = append(query2, fmt.Sprintf(" b.update_date >= %s ", start.Format("20060102")))
  553. if isAdmin {
  554. //是管理员
  555. query1 = append(query1, fmt.Sprintf(" a.ent_user_id in (%s) ", personArrStr))
  556. query2 = append(query2, fmt.Sprintf(" FIND_IN_SET('%s', b.ent_user_ids) ", personArrStr))
  557. query3 = append(query3, fmt.Sprintf(" FIND_IN_SET('%s', b.ent_user_ids) ", personArrStr))
  558. } else {
  559. //不是管理员
  560. query1 = append(query1, fmt.Sprintf(" a.position_id = %s ", personArrStr))
  561. query2 = append(query2, fmt.Sprintf(" FIND_IN_SET('%s', b.position_ids) ", personArrStr))
  562. query3 = append(query3, fmt.Sprintf(" FIND_IN_SET('%s', b.position_ids) ", personArrStr))
  563. }
  564. q := `SELECT A.project_id, B.stage
  565. FROM
  566. (SELECT DISTINCT(project_id)
  567. FROM
  568. (SELECT project_id FROM participate_push_statistics
  569. WHERE %s UNION
  570. SELECT project_id
  571. FROM participate_stage_statistics
  572. WHERE %s)
  573. LIMIT %d , %d) A
  574. LEFT JOIN
  575. participate_stage_statistics B ON A.project_id = B.project_id where %s`
  576. q2 := "select distinct(position_id) from participate_push_statistics where %s union select project_id from participate_stage_statistics where %s "
  577. q1Str := strings.Join(query1, " and ")
  578. q2Str := strings.Join(query2, " and ")
  579. q3Str := strings.Join(query3, " and ")
  580. return fmt.Sprintf(q, q1Str, q2Str, q3Str), fmt.Sprintf(q2, q1Str, q2Str)
  581. }
  582. var q, qCount string
  583. query := []string{}
  584. joinStr := ""
  585. if queryType == 1 {
  586. if isAdmin {
  587. //是管理员
  588. query = append(query, fmt.Sprintf(" a.ent_user_id in (%s) ", personArrStr))
  589. joinStr = "and a.ent_id = b.ent_id"
  590. } else {
  591. query = append(query, fmt.Sprintf(" a.position_id = %s ", personArrStr))
  592. //不是管理员
  593. // 个人版
  594. if req.PositionType == 0 {
  595. joinStr = "and a.position_id = b.position_ids"
  596. } else {
  597. // 企业版 个人 因为是查项目的最新状态信息 所以 用ent_id 和项目id连表
  598. joinStr = "and a.ent_id = b.ent_id"
  599. }
  600. }
  601. if req.StartTime == 0 && req.EndTime == 0 {
  602. //没有传时间,默认时间处理
  603. var start = time.Now().AddDate(0, 0, -30)
  604. query = append(query, fmt.Sprintf(" a.ymd >= %s ", start.Format("20060102")))
  605. }
  606. if req.StartTime != 0 {
  607. query = append(query, fmt.Sprintf(" a.ymd >= %d ", req.StartTime))
  608. }
  609. if req.EndTime != 0 {
  610. query = append(query, fmt.Sprintf(" a.ymd <= %d ", req.EndTime))
  611. }
  612. // 标讯/项目来源
  613. if len(req.Source) > 0 {
  614. sourceValue := ""
  615. for i := 0; i < len(req.Source); i++ {
  616. if req.Source[i] == 0 {
  617. sourceValue += "1,2,"
  618. } else {
  619. sourceValue += fmt.Sprint(req.Source[i]) + ","
  620. }
  621. }
  622. sourceValue = sourceValue[:len(sourceValue)-1]
  623. query = append(query, fmt.Sprintf(" FIND_IN_SET('%s', a.source)", sourceValue))
  624. }
  625. // 投标类型 投标方式;1:直接投标 2:渠道投标',
  626. if req.BidWay != 0 {
  627. query = append(query, fmt.Sprintf("a.bid_way = %d", req.BidWay))
  628. }
  629. //参标状态:-1全部,0未参标、1已参标
  630. if req.IsParticipate != -1 {
  631. query = append(query, fmt.Sprintf("a.isparticipate = %d", req.IsParticipate))
  632. }
  633. q = "select distinct(a.project_id),b.stage,a.id,b.id as bid from participate_push_statistics a left join participate_stage_statistics b on(a.project_id=b.project_id %s ) where %s order by a.id desc,b.id desc"
  634. qCount = "select count(distinct(a.project_id)) from participate_push_statistics a left join participate_stage_statistics b on(a.project_id=b.project_id %s) where %s"
  635. } else if queryType == 2 {
  636. if isAdmin {
  637. //是管理员
  638. query = append(query, fmt.Sprintf(" FIND_IN_SET('%s', b.ent_user_ids) ", personArrStr))
  639. } else {
  640. //不是管理员
  641. query = append(query, fmt.Sprintf(" FIND_IN_SET('%s', b.position_ids)", personArrStr))
  642. }
  643. // 参标状态更新时间
  644. if req.BidUpdateStartTime != "" {
  645. query = append(query, fmt.Sprintf("b.update_date > %s", req.BidUpdateStartTime))
  646. }
  647. if req.BidUpdateEndTime != "" {
  648. query = append(query, fmt.Sprintf("b.update_date > %s", req.BidUpdateStartTime))
  649. }
  650. if req.BidWay != 0 {
  651. query = append(query, fmt.Sprintf("b.bid_way = %d", req.BidWay))
  652. }
  653. //参标状态:-1全部,0未参标、1已参标
  654. if req.IsParticipate == 1 {
  655. query = append(query, fmt.Sprintf("b.isparticipate = %d", req.IsParticipate))
  656. }
  657. q = "select distinct(b.project_id),b.stage,a.id,b.id from participate_stage_statistics b where %s %s order by b.id desc"
  658. qCount = "select count(b.project_id) from participate_stage_statistics b where %s %s"
  659. } else {
  660. if isAdmin {
  661. //是管理员
  662. query = append(query, fmt.Sprintf(" a.ent_user_id in (%s) ", personArrStr))
  663. joinStr = "and a.ent_id = b.ent_id"
  664. } else {
  665. query = append(query, fmt.Sprintf(" a.position_id = %s ", personArrStr))
  666. //不是管理员
  667. // 个人版
  668. if req.PositionType == 0 {
  669. joinStr = "and a.position_id = b.position_ids"
  670. } else {
  671. // 企业版 个人 因为是查项目的最新状态信息 所以 用ent_id 和项目id连表
  672. joinStr = "and a.ent_id = b.ent_id"
  673. }
  674. }
  675. if req.StartTime != 0 {
  676. query = append(query, fmt.Sprintf(" a.ymd >= %d ", req.StartTime))
  677. }
  678. if req.EndTime != 0 {
  679. query = append(query, fmt.Sprintf(" a.ymd <= %d ", req.EndTime))
  680. }
  681. if len(req.Source) > 0 {
  682. sourceValue := ""
  683. for i := 0; i < len(req.Source); i++ {
  684. if req.Source[i] == 0 {
  685. sourceValue += "1,2," // 选择未分发时 相当于选择个人订阅和企业自动分发
  686. } else {
  687. sourceValue += fmt.Sprint(req.Source[i]) + ","
  688. }
  689. }
  690. sourceValue = sourceValue[:len(sourceValue)-1]
  691. query = append(query, fmt.Sprintf(" FIND_IN_SET('%s', a.source)", sourceValue))
  692. }
  693. //参标状态:-1全部,0未参标、1已参标
  694. if req.IsParticipate != -1 {
  695. query = append(query, fmt.Sprintf("a.isparticipate = %d", req.IsParticipate))
  696. }
  697. // 投标类型 投标方式;1:直接投标 2:渠道投标',
  698. if req.BidWay != 0 {
  699. query = append(query, fmt.Sprintf("a.bid_way = %d", req.BidWay))
  700. }
  701. // 参标状态更新时间
  702. if req.BidUpdateStartTime != "" {
  703. query = append(query, fmt.Sprintf("b.update_date > %s", req.BidUpdateStartTime))
  704. }
  705. if req.BidUpdateEndTime != "" {
  706. query = append(query, fmt.Sprintf("b.update_date > %s", req.BidUpdateStartTime))
  707. }
  708. q = "select distinct(a.project_id),b.stage,a.id,b.id from participate_push_statistics a inner join participate_stage_statistics b on(b.project_id=a.project_id %s) where %s order by a.id desc,b.id desc"
  709. qCount = "select count(distinct(a.project_id)) from participate_push_statistics a inner join participate_stage_statistics b on(b.project_id=a.project_id %s) where %s"
  710. }
  711. if len(query) > 0 {
  712. q = fmt.Sprintf(q, joinStr, strings.Join(query, " and "))
  713. qCount = fmt.Sprintf(qCount, joinStr, strings.Join(query, " and "))
  714. }
  715. // 处理分页
  716. if req.PageNum == 0 && req.PageSize == 0 {
  717. req.PageNum = 1
  718. req.PageSize = 50
  719. }
  720. q = fmt.Sprintf("%s limit %d,%d", q, (req.PageNum-1)*req.PageSize, req.PageSize)
  721. return q, qCount
  722. }
  723. type PushInfoStruct struct {
  724. Source string
  725. VisitDate string
  726. DisDate string
  727. IsDistribute int
  728. }
  729. func ProjectDetailHandle(dataList []map[string]interface{}, entId int64, positionId, positionType int) []*bxcore.ProjectDetailData {
  730. //dataList 里面包含 项目id、各阶段信息
  731. // 处理项目名称
  732. projectIdList := []string{}
  733. for i := 0; i < len(dataList); i++ {
  734. projectIdList = append(projectIdList, common.ObjToString(dataList[i]["project_id"]))
  735. }
  736. // 项目名称处理成map用于后续使用
  737. projectNameMap := map[string]string{}
  738. projectNameRs := es.GetProjectNameByProjectId(projectIdList)
  739. if projectNameRs != nil && len(*projectNameRs) > 0 {
  740. for i := 0; i < len(*projectNameRs); i++ {
  741. projectId_ := common.ObjToString((*projectNameRs)[i]["_id"])
  742. projectName_ := (*projectNameRs)[i]["projectname"]
  743. projectNameMap[projectId_] = common.ObjToString(projectName_)
  744. }
  745. }
  746. // 获取推送最新状态
  747. newPushInfo := getNewPushInfo(projectIdList, int(entId), positionId, positionType)
  748. newPushInfoMap := map[string]PushInfoStruct{}
  749. // 处理推送最新状态
  750. if newPushInfo != nil && len(*newPushInfo) > 0 {
  751. for i := 0; i < len(*newPushInfo); i++ {
  752. project_ := common.ObjToString((*newPushInfo)[i]["project_id"])
  753. info := PushInfoStruct{
  754. Source: common.ObjToString((*newPushInfo)[i]["source"]),
  755. VisitDate: common.ObjToString((*newPushInfo)[i]["visit_date"]),
  756. DisDate: common.ObjToString((*newPushInfo)[i]["dis_date"]),
  757. }
  758. newPushInfoMap[project_] = info
  759. }
  760. }
  761. results := []*bxcore.ProjectDetailData{}
  762. // 处理成最后的数据
  763. for i := 0; i < len(dataList); i++ {
  764. projectId := common.ObjToString(dataList[i]["project_id"])
  765. tmp := bxcore.ProjectDetailData{
  766. ProjectName: projectNameMap[projectId],
  767. }
  768. isDistribute_ := ""
  769. // 处理推送表相关字段
  770. if pushInfo_, ok := newPushInfoMap[projectId]; ok {
  771. sourceStr := []string{}
  772. if tmp.Source != "" {
  773. isDistribute_ = "未分发"
  774. sourceSplit := strings.Split(pushInfo_.Source, ",")
  775. for j := 0; j < len(sourceSplit); j++ {
  776. if sourceSplit[j] == "3" {
  777. isDistribute_ = "已分发"
  778. }
  779. if sourceName, ok := SourceMap[sourceSplit[j]]; ok {
  780. sourceStr = append(sourceStr, sourceName)
  781. }
  782. }
  783. }
  784. tmp.Source = strings.Join(sourceStr, ",") // 处理成中文
  785. tmp.ViewDate = pushInfo_.VisitDate
  786. tmp.IsDistribute = isDistribute_
  787. tmp.DisDate = pushInfo_.DisDate
  788. } //
  789. // 处理阶段勾选信息和参标、终止参标信息
  790. if dataList[i]["stage"] != nil {
  791. if stage_, err := json.Marshal(dataList[i]["stage"]); err == nil {
  792. err := json.Unmarshal(stage_, &tmp.Stage)
  793. if err != nil {
  794. log.Println("stage 反序列失败", err)
  795. }
  796. }
  797. }
  798. results = append(results, &tmp)
  799. }
  800. return results
  801. }
  802. // 获取项目的最新推送状态信息
  803. func getNewPushInfo(projectIds []string, entId int, positionId int, positionType int) *[]map[string]interface{} {
  804. s := ""
  805. if positionType == 0 {
  806. s = fmt.Sprintf("position_id=%d", positionId)
  807. } else {
  808. s = fmt.Sprintf("ent_id=%d", entId)
  809. }
  810. sql := `
  811. SELECT
  812. A.project_id, A.source, A.visit_date, A.dis_date, A.is_distribute,A.id,A.ymd,B.ymd
  813. FROM participate_push_statistics A inner join (SELECT
  814. project_id,MAX(ymd) as ymd
  815. FROM
  816. participate_push_statistics
  817. WHERE
  818. %s
  819. AND project_id IN ( "` + strings.Join(projectIds, "\",\"") + `" )
  820. GROUP BY project_id) B on (A.project_id=B.project_id and A.ymd=b.ymd) where A.%s
  821. `
  822. query := fmt.Sprintf(sql, s, s)
  823. return IC.BaseMysql.SelectBySql(query)
  824. }
  825. // GetQueryType 查询类型 0空搜索 全连接 1查左边 连右表查stage 2只查右表 3内连接
  826. // IsParticipate 接收参数时 0 全部 1 未参标 2已参标 数据库中 未参标是0
  827. func GetQueryType(in *bxcore.ProjectDetailsReq) int {
  828. // TODO 调整
  829. if in.BidUpdateStartTime == "" && in.BidUpdateEndTime == "" && in.StartTime == 0 && in.EndTime == 0 && in.IsParticipate == -1 && in.BidWay == 0 && len(in.Source) == 0 {
  830. return 0
  831. }
  832. if in.IsParticipate == 1 {
  833. // 未参标只筛选推送表 右表条件无效
  834. return 1
  835. }
  836. if (in.StartTime != 0 || in.EndTime != 0 || len(in.Source) > 0) && (in.BidUpdateStartTime == "" && in.BidUpdateEndTime == "" && in.IsParticipate != 2) {
  837. return 1
  838. }
  839. if (in.StartTime == 0 && in.EndTime == 0 && len(in.Source) == 0) && (in.BidUpdateStartTime != "" || in.BidUpdateEndTime == "" || in.IsParticipate == 2 || in.BidWay != 0) {
  840. return 2
  841. }
  842. return 3
  843. }