areaStruct.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gogf/gf/v2/frame/g"
  6. "github.com/gogf/gf/v2/os/gctx"
  7. "github.com/gogf/gf/v2/util/gconv"
  8. "jybxseo/internal/consts"
  9. )
  10. var (
  11. JyBxSeoAreaRoot *AreaRoot = &AreaRoot{}
  12. AreaLocationShowNameMap = map[int]string{
  13. 1: "华北",
  14. 2: "华中",
  15. 3: "东北",
  16. 4: "华中",
  17. 5: "华南",
  18. 6: "西南",
  19. 7: "西北",
  20. }
  21. )
  22. type (
  23. AreaRoot struct {
  24. areaCodeMap map[string]*AreaNode //所有节点平铺 key:code (部分城市有重复,请根据省份+GetChildNode code获取 ⚠️suzhou yulin yichun fuzhou taizhou)
  25. areaNameMap map[string]*AreaNode //所有节点平铺 key:name
  26. rootList []*AreaNode //根节点
  27. Location []*AreaLocation //区位
  28. areaCodeConfigMap map[string]*AreaIndexConfig
  29. }
  30. AreaNode struct {
  31. Name string `json:"name" doc:"名称"`
  32. Code string `json:"code" doc:"代码"`
  33. Href string `json:"href" doc:"地址"`
  34. PNode *AreaNode `json:"pNode" doc:"父节点代码"`
  35. Location int `json:"location" doc:"区位"`
  36. Type int `json:"type" doc:"1省份 2城市 3直辖市"`
  37. Child []*AreaNode `json:"child" doc:"子栏目"`
  38. }
  39. AreaLocation struct {
  40. Name string `json:"name" doc:"华北、华中、东北、华东、华南、西南、西北"`
  41. AreaList []*AreaNode `json:"areaList" doc:"地区列表"`
  42. }
  43. AreaIndexConfig struct {
  44. Hots []*AreaNode `json:"node"`
  45. AdLink string `json:"adLink"`
  46. FLinks []struct {
  47. Name string `json:"name"`
  48. Href string `json:"href"`
  49. } `json:"fLinks"`
  50. }
  51. )
  52. func init() {
  53. //JyBxSeoAreaRoot.LoadAreasFromConfig(gctx.New())
  54. JyBxSeoAreaRoot.LoadAreasFromDB(gctx.New())
  55. }
  56. func (aRoot *AreaRoot) LoadAreasFromDB(ctx context.Context) {
  57. areaCodeMap, areaNameMap := map[string]*AreaNode{}, map[string]*AreaNode{}
  58. var rootArr []*AreaNode
  59. res, err := g.DB().Query(ctx, "SELECT * FROM seo_area_code where state=1 and pfcode!='' order by id asc")
  60. if err != nil {
  61. g.Log().Errorf(ctx, "加载地区异常%v", err)
  62. }
  63. for _, m := range res.List() {
  64. node := &AreaNode{
  65. Code: gconv.String(m["pfcode"]),
  66. Type: gconv.Int(m["class"]),
  67. }
  68. switch node.Type {
  69. case consts.AreaType, consts.CitySpecialType:
  70. node.Name = gconv.String(m["area"])
  71. node.Location = gconv.Int(m["location"])
  72. node.Href = fmt.Sprintf(consts.WebDomainFormat, node.Code)
  73. rootArr = append(rootArr, node)
  74. case consts.CityType:
  75. node.Name = gconv.String(m["city"])
  76. pNode := areaNameMap[gconv.String(m["area"])]
  77. node.PNode = pNode
  78. if pNode == nil {
  79. g.Log().Panic(ctx, "加载地区父级异常%s", node.Name)
  80. }
  81. node.Href = fmt.Sprintf("%s/%s/", pNode.Href, node.Code)
  82. pNode.Child = append(pNode.Child, node)
  83. }
  84. areaCodeMap[node.Code] = node
  85. areaNameMap[node.Name] = node
  86. }
  87. //加载区位
  88. for _, m := range g.Cfg("global").MustGet(context.Background(), "areaLocation").Maps() {
  89. tLocation := &AreaLocation{
  90. Name: gconv.String(m["name"]),
  91. AreaList: nil,
  92. }
  93. for _, areaCode := range gconv.Strings(m["values"]) {
  94. if node := areaCodeMap[areaCode]; node != nil {
  95. tLocation.AreaList = append(tLocation.AreaList, node)
  96. }
  97. }
  98. aRoot.Location = append(aRoot.Location, tLocation)
  99. }
  100. // 加载区位
  101. var location []*AreaLocation
  102. locationMap := map[int][]*AreaNode{}
  103. for _, node := range rootArr {
  104. locationMap[node.Location] = append(locationMap[node.Location], node)
  105. }
  106. for i := 1; i <= 7; i++ {
  107. location = append(location, &AreaLocation{
  108. Name: AreaLocationShowNameMap[i],
  109. AreaList: locationMap[i],
  110. })
  111. }
  112. // 加载首页配置
  113. nameCfgMap := map[string]*struct {
  114. Hots []string `json:"hots"`
  115. AdLink string `json:"adLink"`
  116. FLinks []struct {
  117. Name string `json:"name"`
  118. Href string `json:"href"`
  119. } `json:"fLinks"`
  120. }{}
  121. aRoot.areaCodeConfigMap = map[string]*AreaIndexConfig{}
  122. if err := g.Cfg("global").MustGet(context.Background(), "areaIndexConfig").Structs(&nameCfgMap); err == nil {
  123. for name, val := range nameCfgMap {
  124. if node := areaNameMap[name]; node != nil {
  125. cfg := &AreaIndexConfig{
  126. FLinks: val.FLinks,
  127. AdLink: val.AdLink,
  128. }
  129. for _, cityCode := range val.Hots {
  130. if city := node.GetChildNode(cityCode); city != nil {
  131. cfg.Hots = append(cfg.Hots, city)
  132. }
  133. }
  134. aRoot.areaCodeConfigMap[node.Code] = cfg
  135. }
  136. }
  137. }
  138. aRoot.areaCodeMap = areaCodeMap
  139. aRoot.areaNameMap = areaNameMap
  140. aRoot.rootList = rootArr
  141. aRoot.Location = location
  142. }
  143. // LoadAreasFrom 加载地区表示
  144. func (aRoot *AreaRoot) LoadAreasFromConfig(ctx context.Context) {
  145. areaCodeMap, areaNameMap := map[string]*AreaNode{}, map[string]*AreaNode{}
  146. var rootArr []*AreaNode
  147. for _, m := range g.Cfg("global").MustGet(context.Background(), "allAreaTree").Maps() {
  148. root := &AreaNode{
  149. Name: gconv.String(m["name"]),
  150. Code: gconv.String(m["code"]),
  151. }
  152. root.Href = fmt.Sprintf(consts.WebDomainFormat, root.Code)
  153. if gconv.Bool(m["special"]) {
  154. root.Type = consts.CitySpecialType
  155. } else {
  156. root.Type = consts.AreaType
  157. }
  158. for _, n := range gconv.Maps(m["child"]) {
  159. node := &AreaNode{
  160. Name: gconv.String(n["name"]),
  161. Code: gconv.String(n["code"]),
  162. Type: consts.CityType,
  163. PNode: root,
  164. }
  165. node.Href = fmt.Sprintf("%s/%s/", root.Href, node.Code)
  166. root.Child = append(root.Child, node)
  167. areaCodeMap[node.Code] = node
  168. areaNameMap[node.Name] = node
  169. }
  170. areaCodeMap[root.Code] = root
  171. areaNameMap[root.Name] = root
  172. rootArr = append(rootArr, root)
  173. }
  174. //加载区位
  175. for _, m := range g.Cfg("global").MustGet(context.Background(), "areaLocation").Maps() {
  176. tLocation := &AreaLocation{
  177. Name: gconv.String(m["name"]),
  178. AreaList: nil,
  179. }
  180. for _, areaCode := range gconv.Strings(m["values"]) {
  181. if node := areaCodeMap[areaCode]; node != nil {
  182. tLocation.AreaList = append(tLocation.AreaList, node)
  183. }
  184. }
  185. aRoot.Location = append(aRoot.Location, tLocation)
  186. }
  187. // 加载首页配置
  188. nameCfgMap := map[string]*struct {
  189. Hots []string `json:"hots"`
  190. AdLink string `json:"adLink"`
  191. FLinks []struct {
  192. Name string `json:"name"`
  193. Href string `json:"href"`
  194. } `json:"fLinks"`
  195. }{}
  196. aRoot.areaCodeConfigMap = map[string]*AreaIndexConfig{}
  197. if err := g.Cfg("global").MustGet(context.Background(), "areaIndexConfig").Structs(&nameCfgMap); err == nil {
  198. for name, val := range nameCfgMap {
  199. if node := areaNameMap[name]; node != nil {
  200. cfg := &AreaIndexConfig{
  201. FLinks: val.FLinks,
  202. AdLink: val.AdLink,
  203. }
  204. for _, cityCode := range val.Hots {
  205. if city := node.GetChildNode(cityCode); city != nil {
  206. cfg.Hots = append(cfg.Hots, city)
  207. }
  208. }
  209. aRoot.areaCodeConfigMap[node.Code] = cfg
  210. }
  211. }
  212. }
  213. aRoot.areaCodeMap = areaCodeMap
  214. aRoot.areaNameMap = areaNameMap
  215. aRoot.rootList = rootArr
  216. }
  217. // GetData 获取地区数据
  218. func (aRoot *AreaRoot) GetData(ctx context.Context, maxTotal int, query *SeoBiddingQuery) []map[string]interface{} {
  219. var sql string
  220. var values []interface{}
  221. if query.district != "" {
  222. sql += " AND b.district=? "
  223. values = append(values, query.district)
  224. } else if query.city != "" {
  225. sql += " AND b.city=? "
  226. values = append(values, query.city)
  227. } else if query.area != "" {
  228. sql += " AND b.area=? "
  229. values = append(values, query.area)
  230. }
  231. if query.topClass != "" {
  232. sql += " AND b.class1=? "
  233. values = append(values, query.topClass)
  234. }
  235. if query.status > 0 {
  236. sql += " AND b.status=? "
  237. values = append(values, query.status)
  238. }
  239. values = append(values, maxTotal)
  240. queryRes, err := g.DB().Query(ctx, fmt.Sprintf(`SELECT b.bid_id,b.seo_id
  241. FROM %s b
  242. WHERE 1=1 %s
  243. ORDER BY b.publish_time DESC,b.seo_id DESC
  244. LIMIT 0,?`, consts.TableName, sql), values...)
  245. if err != nil || queryRes.IsEmpty() {
  246. return nil
  247. }
  248. return FillingBiddingBaseFields(ctx, queryRes.List())
  249. }
  250. func (an *AreaNode) GetChildNode(code string) *AreaNode {
  251. if len(an.Child) == 0 {
  252. return nil
  253. }
  254. for _, node := range an.Child {
  255. if node.Code == code {
  256. return node
  257. }
  258. }
  259. return nil
  260. }
  261. // GetNodeByCode 根据code (部分城市有重复,请根据省份+GetChildNode code获取 ⚠️suzhou yulin yichun fuzhou taizhou)
  262. func (aRoot *AreaRoot) GetNodeByCode(code string) *AreaNode {
  263. return aRoot.areaCodeMap[code]
  264. }
  265. // GetNodeByName 根据省份名字获取node
  266. func (aRoot *AreaRoot) GetNodeByName(name string) *AreaNode {
  267. return aRoot.areaNameMap[name]
  268. }
  269. // GetAllRootNodes 获取全部根地区节点
  270. func (aRoot *AreaRoot) GetAllRootNodes() []*AreaNode {
  271. return aRoot.rootList
  272. }
  273. // GetAllLocation 获取所有区位
  274. func (aRoot *AreaRoot) GetAllLocation() []*AreaLocation {
  275. return aRoot.Location
  276. }
  277. // GetIndexConfigByCode 获取站点配置
  278. func (aRoot *AreaRoot) GetIndexConfigByCode(code string) *AreaIndexConfig {
  279. return aRoot.areaCodeConfigMap[code]
  280. }
  281. // GetSortLocation 获取关联区位信息
  282. // 规则:按现有的华东华中华南等分类,显示当前省份所在分类的其他省份,再显示下个地区分类的全部省份;以此类推循环;
  283. func (aRoot *AreaRoot) GetSortLocation(code string, num int) (rData []*AreaNode) {
  284. var isFind int = -1
  285. var findTimes int = 0
  286. findStart:
  287. for _, location := range aRoot.Location {
  288. if isFind < 0 {
  289. for _, node := range location.AreaList {
  290. if node.Code == code {
  291. isFind = 0
  292. break
  293. }
  294. }
  295. }
  296. if isFind >= 0 {
  297. for _, node := range location.AreaList {
  298. if node.Code != code {
  299. rData = append(rData, node)
  300. }
  301. }
  302. isFind++
  303. }
  304. if isFind >= 2 {
  305. return
  306. }
  307. }
  308. if findTimes < 2 {
  309. findTimes++
  310. goto findStart
  311. }
  312. return
  313. }