Compare commits

..

No commits in common. "3d67fbbb6265571b3f828edfb5bb7497d137c2e7" and "b9b7309edc85f7e87f15089292553f0d2c2ceed6" have entirely different histories.

218 changed files with 4293 additions and 4954 deletions

View File

@ -0,0 +1,7 @@
package constants
// 千人千面windows访问图片的地址
const DOMAIN_RENDER_IMG_NAME = "https://fusenrenderimg.kayue.cn"
// 云渲染域名和访问地址
const DOMAIN_NAME = "https://fusenapi.kayue.cn:8010/"

View File

@ -1,8 +1,7 @@
package constants package constants
// 发票主体页面 // 主体页面
const MAIN_INVOICE_HTML = ` const MAIN_INVOICE_HTML = `<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -10,235 +9,230 @@ const MAIN_INVOICE_HTML = `
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invoice</title> <title>Invoice</title>
<style>
body {
margin: 0;
}
.header_warp {
background-color: #F8F8FA;
padding: 20px 5% 20px 6%;
}
.header_td {
width: 50%;
}
.header_td.logo {
vertical-align: top;
}
.header_logo {
max-height: 15px;
max-width: 100%;
margin-top: 5px;
}
.header_td.title {
color: #212121;
font-weight: 600;
font-size: 36px;
}
.information_warp {
padding: 30px 5% 30px 6%;
}
.information_td {
width: 50%;
font-size: 13px;
line-height: 20px;
font-weight: 300;
}
.information_td.bill {
color: #212121;
font-weight: 500;
}
.information_td.right {
color: #212121;
}
.information_td.info {
color: #666666;
line-height: 17px;
}
.bill_warp {
padding: 0 5% 0 6%;
}
.bill_td {
font-size: 13px;
}
.bill_td:first-child {
width: 47.59%;
}
.bill_td.title {
border-top: 2px solid #333;
padding: 13px 0 7px;
font-weight: 500;
color: #212121;
}
.bill_td.info {
color: #666;
border-bottom: 1px solid #ccc;
padding: 8px 0;
font-weight: 400;
}
.bill_warp tr:last-child .bill_td.info {
border-bottom: none;
}
.total_warp {
padding: 14px 5% 24px 0;
}
.total_td {
color: #212121;
padding: 8px 0 7px;
font-size: 12px;
font-weight: 500;
}
.total_td.info {
color: #666;
font-weight: 400;
}
.total_td.border-dashed {
border-bottom: 1px dashed #ccc;
}
.total_td.border-solid {
border-bottom: 2px solid #333;
padding-bottom: 12px;
}
.total_td.total {
padding-top: 12px;
font-size: 13px;
font-weight: 600;
}
.notes_warp {
padding: 0 5% 0 6%;
}
.notes_td {
font-size: 13px;
color: #666;
font-weight: 300;
width: 50%;
line-height: 21px;
}
.notes_td.title {
color: #212121;
font-weight: 500;
}
.notes_td.notes {
vertical-align: top;
}
</style>
</head> </head>
<body> <body style="margin: 0;">
<!-- header --> <!-- header -->
<table class="header_warp" border="0" align="center" cellpadding="0" cellspacing="0" width="100%"> <table border="0" align="center" cellpadding="0" cellspacing="0" width="100%"
<tr> style="background-color: #F8F8FA;padding: 0 5%;">
<td class="header_td logo" align="left"> <tr height="30px"></tr>
<img class="header_logo" src="https://fusenapi.kayue.cn:8010/storage/email/logo.png" alt="logo"> <tr>
</td> <td align="left" rowspan="9" style="vertical-align: top; width: 50%;">
<td class="header_td title" align="right">Invoice</td> <img style="max-height: 40px;max-width: 100%;"
</tr> src="{{h5Url}}/storage/email/logo.png" alt="logo">
</table> </td>
<!-- information --> <td align="left" style="width: 50%;">
<table class="information_warp" border="0" align="center" cellpadding="0" cellspacing="0" width="100%"> <span style="color: #212121;font-weight: bold;font-size: 42px; display: block;">Invoice</span>
<tr> </td>
<td class="information_td bill" align="left">Bill To:</td> </tr>
<td class="information_td right" align="right">Invoice No. {{invoice_number}}</td> <tr height="30px"></tr>
</tr> <tr>
<tr> <td align="left" style="width: 50%;">
<td class="information_td info" align="left">{{buyer_name}}</td> <span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Invoice Number:</span>
<td class="information_td right" align="right">Date: {{buy_date}}</td> </td>
</tr> </tr>
<tr> <tr height="15px"></tr>
<td class="information_td info" align="left">{{street}}</td> <tr>
<td class="information_td" align="right"></td> <td align="left" style="width: 50%;">
</tr> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">{{order_sn}}</span>
<tr> </td>
<td class="information_td info" align="left">{{city}}</td> </tr>
<td class="information_td" align="right"></td> <tr height="30px"></tr>
</tr> <tr>
<tr> <td align="left" style="width: 50%;">
<td class="information_td info" align="left">{{country}}</td> <span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Date:</span>
<td class="information_td" align="right"></td> </td>
</tr> </tr>
</table> <tr height="15px"></tr>
<!-- bill --> <tr>
<table class="bill_warp" border="0" align="center" cellpadding="0" cellspacing="0" width="100%"> <td align="left" style="width: 50%;">
<!--循环部分--> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">{{order_expire_time}}</span>
{{product_loop_html}} </td>
<!--循环部分--> </tr>
</table> <tr height="30px"></tr>
<!-- total --> </table>
<table class="total_warp" border="0" align="right" cellpadding="0" cellspacing="0" width="50%"> <!-- information -->
<tr> <table border="0" align="center" cellpadding="0" cellspacing="0" width="100%"
<td class="total_td" align="right">Subtotal</td> style="background-color: #fff;padding: 0 5%;">
<td class="total_td info" align="right">${{subtotal_price}}</td> <tr height="30px"></tr>
</tr> <tr>
<tr> <td align="left" style="width: 50%;">
<td class="total_td" align="right">Shipping Fee</td> <span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Bill To:</span>
<td class="total_td info" align="right">Free</td> </td>
</tr> <td align="left" style="width: 50%;">
<tr> <span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Bill From:</span>
<td class="total_td border-dashed" align="right">Tax</td> </td>
<td class="total_td info border-dashed" align="right">${{tax}}</td> </tr>
</tr> <tr height="15px"></tr>
<tr> <tr>
<td class="total_td" align="right">Total</td> <td align="left" style="width: 50%;">
<td class="total_td info" align="right">${{total_price}}</td> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">{{name}}</span>
</tr> </td>
<tr> <td align="left" style="width: 50%;">
<td class="total_td border-solid" align="right">Deposit Requested</td> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">Lemon
<td class="total_td info border-solid" align="right">${{deposit_price}}</td> Squeezy LLC</span>
</tr> </td>
<tr> </tr>
<td class="total_td total" align="right">Deposit Due</td> <tr>
<td class="total_td total" align="right">${{deposit_price}}</td> <td align="left" style="width: 50%;">
</tr> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">{{street}} {{suite}}</span>
</table> </td>
<!-- notes --> <td align="left" style="width: 50%;">
<table class="notes_warp" border="0" align="center" cellpadding="0" cellspacing="0" width="100%"> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">Lemon
<tr> Squeezy LLC</span>
<td class="notes_td title" align="left">Payment Method:</td> </td>
<td class="notes_td title" align="left">Notes:</td> </tr>
</tr> <tr>
<tr> <td align="left" style="width: 50%;">
<td class="notes_td" align="left">{{payment_method}}</td> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">{{city}} {{state}} {{zip_code}}</span>
<td class="notes_td notes" align="left" rowspan="2">{{notes}}</td> </td>
</tr> <td align="left" style="width: 50%;">
<tr> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">Lemon
<td class="notes_td" align="left">Account No. {{account_number}}</td> Squeezy LLC</span>
</tr> </td>
</table> </tr>
<tr>
<td align="left" style="width: 50%;">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;"> </span>
</td>
<td align="left" style="width: 50%;">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block; line-height: 42px;">Lemon
Squeezy LLC</span>
</td>
</tr>
<tr height="30px"></tr>
</table>
<!-- bill -->
<table border="0" align="center" cellpadding="0" cellspacing="0" width="100%"
style="background-color: #F8F8FA;padding: 0 5%;">
<tr>
<td align="left" style="width: 50%;">
<span
style="color: #212121;font-weight: bold;font-size: 22px; display: block; line-height: 70px;">Product
Name</span>
</td>
<td align="left" style="width: 16.66%;">
<span style="color: #212121;font-weight: bold;font-size: 22px; display: block; line-height: 70px;">Unit
Price</span>
</td>
<td align="center" style="width: 16.66%;">
<span
style="color: #212121;font-weight: bold;font-size: 22px; display: block; line-height: 70px;">Quantity</span>
</td>
<td align="right" style="width: 16.66%;">
<span
style="color: #212121;font-weight: bold;font-size: 22px; display: block; line-height: 70px;">Total</span>
</td>
</tr>
</table>
<table border="0" align="center" cellpadding="0" cellspacing="0" width="100%"
style="background-color: #fff;padding: 0 5%;">
<tr height="30px"></tr>
{{orderHTML}}
<tr>
<td align="left" colspan="2">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">Subtotal</span>
</td>
<td align="right" style="width: 16.66%;">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">${{total_amount}}</span>
</td>
</tr>
<tr height="15px"></tr>
<tr>
<td align="left" colspan="2">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">Tax</span>
</td>
<td align="right" style="width: 16.66%;">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">$0.00</span>
</td>
</tr>
<tr height="15px"></tr>
<tr>
<td align="left" colspan="2">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">Invoice Total</span>
</td>
<td align="right" style="width: 16.66%;">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">${{total_amount}}</span>
</td>
</tr>
<tr height="15px"></tr>
<tr>
<td align="left" colspan="2" {{first_style1}}>
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">First Payment</span>
</td>
<td align="right" {{first_style2}}>
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">-${{first_payment}}</span>
</td>
</tr>
<tr height="15px"></tr>
{{second_payment_html}}
<tr height="15px"></tr>
<tr>
<td align="left" colspan="2">
<span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Amount Due</span>
</td>
<td align="right" style="width: 16.66%;">
<span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">${{amount_due}}</span>
</td>
</tr>
<tr height="88px"></tr>
<tr>
<td align="left" colspan="4">
<span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Payment Method:</span>
</td>
</tr>
{{pay_html}}
<tr height="30px"></tr>
<tr>
<td align="left" colspan="4">
<span style="color: #212121;font-weight: bold;font-size: 24px; display: block;">Notes:</span>
</td>
</tr>
<tr height="15px"></tr>
<tr>
<td align="left" colspan="4">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">Add a note...</span>
</td>
</tr>
<!-- <tr height="80px"></tr> -->
</table>
</body> </body>
</html> </html>`
` // 发票支付html模板
const PAYMENT_HTML = `<tr height="15px"></tr>
<tr>
<td align="left" colspan="4">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">${{pay_amount}} payment from {{brand}}
····{{card_no}}</span>
</td>
</tr>`
// 产品循环部分{{product_loop_html}} // 二次支付html
const PRODUCT_LOOP_HTML_CONTENT = ` <tr> const SECOND_PAYMENY_HTML = `<tr>
<td class="bill_td title" align="left">{{product_name}}</td> <td align="left" colspan="2" style="padding-bottom: 20px; border-bottom: 1px solid #212121;">
<td class="bill_td title" align="right">${{product_item_price}}</td> <span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">Second Payment</span>
<td class="bill_td title" align="right">{{purchase_quantity}}</td> </td>
<td class="bill_td title" align="right">${{product_total_price}}</td> <td align="right" style="width: 16.66%; padding-bottom: 20px; border-bottom: 1px solid #212121;">
</tr>` <span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">-${{remain_amount}}</span>
</td>
</tr>
<tr height="15px"></tr>`
// order html
const ORDER_HTML = `<tr>
<td align="left" style="width: 50%;{{style1}}" {{rowspan}}">
<span style="color: #212121;font-weight: bold;font-size: 22px; display: block;">{{product_title}}</span>
</td>
<td align="left" style="width: 16.66%;{{style2}}">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">${{amount}}</span>
</td>
<td align="center" style="width: 16.66%;' . $style2 . '">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">{{buy_num}}pcs</span>
</td>
<td align="right" style="width: 16.66%;' . $style2 . '">
<span style="color: #666666;font-weight: 400;font-size: 22px; display: block;">${{sum_amount}}</span>
</td>
</tr>
<tr height="15px"></tr>`

View File

@ -2,8 +2,8 @@ package constants
// 订单类型 // 订单类型
const ( const (
DELIVERYMETHODDIRECTMAIL int64 = 1 // 直邮 DELIVERYMETHODDIRECTMAIL int64 = 1
DELIVERYMETHODDSCLOUDSTORE int64 = 2 // 云仓 DELIVERYMETHODDSCLOUDSTORE int64 = 2
) )
// 货币 // 货币
@ -24,16 +24,16 @@ type PayMethods string
const ( const (
PAY_METHOD_CARD PayMethods = "CARD" PAY_METHOD_CARD PayMethods = "CARD"
PAY_METHOD_VISA PayMethods = "VISA" PayMethodVISA PayMethods = "VISA"
) )
// 支付状态 // 支付状态
type PayStatusCode int64 type PayStatusCode int64
const ( const (
PAY_STATUS_UNPAID PayStatusCode = 10 //10,未支付 PAYSTATUSUNPAID PayStatusCode = 10 //10,未支付
PAY_STATUS_PAID PayStatusCode = 20 //20,已支付 PAYSTATUSPAID PayStatusCode = 20 //20,已支付
PAY_STATUS_REFUNDED PayStatusCode = 30 //30,已退款 PAYSTATUSREFUNDED PayStatusCode = 30 //30,已退款
) )
// 订单支付状态 // 订单支付状态
@ -45,22 +45,18 @@ type OrderPayStatusCode int64
// 30,已付尾款 // 30,已付尾款
// 40,已退尾款 // 40,已退尾款
const ( const (
ORDER_PAY_STATUS_UNPAIDDEPOSIT OrderPayStatusCode = 0 ORDERPAYSTATUSUNPAIDDEPOSIT OrderPayStatusCode = 0
ORDER_PAY_STATUS_PAIDDEPOSIT OrderPayStatusCode = 10 ORDERPAYSTATUSPAIDDEPOSIT OrderPayStatusCode = 10
ORDER_PAY_STATUS_REFUNDEDDEPOSIT OrderPayStatusCode = 20 ORDERPAYSTATUSREFUNDEDDEPOSIT OrderPayStatusCode = 20
ORDER_PAY_STATUS_PAIDDREMAINING OrderPayStatusCode = 30 ORDERPAYSTATUSPAIDDREMAINING OrderPayStatusCode = 30
ORDER_PAY_STATUS_REFUNDEDREMAINING OrderPayStatusCode = 40 ORDERPAYSTATUSREFUNDEDREMAINING OrderPayStatusCode = 40
) )
// 订单状态 // 订单状态
type OrderStatusCode int64 type OrderStatusCode int64
const ( const (
ORDER_STATUS_UNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金 ORDER_STATUS_UNPAIDDEPOSIT OrderStatusCode = 0 // 0,未支付定金
ORDER_STATUS_CLOSE OrderStatusCode = 10 // 10,订单已关闭
ORDER_STATUS_COMPLETE OrderStatusCode = 20 // 20,订单已完成
ORDER_STATUS_DELETE OrderStatusCode = 30 // 20,订单已删除
ORDER_STATUS_DIRECTMAIL_ORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单 ORDER_STATUS_DIRECTMAIL_ORDERED OrderStatusCode = 10100 // 10100,直邮单--已下单
ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING OrderStatusCode = 10100001 // 10100001,直邮单--已下单--尾款 ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING OrderStatusCode = 10100001 // 10100001,直邮单--已下单--尾款
ORDER_STATUS_DIRECTMAIL_CANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消 ORDER_STATUS_DIRECTMAIL_CANCEL OrderStatusCode = 10101 // 10101,直邮单--已取消
@ -68,13 +64,13 @@ const (
ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成 ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION OrderStatusCode = 10300 // 10300,直邮单--生产完成
ORDER_STATUS_DIRECTMAIL_SHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货 ORDER_STATUS_DIRECTMAIL_SHIPPED OrderStatusCode = 10400 // 10400,直邮单--已发货
ORDER_STATUS_DIRECTMAIL_ARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达 ORDER_STATUS_DIRECTMAIL_ARRIVED OrderStatusCode = 10500 // 10500,直邮单--已到达
ORDER_STATUS_CLOUDSTORE_ORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单 ORDER_STATUS_CLOUDSTORE_ORDERED OrderStatusCode = 20100 // 20100,云仓单--已下单
ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING OrderStatusCode = 20100001 // 20100001,云仓单--已下单-尾款 ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING OrderStatusCode = 20100001 // 20100001,云仓单--已下单-尾款
ORDER_STATUS_CLOUDSTORE_CANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消 ORDER_STATUS_CLOUDSTORE_CANCEL OrderStatusCode = 20101 // 20101,云仓单--已取消
ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产 ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION OrderStatusCode = 20200 // 20200,云仓单--开始生产
ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成 ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION OrderStatusCode = 20300 // 20300,云仓单--生产完成
ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库 ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE OrderStatusCode = 20400 // 20400,云仓单--直达仓库
ORDER_STATUS_COMPLETE OrderStatusCode = 30000 // 30000,订单完成
) )
// 订单状态名称 // 订单状态名称
@ -83,9 +79,6 @@ var OrderStatusMessage map[OrderStatusCode]string
// 支付状态名称 // 支付状态名称
var PayStatusMessage map[PayStatusCode]string var PayStatusMessage map[PayStatusCode]string
// 支付状态名称
var OrderPayStatusMessage map[OrderPayStatusCode]string
// 订单状态--用户可见--直邮 // 订单状态--用户可见--直邮
var OrderStatusUserDIRECTMAIL []OrderStatusCode var OrderStatusUserDIRECTMAIL []OrderStatusCode
@ -93,50 +86,37 @@ var OrderStatusUserDIRECTMAIL []OrderStatusCode
var OrderStatusUserCLOUDSTORE []OrderStatusCode var OrderStatusUserCLOUDSTORE []OrderStatusCode
func init() { func init() {
// 订单状态名称
OrderPayStatusMessage = make(map[OrderPayStatusCode]string)
OrderPayStatusMessage[ORDER_PAY_STATUS_UNPAIDDEPOSIT] = "Deposit Payment Unpaid"
OrderPayStatusMessage[ORDER_PAY_STATUS_PAIDDEPOSIT] = "Deposit Payment Paid"
OrderPayStatusMessage[ORDER_PAY_STATUS_REFUNDEDDEPOSIT] = "Deposit Payment Refunded"
OrderPayStatusMessage[ORDER_PAY_STATUS_PAIDDREMAINING] = "Final Payment Paid"
OrderPayStatusMessage[ORDER_PAY_STATUS_REFUNDEDREMAINING] = "Final Payment Refunded"
// 订单状态名称 // 订单状态名称
PayStatusMessage = make(map[PayStatusCode]string) PayStatusMessage = make(map[PayStatusCode]string)
PayStatusMessage[PAY_STATUS_UNPAID] = "Unpaid" PayStatusMessage[PAYSTATUSUNPAID] = "Unpaid"
PayStatusMessage[PAY_STATUS_PAID] = "Paid" PayStatusMessage[PAYSTATUSPAID] = "Paid"
PayStatusMessage[PAY_STATUS_REFUNDED] = "Refunded" PayStatusMessage[PAYSTATUSREFUNDED] = "Refunded"
// 订单状态名称 // 订单状态名称
OrderStatusMessage = make(map[OrderStatusCode]string) OrderStatusMessage = make(map[OrderStatusCode]string)
OrderStatusMessage[ORDER_STATUS_UNPAIDDEPOSIT] = "Deposit Payment Unpaid" // 首款未支付 OrderStatusMessage[ORDER_STATUS_UNPAIDDEPOSIT] = "未支付定金"
OrderStatusMessage[ORDER_STATUS_CLOSE] = "Closed" // 已关闭
OrderStatusMessage[ORDER_STATUS_COMPLETE] = "Completed" // 已完成
OrderStatusMessage[ORDER_STATUS_DELETE] = "Deleted" // 已删除
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ORDERED] = "Order" // 直邮单--已下单 OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ORDERED] = "直邮单--已下单"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING] = "Final Payment Paid" // 直邮单--已下单--尾款 OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION] = "直邮单--开始生产"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION] = "Start Production" // 直邮单--开始生产 OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION] = "直邮单--生产完成"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION] = "Production Complete" // 直邮单--生产完成 OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_SHIPPED] = "直邮单--已发货"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_SHIPPED] = "Shipped" // 直邮单--已发货 OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ARRIVED] = "直邮单--已到达"
OrderStatusMessage[ORDER_STATUS_DIRECTMAIL_ARRIVED] = "Delivered" // 直邮单--已到达
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ORDERED] = "Order" // 云仓单--已下单 OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ORDERED] = "云仓单--已下单"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING] = "Final Payment Paid" // 云仓单--已下单-尾款 OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION] = "云仓单--开始生产"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION] = "Start Production" // 云仓单--开始生产 OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION] = "云仓单--生产完成"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION] = "Production Complete" // 云仓单--生产完成 OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE] = "云仓单--直达仓库"
OrderStatusMessage[ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE] = "Arrived Inventory" // 云仓单--直达仓库
OrderStatusMessage[ORDER_STATUS_COMPLETE] = "订单完成"
// 订单状态--用户可见--直邮 // 订单状态--用户可见--直邮
OrderStatusUserDIRECTMAIL = []OrderStatusCode{ OrderStatusUserDIRECTMAIL = []OrderStatusCode{
ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDER_STATUS_DIRECTMAIL_ORDERED, ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION, ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION, ORDER_STATUS_DIRECTMAIL_SHIPPED, ORDER_STATUS_DIRECTMAIL_ARRIVED, ORDER_STATUS_DIRECTMAIL_ORDERED, ORDER_STATUS_DIRECTMAIL_STARTPRODUCTION, ORDER_STATUS_DIRECTMAIL_COMPLETEPRODUCTION, ORDER_STATUS_DIRECTMAIL_SHIPPED, ORDER_STATUS_DIRECTMAIL_ARRIVED,
ORDER_STATUS_COMPLETE, ORDER_STATUS_CLOSE,
} }
// 订单状态--用户可见--云仓 // 订单状态--用户可见--云仓
OrderStatusUserCLOUDSTORE = []OrderStatusCode{ OrderStatusUserCLOUDSTORE = []OrderStatusCode{
ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_UNPAIDDEPOSIT, ORDER_STATUS_COMPLETE,
ORDER_STATUS_CLOUDSTORE_ORDERED, ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION, ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION, ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE, ORDER_STATUS_CLOUDSTORE_ORDERED, ORDER_STATUS_CLOUDSTORE_STARTPRODUCTION, ORDER_STATUS_CLOUDSTORE_COMPLETEPRODUCTION, ORDER_STATUS_CLOUDSTORE_ARRIVEDWAREHOUSE,
ORDER_STATUS_COMPLETE, ORDER_STATUS_CLOSE,
} }
} }

View File

@ -1,5 +0,0 @@
package constants
const (
QUEUE_NAME_ORDER = "queue_order"
)

View File

@ -4,9 +4,12 @@ type Websocket string
// websocket消息类型(主类别) // websocket消息类型(主类别)
const ( const (
WEBSOCKET_UNAUTH Websocket = "WEBSOCKET_UNAUTH" //鉴权失败 1级消息单向通信 WEBSOCKET_UNAUTH Websocket = "WEBSOCKET_UNAUTH" //鉴权失败 1级消息单向通信
WEBSOCKET_CONNECT_ERR Websocket = "WEBSOCKET_CONNECT_ERR" //ws连接错误 1级消息单向通信 WEBSOCKET_CONNECT_ERR Websocket = "WEBSOCKET_CONNECT_ERR" //ws连接错误 1级消息单向通信
WEBSOCKET_CONNECT_SUCCESS Websocket = "WEBSOCKET_CONNECT_SUCCESS" //ws连接成功 1级消息单向通信 WEBSOCKET_CONNECT_SUCCESS Websocket = "WEBSOCKET_CONNECT_SUCCESS" //ws连接成功 1级消息单向通信
WEBSOCKET_REQUEST_REUSE_LAST_CONNECT Websocket = "WEBSOCKET_REQUEST_REUSE_LAST_CONNECT" //请求恢复为上次连接的标识 1级消息单向通信
WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR Websocket = "WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR" //请求恢复为上次连接的标识错误 1级消息单向通信
WEBSOCKET_INCOME_CACHE_QUEUE_OVERFLOW = "WEBSOCKET_INCOME_CACHE_QUEUE_OVERFLOW" //数据接收速度超过数据消费速度缓冲队列满了1级消息单向通信
) )
// websocket消息类型(通用通知类别) // websocket消息类型(通用通知类别)

View File

@ -2,22 +2,14 @@
name=${1%%\\*} name=${1%%\\*}
#进入对应服务目录 #进入对应服务目录
cd server/$name cd server/$name
#把https加密密钥对复制进来
cp /opt/env.yaml ./
cp /opt/server.fusen.3718.cn.pem ./
cp /opt/server.fusen.3718.cn.key ./
#构建二进制文件 #构建二进制文件
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./bin/api-$name-srv ./$name.go CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./bin/api-$name-srv ./$name.go
#删除之前旧的镜像
docker rmi -f api-$name-srv:latest
docker rmi -f registry.cn-hangzhou.aliyuncs.com/fusen-test/fusen_docker_hub:latest
#打包docker镜像 #打包docker镜像
docker build -t api-$name-srv:latest . docker build -t api-$name-srv:latest .
#删除临时复制进来的文件
rm ./env.yaml
rm ./server.fusen.3718.cn.pem
rm ./server.fusen.3718.cn.key
#打tag(测试环境正式把命名空间fusentest改成fusen) #打tag(测试环境正式把命名空间fusentest改成fusen)
docker tag api-$name-srv:latest registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest docker tag api-$name-srv:latest registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest
#推送到阿里云镜像库(测试环境正式把命名空间fusentest改成fusen) #推送到阿里云镜像库(测试环境正式把命名空间fusentest改成fusen)
docker push registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest docker push registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest
#上传了的镜像
docker rmi -f api-$name-srv:latest
docker rmi -f registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest

2
go.mod
View File

@ -98,9 +98,11 @@ require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.15.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect

13
go.sum
View File

@ -48,6 +48,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EF
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
@ -67,6 +68,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
@ -137,6 +140,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -159,6 +164,7 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk= github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk=
@ -183,6 +189,8 @@ github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@ -438,12 +446,15 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@ -574,6 +585,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
github.com/zeromicro/go-zero v1.5.4 h1:kRvcYuxcHOkUZvg7887KQl77Qv4klGL7MqGkTBgkpS8= github.com/zeromicro/go-zero v1.5.4 h1:kRvcYuxcHOkUZvg7887KQl77Qv4klGL7MqGkTBgkpS8=
github.com/zeromicro/go-zero v1.5.4/go.mod h1:x/aUyLmSwRECvOyjOf+lhwThBOilJIY+s3slmPAeboA= github.com/zeromicro/go-zero v1.5.4/go.mod h1:x/aUyLmSwRECvOyjOf+lhwThBOilJIY+s3slmPAeboA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -990,6 +1002,7 @@ gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -1,14 +0,0 @@
package initalize
import (
"fusenapi/utils/queue"
)
// 初始化
func InitDelayMessage() *queue.DelayMessage {
//创建延迟消息
dm := queue.NewDelayMessage()
go dm.Start()
return dm
}

View File

@ -2,7 +2,6 @@ package initalize
import ( import (
"fusenapi/service/repositories" "fusenapi/service/repositories"
"fusenapi/utils/queue"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"gorm.io/gorm" "gorm.io/gorm"
@ -16,17 +15,16 @@ type Repositories struct {
} }
type NewAllRepositorieData struct { type NewAllRepositorieData struct {
GormDB *gorm.DB GormDB *gorm.DB
BLMServiceUrls []string BLMServiceUrl *string
AwsSession *session.Session AwsSession *session.Session
DelayQueue *queue.DelayMessage
} }
func NewAllRepositories(newData *NewAllRepositorieData) *Repositories { func NewAllRepositories(newData *NewAllRepositorieData) *Repositories {
return &Repositories{ return &Repositories{
ImageHandle: repositories.NewImageHandle(newData.GormDB, newData.BLMServiceUrls, newData.AwsSession), ImageHandle: repositories.NewImageHandle(newData.GormDB, newData.BLMServiceUrl, newData.AwsSession),
NewShoppingCart: repositories.NewShoppingCart(newData.GormDB, newData.BLMServiceUrls, newData.AwsSession), NewShoppingCart: repositories.NewShoppingCart(newData.GormDB, newData.BLMServiceUrl, newData.AwsSession),
NewResource: repositories.NewResource(newData.GormDB, newData.BLMServiceUrls, newData.AwsSession), NewResource: repositories.NewResource(newData.GormDB, newData.BLMServiceUrl, newData.AwsSession),
NewOrder: repositories.NewOrder(newData.GormDB, newData.AwsSession, newData.DelayQueue), NewOrder: repositories.NewOrder(newData.GormDB, newData.BLMServiceUrl, newData.AwsSession),
} }
} }

View File

@ -4,16 +4,15 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// casbin_rule 后台--权限规则表 // casbin_rule
type CasbinRule struct { type CasbinRule struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // 序号 PType *string `gorm:"default:'';" json:"p_type"` //
PType *string `gorm:"default:'';" json:"p_type"` // V0 *string `gorm:"default:'';" json:"v0"` //
V0 *string `gorm:"default:'';" json:"v0"` // V1 *string `gorm:"default:'';" json:"v1"` //
V1 *string `gorm:"default:'';" json:"v1"` // V2 *string `gorm:"default:'';" json:"v2"` //
V2 *string `gorm:"default:'';" json:"v2"` // V3 *string `gorm:"default:'';" json:"v3"` //
V3 *string `gorm:"default:'';" json:"v3"` // V4 *string `gorm:"default:'';" json:"v4"` //
V4 *string `gorm:"default:'';" json:"v4"` // V5 *string `gorm:"default:'';" json:"v5"` //
V5 *string `gorm:"default:'';" json:"v5"` //
} }
type CasbinRuleModel struct { type CasbinRuleModel struct {
db *gorm.DB db *gorm.DB

View File

@ -7,21 +7,23 @@ import (
// fs_address 用户地址表 // fs_address 用户地址表
type FsAddress struct { type FsAddress struct {
AddressId int64 `gorm:"primary_key;default:0;auto_increment;" json:"address_id"` // AddressId int64 `gorm:"primary_key;default:0;auto_increment;" json:"address_id"` //
UserId *int64 `gorm:"default:0;" json:"user_id"` // 用户ID UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID
FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName AddressName *string `gorm:"default:'';" json:"address_name"` //
LastName *string `gorm:"default:'';" json:"last_name"` // LastName FirstName *string `gorm:"default:'';" json:"first_name"` // FirstName
Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码 LastName *string `gorm:"default:'';" json:"last_name"` // LastName
Street *string `gorm:"default:'';" json:"street"` // 街道 Mobile *string `gorm:"default:'';" json:"mobile"` // 手机号码
Suite *string `gorm:"default:'';" json:"suite"` // 房号 Street *string `gorm:"default:'';" json:"street"` // 街道
City *string `gorm:"default:'';" json:"city"` // 城市 Suite *string `gorm:"default:'';" json:"suite"` // 房号
State *string `gorm:"default:'';" json:"state"` // City *string `gorm:"default:'';" json:"city"` // 城市
Country *string `gorm:"default:'';" json:"country"` // State *string `gorm:"default:'';" json:"state"` //
ZipCode *string `gorm:"default:'';" json:"zip_code"` // Country *string `gorm:"default:'';" json:"country"` //
Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常 ZipCode *string `gorm:"default:'';" json:"zip_code"` //
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // 创建时间 Status *int64 `gorm:"default:0;" json:"status"` // 1正常 0异常
Utime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"utime"` // 更新时间 IsDefault *int64 `gorm:"index;default:0;" json:"is_default"` // 1默认地址0非默认地址
Ltime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ltime"` // 上次被使用的时间 Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // 创建时间
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // 更新时间
Ltime *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"ltime"` // 上次被使用的时间
} }
type FsAddressModel struct { type FsAddressModel struct {
db *gorm.DB db *gorm.DB

View File

@ -13,30 +13,11 @@ func (a *FsAddressModel) GetOne(ctx context.Context, addressId int64, userId int
return resp, err return resp, err
} }
func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (resp []*FsAddressWithDefault, err error) { func (a *FsAddressModel) GetUserAllAddress(ctx context.Context, userId int64) (resp []FsAddress, err error) {
resp = make([]*FsAddressWithDefault, 0) err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = ?", userId, 1).Order("`ltime` DESC").Find(&resp).Error
var dbresp []*FsAddress
err = a.db.WithContext(ctx).Model(&FsAddress{}).Where("`user_id` = ? and `status` = 1", userId).Order("`ltime` DESC").Find(&dbresp).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
now := time.Now().UTC().AddDate(10, 0, 0).Unix()
for _, r := range dbresp {
rd := &FsAddressWithDefault{
FsAddress: r,
}
if r.Ltime.UTC().Unix() > now {
rd.IsDefault = 1
} else {
rd.IsDefault = 0
}
resp = append(resp, rd)
}
return return
} }
@ -45,21 +26,38 @@ func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (res
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error { err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
now := time.Now().UTC() now := time.Now().UTC()
result = &FsAddress{ result = &FsAddress{
UserId: address.UserId, UserId: address.UserId,
FirstName: address.FirstName, AddressName: address.AddressName,
LastName: address.LastName, FirstName: address.FirstName,
Mobile: address.Mobile, LastName: address.LastName,
Street: address.Street, Mobile: address.Mobile,
Suite: address.Suite, Street: address.Street,
City: address.City, Suite: address.Suite,
State: address.State, City: address.City,
Country: address.Country, State: address.State,
ZipCode: address.ZipCode, Country: address.Country,
Status: address.Status, ZipCode: address.ZipCode,
Ctime: &now, Status: address.Status,
Utime: &now, IsDefault: address.IsDefault,
Ltime: &now, Ctime: &now,
Utime: &now,
Ltime: &now,
} }
// lastOne := &FsAddress{}
// err = tx.Where("user_id = ?", lastOne.UserId).Order("ltime ASC").Take(&lastOne).Error
// if err == gorm.ErrRecordNotFound {
// result.Ltime = &now
// return tx.Model(&FsAddress{}).Create(result).Error
// }
// if err != nil {
// return err
// }
// // 根据lastOne处理时间
// ltime := (*lastOne.Ltime).Add(-time.Second)
// result.Ltime = &ltime
return tx.Model(&FsAddress{}).Create(result).Error return tx.Model(&FsAddress{}).Create(result).Error
}) })
@ -73,7 +71,7 @@ func (a *FsAddressModel) CreateOne(ctx context.Context, address *FsAddress) (res
func (a *FsAddressModel) UpdateAddress(ctx context.Context, address *FsAddress) (err error) { func (a *FsAddressModel) UpdateAddress(ctx context.Context, address *FsAddress) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error { err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
err = tx. err = tx.
Where("address_id = ? and user_id = ? and status = 1 ", address.AddressId, address.UserId). Where("user_id = ? and address_id = ? and status = 1 ", address.UserId, address.AddressId).
Updates(address).Error Updates(address).Error
if err != nil { if err != nil {
return err return err
@ -83,64 +81,34 @@ func (a *FsAddressModel) UpdateAddress(ctx context.Context, address *FsAddress)
return err return err
} }
func (a *FsAddressModel) SettingUserDefaultAddress(ctx context.Context, userId int64, addressId int64, isDefault int64) (err error) { func (a *FsAddressModel) SettingUserDefaultAddress(ctx context.Context, userId int64, addressId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error { err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
logx.Info("address_id:", addressId, " set default ", isDefault)
now := time.Now().UTC() now := time.Now().UTC()
var updates = map[string]interface{}{
"ltime": now,
"utime": now,
}
if isDefault == 1 { err = tx.Model(&FsAddress{}).Where(" `user_id` = ? and `status` = ? and `address_id` = ? ", userId, 1, addressId).
err = tx.Where("`user_id` = ? and `status` = 1 and `ltime` > ? and `address_id` != ?", userId, now.AddDate(10, 0, 0), addressId). UpdateColumn("ltime", now.AddDate(250, 0, 0)).
UpdateColumns(updates).Error UpdateColumn("utime", now).Error
if err != nil {
return err
}
updates["ltime"] = now.AddDate(250, 0, 0)
}
tr := tx.Model(&FsAddress{}).Where("`address_id` = ? and `user_id` = ? and `status` = 1", addressId, userId).
UpdateColumns(updates)
err = tr.Error
if err != nil { if err != nil {
return err return err
} }
err = tx.Where(" `user_id` = ? and `status` = ? and `address_id` != ? and `ltime` > ? ", userId, 1, addressId, now.AddDate(10, 0, 0)).
UpdateColumn("ltime", now).Error
if err != nil {
logx.Error(err)
}
return nil return nil
}) })
return err return
} }
func (a *FsAddressModel) DeleteOne(ctx context.Context, addressId int64, userId int64) (err error) { func (a *FsAddressModel) DeleteOne(ctx context.Context, addressId int64, userId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}). err = a.db.WithContext(ctx).Model(&FsAddress{}).
Where("`address_id` = ? and `user_id` = ? and `status` = 1 ", addressId, userId). Where("`address_id` = ? and `user_id` = ? and `status` = ? ", addressId, userId, 1).
UpdateColumn("status", 0).Error UpdateColumn("status", 0).Error
return err return err
} }
// UpdateUsedAddress 当每次订单成功后, 更新一次地址使用时间
func (a *FsAddressModel) UpdateUsedAddress(ctx context.Context, addressId int64, userId int64) (err error) {
err = a.db.WithContext(ctx).Model(&FsAddress{}).Transaction(func(tx *gorm.DB) error {
logx.Info("address_id:", addressId, " update used")
now := time.Now().UTC()
var updates = map[string]interface{}{
"ltime": now,
"utime": now,
}
err = tx.Where("`address_id` = ? and `user_id` = ? and `status` = 1", addressId, userId).
UpdateColumns(updates).Error
if err != nil {
return err
}
return nil
})
return err
}

View File

@ -20,7 +20,6 @@ type FsAdminApi struct {
UpdateUid *int64 `gorm:"default:0;" json:"update_uid"` // 更新人 UpdateUid *int64 `gorm:"default:0;" json:"update_uid"` // 更新人
DeleteUid *int64 `gorm:"default:0;" json:"delete_uid"` // 删除人 DeleteUid *int64 `gorm:"default:0;" json:"delete_uid"` // 删除人
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除1=是 0=否 IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除1=是 0=否
Method *int64 `gorm:"default:0;" json:"method"` // 接口方法
} }
type FsAdminApiModel struct { type FsAdminApiModel struct {
db *gorm.DB db *gorm.DB

View File

@ -32,7 +32,6 @@ type FsAdminMenu struct {
UpdateUid *int64 `gorm:"default:0;" json:"update_uid"` // 更新人 UpdateUid *int64 `gorm:"default:0;" json:"update_uid"` // 更新人
DeleteUid *int64 `gorm:"default:0;" json:"delete_uid"` // 删除人 DeleteUid *int64 `gorm:"default:0;" json:"delete_uid"` // 删除人
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除1=是 0=否 IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除1=是 0=否
ApiAuth *[]byte `gorm:"default:'';" json:"api_auth"` //
} }
type FsAdminMenuModel struct { type FsAdminMenuModel struct {
db *gorm.DB db *gorm.DB

View File

@ -1,23 +0,0 @@
package gmodel
import (
"gorm.io/gorm"
)
// fs_admin_role_api 后台--角色接口表
type FsAdminRoleApi struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // 序号
RoleId *int64 `gorm:"index;default:0;" json:"role_id"` // 角色ID
MenuId *int64 `gorm:"index;default:0;" json:"menu_id"` // 菜单ID
ApiId *int64 `gorm:"index;default:0;" json:"api_id"` // 接口ID
ApiPath *string `gorm:"default:'';" json:"api_path"` //
ApiMethod *int64 `gorm:"default:0;" json:"api_method"` // 接口方法
}
type FsAdminRoleApiModel struct {
db *gorm.DB
name string
}
func NewFsAdminRoleApiModel(db *gorm.DB) *FsAdminRoleApiModel {
return &FsAdminRoleApiModel{db: db, name: "fs_admin_role_api"}
}

View File

@ -1,2 +0,0 @@
package gmodel
// TODO: 使用model的属性做你想做的

View File

@ -2,20 +2,18 @@ package gmodel
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"time"
) )
// fs_contact 该表暂未使用 // fs_contact 该表暂未使用
type FsContact struct { type FsContact struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` //
Name *string `gorm:"default:'';" json:"name"` // Name *string `gorm:"default:'';" json:"name"` // 名字
Email *string `gorm:"index;default:'';" json:"email"` // 邮箱 Email *string `gorm:"index;default:'';" json:"email"` // 邮箱
Subject *string `gorm:"default:'0';" json:"subject"` // 主题 Subject *int64 `gorm:"default:0;" json:"subject"` // 主题
Message *string `gorm:"default:'';" json:"message"` // 消息 Message *string `gorm:"default:'';" json:"message"` // 消息
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
Status *int64 `gorm:"default:0;" json:"status"` // 状态位 是否已处理 Status *int64 `gorm:"default:0;" json:"status"` // 状态位 是否已处理
Mark *string `gorm:"default:'';" json:"mark"` // 后台订单备注 Mark *string `gorm:"default:'';" json:"mark"` // 后台订单备注
Phone *string `gorm:"default:'';" json:"phone"` //
} }
type FsContactModel struct { type FsContactModel struct {
db *gorm.DB db *gorm.DB

View File

@ -1,9 +1,3 @@
package gmodel package gmodel
import "context"
// TODO: 使用model的属性做你想做的 // TODO: 使用model的属性做你想做的
func (contact *FsContactModel) Save(ctx context.Context, obj *FsContact) (err error) {
return contact.db.WithContext(ctx).Model(&FsContact{}).Create(obj).Error
}

View File

@ -32,16 +32,7 @@ func (m *FsGuestModel) GenerateGuestID(ctx context.Context, AccessSecret uint64)
logx.Error(err) logx.Error(err)
return err return err
} }
return nil
uinfo := &FsUserInfo{
Module: FsString("profile"),
UserId: FsInt64(0),
GuestId: &record.GuestId,
Metadata: FsBytes("{}"),
Ctime: &now,
Utime: &now,
}
return tx.Model(FsUserInfo{}).Create(uinfo).Error
}) })
if err != nil { if err != nil {

View File

@ -7,24 +7,17 @@ import (
// fs_order 订单表 // fs_order 订单表
type FsOrder struct { type FsOrder struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // 订单ID Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // 订单ID
UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户ID
DeliveryMethod *int64 `gorm:"index;default:0;" json:"delivery_method"` // 物流类型 DeliveryMethod *int64 `gorm:"index;default:0;" json:"delivery_method"` // 物流类型
OrderSn *string `gorm:"unique_key;default:'';" json:"order_sn"` // OrderSn *string `gorm:"unique_key;default:'';" json:"order_sn"` //
OrderSource *string `gorm:"default:'';" json:"order_source"` // OrderSource *string `gorm:"default:'';" json:"order_source"` //
Status *int64 `gorm:"index;default:0;" json:"status"` // 订单状态 Status *int64 `gorm:"index;default:0;" json:"status"` // 订单状态
Metadata *[]byte `gorm:"default:'';" json:"metadata"` // Metadata *[]byte `gorm:"default:'';" json:"metadata"` //
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除0=否1=是 IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除0=否1=是
PayStatus *int64 `gorm:"default:0;" json:"pay_status"` // 支付状态 PayStatus *int64 `gorm:"default:0;" json:"pay_status"` // 支付状态
StatusLink *[]byte `gorm:"default:'';" json:"status_link"` //
OrderProduct *[]byte `gorm:"default:'';" json:"order_product"` //
OrderAddress *[]byte `gorm:"default:'';" json:"order_address"` //
OrderAmount *[]byte `gorm:"default:'';" json:"order_amount"` //
PayStatusLink *[]byte `gorm:"default:'';" json:"pay_status_link"` //
ShoppingCartSnapshot *[]byte `gorm:"default:'';" json:"shopping_cart_snapshot"` //
ShoppingProductSnapshot *[]byte `gorm:"default:'';" json:"shopping_product_snapshot"` //
} }
type FsOrderModel struct { type FsOrderModel struct {
db *gorm.DB db *gorm.DB

View File

@ -73,14 +73,13 @@ type PayStatus struct {
// 订单信息 // 订单信息
type OrderInfo struct { type OrderInfo struct {
UserId int64 `json:"user_id"` // 物流类型 Ctime *time.Time `json:"ctime"` // 创建日期
Ctime *time.Time `json:"ctime"` // 创建日期 DeliveryMethod int64 `json:"delivery_method"` // 物流类型
DeliveryMethod int64 `json:"delivery_method"` // 物流类型 Metadata map[string]interface{} `json:"metadata"` // 额外参数
Metadata OrderMetadata `json:"metadata"` // 额外参数 OrderSn string `json:"order_sn"` // 订单编号
OrderSn string `json:"order_sn"` // 订单编号 Status OrderStatus `json:"status"` // 当前状态
Status OrderStatus `json:"status"` // 当前状态 StatusLink []OrderStatus `json:"status_link"` // 状态链路
StatusLink []OrderStatus `json:"status_link"` // 状态链路 Utime *time.Time `json:"utime"` // 更新时间
Utime *time.Time `json:"utime"` // 更新时间
} }
// 订单状态--用户 // 订单状态--用户
@ -96,24 +95,21 @@ type OrderStatus struct {
// 订单商品 // 订单商品
type OrderProduct struct { type OrderProduct struct {
TotalPrice AmountInfo `json:"total_price"` // 商品总价 TotalPrice AmountInfo `json:"total_price"` // 商品总价
ItemPrice AmountInfo `json:"item_price"` // 商品单价 ExpectedDeliveryTime *time.Time `json:"expected_delivery_time"` // 预计到货时间
ExpectedDeliveryTime *time.Time `json:"expected_delivery_time"` // 预计到货时间 PurchaseQuantity PurchaseQuantity `json:"purchase_quantity"` // 购买数量
PurchaseQuantity PurchaseQuantity `json:"purchase_quantity"` // 购买数量 ProductID int64 `json:"product_id"` // 商品ID
ProductId int64 `json:"product_id"` // 商品ID ProductName string `json:"product_name"` // 商品名称
ProductSn string `json:"product_sn"` // 商品编码 ItemPrice AmountInfo `json:"item_price"` // 商品单价
ProductName string `json:"product_name"` // 商品名称 ProductSnapshot interface{} `json:"product_snapshot"` // 商品快照
ProductCover string `json:"product_cover"` // 商品封面 ShoppingCartSnapshot *FsShoppingCartData `json:"shopping_cart_snapshot"` // 购物车快照
ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面 ProductCover string `json:"product_cover"` // 商品封面
ProductSnapshot interface{} `json:"product_snapshot"` // 商品快照 ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面
ShoppingCartSnapshot *FsShoppingCartData `json:"shopping_cart_snapshot"` // 购物车快照 ProductSn string `json:"product_sn"` // 商品编码
DiyInformation *UserDiyInformation `json:"diy_information"`
DiyInformation *UserDiyInformation `json:"diy_information"` SizeInfo *OrderProductSizeInfo `json:"size_info"`
SizeInfo *OrderProductSizeInfo `json:"size_info"` FittingInfo *OrderProductFittingInfo `json:"fitting_info"`
FittingInfo *OrderProductFittingInfo `json:"fitting_info"` IsHighlyCustomized int64 `json:"is_highly_customized"`
IsHighlyCustomized int64 `json:"is_highly_customized"`
RenderImage string `json:"render_image"`
SelectColorIndex int64 `json:"select_color_index"`
} }
type PurchaseQuantity struct { type PurchaseQuantity struct {
Current interface{} `json:"current"` Current interface{} `json:"current"`
@ -135,31 +131,3 @@ type OrderProductFittingInfo struct {
FittingID int64 `json:"fitting_id"` //配件ID FittingID int64 `json:"fitting_id"` //配件ID
FittingName string `json:"fitting_name"` //配件名称 FittingName string `json:"fitting_name"` //配件名称
} }
type ExpectedDelivery struct {
Current time.Time `json:"current"`
Initiate time.Time `json:"initiate"`
}
type OrderProductInter struct {
CartId int64 `json:"cart_id"` // 购物车ID
TotalPrice AmountInfo `json:"total_price"` // 商品总价
ItemPrice AmountInfo `json:"item_price"` // 商品单价
PurchaseQuantity *PurchaseQuantity `json:"purchase_quantity"` // 购买数量
ProductId int64 `json:"product_id"` // 商品ID
ProductName string `json:"product_name"` // 商品名称
ProductCover string `json:"product_cover"` // 商品封面
ProductCoverMetadata map[string]interface{} `json:"product_cover_metadata"` // 商品封面
ProductSn string `json:"product_sn"` // 商品编码
DiyInformation *UserDiyInformation `json:"diy_information"`
SizeInfo *OrderProductSizeInfo `json:"size_info"`
FittingInfo *OrderProductFittingInfo `json:"fitting_info"`
IsHighlyCustomized int64 `json:"is_highly_customized"`
RenderImage string `json:"render_image"`
ExpectedDeliveryTime *ExpectedDelivery `json:"expected_delivery_time"` // 预计到货时间
ActualDeliveryTime *ExpectedDelivery `json:"actual_delivery_time"` // 实际到货时间
}
type OrderMetadata struct {
ExpectedDeliveryTime *ExpectedDelivery `json:"expected_delivery_time"` // 预计到货时间
ActualDeliveryTime *ExpectedDelivery `json:"actual_delivery_time"` // 实际到货时间
}

View File

@ -1,27 +0,0 @@
package gmodel
import (
"gorm.io/gorm"
"time"
)
// fs_product_collection 产品收藏表
type FsProductCollection struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
UserId *int64 `gorm:"default:0;" json:"user_id"` // 用户id
GuestId *int64 `gorm:"default:0;" json:"guest_id"` // 游客id
ProductId *int64 `gorm:"default:0;" json:"product_id"` // 产品id
TemplateTag *string `gorm:"default:'';" json:"template_tag"` //
SelectColorIndex *int64 `gorm:"default:0;" json:"select_color_index"` // 选择的颜色索引
Logo *string `gorm:"default:'';" json:"logo"` // logo地址
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
}
type FsProductCollectionModel struct {
db *gorm.DB
name string
}
func NewFsProductCollectionModel(db *gorm.DB) *FsProductCollectionModel {
return &FsProductCollectionModel{db: db, name: "fs_product_collection"}
}

View File

@ -1,52 +0,0 @@
package gmodel
import "context"
// 查询
func (c *FsProductCollectionModel) FindOne(ctx context.Context, userId, guestId, productId int64) (resp *FsProductCollection, err error) {
err = c.db.WithContext(ctx).Model(&FsProductCollection{}).
Where("user_id = ? and guest_id = ? and product_id = ?", userId, guestId, productId).
Take(&resp).Error
return resp, err
}
// 创建
func (c *FsProductCollectionModel) Create(ctx context.Context, data *FsProductCollection) error {
return c.db.WithContext(ctx).Model(&FsProductCollection{}).Create(&data).Error
}
// 更新
func (c *FsProductCollectionModel) Update(ctx context.Context, userId, guestId, productId int64, data *FsProductCollection) error {
return c.db.WithContext(ctx).Model(&FsProductCollection{}).
Where("user_id = ? and guest_id = ? and product_id = ?", userId, guestId, productId).
Updates(&data).Error
}
// 删除
func (c *FsProductCollectionModel) Delete(ctx context.Context, userId, guestId, productId int64) error {
return c.db.WithContext(ctx).Model(&FsProductCollection{}).
Where("user_id = ? and guest_id = ? and product_id = ?", userId, guestId, productId).
Delete(&FsProductCollection{}).Error
}
// 删除
func (c *FsProductCollectionModel) Delete2(ctx context.Context, userId, guestId, id int64) error {
return c.db.WithContext(ctx).Model(&FsProductCollection{}).
Where("user_id = ? and guest_id = ? and id = ?", userId, guestId, id).
Delete(&FsProductCollection{}).Error
}
// 获取列表
func (c *FsProductCollectionModel) GetList(ctx context.Context, userId, guestId int64, page, limit int, sort string) (resp []FsProductCollection, total int64, err error) {
db := c.db.WithContext(ctx).Model(&FsProductCollection{}).
Where("user_id = ? and guest_id = ?", userId, guestId)
if sort != "" {
db = db.Order(sort)
}
if err = db.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * limit
err = db.Offset(offset).Limit(limit).Find(&resp).Error
return resp, total, err
}

View File

@ -11,11 +11,11 @@ type FsProduct struct {
Type *int64 `gorm:"default:0;" json:"type"` // 分类ID Type *int64 `gorm:"default:0;" json:"type"` // 分类ID
Title *string `gorm:"default:'';" json:"title"` // 名称 Title *string `gorm:"default:'';" json:"title"` // 名称
TitleCn *string `gorm:"default:'';" json:"title_cn"` // 中文名称 TitleCn *string `gorm:"default:'';" json:"title_cn"` // 中文名称
Sort *int64 `gorm:"default:0;" json:"sort"` // 排序
Cover *string `gorm:"default:'';" json:"cover"` // 封面图 Cover *string `gorm:"default:'';" json:"cover"` // 封面图
Imgs *string `gorm:"default:'';" json:"imgs"` // 一个或多个介绍图或视频 Imgs *string `gorm:"default:'';" json:"imgs"` // 一个或多个介绍图或视频
Keywords *string `gorm:"default:'';" json:"keywords"` // 关键字 Keywords *string `gorm:"default:'';" json:"keywords"` // 关键字
Intro *string `gorm:"default:'';" json:"intro"` // 简要描述 Intro *string `gorm:"default:'';" json:"intro"` // 简要描述
Sort *int64 `gorm:"default:0;" json:"sort"` // 排序
SelledNum *int64 `gorm:"default:0;" json:"selled_num"` // 已卖数量 SelledNum *int64 `gorm:"default:0;" json:"selled_num"` // 已卖数量
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间 Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
View *int64 `gorm:"default:0;" json:"view"` // 浏览量 View *int64 `gorm:"default:0;" json:"view"` // 浏览量

View File

@ -4,7 +4,7 @@ import "context"
type RelaFsProduct struct { type RelaFsProduct struct {
FsProduct FsProduct
CoverResource *FsResource `json:"cover_resource" gorm:"foreignkey:cover;references:resource_url"` CoverResource *FsResource `json:"cover_resource" gorm:"foreignkey:cover;references:resource_id"`
} }
func (m *FsProductModel) TableName() string { func (m *FsProductModel) TableName() string {

View File

@ -23,7 +23,7 @@ type FsProductModel3d struct {
Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除 Status *int64 `gorm:"default:0;" json:"status"` // 状态位 显示 删除
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板 OptionTemplate *int64 `gorm:"default:0;" json:"option_template"` // 配件绑定的公共模板
Price *int64 `gorm:"default:0;" json:"price"` // 仅配件用,配件的价格, 单位0.1美分 Price *int64 `gorm:"default:0;" json:"price"` //
Sku *string `gorm:"default:'';" json:"sku"` // sku Sku *string `gorm:"default:'';" json:"sku"` // sku
IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门 IsHot *int64 `gorm:"default:0;" json:"is_hot"` // 是否热门
IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型 IsCloudRender *int64 `gorm:"default:0;" json:"is_cloud_render"` // 是否设置为云渲染模型

View File

@ -2,11 +2,6 @@ package gmodel
import ( import (
"context" "context"
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"sort"
) )
// 阶梯价结构 // 阶梯价结构
@ -157,72 +152,3 @@ func (d *FsProductModel3dModel) FindOneByProductIdSizeIdTag(ctx context.Context,
err = db.Take(&resp).Error err = db.Take(&resp).Error
return resp, err return resp, err
} }
func (d *FsProductModel3dModel) GetAllByProductIdsTags(ctx context.Context, productIds []int64, tags []int, fields ...string) (resp []FsProductModel3d, err error) {
if len(productIds) == 0 || len(tags) == 0 {
return
}
db := d.db.WithContext(ctx).Model(&FsProductModel3d{}).
Where("`product_id` in (?) and `tag` in (?) and `status` = ?", productIds, tags, 1).
Order("sort DESC")
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Find(&resp).Error
return resp, err
}
// 获取每个产品最低价格
func (d *FsProductModel3dModel) GetProductMinPrice(ctx context.Context, productIds []int64, mapProductMinPrice map[int64]int64) error {
//获取产品模型价格列表
modelList, err := d.GetAllByProductIdsTags(ctx, productIds, []int{constants.TAG_MODEL, constants.TAG_PARTS}, "id,product_id,price,tag,part_id,step_price")
if err != nil {
return errors.New("failed to get model list")
}
mapModelMinPrice := make(map[int64]int64)
//每个模型/配件存储最小价格
for _, modelInfo := range modelList {
switch *modelInfo.Tag {
case constants.TAG_MODEL: //模型
if modelInfo.StepPrice == nil || len(*modelInfo.StepPrice) == 0 {
mapModelMinPrice[modelInfo.Id] = 0
continue
}
var stepPrice StepPriceJsonStruct
if err = json.Unmarshal(*modelInfo.StepPrice, &stepPrice); err != nil {
return errors.New(fmt.Sprintf("failed to parse model step price:%d", modelInfo.Id))
}
lenRange := len(stepPrice.PriceRange)
if lenRange == 0 {
mapModelMinPrice[modelInfo.Id] = 0
continue
}
sort.SliceStable(stepPrice.PriceRange, func(i, j int) bool {
return stepPrice.PriceRange[i].Price > stepPrice.PriceRange[j].Price
})
mapModelMinPrice[modelInfo.Id] = stepPrice.PriceRange[lenRange-1].Price
case constants.TAG_PARTS: //配件
mapModelMinPrice[modelInfo.Id] = *modelInfo.Price
}
}
//给产品存储最小价格
for _, v := range modelList {
if *v.Tag != constants.TAG_MODEL {
continue
}
itemPrice := mapModelMinPrice[v.Id]
if *v.PartId > 0 {
if fittingPrice, ok := mapModelMinPrice[*v.PartId]; ok {
itemPrice += fittingPrice
}
}
if minPrice, ok := mapProductMinPrice[*v.ProductId]; ok {
if itemPrice < minPrice {
mapProductMinPrice[*v.ProductId] = itemPrice
}
continue
}
mapProductMinPrice[*v.ProductId] = itemPrice
}
return nil
}

View File

@ -18,7 +18,7 @@ type FsShoppingCart struct {
PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量 PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量
Snapshot *string `gorm:"default:'';" json:"snapshot"` // Snapshot *string `gorm:"default:'';" json:"snapshot"` //
IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是 IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是
IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制,该类行无法跳详情页 IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制只能后台增加如购物车
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
} }

View File

@ -27,12 +27,14 @@ type FsShoppingCartData struct {
FittingId *int64 `gorm:"default:0;" json:"fitting_id"` // 配件id FittingId *int64 `gorm:"default:0;" json:"fitting_id"` // 配件id
PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量 PurchaseQuantity *int64 `gorm:"default:0;" json:"purchase_quantity"` // 购买数量
Snapshot *map[string]interface{} `gorm:"default:'';" json:"snapshot"` // Snapshot *map[string]interface{} `gorm:"default:'';" json:"snapshot"` //
SnapshotData *string `gorm:"default:'';" json:"snapshot_data"` //
IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是 IsSelected *int64 `gorm:"default:0;" json:"is_selected"` // 是否被选中 0非 1是
IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制只能后台增加如购物车 IsHighlyCustomized *int64 `gorm:"default:0;" json:"is_highly_customized"` // 是否高度定制 0非 1是针对客人高度定制只能后台增加如购物车
Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` // Ctime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"ctime"` //
Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` // Utime *time.Time `gorm:"default:'0000-00-00 00:00:00';" json:"utime"` //
} }
// 快照json数据结构
// 购物车快照数据结构 // 购物车快照数据结构
type CartSnapshot struct { type CartSnapshot struct {
Logo string `json:"logo"` //logo地址 Logo string `json:"logo"` //logo地址
@ -51,17 +53,16 @@ type ProductInfo struct {
ProductSn string `json:"product_sn"` ProductSn string `json:"product_sn"`
} }
type ModelInfo struct { type ModelInfo struct {
ModelJson interface{} `json:"model_json"` //模型设计json数据 ModelJson string `json:"model_json"` //模型设计json数据
} }
type FittingInfo struct { type FittingInfo struct {
FittingJson interface{} `json:"fitting_json"` //配件设计json数据 FittingJson string `json:"fitting_json"` //配件设计json数据
FittingName string `json:"fitting_name"` //配件名称 FittingName string `json:"fitting_name"` //配件名称
} }
type TemplateInfo struct { type TemplateInfo struct {
TemplateJson interface{} `json:"template_json"` //模板设计json数据 TemplateJson string `json:"template_json"` //模板设计json数据
TemplateTag string `json:"template_tag"` //模板标签 TemplateTag string `json:"template_tag"` //模板标签
SelectColorIndex int64 `json:"select_color_index"` //颜色选择索引
} }
type SizeInfo struct { type SizeInfo struct {
Inch string `json:"inch"` Inch string `json:"inch"`
@ -76,8 +77,8 @@ type UserDiyInformation struct {
Slogan string `json:"slogan"` //slogan Slogan string `json:"slogan"` //slogan
} }
type LightInfo struct { type LightInfo struct {
LightJson interface{} `json:"light_json"` //灯光设计json数据 LightJson string `json:"light_json"` //灯光设计json数据
LightName string `json:"light_name"` //名称 LightName string `json:"light_name"` //名称
} }
// 获取单个 // 获取单个

View File

@ -47,7 +47,9 @@ func (p *FsUserInfoModel) CreateOrUpdate(gormDB *gorm.DB, req *FsUserInfo) (resp
} }
func (m *FsUserInfoModel) MergeMetadata(userId int64, meta any) error { func (m *FsUserInfoModel) MergeMetadata(userId int64, meta any) error {
return fssql.MetadataModulePATCH(m.db, "profile", FsUserInfo{}, meta, "user_id = ?", userId) return fssql.MetadataModulePATCH(m.db, "profile", FsUserInfo{}, map[string]any{
"base": meta,
}, "user_id = ?", userId)
} }
func (m *FsUserInfoModel) GetProfile(ctx context.Context, pkey string, userId int64) (map[string]any, error) { func (m *FsUserInfoModel) GetProfile(ctx context.Context, pkey string, userId int64) (map[string]any, error) {
@ -79,11 +81,3 @@ func (m *FsUserInfoModel) GetProfile(ctx context.Context, pkey string, userId in
} }
return info, nil return info, nil
} }
func (m *FsUserInfoModel) FindOneByUser(ctx context.Context, userId, guestId int64) (resp *FsUserInfo, err error) {
if userId > 0 {
err = m.db.WithContext(ctx).Model(&FsUserInfo{}).Where("user_id = ?", userId).Take(&resp).Error
} else {
err = m.db.WithContext(ctx).Model(&FsUserInfo{}).Where("user_id = ? and guest_id = ?", userId, guestId).Take(&resp).Error
}
return resp, err
}

View File

@ -121,58 +121,13 @@ func (u *FsUserModel) RegisterByGoogleOAuth(ctx context.Context, token *auth.Reg
user.GoogleId = &googleId user.GoogleId = &googleId
user.PasswordHash = &token.Password user.PasswordHash = &token.Password
user.FirstName = &firstName user.FirstName = &firstName
user.LastName = &lastName user.FirstName = &lastName
err = tx.Model(&FsUser{}).Create(user).Error err = tx.Model(&FsUser{}).Create(user).Error
if err != nil { if err != nil {
return err return err
} }
// 继承guest_id的资源表 // 继承guest_id的资源表
return InheritGuestIdResource(tx, user.Id, token.GuestId, func(txResouce, txUserMaterial, txUserInfo *gorm.DB) error { return InheritGuestIdResource(tx, user.Id, token.GuestId, nil)
userProfileBase := UserProfileBase{
FirstName: *user.FirstName,
LastName: *user.LastName,
Email: *user.Email,
}
userProfile := &UserProfile{
ProfileBase: userProfileBase,
}
metadata, err := json.Marshal(userProfile)
if err != nil {
return err
}
now := time.Now().UTC()
uinfo := &FsUserInfo{
Module: FsString("profile"),
UserId: &user.Id,
GuestId: &token.GuestId,
Metadata: &metadata,
Ctime: &now,
Utime: &now,
}
// logx.Error(metadata)
err = txUserInfo.Where("module = 'profile' and user_id = ?", *uinfo.UserId).Take(nil).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
err = tx.Model(&FsUserInfo{}).Create(uinfo).Error
// logx.Info(err, "*uinfo.UserId:", *uinfo.UserId, " ", uinfo.Id)
if err == gorm.ErrRecordNotFound {
return nil
}
}
} else {
err = fssql.MetadataModulePATCH(txUserInfo, "profile", FsUserInfo{}, metadata, "user_id = ?", *uinfo.UserId)
if err != nil {
return err
}
}
return err
})
} }
return err return err
@ -223,7 +178,6 @@ func (u *FsUserModel) RegisterByFusen(ctx context.Context, token *auth.RegisterT
FirstName: FirstName, FirstName: FirstName,
LastName: LastName, LastName: LastName,
Resetaurant: Resetaurant, Resetaurant: Resetaurant,
Email: *user.Email,
} }
userProfile := &UserProfile{ userProfile := &UserProfile{

View File

@ -36,22 +36,11 @@ func FsBool(v bool) *bool {
return &v return &v
} }
func FsBytes(v string) *[]byte {
bs := []byte(v)
return &bs
}
// SubscriptionStatus 订阅状态 // SubscriptionStatus 订阅状态
type SubscriptionStatus struct { type SubscriptionStatus struct {
NotificationEmail struct { SubEmail bool `json:"all_emails"`
OrderUpdate bool `json:"order_update"` ItemMap *struct {
Newseleter bool `json:"newseleter"` } `json:"item_map"`
} `json:"notification_email"`
NotificationPhone struct {
OrderUpdate bool `json:"order_update"`
Newseleter bool `json:"newseleter"`
} `json:"notification_phone"`
} }
type UserProfile struct { type UserProfile struct {
@ -63,13 +52,8 @@ type UserProfile struct {
type UserProfileBase struct { type UserProfileBase struct {
FirstName string `json:"first_name"` // 首名 FirstName string `json:"first_name"` // 首名
LastName string `json:"last_name"` // 后名 LastName string `json:"last_name"` // 后名
Email string `json:"email"` // email UserName string `json:"user_name"` // 用户名
Mobile string `json:"mobile"` // 电话 Mobile string `json:"mobile"` // 电话
Resetaurant string `json:"resetaurant"` // 不知道干什么 Resetaurant string `json:"resetaurant"` // 不知道干什么
Company string `json:"company"` // 公司 Company string `json:"company"` // 公司
} }
type FsAddressWithDefault struct {
*FsAddress
IsDefault int64 `json:"is_default"`
}

View File

@ -4,13 +4,12 @@ import "gorm.io/gorm"
// AllModelsGen 所有Model集合,修改单行,只要不改字段名,不会根据新的内容修改,需要修改的话手动删除 // AllModelsGen 所有Model集合,修改单行,只要不改字段名,不会根据新的内容修改,需要修改的话手动删除
type AllModelsGen struct { type AllModelsGen struct {
CasbinRule *CasbinRuleModel // casbin_rule 后台--权限规则表 CasbinRule *CasbinRuleModel // casbin_rule
FsAddress *FsAddressModel // fs_address 用户地址表 FsAddress *FsAddressModel // fs_address 用户地址表
FsAdminApi *FsAdminApiModel // fs_admin_api 后台--接口表 FsAdminApi *FsAdminApiModel // fs_admin_api 后台--接口表
FsAdminDepartment *FsAdminDepartmentModel // fs_admin_department 后台--部门表 FsAdminDepartment *FsAdminDepartmentModel // fs_admin_department 后台--部门表
FsAdminMenu *FsAdminMenuModel // fs_admin_menu 后台--菜单表 FsAdminMenu *FsAdminMenuModel // fs_admin_menu 后台--菜单表
FsAdminRole *FsAdminRoleModel // fs_admin_role 后台--角色表 FsAdminRole *FsAdminRoleModel // fs_admin_role 后台--角色表
FsAdminRoleApi *FsAdminRoleApiModel // fs_admin_role_api 后台--角色接口表
FsAdminUser *FsAdminUserModel // fs_admin_user 后台--管理员表 FsAdminUser *FsAdminUserModel // fs_admin_user 后台--管理员表
FsAuthAssignment *FsAuthAssignmentModel // fs_auth_assignment 用户角色和权限信息 FsAuthAssignment *FsAuthAssignmentModel // fs_auth_assignment 用户角色和权限信息
FsAuthItem *FsAuthItemModel // fs_auth_item 用户角色和权限信息 FsAuthItem *FsAuthItemModel // fs_auth_item 用户角色和权限信息
@ -68,7 +67,6 @@ type AllModelsGen struct {
FsPay *FsPayModel // fs_pay 支付记录 FsPay *FsPayModel // fs_pay 支付记录
FsPayEvent *FsPayEventModel // fs_pay_event 支付回调事件日志 FsPayEvent *FsPayEventModel // fs_pay_event 支付回调事件日志
FsProduct *FsProductModel // fs_product 产品表 FsProduct *FsProductModel // fs_product 产品表
FsProductCollection *FsProductCollectionModel // fs_product_collection 产品收藏表
FsProductCopy1 *FsProductCopy1Model // fs_product_copy1 产品表 FsProductCopy1 *FsProductCopy1Model // fs_product_copy1 产品表
FsProductDesign *FsProductDesignModel // fs_product_design 产品设计表 FsProductDesign *FsProductDesignModel // fs_product_design 产品设计表
FsProductDesignGather *FsProductDesignGatherModel // fs_product_design_gather FsProductDesignGather *FsProductDesignGatherModel // fs_product_design_gather
@ -123,7 +121,6 @@ func NewAllModels(gdb *gorm.DB) *AllModelsGen {
FsAdminDepartment: NewFsAdminDepartmentModel(gdb), FsAdminDepartment: NewFsAdminDepartmentModel(gdb),
FsAdminMenu: NewFsAdminMenuModel(gdb), FsAdminMenu: NewFsAdminMenuModel(gdb),
FsAdminRole: NewFsAdminRoleModel(gdb), FsAdminRole: NewFsAdminRoleModel(gdb),
FsAdminRoleApi: NewFsAdminRoleApiModel(gdb),
FsAdminUser: NewFsAdminUserModel(gdb), FsAdminUser: NewFsAdminUserModel(gdb),
FsAuthAssignment: NewFsAuthAssignmentModel(gdb), FsAuthAssignment: NewFsAuthAssignmentModel(gdb),
FsAuthItem: NewFsAuthItemModel(gdb), FsAuthItem: NewFsAuthItemModel(gdb),
@ -181,7 +178,6 @@ func NewAllModels(gdb *gorm.DB) *AllModelsGen {
FsPay: NewFsPayModel(gdb), FsPay: NewFsPayModel(gdb),
FsPayEvent: NewFsPayEventModel(gdb), FsPayEvent: NewFsPayEventModel(gdb),
FsProduct: NewFsProductModel(gdb), FsProduct: NewFsProductModel(gdb),
FsProductCollection: NewFsProductCollectionModel(gdb),
FsProductCopy1: NewFsProductCopy1Model(gdb), FsProductCopy1: NewFsProductCopy1Model(gdb),
FsProductDesign: NewFsProductDesignModel(gdb), FsProductDesign: NewFsProductDesignModel(gdb),
FsProductDesignGather: NewFsProductDesignGatherModel(gdb), FsProductDesignGather: NewFsProductDesignGatherModel(gdb),

View File

@ -91,20 +91,23 @@ func main() {
routes...)) routes...))
} }
Backends = append(Backends, NewBackend(mux,
fmt.Sprintf("http://%s:%d", "localhost", 9501),
"/api/v1/namespaces/kubernetes-dashboard"))
// 定义用于服务Vue dist文件夹的静态文件服务器 // 定义用于服务Vue dist文件夹的静态文件服务器
fs := http.FileServer(http.Dir(vueBuild)) fs := http.FileServer(http.Dir(vueBuild))
indexHtmlPath := vueBuild + "/index.html" indexHtmlPath := vueBuild + "/index.html"
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") { if strings.HasPrefix(r.URL.Path, "/api/") {
r.ParseMultipartForm(100 << 20) r.ParseMultipartForm(100 << 20)
// if err != nil {
// logx.Error(err)
// }
// 对/api开头的请求进行反向代理 // 对/api开头的请求进行反向代理
proxy := httputil.NewSingleHostReverseProxy(apiURL) proxy := httputil.NewSingleHostReverseProxy(apiURL)
proxy.ServeHTTP(w, r) proxy.ServeHTTP(w, r)
return return
} else { } else {
// 根据请求路径判断是服务静态文件或者是返回index.html // 根据请求路径判断是服务静态文件或者是返回index.html
idx := strings.Index(r.URL.Path[1:], "/") idx := strings.Index(r.URL.Path[1:], "/")

View File

@ -48,7 +48,7 @@ run_server() {
# 循环检查screen进程是否存在 # 循环检查screen进程是否存在
[ -f .gitignore ] || (echo "$server_name" > .gitignore && echo "main" >> .gitignore) [ -f .gitignore ] || echo $server_name > .gitignore
# 使用 screen 运行 go run <server_name>.go # 使用 screen 运行 go run <server_name>.go
echo "Running $server_name" echo "Running $server_name"

View File

@ -1,2 +1 @@
auth auth
main

View File

@ -1,8 +1,6 @@
FROM alpine FROM alpine
WORKDIR /www/fusenapi/ WORKDIR /www/fusenapi/
COPY ./bin/api-auth-srv /www/fusenapi/ COPY ./bin/api-assistant-srv /www/fusenapi/
COPY ./env.yaml /opt/ COPY ./etc /www/fusenapi/etc
COPY ./server.fusen.3718.cn.pem /opt/ CMD ["/www/fusenapi/api-assistant-srv"]
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-auth-srv"]

View File

@ -2,7 +2,6 @@ Name: auth
Host: localhost Host: localhost
Port: 9980 Port: 9980
ReplicaId: 10 ReplicaId: 10
HomePage: "http://www.fusen.3718.cn"
MainAddress: "https://server.fusen.3718.cn:9900" MainAddress: "https://server.fusen.3718.cn:9900"
WebsocketAddr: "https://server.fusen.3718.cn:9914" WebsocketAddr: "https://server.fusen.3718.cn:9914"
SourceMysql: "fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen" SourceMysql: "fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen"

View File

@ -12,7 +12,6 @@ type Config struct {
Auth types.Auth Auth types.Auth
ReplicaId uint64 ReplicaId uint64
HomePage string
MainAddress string MainAddress string
WebsocketAddr string WebsocketAddr string

View File

@ -28,7 +28,7 @@ func init() {
log.Fatal(err) log.Fatal(err)
} }
TimeLimit = check.NewTimeLimit[string](EmailTaskResendTime) TimeLimit = check.NewTimelimit[string](EmailTaskResendTime)
// Initialize the email manager // Initialize the email manager
EmailManager = &EmailSender{ EmailManager = &EmailSender{
@ -53,17 +53,16 @@ func init() {
} }
type EmailFormat struct { type EmailFormat struct {
TemplateName string // 模板名字 TemplateName string // 模板名字
UniqueKey string // 用于处理唯一的任务,重发都会被利用到 UniqueKey string // 用于处理唯一的任务,重发都会被利用到
TargetEmail string // 发送的目标email TargetEmail string // 发送的目标email
CompanyName string // fs公司名 CompanyName string // fs公司名
ConfirmationLink string // fs确认连接 ConfirmationLink string // fs确认连接
SenderName string // 发送人 SenderName string // 发送人
SenderTitle string // 发送标题 SenderTitle string // 发送标题
Extend map[string]string // 扩展参数 Extend map[string]string
} }
// 验证邮件格式是否符合要求
func (eformat *EmailFormat) Vaild() error { func (eformat *EmailFormat) Vaild() error {
// 1. 检查模板名称 // 1. 检查模板名称
@ -124,47 +123,39 @@ type EmailTask struct {
SendTime time.Time // 处理的任务时间 SendTime time.Time // 处理的任务时间
} }
// ProcessEmailTasks 是 EmailSender 结构体的方法,用于处理邮件任务。
func (m *EmailSender) ProcessEmailTasks() { func (m *EmailSender) ProcessEmailTasks() {
for { for {
// 从 EmailTasks 通道中接收邮件任务
emailformat, ok := <-m.EmailTasks emailformat, ok := <-m.EmailTasks
if !ok { if !ok {
log.Println("Email task channel closed") log.Println("Email task channel closed")
break break
} }
// 验证邮件格式是否合法
err := emailformat.Vaild() err := emailformat.Vaild()
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
continue continue
} }
// 加锁,避免并发修改 emailSending 字典
m.lock.Lock() m.lock.Lock()
// 检查 emailSending 字典中是否已存在相同的任务
_, isSending := m.emailSending[emailformat.UniqueKey] _, isSending := m.emailSending[emailformat.UniqueKey]
if isSending { if isSending {
m.lock.Unlock() m.lock.Unlock()
continue continue
} }
// 将邮件任务添加到 emailSending 字典中
m.emailSending[emailformat.UniqueKey] = &EmailTask{ m.emailSending[emailformat.UniqueKey] = &EmailTask{
Email: emailformat, Email: emailformat,
SendTime: time.Now().UTC(), SendTime: time.Now().UTC(),
} }
m.lock.Unlock() m.lock.Unlock()
// 获取一个信号量,限制同时发送的邮件任务数量 // Acquire a token
m.semaphore <- struct{}{} m.semaphore <- struct{}{}
go func() { go func() {
defer func() { <-m.semaphore }() // 释放一个信号量 defer func() { <-m.semaphore }() // Release a token
// 渲染邮件模板内容
content := RenderEmailTemplate( content := RenderEmailTemplate(
emailformat.TemplateName, emailformat.TemplateName,
emailformat.CompanyName, emailformat.CompanyName,
@ -173,41 +164,34 @@ func (m *EmailSender) ProcessEmailTasks() {
emailformat.SenderTitle, emailformat.SenderTitle,
emailformat.Extend, emailformat.Extend,
) )
// 发送邮件
err := smtp.SendMail("smtp.gmail.com:587", m.Auth, m.FromEmail, []string{emailformat.TargetEmail}, content) err := smtp.SendMail("smtp.gmail.com:587", m.Auth, m.FromEmail, []string{emailformat.TargetEmail}, content)
if err != nil { if err != nil {
log.Printf("Failed to send email to %s: %v\n", emailformat, err) log.Printf("Failed to send email to %s: %v\n", emailformat, err)
// 重新发送邮件
m.Resend(emailformat.UniqueKey, content) m.Resend(emailformat.UniqueKey, content)
} }
}() }()
} }
} }
// Resend 是 EmailSender 结构体的方法,用于重发邮件 // Resend 重发邮件
func (m *EmailSender) Resend(uniqueKey string, content []byte) { func (m *EmailSender) Resend(uniqueKey string, content []byte) {
// 等待一段时间后重发邮件,避免频繁重发
time.Sleep(m.ResendTimeLimit) time.Sleep(m.ResendTimeLimit)
m.lock.Lock() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
// Check if the email task still exists and has not been sent successfully
// 检查邮件任务是否仍存在并且未成功发送
if task, ok := m.emailSending[uniqueKey]; ok && task.SendTime.Add(m.ResendTimeLimit).After(time.Now().UTC()) { if task, ok := m.emailSending[uniqueKey]; ok && task.SendTime.Add(m.ResendTimeLimit).After(time.Now().UTC()) {
err := smtp.SendMail(task.Email.TargetEmail, m.Auth, m.FromEmail, []string{task.Email.TargetEmail}, content) err := smtp.SendMail(task.Email.TargetEmail, m.Auth, m.FromEmail, []string{task.Email.TargetEmail}, content)
if err != nil { if err != nil {
log.Printf("Failed to resend email to %s: %v\n", task.Email.TargetEmail, err) log.Printf("Failed to resend email to %s: %v\n", task.Email.TargetEmail, err)
} else { } else {
// 从 emailSending 字典中删除已成功发送的邮件任务
delete(m.emailSending, uniqueKey) delete(m.emailSending, uniqueKey)
} }
} }
} }
// ClearExpiredTasks 是 EmailSender 结构体的方法,用于清除过期的邮件任务 // ClearExpiredTasks 清除过期的邮件任务
func (m *EmailSender) ClearExpiredTasks() { func (m *EmailSender) ClearExpiredTasks() {
// 每分钟触发一次清除操作
ticker := time.NewTicker(time.Minute) ticker := time.NewTicker(time.Minute)
defer ticker.Stop() defer ticker.Stop()
@ -215,7 +199,6 @@ func (m *EmailSender) ClearExpiredTasks() {
<-ticker.C <-ticker.C
m.lock.Lock() m.lock.Lock()
// 遍历 emailSending 字典,删除发送时间超过一定限制的过期任务
for email, task := range m.emailSending { for email, task := range m.emailSending {
if task.SendTime.Add(m.ResendTimeLimit).Before(time.Now().UTC()) { if task.SendTime.Add(m.ResendTimeLimit).Before(time.Now().UTC()) {
delete(m.emailSending, email) delete(m.emailSending, email)
@ -225,19 +208,8 @@ func (m *EmailSender) ClearExpiredTasks() {
} }
} }
// RenderEmailTemplate 是一个渲染邮件模板的函数,根据给定的参数生成邮件内容。
// 参数:
// - templateName: 邮件模板的名称
// - companyName: 公司名称
// - confirmationLink: 确认链接
// - senderName: 发件人姓名
// - senderTitle: 发件人职务
// - extend: 扩展字段,包含其他自定义键值对的映射
// 返回值:
// - []byte: 渲染后的邮件内容(以字节切片形式返回)
func RenderEmailTemplate(templateName, companyName, confirmationLink, senderName, senderTitle string, extend map[string]string) []byte { func RenderEmailTemplate(templateName, companyName, confirmationLink, senderName, senderTitle string, extend map[string]string) []byte {
// 创建一个包含邮件模板所需数据的映射
data := map[string]string{ data := map[string]string{
"CompanyName": companyName, "CompanyName": companyName,
"ConfirmationLink": confirmationLink, "ConfirmationLink": confirmationLink,
@ -245,20 +217,16 @@ func RenderEmailTemplate(templateName, companyName, confirmationLink, senderName
"SenderTitle": senderTitle, "SenderTitle": senderTitle,
} }
// 将扩展字段中的键值对添加到数据映射中
for k, v := range extend { for k, v := range extend {
data[k] = v data[k] = v
} }
// 创建一个字节缓冲区,用于存储渲染后的邮件内容
var result bytes.Buffer var result bytes.Buffer
// result.Write([]byte("MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"))
// 使用给定的数据映射执行邮件模板渲染
err := tpls.ExecuteTemplate(&result, templateName, data) err := tpls.ExecuteTemplate(&result, templateName, data)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// 将渲染后的邮件内容转换为字节切片并返回
return result.Bytes() return result.Bytes()
} }

View File

@ -14,6 +14,7 @@ import (
"fusenapi/server/auth/internal/svc" "fusenapi/server/auth/internal/svc"
"fusenapi/server/auth/internal/types" "fusenapi/server/auth/internal/types"
"github.com/474420502/requests"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx" "github.com/zeromicro/go-zero/rest/httpx"
"gorm.io/gorm" "gorm.io/gorm"
@ -48,6 +49,7 @@ func FinishRegister(svcCtx *svc.ServiceContext, user *gmodel.FsUser, token *auth
) )
if err != nil { if err != nil {
return err return err
} }
@ -55,7 +57,7 @@ func FinishRegister(svcCtx *svc.ServiceContext, user *gmodel.FsUser, token *auth
event.Data = wevent.DataEmailRegister{ event.Data = wevent.DataEmailRegister{
JwtToken: jwtToken, JwtToken: jwtToken,
} }
err = wevent.CommonNotify(svcCtx.Config.WebsocketAddr, token.Wid, event) err = CommonNotify(svcCtx.Config.WebsocketAddr, token.Wid, event)
if err != nil { if err != nil {
// logx.Error(err, token.TraceId) // logx.Error(err, token.TraceId)
return err return err
@ -64,6 +66,34 @@ func FinishRegister(svcCtx *svc.ServiceContext, user *gmodel.FsUser, token *auth
return nil return nil
} }
func CommonNotify(WebsocketAddr, wid string, event *wevent.WebsocketEvent) error {
reqWebsocketAddr := fmt.Sprintf("%s/api/websocket/common_notify", WebsocketAddr)
tp := requests.Post(reqWebsocketAddr)
tp.SetBodyJson(requests.M{
"wid": wid,
"data": event,
})
wresp, err := tp.Execute()
if err != nil {
// logx.Error(err, token.TraceId)
return err
}
result := wresp.Json()
if !result.Get("code").Exists() {
return fmt.Errorf("send %s is error", reqWebsocketAddr)
}
if result.Get("code").Int() != 200 {
return fmt.Errorf("%s", result.String())
}
return nil
}
func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
@ -146,7 +176,7 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma
} }
event := wevent.NewWebsocketEventSuccess(wevent.UserResetToken, rt.TraceId) event := wevent.NewWebsocketEventSuccess(wevent.UserResetToken, rt.TraceId)
err = wevent.CommonNotify(l.svcCtx.Config.MainAddress, rt.Wid, event) err = CommonNotify(l.svcCtx.Config.MainAddress, rt.Wid, event)
if err != nil { if err != nil {
logx.Error(err, rt.TraceId) logx.Error(err, rt.TraceId)
return resp.SetStatus(basic.CodeResetPasswordErr, err.Error()) return resp.SetStatus(basic.CodeResetPasswordErr, err.Error())

View File

@ -47,10 +47,6 @@ func (l *UserEmailRegisterLogic) UserEmailRegister(req *types.RequestEmailRegist
return resp.SetStatus(basic.CodeOAuthEmailErr) return resp.SetStatus(basic.CodeOAuthEmailErr)
} }
if len(req.Email) > 50 {
return resp.SetStatusWithMessage(basic.CodeOAuthEmailErr, "email len must < 50")
}
if !TimeLimit.Is(req.Email) { if !TimeLimit.Is(req.Email) {
return resp.SetStatus(basic.CodeEmailTimeShortErr) return resp.SetStatus(basic.CodeEmailTimeShortErr)
} }

View File

@ -41,10 +41,6 @@ func (l *UserRegisterLogic) UserRegister(req *types.RequestUserRegister, userinf
return resp.SetStatus(basic.CodeOAuthEmailErr) return resp.SetStatus(basic.CodeOAuthEmailErr)
} }
if len(req.Email) > 50 {
return resp.SetStatusWithMessage(basic.CodeOAuthEmailErr, "email len must < 50")
}
// _, err := l.svcCtx.AllModels.FsUser.FindUserByEmail(l.ctx, req.Email) // _, err := l.svcCtx.AllModels.FsUser.FindUserByEmail(l.ctx, req.Email)
// if err == nil { // if err == nil {
// return resp.SetStatus(basic.CodeEmailExistsErr) // return resp.SetStatus(basic.CodeEmailExistsErr)

View File

@ -50,7 +50,7 @@ func (l *UserResetPasswordHtmlLogic) UserResetPasswordHtml(req *types.RequestUse
func (l *UserResetPasswordHtmlLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { func (l *UserResetPasswordHtmlLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
err := tpls.ExecuteTemplate(w, "reset_confirm.tpl", map[string]string{ err := tpls.ExecuteTemplate(w, "reset_confirm.tpl", map[string]string{
"HomePage": l.svcCtx.Config.HomePage, "HomePage": "http://www.fusen.3718.cn",
"ResetToken": l.ResetToken, "ResetToken": l.ResetToken,
"ResetPasswordLink": l.svcCtx.Config.MainAddress + "/api/auth/reset/password", "ResetPasswordLink": l.svcCtx.Config.MainAddress + "/api/auth/reset/password",
}) })

View File

@ -39,10 +39,6 @@ func (l *UserResetPasswordLogic) UserResetPassword(req *types.RequestUserResetPa
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
if len(req.NewPassword) > 30 {
return resp.SetStatusWithMessage(basic.CodePasswordErr, "password len must < 30")
}
rt, err := l.svcCtx.ResetTokenManger.Decrypt(req.ResetToken) // ResetToken rt, err := l.svcCtx.ResetTokenManger.Decrypt(req.ResetToken) // ResetToken
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
@ -55,7 +51,7 @@ func (l *UserResetPasswordLogic) UserResetPassword(req *types.RequestUserResetPa
} }
if time.Since(rt.CreateAt) > 30*time.Minute { if time.Since(rt.CreateAt) > 30*time.Minute {
return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "verification links expire after 30 minute.") return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "Verification links expire after 30 minute.")
} }
err = l.svcCtx.AllModels.FsUser.Transaction(l.ctx, func(tx *gorm.DB) error { err = l.svcCtx.AllModels.FsUser.Transaction(l.ctx, func(tx *gorm.DB) error {
@ -71,7 +67,7 @@ func (l *UserResetPasswordLogic) UserResetPassword(req *types.RequestUserResetPa
} }
if *user.PasswordHash == req.NewPassword { if *user.PasswordHash == req.NewPassword {
return fmt.Errorf("the password is the same as the old one. it needs to be changed") return fmt.Errorf("the password is the same as the old one. It needs to be changed")
} }
return tx.Where("id = ?", rt.UserId).Update("PasswordHash", req.NewPassword).Error return tx.Where("id = ?", rt.UserId).Update("PasswordHash", req.NewPassword).Error
@ -83,7 +79,7 @@ func (l *UserResetPasswordLogic) UserResetPassword(req *types.RequestUserResetPa
} }
event := wevent.NewWebsocketEventSuccess(wevent.UserResetToken, rt.TraceId) event := wevent.NewWebsocketEventSuccess(wevent.UserResetToken, rt.TraceId)
err = wevent.CommonNotify(l.svcCtx.Config.WebsocketAddr, rt.Wid, event) err = CommonNotify(l.svcCtx.Config.WebsocketAddr, rt.Wid, event)
if err != nil { if err != nil {
logx.Error(err, rt.TraceId) logx.Error(err, rt.TraceId)
return resp.SetStatusWithMessage(basic.CodeResetPasswordErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeResetPasswordErr, err.Error())

View File

@ -39,7 +39,7 @@ func (l *UserResetTokenLogic) UserResetToken(req *types.RequestUserResetToken, u
user, err := l.svcCtx.AllModels.FsUser.FindUserByEmail(context.TODO(), req.Email) user, err := l.svcCtx.AllModels.FsUser.FindUserByEmail(context.TODO(), req.Email)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, err.Error()) return resp.SetStatus(basic.CodeRequestParamsErr, err.Error())
} }
token := &auth.ResetToken{ token := &auth.ResetToken{

View File

@ -1,2 +1 @@
base base
main

View File

@ -1,8 +0,0 @@
FROM alpine
WORKDIR /www/fusenapi/
COPY ./bin/api-base-srv /www/fusenapi/
COPY ./env.yaml /opt/
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-base-srv"]

View File

@ -1,2 +1 @@
canteen canteen
main

View File

@ -2,7 +2,5 @@ FROM alpine
WORKDIR /www/fusenapi/ WORKDIR /www/fusenapi/
COPY ./bin/api-canteen-srv /www/fusenapi/ COPY ./bin/api-canteen-srv /www/fusenapi/
COPY ./env.yaml /opt/ COPY ./etc /www/fusenapi/etc
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-canteen-srv"] CMD ["/www/fusenapi/api-canteen-srv"]

View File

@ -1,2 +0,0 @@
collection
main

View File

@ -1,8 +0,0 @@
FROM alpine
WORKDIR /www/fusenapi/
COPY ./bin/api-collection-srv /www/fusenapi/
COPY ./env.yaml /opt/
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-collection-srv"]

View File

@ -1,36 +0,0 @@
package main
import (
"flag"
"fmt"
"net/http"
"time"
"fusenapi/utils/auth"
"fusenapi/utils/fsconfig"
"fusenapi/server/collection/internal/config"
"fusenapi/server/collection/internal/handler"
"fusenapi/server/collection/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
var configFile = flag.String("f", "etc/collection.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
fsconfig.StartNacosConfig(*configFile, &c, nil)
c.Timeout = int64(time.Second * 15)
server := rest.MustNewServer(c.RestConf, rest.WithCustomCors(auth.FsCors, func(w http.ResponseWriter) {
}))
defer server.Stop()
ctx := svc.NewServiceContext(c)
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}

View File

@ -1,10 +0,0 @@
Name: collection
Host: 0.0.0.0
Port: 9922
Timeout: 15000 #服务超时时间(毫秒)
SourceMysql: fsreaderwriter:XErSYmLELKMnf3Dh@tcp(fusen.cdmigcvz3rle.us-east-2.rds.amazonaws.com:3306)/fusen
SourceRabbitMq: ""
Auth:
AccessSecret: fusen2023
AccessExpire: 2592000
RefreshAfter: 1592000

View File

@ -1,17 +0,0 @@
package config
import (
"fusenapi/server/collection/internal/types"
"github.com/zeromicro/go-zero/rest"
)
type Config struct {
rest.RestConf
SourceMysql string
Auth types.Auth
SourceRabbitMq string
BLMService struct {
Version string
Urls []string
}
}

View File

@ -1,35 +0,0 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/collection/internal/logic"
"fusenapi/server/collection/internal/svc"
"fusenapi/server/collection/internal/types"
)
func GetCollectProductListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetCollectProductListReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewGetCollectProductListLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.GetCollectProductList(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -1,42 +0,0 @@
// Code generated by goctl. DO NOT EDIT.
package handler
import (
"net/http"
"fusenapi/server/collection/internal/svc"
"github.com/zeromicro/go-zero/rest"
)
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/api/collection/collect_product",
Handler: CollectProductHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/collection/delete_collect_product",
Handler: DeleteCollectProductHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/collection/get_collect_product_list",
Handler: GetCollectProductListHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/collection/test_ai",
Handler: TestAiHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/collection/test_pdf",
Handler: TestPdfHandler(serverCtx),
},
},
)
}

View File

@ -1,92 +0,0 @@
package logic
import (
"errors"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"gorm.io/gorm"
"time"
"context"
"fusenapi/server/collection/internal/svc"
"fusenapi/server/collection/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CollectProductLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCollectProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CollectProductLogic {
return &CollectProductLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *CollectProductLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *CollectProductLogic) CollectProduct(req *types.CollectProductReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if !userinfo.IsUser() && !userinfo.IsGuest() {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in before collect product")
}
//查询产品
productInfo, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, req.ProductId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product is not found")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "faile to get product info")
}
//校验下状态
/*if *productInfo.Status != 1 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "the product status is unNormal")
}*/
//下架了
if *productInfo.IsShelf == 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "the product is off shelf")
}
if *productInfo.IsDel == 1 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "the product is deleted")
}
//查询收藏
_, err = l.svcCtx.AllModels.FsProductCollection.FindOne(l.ctx, userinfo.UserId, userinfo.GuestId, req.ProductId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to check repeat of collection")
}
//创建
now := time.Now().UTC()
err = l.svcCtx.AllModels.FsProductCollection.Create(l.ctx, &gmodel.FsProductCollection{
UserId: &userinfo.UserId,
GuestId: &userinfo.GuestId,
ProductId: &req.ProductId,
TemplateTag: &req.TemplateTag,
SelectColorIndex: &req.SelectColorIndex,
Logo: &req.Logo,
Ctime: &now,
Utime: &now,
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to collect product")
}
return resp.SetStatusWithMessage(basic.CodeOK, "The product has been collected successfully")
}
return resp.SetStatusAddMessage(basic.CodeOK, "You have collect this product and don`t need to repeat again")
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *CollectProductLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,50 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/collection/internal/svc"
"fusenapi/server/collection/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteCollectProductLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewDeleteCollectProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCollectProductLogic {
return &DeleteCollectProductLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *DeleteCollectProductLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *DeleteCollectProductLogic) DeleteCollectProduct(req *types.DeleteCollectProductReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if !userinfo.IsUser() && !userinfo.IsGuest() {
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please sign in before to collect product")
}
for _, id := range req.Ids {
err := l.svcCtx.AllModels.FsProductCollection.Delete2(l.ctx, userinfo.UserId, userinfo.GuestId, id)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to remove product collection")
}
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *DeleteCollectProductLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,190 +0,0 @@
package logic
import (
"encoding/json"
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/s3url_to_s3id"
"math"
"context"
"fusenapi/server/collection/internal/svc"
"fusenapi/server/collection/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetCollectProductListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetCollectProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCollectProductListLogic {
return &GetCollectProductListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *GetCollectProductListLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *GetCollectProductListLogic) GetCollectProductList(req *types.GetCollectProductListReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if req.CurrentPage <= 0 {
req.CurrentPage = constants.DEFAULT_PAGE
}
limit := 10
//查询列表
collectionList, total, err := l.svcCtx.AllModels.FsProductCollection.GetList(l.ctx, userinfo.UserId, userinfo.GuestId, req.CurrentPage, limit, "id DESC")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get collection list")
}
//没有数据
if len(collectionList) == 0 {
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCollectProductListRsp{
Meta: types.Meta{
TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: req.CurrentPage,
PerPage: limit,
},
List: []types.GetCollectProductListRspItem{},
})
}
productIds := make([]int64, 0, len(collectionList))
for _, v := range collectionList {
productIds = append(productIds, *v.ProductId)
}
//获取产品所有模型+配件来计算最低价
modelList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByProductIdsTags(l.ctx, productIds, []int{constants.TAG_MODEL, constants.TAG_PARTS}, "id,tag,product_id,part_id,price,step_price")
mapModel := make(map[int64]int)
for k, v := range modelList {
mapModel[v.Id] = k
}
//计算最低价
mapProductMinPrice := make(map[int64]int64)
for _, v := range modelList {
if *v.Tag != constants.TAG_MODEL {
continue
}
var stepPrice gmodel.StepPriceJsonStruct
if err = json.Unmarshal(*v.StepPrice, &stepPrice); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeJsonErr, fmt.Sprintf("failed to parse step price:%d", v.Id))
}
//阶梯最低单价
itemPrice := int64(0)
if len(stepPrice.PriceRange) > 0 {
itemPrice = stepPrice.PriceRange[0].Price
}
//配件价格
if fittingIndex, ok := mapModel[*v.PartId]; ok {
itemPrice += *modelList[fittingIndex].Price
}
//查询比较最低价
if minPrice, ok := mapProductMinPrice[*v.ProductId]; ok {
if minPrice < itemPrice {
continue
}
}
mapProductMinPrice[*v.ProductId] = itemPrice
}
//获取产品列表
productList, err := l.svcCtx.AllModels.FsProduct.GetProductListByIdsWithoutStatus(l.ctx, productIds, "")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product list")
}
mapProduct := make(map[int64]int)
resourceIds := make([]string, 0, len(productList))
for k, v := range productList {
mapProduct[v.Id] = k
resourceIds = append(resourceIds, s3url_to_s3id.GetS3ResourceIdFormUrl(*v.Cover))
}
sizeCounts, err := l.svcCtx.AllModels.FsProductSize.GetGroupProductSizeByStatus(l.ctx, productIds, 1)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product size count")
}
mapProductSizeCount := make(map[int64]int64)
for _, v := range sizeCounts {
mapProductSizeCount[v.ProductId] = v.Num
}
//获取资源列表
resourceList, err := l.svcCtx.AllModels.FsResource.FindAllByResourceIds(l.ctx, resourceIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get resource list")
}
mapResourceMetadata := make(map[string]interface{})
for _, v := range resourceList {
var metadata interface{}
if err = json.Unmarshal(*v.Metadata, &metadata); err != nil {
logx.Error(err)
return resp.SetStatusAddMessage(basic.CodeJsonErr, fmt.Sprintf("failed to parse resource metadata:%s", v.ResourceId))
}
mapResourceMetadata[*v.ResourceUrl] = metadata
}
listRsp := make([]types.GetCollectProductListRspItem, 0, len(collectionList))
for _, collection := range collectionList {
productName := ""
cover := ""
isShelf := int64(0)
isDeleted := int64(0)
var coverMetadata interface{}
if productIndex, ok := mapProduct[*collection.ProductId]; ok {
productName = *productList[productIndex].Title
cover = *productList[productIndex].Cover
isShelf = *productList[productIndex].IsShelf
isDeleted = *productList[productIndex].IsDel
if metadata, ok := mapResourceMetadata[cover]; ok {
coverMetadata = metadata
}
}
sizeCount := int64(0)
if count, ok := mapProductSizeCount[*collection.ProductId]; ok {
sizeCount = count
}
minPrice := ""
if price, ok := mapProductMinPrice[*collection.ProductId]; ok {
minPrice = format.CentitoDollar(price, 3)
}
listRsp = append(listRsp, types.GetCollectProductListRspItem{
Id: collection.Id,
ProductId: *collection.ProductId,
ProductName: productName,
Logo: *collection.Logo,
Cover: cover,
CoverMetadata: coverMetadata,
SelectColorIndex: *collection.SelectColorIndex,
TemplateTag: *collection.TemplateTag,
SizeCount: sizeCount,
MinPrice: minPrice,
IsShelf: isShelf,
IsDeleted: isDeleted,
})
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCollectProductListRsp{
Meta: types.Meta{
TotalCount: total,
PageCount: int64(math.Ceil(float64(total) / float64(limit))),
CurrentPage: req.CurrentPage,
PerPage: limit,
},
List: listRsp,
})
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetCollectProductListLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

File diff suppressed because one or more lines are too long

View File

@ -1,50 +0,0 @@
package logic
import (
"context"
"fusenapi/server/collection/internal/svc"
"fusenapi/server/collection/internal/types"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/pdf"
"github.com/zeromicro/go-zero/core/logx"
)
type TestPdfLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewTestPdfLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TestPdfLogic {
return &TestPdfLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *TestPdfLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *TestPdfLogic) TestPdf(req *types.TestPdfReq, userinfo *auth.UserInfo) (resp *basic.Response) {
return resp.SetStatusWithMessage(basic.CodeOK, "你干嘛,哎哟")
switch req.Type {
case "url":
case "html":
default:
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid type")
}
res, err := pdf.HtmlToPdfBase64(req.Content, req.Type)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error())
}
return resp.SetStatus(basic.CodeOK, res)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *TestPdfLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,26 +0,0 @@
package svc
import (
"fusenapi/initalize"
"fusenapi/model/gmodel"
"fusenapi/server/collection/internal/config"
"gorm.io/gorm"
)
type ServiceContext struct {
Config config.Config
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
RabbitMq *initalize.RabbitMqHandle
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := initalize.InitMysql(c.SourceMysql)
return &ServiceContext{
Config: c,
MysqlConn: conn,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
}
}

View File

@ -1,119 +0,0 @@
// Code generated by goctl. DO NOT EDIT.
package types
import (
"fusenapi/utils/basic"
)
type CollectProductReq struct {
ProductId int64 `json:"product_id"`
Logo string `json:"logo"`
SelectColorIndex int64 `json:"select_color_index"`
TemplateTag string `json:"template_tag"`
}
type DeleteCollectProductReq struct {
Ids []int64 `json:"ids"`
}
type GetCollectProductListReq struct {
CurrentPage int `form:"current_page"`
}
type GetCollectProductListRsp struct {
Meta Meta `json:"meta"` //分页信息
List []GetCollectProductListRspItem `json:"list"`
}
type GetCollectProductListRspItem struct {
Id int64 `json:"id"`
ProductId int64 `json:"product_id"`
ProductName string `json:"product_name"`
Logo string `json:"logo"`
Cover string `json:"cover"`
CoverMetadata interface{} `json:"coverMetadata"`
SelectColorIndex int64 `json:"select_color_index"`
TemplateTag string `json:"template_tag"`
SizeCount int64 `json:"size_count"`
MinPrice string `json:"min_price"`
IsShelf int64 `json:"is_shelf"`
IsDeleted int64 `json:"is_deleted"`
}
type TestAiReq struct {
Num int `form:"num"`
}
type TestPdfReq struct {
Content string `json:"content"`
Type string `json:"type"`
}
type Request struct {
}
type Response struct {
Code int `json:"code"`
Message string `json:"msg"`
Data interface{} `json:"data"`
}
type Auth struct {
AccessSecret string `json:"accessSecret"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
type File struct {
Filename string `fsfile:"filename"`
Header map[string][]string `fsfile:"header"`
Size int64 `fsfile:"size"`
Data []byte `fsfile:"data"`
}
type Meta struct {
TotalCount int64 `json:"total_count"`
PageCount int64 `json:"page_count"`
CurrentPage int `json:"current_page"`
PerPage int `json:"per_page"`
}
// Set 设置Response的Code和Message值
func (resp *Response) Set(Code int, Message string) *Response {
return &Response{
Code: Code,
Message: Message,
}
}
// Set 设置整个Response
func (resp *Response) SetWithData(Code int, Message string, Data interface{}) *Response {
return &Response{
Code: Code,
Message: Message,
Data: Data,
}
}
// SetStatus 设置默认StatusResponse(内部自定义) 默认msg, 可以带data, data只使用一个参数
func (resp *Response) SetStatus(sr *basic.StatusResponse, data ...interface{}) *Response {
newResp := &Response{
Code: sr.Code,
}
if len(data) == 1 {
newResp.Data = data[0]
}
return newResp
}
// SetStatusWithMessage 设置默认StatusResponse(内部自定义) 非默认msg, 可以带data, data只使用一个参数
func (resp *Response) SetStatusWithMessage(sr *basic.StatusResponse, msg string, data ...interface{}) *Response {
newResp := &Response{
Code: sr.Code,
Message: msg,
}
if len(data) == 1 {
newResp.Data = data[0]
}
return newResp
}

View File

@ -1,2 +1 @@
data-transfer data-transfer
main

View File

@ -2,7 +2,5 @@ FROM alpine
WORKDIR /www/fusenapi/ WORKDIR /www/fusenapi/
COPY ./bin/api-data-transfer-srv /www/fusenapi/ COPY ./bin/api-data-transfer-srv /www/fusenapi/
COPY ./env.yaml /opt/ COPY ./etc /www/fusenapi/etc
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-data-transfer-srv"] CMD ["/www/fusenapi/api-data-transfer-srv"]

View File

@ -1,2 +1 @@
home-user-auth home-user-auth
main

View File

@ -2,7 +2,5 @@ FROM alpine
WORKDIR /www/fusenapi/ WORKDIR /www/fusenapi/
COPY ./bin/api-home-user-auth-srv /www/fusenapi/ COPY ./bin/api-home-user-auth-srv /www/fusenapi/
COPY ./env.yaml /opt/ COPY ./etc /www/fusenapi/etc
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-home-user-auth-srv"] CMD ["/www/fusenapi/api-home-user-auth-srv"]

View File

@ -36,7 +36,9 @@ type Config struct {
} }
} }
BLMService struct { BLMService struct {
Version string Url string
Urls []string LogoCombine struct {
Url string
}
} }
} }

View File

@ -17,11 +17,36 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/user/fonts", Path: "/api/user/fonts",
Handler: UserFontsHandler(serverCtx), Handler: UserFontsHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/api/user/get-type",
Handler: UserGetTypeHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/user/basic-info",
Handler: UserSaveBasicInfoHandler(serverCtx),
},
{ {
Method: http.MethodGet, Method: http.MethodGet,
Path: "/api/user/status-config", Path: "/api/user/status-config",
Handler: UserStatusConfigHandler(serverCtx), Handler: UserStatusConfigHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/api/user/basic-info",
Handler: UserBasicInfoHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/user/address-list",
Handler: UserAddressListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/user/add-address",
Handler: UserAddAddressHandler(serverCtx),
},
{ {
Method: http.MethodPost, Method: http.MethodPost,
Path: "/api/user/contact-service", Path: "/api/user/contact-service",

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/home-user-auth/internal/logic"
"fusenapi/server/home-user-auth/internal/svc"
"fusenapi/server/home-user-auth/internal/types"
)
func UserAddAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.RequestAddAddress
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUserAddAddressLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UserAddAddress(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/home-user-auth/internal/logic"
"fusenapi/server/home-user-auth/internal/svc"
"fusenapi/server/home-user-auth/internal/types"
)
func UserAddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.Request
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUserAddressListLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UserAddressList(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,98 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/home-user-auth/internal/svc"
"fusenapi/server/home-user-auth/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UserAddAddressLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserAddAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserAddAddressLogic {
return &UserAddAddressLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UserAddAddressLogic) UserAddAddress(req *types.RequestAddAddress, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth) // 如果不是用户信息, 返回未授权错误
}
// 确认这个IsDefault的值范围
if !auth.CheckValueRange(req.IsDefault, 0, 1) {
return resp.SetStatus(basic.CodeSafeValueRangeErr) // IsDefault值超出范围, 返回安全值范围错误
}
m := l.svcCtx.AllModels.FsAddress // 创建地址模型
var status int64 = 1 // 默认地址状态为1(正常)
// 如果ID为0, 表示新增地址
if req.Id == 0 {
var (
country string = "USA" // 国家默认为美国
isDefautl int64 = 1 // 默认地址为1
)
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
AddressName: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Country: &country,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
}
created, err := m.CreateOne(l.ctx, createOne) // 新增地址
if err != nil {
logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": created.AddressId}) // 返回成功并返回地址ID
}
address := &gmodel.FsAddress{
AddressId: req.Id,
AddressName: &req.Name,
FirstName: &req.FirstName,
LastName: &req.LastName,
Mobile: &req.Mobile,
Street: &req.Street,
Suite: &req.Suite,
City: &req.City,
State: &req.State,
Status: &status,
UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &req.IsDefault,
}
// 插入数据库 更新地址
err := m.UpdateAddress(l.ctx, address)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbUpdateErr)
}
return resp.SetStatus(basic.CodeOK, map[string]int64{"id": address.AddressId})
}

View File

@ -0,0 +1,42 @@
package logic
import (
"context"
"fusenapi/server/home-user-auth/internal/svc"
"fusenapi/server/home-user-auth/internal/types"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"github.com/zeromicro/go-zero/core/logx"
)
type UserAddressListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserAddressListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserAddressListLogic {
return &UserAddressListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UserAddressListLogic) UserAddressList(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
m := l.svcCtx.AllModels.FsAddress
data, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, err.Error())
}
return resp.SetStatus(basic.CodeOK, data)
}

View File

@ -62,7 +62,6 @@ func (l *UserLogoSetLogic) UserLogoSet(req *types.UserLogoSetReq, userinfo *auth
ResourceId: defaultMaterialInfo.ResourceId, ResourceId: defaultMaterialInfo.ResourceId,
ResourceUrl: defaultMaterialInfo.ResourceUrl, ResourceUrl: defaultMaterialInfo.ResourceUrl,
Ctime: &nowTime, Ctime: &nowTime,
Metadata: defaultMaterialInfo.Metadata,
} }
MaterialCreateRes := l.svcCtx.MysqlConn.Create(&defaultMaterial) MaterialCreateRes := l.svcCtx.MysqlConn.Create(&defaultMaterial)
err = MaterialCreateRes.Error err = MaterialCreateRes.Error

View File

@ -38,9 +38,9 @@ func NewServiceContext(c config.Config) *ServiceContext {
SharedState: nil, SharedState: nil,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{ Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: initalize.InitMysql(c.SourceMysql), GormDB: initalize.InitMysql(c.SourceMysql),
BLMServiceUrls: c.BLMService.Urls, BLMServiceUrl: &c.BLMService.Url,
AwsSession: session.Must(session.NewSession(&config)), AwsSession: session.Must(session.NewSession(&config)),
}), }),
} }
} }

View File

@ -1,2 +1 @@
info info
main

View File

@ -1,8 +0,0 @@
FROM alpine
WORKDIR /www/fusenapi/
COPY ./bin/api-info-srv /www/fusenapi/
COPY ./env.yaml /opt/
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-info-srv"]

View File

@ -14,7 +14,7 @@ import (
func AddressDefaultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { func AddressDefaultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.AddressDefaultRequest var req types.AddressIdRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req) userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil { if err != nil {
return return

View File

@ -42,11 +42,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/info/address/update", Path: "/api/info/address/update",
Handler: AddressUpdateHandler(serverCtx), Handler: AddressUpdateHandler(serverCtx),
}, },
{
Method: http.MethodPost,
Path: "/api/info/address/update/used",
Handler: AddressUsedUpdateHandler(serverCtx),
},
{ {
Method: http.MethodPost, Method: http.MethodPost,
Path: "/api/info/address/delete", Path: "/api/info/address/delete",
@ -57,16 +52,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/info/address/list", Path: "/api/info/address/list",
Handler: AddressListHandler(serverCtx), Handler: AddressListHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/api/info/restaurant/list",
Handler: RestaurantListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/info/contact/us",
Handler: ContactUsHandler(serverCtx),
},
}, },
) )
} }

View File

@ -14,7 +14,7 @@ import (
func UpdateProfileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { func UpdateProfileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.ProfileRequest var req types.ProfileBaseRequest
userinfo, err := basic.RequestParse(w, r, svcCtx, &req) userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil { if err != nil {
return return

View File

@ -49,33 +49,32 @@ func (l *AddressAddLogic) AddressAdd(req *types.AddressRequest, userinfo *auth.U
// 如果ID为0, 表示新增地址 // 如果ID为0, 表示新增地址
var ( var (
country string = "USA" // 国家默认为美国 country string = "USA" // 国家默认为美国
status int64 = 1 // 默认地址状态为1(正常) isDefautl int64 = 1 // 默认地址为1
status int64 = 1 // 默认地址状态为1(正常)
) )
createOne := &gmodel.FsAddress{ // 构建FsAddress结构体 createOne := &gmodel.FsAddress{ // 构建FsAddress结构体
FirstName: &req.FirstName, AddressName: &req.AddressName,
LastName: &req.LastName, FirstName: &req.FirstName,
Mobile: &req.Mobile, LastName: &req.LastName,
Street: &req.Street, Mobile: &req.Mobile,
Suite: &req.Suite, Street: &req.Street,
City: &req.City, Suite: &req.Suite,
State: &req.State, City: &req.City,
Country: &country, State: &req.State,
Status: &status, Country: &country,
UserId: &userinfo.UserId, Status: &status,
ZipCode: &req.ZipCode, UserId: &userinfo.UserId,
ZipCode: &req.ZipCode,
IsDefault: &isDefautl,
} }
address, err := m.CreateOne(l.ctx, createOne) // 新增地址 _, err := m.CreateOne(l.ctx, createOne) // 新增地址
if err != nil { if err != nil {
logx.Error(err) // 日志记录错误 logx.Error(err) // 日志记录错误
return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误 return resp.SetStatus(basic.CodeDbCreateErr) // 返回数据库创建错误
} }
if req.IsDefault > 0 {
m.SettingUserDefaultAddress(l.ctx, userinfo.UserId, address.AddressId, req.IsDefault)
}
addresses, err := m.GetUserAllAddress(l.ctx, userinfo.UserId) addresses, err := m.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
@ -83,7 +82,6 @@ func (l *AddressAddLogic) AddressAdd(req *types.AddressRequest, userinfo *auth.U
} }
return resp.SetStatus(basic.CodeOK, map[string]any{ return resp.SetStatus(basic.CodeOK, map[string]any{
"address_id": address.AddressId,
"address_list": addresses, "address_list": addresses,
}) // 返回成功并返回地址ID }) // 返回成功并返回地址ID

View File

@ -30,7 +30,7 @@ func NewAddressDefaultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ad
// func (l *AddressDefaultLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { // func (l *AddressDefaultLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// } // }
func (l *AddressDefaultLogic) AddressDefault(req *types.AddressDefaultRequest, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *AddressDefaultLogic) AddressDefault(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
@ -38,26 +38,12 @@ func (l *AddressDefaultLogic) AddressDefault(req *types.AddressDefaultRequest, u
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
// 确认这个IsDefault的值范围 err := l.svcCtx.AllModels.FsAddress.SettingUserDefaultAddress(l.ctx, userinfo.UserId, req.AddressId)
if !auth.CheckValueRange(req.IsDefault, 0, 1) {
return resp.SetStatus(basic.CodeSafeValueRangeErr) // IsDefault值超出范围, 返回安全值范围错误
}
err := l.svcCtx.AllModels.FsAddress.SettingUserDefaultAddress(l.ctx, userinfo.UserId, req.AddressId, req.IsDefault)
if err != nil { if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
} }
addresses, err := l.svcCtx.AllModels.FsAddress.GetUserAllAddress(l.ctx, userinfo.UserId) return resp.SetStatus(basic.CodeOK)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbSqlErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_id": req.AddressId,
"address_list": addresses,
}) // 返回成功并返回地址ID
} }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理

View File

@ -43,9 +43,7 @@ func (l *AddressDeleteLogic) AddressDelete(req *types.AddressIdRequest, userinfo
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
} }
return resp.SetStatus(basic.CodeOK, map[string]any{ return resp.SetStatus(basic.CodeOK)
"address_id": req.AddressId,
}) // 返回成功并返回地址ID
} }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理

View File

@ -40,11 +40,6 @@ func (l *AddressUpdateLogic) AddressUpdate(req *types.AddressRequest, userinfo *
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
// 确认这个IsDefault的值范围
if !auth.CheckValueRange(req.IsDefault, 0, 1) {
return resp.SetStatus(basic.CodeSafeValueRangeErr) // IsDefault值超出范围, 返回安全值范围错误
}
now := time.Now().UTC() now := time.Now().UTC()
if req.AddressId == 0 { if req.AddressId == 0 {
@ -52,17 +47,19 @@ func (l *AddressUpdateLogic) AddressUpdate(req *types.AddressRequest, userinfo *
} }
address := gmodel.FsAddress{ address := gmodel.FsAddress{
AddressId: req.AddressId, AddressId: req.AddressId,
UserId: &userinfo.UserId, UserId: &userinfo.UserId,
FirstName: &req.FirstName, IsDefault: &req.IsDefault,
LastName: &req.LastName, AddressName: &req.AddressName,
Mobile: &req.Mobile, FirstName: &req.FirstName,
ZipCode: &req.ZipCode, LastName: &req.LastName,
Street: &req.Street, Mobile: &req.Mobile,
Suite: &req.Suite, ZipCode: &req.ZipCode,
City: &req.City, Street: &req.Street,
State: &req.State, Suite: &req.Suite,
Utime: &now, City: &req.City,
State: &req.State,
Utime: &now,
} }
err := l.svcCtx.AllModels.FsAddress.UpdateAddress(l.ctx, &address) err := l.svcCtx.AllModels.FsAddress.UpdateAddress(l.ctx, &address)
@ -70,19 +67,7 @@ func (l *AddressUpdateLogic) AddressUpdate(req *types.AddressRequest, userinfo *
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error()) return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
} }
l.svcCtx.AllModels.FsAddress.SettingUserDefaultAddress(l.ctx, userinfo.UserId, address.AddressId, req.IsDefault) return resp.SetStatus(basic.CodeOK)
addresses, err := l.svcCtx.AllModels.FsAddress.GetUserAllAddress(l.ctx, userinfo.UserId)
if err != nil {
logx.Error(err)
return resp.SetStatus(basic.CodeDbSqlErr) // 返回数据库创建错误
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_id": req.AddressId,
"address_list": addresses,
}) // 返回成功并返回地址ID
} }
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // 处理逻辑后 w,r 如:重定向, resp 必须重新处理

View File

@ -1,54 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type AddressUsedUpdateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAddressUsedUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddressUsedUpdateLogic {
return &AddressUsedUpdateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *AddressUsedUpdateLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *AddressUsedUpdateLogic) AddressUsedUpdate(req *types.AddressIdRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth)
}
err := l.svcCtx.AllModels.FsAddress.UpdateUsedAddress(l.ctx, req.AddressId, userinfo.UserId)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeApiErr, err.Error())
}
return resp.SetStatus(basic.CodeOK, map[string]any{
"address_id": req.AddressId,
}) // 返回成功并返回地址ID
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *AddressUsedUpdateLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,66 +0,0 @@
package logic
import (
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"time"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ContactUsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewContactUsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ContactUsLogic {
return &ContactUsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *ContactUsLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *ContactUsLogic) ContactUs(req *types.ContactUsRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !auth.ValidateEmail(req.Email) {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "email format error")
}
if req.Message == "" {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "remarks must exist")
}
now := time.Now().UTC()
err := l.svcCtx.AllModels.FsContact.Save(l.ctx, &gmodel.FsContact{
Name: &req.Name,
Email: &req.Email,
Phone: &req.Phone,
Message: &req.Message,
Status: gmodel.FsInt64(0),
Ctime: &now,
})
if err != nil {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, err.Error())
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *ContactUsLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,71 +0,0 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/info/internal/svc"
"fusenapi/server/info/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type RestaurantListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRestaurantListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RestaurantListLogic {
return &RestaurantListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *RestaurantListLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *RestaurantListLogic) RestaurantList(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
values := []string{
"Pizza Shop",
"Coffee Shop",
"Salad Shop",
"Other Non-Asian Restaurants",
"Fried Chicken / Burger / Sandwich Restaurant",
"Other Restaurants",
"Bakery / Dessert Shop",
"Ramen /Vietnamese / Thai / Korean / Chinese",
"Breakfast & Brunch",
"Moxican",
"Pho",
"Ramen",
"Chinese",
"Burgers",
"Sushi Restaurant",
"Indian",
"Vegan",
"Smoothie",
"Healthy",
"Soup",
"Italian",
"Boba Tea Shop",
"Other",
"Korean / Thai",
"Bar",
}
return resp.SetStatus(basic.CodeOK, values)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *RestaurantListLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -30,15 +30,13 @@ func NewUpdateProfileBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext)
// func (l *UpdateProfileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { // func (l *UpdateProfileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// } // }
func (l *UpdateProfileBaseLogic) UpdateProfileBase(req *types.ProfileRequest, userinfo *auth.UserInfo) (resp *basic.Response) { func (l *UpdateProfileBaseLogic) UpdateProfileBase(req *types.ProfileBaseRequest, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null // userinfo 传入值时, 一定不为null
if !userinfo.IsUser() { if !userinfo.IsUser() {
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
req.ProfileBase.Email = nil
err := l.svcCtx.AllModels.FsUserInfo.MergeMetadata(userinfo.UserId, req) err := l.svcCtx.AllModels.FsUserInfo.MergeMetadata(userinfo.UserId, req)
if err != nil { if err != nil {
logx.Error(err) // 日志记录错误 logx.Error(err) // 日志记录错误

View File

@ -5,13 +5,6 @@ import (
"fusenapi/utils/basic" "fusenapi/utils/basic"
) )
type ContactUsRequest struct {
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
Message string `json:"message"`
}
type UserInfoRequest struct { type UserInfoRequest struct {
Module []string `json:"module"` Module []string `json:"module"`
} }
@ -25,53 +18,33 @@ type AddressIdRequest struct {
AddressId int64 `json:"address_id"` // 地址id AddressId int64 `json:"address_id"` // 地址id
} }
type AddressDefaultRequest struct { type AddressNameRequest struct {
AddressId int64 `json:"address_id"` // 地址id AddressName string `json:"address_name"` // 地址
IsDefault int64 `json:"is_default"` // 是否默认
} }
type AddressRequest struct { type AddressRequest struct {
AddressId int64 `json:"address_id,optional"` AddressId int64 `json:"address_id,optional"`
IsDefault int64 `json:"is_default"` //是否默认 IsDefault int64 `json:"is_default"` //是否默认
FirstName string `json:"first_name"` //first_name AddressName string `json:"address_name"` //收货人
LastName string `json:"last_name"` //last_name FirstName string `json:"first_name"` //first_name
Mobile string `json:"mobile"` //手机 LastName string `json:"last_name"` //last_name
ZipCode string `json:"zip_code"` //邮编 Mobile string `json:"mobile"` //手机
Street string `json:"street"` //街道 ZipCode string `json:"zip_code"` //邮编
Suite string `json:"suite"` //房号 Street string `json:"street"` //街道
City string `json:"city"` //城市 Suite string `json:"suite"` //房号
State string `json:"state"` //州 City string `json:"city"` //城市
State string `json:"state"` //州
} }
type ProfileRequest struct { type ProfileBaseRequest struct {
ProfileBase *ProfileBase `json:"base,optional,omitempty"` // 基础的个人消息, 姓名 公司等
SubscriptionStatus *SubscriptionStatus `json:"sub_status,optional,omitempty"` // 订阅的通知状态
}
type ProfileBase struct {
FirstName *string `json:"first_name,optional,omitempty"` // 首名 FirstName *string `json:"first_name,optional,omitempty"` // 首名
LastName *string `json:"last_name,optional,omitempty"` // 后名 LastName *string `json:"last_name,optional,omitempty"` // 后名
Email *string `json:"email,optional,omitempty"` // email UserName *string `json:"user_name,optional,omitempty"` // 用户名
Mobile *string `json:"mobile,optional,omitempty"` // 电话 Mobile *string `json:"mobile,optional,omitempty"` // 电话
Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么 Resetaurant *string `json:"resetaurant,optional,omitempty"` // 不知道干什么
Company *string `json:"company,optional,omitempty"` // 公司 Company *string `json:"company,optional,omitempty"` // 公司
} }
type SubscriptionStatus struct {
NotificationEmail NotificationEmail `json:"notification_email,optional,omitempty"`
NotificationPhone NotificationPhone `json:"notification_phone,optional,omitempty"`
}
type NotificationEmail struct {
OrderUpdate bool `json:"order_update,optional,omitempty"`
Newseleter bool `json:"newseleter,optional,omitempty"`
}
type NotificationPhone struct {
OrderUpdate bool `json:"order_update,optional,omitempty"`
Newseleter bool `json:"newseleter,optional,omitempty"`
}
type QueryProfileRequest struct { type QueryProfileRequest struct {
TopKey string `json:"top_key"` // 首名 TopKey string `json:"top_key"` // 首名
} }

View File

@ -1,2 +1 @@
map-library map-library
main

View File

@ -2,7 +2,5 @@ FROM alpine
WORKDIR /www/fusenapi/ WORKDIR /www/fusenapi/
COPY ./bin/api-map-library-srv /www/fusenapi/ COPY ./bin/api-map-library-srv /www/fusenapi/
COPY ./env.yaml /opt/ COPY ./etc /www/fusenapi/etc
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-map-library-srv"] CMD ["/www/fusenapi/api-map-library-srv"]

View File

@ -1,2 +1 @@
order order
main

View File

@ -1,8 +0,0 @@
FROM alpine
WORKDIR /www/fusenapi/
COPY ./bin/api-order-srv /www/fusenapi/
COPY ./env.yaml /opt/
COPY ./server.fusen.3718.cn.pem /opt/
COPY ./server.fusen.3718.cn.key /opt/
CMD ["/www/fusenapi/api-order-srv"]

View File

@ -27,16 +27,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/order/create-prepayment-balance", Path: "/api/order/create-prepayment-balance",
Handler: CreatePrePaymentByBalanceHandler(serverCtx), Handler: CreatePrePaymentByBalanceHandler(serverCtx),
}, },
{
Method: http.MethodPost,
Path: "/api/order/delete",
Handler: DeleteOrderHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/order/close",
Handler: CloseOrderHandler(serverCtx),
},
{ {
Method: http.MethodGet, Method: http.MethodGet,
Path: "/api/order/list", Path: "/api/order/list",

View File

@ -1,56 +0,0 @@
package logic
import (
"fusenapi/service/repositories"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/order/internal/svc"
"fusenapi/server/order/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CloseOrderLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCloseOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CloseOrderLogic {
return &CloseOrderLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *CloseOrderLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *CloseOrderLogic) CloseOrder(req *types.CloseOrderReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
// 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth)
}
res, err := l.svcCtx.Repositories.NewOrder.Close(l.ctx, &repositories.CloseReq{
UserId: userinfo.UserId,
OrderSn: req.OrderSn,
Type: 1,
})
if err != nil {
return resp.SetStatus(&res.ErrorCode)
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *CloseOrderLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -1,7 +1,6 @@
package logic package logic
import ( import (
"fmt"
"fusenapi/constants" "fusenapi/constants"
"fusenapi/service/repositories" "fusenapi/service/repositories"
"fusenapi/utils/auth" "fusenapi/utils/auth"
@ -41,7 +40,7 @@ func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth
// 如果是,返回未授权的错误码 // 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth) return resp.SetStatus(basic.CodeUnAuth)
} }
tPlus60Days := time.Now().AddDate(0, 0, 60).UTC() tPlus60Days := time.Now().AddDate(0, 0, 60)
res, err := l.svcCtx.Repositories.NewOrder.Create(l.ctx, &repositories.CreateReq{ res, err := l.svcCtx.Repositories.NewOrder.Create(l.ctx, &repositories.CreateReq{
ExpectedDeliveryTime: tPlus60Days, ExpectedDeliveryTime: tPlus60Days,
CurrentCurrency: string(constants.CURRENCYUSD), CurrentCurrency: string(constants.CURRENCYUSD),
@ -55,36 +54,6 @@ func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq, userinfo *auth
return resp.SetStatus(&res.ErrorCode) return resp.SetStatus(&res.ErrorCode)
} }
// 延时任务
// l.svcCtx.DelayQueue.AddTask(time.Now().Add(time.Minute*30), constants.QUEUE_NAME_ORDER, func(args ...interface{}) {
// ctx := context.Background()
// orderSn := args[0].(string)
// svcCtx := svc.ServiceContext{
// Config: l.svcCtx.Config,
// Repositories: l.svcCtx.Repositories,
// }
// svcCtx.Repositories.NewOrder.Close(ctx, &repositories.CloseReq{
// OrderSn: orderSn,
// Type: 1,
// })
// }, []interface{}{res.OrderSn})
// 延时任务
time.AfterFunc(time.Minute*30, func() {
orderSn := res.OrderSn
fmt.Println("延时任务: OrderSn--", orderSn)
ctx := context.Background()
svcCtx := svc.ServiceContext{
Config: l.svcCtx.Config,
Repositories: l.svcCtx.Repositories,
}
svcCtx.Repositories.NewOrder.Close(ctx, &repositories.CloseReq{
OrderSn: orderSn,
Type: 1,
})
})
return resp.SetStatus(basic.CodeOK, map[string]interface{}{ return resp.SetStatus(basic.CodeOK, map[string]interface{}{
"order_sn": res.OrderSn, "order_sn": res.OrderSn,
}) })

View File

@ -1,55 +0,0 @@
package logic
import (
"fusenapi/service/repositories"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/order/internal/svc"
"fusenapi/server/order/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteOrderLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewDeleteOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteOrderLogic {
return &DeleteOrderLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *DeleteOrderLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *DeleteOrderLogic) DeleteOrder(req *types.DeleteOrderReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
if !userinfo.IsUser() {
// 如果是,返回未授权的错误码
return resp.SetStatus(basic.CodeUnAuth)
}
res, err := l.svcCtx.Repositories.NewOrder.Delete(l.ctx, &repositories.DeleteReq{
UserId: userinfo.UserId,
OrderSn: req.OrderSn,
})
if err != nil {
return resp.SetStatus(&res.ErrorCode)
}
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *DeleteOrderLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -2,7 +2,6 @@ package svc
import ( import (
"fusenapi/server/order/internal/config" "fusenapi/server/order/internal/config"
"fusenapi/utils/queue"
"fusenapi/initalize" "fusenapi/initalize"
"fusenapi/model/gmodel" "fusenapi/model/gmodel"
@ -16,22 +15,17 @@ type ServiceContext struct {
MysqlConn *gorm.DB MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen AllModels *gmodel.AllModelsGen
Repositories *initalize.Repositories Repositories *initalize.Repositories
DelayQueue *queue.DelayMessage
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
conn := initalize.InitMysql(c.SourceMysql) conn := initalize.InitMysql(c.SourceMysql)
// delayQueue := initalize.InitDelayMessage()
repositories := initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
// DelayQueue: delayQueue,
})
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
MysqlConn: conn, MysqlConn: conn,
AllModels: gmodel.NewAllModels(conn), AllModels: gmodel.NewAllModels(conn),
Repositories: repositories, Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
// DelayQueue: delayQueue, GormDB: conn,
}),
} }
} }

Some files were not shown because too many files have changed in this diff Show More