customerRule.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. package client
  2. import (
  3. "cmplatform/util"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "os"
  8. "regexp"
  9. "strings"
  10. "time"
  11. "app.yhyue.com/moapp/jybase/common"
  12. "app.yhyue.com/moapp/jybase/encrypt"
  13. "app.yhyue.com/moapp/jybase/go-xweb/xweb"
  14. "app.yhyue.com/moapp/jybase/log"
  15. "app.yhyue.com/moapp/jybase/mongodb"
  16. "github.com/antonmedv/expr"
  17. "github.com/lauyoume/gopinyin"
  18. "go.mongodb.org/mongo-driver/bson"
  19. "go.uber.org/zap"
  20. )
  21. type CustomerRule struct {
  22. *xweb.Action
  23. cuserRuleCreate xweb.Mapper `xweb:"/customerRule/cuser/rule/create"` //新建规则
  24. ruleImport xweb.Mapper `xweb:"/customerRule/rule/import"` //导入关键词 导入文件excel
  25. productData xweb.Mapper `xweb:"/customerRule/cuser/produce"` //生成预览数据
  26. demoData xweb.Mapper `xweb:"/customerRule/rule/preview"` //预览数据
  27. dataTest xweb.Mapper `xweb:"/customerRule/rule/dataTest/(.*)"` //规则测试
  28. downloadRule xweb.Mapper `xweb:"/customerRule/rule/downloadrule"` //下载规则
  29. }
  30. var (
  31. replaceField_detail = map[string]bool{`"title"`: true, `"projectname.pname"`: true}
  32. reg_detail = regexp.MustCompile("\"fields\":\\[([^]]*detail[^]]*)\\]")
  33. reg_single = regexp.MustCompile("\"query\":\"[^\"{:]\"")
  34. )
  35. func (c *CustomerRule) CuserRuleCreate() {
  36. defer common.Catch()
  37. ids := strings.Split(c.GetString("ids"), ",")
  38. if c.Method() == "POST" {
  39. user := c.GetSession("user").(map[string]interface{})
  40. data := util.GetPostForm(c.Request)
  41. o_rules := []map[string]interface{}{}
  42. o_rulesStr := data["o_rules"].(string)
  43. json.Unmarshal([]byte(o_rulesStr), &o_rules)
  44. data["o_rules"] = o_rules
  45. id := common.ObjToString(data["id"])
  46. delete(data, "id")
  47. delete(data, "ids")
  48. if common.IntAll(data["i_esquerytype"]) == 1 { //自动生成es
  49. esStr := util.Utiltags(data, id)
  50. data["s_esquery"] = esStr
  51. data["s_esquery_search"] = filter(esStr)
  52. }
  53. i_createtime := time.Now().Unix()
  54. data["i_updatetime"] = i_createtime
  55. data["s_updateuser"] = user["name"]
  56. var rep = false
  57. if id == "" { //新建
  58. data["s_userid"] = ids[1]
  59. data["s_departid"] = ids[0]
  60. data["i_createtime"] = i_createtime
  61. data["s_createuser"] = user["name"]
  62. s_namekey := gopinyin.Convert(common.ObjToString(data["s_name"]), false)
  63. data["s_namekey"] = s_namekey
  64. data["b_delete"] = false
  65. data["s_dataid"] = encrypt.SE.EncodeString(fmt.Sprintf("%v", i_createtime) + s_namekey + ids[0])
  66. id = util.Mgo.Save("cuserdepartrule", data)
  67. if id != "" {
  68. rep = true
  69. } else {
  70. rep = false
  71. }
  72. } else {
  73. query := bson.M{
  74. "_id": mongodb.StringTOBsonId(id),
  75. }
  76. rep = util.Mgo.Update("cuserdepartrule", query, bson.M{"$set": data}, false, false)
  77. }
  78. c.ServeJson(map[string]interface{}{
  79. "id": id,
  80. "rep": rep,
  81. "s_esquery": data["s_esquery"],
  82. "s_dataid": data["s_dataid"],
  83. })
  84. } else {
  85. c.T["did"] = ids[0] //部门id
  86. c.T["cid"] = ids[1] //客户id
  87. c.T["ids"] = c.GetString("ids")
  88. c.T["province"] = util.Province
  89. c.T["city"] = util.ProvinceCitys
  90. c.T["district"] = util.CityDistricts
  91. c.T["topTypeArr"] = util.TopTypeArr
  92. c.T["subTypeArr"] = util.SubTypeArr
  93. c.T["matchTypeMap"] = util.MatchTypeMap
  94. c.T["matchTypeMap2"] = util.MatchTypeMap2
  95. c.T["existField"] = util.ExistFiled
  96. c.T["buyerClass"] = util.BuyerClass
  97. c.T["buyerClassMap"] = util.BuyerClassMap
  98. c.T["scopeClass"] = util.ScopeClassMap
  99. c.T["siteArr"] = util.SiteArr
  100. /*userId := ids[1]
  101. cuser, _ := util.Mgo.FindById("cuser", userId, `{"s_appid":1}`)
  102. appid := common.ObjToString((*cuser)["s_appid"])
  103. user, _ := MgoCus.FindOneByField("user", map[string]interface{}{"appid": appid}, `{"plan":1}`)
  104. _plan := (*user)["plan"]
  105. if _plan != nil {
  106. plan := _plan.(map[string]interface{})
  107. fieldstype := common.ObjToString(plan["name"])
  108. if strings.Contains(fieldstype, "B") || strings.Contains(fieldstype, "D") {
  109. c.T["i_extfieldstype"] = 2
  110. } else {
  111. c.T["i_extfieldstype"] = 1
  112. }
  113. }*/
  114. c.Render("client/cuser_rule_create.html", &c.T)
  115. }
  116. }
  117. func filter(sql string) string {
  118. if !checkSingleWord(sql) {
  119. replace_map := checkDetail(sql)
  120. for k, v := range replace_map {
  121. // sql = regexp.MustCompile(k).ReplaceAllString(sql, v)
  122. sql = strings.ReplaceAll(sql, k, v)
  123. }
  124. }
  125. return sql
  126. }
  127. // 匹配包含detail的组
  128. func checkDetail(sql string) (arrMap map[string]string) {
  129. arrMap = map[string]string{}
  130. res := reg_detail.FindAllStringSubmatch(sql, -1)
  131. for _, v := range res {
  132. if len(v) == 2 {
  133. if v[1] != makeReplace(v[1]) {
  134. arrMap[v[1]] = makeReplace(v[1])
  135. }
  136. }
  137. }
  138. return
  139. }
  140. // 校验是否有单字
  141. func checkSingleWord(sql string) bool {
  142. return len(reg_single.FindStringSubmatch(sql)) > 0
  143. }
  144. // 计算每组字段的替换值
  145. func makeReplace(s_match string) (s_replace string) {
  146. arr := []string{}
  147. for _, v := range strings.Split(s_match, ",") {
  148. if !replaceField_detail[v] {
  149. arr = append(arr, v)
  150. }
  151. }
  152. return strings.Join(arr, ",")
  153. }
  154. // 导入关键词
  155. func (r *CustomerRule) RuleImport() {
  156. defer common.Catch()
  157. if r.Method() == "POST" {
  158. mf, _, err := r.GetFile("xlsx")
  159. if err == nil {
  160. binary, err := io.ReadAll(mf)
  161. if err == nil {
  162. rdata, err := util.Parsxlsx(binary)
  163. if err == nil {
  164. //id, rep := updateDbXf("", rdata)
  165. //common.Debug("import data:", rdata)
  166. r.ServeJson(map[string]interface{}{
  167. "rdata": rdata,
  168. "id": "",
  169. "rep": true,
  170. })
  171. return
  172. }
  173. }
  174. }
  175. r.ServeJson(map[string]interface{}{
  176. "rep": false,
  177. })
  178. }
  179. }
  180. // 生成预览数据
  181. func (c *CustomerRule) ProductData() {
  182. defer common.Catch()
  183. if c.Method() == "POST" {
  184. rep := false
  185. id := c.GetString("id")
  186. dataType := c.GetString("dataType")
  187. user := c.GetSession("user").(map[string]interface{})
  188. userId := common.ObjToString(user["id"])
  189. tag, ok := util.Mgo.FindById("cuserdepartrule", id, `{}`)
  190. if !ok {
  191. c.ServeJson(map[string]interface{}{
  192. "rep": false,
  193. "msg": "规则获取失败",
  194. })
  195. return
  196. }
  197. s_esquery := common.ObjToString((*tag)["s_esquery"])
  198. if util.IsNewSql != 0 {
  199. s_esquery = common.ObjToString((*tag)["s_esquery_search"])
  200. }
  201. s_startTime := common.IntAll((*tag)["i_starttime"])
  202. s_endTime := common.IntAll((*tag)["i_endtime"])
  203. totalCount := 0
  204. multiMatchcount := strings.Count(s_esquery, "multi_match")
  205. termsCount := strings.Count(s_esquery, "terms")
  206. rangeCount := strings.Count(s_esquery, "range")
  207. if multiMatchcount != -1 {
  208. totalCount += multiMatchcount
  209. }
  210. if termsCount != -1 {
  211. totalCount += termsCount
  212. }
  213. if rangeCount != -1 {
  214. totalCount += rangeCount
  215. }
  216. log.Debug("multi_match", zap.Int("multiMatchcount", multiMatchcount), zap.String("s_esquery", s_esquery))
  217. if totalCount > 1000 && (s_startTime == 0 || s_endTime == 0) {
  218. c.ServeJson(map[string]interface{}{
  219. "rep": false,
  220. "msg": "查询过多,请限制开始时间及结束时间",
  221. })
  222. return
  223. }
  224. if totalCount > 8000 {
  225. c.ServeJson(map[string]interface{}{
  226. "rep": false,
  227. "msg": "查询过多,无法执行",
  228. })
  229. return
  230. }
  231. // 其他的分隔
  232. // 1000<=总个数<4000,将时间(publishtime)按照每3个月进行分割,然后查询到的数据量进行求和。
  233. // 4000<=总个数<8000,将时间(publishtime)按照每1个月进行分割,然后查询到的数据量进行求和
  234. var err error
  235. var count int64
  236. var dataTypes string
  237. // var n int
  238. // 小于1000的直接查
  239. // if totalCount < 1000 {
  240. err, dataTypes, count = util.UtilEsFind1(*tag, dataType, userId)
  241. // } else {
  242. // if totalCount >= 1000 && totalCount < 4000 {
  243. // n = 3
  244. // }
  245. // if totalCount >= 4000 && totalCount < 8000 {
  246. // n = 1
  247. // }
  248. // err, count = UtilEsFind2(*tag, n)
  249. // }
  250. var msg string
  251. if err == nil {
  252. rep = true
  253. msg = "数据生成成功"
  254. } else {
  255. rep = false
  256. msg = "数据生成失败,请稍后再试"
  257. if err.Error() == "请设置开始结束时间" {
  258. msg = "请设置开始结束时间"
  259. }
  260. }
  261. c.ServeJson(map[string]interface{}{
  262. "rep": rep,
  263. "count": count,
  264. "msg": msg,
  265. "dataType": dataTypes,
  266. })
  267. }
  268. }
  269. func (r *CustomerRule) DemoData() {
  270. defer common.Catch()
  271. if r.Method() == "POST" {
  272. sDataid := r.GetString("s_dataid")
  273. start, _ := r.GetInt("start")
  274. limit, _ := r.GetInt("length")
  275. draw, _ := r.GetInt("draw")
  276. dataType := r.GetString("dataType")
  277. index := util.InterimIndex
  278. if dataType != "1" {
  279. index = util.TotalIndex
  280. }
  281. query := bson.M{
  282. "s_dataid": sDataid,
  283. "esIndex": index,
  284. }
  285. data, _ := util.Mgo.Find("tagsdata", query, `{"publishtime":-1}`, nil, false, int(start), int(limit))
  286. count := util.Mgo.Count("tagsdata", query)
  287. for _, v := range *data {
  288. if v["budget"] != nil {
  289. v["budget"] = common.Float64All(fmt.Sprintf("%f", common.Float64All(v["budget"])/10000))
  290. }
  291. if v["bidamount"] != nil {
  292. v["bidamount"] = common.Float64All(fmt.Sprintf("%f", common.Float64All(v["bidamount"])/10000))
  293. }
  294. }
  295. r.ServeJson(map[string]interface{}{
  296. "data": data,
  297. "draw": draw,
  298. "recordsFiltered": count,
  299. "recordsTotal": count,
  300. })
  301. }
  302. }
  303. func (this *CustomerRule) DataTest(id string) {
  304. //获取数据
  305. title := this.GetString("title")
  306. detail := this.GetString("detail")
  307. exactRule, exactResult := "", false
  308. if title == "" && detail == "" {
  309. this.ServeJson(map[string]interface{}{
  310. "status": false,
  311. "data": "",
  312. "message": "标题和正文至少要有一个",
  313. "exactResult": exactResult,
  314. "exactRule": exactRule,
  315. })
  316. return
  317. }
  318. article := map[string]interface{}{
  319. "title": title,
  320. "detail": detail,
  321. }
  322. log.Debug("测试数据是否匹配开始...")
  323. //加载一个客户
  324. customer, _ := util.Mgo.Find("cuserdepartrule", map[string]interface{}{"_id": mongodb.StringTOBsonId(id)}, nil, nil, false, -1, -1)
  325. if len(*customer) == 1 {
  326. c := (*customer)[0]
  327. s_globaladdkey := common.ObjToString(c["s_globaladdkey"])
  328. s_globaladdkeymatch := common.ObjToString(c["s_globaladdkeymatch"])
  329. s_globalnotkey := common.ObjToString(c["s_globalnotkey"])
  330. s_globalnotkeymatch := common.ObjToString(c["s_globalnotkeymatch"])
  331. s_globalclearkey := common.ObjToString(c["s_globalclearkey"])
  332. s_globalclearkeymatch := common.ObjToString(c["s_globalclearkeymatch"])
  333. exactRule = common.ObjToString(c["s_exactRule"])
  334. //清理词匹配方式
  335. cwmArr := []string{}
  336. for _, mv := range strings.Split(s_globalclearkeymatch, ",") {
  337. if field := common.ObjToString(MatchType[mv]); field != "" {
  338. cwmArr = append(cwmArr, field)
  339. }
  340. }
  341. //清理词正则
  342. cwkArr := []*regexp.Regexp{}
  343. for _, kv := range strings.Split(s_globalclearkey, ",") {
  344. if LetterCase.MatchString(kv) { //字母转大写
  345. kv = strings.ToUpper(kv)
  346. }
  347. reg := regexp.MustCompile(kv)
  348. cwkArr = append(cwkArr, reg)
  349. }
  350. //清理清理词
  351. for _, cwm := range cwmArr {
  352. if text := common.ObjToString(article[cwm]); text != "" {
  353. for _, gcw_reg := range cwkArr {
  354. text = gcw_reg.ReplaceAllString(text, "")
  355. }
  356. article[cwm] = text
  357. }
  358. }
  359. o_rule, ok := c["o_rules"].([]interface{})
  360. if !ok {
  361. o_rule = []interface{}{}
  362. }
  363. o_rules := common.ObjArrToMapArr(o_rule)
  364. matchKey := ""
  365. if s_globaladdkey != "" {
  366. gKey := TestMactchKeys(s_globaladdkeymatch, s_globaladdkey, article)
  367. if gKey == "" {
  368. this.ServeJson(map[string]interface{}{
  369. "status": true,
  370. "data": map[string]interface{}{
  371. "result": false,
  372. "info": "全局附加词没有匹配成功",
  373. "data": s_globaladdkey,
  374. },
  375. "message": "测试成功",
  376. "exactResult": exactResult,
  377. "exactRule": exactRule,
  378. })
  379. return
  380. } else {
  381. matchKey = gKey
  382. }
  383. }
  384. if s_globalnotkey != "" {
  385. gNKey := TestMactchKeys(s_globalnotkeymatch, s_globalnotkey, article)
  386. if gNKey != "" {
  387. this.ServeJson(map[string]interface{}{
  388. "status": true,
  389. "data": map[string]interface{}{
  390. "result": false,
  391. "info": "被全局排除词排除",
  392. "data": gNKey,
  393. },
  394. "message": "测试成功",
  395. "exactResult": exactResult,
  396. "exactRule": exactRule,
  397. })
  398. return
  399. }
  400. }
  401. var resultList []map[string]interface{}
  402. for _, v := range o_rules {
  403. matchKey = ""
  404. key := common.ObjToString(v["s_matchkey"])
  405. keymatch := common.ObjToString(v["s_keymatch"])
  406. addkey := common.ObjToString(v["s_addkey"])
  407. addkeymatch := common.ObjToString(v["s_addkeymatch"])
  408. notkey := common.ObjToString(v["s_notkey"])
  409. notkeymatch := common.ObjToString(v["s_notkeymatch"])
  410. s_group := common.ObjToString(v["s_group"])
  411. var tempData = map[string]interface{}{
  412. "key": key,
  413. "keymatch": keymatch,
  414. "addkey": addkey,
  415. "addkeymatch": addkeymatch,
  416. "notkey": notkey,
  417. "notkeymatch": notkeymatch,
  418. "s_group": s_group,
  419. }
  420. if notkey != "" {
  421. nKey := TestMactchKeys(notkeymatch, notkey, article)
  422. if nKey != "" {
  423. tempData["status"] = false
  424. tempData["info"] = "排除词排除"
  425. tempData["data"] = nKey
  426. resultList = append(resultList, tempData)
  427. continue
  428. }
  429. }
  430. if key != "" {
  431. sKey := TestMactchKeys(keymatch, key, article)
  432. aKey := ""
  433. if addkey != "" {
  434. aKey = TestMactchKeys(addkeymatch, addkey, article)
  435. if aKey != "" && sKey != "" {
  436. matchKey = aKey + "," + sKey
  437. tempData["status"] = true
  438. tempData["info"] = "匹配成功"
  439. tempData["data"] = matchKey
  440. resultList = append(resultList, tempData)
  441. } else if aKey == "" {
  442. tempData["status"] = false
  443. tempData["info"] = "附加词匹配失败"
  444. tempData["data"] = ""
  445. resultList = append(resultList, tempData)
  446. } else if sKey == "" {
  447. tempData["status"] = false
  448. tempData["info"] = "关键词匹配失败"
  449. tempData["data"] = ""
  450. resultList = append(resultList, tempData)
  451. }
  452. } else {
  453. if sKey != "" {
  454. matchKey = sKey
  455. tempData["status"] = true
  456. tempData["info"] = "匹配成功"
  457. tempData["data"] = matchKey
  458. resultList = append(resultList, tempData)
  459. } else {
  460. matchKey = sKey
  461. tempData["status"] = false
  462. tempData["info"] = "关键词匹配失败"
  463. tempData["data"] = matchKey
  464. resultList = append(resultList, tempData)
  465. }
  466. }
  467. }
  468. }
  469. if resultList == nil {
  470. this.ServeJson(map[string]interface{}{
  471. "status": true,
  472. "data": map[string]interface{}{
  473. "result": true,
  474. "info": "全局附加词匹配成功" + matchKey,
  475. "data": "",
  476. },
  477. "message": "测试成功",
  478. "exactResult": exactResult,
  479. "exactRule": exactRule,
  480. })
  481. return
  482. } else {
  483. nameArr := []string{}
  484. data, ok := util.Mgo.Find("groups", map[string]interface{}{"ruleId": id}, nil, nil, false, -1, -1)
  485. if ok && data != nil && len(*data) > 0 {
  486. for _, v := range *data {
  487. nameArr = append(nameArr, common.ObjToString(v["name"]))
  488. }
  489. }
  490. exactResult = exactMatch(exactRule, resultList, nameArr)
  491. this.ServeJson(map[string]interface{}{
  492. "status": true,
  493. "data": resultList,
  494. "message": "测试成功",
  495. "exactResult": exactResult,
  496. "exactRule": exactRule,
  497. })
  498. }
  499. return
  500. } else {
  501. this.ServeJson(map[string]interface{}{
  502. "status": true,
  503. "data": "",
  504. "message": "初始化客户信息失败",
  505. "exactResult": exactResult,
  506. "exactRule": exactRule,
  507. })
  508. return
  509. }
  510. log.Debug("测试数据是否匹配结束...")
  511. }
  512. func exactMatch(rule string, data []map[string]interface{}, nameArr []string) bool {
  513. realdata := map[string]float64{}
  514. for _, v := range nameArr {
  515. realdata["title_"+v] = 0
  516. realdata["content_"+v] = 0
  517. }
  518. mapping := map[string]string{
  519. " and ": " && ",
  520. " or ": " || ",
  521. " not ": " ! ",
  522. }
  523. for k, v := range mapping {
  524. rule = strings.ReplaceAll(rule, k, v)
  525. }
  526. //可以将编译后的表达式,存放在缓存中
  527. program, err := expr.Compile(rule, expr.Env(realdata))
  528. if err != nil {
  529. log.Error("表达式错误 ", zap.Error(err))
  530. return false
  531. }
  532. for _, v := range data {
  533. if v["status"].(bool) {
  534. keymatch := common.ObjToString(v["keymatch"])
  535. group := common.ObjToString(v["s_group"])
  536. markkey := strings.Split(common.ObjToString(v["markkey"]), ",")
  537. if group != "" {
  538. if strings.Contains(keymatch, "1") {
  539. realdata["title_"+group] = realdata["title_"+group] + float64(len(markkey))
  540. }
  541. if strings.Contains(keymatch, "2") {
  542. realdata["content_"+group] = realdata["content_"+group] + float64(len(markkey))
  543. }
  544. }
  545. }
  546. }
  547. log.Debug("匹配结果 ", zap.Any("realdata", realdata))
  548. output, err := expr.Run(program, realdata)
  549. if err != nil {
  550. log.Error("表达式执行错误 ", zap.Error(err))
  551. return false
  552. }
  553. return output.(bool)
  554. }
  555. func (this *CustomerRule) DownloadRule() {
  556. defer common.Catch()
  557. id := this.GetString("id")
  558. // 验证一下规则
  559. user, ok := this.GetSession("user").(map[string]interface{})
  560. if !ok {
  561. this.ServeJson("身份异常")
  562. return
  563. }
  564. uID := ""
  565. users, ok := util.Mgo.FindOne("cuser", map[string]interface{}{"s_name": user["name"], "b_delete": false})
  566. if users != nil && ok {
  567. uID = mongodb.BsonIdToSId((*users)["_id"])
  568. }
  569. if uID == "" {
  570. this.ServeJson("身份异常")
  571. return
  572. }
  573. count := util.Mgo.Count("cuserdepartrule", map[string]interface{}{"_id": mongodb.StringTOBsonId(id), "s_userid": uID, "b_delete": false})
  574. if count <= 0 {
  575. this.ServeJson("规则异常")
  576. return
  577. }
  578. path := util.ResponseXlsx_Rule(id)
  579. if path == "" {
  580. this.ServeJson("没有数据")
  581. } else {
  582. arr := strings.Split(path, "/")
  583. this.ResponseWriter.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", arr[len(arr)-1]))
  584. this.ServeFile(path)
  585. go func(path string) {
  586. time.Sleep(time.Minute * 3)
  587. os.Remove(path)
  588. }(path)
  589. }
  590. }