acceptance.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. package service
  2. import (
  3. "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/date"
  5. "app.yhyue.com/moapp/jybase/mail"
  6. "app.yhyue.com/moapp/jybase/redis"
  7. . "bp.jydev.jianyu360.cn/BaseService/biService/entity"
  8. "bp.jydev.jianyu360.cn/BaseService/biService/rpc/biservice"
  9. "database/sql"
  10. "fmt"
  11. "github.com/gogf/gf/v2/util/gconv"
  12. "github.com/zeromicro/go-zero/core/logx"
  13. "log"
  14. "strings"
  15. "time"
  16. )
  17. // AddAcceptance 处理受理单新增逻辑
  18. // 参数:
  19. //
  20. // in - 受理单请求数据
  21. // productMap - 产品映射关系
  22. // entId - 企业ID
  23. //
  24. // 返回值:
  25. //
  26. // 成功返回受理单编号,失败返回空字符串
  27. func AddAcceptance(in *biservice.AcceptanceReq, productMap []ProductMap, entId int64) string {
  28. // 清理参数数据中的换行符
  29. in.ParamData = strings.ReplaceAll(in.ParamData, "\n", "")
  30. nowTime := time.Now().Format(date.Date_Full_Layout)
  31. // 线索标识初始化
  32. is_clue := 1
  33. deptName := ""
  34. // 如果有部门ID,查询部门名称
  35. if in.DeptId != "" {
  36. deptData := JyMysql.FindOne("entniche_department", map[string]interface{}{
  37. "id": in.DeptId,
  38. }, "name", "")
  39. if deptData != nil && len(*deptData) > 0 {
  40. deptName = gconv.String((*deptData)["name"])
  41. }
  42. }
  43. // 生成受理单编号:SLD+年月日+4位序号
  44. acceptance_no := fmt.Sprintf("SLD%s%s", time.Now().Format(date.Date_yyyyMMdd), FindNumber("sld"))
  45. // 准备受理单主表数据
  46. acceptanceMap := map[string]interface{}{
  47. "acceptance_no": acceptance_no, // 受理单编号
  48. "propose_type": in.ProposeType, // 提出类型
  49. "propose_time": in.ProposeTime, // 提出时间
  50. "channel": in.Channel, // 渠道
  51. "acceptance_type": in.AcceptanceType, // 受理类型
  52. "status": in.Status, // 状态
  53. "initiator_name": in.EntUserName, // 发起人姓名
  54. "initiator_position_id": in.PositionId, // 发起人职位ID
  55. "department_no": in.DeptId, // 部门编号
  56. "remark": in.Remark, // 备注
  57. "is_delete": 1, // 删除标识
  58. "creator_name": in.EntUserName, // 创建人姓名
  59. "creator_position_id": in.PositionId, // 创建人职位ID
  60. "creator_time": nowTime, // 创建时间
  61. "department_name": deptName, // 部门名称
  62. }
  63. // 开启事务处理
  64. ok := WorkOrder.ExecTx("受理单处理", func(tx *sql.Tx) bool {
  65. // 处理受理单子表数据
  66. childMap := gconv.Map(in.ParamData)
  67. if childMap != nil && len(childMap) > 0 {
  68. phone := "" // 客户联系方式
  69. company := "" // 公司名称
  70. innerArr := []interface{}{} // 子表数据数组
  71. innerStr := []string{"acceptance_no", "field_name", "field_value", "creator_name", "creator_position_id", "creator_time"}
  72. // 遍历子表字段
  73. for k, v := range childMap {
  74. innerArr = append(innerArr, acceptance_no) // 受理单编号
  75. innerArr = append(innerArr, k) // 字段名
  76. innerArr = append(innerArr, v) // 字段值
  77. innerArr = append(innerArr, in.EntUserName) // 创建人
  78. innerArr = append(innerArr, in.PositionId) // 职位ID
  79. innerArr = append(innerArr, nowTime) // 创建时间
  80. // 特殊字段处理
  81. switch k {
  82. case "公司名称":
  83. company = gconv.String(v)
  84. case "联系方式num":
  85. phone = gconv.String(v)
  86. }
  87. }
  88. // 批量插入子表数据
  89. if len(innerArr) > 0 {
  90. ok2, ok3 := WorkOrder.InsertBatchByTx(tx, "order_acceptance_children", innerStr, innerArr)
  91. if ok2 <= 0 && ok3 <= 0 {
  92. return false
  93. }
  94. }
  95. // 处理产品信息
  96. selectedProductMap := map[string]SelectProductMap{} // 选中的产品映射
  97. productArr := []string{} // 产品数组
  98. // 如果有咨询产品字段
  99. if _, isOk := childMap["咨询产品"]; isOk {
  100. // 分割产品字符串
  101. for _, v := range strings.Split(gconv.String(childMap["咨询产品"]), ",") {
  102. // 匹配产品信息
  103. for _, product := range productMap {
  104. if strings.Contains(product.Product, v) {
  105. selectedProduct := selectedProductMap[product.ProductCode]
  106. selectedProduct.PersonArr = product.PersonArr
  107. selectedProduct.Product = append(selectedProduct.Product, v)
  108. selectedProduct.IsAddMarketing = product.IsAddMarketing
  109. productArr = append(productArr, v)
  110. selectedProductMap[product.ProductCode] = selectedProduct
  111. continue
  112. }
  113. }
  114. }
  115. // 检查是否所有产品都匹配成功
  116. if len(strings.Split(gconv.String(childMap["咨询产品"]), ",")) != len(productArr) {
  117. is_clue = 2 // 设置为线索
  118. }
  119. }
  120. // 为每个产品创建工单
  121. for k, v := range selectedProductMap {
  122. ok, positionId, product, dkPerson := AddOrderWork(k, acceptance_no, nowTime, phone, company, tx, in, v, entId)
  123. if !ok {
  124. return false
  125. } else {
  126. // 如果需要加入营销
  127. if v.IsAddMarketing {
  128. go MarketingSave(in, positionId, product, dkPerson)
  129. }
  130. }
  131. }
  132. }
  133. // 设置线索标识并插入受理单主表
  134. acceptanceMap["is_clue"] = is_clue
  135. ok1 := WorkOrder.InsertByTx(tx, "order_acceptance", acceptanceMap)
  136. if ok1 <= 0 {
  137. logx.Info("受理单创建失败")
  138. return false
  139. }
  140. return true
  141. })
  142. if ok {
  143. return acceptance_no
  144. }
  145. return ""
  146. }
  147. // AddOrderWork 创建工单
  148. // 参数:
  149. //
  150. // orderType - 工单类型
  151. // acceptance_no - 受理单编号
  152. // nowTime - 当前时间
  153. // phone - 联系电话
  154. // company - 公司名称
  155. // tx - 事务对象
  156. // in - 受理单请求数据
  157. // selectPersonMap - 选择的人员映射
  158. // entId - 企业ID
  159. //
  160. // 返回值:
  161. //
  162. // bool - 是否成功
  163. // int64 - 职位ID
  164. // string - 产品信息
  165. // string - 处理人员姓名
  166. func AddOrderWork(orderType, acceptance_no, nowTime, phone,
  167. company string, tx *sql.Tx, in *biservice.AcceptanceReq, selectPersonMap SelectProductMap, entId int64) (bool, int64, string, string) {
  168. dkPerson := "" // 大客人员姓名
  169. dkdeptName := "" // 部门名称
  170. dkdeptId := int64(0) // 部门ID
  171. dkPositionId := int64(0) // 职位ID
  172. // 查找候选人
  173. personMap := FindCandidate(selectPersonMap.PersonArr, entId, orderType)
  174. dkPositionId = personMap.PositionId
  175. dkPerson = personMap.Name
  176. dkdeptId = personMap.DeptId
  177. dkdeptName = personMap.DeptName
  178. // 如果有有效的职位ID
  179. if dkPositionId != 0 {
  180. // 生成工单编号:GD+年月日+4位序号
  181. work_order_no := fmt.Sprintf("GD%s%s", time.Now().Format(date.Date_yyyyMMdd), FindNumber("gd"))
  182. // 准备工单数据
  183. orderWorkMap := map[string]interface{}{
  184. "work_order_no": work_order_no, // 工单编号
  185. "acceptance_no": acceptance_no, // 受理单编号
  186. "type": strings.Join(selectPersonMap.Product, ","), // 工单类型
  187. "status": 1, // 状态
  188. "initiator_name": in.EntUserName, // 发起人姓名
  189. "initiator_position_id": in.PositionId, // 发起人职位ID
  190. "current_name": dkPerson, // 当前处理人
  191. "current_position_id": dkPositionId, // 当前处理人职位ID
  192. "is_delete": 1, // 删除标识
  193. "creator_name": in.EntUserName, // 创建人
  194. "creator_position_id": in.PositionId, // 创建人职位ID
  195. "creator_time": nowTime, // 创建时间
  196. "two_type": orderType, // 二级类型
  197. "department_no": dkdeptId, // 部门编号
  198. "department_name": dkdeptName, // 部门名称
  199. "update_time": nil, // 更新时间
  200. }
  201. logx.Info(orderWorkMap, "11111", selectPersonMap)
  202. // 插入工单数据
  203. ok3 := WorkOrder.InsertByTx(tx, "order_work", orderWorkMap)
  204. if ok3 <= 0 {
  205. log.Println("工单保存失败")
  206. return false, 0, "", ""
  207. }
  208. // 准备审批记录数据
  209. approvalRecordMap := map[string]interface{}{
  210. "work_order_no": work_order_no, // 工单编号
  211. "status": 1, // 状态
  212. "new_status": nil, // 新状态
  213. "handle_name": dkPerson, // 处理人姓名
  214. "handle_position_id": dkPositionId, // 处理人职位ID
  215. "handle_dept_id": dkdeptId, // 处理部门ID
  216. "handle_dept_name": dkdeptName, // 处理部门名称
  217. "creator_name": in.EntUserName, // 创建人
  218. "creator_position_id": in.PositionId, // 创建人职位ID
  219. "is_delete": 1, // 删除标识
  220. "creator_time": nowTime, // 创建时间
  221. }
  222. // 插入审批记录
  223. ok4 := WorkOrder.InsertByTx(tx, "approval_record", approvalRecordMap)
  224. if ok4 <= 0 {
  225. log.Println("工单记录保存失败")
  226. return false, 0, "", ""
  227. }
  228. log.Println(GmailAuth, personMap, strings.Join(selectPersonMap.Product, ","), dkPerson, in.EntUserName, nowTime, work_order_no, phone, company)
  229. // 发送工作邮件
  230. WorkMail(GmailAuth, personMap, strings.Join(selectPersonMap.Product, ","), dkPerson, in.EntUserName, nowTime, work_order_no, phone, company)
  231. }
  232. return true, dkPositionId, strings.Join(selectPersonMap.Product, ","), dkPerson
  233. }
  234. // PersonJson 人员信息结构体
  235. type PersonJson struct {
  236. Name string // 姓名
  237. Phone string // 电话
  238. Mail string // 邮箱
  239. DeptId int64 // 部门ID
  240. DeptName string // 部门名称
  241. PositionId int64 // 职位ID
  242. IsResign bool // 是否离职
  243. EntUserId int64 // 企业用户ID
  244. DeptPersonMail string // 部门负责人邮箱
  245. DeptPersonName string // 部门负责人姓名
  246. SuperiorDepthPersonMail string // 上级部门负责人邮箱
  247. SuperiorDepthPersonName string // 上级部门负责人姓名
  248. }
  249. // FindCandidate 查找候选人
  250. // 参数:
  251. //
  252. // personArr - 人员数组
  253. // entId - 企业ID
  254. // orderType - 工单类型
  255. //
  256. // 返回值:
  257. //
  258. // PersonJson - 找到的候选人信息
  259. func FindCandidate(personArr []Person, entId int64, orderType string) PersonJson {
  260. personEntity := PersonJson{}
  261. personMap := make(map[string]map[string]interface{}) // 人员信息映射
  262. phoneArr := make([]string, len(personArr)) // 电话号码数组
  263. persons := make([]PersonJson, len(personArr)) // 人员信息数组
  264. // 初始化人员信息和电话数组
  265. for k, v := range personArr {
  266. phone := gconv.String(v.Phone)
  267. phoneArr[k] = fmt.Sprintf(`"%s"`, phone)
  268. personMap[phone] = map[string]interface{}{
  269. "name": gconv.String(v.Name),
  270. }
  271. persons[k] = PersonJson{
  272. Name: v.Name,
  273. Phone: v.Phone,
  274. IsResign: v.IsResign,
  275. }
  276. }
  277. // 查询人员邮箱和部门信息
  278. entUserArr := JyMysql.SelectBySql(fmt.Sprintf(`
  279. SELECT a.name, a.mail, b.dept_id AS deptId, a.phone, c.name AS deptName,a.id as entUserId
  280. FROM entniche_user a
  281. INNER JOIN entniche_department_user b ON a.ent_id = %d AND a.phone IN %s AND a.id = b.user_id
  282. INNER JOIN entniche_department c ON b.dept_id = c.id
  283. `, entId, fmt.Sprintf("(%s)", strings.Join(phoneArr, ","))))
  284. // 填充人员邮箱和部门信息
  285. if entUserArr != nil {
  286. for _, v := range *entUserArr {
  287. phone := gconv.String(v["phone"])
  288. personMap[phone]["mail"] = gconv.String(v["mail"])
  289. personMap[phone]["deptId"] = gconv.String(v["deptId"])
  290. personMap[phone]["deptName"] = gconv.String(v["deptName"])
  291. personMap[phone]["entUserId"] = gconv.String(v["entUserId"])
  292. }
  293. }
  294. // 查询职位信息
  295. positionArrMap := JyMysql.SelectBySql(fmt.Sprintf(`
  296. SELECT a.phone, b.id
  297. FROM base_service.base_user a
  298. INNER JOIN base_service.base_position b ON b.ent_id = %d AND a.phone IN %s AND b.user_id = a.id AND b.type = 1
  299. `, entId, fmt.Sprintf("(%s)", strings.Join(phoneArr, ","))))
  300. // 填充职位信息
  301. if positionArrMap != nil {
  302. for _, v := range *positionArrMap {
  303. phone := gconv.String(v["phone"])
  304. personMap[phone]["positionId"] = gconv.Int64(v["id"])
  305. }
  306. }
  307. // 更新人员数组中的完整信息
  308. for k, v := range persons {
  309. phone := v.Phone
  310. if info, exists := personMap[phone]; exists {
  311. persons[k].Mail = gconv.String(info["mail"])
  312. persons[k].DeptId = gconv.Int64(info["deptId"])
  313. persons[k].DeptName = gconv.String(info["deptName"])
  314. persons[k].PositionId = gconv.Int64(info["positionId"])
  315. persons[k].EntUserId = gconv.Int64(info["entUserId"])
  316. }
  317. }
  318. // 查询最近创建的工单
  319. orderWorkMap := WorkOrder.SelectBySql(fmt.Sprintf(`
  320. SELECT * FROM order_work WHERE two_type = "%s" ORDER BY creator_time DESC LIMIT 1
  321. `, orderType))
  322. var k int
  323. // 如果没有工单记录,从第一个人员开始
  324. if orderWorkMap == nil || len(*orderWorkMap) == 0 {
  325. k = findNextPersonIndex(persons, 0)
  326. } else {
  327. // 否则查找上次处理人,并找下一个
  328. currentName := gconv.String((*orderWorkMap)[0]["current_name"])
  329. k = findPersonIndexByName(persons, currentName)
  330. k = findNextPersonIndex(persons, k)
  331. }
  332. personEntity = persons[k]
  333. // 查询部门管理员信息
  334. fetchDeptAdmin(&personEntity)
  335. // 查询上级部门管理员信息
  336. fetchSuperiorAdmin(&personEntity)
  337. return personEntity
  338. }
  339. // findNextPersonIndex 查找下一个人员索引
  340. // 参数:
  341. //
  342. // personArr - 人员数组
  343. // startIndex - 起始索引
  344. //
  345. // 返回值:
  346. //
  347. // 下一个未离职人员的索引
  348. func findNextPersonIndex(personArr []PersonJson, startIndex int) int {
  349. n := len(personArr)
  350. // 如果当前索引是最后一个,则从0开始
  351. if startIndex >= n-1 {
  352. startIndex = -1 // 设置为-1以便在下次循环中变为0
  353. }
  354. // 循环查找下一个未离职人员
  355. for count := 0; count < n; count++ {
  356. startIndex++
  357. if startIndex >= n {
  358. startIndex = 0
  359. }
  360. if !personArr[startIndex].IsResign {
  361. return startIndex
  362. }
  363. }
  364. return 0
  365. }
  366. // findPersonIndexByName 根据姓名查找人员索引
  367. // 参数:
  368. //
  369. // personArr - 人员数组
  370. // name - 要查找的姓名
  371. //
  372. // 返回值:
  373. //
  374. // 找到的索引,没找到返回0
  375. func findPersonIndexByName(personArr []PersonJson, name string) int {
  376. for i, v := range personArr {
  377. if v.Name == name {
  378. return i
  379. }
  380. }
  381. return 0
  382. }
  383. // fetchDeptAdmin 获取部门管理员信息
  384. // 参数:
  385. //
  386. // person - 人员信息(会被修改)
  387. func fetchDeptAdmin(person *PersonJson) {
  388. deptMap := JyMysql.SelectBySql(`SELECT c.name AS name, c.mail AS mail
  389. FROM entniche_department_user a
  390. INNER JOIN entniche_user_role b ON a.dept_id = ? AND a.user_id = b.user_id AND b.role_id != ""
  391. INNER JOIN entniche_user c ON a.user_id = c.id`, person.DeptId)
  392. if deptMap != nil && len(*deptMap) > 0 {
  393. person.DeptPersonName = gconv.String((*deptMap)[0]["name"])
  394. person.DeptPersonMail = gconv.String((*deptMap)[0]["mail"])
  395. }
  396. }
  397. // fetchSuperiorAdmin 获取上级部门管理员信息
  398. // 参数:
  399. //
  400. // person - 人员信息(会被修改)
  401. func fetchSuperiorAdmin(person *PersonJson) {
  402. superiorMap := JyMysql.SelectBySql(`SELECT c.*
  403. FROM entniche_department d
  404. INNER JOIN entniche_department_user a ON d.id = ? AND d.pid = a.dept_id
  405. INNER JOIN entniche_user_role b ON a.user_id = b.user_id AND b.role_id != ""
  406. INNER JOIN entniche_user c ON a.user_id = c.id`, person.DeptId)
  407. if superiorMap != nil && len(*superiorMap) > 0 {
  408. person.SuperiorDepthPersonName = gconv.String((*superiorMap)[0]["name"])
  409. person.SuperiorDepthPersonMail = gconv.String((*superiorMap)[0]["mail"])
  410. }
  411. }
  412. // FindNumber 获取编号
  413. // 参数:
  414. //
  415. // moudle - 模块标识
  416. //
  417. // 返回值:
  418. //
  419. // 4位序号字符串
  420. func FindNumber(moudle string) string {
  421. today := time.Now().Format("2006-01-02")
  422. yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
  423. key := fmt.Sprintf("%s_%s", today, moudle)
  424. yesterdayKey := fmt.Sprintf("%s_%s", yesterday, moudle)
  425. // 删除昨天的缓存
  426. if ok, _ := redis.Exists("newother", yesterdayKey); ok {
  427. redis.Del("newother", yesterdayKey)
  428. }
  429. // 自增获取序号
  430. count := redis.Incr("newother", key)
  431. log.Println("编号获取", moudle, fmt.Sprintf("%04d", count))
  432. return fmt.Sprintf("%04d", count)
  433. }
  434. // WorkMail 发送工作邮件
  435. // 参数:
  436. //
  437. // gmailAuth - Gmail认证信息
  438. // personMap - 人员信息
  439. // productStr - 产品字符串
  440. // personName1 - 处理人姓名
  441. // personName2 - 发起人姓名
  442. // createTimeStr - 创建时间字符串
  443. // acceptance_no - 受理单编号
  444. // phone - 联系电话
  445. // company - 公司名称
  446. func WorkMail(gmailAuth []*mail.GmailAuth, personMap PersonJson, productStr string, personName1, personName2, createTimeStr, acceptance_no, phone, company string) {
  447. orderType := fmt.Sprintf(`客户咨询线索(%s)`, productStr)
  448. title := fmt.Sprintf("%s通知", orderType)
  449. // 避免重复发送给同一个人
  450. if personName1 == personMap.DeptPersonName {
  451. personMap.DeptPersonMail = ""
  452. }
  453. if personName1 == personMap.SuperiorDepthPersonName {
  454. personMap.SuperiorDepthPersonMail = ""
  455. }
  456. // 构建邮件内容
  457. content := fmt.Sprintf(`%s,您好,“%s”于%s新增了1条"%s”(工单编号:%s)%s%s,请及时前往【剑鱼PC工作台-受理-工单管理-我负责的】进行工单处理。`,
  458. personName1, personName2, createTimeStr, orderType, acceptance_no,
  459. gconv.String(common.If(phone == "", "", fmt.Sprintf(`,客户联系方式为:%s`, phone))),
  460. gconv.String(common.If(company == "", "", fmt.Sprintf(`,公司名称:%s`, company))))
  461. toMail := personMap.Mail
  462. mailArr := []string{}
  463. // 添加抄送人
  464. if gconv.String(common.If(personMap.DeptPersonMail == "", "", personMap.DeptPersonMail)) != "" {
  465. mailArr = append(mailArr, gconv.String(common.If(personMap.DeptPersonMail == "", "", personMap.DeptPersonMail)))
  466. }
  467. if gconv.String(common.If(personMap.SuperiorDepthPersonMail == "", "", personMap.SuperiorDepthPersonMail)) != "" {
  468. mailArr = append(mailArr, gconv.String(common.If(personMap.SuperiorDepthPersonMail == "", "", personMap.SuperiorDepthPersonMail)))
  469. }
  470. // 设置抄送
  471. toCc := strings.Join(mailArr, ",")
  472. if len(mailArr) > 0 {
  473. toMail = fmt.Sprintf("%s|%s", toMail, toCc)
  474. }
  475. log.Println(toMail, title, content)
  476. if toMail == "" {
  477. return
  478. }
  479. // 尝试使用多个Gmail账号发送
  480. for k, v := range gmailAuth {
  481. fool := mail.GSendMail_q("剑鱼标讯", toMail, "", "", title, content, "", "", v)
  482. if fool {
  483. logx.Info(toMail, fmt.Sprintf("使用%s发送邮件成功", v.User))
  484. break
  485. }
  486. if k < len(gmailAuth)-1 {
  487. logx.Info(toMail, fmt.Sprintf("使用%s发送邮件失败!3s后使用其他邮箱尝试", v.User))
  488. } else {
  489. logx.Info(toMail, fmt.Sprintf("使用%s发送邮件失败!", v.User))
  490. }
  491. time.Sleep(time.Second * 3)
  492. }
  493. }
  494. // MarketingSave 营销线索保存
  495. // 参数:
  496. //
  497. // in - 受理单请求数据
  498. // positionId - 职位ID
  499. // product - 产品信息
  500. // dkPerson - 大客人员姓名
  501. func MarketingSave(in *biservice.AcceptanceReq, positionId int64, product, dkPerson string) {
  502. // 查询用户系统映射
  503. userMapping := JyMysql.FindOne("data_service.user_system", map[string]interface{}{"position_id": positionId, "status": 1}, "", "")
  504. if userMapping == nil || len(*userMapping) == 0 {
  505. log.Println("大客用户信息获取失败")
  506. return
  507. }
  508. log.Println(in)
  509. entId := gconv.Int64((*userMapping)["ent_id"])
  510. entUserId := gconv.Int64((*userMapping)["ent_user_id"])
  511. // 开启事务处理营销线索
  512. CrmService.ExecTx("线索进营销保存", func(tx *sql.Tx) bool {
  513. childMap := gconv.Map(in.ParamData)
  514. company := "" // 公司名称
  515. phone := "" // 联系电话
  516. demand := "" // 客户需求
  517. customerName := "" // 客户姓名
  518. channel := ""
  519. //渠道查询
  520. channelMap := WorkOrder.FindOne("dictionaries", map[string]interface{}{
  521. "id": in.Channel,
  522. }, "", "")
  523. if channelMap == nil || len(*channelMap) == 0 {
  524. log.Println(in.Channel, "渠道查询不到")
  525. } else {
  526. channel = gconv.String((*channelMap)["name"])
  527. }
  528. // 提取关键字段
  529. for k, v := range childMap {
  530. switch k {
  531. case "公司名称":
  532. company = gconv.String(v)
  533. case "联系方式num":
  534. phone = gconv.String(v)
  535. case "客户需求":
  536. demand = gconv.String(v)
  537. case "客户姓名":
  538. customerName = gconv.String(v)
  539. }
  540. }
  541. // 构建备注JSON
  542. remarkFields := []string{
  543. fmt.Sprintf("%s :%s", "提出时间", time.Now().Format(time.DateTime)),
  544. fmt.Sprintf("%s :%s", "销售线索来源", "主动咨询客服留资客户"),
  545. fmt.Sprintf("%s :%s", "姓名", common.If(customerName == "", phone, customerName)),
  546. fmt.Sprintf("%s :%s", "联系方式", phone),
  547. fmt.Sprintf("%s :%s", "公司名称", company),
  548. fmt.Sprintf("%s :%s", "咨询产品", product),
  549. fmt.Sprintf("%s :%s", "客户需求", demand),
  550. fmt.Sprintf("%s :%s", "备注", in.Remark),
  551. }
  552. filterStr := strings.Join(remarkFields, "\n")
  553. // 保存销售线索
  554. clueId := CrmService.InsertByTx(tx, "sale_clue", map[string]interface{}{
  555. "position_id": positionId, // 职位ID
  556. "ent_id": entId, // 企业ID
  557. "ent_user_id": entUserId, // 企业用户ID
  558. "employ_info_id": 0, // 雇佣信息ID
  559. "name": common.If(company == "", phone, company), // 名称
  560. "source_BAK": "", // 来源备份
  561. "summary": common.If(company == "", phone, company), // 摘要
  562. "is_close": 0, // 是否关闭
  563. "close_reason_classify": nil, // 关闭原因分类
  564. "close_reason_desc": nil, // 关闭原因描述
  565. "create_person": dkPerson, // 创建人
  566. "create_time": time.Now().Format(date.Date_Full_Layout), // 创建时间
  567. "channel": channel, // 渠道
  568. "source": "主动咨询客服留资客户", // 来源
  569. })
  570. // 保存任务
  571. taskId := CrmService.InsertByTx(tx, "task", map[string]interface{}{
  572. "ent_id": entId, // 企业ID
  573. "name": common.If(customerName == "", phone, customerName), // 任务名称
  574. "source": 1, // 来源类型
  575. "source_id": clueId, // 来源ID
  576. "create_way": 2, // 创建方式
  577. "status": 2, // 状态
  578. "create_time": time.Now().Format(date.Date_Full_Layout), // 创建时间
  579. "join_task_vehicle": 0, // 是否加入任务车辆
  580. "remark": filterStr, // 备注
  581. })
  582. if taskId <= 0 {
  583. return false
  584. }
  585. // 保存任务划转记录
  586. CrmService.InsertByTx(tx, "task_transfer", map[string]interface{}{
  587. "task_id": taskId, // 任务ID
  588. "transfer_id": positionId, // 划转ID
  589. "responsible_id": positionId, // 负责人ID
  590. "is_transfer": 0, // 是否划转
  591. "create_time": time.Now().Format(date.Date_Full_Layout), // 创建时间
  592. })
  593. // 保存任务团队
  594. CrmService.InsertByTx(tx, "task_team", map[string]interface{}{
  595. "task_id": taskId, // 任务ID
  596. "position_id": positionId, // 职位ID
  597. "ent_user_id": entUserId, // 企业用户ID
  598. "name": dkPerson, // 姓名
  599. "role": 1, // 角色
  600. "create_time": time.Now().Format(date.Date_Full_Layout), // 创建时间
  601. })
  602. return true
  603. })
  604. return
  605. }