participateBid.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. package mysql
  2. import (
  3. MC "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/date"
  5. "app.yhyue.com/moapp/jybase/encrypt"
  6. "database/sql"
  7. "encoding/json"
  8. "fmt"
  9. "github.com/zeromicro/go-zero/core/logx"
  10. IC "jyBXCore/rpc/init"
  11. "jyBXCore/rpc/model/es"
  12. "jyBXCore/rpc/type/bxcore"
  13. "log"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. //投标状态更新内容
  19. type PartStatusContent struct {
  20. BidStage []string `json:"bidStage"` //投标项目阶段
  21. BidType int64 `json:"bidType"` //投标类型
  22. ChannelName string `json:"channelName"` //渠道名称
  23. ChannelPerson string `json:"channelPerson"` //联系人
  24. ChannelPhone string `json:"channelPhone"` //联系电话
  25. IsWin int64 `json:"isWin"` //渠道是否中标
  26. Winner string `json:"winner"` //中标单位
  27. }
  28. //参标
  29. type RecordsContent struct {
  30. After PartStatusContent `json:"after"` //更新前
  31. Before PartStatusContent `json:"before"` //更新后
  32. ChangeField []string `json:"changeField"` //更新字段
  33. Content string `json:"content"` //更新内容
  34. }
  35. var (
  36. PartTable = "participate"
  37. ParticipateBidRecordsTable = "participate_bid_records"
  38. ParticipateUserTable = "participate_user" // 参标用户表
  39. EntnicheUserTable = "entniche_user" // 企业用户表
  40. )
  41. //划转参标信息
  42. func TransferParticipateInfo(projectId string, in *bxcore.ParticipateActionReq) error {
  43. defer MC.Catch()
  44. //保存或更新新跟踪人
  45. if !IC.BaseMysql.ExecTx("划转参标信息", func(tx *sql.Tx) bool {
  46. var (
  47. b1 = true
  48. b2, b3 bool
  49. now = time.Now()
  50. content = "%s划转给%s%s"
  51. lastNotes = ",保留原参标人"
  52. fromUserNames []string
  53. ids []int
  54. )
  55. partInfo := IC.BaseMysql.SelectBySqlByTx(tx, "SELECT id,position_id FROM "+ParticipateUserTable+" WHERE project_id = ? AND ent_id = ? AND state > -1", projectId, in.EntId)
  56. if partInfo == nil || len(*partInfo) == 0 {
  57. logx.Info("当前项目不满足划转条件")
  58. return false
  59. } else {
  60. for _, v := range *partInfo {
  61. ids = append(ids, MC.IntAll(v["id"]))
  62. positionId := MC.Int64All(v["position_id"])
  63. userInfo := IC.Middleground.UserCenter.IdentityByPositionId(positionId)
  64. if userInfo.EntUserName != "" {
  65. fromUserNames = append(fromUserNames, userInfo.EntUserName)
  66. }
  67. }
  68. }
  69. if len(fromUserNames) == 0 {
  70. logx.Info("原参标人信息查询有误")
  71. return false
  72. }
  73. //是否保留原参标人
  74. if !in.IsRetain {
  75. lastNotes = ""
  76. //不保留 原参标人,获取把原参标人信息
  77. //当前项目有参标人 更新参标人状态
  78. b1 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, map[string]interface{}{
  79. "ent_id": in.EntId,
  80. "project_id": projectId,
  81. }, map[string]interface{}{
  82. "state": -1,
  83. "mark": -2, //0:参标;1:被划入;-1:终止参标;-2:被划走
  84. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  85. })
  86. }
  87. //查询划转人信息
  88. entUserId, _ := strconv.ParseInt(in.ToEntUserId, 10, 64)
  89. userInfo := IC.Middleground.UserCenter.IdentityByEntUserId(entUserId)
  90. positionId := userInfo.PositionId
  91. content = fmt.Sprintf(content, strings.Join(fromUserNames, ","), userInfo.EntUserName, lastNotes)
  92. //划转记录
  93. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  94. "ent_id": in.EntId,
  95. "ent_user_id": entUserId,
  96. "position_id": positionId,
  97. "project_id": projectId,
  98. "record_type": 0,
  99. "record_content": content,
  100. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  101. }) > 0
  102. //保存参标--participate_user
  103. //查看是否参标过当前项目
  104. if c := IC.BaseMysql.CountBySql("SELECT count(id) FROM "+ParticipateUserTable+" WHERE position_id = ? AND project_id = ? AND ent_id = ?", positionId, projectId, in.EntId); c > 0 {
  105. //更新
  106. b3 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, map[string]interface{}{
  107. "position_id": positionId,
  108. "project_id": projectId,
  109. "ent_id": in.EntId,
  110. }, map[string]interface{}{
  111. "state": 0,
  112. "mark": 1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  113. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  114. })
  115. } else {
  116. //保存
  117. b3 = IC.BaseMysql.InsertByTx(tx, ParticipateUserTable, map[string]interface{}{
  118. "ent_id": in.EntId,
  119. "ent_user_id": entUserId,
  120. "position_id": positionId,
  121. "project_id": projectId,
  122. "state": 0,
  123. "mark": 1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  124. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  125. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  126. }) > 0
  127. }
  128. return b1 && b2 && b3
  129. }) {
  130. logx.Info(in.PositionId, "---终止---", projectId)
  131. return fmt.Errorf("终止参标更新信息出错")
  132. }
  133. return nil
  134. }
  135. //终止参标
  136. func CancelParticipateInfo(in *bxcore.ParticipateActionReq, roleId int64) error {
  137. defer MC.Catch()
  138. if !IC.BaseMysql.ExecTx("终止参标", func(tx *sql.Tx) bool {
  139. var (
  140. b1, b2 bool
  141. now = time.Now()
  142. tip = "终止参标(被)"
  143. )
  144. //管理员终止:当前项目 其他参标人也被终止
  145. query := map[string]interface{}{
  146. "project_id": in.ProjectIds,
  147. "ent_id": in.EntId,
  148. }
  149. //个人终止:仅仅终止本人参标项目
  150. if roleId == 0 {
  151. query["position_id"] = in.PositionId
  152. tip = "终止参标"
  153. }
  154. insert := map[string]interface{}{
  155. "state": -1,
  156. "mark": -1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  157. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  158. }
  159. //更新参标participate_user
  160. b1 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, query, insert)
  161. //保存参标记录--participate_bid_records
  162. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  163. "ent_id": in.EntId,
  164. "ent_user_id": in.EntUserId,
  165. "position_id": in.PositionId,
  166. "project_id": in.ProjectIds,
  167. "record_type": 0,
  168. "record_content": tip,
  169. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  170. }) > 0
  171. return b1 && b2
  172. }) {
  173. logx.Info(in.PositionId, "---终止---", in.ProjectIds)
  174. return fmt.Errorf("终止参标更新信息出错")
  175. }
  176. return nil
  177. }
  178. //保存参标信息
  179. func SaveParticipateInfo(in *bxcore.ParticipateActionReq) error {
  180. defer MC.Catch()
  181. if !IC.BaseMysql.ExecTx("保存|更新参标信息及保存参标记录", func(tx *sql.Tx) bool {
  182. var (
  183. b1, b2, b3 bool
  184. now = time.Now()
  185. )
  186. //保存参标--participate_user
  187. //查看是否参标过当前项目
  188. if c := IC.BaseMysql.CountBySql("SELECT count(id) FROM "+ParticipateUserTable+" WHERE position_id = ? AND project_id = ? AND ent_id = ?", in.PositionId, in.ProjectIds, in.EntId); c > 0 {
  189. //更新
  190. b1 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, map[string]interface{}{
  191. "state": 0,
  192. "mark": 0,
  193. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  194. }, map[string]interface{}{
  195. "position_id": in.PositionId,
  196. "ent_id": in.EntId,
  197. "project_id": in.ProjectIds,
  198. })
  199. } else {
  200. //保存
  201. b1 = IC.BaseMysql.InsertByTx(tx, ParticipateUserTable, map[string]interface{}{
  202. "ent_id": in.EntId,
  203. "ent_user_id": in.EntUserId,
  204. "position_id": in.PositionId,
  205. "project_id": in.ProjectIds,
  206. "state": 0,
  207. "mark": 0,
  208. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  209. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  210. }) > 0
  211. }
  212. if !b1 {
  213. return false
  214. }
  215. //保存参标记录participate_bid_records
  216. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  217. "ent_id": in.EntId,
  218. "ent_user_id": in.EntUserId,
  219. "position_id": in.PositionId,
  220. "project_id": in.ProjectIds,
  221. "record_type": 0,
  222. "record_content": "参标",
  223. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  224. }) > 0
  225. if !b2 {
  226. return false
  227. }
  228. //保存或更新项目信息
  229. //有问题 其他回滚,项目信息不用回滚
  230. b3 = UpdateProjectInfo(in.ProjectIds, es.GetProjectInfo(in.ProjectIds), es.GetBiddingInfo(in.BidIds)) == nil
  231. return b1 && b2 && b3
  232. }) {
  233. logx.Info(in.PositionId, "---保存---", in.BidIds)
  234. return fmt.Errorf("保存参标信息出错")
  235. }
  236. return nil
  237. }
  238. //查询当前招标信息是否已被参标
  239. func IsParticipatedByBidId(in *bxcore.ParticipateActionReq) bool {
  240. defer MC.Catch()
  241. //如果不允许多人参标 当前项目是否已经有企业其他人员参标
  242. query := fmt.Sprintf(`SELECT count(id) FROM `+ParticipateUserTable+` WHERE %s AND project_id = %s AND state >-1`, "%s", in.BidIds)
  243. if in.PositionType > 0 { //企业版
  244. query = fmt.Sprintf(query, fmt.Sprintf("ent_id = %d", in.EntId))
  245. } else { //个人版
  246. query = fmt.Sprintf(query, fmt.Sprintf("position_id = %d", in.PositionId))
  247. }
  248. return IC.BaseMysql.CountBySql(query) > 0
  249. }
  250. //获取参标权限
  251. func GetParticipateIsAllow(query map[string]interface{}) (b bool) {
  252. defer MC.Catch()
  253. if info, ok := IC.Mgo.FindOne(PartTable, query); ok {
  254. if info != nil {
  255. if (*info)["i_isallow"] != nil {
  256. b = MC.IntAll((*info)["i_isallow"]) > 0
  257. }
  258. }
  259. }
  260. return
  261. }
  262. //更新设置信息
  263. func UpdateParticipateSetInfo(in *bxcore.ParticipateSetUpInfoReq) error {
  264. defer MC.Catch()
  265. query := map[string]interface{}{
  266. "i_positionid": in.PositionId,
  267. }
  268. if in.PositionType > 0 {
  269. //企业版 判断是否是管理员
  270. //判断用户身份
  271. userInfo := IC.Middleground.PowerCheckCenter.Check(in.AppId, in.UserId, in.NewUserId, in.AccountId, in.EntId, in.PositionType, in.PositionId)
  272. if userInfo.Ent.EntRoleId == 0 {
  273. return fmt.Errorf("当前企业身份无权限")
  274. }
  275. query["i_entid"] = in.EntId
  276. }
  277. upsert := map[string]interface{}{
  278. "i_entid": in.EntId,
  279. "i_entuserid": in.EntUserId,
  280. "i_positionid": in.PositionId,
  281. "l_createtime": time.Now().Unix(),
  282. }
  283. if in.IsAllow != "" {
  284. isAllow, _ := strconv.Atoi(in.IsAllow)
  285. upsert["i_isallow"] = isAllow
  286. }
  287. if len(in.BidType) > 0 {
  288. upsert["o_bidtype"] = in.BidType
  289. }
  290. if len(in.RemindRule) > 0 {
  291. upsert["o_remindrule"] = in.RemindRule
  292. }
  293. if ok := IC.Mgo.Update(PartTable, query, map[string]interface{}{
  294. "$set": upsert,
  295. }, true, false); ok {
  296. return nil
  297. }
  298. return fmt.Errorf("更新失败")
  299. }
  300. //查询企业|个人参标设置信息
  301. func GetParticipateSetInfo(in *bxcore.ParticipateSetUpInfoReq) (*bxcore.ParticipateSetUpInfo, error) {
  302. defer MC.Catch()
  303. query := map[string]interface{}{
  304. "i_positionid": in.PositionId,
  305. }
  306. if in.PositionType > 0 {
  307. query["i_entid"] = in.EntId
  308. }
  309. if setInfo, ok := IC.Mgo.FindOne(PartTable, query); ok {
  310. var (
  311. isAllow = ""
  312. bidType []*bxcore.BidTypeReq
  313. remindRule []*bxcore.RemindRuleReq
  314. )
  315. bidType = append(bidType, &bxcore.BidTypeReq{
  316. Name: "直接投标",
  317. Content: []string{"未报名", "已报名", "投标决策", "编制投标文件", "递交投标文件", "中标公示", "签合同", "已结束"},
  318. }, &bxcore.BidTypeReq{
  319. Name: "渠道投标",
  320. Content: []string{"已报名", "签合同", "已结束"},
  321. })
  322. remindRule = append(remindRule, &bxcore.RemindRuleReq{
  323. BidState: "直接投标",
  324. Remainder: 72,
  325. Node: "编制投标文件",
  326. })
  327. if setInfo != nil {
  328. if (*setInfo)["i_isallow"] != nil {
  329. isAllow = strconv.Itoa(MC.IntAll((*setInfo)["i_isallow"]))
  330. }
  331. if (*setInfo)["bidType"] != nil {
  332. if sbb, err := json.Marshal((*setInfo)["o_bidtype"]); err == nil {
  333. if err := json.Unmarshal(sbb, &bidType); err != nil {
  334. logx.Info("bidType json un err:", err.Error())
  335. return nil, err
  336. }
  337. } else {
  338. logx.Info("bidType json err:", err.Error())
  339. return nil, err
  340. }
  341. }
  342. if (*setInfo)["o_remindrule"] != nil {
  343. if sbr, err := json.Marshal((*setInfo)["o_remindrule"]); err == nil {
  344. if err := json.Unmarshal(sbr, &remindRule); err != nil {
  345. logx.Info("remindRule json un err:", err.Error())
  346. return nil, err
  347. }
  348. } else {
  349. logx.Info("remindRule json err:", err.Error())
  350. return nil, err
  351. }
  352. }
  353. }
  354. return &bxcore.ParticipateSetUpInfo{
  355. IsAllow: isAllow,
  356. BidType: bidType,
  357. RemindRule: remindRule,
  358. }, nil
  359. }
  360. return nil, nil
  361. }
  362. //保存或更新tidb 项目信息
  363. func UpdateProjectInfo(id string, pInfo map[string]interface{}, bInfo map[string]interface{}) error {
  364. //id 项目id
  365. //name 项目名称
  366. //area 省份
  367. //city 城市
  368. //buyer 采购单位
  369. //budget 预算
  370. //bid_open_time 开标时间
  371. //bid_time 招标时间 bidding表
  372. //bid_end_time 开标结束时间 bidding表
  373. //pici 批次 轮询更新数据
  374. //
  375. projectInfo := map[string]interface{}{
  376. "id": id,
  377. "name": MC.ObjToString(pInfo["projectname"]),
  378. "area": MC.ObjToString(pInfo["area"]),
  379. "city": MC.ObjToString(pInfo["city"]),
  380. "buyer": MC.ObjToString(pInfo["buyer"]),
  381. "budget": MC.Int64All(pInfo["budget"]),
  382. }
  383. if pInfo["bidopentime"] != nil {
  384. openTime := pInfo["bidopentime"]
  385. projectInfo["bid_open_time"] = date.FormatDateWithObj(&openTime, date.Date_Full_Layout)
  386. }
  387. if pInfo["pici"] != nil {
  388. pici := pInfo["pici"]
  389. projectInfo["pici"] = date.FormatDateWithObj(&pici, date.Date_Full_Layout)
  390. }
  391. // 项目表:zbtime 招标时间是 biding表:publishtime发布时间
  392. if pInfo["zbtime"] != nil {
  393. bidTime := pInfo["zbtime"]
  394. projectInfo["bid_time"] = date.FormatDateWithObj(&bidTime, date.Date_Full_Layout)
  395. }
  396. if bInfo["bidendtime"] != nil {
  397. bidEndTime := bInfo["bidendtime"]
  398. projectInfo["bid_end_time"] = date.FormatDateWithObj(&bidEndTime, date.Date_Full_Layout)
  399. }
  400. if c := IC.BaseMysql.CountBySql(`SELECT COUNT(id) FROM project WHERE id = ?`, id); c > 0 {
  401. if ok := IC.BaseMysql.Update("project", map[string]interface{}{
  402. "id": id,
  403. }, projectInfo); !ok {
  404. return fmt.Errorf("项目信息更新异常", id)
  405. }
  406. } else {
  407. if i := IC.BaseMysql.Insert("project", projectInfo); i < 0 {
  408. return fmt.Errorf("项目信息插入异常", id)
  409. }
  410. }
  411. return nil
  412. }
  413. //参标列表其他条件
  414. func ParticipateListSql(in *bxcore.ParticipateListReq) string {
  415. //b project表
  416. //a participate_user表
  417. now := time.Now()
  418. nowDate := date.FormatDate(&now, date.Date_Full_Layout)
  419. //查询tidb base_service.project
  420. conditionSql := ` WHERE 1=1 `
  421. //地区
  422. if in.Area != "" {
  423. conditionSql += fmt.Sprintf(" AND pt.area IN ('%s') ", strings.ReplaceAll(in.Area, ",", "','"))
  424. }
  425. //城市
  426. if in.City != "" {
  427. conditionSql += fmt.Sprintf(" AND pt.city IN ('%s') ", strings.ReplaceAll(in.City, ",", "','"))
  428. }
  429. //关键词
  430. if in.Keywords != "" {
  431. kSql := ` AND (`
  432. for kk, kv := range strings.Split(in.Keywords, " ") {
  433. if kk > 0 {
  434. kSql += " OR "
  435. }
  436. kSql += " pt.name like '%" + kv + "%'"
  437. }
  438. kSql += `)`
  439. conditionSql += kSql
  440. }
  441. //招标日期
  442. if in.BidTime != "" && strings.Contains(in.BidTime, "-") {
  443. startTime := strings.Split(in.BidTime, "-")[0]
  444. entTime := strings.Split(in.BidTime, "-")[1]
  445. if startTime != "" {
  446. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  447. conditionSql += ` AND pt.bid_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  448. }
  449. if entTime != "" {
  450. entTimeInt, _ := strconv.ParseInt(entTime, 10, 64)
  451. conditionSql += ` AND pt.bid_time < '` + date.FormatDateByInt64(&entTimeInt, date.Date_Full_Layout) + `'`
  452. }
  453. }
  454. //招标截止日期
  455. if in.BidEndTime != "" {
  456. //投标截止日期规则:
  457. //1、开始时间小于当前时间 ,结束时间大于当前时间,投标截止状态按钮未截止和已截止可用;
  458. //2、结束时间小于当前时间|开始时间大于当前时间,投标截止状态按钮未截止和已截止不可用;
  459. //3、需要前端做成连动
  460. startTime := strings.Split(in.BidEndTime, "-")[0]
  461. endTime := strings.Split(in.BidEndTime, "-")[1]
  462. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  463. endTimeInt, _ := strconv.ParseInt(endTime, 10, 64)
  464. if startTimeInt > 0 && endTimeInt > 0 && startTimeInt > endTimeInt {
  465. logx.Info(fmt.Sprintf("投标截止日期 %d 开始时间 大于 结束时间%d!!!", startTimeInt, endTimeInt))
  466. } else {
  467. switch in.BidEndStatus {
  468. case 0:
  469. if startTimeInt > 0 {
  470. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  471. }
  472. if endTimeInt > 0 {
  473. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  474. }
  475. case 1: //投标截止状态:1:未截止;2:已截止;3:终止参标
  476. //未截止:
  477. var (
  478. endBool = true
  479. )
  480. //如果结束时间存在且小于当前时间,投标截止日期 范围都是已截止 不会存在未截止的数据
  481. if endTimeInt > 0 {
  482. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  483. endBool = endTimeInt > now.Unix()
  484. }
  485. //开始时间小于 当前时间
  486. if endBool && now.Unix() > startTimeInt {
  487. startTimeInt = now.Unix()
  488. }
  489. //存在开始时间为0的情况
  490. if startTimeInt > 0 {
  491. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  492. }
  493. case 2: //投标截止状态:1:未截止;2:已截止;3:终止参标
  494. //如果开始时间存在且大于当前时间,投标截止日期 范围都是未截止 不会存在已截止的数据
  495. var (
  496. startBool = true
  497. )
  498. if startTimeInt > 0 {
  499. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  500. startBool = startTimeInt < now.Unix()
  501. }
  502. if startBool && (endTimeInt == 0 || now.Unix() < endTimeInt) {
  503. endTimeInt = now.Unix()
  504. }
  505. //存在结束时间为0的情况
  506. if endTimeInt > 0 {
  507. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  508. }
  509. case 3:
  510. conditionSql += ` AND pug.state < 0 `
  511. }
  512. }
  513. } else if in.BidEndStatus > 0 { //投标截止状态1:未截止;2:已截止;3:终止参标
  514. switch in.BidEndStatus {
  515. case 1:
  516. conditionSql += ` AND pt.bid_end_time > '` + nowDate + `'`
  517. case 2:
  518. conditionSql += ` AND pt.bid_end_time < '` + nowDate + `'`
  519. case 3:
  520. conditionSql += ` AND pug.state < 0 `
  521. }
  522. }
  523. //开标时间
  524. if in.BidOpenTime != "" {
  525. startTime := strings.Split(in.BidOpenTime, "-")[0]
  526. entTime := strings.Split(in.BidOpenTime, "-")[1]
  527. if startTime != "" {
  528. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  529. conditionSql += ` AND pt.bid_open_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  530. }
  531. if entTime != "" {
  532. entTimeInt, _ := strconv.ParseInt(entTime, 10, 64)
  533. conditionSql += ` AND pt.bid_open_time < '` + date.FormatDateByInt64(&entTimeInt, date.Date_Full_Layout) + `'`
  534. }
  535. }
  536. //开标状态1:未开标;2:已开标
  537. if in.BidOpenStatus > 0 {
  538. switch in.BidOpenStatus {
  539. case 1:
  540. conditionSql += ` AND pt.bid_open_time > '` + nowDate + `'`
  541. case 2:
  542. conditionSql += ` AND pt.bid_open_time < '` + nowDate + `'`
  543. }
  544. }
  545. //参标人 管理员权限
  546. if in.EntUserIds != "" && in.PositionType > 0 {
  547. conditionSql += ` AND (`
  548. for k, v := range strings.Split(in.EntUserIds, ",") {
  549. if k > 0 {
  550. conditionSql += " OR "
  551. }
  552. conditionSql += ` FIND_IN_SET(` + v + ` , pug.ent_user_id) `
  553. }
  554. conditionSql += `)`
  555. }
  556. //默认按照投标截止日期正序排列、1:开标时间正序、2:更新状态时间倒序
  557. switch in.OrderNum {
  558. case 1:
  559. conditionSql += ` ORDER BY pt.bid_open_time ASC`
  560. case 2:
  561. conditionSql += ` ORDER BY pug.update_date DESC`
  562. default:
  563. conditionSql += ` ORDER BY pt.bid_end_time ASC`
  564. }
  565. logx.Info(conditionSql)
  566. return conditionSql
  567. }
  568. //个人或员工查询参标列表
  569. func SingleParticipateList(in *bxcore.ParticipateListReq, conditionSql string) (data *bxcore.ParticipateData, err error) {
  570. defer MC.Catch()
  571. data = &bxcore.ParticipateData{
  572. Count: 0,
  573. List: []*bxcore.ParticipateList{},
  574. }
  575. //员工|个人列表
  576. singlePersonSql := `SELECT %s FROM ` + ParticipateUserTable + ` pug LEFT JOIN project pt ON pug.project_id = pt.id WHERE pug.position_id = ? `
  577. singlePersonSql += conditionSql
  578. countSql := fmt.Sprintf(singlePersonSql, " COUNT(pt.id) ")
  579. count := IC.BaseMysql.CountBySql(countSql, in.PositionId)
  580. if count > 0 {
  581. data.Count = count
  582. listSql := fmt.Sprintf(singlePersonSql, " pug.update_date,pt.* ")
  583. //分页
  584. listSql += fmt.Sprintf(` LIMIT %d,%d`, in.PageNum, in.PageSize)
  585. list := IC.BaseMysql.SelectBySql(listSql, in.PositionId)
  586. if list != nil && len(*list) > 0 {
  587. for _, v := range *list {
  588. data.List = append(data.List, &bxcore.ParticipateList{
  589. Id: encrypt.EncodeArticleId2ByCheck(MC.ObjToString(v["id"])),
  590. ProjectName: MC.ObjToString(v["name"]),
  591. Buyer: MC.ObjToString(v["buyer"]),
  592. Budget: MC.ObjToString(v["budget"]),
  593. BidTime: MC.ObjToString(v["bid_time"]),
  594. BidEndTime: MC.ObjToString(v["bid_end_time"]),
  595. BidOpenTime: MC.ObjToString(v["bid_open_time"]),
  596. UpdateStatusTime: MC.ObjToString(v["update_date"]),
  597. UpdateStatusCon: GetParticipateContent("s", in.PositionId, MC.ObjToString(v["id"])), //查询最后一次 投标状态更新,
  598. })
  599. }
  600. return data, nil
  601. }
  602. return nil, fmt.Errorf("数据异常")
  603. }
  604. return data, nil
  605. }
  606. //管理员获取参标列表数据
  607. func AdminParticipateList(in *bxcore.ParticipateListReq, conditionSql string) (data *bxcore.ParticipateData, err error) {
  608. defer MC.Catch()
  609. data = &bxcore.ParticipateData{
  610. Count: 0,
  611. List: []*bxcore.ParticipateList{},
  612. }
  613. adminSql := `SELECT %s FROM (SELECT pu.ent_id, pu.project_id, GROUP_CONCAT(pu.ent_user_id SEPARATOR ',') ent_user_id, MAX(pu.update_date) update_date,MAX(pu.state) state FROM ` + ParticipateUserTable + ` pu WHERE pu.ent_id = ? AND NOT EXISTS ( SELECT 1 FROM ` + ParticipateUserTable + ` WHERE project_id = pu.project_id AND state > pu. state ) GROUP BY pu.project_id ) pug LEFT JOIN project pt ON pug.project_id = pt.id`
  614. adminCountSql := fmt.Sprintf(adminSql, "COUNT(pt.id)") + conditionSql
  615. log.Println(adminCountSql)
  616. count := IC.BaseMysql.CountBySql(adminCountSql, in.EntId)
  617. if count > 0 {
  618. data.Count = count
  619. in.PageNum = (in.PageNum - 1) * in.PageSize
  620. adminListSql := fmt.Sprintf(adminSql, " pt.*, pug.ent_user_id,pug.update_date ") + conditionSql + fmt.Sprintf(" LIMIT %d,%d", in.PageNum, in.PageSize)
  621. list := IC.BaseMysql.SelectBySql(adminListSql, in.EntId)
  622. if list != nil && len(*list) > 0 {
  623. for _, v := range *list {
  624. data.List = append(data.List, &bxcore.ParticipateList{
  625. Id: encrypt.EncodeArticleId2ByCheck(MC.ObjToString(v["id"])),
  626. ProjectName: MC.ObjToString(v["name"]),
  627. Buyer: MC.ObjToString(v["buyer"]),
  628. Budget: MC.ObjToString(v["budget"]),
  629. BidTime: MC.ObjToString(v["bid_time"]),
  630. BidEndTime: MC.ObjToString(v["bid_end_time"]),
  631. BidOpenTime: MC.ObjToString(v["bid_open_time"]),
  632. UpdateStatusTime: MC.ObjToString(v["update_date"]),
  633. UpdateStatusCon: GetParticipateContent("e", in.EntId, MC.ObjToString(v["id"])), //查询最后一次 投标状态更新
  634. Participants: GetParticipateUserName(MC.ObjToString(v["ent_user_id"])), //参标人信息
  635. })
  636. }
  637. return data, nil
  638. }
  639. return nil, fmt.Errorf("数据异常")
  640. }
  641. return data, nil
  642. }
  643. //获取最新参标 更新内容
  644. func GetParticipateContent(s string, id int64, projectId string) string {
  645. identitySql := `ent_id = ?`
  646. if s == "s" {
  647. identitySql = `position_id = ?`
  648. }
  649. recordsSql := `SELECT record_content,record_type FROM ` + ParticipateBidRecordsTable + ` WHERE ` + identitySql + ` AND project_id = ? ORDER BY create_date DESC LIMIT 1;`
  650. records := IC.BaseMysql.SelectBySql(recordsSql, id, projectId)
  651. if records != nil && len(*records) > 0 {
  652. rec := (*records)[0]
  653. switch MC.IntAll(rec["record_type"]) {
  654. case 0:
  655. return MC.ObjToString(rec["record_content"])
  656. case 1:
  657. recordContent := *MC.ObjToMap(rec["record_content"])
  658. rb, err := json.Marshal(recordContent)
  659. if err != nil {
  660. log.Println(err.Error())
  661. return ""
  662. }
  663. var rc = RecordsContent{
  664. After: PartStatusContent{},
  665. Before: PartStatusContent{},
  666. }
  667. err1 := json.Unmarshal(rb, &rc)
  668. if err1 == nil {
  669. return rc.Content
  670. }
  671. }
  672. }
  673. return ""
  674. }
  675. //根据ent_user_id 获取参标人昵称,企业管理员现在都是“我”
  676. func GetParticipateUserName(entUserId string) string {
  677. if entUserId != "" {
  678. var userNames []string
  679. for _, v := range strings.Split(entUserId, ",") {
  680. entUserInfos := IC.MainMysql.SelectBySql(`SELECT * FROM entniche_user WHERE id = ?`, v)
  681. if entUserInfos != nil && len(*entUserInfos) > 0 {
  682. entUserInfo := (*entUserInfos)[0]
  683. if entUserInfo["name"] != nil {
  684. if userName := MC.ObjToString(entUserInfo["name"]); userName != "" {
  685. userNames = append(userNames, userName)
  686. }
  687. }
  688. }
  689. }
  690. return strings.Join(userNames, ",")
  691. }
  692. return ""
  693. }
  694. // GetBidContentEnt 企业版 获取投标状态更新内容
  695. func GetBidContentEnt(projectId string, entId int64) *[]map[string]interface{} {
  696. // record_type '默认0:参标、划转、取消参标;1:投标状态更新存储'
  697. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? and record_type=1 order by create_date desc limit 1; "
  698. return IC.BaseMysql.SelectBySql(query, projectId, entId)
  699. }
  700. // GetBidContentPersonal 个人版 获取投标状态更新内容
  701. func GetBidContentPersonal(projectId string, positionId int64) *[]map[string]interface{} {
  702. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? and record_type=1 order by create_date desc limit 1;"
  703. return IC.BaseMysql.SelectBySql(query, projectId, positionId)
  704. }
  705. // UpdateBidContent 更新投标状态信息以及操作记录
  706. func UpdateBidContent(recordData map[string]interface{}) (flag bool) {
  707. r2 := IC.BaseMysql.Insert(ParticipateBidRecordsTable, recordData)
  708. return r2 > 0
  709. }
  710. // InsertBidContent 新增投标状态信息及操作记录
  711. func InsertBidContent(recordData map[string]interface{}) (flag bool) {
  712. r2 := IC.BaseMysql.Insert(ParticipateBidRecordsTable, recordData)
  713. return r2 > 0
  714. }
  715. // GetBidRecordsEnt 获取操作记录列表企业
  716. func GetBidRecordsEnt(projectId string, entId, page, pageSize int64) (rs *[]map[string]interface{}, total int64) {
  717. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? order by create_date desc limit ?,?"
  718. countQuery := "SELECT count(id) FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? ;"
  719. rs = IC.BaseMysql.SelectBySql(query, projectId, entId, (page-1)*pageSize, pageSize)
  720. total = IC.BaseMysql.CountBySql(countQuery, projectId, entId)
  721. return rs, total
  722. }
  723. // GetBidRecordsPersonal 获取操作记录列表个人
  724. func GetBidRecordsPersonal(projectId string, positionId, page, pageSize int64) (rs *[]map[string]interface{}, total int64) {
  725. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? order by create_date desc limit ?,?;"
  726. countQuery := "SELECT count(id) FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? ;"
  727. rs = IC.BaseMysql.SelectBySql(query, projectId, positionId, (page-1)*pageSize, pageSize)
  728. total = IC.BaseMysql.CountBySql(countQuery, projectId, positionId)
  729. return rs, total
  730. }
  731. // GetUserMap 查询用户id的姓名
  732. func GetUserMap(userIds string) (rs *[]map[string]interface{}) {
  733. query := fmt.Sprintf("select id,name from entniche_user where id in (%s)", userIds)
  734. rs = IC.MainMysql.SelectBySql(query)
  735. return rs
  736. }
  737. // CheckParticipateManager 验证项目id是否是该管理员企业下的参标项目
  738. func CheckParticipateManager(projectId string, entId int64, valid bool) (flag bool) {
  739. stateStr := "" // 是否需要验证是正在参标
  740. if valid {
  741. stateStr = " and state=0"
  742. }
  743. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and ent_id=?" + stateStr
  744. return IC.BaseMysql.CountBySql(query, projectId, entId) > 0
  745. }
  746. // CheckParticipateEntUser 验证项目id是否是该企业用户参标的项目
  747. func CheckParticipateEntUser(projectId string, entUserId int64, valid bool) (flag bool) {
  748. stateStr := "" // 是否需要验证是正在参标
  749. if valid {
  750. stateStr = " and state=0"
  751. }
  752. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and ent_user_id=?" + stateStr
  753. return IC.BaseMysql.CountBySql(query, projectId, entUserId) > 0
  754. }
  755. // CheckParticipatePersonal 查询项目id是否是该用户参标项目
  756. func CheckParticipatePersonal(projectId string, positionId int64, valid bool) (flag bool) {
  757. stateStr := "" // 是否需要验证是正在参标 终止参标的用户还能查看记录,但是不能更新状态
  758. if valid {
  759. stateStr = " and state=0"
  760. }
  761. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and position_id=?" + stateStr
  762. return IC.BaseMysql.CountBySql(query, projectId, positionId) > 0
  763. }
  764. // GetNameByUserIds 获取用户名字符串
  765. // 参数:逗号分割的用户id "11,22,333..."
  766. // 返回: "张三,李四,王五..."
  767. func GetNameByUserIds(ids string) *[]map[string]interface{} {
  768. query := "select group_concat(name) as name from " + EntnicheUserTable + " where id in (" + ids + ") "
  769. rs := IC.MainMysql.SelectBySql(query)
  770. return rs
  771. }
  772. // ParticipateProjectPersonal 查询给定项目id中已经参标的项目id
  773. func ParticipateProjectPersonal(positionId int64, projectId []string) *[]map[string]interface{} {
  774. // 1. 查询出已经参标的
  775. var arg []string
  776. var value []interface{}
  777. value = append(value, positionId)
  778. for i := 0; i < len(projectId); i++ {
  779. arg = append(arg, "?")
  780. value = append(value, projectId[i])
  781. }
  782. argStr := strings.Join(arg, ",")
  783. query := "select project_id from " + ParticipateUserTable + " where position_id = ? and project_id in (%s) and state=0"
  784. rs := IC.BaseMysql.SelectBySql(fmt.Sprintf(query, argStr), value...)
  785. return rs
  786. }
  787. // ParticipateProjectEnt 查询给定项目id中已经参标的项目id
  788. func ParticipateProjectEnt(entId int64, projectId []string) *[]map[string]interface{} {
  789. // 1. 查询出已经参标的
  790. var arg []string
  791. var value []interface{}
  792. value = append(value, entId)
  793. for i := 0; i < len(projectId); i++ {
  794. arg = append(arg, "?")
  795. value = append(value, projectId[i])
  796. }
  797. argStr := strings.Join(arg, ",")
  798. query := "select GROUP_CONCAT(ent_user_id) as personIds ,project_id from " + EntnicheUserTable + " where ent_id=? and project_id in (%s) and state=0 group by project_id "
  799. rs := IC.BaseMysql.SelectBySql(fmt.Sprintf(query, argStr), value...)
  800. return rs
  801. }