participateBid.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  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"` //投标类型1:直接投标;2:渠道投标
  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. fromEntUserNames, toEntUserNames, toEntUserIds []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. fromEntUserNames = append(fromEntUserNames, userInfo.EntUserName)
  66. }
  67. }
  68. }
  69. if len(fromEntUserNames) == 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 解密
  89. for _, toEntUserId := range strings.Split(in.ToEntUserId, ",") {
  90. toEntUserId = encrypt.SE.Decode4HexByCheck(toEntUserId)
  91. if toEntUserId == "" {
  92. logx.Info("划转对象不能为空", in.ProjectIds, in.EntId)
  93. continue
  94. }
  95. //查询划转人信息
  96. entUserId, _ := strconv.ParseInt(toEntUserId, 10, 64)
  97. userInfo := IC.Middleground.UserCenter.IdentityByEntUserId(entUserId)
  98. positionId := userInfo.PositionId
  99. //保存参标--participate_user
  100. //查看是否参标过当前项目
  101. 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 {
  102. //更新
  103. b3 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, map[string]interface{}{
  104. "position_id": positionId,
  105. "project_id": projectId,
  106. "ent_id": in.EntId,
  107. }, map[string]interface{}{
  108. "state": 0,
  109. "mark": 1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  110. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  111. })
  112. } else {
  113. //保存
  114. b3 = IC.BaseMysql.InsertByTx(tx, ParticipateUserTable, map[string]interface{}{
  115. "ent_id": in.EntId,
  116. "ent_user_id": entUserId,
  117. "position_id": positionId,
  118. "project_id": projectId,
  119. "user_id": in.MgoUserId,
  120. "state": 0,
  121. "mark": 1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  122. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  123. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  124. }) > 0
  125. }
  126. if b3 {
  127. toEntUserIds = append(toEntUserIds, toEntUserId)
  128. toEntUserNames = append(toEntUserNames, userInfo.EntUserName)
  129. }
  130. }
  131. //保存多个用户时 如果个别用户划转参标项目异常,直接跳过此用户,保存其他用户信息
  132. //防止最后一个用户保存异常
  133. if len(toEntUserIds) > 0 {
  134. b3 = true
  135. }
  136. //移动端单个项目划转给多个用户,划转记录保存一份,当前企业下参过标的或当前正在参标的人都能看到次记录
  137. //企业下 根据企业id 和项目id查询划转记录
  138. //个人版 根据职位id 和项目id查询划转记录
  139. //划转记录
  140. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  141. "ent_id": in.EntId,
  142. "ent_user_id": in.EntUserId,
  143. "position_id": in.PositionId,
  144. "project_id": projectId,
  145. "record_type": 0,
  146. "transfer_ent_user_id": strings.Join(toEntUserIds, ","),
  147. "record_content": fmt.Sprintf(content, strings.Join(fromEntUserNames, "、"), strings.Join(toEntUserNames, "、"), lastNotes),
  148. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  149. }) > 0
  150. return b1 && b2 && b3
  151. }) {
  152. logx.Info(in.PositionId, "---终止---", projectId)
  153. return fmt.Errorf("终止参标更新信息出错")
  154. }
  155. return nil
  156. }
  157. //终止参标
  158. func CancelParticipateInfo(in *bxcore.ParticipateActionReq, roleId int64) error {
  159. defer MC.Catch()
  160. if !IC.BaseMysql.ExecTx("终止参标", func(tx *sql.Tx) bool {
  161. var (
  162. b1, b2 bool
  163. now = time.Now()
  164. tip = "终止参标(被)"
  165. )
  166. //管理员终止:当前项目 其他参标人也被终止
  167. query := map[string]interface{}{
  168. "project_id": in.ProjectIds,
  169. "ent_id": in.EntId,
  170. }
  171. //个人终止:仅仅终止本人参标项目
  172. if roleId == 0 {
  173. query["position_id"] = in.PositionId
  174. tip = "终止参标"
  175. }
  176. insert := map[string]interface{}{
  177. "state": -1,
  178. "mark": -1, //0:参标;1:被划入;-1:终止参标;-2:被划走
  179. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  180. }
  181. //更新参标participate_user
  182. b1 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, query, insert)
  183. //保存参标记录--participate_bid_records
  184. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  185. "ent_id": in.EntId,
  186. "ent_user_id": in.EntUserId,
  187. "position_id": in.PositionId,
  188. "project_id": in.ProjectIds,
  189. "record_type": 0,
  190. "record_content": tip,
  191. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  192. }) > 0
  193. return b1 && b2
  194. }) {
  195. logx.Info(in.PositionId, "---终止---", in.ProjectIds)
  196. return fmt.Errorf("终止参标更新信息出错")
  197. }
  198. return nil
  199. }
  200. //保存参标信息
  201. func SaveParticipateInfo(in *bxcore.ParticipateActionReq) error {
  202. defer MC.Catch()
  203. if !IC.BaseMysql.ExecTx("保存|更新参标信息及保存参标记录", func(tx *sql.Tx) bool {
  204. var (
  205. b1, b2, b3 bool
  206. now = time.Now()
  207. )
  208. //保存参标--participate_user
  209. //查看是否参标过当前项目
  210. 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 {
  211. //更新
  212. b1 = IC.BaseMysql.UpdateByTx(tx, ParticipateUserTable, map[string]interface{}{
  213. "position_id": in.PositionId,
  214. "ent_id": in.EntId,
  215. "project_id": in.ProjectIds,
  216. }, map[string]interface{}{
  217. "state": 0,
  218. "mark": 0,
  219. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  220. })
  221. } else {
  222. //保存
  223. b1 = IC.BaseMysql.InsertByTx(tx, ParticipateUserTable, map[string]interface{}{
  224. "ent_id": in.EntId,
  225. "ent_user_id": in.EntUserId,
  226. "position_id": in.PositionId,
  227. "project_id": in.ProjectIds,
  228. "user_id": in.MgoUserId,
  229. "state": 0,
  230. "mark": 0,
  231. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  232. "update_date": date.FormatDate(&now, date.Date_Full_Layout),
  233. }) > 0
  234. }
  235. if !b1 {
  236. return false
  237. }
  238. //保存参标记录participate_bid_records
  239. b2 = IC.BaseMysql.InsertByTx(tx, ParticipateBidRecordsTable, map[string]interface{}{
  240. "ent_id": in.EntId,
  241. "ent_user_id": in.EntUserId,
  242. "position_id": in.PositionId,
  243. "project_id": in.ProjectIds,
  244. "record_type": 0,
  245. "record_content": "参标",
  246. "create_date": date.FormatDate(&now, date.Date_Full_Layout),
  247. }) > 0
  248. if !b2 {
  249. return false
  250. }
  251. //保存或更新项目信息
  252. //有问题 其他回滚,项目信息不用回滚
  253. b3 = UpdateProjectInfo(in.ProjectIds, es.GetProjectInfo(in.ProjectIds)) == nil
  254. return b1 && b2 && b3
  255. }) {
  256. logx.Info(in.PositionId, "---保存---", in.ProjectIds)
  257. return fmt.Errorf("保存参标信息出错")
  258. }
  259. return nil
  260. }
  261. //查询当前招标信息是否已被参标
  262. func IsParticipatedByBidId(in *bxcore.ParticipateActionReq) bool {
  263. defer MC.Catch()
  264. //如果不允许多人参标 当前项目是否已经有企业其他人员参标
  265. query := fmt.Sprintf(`SELECT count(id) FROM `+ParticipateUserTable+` WHERE %s AND project_id = %s AND state >-1`, "%s", in.ProjectIds)
  266. if in.PositionType > 0 { //企业版
  267. query = fmt.Sprintf(query, fmt.Sprintf("ent_id = %d", in.EntId))
  268. } else { //个人版
  269. query = fmt.Sprintf(query, fmt.Sprintf("position_id = %d", in.PositionId))
  270. }
  271. return IC.BaseMysql.CountBySql(query) > 0
  272. }
  273. //获取参标权限
  274. func GetParticipateIsAllow(query map[string]interface{}) (b bool) {
  275. defer MC.Catch()
  276. if info, ok := IC.Mgo.FindOne(PartTable, query); ok {
  277. if info != nil {
  278. if (*info)["i_isallow"] != nil {
  279. b = MC.IntAll((*info)["i_isallow"]) > 0
  280. }
  281. }
  282. }
  283. return
  284. }
  285. //更新设置信息
  286. func UpdateParticipateSetInfo(in *bxcore.ParticipateSetUpInfoReq) error {
  287. defer MC.Catch()
  288. query := map[string]interface{}{
  289. "i_positionid": in.PositionId,
  290. }
  291. if in.PositionType > 0 {
  292. //企业版 判断是否是管理员
  293. //判断用户身份
  294. userInfo := IC.Middleground.PowerCheckCenter.Check(in.AppId, in.UserId, in.NewUserId, in.AccountId, in.EntId, in.PositionType, in.PositionId)
  295. if userInfo.Ent.EntRoleId == 0 {
  296. return fmt.Errorf("当前企业身份无权限")
  297. }
  298. query["i_entid"] = in.EntId
  299. }
  300. upsert := map[string]interface{}{
  301. "i_entid": in.EntId,
  302. "i_entuserid": in.EntUserId,
  303. "i_positionid": in.PositionId,
  304. "l_createtime": time.Now().Unix(),
  305. }
  306. if in.IsAllow != "" {
  307. isAllow, _ := strconv.Atoi(in.IsAllow)
  308. upsert["i_isallow"] = isAllow
  309. }
  310. if len(in.BidType) > 0 {
  311. upsert["o_bidtype"] = in.BidType
  312. }
  313. if len(in.RemindRule) > 0 {
  314. upsert["o_remindrule"] = in.RemindRule
  315. }
  316. if in.NecessaryField != "" {
  317. upsert["s_requiredField"] = in.NecessaryField
  318. }
  319. if ok := IC.Mgo.Update(PartTable, query, map[string]interface{}{
  320. "$set": upsert,
  321. }, true, false); ok {
  322. return nil
  323. }
  324. return fmt.Errorf("更新失败")
  325. }
  326. //查询企业|个人参标设置信息
  327. func GetParticipateSetInfo(in *bxcore.ParticipateSetUpInfoReq) (*bxcore.ParticipateSetUpInfo, error) {
  328. defer MC.Catch()
  329. query := map[string]interface{}{
  330. "i_positionid": in.PositionId,
  331. }
  332. if in.PositionType > 0 {
  333. query["i_entid"] = in.EntId
  334. }
  335. if setInfo, ok := IC.Mgo.FindOne(PartTable, query); ok {
  336. var (
  337. isAllow, isRequird string
  338. bidType []*bxcore.BidTypeReq
  339. remindRule []*bxcore.RemindRuleReq
  340. )
  341. bidType = append(bidType, &bxcore.BidTypeReq{
  342. Name: "直接投标",
  343. Content: []string{"未报名", "已报名", "投标决策", "编制投标文件", "递交投标文件", "中标公示", "签合同", "已结束"},
  344. }, &bxcore.BidTypeReq{
  345. Name: "渠道投标",
  346. Content: []string{"已报名", "签合同", "已结束"},
  347. })
  348. remindRule = append(remindRule, &bxcore.RemindRuleReq{
  349. BidState: "直接投标",
  350. Remainder: 72,
  351. Node: "编制投标文件",
  352. })
  353. if setInfo != nil {
  354. //必填字段
  355. if (*setInfo)["s_requiredField"] != nil {
  356. isRequird = MC.ObjToString((*setInfo)["s_requiredField"])
  357. } else {
  358. isRequird = "bidType"
  359. }
  360. if (*setInfo)["i_isallow"] != nil {
  361. isAllow = strconv.Itoa(MC.IntAll((*setInfo)["i_isallow"]))
  362. }
  363. if (*setInfo)["o_bidtype"] != nil {
  364. if sbb, err := json.Marshal((*setInfo)["o_bidtype"]); err == nil {
  365. if err := json.Unmarshal(sbb, &bidType); err != nil {
  366. logx.Info("bidType json un err:", err.Error())
  367. return nil, err
  368. }
  369. } else {
  370. logx.Info("bidType json err:", err.Error())
  371. return nil, err
  372. }
  373. }
  374. if (*setInfo)["o_remindrule"] != nil {
  375. if sbr, err := json.Marshal((*setInfo)["o_remindrule"]); err == nil {
  376. if err := json.Unmarshal(sbr, &remindRule); err != nil {
  377. logx.Info("remindRule json un err:", err.Error())
  378. return nil, err
  379. }
  380. } else {
  381. logx.Info("remindRule json err:", err.Error())
  382. return nil, err
  383. }
  384. }
  385. }
  386. return &bxcore.ParticipateSetUpInfo{
  387. NecessaryField: isRequird,
  388. IsAllow: isAllow,
  389. BidType: bidType,
  390. RemindRule: remindRule,
  391. }, nil
  392. }
  393. return nil, nil
  394. }
  395. //保存或更新tidb 项目信息
  396. func UpdateProjectInfo(id string, pInfo map[string]interface{}) error {
  397. //id 项目id
  398. //name 项目名称
  399. //area 省份
  400. //city 城市
  401. //buyer 采购单位
  402. //budget 预算
  403. //bid_open_time 开标时间
  404. //zbtime 招标时间
  405. //bid_end_time 开标结束时间 bidding表 由 数据组 重新生索引到project表
  406. //pici 批次 轮询更新数据
  407. //
  408. projectInfo := map[string]interface{}{
  409. "id": id,
  410. "name": MC.ObjToString(pInfo["projectname"]),
  411. "area": MC.ObjToString(pInfo["area"]),
  412. "city": MC.ObjToString(pInfo["city"]),
  413. "buyer": MC.ObjToString(pInfo["buyer"]),
  414. "budget": MC.Int64All(pInfo["budget"]),
  415. }
  416. if pInfo["bidopentime"] != nil {
  417. openTime := pInfo["bidopentime"]
  418. projectInfo["bid_open_time"] = date.FormatDateWithObj(&openTime, date.Date_Full_Layout)
  419. }
  420. if pInfo["pici"] != nil {
  421. pici := pInfo["pici"]
  422. projectInfo["pici"] = date.FormatDateWithObj(&pici, date.Date_Full_Layout)
  423. }
  424. // 项目表:zbtime 招标时间是 biding表:publishtime发布时间
  425. if pInfo["zbtime"] != nil {
  426. bidTime := pInfo["zbtime"]
  427. projectInfo["bid_time"] = date.FormatDateWithObj(&bidTime, date.Date_Full_Layout)
  428. }
  429. if pInfo["bidendtime"] != nil {
  430. bidEndTime := pInfo["bidendtime"]
  431. projectInfo["bid_end_time"] = date.FormatDateWithObj(&bidEndTime, date.Date_Full_Layout)
  432. }
  433. if c := IC.BaseMysql.CountBySql(`SELECT COUNT(id) FROM project WHERE id = ?`, id); c > 0 {
  434. if ok := IC.BaseMysql.Update("project", map[string]interface{}{
  435. "id": id,
  436. }, projectInfo); !ok {
  437. return fmt.Errorf("项目信息更新异常", id)
  438. }
  439. } else {
  440. if i := IC.BaseMysql.Insert("project", projectInfo); i < 0 {
  441. return fmt.Errorf("项目信息插入异常", id)
  442. }
  443. }
  444. return nil
  445. }
  446. //参标列表其他条件
  447. func ParticipateListSql(in *bxcore.ParticipateListReq) string {
  448. //b project表
  449. //a participate_user表
  450. now := time.Now()
  451. nowDate := date.FormatDate(&now, date.Date_Full_Layout)
  452. //查询tidb base_service.project
  453. conditionSql := ` WHERE 1=1 `
  454. //地区
  455. if in.Area != "" {
  456. conditionSql += fmt.Sprintf(" AND pt.area IN ('%s') ", strings.ReplaceAll(in.Area, ",", "','"))
  457. }
  458. //城市
  459. if in.City != "" {
  460. conditionSql += fmt.Sprintf(" AND pt.city IN ('%s') ", strings.ReplaceAll(in.City, ",", "','"))
  461. }
  462. //关键词
  463. if in.Keywords != "" {
  464. kSql := ` AND (`
  465. for kk, kv := range strings.Split(in.Keywords, " ") {
  466. if kk > 0 {
  467. kSql += " OR "
  468. }
  469. kSql += " pt.name like '%" + kv + "%'"
  470. }
  471. kSql += `)`
  472. conditionSql += kSql
  473. }
  474. //招标日期
  475. if in.BidTime != "" && strings.Contains(in.BidTime, "-") {
  476. startTime := strings.Split(in.BidTime, "-")[0]
  477. entTime := strings.Split(in.BidTime, "-")[1]
  478. if startTime != "" {
  479. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  480. conditionSql += ` AND pt.bid_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  481. }
  482. if entTime != "" {
  483. entTimeInt, _ := strconv.ParseInt(entTime, 10, 64)
  484. conditionSql += ` AND pt.bid_time < '` + date.FormatDateByInt64(&entTimeInt, date.Date_Full_Layout) + `'`
  485. }
  486. }
  487. //招标截止日期
  488. if in.BidEndTime != "" {
  489. //投标截止日期规则:
  490. //1、开始时间小于当前时间 ,结束时间大于当前时间,投标截止状态按钮未截止和已截止可用;
  491. //2、结束时间小于当前时间|开始时间大于当前时间,投标截止状态按钮未截止和已截止不可用;
  492. //3、需要前端做成连动
  493. startTime := strings.Split(in.BidEndTime, "-")[0]
  494. endTime := strings.Split(in.BidEndTime, "-")[1]
  495. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  496. endTimeInt, _ := strconv.ParseInt(endTime, 10, 64)
  497. if startTimeInt > 0 && endTimeInt > 0 && startTimeInt > endTimeInt {
  498. logx.Info(fmt.Sprintf("投标截止日期 %d 开始时间 大于 结束时间%d!!!", startTimeInt, endTimeInt))
  499. } else {
  500. switch in.BidEndStatus {
  501. case 0:
  502. if startTimeInt > 0 {
  503. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  504. }
  505. if endTimeInt > 0 {
  506. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  507. }
  508. case 1: //投标截止状态:1:未截止;2:已截止;3:终止参标
  509. //未截止:
  510. var (
  511. endBool = true
  512. )
  513. //如果结束时间存在且小于当前时间,投标截止日期 范围都是已截止 不会存在未截止的数据
  514. if endTimeInt > 0 {
  515. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  516. endBool = endTimeInt > now.Unix()
  517. }
  518. //开始时间小于 当前时间
  519. if endBool && now.Unix() > startTimeInt {
  520. startTimeInt = now.Unix()
  521. }
  522. //存在开始时间为0的情况
  523. if startTimeInt > 0 {
  524. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  525. }
  526. case 2: //投标截止状态:1:未截止;2:已截止;3:终止参标
  527. //如果开始时间存在且大于当前时间,投标截止日期 范围都是未截止 不会存在已截止的数据
  528. var (
  529. startBool = true
  530. )
  531. if startTimeInt > 0 {
  532. conditionSql += ` AND pt.bid_end_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  533. startBool = startTimeInt < now.Unix()
  534. }
  535. if startBool && (endTimeInt == 0 || now.Unix() < endTimeInt) {
  536. endTimeInt = now.Unix()
  537. }
  538. //存在结束时间为0的情况
  539. if endTimeInt > 0 {
  540. conditionSql += ` AND pt.bid_end_time < '` + date.FormatDateByInt64(&endTimeInt, date.Date_Full_Layout) + `'`
  541. }
  542. case 3:
  543. conditionSql += ` AND pug.state < 0 `
  544. }
  545. }
  546. } else if in.BidEndStatus > 0 { //投标截止状态1:未截止;2:已截止;3:终止参标
  547. switch in.BidEndStatus {
  548. case 1:
  549. conditionSql += ` AND pt.bid_end_time > '` + nowDate + `'`
  550. case 2:
  551. conditionSql += ` AND pt.bid_end_time < '` + nowDate + `'`
  552. case 3:
  553. conditionSql += ` AND pug.state < 0 `
  554. }
  555. }
  556. //开标时间
  557. if in.BidOpenTime != "" {
  558. startTime := strings.Split(in.BidOpenTime, "-")[0]
  559. entTime := strings.Split(in.BidOpenTime, "-")[1]
  560. if startTime != "" {
  561. startTimeInt, _ := strconv.ParseInt(startTime, 10, 64)
  562. conditionSql += ` AND pt.bid_open_time > '` + date.FormatDateByInt64(&startTimeInt, date.Date_Full_Layout) + `'`
  563. }
  564. if entTime != "" {
  565. entTimeInt, _ := strconv.ParseInt(entTime, 10, 64)
  566. conditionSql += ` AND pt.bid_open_time < '` + date.FormatDateByInt64(&entTimeInt, date.Date_Full_Layout) + `'`
  567. }
  568. }
  569. //开标状态1:未开标;2:已开标
  570. if in.BidOpenStatus > 0 {
  571. switch in.BidOpenStatus {
  572. case 1:
  573. conditionSql += ` AND pt.bid_open_time > '` + nowDate + `'`
  574. case 2:
  575. conditionSql += ` AND pt.bid_open_time < '` + nowDate + `'`
  576. }
  577. }
  578. //参标人 管理员权限
  579. if in.EntUserIds != "" && in.PositionType > 0 {
  580. conditionSql += ` AND (`
  581. for k, v := range strings.Split(in.EntUserIds, ",") {
  582. if k > 0 {
  583. conditionSql += " OR "
  584. }
  585. conditionSql += ` FIND_IN_SET(` + v + ` , pug.ent_user_id) `
  586. }
  587. conditionSql += `)`
  588. }
  589. //默认按照投标截止日期正序排列、1:开标时间正序、2:更新状态时间倒序
  590. //投标结束时间和开标时间 很多项目数据没有这两个字段值
  591. switch in.OrderNum {
  592. case 1:
  593. conditionSql += ` ORDER BY pt.bid_open_time ASC,pt.bid_end_time ASC,pug.update_date DESC`
  594. case 2:
  595. conditionSql += ` ORDER BY pug.update_date DESC`
  596. default:
  597. conditionSql += ` ORDER BY pt.bid_end_time ASC,pt.bid_open_time ASC,pug.update_date DESC`
  598. }
  599. logx.Info(conditionSql)
  600. return conditionSql
  601. }
  602. //个人或员工查询参标列表
  603. func SingleParticipateList(in *bxcore.ParticipateListReq, conditionSql string) (data *bxcore.ParticipateData, err error) {
  604. defer MC.Catch()
  605. data = &bxcore.ParticipateData{
  606. NowTime: time.Now().Unix(),
  607. Count: 0,
  608. List: []*bxcore.ParticipateList{},
  609. }
  610. //员工|个人列表
  611. singlePersonSql := `SELECT %s FROM ` + ParticipateUserTable + ` pug LEFT JOIN project pt ON pug.project_id = pt.id WHERE pug.position_id = ? `
  612. singlePersonSql += conditionSql
  613. countSql := fmt.Sprintf(singlePersonSql, " COUNT(pt.id) ")
  614. count := IC.BaseMysql.CountBySql(countSql, in.PositionId)
  615. if count > 0 {
  616. data.Count = count
  617. listSql := fmt.Sprintf(singlePersonSql, " pug.update_date,pt.* ")
  618. //分页
  619. listSql += fmt.Sprintf(` LIMIT %d,%d`, in.PageNum, in.PageSize)
  620. list := IC.BaseMysql.SelectBySql(listSql, in.PositionId)
  621. if list != nil && len(*list) > 0 {
  622. for _, v := range *list {
  623. bidTimeStr := MC.ObjToString(v["bid_time"])
  624. bidEndTimeStr := MC.ObjToString(v["bid_end_time"])
  625. bidOpenTimeStr := MC.ObjToString(v["bid_open_time"])
  626. updateStatusTimeStr := MC.ObjToString(v["update_date"])
  627. var bidTime, bidEndTime, bidOpenTime, updateStatusTime int64
  628. if bidTimeStr != "" {
  629. bidTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidTimeStr, time.Local)
  630. bidTime = bidTime_.Unix()
  631. }
  632. if bidEndTimeStr != "" {
  633. bidEndTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidEndTimeStr, time.Local)
  634. bidEndTime = bidEndTime_.Unix()
  635. }
  636. if bidOpenTimeStr != "" {
  637. bidOpenTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidOpenTimeStr, time.Local)
  638. bidOpenTime = bidOpenTime_.Unix()
  639. }
  640. if updateStatusTimeStr != "" {
  641. updateStatusTime_, _ := time.ParseInLocation(date.Date_Full_Layout, updateStatusTimeStr, time.Local)
  642. updateStatusTime = updateStatusTime_.Unix()
  643. }
  644. data.List = append(data.List, &bxcore.ParticipateList{
  645. Id: encrypt.EncodeArticleId2ByCheck(MC.ObjToString(v["id"])),
  646. ProjectName: MC.ObjToString(v["name"]),
  647. Buyer: MC.ObjToString(v["buyer"]),
  648. Budget: MC.ObjToString(v["budget"]),
  649. BidTime: bidTime,
  650. BidEndTime: bidEndTime,
  651. BidOpenTime: bidOpenTime,
  652. UpdateStatusTime: updateStatusTime,
  653. //UpdateStatusCon: GetParticipateContent("s", in.PositionId, MC.ObjToString(v["id"])), //查询最后一次 投标状态更新,
  654. })
  655. }
  656. return data, nil
  657. }
  658. return nil, fmt.Errorf("数据异常")
  659. }
  660. return data, nil
  661. }
  662. //管理员获取参标列表数据
  663. func AdminParticipateList(in *bxcore.ParticipateListReq, conditionSql string) (data *bxcore.ParticipateData, err error) {
  664. defer MC.Catch()
  665. data = &bxcore.ParticipateData{
  666. IsAllow: IsALLow(in.EntId),
  667. NowTime: time.Now().Unix(),
  668. Count: 0,
  669. List: []*bxcore.ParticipateList{},
  670. }
  671. 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`
  672. adminCountSql := fmt.Sprintf(adminSql, "COUNT(pt.id)") + conditionSql
  673. log.Println(adminCountSql)
  674. count := IC.BaseMysql.CountBySql(adminCountSql, in.EntId)
  675. if count > 0 {
  676. data.Count = count
  677. in.PageNum = (in.PageNum - 1) * in.PageSize
  678. adminListSql := fmt.Sprintf(adminSql, " pt.*, pug.ent_user_id,pug.update_date ") + conditionSql + fmt.Sprintf(" LIMIT %d,%d", in.PageNum, in.PageSize)
  679. list := IC.BaseMysql.SelectBySql(adminListSql, in.EntId)
  680. if list != nil && len(*list) > 0 {
  681. for _, v := range *list {
  682. bidTimeStr := MC.ObjToString(v["bid_time"])
  683. bidEndTimeStr := MC.ObjToString(v["bid_end_time"])
  684. bidOpenTimeStr := MC.ObjToString(v["bid_open_time"])
  685. updateStatusTimeStr := MC.ObjToString(v["update_date"])
  686. var bidTime, bidEndTime, bidOpenTime, updateStatusTime int64
  687. if bidTimeStr != "" {
  688. bidTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidTimeStr, time.Local)
  689. bidTime = bidTime_.Unix()
  690. }
  691. if bidEndTimeStr != "" {
  692. bidEndTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidEndTimeStr, time.Local)
  693. bidEndTime = bidEndTime_.Unix()
  694. }
  695. if bidOpenTimeStr != "" {
  696. bidOpenTime_, _ := time.ParseInLocation(date.Date_Full_Layout, bidOpenTimeStr, time.Local)
  697. bidOpenTime = bidOpenTime_.Unix()
  698. }
  699. if updateStatusTimeStr != "" {
  700. updateStatusTime_, _ := time.ParseInLocation(date.Date_Full_Layout, updateStatusTimeStr, time.Local)
  701. updateStatusTime = updateStatusTime_.Unix()
  702. }
  703. data.List = append(data.List, &bxcore.ParticipateList{
  704. Id: encrypt.EncodeArticleId2ByCheck(MC.ObjToString(v["id"])),
  705. ProjectName: MC.ObjToString(v["name"]),
  706. Buyer: MC.ObjToString(v["buyer"]),
  707. Budget: MC.ObjToString(v["budget"]),
  708. BidTime: bidTime,
  709. BidEndTime: bidEndTime,
  710. BidOpenTime: bidOpenTime,
  711. UpdateStatusTime: updateStatusTime,
  712. //UpdateStatusCon: GetParticipateContent("e", in.EntId, MC.ObjToString(v["id"])), //查询最后一次 投标状态更新
  713. Participants: GetParticipateUserName(MC.ObjToString(v["ent_user_id"])), //参标人信息
  714. })
  715. }
  716. return data, nil
  717. }
  718. return nil, fmt.Errorf("数据异常")
  719. }
  720. return data, nil
  721. }
  722. //获取最新参标 更新内容
  723. func GetParticipateContent(s string, id int64, projectId string) string {
  724. identitySql := `ent_id = ?`
  725. if s == "s" {
  726. identitySql = `position_id = ?`
  727. }
  728. recordsSql := `SELECT record_content,record_type FROM ` + ParticipateBidRecordsTable + ` WHERE ` + identitySql + ` AND project_id = ? ORDER BY create_date DESC LIMIT 1;`
  729. records := IC.BaseMysql.SelectBySql(recordsSql, id, projectId)
  730. if records != nil && len(*records) > 0 {
  731. rec := (*records)[0]
  732. switch MC.IntAll(rec["record_type"]) {
  733. case 0:
  734. return MC.ObjToString(rec["record_content"])
  735. case 1:
  736. recordContent := *MC.ObjToMap(rec["record_content"])
  737. rb, err := json.Marshal(recordContent)
  738. if err != nil {
  739. log.Println(err.Error())
  740. return ""
  741. }
  742. var rc = RecordsContent{
  743. After: PartStatusContent{},
  744. Before: PartStatusContent{},
  745. }
  746. err1 := json.Unmarshal(rb, &rc)
  747. if err1 == nil {
  748. return rc.Content
  749. }
  750. }
  751. }
  752. return ""
  753. }
  754. //根据ent_user_id 获取参标人昵称,企业管理员现在都是“我”
  755. func GetParticipateUserName(entUserId string) string {
  756. if entUserId != "" {
  757. var userNames []string
  758. for _, v := range strings.Split(entUserId, ",") {
  759. entUserInfos := IC.MainMysql.SelectBySql(`SELECT * FROM entniche_user WHERE id = ?`, v)
  760. if entUserInfos != nil && len(*entUserInfos) > 0 {
  761. entUserInfo := (*entUserInfos)[0]
  762. if entUserInfo["name"] != nil {
  763. if userName := MC.ObjToString(entUserInfo["name"]); userName != "" {
  764. userNames = append(userNames, userName)
  765. }
  766. }
  767. }
  768. }
  769. return strings.Join(userNames, ",")
  770. }
  771. return ""
  772. }
  773. // GetBidContentEnt 企业版 获取投标状态更新内容
  774. func GetBidContentEnt(projectId string, entId int64) *[]map[string]interface{} {
  775. // record_type '默认0:参标、划转、取消参标;1:投标状态更新存储'
  776. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? and record_type=1 order by create_date desc limit 1; "
  777. return IC.BaseMysql.SelectBySql(query, projectId, entId)
  778. }
  779. // GetBidContentPersonal 个人版 获取投标状态更新内容
  780. func GetBidContentPersonal(projectId string, positionId int64) *[]map[string]interface{} {
  781. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? and record_type=1 order by create_date desc limit 1;"
  782. return IC.BaseMysql.SelectBySql(query, projectId, positionId)
  783. }
  784. // UpdateBidContent 更新投标状态信息以及操作记录
  785. func UpdateBidContent(recordData map[string]interface{}) (flag bool) {
  786. r2 := IC.BaseMysql.Insert(ParticipateBidRecordsTable, recordData)
  787. return r2 > 0
  788. }
  789. // InsertBidContent 新增投标状态信息及操作记录
  790. func InsertBidContent(recordData map[string]interface{}) (flag bool) {
  791. r2 := IC.BaseMysql.Insert(ParticipateBidRecordsTable, recordData)
  792. return r2 > 0
  793. }
  794. // GetBidRecordsEnt 获取操作记录列表企业
  795. func GetBidRecordsEnt(projectId string, entId, page, pageSize int64) (rs *[]map[string]interface{}, total int64) {
  796. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? order by create_date desc limit ?,?"
  797. countQuery := "SELECT count(id) FROM " + ParticipateBidRecordsTable + " where project_id=? and ent_id=? ;"
  798. rs = IC.BaseMysql.SelectBySql(query, projectId, entId, (page-1)*pageSize, pageSize)
  799. total = IC.BaseMysql.CountBySql(countQuery, projectId, entId)
  800. return rs, total
  801. }
  802. // GetBidRecordsPersonal 获取操作记录列表个人
  803. func GetBidRecordsPersonal(projectId string, positionId, page, pageSize int64) (rs *[]map[string]interface{}, total int64) {
  804. query := "SELECT * FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? order by create_date desc limit ?,?;"
  805. countQuery := "SELECT count(id) FROM " + ParticipateBidRecordsTable + " where project_id=? and position_id=? ;"
  806. rs = IC.BaseMysql.SelectBySql(query, projectId, positionId, (page-1)*pageSize, pageSize)
  807. total = IC.BaseMysql.CountBySql(countQuery, projectId, positionId)
  808. return rs, total
  809. }
  810. // GetUserMap 查询用户id的姓名
  811. func GetUserMap(userIds string) (rs *[]map[string]interface{}) {
  812. query := fmt.Sprintf("select id,name from entniche_user where id in (%s)", userIds)
  813. rs = IC.MainMysql.SelectBySql(query)
  814. return rs
  815. }
  816. // CheckParticipateManager 验证项目id是否是该管理员企业下的参标项目
  817. func CheckParticipateManager(projectId string, entId int64, valid bool) (flag bool) {
  818. stateStr := "" // 是否需要验证是正在参标
  819. if valid {
  820. stateStr = " and state=0"
  821. }
  822. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and ent_id=?" + stateStr
  823. return IC.BaseMysql.CountBySql(query, projectId, entId) > 0
  824. }
  825. // CheckParticipateEntUser 验证项目id是否是该企业用户参标的项目
  826. func CheckParticipateEntUser(projectId string, entUserId int64, valid bool) (flag bool) {
  827. stateStr := "" // 是否需要验证是正在参标
  828. if valid {
  829. stateStr = " and state=0"
  830. }
  831. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and ent_user_id=?" + stateStr
  832. return IC.BaseMysql.CountBySql(query, projectId, entUserId) > 0
  833. }
  834. // CheckParticipatePersonal 查询项目id是否是该用户参标项目
  835. func CheckParticipatePersonal(projectId string, positionId int64, valid bool) (flag bool) {
  836. stateStr := "" // 是否需要验证是正在参标 终止参标的用户还能查看记录,但是不能更新状态
  837. if valid {
  838. stateStr = " and state=0"
  839. }
  840. query := "SELECT count(id) FROM " + ParticipateUserTable + " where project_id=? and position_id=?" + stateStr
  841. return IC.BaseMysql.CountBySql(query, projectId, positionId) > 0
  842. }
  843. // GetNameByUserIds 获取用户名字符串
  844. // 参数:逗号分割的用户id "11,22,333..."
  845. // 返回: "张三,李四,王五..."
  846. func GetNameByUserIds(ids string) *[]map[string]interface{} {
  847. query := "select group_concat(name) as name from " + EntnicheUserTable + " where id in (" + ids + ") "
  848. rs := IC.MainMysql.SelectBySql(query)
  849. return rs
  850. }
  851. // ParticipateProjectPersonal 查询给定项目id中已经参标的项目id
  852. func ParticipateProjectPersonal(positionId int64, projectId []string) *[]map[string]interface{} {
  853. // 1. 查询出已经参标的
  854. var arg []string
  855. var value []interface{}
  856. value = append(value, positionId)
  857. for i := 0; i < len(projectId); i++ {
  858. arg = append(arg, "?")
  859. value = append(value, projectId[i])
  860. }
  861. argStr := strings.Join(arg, ",")
  862. query := "select project_id from " + ParticipateUserTable + " where position_id = ? and project_id in (%s) and state=0"
  863. rs := IC.BaseMysql.SelectBySql(fmt.Sprintf(query, argStr), value...)
  864. return rs
  865. }
  866. // ParticipateProjectEnt 查询给定项目id中已经参标的项目id
  867. func ParticipateProjectEnt(entId int64, projectId []string) *[]map[string]interface{} {
  868. // 1. 查询出已经参标的
  869. var arg []string
  870. var value []interface{}
  871. value = append(value, entId)
  872. for i := 0; i < len(projectId); i++ {
  873. arg = append(arg, "?")
  874. value = append(value, projectId[i])
  875. }
  876. argStr := strings.Join(arg, ",")
  877. query := "select GROUP_CONCAT(ent_user_id) as personIds ,project_id from " + ParticipateUserTable + " where ent_id=? and project_id in (%s) and state=0 group by project_id "
  878. rs := IC.BaseMysql.SelectBySql(fmt.Sprintf(query, argStr), value...)
  879. return rs
  880. }
  881. //查询企业人员信息
  882. func GetPersonInfo(entId, entUserId int64, participateMap map[int64]bool) []*bxcore.ParticipatePerson {
  883. r := IC.MainMysql.SelectBySql(`SELECT a.id,a.pid,a.name,c.id as user_id,c.name as user_name,c.phone as user_phone,c.power as user_power,e.name as role from entniche_department a
  884. INNER JOIN entniche_department_user b on (a.ent_id=? and a.id=b.dept_id)
  885. INNER JOIN entniche_user c on (b.user_id=c.id)
  886. LEFT JOIN entniche_user_role d on (c.id=d.user_id)
  887. LEFT JOIN entniche_role e on (d.role_id=e.id)
  888. order by a.id,convert(c.name using gbk) COLLATE gbk_chinese_ci asc`, entId)
  889. var (
  890. list []*bxcore.ParticipatePerson
  891. prevId int64 = 0
  892. )
  893. for _, v := range *r {
  894. //if entUserId == MC.Int64All(v["user_id"]) {
  895. // continue
  896. //}
  897. id := MC.Int64All(v["id"])
  898. userId := strconv.FormatInt(MC.Int64All(v["user_id"]), 10)
  899. user := &bxcore.ParticipatePerson{
  900. Id: encrypt.SE.Encode2HexByCheck(userId),
  901. Power: MC.Int64All(v["user_power"]),
  902. Name: MC.ObjToString(v["user_name"]),
  903. Phone: MC.ObjToString(v["user_phone"]),
  904. Role: MC.ObjToString(v["role"]),
  905. }
  906. if participateMap != nil {
  907. if participateMap[MC.Int64All(v["user_id"])] {
  908. user.IsPart = 1
  909. }
  910. }
  911. if prevId == id {
  912. users := list[len(list)-1].Users
  913. users = append(users, user)
  914. list[len(list)-1].Users = users
  915. } else {
  916. seId := strconv.FormatInt(id, 10)
  917. list = append(list, &bxcore.ParticipatePerson{
  918. Id: encrypt.SE.Encode2HexByCheck(seId),
  919. Name: MC.ObjToString(v["name"]),
  920. Pid: MC.Int64All(v["pid"]),
  921. Users: []*bxcore.ParticipatePerson{user},
  922. })
  923. }
  924. prevId = id
  925. }
  926. return list
  927. }
  928. //是否允许多人参标
  929. func IsALLow(entId int64) bool {
  930. return GetParticipateIsAllow(map[string]interface{}{
  931. "i_entid": entId,
  932. })
  933. }