Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
黄成意
/
go_sku_server
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
3a6792ae
authored
Nov 03, 2025
by
hcy
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
并发问题
parent
32b298ac
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
288 additions
and
347 deletions
controller/sku_controller.go
model/prev_sku.go
service/service_ly.go
service/service_sample.go
service/service_spu.go
controller/sku_controller.go
View file @
3a6792ae
...
@@ -3,10 +3,13 @@ package controller
...
@@ -3,10 +3,13 @@ package controller
import
(
import
(
"context"
"context"
"encoding/json"
"encoding/json"
"fmt"
"github.com/tidwall/gjson"
"go_sku_server/pkg/common"
"go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/
logger
"
"go_sku_server/pkg/
mongo
"
"go_sku_server/service"
"go_sku_server/service"
"gopkg.in/mgo.v2/bson"
"sync"
"sync"
"time"
"time"
...
@@ -41,14 +44,11 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
...
@@ -41,14 +44,11 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 1. 提前提取所有请求参数(在主协程中,避免在子协程中访问 gin.Context)
// 1. 提前提取所有请求参数(在主协程中,避免在子协程中访问 gin.Context)
requestParams
:=
service
.
ExtractRequestParams
(
ctx
)
requestParams
:=
service
.
ExtractRequestParams
(
ctx
)
// 2. 创建带超时的 context,用于控制所有协程的生命周期
// 5秒超时后,所有子协程都会收到取消信号
ctxWithTimeout
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
defer
cancel
()
// 确保函数返回时取消所有协程,释放资源
//抽取自营 或者联营 goods_id
//抽取自营 或者联营 goods_id
zyService
:=
service
.
ZiyingService
{}
//实例化自营查询
zyService
:=
service
.
ZiyingService
{}
//实例化自营查询
lyService
:=
service
.
LyService
{}
//实例化联营查询
lyService
:=
service
.
LyService
{}
//实例化联营查询
SpuService
:=
service
.
SpuService
{}
var
goodsIdArr
[]
string
var
goodsIdArr
[]
string
if
GoodsIdStr
==
""
{
if
GoodsIdStr
==
""
{
goodsIdMap
:=
ctx
.
PostFormMap
(
"goods_id"
)
goodsIdMap
:=
ctx
.
PostFormMap
(
"goods_id"
)
...
@@ -63,11 +63,64 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
...
@@ -63,11 +63,64 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
return
nil
return
nil
}
}
//////////初始化公共变量 以及 批量查询///////////
zyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
lyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
for
_
,
goodsId
:=
range
goodsIdArr
{
if
len
(
goodsId
)
<
19
{
//自营
zyGoodsId
=
append
(
zyGoodsId
,
goodsId
)
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
}
}
//批量查询redis-sku信息
redisLySkuArr
:=
gredis
.
Hmget
(
"default_r"
,
"sku"
,
lyGoodsId
)
//批量查询归档的sku
preSkuIds
:=
make
([]
int64
,
0
)
for
_
,
goodsId
:=
range
goodsIdArr
{
if
redisLySkuArr
[
goodsId
]
==
""
{
preSkuIds
=
append
(
preSkuIds
,
gconv
.
Int64
(
goodsId
))
}
}
if
len
(
preSkuIds
)
>
0
{
var
prevSkuArr
[]
bson
.
M
prevSkuMongo
:=
mongo
.
Conn
(
"pre_sku"
)
query
:=
bson
.
M
{
"sku_id"
:
bson
.
M
{
"$in"
:
preSkuIds
,
},
}
err
:=
prevSkuMongo
.
DB
(
"ichunt"
)
.
C
(
"prev_sku"
)
.
Find
(
query
)
.
All
(
&
prevSkuArr
)
if
err
!=
nil
{
fmt
.
Println
(
"查询失败: %v"
,
err
)
}
for
_
,
preSkuOne
:=
range
prevSkuArr
{
jsonBytes
,
err
:=
json
.
Marshal
(
preSkuOne
)
if
err
!=
nil
{
continue
}
preSkuOneStr
:=
string
(
jsonBytes
)
skuId
:=
gjson
.
Get
(
preSkuOneStr
,
"sku_id"
)
.
String
()
redisLySkuArr
[
skuId
]
=
preSkuOneStr
}
}
//查询spu信息
redisLySpuArr
:=
SpuService
.
GetSpuList
(
redisLySkuArr
)
SpuService
.
SetInit
()
//设置查询公共变量
/////////////////多线程///////////////////////////
var
wg
sync
.
WaitGroup
var
wg
sync
.
WaitGroup
ch
:=
make
(
chan
sync
.
Map
,
50
)
//管道
ch
:=
make
(
chan
sync
.
Map
,
50
)
//管道
wgMax
:=
3
//线程数量最多多少
wgcount
:=
0
//当前线程数
zyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
temp
:=
make
(
map
[
string
]
interface
{})
//最后输出计算结果
lyGoodsId
:=
make
([]
string
,
0
,
goodsSliceCount
)
for
_
,
goodsId
:=
range
goodsIdArr
{
for
_
,
goodsId
:=
range
goodsIdArr
{
//if len(goodsIdArr) > 100 {
//if len(goodsIdArr) > 100 {
// common.Output(ctx, 1001, "查询型号ID不得超过100个", "")
// common.Output(ctx, 1001, "查询型号ID不得超过100个", "")
...
@@ -90,87 +143,49 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
...
@@ -90,87 +143,49 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
defer
wg
.
Done
()
zyService
.
ZyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
zyService
.
ZyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctx
WithTimeout
,
requestParams
,
idsToProcess
,
ch
)
}(
ctx
,
requestParams
,
idsToProcess
,
ch
)
zyGoodsId
=
zyGoodsId
[
:
0
]
zyGoodsId
=
zyGoodsId
[
:
0
]
}
}
}
else
{
//联营
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程:"
+
goodsId
)
if
len
(
lyGoodsId
)
>=
goodsSliceCount
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1002:"
)
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
//单个sku详情
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
if
_
,
ok
:=
redisLySkuArr
[
goodsId
];
!
ok
{
defer
wg
.
Done
()
temp
[
goodsId
]
=
false
lyService
.
LyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
continue
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
}
skuStr
:=
redisLySkuArr
[
goodsId
]
lyGoodsId
=
lyGoodsId
[
:
0
]
spuId
:=
gjson
.
Get
(
skuStr
,
"spu_id"
)
.
String
()
if
_
,
ok
:=
redisLySpuArr
[
spuId
];
!
ok
{
temp
[
goodsId
]
=
false
continue
}
}
}
}
if
len
(
zyGoodsId
)
>
0
{
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
common
.
PrintDebugHtml
(
ctx
,
"zy增加协程1003:"
)
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
skuStr
,
goodsId
,
spuStr
string
,
ch
chan
sync
.
Map
)
{
common
.
PrintDebugHtml
(
ctx
,
zyGoodsId
)
defer
wg
.
Done
()
wg
.
Add
(
1
)
//协程计数一
lyService
.
LyGoodsDetail
(
ctx
,
params
,
skuStr
,
goodsId
,
spuStr
,
ch
)
}(
ctx
,
requestParams
,
skuStr
,
goodsId
,
redisLySpuArr
[
spuId
],
ch
)
idsToProcess
:=
make
([]
string
,
len
(
zyGoodsId
)
)
wg
.
Add
(
1
)
copy
(
idsToProcess
,
zyGoodsId
)
wgcount
+=
1
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
if
wgcount
>=
wgMax
{
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
println
(
"线程数量:"
+
gconv
.
String
(
wgcount
))
defer
wg
.
Done
()
wg
.
Wait
()
// 等待所有登记的goroutine都结束
zyService
.
ZyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
wgcount
=
0
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
}
}
}
}
if
len
(
lyGoodsId
)
>
0
{
if
wgcount
>
0
{
common
.
PrintDebugHtml
(
ctx
,
"ly增加协程1004:"
)
//println("等待结束,现有运行线程数:" + gconv.String(wgcount))
common
.
PrintDebugHtml
(
ctx
,
lyGoodsId
)
//wg.Wait()
wg
.
Add
(
1
)
idsToProcess
:=
make
([]
string
,
len
(
lyGoodsId
))
copy
(
idsToProcess
,
lyGoodsId
)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go
func
(
ctx
context
.
Context
,
params
service
.
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
defer
wg
.
Done
()
lyService
.
LyGoodsDetail
(
ctx
,
params
,
goodsIds
,
ch
)
}(
ctxWithTimeout
,
requestParams
,
idsToProcess
,
ch
)
}
}
close
(
ch
)
// 开启一个协程,等待所有任务完成,然后关闭channel
// 使用 context 来控制这个等待协程的生命周期
go
func
()
{
// 创建一个 done channel 用于通知 wg.Wait() 完成
done
:=
make
(
chan
struct
{})
go
func
()
{
wg
.
Wait
()
close
(
done
)
}()
// 等待 wg.Wait() 完成或 context 取消
select
{
case
<-
done
:
// 所有协程都正常完成
close
(
ch
)
case
<-
ctxWithTimeout
.
Done
()
:
// context 超时,不再等待剩余协程
// 等待一小段时间让协程有机会退出
time
.
Sleep
(
300
*
time
.
Millisecond
)
close
(
ch
)
logger
.
Log
(
"等待协程完成超时,强制关闭channel"
,
"sku"
,
1
)
}
}()
//异步map最后转成map
//异步map最后转成map
temp
:=
make
(
map
[
string
]
interface
{})
for
{
for
{
select
{
select
{
case
GoodsRes
,
ok
:=
<-
ch
:
case
GoodsRes
,
ok
:=
<-
ch
:
...
@@ -182,36 +197,12 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
...
@@ -182,36 +197,12 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
temp
[
s
]
=
v
temp
[
s
]
=
v
return
true
return
true
})
})
case
<-
time
.
After
(
20
*
time
.
Second
)
:
case
<-
ctxWithTimeout
.
Done
()
:
println
(
"协程超时20秒"
)
// context 超时或被取消
return
temp
logger
.
Log
(
"协程整体处理超时,所有子协程已收到取消信号"
,
"sku"
,
1
)
// 继续从 channel 读取已经发送的数据,避免协程阻塞
// 等待 channel 被关闭(由上面的 wg.Wait() 协程关闭)
cleanupTimeout
:=
time
.
After
(
500
*
time
.
Millisecond
)
for
{
select
{
case
GoodsRes
,
ok
:=
<-
ch
:
if
!
ok
{
// channel 已关闭,所有协程都已退出
logger
.
Log
(
"channel已关闭,返回结果"
,
"sku"
,
1
)
return
temp
}
// 收集已经发送的数据
GoodsRes
.
Range
(
func
(
k
,
v
interface
{})
bool
{
s
,
_
:=
k
.
(
string
)
temp
[
s
]
=
v
return
true
})
case
<-
cleanupTimeout
:
// 清理超时,强制返回
logger
.
Log
(
"清理超时,强制返回"
,
"sku"
,
1
)
return
temp
}
}
}
}
}
}
}
}
func
Synchronization
(
ctx
*
gin
.
Context
)
{
func
Synchronization
(
ctx
*
gin
.
Context
)
{
...
...
model/prev_sku.go
View file @
3a6792ae
...
@@ -7,5 +7,5 @@ type PrevSku struct {
...
@@ -7,5 +7,5 @@ type PrevSku struct {
ID
bson
.
ObjectId
`bson:"_id"`
ID
bson
.
ObjectId
`bson:"_id"`
SkuId
int64
`bson:"sku_id"`
SkuId
int64
`bson:"sku_id"`
SpuId
int64
`bson:"spu_id"`
SpuId
int64
`bson:"spu_id"`
SupplierId
int
64
`bson:"supplier_id"`
SupplierId
int
32
`bson:"supplier_id"`
}
}
service/service_ly.go
View file @
3a6792ae
...
@@ -9,7 +9,6 @@ import (
...
@@ -9,7 +9,6 @@ import (
"go_sku_server/pkg/mongo"
"go_sku_server/pkg/mongo"
"go_sku_server/service/sorter"
"go_sku_server/service/sorter"
"sort"
"sort"
"strconv"
"sync"
"sync"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2"
...
@@ -37,14 +36,7 @@ type Power struct {
...
@@ -37,14 +36,7 @@ type Power struct {
联营数据详情
联营数据详情
使用 context.Context 控制协程生命周期,避免 gin.Context 在协程中的并发问题
使用 context.Context 控制协程生命周期,避免 gin.Context 在协程中的并发问题
*/
*/
func
(
ls
*
LyService
)
LyGoodsDetail
(
ctx
context
.
Context
,
params
RequestParams
,
goodsIds
[]
string
,
ch
chan
sync
.
Map
)
{
func
(
ls
*
LyService
)
LyGoodsDetail
(
ctx
context
.
Context
,
params
RequestParams
,
skuStr
,
goodsId
,
spuStr
string
,
ch
chan
sync
.
Map
)
{
// 检查 context 是否已取消(超时或主动取消)
select
{
case
<-
ctx
.
Done
()
:
logger
.
Log
(
"LyGoodsDetail: context已取消,直接返回"
,
"sku"
,
1
)
return
default
:
}
redisConn
:=
gredis
.
Conn
(
"search_r"
)
redisConn
:=
gredis
.
Conn
(
"search_r"
)
redisConnSpu
:=
gredis
.
Conn
(
"spu"
)
redisConnSpu
:=
gredis
.
Conn
(
"spu"
)
...
@@ -68,270 +60,219 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
...
@@ -68,270 +60,219 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//是否展示spu额外信息
//是否展示spu额外信息
showSpuExtra
:=
params
.
ShowSpuExtra
showSpuExtra
:=
params
.
ShowSpuExtra
//批量获取商品详情
skuArr
:=
gredis
.
Hmget
(
"default_r"
,
"sku"
,
goodsIds
)
//为了性能着想,这边也先去批量获取spu的信息
var
spuService
SpuService
spuList
:=
spuService
.
getSpuList
(
skuArr
)
GoodsRes
:=
sync
.
Map
{}
GoodsRes
:=
sync
.
Map
{}
for
goodsId
,
skuStr
:=
range
skuArr
{
// 在处理每个商品前检查 context 是否已取消
select
{
case
<-
ctx
.
Done
()
:
logger
.
Log
(
"LyGoodsDetail: 处理过程中context被取消"
,
"sku"
,
1
)
// 不发送不完整的数据,直接返回让协程尽快退出
return
default
:
}
//初始化有序map,拼接data数据,就是从redis取出初始数据
//初始化有序map,拼接data数据,就是从redis取出初始数据
sku
:=
model
.
InitSkuData
(
skuStr
)
sku
:=
model
.
InitSkuData
(
skuStr
)
var
spu
string
spu
:=
spuStr
if
skuStr
==
""
{
// 如果redis中找不到sku数据,尝试从prev_sku MongoDB中查找
skuId
,
err
:=
strconv
.
ParseInt
(
goodsId
,
10
,
64
)
if
err
!=
nil
{
GoodsRes
.
Store
(
goodsId
,
false
)
continue
}
var
prevSku
model
.
PrevSku
err
=
prevSkuMongo
.
DB
(
"ichunt"
)
.
C
(
"prev_sku"
)
.
Find
(
bson
.
M
{
"sku_id"
:
skuId
})
.
One
(
&
prevSku
)
if
err
!=
nil
{
// 如果在prev_sku中也找不到,则保持默认值
GoodsRes
.
Store
(
goodsId
,
false
)
continue
}
// 根据找到的spu_id去spu的redis中查找
sku
.
GoodsId
=
goodsId
spuIdStr
:=
strconv
.
FormatInt
(
prevSku
.
SpuId
,
10
)
//读取包装字段的缓存(分别是DGK,avnet,mro)
spuStr
,
_
:=
redis
.
String
(
redisConnSpu
.
Do
(
"HGET"
,
"spu"
,
spuIdStr
))
if
sku
.
SupplierId
==
7
||
sku
.
SupplierId
==
13
||
sku
.
SupplierId
==
1688
||
sku
.
SupplierId
==
17
{
if
spuStr
==
""
{
//sku_raw_map哪里写入(成意写的)
// 如果spu缓存也没有,保持默认值
packing
,
_
:=
redis
.
String
(
redisConnSpu
.
Do
(
"HGET"
,
"sku_raw_map"
,
goodsId
))
GoodsRes
.
Store
(
goodsId
,
false
)
sku
.
Packing
=
gjson
.
Get
(
packing
,
"pack"
)
.
String
()
continue
}
}
sku
=
ls
.
GetGoodsImages
(
sku
,
spu
)
sku
.
SupplierId
=
prevSku
.
SupplierId
sku
=
ls
.
GetPdf
(
sku
,
spu
)
sku
.
SpuId
=
spuIdStr
//用spuInfo补全信息
spu
=
spuStr
sku
=
ls
.
CombineSup
(
sku
,
spu
)
}
else
{
// 2023.11.20 DGK商品的包装若为“Tape & Reel (TR)”,则递增量=起订量
spu
=
spuList
[
sku
.
SpuId
]
if
sku
.
SupplierId
==
7
&&
sku
.
Packing
==
"Tape & Reel (TR)"
{
}
sku
.
Multiple
=
sku
.
Moq
}
//获取商品名称
//spuName和GoodsName不是一个东西,不能公用,因为订单系统也用到了goods_name这个字段
//而下单的时候,只能给spu型号才行
if
sku
.
GoodsName
!=
""
{
sku
.
GoodsName
=
gjson
.
Get
(
spu
,
"spu_name"
)
.
String
()
}
if
sku
.
GoodsName
==
""
{
sku
.
GoodsName
=
gjson
.
Get
(
spu
,
"spu_name"
)
.
String
()
}
sku
.
GoodsId
=
goodsId
//获取品牌名称
//读取包装字段的缓存(分别是DGK,avnet,mro)
brandId
:=
gjson
.
Get
(
spu
,
"brand_id"
)
.
Int
()
if
sku
.
SupplierId
==
7
||
sku
.
SupplierId
==
13
||
sku
.
SupplierId
==
1688
||
sku
.
SupplierId
==
17
{
brandName
,
_
:=
redis
.
String
(
redisConn
.
Do
(
"HGET"
,
"brand"
,
brandId
))
//sku_raw_map哪里写入(成意写的)
sku
.
BrandName
=
brandName
packing
,
_
:=
redis
.
String
(
redisConnSpu
.
Do
(
"HGET"
,
"sku_raw_map"
,
goodsId
))
sku
.
BrandId
=
brandId
sku
.
Packing
=
gjson
.
Get
(
packing
,
"pack"
)
.
String
()
}
//判断是否要取精简信息
sku
=
ls
.
GetGoodsImages
(
sku
,
spu
)
if
fast
!=
"1"
{
sku
=
ls
.
GetPdf
(
sku
,
spu
)
sku
=
ls
.
GetGoodsClass
(
sku
,
spu
)
//用spuInfo补全信息
//仅提供价格和库存
sku
=
ls
.
CombineSup
(
sku
,
spu
)
if
sku
.
GoodsName
!=
""
&&
brandId
!=
0
{
// 2023.11.20 DGK商品的包装若为“Tape & Reel (TR)”,则递增量=起订量
sku
.
ErpTax
=
ls
.
GetErpTax
(
sku
.
GoodsName
,
brandName
)
if
sku
.
SupplierId
==
7
&&
sku
.
Packing
==
"Tape & Reel (TR)"
{
sku
.
Multiple
=
sku
.
Moq
}
}
//获取商品名称
sku
.
SupplierName
=
ls
.
GetPoolSupplierName
(
sku
.
SupplierId
)
//spuName和GoodsName不是一个东西,不能公用,因为订单系统也用到了goods_name这个字段
if
showAttr
==
"1"
{
//而下单的时候,只能给spu型号才行
//获取属性
if
sku
.
GoodsName
!=
""
{
sku
.
Attrs
=
ls
.
GetSpuAttr
(
sku
.
SpuId
)
sku
.
GoodsName
=
gjson
.
Get
(
spu
,
"spu_name"
)
.
String
()
}
}
if
sku
.
GoodsName
==
""
{
if
sku
.
Attrs
==
nil
{
sku
.
GoodsName
=
gjson
.
Get
(
spu
,
"spu_name"
)
.
String
()
sku
.
Attrs
=
[]
interface
{}{}
}
}
}
//获取品牌名称
//获取在途库存信息
brandId
:=
gjson
.
Get
(
spu
,
"brand_id"
)
.
Int
()
if
showStockInfo
==
"1"
&&
sku
.
OldGoodsId
!=
0
{
brandName
,
_
:=
redis
.
String
(
redisConn
.
Do
(
"HGET"
,
"brand"
,
brandId
))
sku
.
StockInfo
=
ls
.
getStockInfo
(
sku
.
SupplierId
,
sku
.
OldGoodsId
)
sku
.
BrandName
=
brandName
}
sku
.
BrandId
=
brandId
//格式化为对象返回
if
sku
.
StockInfo
==
nil
{
//判断是否要取精简信息
type
StockInfoResult
struct
{
if
fast
!=
"1"
{
sku
=
ls
.
GetGoodsClass
(
sku
,
spu
)
//仅提供价格和库存
if
sku
.
GoodsName
!=
""
&&
brandId
!=
0
{
sku
.
ErpTax
=
ls
.
GetErpTax
(
sku
.
GoodsName
,
brandName
)
}
sku
.
SupplierName
=
ls
.
GetPoolSupplierName
(
sku
.
SupplierId
)
if
showAttr
==
"1"
{
//获取属性
sku
.
Attrs
=
ls
.
GetSpuAttr
(
sku
.
SpuId
)
}
if
sku
.
Attrs
==
nil
{
sku
.
Attrs
=
[]
interface
{}{}
}
}
}
sku
.
StockInfo
=
new
(
StockInfoResult
)
}
//获取在途库存信息
//判断是否需要返回sku详情
if
showStockInfo
==
"1"
&&
sku
.
OldGoodsId
!=
0
{
if
showSkuDetail
==
"1"
{
sku
.
StockInfo
=
ls
.
getStockInfo
(
sku
.
SupplierId
,
sku
.
OldGoodsId
)
sku
.
SkuDetail
=
ls
.
GetSkuDetail
(
sku
.
GoodsId
)
}
}
//格式化为对象返回
if
sku
.
StockInfo
==
nil
{
type
StockInfoResult
struct
{
}
sku
.
StockInfo
=
new
(
StockInfoResult
)
}
//判断是否需要返回sku详情
//是否需要返回spu额外信息
if
showSkuDetail
==
"1"
{
if
showSpuExtra
==
"1"
{
sku
.
SkuDetail
=
ls
.
GetSkuDetail
(
sku
.
Goods
Id
)
sku
.
SpuExtra
=
ls
.
GetSpuExtra
(
sku
.
Spu
Id
)
}
}
//是否需要返回spu额外信息
brandPack
:=
gjson
.
Get
(
spu
,
"brand_pack"
)
.
String
()
if
showSpuExtra
==
"1"
{
if
brandPack
!=
""
{
sku
.
SpuExtra
=
ls
.
GetSpuExtra
(
sku
.
SpuId
)
sku
.
SpuExtra
.
BrandPack
=
brandPack
}
sku
.
BrandPack
=
brandPack
}
brandPack
:=
gjson
.
Get
(
spu
,
"brand_pack"
)
.
String
()
//获取供应链标准品牌
if
brandPack
!=
""
{
//什么是供应链的标准品牌 供应链那边报关的时候要求他们的标准品牌,所以要吧自己的品牌映射上去
sku
.
SpuExtra
.
BrandPack
=
brandPack
//继来那边对接的标准品牌(下单的时候)
sku
.
BrandPack
=
brandPack
sku
.
ScmBrand
=
ls
.
GetScmBrand
(
brandId
)
}
//获取供应链标准品牌
//获取新版的标准品牌
//什么是供应链的标准品牌 供应链那边报关的时候要求他们的标准品牌,所以要吧自己的品牌映射上去
sku
.
StandardBrand
=
ls
.
GetStandardBrand
(
brandId
)
//继来那边对接的标准品牌(下单的时候)
sku
.
ScmBrand
=
ls
.
GetScmBrand
(
brandId
)
//获取新版的标准品牌
//处理过期, 2022.7.13 专卖没有过期
sku
.
StandardBrand
=
ls
.
GetStandardBrand
(
brandId
)
if
sku
.
SupplierId
!=
17
&&
gjson
.
Get
(
skuStr
,
"is_expire"
)
.
Int
()
!=
0
{
sku
.
LadderPrice
=
nil
}
//处理过期, 2022.7.13 专卖没有过期
//处理活动
if
sku
.
SupplierId
!=
17
&&
gjson
.
Get
(
skuStr
,
"is_expire"
)
.
Int
()
!=
0
{
sku
.
AcType
=
0
sku
.
LadderPrice
=
nil
sku
.
AllowCoupon
=
1
//这里获取活动价格和活动类型(折扣打折活动)
sku
=
ls
.
GetActivity
(
sku
)
priceService
:=
PriceService
{}
//这里又有一个判断,如果是非猎芯的,目前只有爱智,通过org_id来判断
//1是猎芯,3是爱智
switch
sku
.
OrgId
{
//case为0是为了兼容价格体系之前的价格
case
0
:
case
1
:
//这里猎芯和寄售都是走同一套的价格体系了
//获取系数和价格
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
//获取自定义价格后的阶梯价
customPriceService
:=
CustomPrice
{}
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
sku
=
priceService
.
GetActivityPrice
(
sku
)
case
3
:
//如果是寄售的,不走价格体系
if
sku
.
Source
==
12
{
break
}
}
//这里还有个特殊判断,要兼容华云改价格体系之前的老数据
//
处理活动
//
判断组织是3并且阶梯价数量为2,并且第一个阶梯不是0的就是老数据
sku
.
AcType
=
0
//兼容最近的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2)
sku
.
AllowCoupon
=
1
//又要兼容新的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2) + 销售限价(阶梯数量3)
//还有一种特殊情况,那就是只上传成本价和销售限价,那么就是要走价格体系的(最新)
//这里获取活动价格和活动类型(折扣打折活动)
if
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
2
&&
sku
.
LadderPrice
[
0
]
.
Purchases
!=
0
)
||
sku
=
ls
.
GetActivity
(
sku
)
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
3
&&
sku
.
LadderPrice
[
0
]
.
Purchases
==
0
)
||
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
4
&&
sku
.
LadderPrice
[
0
]
.
Purchases
==
0
)
{
priceService
:=
PriceService
{}
sku
.
LadderPrice
=
priceService
.
GetIEdgePrice
(
sku
.
LadderPrice
)
//这里又有一个判断,如果是非猎芯的,目前只有爱智,通过org_id来判断
}
else
{
//1是猎芯,3是爱智
//判断是不是华云的,如果是的话,还要判断是不是有成本价和销售限价,如果是的话,要把销售限价去掉,因为走的价格体系的前提是有成本价的时候
switch
sku
.
OrgId
{
//只能有一个阶梯,并且阶梯数量为0
//case为0是为了兼容价格体系之前的价格
if
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
2
{
case
0
:
sku
.
LadderPrice
=
sku
.
LadderPrice
[
:
1
]
case
1
:
}
//这里猎芯和
寄售
都是走同一套的价格体系了
//这里猎芯和
华云
都是走同一套的价格体系了
//获取系数和价格
//获取系数和价格
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
//获取自定义价格后的阶梯价
//获取自定义价格后的阶梯价
customPriceService
:=
CustomPrice
{}
customPriceService
:=
CustomPrice
{}
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
sku
=
priceService
.
GetActivityPrice
(
sku
)
//这里还要针对华云的阶梯价进行一次转换,因为要兼容目前华云的使用方式
case
3
:
if
sku
.
OrgId
==
3
{
//如果是寄售的,不走价格体系
sku
.
LadderPrice
=
customPriceService
.
transformIEdgeLadderPrice
(
sku
)
if
sku
.
Source
==
12
{
break
}
//这里还有个特殊判断,要兼容华云改价格体系之前的老数据
//判断组织是3并且阶梯价数量为2,并且第一个阶梯不是0的就是老数据
//兼容最近的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2)
//又要兼容新的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2) + 销售限价(阶梯数量3)
//还有一种特殊情况,那就是只上传成本价和销售限价,那么就是要走价格体系的(最新)
if
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
2
&&
sku
.
LadderPrice
[
0
]
.
Purchases
!=
0
)
||
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
3
&&
sku
.
LadderPrice
[
0
]
.
Purchases
==
0
)
||
(
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
4
&&
sku
.
LadderPrice
[
0
]
.
Purchases
==
0
)
{
sku
.
LadderPrice
=
priceService
.
GetIEdgePrice
(
sku
.
LadderPrice
)
}
else
{
//判断是不是华云的,如果是的话,还要判断是不是有成本价和销售限价,如果是的话,要把销售限价去掉,因为走的价格体系的前提是有成本价的时候
//只能有一个阶梯,并且阶梯数量为0
if
sku
.
OrgId
==
3
&&
len
(
sku
.
LadderPrice
)
==
2
{
sku
.
LadderPrice
=
sku
.
LadderPrice
[
:
1
]
}
//这里猎芯和华云都是走同一套的价格体系了
//获取系数和价格
sku
=
ls
.
GetCoefficientAndPrice
(
sku
)
//获取自定义价格后的阶梯价
customPriceService
:=
CustomPrice
{}
sku
.
CustomPriceList
,
_
=
customPriceService
.
getCustomPriceList
(
sku
)
//这里还要针对华云的阶梯价进行一次转换,因为要兼容目前华云的使用方式
if
sku
.
OrgId
==
3
{
sku
.
LadderPrice
=
customPriceService
.
transformIEdgeLadderPrice
(
sku
)
}
}
}
sku
=
priceService
.
GetActivityPrice
(
sku
)
}
}
sku
=
priceService
.
GetActivityPrice
(
sku
)
}
//仅提供价格和库存
//仅提供价格和库存
if
fast
!=
"1"
{
if
fast
!=
"1"
{
if
sku
.
SupplierId
!=
0
{
if
sku
.
SupplierId
!=
0
{
sku
.
SuppExtendFee
=
ls
.
GetExtendFee
(
sku
.
SupplierId
,
sku
.
Canal
)
sku
.
SuppExtendFee
=
ls
.
GetExtendFee
(
sku
.
SupplierId
,
sku
.
Canal
)
}
//还要处理货期
delivery
:=
ls
.
GetDelivery
(
sku
.
SupplierId
,
sku
.
Canal
)
if
sku
.
CnDeliveryTime
==
""
{
sku
.
CnDeliveryTime
=
delivery
[
"cn_delivery"
]
}
if
sku
.
HkDeliveryTime
==
""
{
sku
.
HkDeliveryTime
=
delivery
[
"hk_delivery"
]
}
//只要是寄售的,大陆交期都是0.5工作日
if
sku
.
Source
==
12
{
sku
.
CnDeliveryTime
=
"0.5工作日"
}
}
}
//还要处理货期
//最小起订量要大于阶梯价的最小阶梯数量
delivery
:=
ls
.
GetDelivery
(
sku
.
SupplierId
,
sku
.
Canal
)
if
len
(
sku
.
LadderPrice
)
>
0
{
if
sku
.
CnDeliveryTime
==
""
{
//排序
sku
.
CnDeliveryTime
=
delivery
[
"cn_delivery"
]
sort
.
Sort
(
sorter
.
LadderPriceSorter
(
sku
.
LadderPrice
))
//取出第一个阶梯价
purchases
:=
sku
.
LadderPrice
[
0
]
.
Purchases
if
purchases
>
sku
.
Moq
{
sku
.
Moq
=
purchases
}
}
}
if
sku
.
HkDeliveryTime
==
""
{
//处理是否可以购买
sku
.
HkDeliveryTime
=
delivery
[
"hk_delivery"
]
if
sku
.
Mpq
==
0
{
sku
.
Mpq
=
1
}
}
if
len
(
sku
.
LadderPrice
)
>
0
{
//只要是寄售的,大陆交期都是0.5工作日
sku
.
LadderPriceResult
=
sku
.
LadderPrice
if
sku
.
Source
==
12
{
}
else
{
sku
.
CnDeliveryTime
=
"0.5工作日"
sku
.
LadderPriceResult
=
[]
int
{}
}
}
//判断是否可以购买
}
sku
.
IsBuy
=
ls
.
GetIsBuy
(
sku
)
if
sku
.
IsBuy
==
0
&&
sku
.
OrgId
!=
1
{
//最小起订量要大于阶梯价的最小阶梯数量
sku
.
AcType
=
0
if
len
(
sku
.
LadderPrice
)
>
0
{
//排序
sort
.
Sort
(
sorter
.
LadderPriceSorter
(
sku
.
LadderPrice
))
//取出第一个阶梯价
purchases
:=
sku
.
LadderPrice
[
0
]
.
Purchases
if
purchases
>
sku
.
Moq
{
sku
.
Moq
=
purchases
}
}
}
sku
.
Stock
=
ls
.
GetStock
(
sku
)
//处理是否可以购买
if
sku
.
Mpq
==
0
{
sku
.
Mpq
=
1
}
//获取标签信息
if
len
(
sku
.
LadderPrice
)
>
0
{
var
TagService
TagsService
sku
.
LadderPriceResult
=
sku
.
LadderPrice
sku
.
GoodsTag
=
TagService
.
GetLyTags
(
sku
)
}
else
{
sku
.
LadderPriceResult
=
[]
int
{}
}
//获取关税以及价格转换
//判断是否可以购买
sku
=
ls
.
GetTariffAndPrice
(
sku
)
sku
.
IsBuy
=
ls
.
GetIsBuy
(
sku
)
if
sku
.
IsBuy
==
0
&&
sku
.
OrgId
!=
1
{
sku
.
AcType
=
0
}
//最后一步,将sku的全部信息放到有序map里面
sku
.
Stock
=
ls
.
GetStock
(
sku
)
GoodsRes
.
Store
(
goodsId
,
sku
)
//(*goodsRes)[goodsId] = A
}
//获取标签信息
// 发送结果时也要检查 context,避免在超时后阻塞
var
TagService
TagsService
select
{
sku
.
GoodsTag
=
TagService
.
GetLyTags
(
sku
)
case
<-
ctx
.
Done
()
:
logger
.
Log
(
"LyGoodsDetail: 发送结果前context已取消,直接返回"
,
"sku"
,
1
)
//获取关税以及价格转换
return
sku
=
ls
.
GetTariffAndPrice
(
sku
)
case
ch
<-
GoodsRes
:
// 成功发送
//最后一步,将sku的全部信息放到有序map里面
}
GoodsRes
.
Store
(
goodsId
,
sku
)
//(*goodsRes)[goodsId] = A
//退出通道
ch
<-
GoodsRes
}
}
// 获取活动
// 获取活动
...
...
service/service_sample.go
View file @
3a6792ae
...
@@ -83,9 +83,9 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
...
@@ -83,9 +83,9 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
//抽取自营 或者联营 goods_id
//抽取自营 或者联营 goods_id
zyService
:=
ZiyingService
{}
//实例化自营查询
zyService
:=
ZiyingService
{}
//实例化自营查询
lyService
:=
LyService
{}
//实例化联营查询
//
lyService := LyService{} //实例化联营查询
ch
:=
make
(
chan
sync
.
Map
)
//管道
ch
:=
make
(
chan
sync
.
Map
)
//管道
p
:=
0
//总共协程
p
:=
0
//总共协程
zyGoodsId
:=
make
([]
string
,
0
)
zyGoodsId
:=
make
([]
string
,
0
)
lyGoodsId
:=
make
([]
string
,
0
)
lyGoodsId
:=
make
([]
string
,
0
)
for
_
,
goodsId
:=
range
goodsIds
{
for
_
,
goodsId
:=
range
goodsIds
{
...
@@ -102,7 +102,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
...
@@ -102,7 +102,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
}
else
{
//联营
}
else
{
//联营
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
lyGoodsId
=
append
(
lyGoodsId
,
goodsId
)
if
len
(
lyGoodsId
)
>=
10
{
if
len
(
lyGoodsId
)
>=
10
{
go
lyService
.
LyGoodsDetail
(
ctxWithTimeout
,
params
,
lyGoodsId
,
ch
)
//
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
lyGoodsId
=
lyGoodsId
[
:
0
:
0
]
lyGoodsId
=
lyGoodsId
[
:
0
:
0
]
p
++
p
++
}
}
...
@@ -113,7 +113,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
...
@@ -113,7 +113,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
p
++
p
++
}
}
if
len
(
lyGoodsId
)
>
0
{
if
len
(
lyGoodsId
)
>
0
{
go
lyService
.
LyGoodsDetail
(
ctxWithTimeout
,
params
,
lyGoodsId
,
ch
)
//
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
p
++
p
++
}
}
//异步map最后转成map
//异步map最后转成map
...
...
service/service_spu.go
View file @
3a6792ae
package
service
package
service
import
(
import
(
"github.com/gomodule/redigo/redis"
"github.com/tidwall/gjson"
"github.com/tidwall/gjson"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/gredis"
)
)
type
SpuService
struct
{
var
UsdRate
float64
//美金匯率
type
SpuService
struct
{
}
}
func
(
ss
*
SpuService
)
g
etSpuList
(
skuArr
map
[
string
]
string
)
(
spuList
map
[
string
]
string
)
{
func
(
ss
*
SpuService
)
G
etSpuList
(
skuArr
map
[
string
]
string
)
(
spuList
map
[
string
]
string
)
{
var
spuIds
[]
string
var
spuIds
[]
string
for
_
,
skuStr
:=
range
skuArr
{
for
_
,
skuStr
:=
range
skuArr
{
spuId
:=
gjson
.
Get
(
skuStr
,
"spu_id"
)
.
String
()
spuId
:=
gjson
.
Get
(
skuStr
,
"spu_id"
)
.
String
()
...
@@ -19,3 +21,10 @@ func (ss *SpuService) getSpuList(skuArr map[string]string) (spuList map[string]s
...
@@ -19,3 +21,10 @@ func (ss *SpuService) getSpuList(skuArr map[string]string) (spuList map[string]s
spuList
=
gredis
.
Hmget
(
"spu"
,
"spu"
,
spuIds
)
spuList
=
gredis
.
Hmget
(
"spu"
,
"spu"
,
spuIds
)
return
return
}
}
// 设置查询公共变量
func
(
ss
*
SpuService
)
SetInit
()
{
redisCon
:=
gredis
.
Conn
(
"default_r"
)
usdRatio
,
_
:=
redis
.
Float64
(
redisCon
.
Do
(
"HGET"
,
"erp_rate"
,
2
))
UsdRate
=
usdRatio
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment