runtime.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. package calculate
  2. import (
  3. "errors"
  4. "math"
  5. "zhiyuan/pkg/db"
  6. "zhiyuan/pkg/logger"
  7. "zhiyuan/pkg/utils"
  8. "zhiyuan/services/admin"
  9. "github.com/Knetic/govaluate"
  10. "github.com/gin-gonic/gin"
  11. )
  12. type Call struct {
  13. Name string `json:"name" label:"变量名"`
  14. Item *OrderItem `json:"item" label:"项目"`
  15. }
  16. type Stack struct {
  17. OrderNumber int64 `json:"order_number"`
  18. Item *OrderItem `json:"item" label:"项目"`
  19. }
  20. type Context struct {
  21. Order *Order `json:"order" label:"当前订单"`
  22. OrderNumber int64 `json:"order_number"`
  23. Item *OrderItem `json:"item" label:"当前项目"`
  24. Calls []Call `json:"calls"`
  25. Stack []Stack `json:"stack"`
  26. C *gin.Context
  27. }
  28. func NewContext(order *Order, c *gin.Context) *Context {
  29. context := new(Context)
  30. context.Order = order
  31. context.OrderNumber = -1
  32. context.Calls = make([]Call, 0)
  33. context.Stack = make([]Stack, 0)
  34. context.C = c
  35. return context
  36. }
  37. func ToDataType(value interface{}, dataType string) (interface{}, bool) {
  38. if value != nil {
  39. switch dataType {
  40. case "number":
  41. ret, ok := db.ToFloat64(value)
  42. if ok {
  43. return ret, true
  44. }
  45. case "string":
  46. return db.ToString(value), true
  47. case "array":
  48. ret, ok := value.([]interface{})
  49. if !ok {
  50. var array interface{}
  51. utils.JsonDecode(db.ToString(value)).To(&array)
  52. ret, ok = db.ToArray(array)
  53. }
  54. if ok {
  55. return ret, true
  56. }
  57. }
  58. }
  59. return nil, false
  60. }
  61. func (context *Context) Push(item *OrderItem) {
  62. context.Stack = append(context.Stack, Stack{context.OrderNumber, context.Item})
  63. context.Item = item
  64. context.OrderNumber = -1
  65. }
  66. func (context *Context) Pop() {
  67. context.Item = context.Stack[len(context.Stack)-1].Item
  68. context.OrderNumber = context.Stack[len(context.Stack)-1].OrderNumber
  69. context.Stack = context.Stack[:len(context.Stack)-1]
  70. }
  71. func (context *Context) Get(name string) (interface{}, error) {
  72. for _, call := range context.Calls {
  73. if call.Item == context.Item && call.Name == name {
  74. return nil, errors.New("circular reference: " + name)
  75. }
  76. }
  77. context.Calls = append(context.Calls, Call{name, context.Item})
  78. defer func() { context.Calls = context.Calls[:len(context.Calls)-1] }()
  79. item := context.Item
  80. for ; item != nil; item = item.Parent {
  81. if name == "项目名称" {
  82. return item.Item.Name, nil
  83. }
  84. for _, prop := range item.Item.Props {
  85. if name == prop.Name {
  86. var value interface{} = nil
  87. switch prop.Type {
  88. case 0:
  89. value = prop.Value
  90. case 1:
  91. if _, ok := item.From.Results[prop.ID]; !ok {
  92. result, err := context.Exec(prop.Value, item, -1)
  93. if err != nil {
  94. return nil, err
  95. }
  96. item.From.Results[prop.ID] = result
  97. }
  98. value = item.From.Results[prop.ID]
  99. case 2, 3:
  100. value = item.From.Prop[prop.ID]
  101. }
  102. if ret, ok := ToDataType(value, prop.DataType); ok {
  103. return ret, nil
  104. }
  105. }
  106. }
  107. if item == context.Item && item.From.Product.ID != 0 {
  108. if name == "产品名称" {
  109. return item.From.Product.Name, nil
  110. }
  111. if item.Product != nil {
  112. propMap := utils.JsonDecode(item.Product.Property).ToMap()
  113. if _, ok := propMap[name]; ok {
  114. if number, ok := db.ToFloat64(propMap[name]); ok {
  115. return number, nil
  116. }
  117. return propMap[name], nil
  118. }
  119. }
  120. if _, ok := item.From.Product.Spec[name]; ok {
  121. return item.From.Product.Spec[name], nil
  122. }
  123. }
  124. }
  125. for _, prop := range context.Order.Calc.Props {
  126. if name == prop.Name {
  127. var value interface{} = nil
  128. switch prop.Type {
  129. case 0:
  130. value = prop.Value
  131. case 1:
  132. if _, ok := context.Order.From.Results[prop.ID]; !ok {
  133. result, err := context.Exec(prop.Value, item, -1)
  134. if err != nil {
  135. return nil, err
  136. }
  137. context.Order.From.Results[prop.ID] = result
  138. }
  139. value = context.Order.From.Results[prop.ID]
  140. case 2, 3:
  141. value = context.Order.From.Prop[prop.ID]
  142. }
  143. if ret, ok := ToDataType(value, prop.DataType); ok {
  144. return ret, nil
  145. }
  146. }
  147. }
  148. return nil, errors.New("undeclared name: " + name)
  149. }
  150. func (context *Context) GetArray(args ...interface{}) (interface{}, error) {
  151. if len(args) == 0 || len(args) > 3 {
  152. return nil, errors.New("not enough arguments in call to call")
  153. }
  154. var ok bool
  155. expr := ""
  156. if expr, ok = args[0].(string); !ok {
  157. return nil, errors.New("wrong parameter type: call")
  158. }
  159. cond := ""
  160. if len(args) >= 2 {
  161. if cond, ok = args[1].(string); !ok {
  162. return nil, errors.New("wrong parameter type: call")
  163. }
  164. }
  165. inChild := false
  166. if len(args) >= 3 {
  167. if inChild, ok = args[2].(bool); !ok {
  168. return nil, errors.New("wrong parameter type: call")
  169. }
  170. }
  171. items := context.Order.Items
  172. if context.Item != nil {
  173. items = context.Item.Childs
  174. }
  175. var array []interface{}
  176. orderNumber := int64(0)
  177. for i, _ := range items {
  178. if inChild {
  179. context.Push(items[i])
  180. ret, err := context.GetArray(expr, cond, inChild)
  181. context.Pop()
  182. if err == nil {
  183. if reta, ok := ret.([]interface{}); ok {
  184. array = append(array, reta...)
  185. }
  186. }
  187. }
  188. if cond != "" {
  189. ret, err := context.Exec(cond, items[i], int64(i))
  190. if err != nil {
  191. continue
  192. }
  193. if retb, ok := ret.(bool); !ok || !retb {
  194. continue
  195. }
  196. }
  197. result, err := context.Exec(expr, items[i], orderNumber)
  198. orderNumber++
  199. if err == nil {
  200. array = append(array, result)
  201. }
  202. }
  203. return array, nil
  204. }
  205. func (context *Context) ToFloat(value interface{}) float64 {
  206. ret, ok := db.ToFloat64(value)
  207. if ok {
  208. return ret
  209. }
  210. return 0
  211. }
  212. func (context *Context) Exec(expression string, item *OrderItem, orderNumber int64) (interface{}, error) {
  213. if item != context.Item {
  214. context.Push(item)
  215. context.OrderNumber = orderNumber
  216. defer context.Pop()
  217. }
  218. return context.EvaluableExpression(expression)
  219. }
  220. func (context *Context) EvaluableExpression(expression string) (interface{}, error) {
  221. functions := map[string]govaluate.ExpressionFunction{
  222. "call": context.GetArray,
  223. "sum": func(args ...interface{}) (interface{}, error) {
  224. array, err := context.GetArray(args...)
  225. if err != nil {
  226. return nil, err
  227. }
  228. var result float64
  229. for _, item := range array.([]interface{}) {
  230. result += context.ToFloat(item)
  231. }
  232. return result, nil
  233. },
  234. "len": func(args ...interface{}) (interface{}, error) {
  235. return len(args), nil
  236. },
  237. "index": func(args ...interface{}) (interface{}, error) {
  238. if len(args) < 2 {
  239. return nil, errors.New("not enough arguments in call to call")
  240. }
  241. index := int(context.ToFloat(args[len(args)-1]))
  242. if index >= len(args)-1 {
  243. return nil, errors.New("index out of range: index")
  244. }
  245. return args[index], nil
  246. },
  247. "string_slice": func(args ...interface{}) (interface{}, error) {
  248. if len(args) == 0 || len(args) > 3 {
  249. return nil, errors.New("not enough arguments in call to call")
  250. }
  251. str := []rune("")
  252. if s, ok := args[0].(string); ok {
  253. str = []rune(s)
  254. } else {
  255. return nil, errors.New("wrong parameter type: string_slice")
  256. }
  257. start := int(0)
  258. if len(args) >= 2 {
  259. if num, ok := args[1].(float64); ok {
  260. start = int(num)
  261. } else {
  262. return nil, errors.New("wrong parameter type: string_slice")
  263. }
  264. }
  265. if start < 0 {
  266. start = len(str) + start
  267. }
  268. if start < 0 {
  269. start = 0
  270. }
  271. if start > len(args) {
  272. start = len(args)
  273. }
  274. end := len(str)
  275. if len(args) >= 3 {
  276. if num, ok := args[2].(float64); ok {
  277. end = int(num)
  278. } else {
  279. return nil, errors.New("wrong parameter type: string_slice")
  280. }
  281. }
  282. if end < 0 {
  283. end = len(str) + end
  284. }
  285. if end < 0 {
  286. end = 0
  287. }
  288. if end > len(args) {
  289. end = len(args)
  290. }
  291. return string(str[start:end]), nil
  292. },
  293. "count": func(args ...interface{}) (interface{}, error) {
  294. array, err := context.GetArray(args...)
  295. if err != nil {
  296. return nil, err
  297. }
  298. return len(array.([]interface{})), nil
  299. },
  300. "sub": func(args ...interface{}) (interface{}, error) {
  301. var ok bool
  302. expr := ""
  303. if expr, ok = args[0].(string); !ok {
  304. return nil, errors.New("wrong parameter type: call")
  305. }
  306. cond := ""
  307. if len(args) >= 2 {
  308. if cond, ok = args[1].(string); !ok {
  309. return nil, errors.New("wrong parameter type: call")
  310. }
  311. }
  312. num := int64(0)
  313. if len(args) >= 3 {
  314. if _, ok = args[2].(float64); !ok {
  315. return nil, errors.New("wrong parameter type: call")
  316. }
  317. num = int64(args[2].(float64))
  318. }
  319. array, err := context.GetArray(expr, cond, false)
  320. if err != nil {
  321. return nil, err
  322. }
  323. if num < 0 {
  324. num = int64(len(array.([]interface{}))) + num
  325. }
  326. if num < 0 {
  327. num = 0
  328. }
  329. if num >= int64(len(array.([]interface{}))) {
  330. num = int64(len(array.([]interface{}))) - 1
  331. }
  332. if num < 0 {
  333. return 0, nil
  334. }
  335. return array.([]interface{})[num], nil
  336. },
  337. "name": func(args ...interface{}) (interface{}, error) {
  338. if context.Item == nil {
  339. return context.Order.Calc.Name, nil
  340. }
  341. return context.Item.Item.Name, nil
  342. },
  343. "product": func(args ...interface{}) (interface{}, error) {
  344. if context.Item.From.Product.ID != 0 {
  345. return context.Item.From.Product.Name, nil
  346. }
  347. return "", nil
  348. },
  349. "order": func(args ...interface{}) (interface{}, error) {
  350. if context.OrderNumber < 0 {
  351. if context.Item == nil {
  352. return 0, nil
  353. }
  354. return float64(context.Item.OrderNumber), nil
  355. }
  356. return float64(context.OrderNumber), nil
  357. },
  358. "unit": func(args ...interface{}) (interface{}, error) {
  359. var ok bool
  360. name := ""
  361. if name, ok = args[0].(string); !ok {
  362. return nil, errors.New("wrong parameter type: call")
  363. }
  364. item := context.Item
  365. for ; item != nil; item = item.Parent {
  366. for _, prop := range item.Item.Props {
  367. if name == prop.Name {
  368. return prop.Unit, nil
  369. }
  370. }
  371. }
  372. for _, prop := range context.Order.Calc.Props {
  373. if name == prop.Name {
  374. return prop.Unit, nil
  375. }
  376. }
  377. return "", nil
  378. },
  379. "author": func(args ...interface{}) (interface{}, error) {
  380. type AdminInfo struct {
  381. ID int `json:"id"`
  382. UserName string `json:"username"`
  383. Phone string `json:"phone"`
  384. }
  385. var adminInfo AdminInfo
  386. _, err := admin.GetInfoByID(int(context.Order.AdminId), []string{"id", "username", "phone"}, &adminInfo)
  387. if err != nil {
  388. return "", nil
  389. }
  390. return adminInfo.UserName, nil
  391. },
  392. "round": func(args ...interface{}) (interface{}, error) {
  393. var ok bool
  394. value := float64(0)
  395. if value, ok = args[0].(float64); !ok {
  396. return nil, errors.New("wrong parameter type: round")
  397. }
  398. precision := float64(0)
  399. if len(args) >= 2 {
  400. if precision, ok = args[1].(float64); !ok {
  401. return nil, errors.New("wrong parameter type: round")
  402. }
  403. }
  404. p := math.Pow10(int(precision))
  405. return math.Floor(value*p+0.5) / p, nil
  406. },
  407. }
  408. expr, err := govaluate.NewEvaluableExpressionWithFunctions(expression, functions)
  409. if err != nil {
  410. if context.Item == nil {
  411. logger.Sugar.Infof("expr: %v error: %v", expression, err.Error())
  412. } else {
  413. logger.Sugar.Infof("item: %v %v expr: %v error: %v", context.Item.Item.ID, context.Item.Item.Name, expression, err.Error())
  414. }
  415. return nil, err
  416. }
  417. result, err := expr.Eval(context)
  418. if err != nil {
  419. if context.Item == nil {
  420. logger.Sugar.Infof("expr: %v error: %v", expression, err.Error())
  421. } else {
  422. logger.Sugar.Infof("item: %v %v expr: %v error: %v", context.Item.Item.ID, context.Item.Item.Name, expression, err.Error())
  423. }
  424. return nil, err
  425. }
  426. return result, nil
  427. }
  428. func (context *Context) Eval() error {
  429. if context.Item == nil {
  430. for _, item := range context.Order.Items {
  431. context.Push(item)
  432. err := context.Eval()
  433. context.Pop()
  434. if err != nil {
  435. return err
  436. }
  437. }
  438. for _, prop := range context.Order.Calc.Props {
  439. if prop.Type == 1 {
  440. if _, ok := context.Order.From.Results[prop.ID]; !ok {
  441. result, err := context.EvaluableExpression(prop.Value)
  442. if err != nil {
  443. return err
  444. }
  445. if context.Order.From.Results[prop.ID], ok = ToDataType(result, prop.DataType); !ok {
  446. return errors.New("wrong property type")
  447. }
  448. }
  449. }
  450. }
  451. } else {
  452. for _, item := range context.Item.Childs {
  453. context.Push(item)
  454. err := context.Eval()
  455. context.Pop()
  456. if err != nil {
  457. return err
  458. }
  459. }
  460. for _, prop := range context.Item.Item.Props {
  461. if prop.Type == 1 {
  462. if _, ok := context.Item.From.Results[prop.ID]; !ok {
  463. result, err := context.EvaluableExpression(prop.Value)
  464. if err != nil {
  465. return err
  466. }
  467. context.Item.From.Results[prop.ID] = result
  468. }
  469. }
  470. }
  471. }
  472. return nil
  473. }