From 503b6ddd4f8ef4adb639b911ba95ebad96e6b2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=87=E5=B3=B0?= Date: Mon, 13 Apr 2026 21:29:51 +0800 Subject: [PATCH] up --- .workbuddy/expert-history.json | 2 +- backend/my_work/routers/apiPurchase.go | 196 +++++++++--------- frontend/ops_vue_js/src/i18n/en.json | 5 +- frontend/ops_vue_js/src/i18n/zh-CN.json | 5 +- frontend/ops_vue_js/src/stores/users.js | 47 ++--- .../src/views/purchase/ShowOrder.vue | 80 +++++-- .../src/views/purchase/addorder.vue | 8 +- 7 files changed, 202 insertions(+), 141 deletions(-) diff --git a/.workbuddy/expert-history.json b/.workbuddy/expert-history.json index 543c17d..29a355f 100644 --- a/.workbuddy/expert-history.json +++ b/.workbuddy/expert-history.json @@ -13,5 +13,5 @@ } ] }, - "lastUpdated": 1776083682738 + "lastUpdated": 1776086663736 } \ No newline at end of file diff --git a/backend/my_work/routers/apiPurchase.go b/backend/my_work/routers/apiPurchase.go index ebcc4e6..5918730 100644 --- a/backend/my_work/routers/apiPurchase.go +++ b/backend/my_work/routers/apiPurchase.go @@ -8,28 +8,33 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/mitchellh/mapstructure" "gorm.io/gorm" ) +// decodeJSON 将 map 通过 JSON 中转解码到目标结构体,绕过 mapstructure 的字段名匹配问题 +func decodeJSON(data map[string]interface{}, out interface{}) error { + jsonBytes, err := json.Marshal(data) + if err != nil { + return err + } + return json.Unmarshal(jsonBytes, out) +} + type CostItem struct { - Cost int `json:"cost"` // 费用(分) - CostT int `json:"costt"` // 总价 - CurrencyType int `json:"currencytype"` // 货币类型: 1-CNY 2-MOP 3-HKD 4-USD - Int int `json:"int"` // 数量 - Type int `json:"type"` // 费用类型: 1-单价 2-运费 + Cost int `json:"cost"` // 费用(分) + CostT int `json:"costt"` // 总价 + CurrencyType int `json:"currencytype"` // 货币类型: 1-CNY 2-MOP 3-HKD 4-USD + Int int `json:"int"` // 数量 + Type int `json:"type"` // 费用类型: 1-单价 2-运费 } type From_purchase_addorder struct { Costs []CostItem `json:"costs"` // 成本 Link string `json:"link"` // 链接 OrderStatus string `json:"order_status"` // 订单状态 - //PartName string `json:"partname"` // 物件名称 - Photos []string `json:"photos"` // 图片备注 - Remark string `json:"remark"` // 备注 - Styles string `json:"styles"` // 样式备注 - Title string `json:"title"` // 标题 - //TrackingNumber string `json:"tracking_number"` // 快递单号 - //UpdateTime string `json:"update_time"` // 更新时间 + Photos []string `json:"photos"` // 图片备注 + Remark string `json:"remark"` // 备注 + Styles string `json:"styles"` // 样式备注 + Title string `json:"title"` // 标题 } type TabPurchaseOrder struct { @@ -39,21 +44,21 @@ type TabPurchaseOrder struct { Remark string `gorm:"type:text;comment:备注"` Link string `gorm:"size:1000;comment:链接"` Styles string `gorm:"type:text;comment:样式数组"` - OrderStatus string `gorm:"size:50;default:pending;comment:订单状态: pending-待处理 ordered-已下单 arrived-已到达 received-已收件"` + OrderStatus string `gorm:"size:50;default:pending;comment:订单状态: pending-待处理 ordered-已下单 arrived-已到达 received-已收件 lost-丢件 returned-退件"` CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"` UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index"` } type TabPurchaseCosts struct { - ID uint `gorm:"primarykey"` - OrderID uint `gorm:"not null"` - UserID uint `gorm:"not null"` - Price int `gorm:"not null"` - Quantity int `gorm:"not null"` - CurrencyType int `gorm:"default:1;comment:货币类型: 1-CNY 2-MOP 3-HKD 4-USD"` - CostType int `gorm:"default:1;comment:费用类型: 1-单价 2-运费"` - CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"` + ID uint `gorm:"primarykey"` + OrderID uint `gorm:"not null"` + UserID uint `gorm:"not null"` + Price int `gorm:"not null"` + Quantity int `gorm:"not null"` + CurrencyType int `gorm:"default:1;comment:货币类型: 1-CNY 2-MOP 3-HKD 4-USD"` + CostType int `gorm:"default:1;comment:费用类型: 1-单价 2-运费"` + CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"` } type TabPurchaseFileBind struct { @@ -113,7 +118,7 @@ func ApiPurchase(r *gin.RouterGroup) { ID uint `json:"id"` } var from FromGetOrder - if err := mapstructure.Decode(data, &from); err != nil || from.ID == 0 { + if err := decodeJSON(data, &from); err != nil || from.ID == 0 { ReturnJson(ctx, "jsonErr", nil) return } @@ -212,7 +217,7 @@ func ApiPurchase(r *gin.RouterGroup) { Photos []string `json:"photos"` // 变更附带的图片哈希 } var from FromUpdateStatus - if err := mapstructure.Decode(data, &from); err != nil || from.ID == 0 { + if err := decodeJSON(data, &from); err != nil || from.ID == 0 { ReturnJson(ctx, "jsonErr", nil) return } @@ -231,6 +236,8 @@ func ApiPurchase(r *gin.RouterGroup) { "ordered": true, "arrived": true, "received": true, + "lost": true, + "returned": true, } if !validStatuses[from.Status] { ReturnJson(ctx, "invalid_status", nil) @@ -283,7 +290,7 @@ func ApiPurchase(r *gin.RouterGroup) { // 写操作日志 newContent, _ := json.Marshal(map[string]string{ - "status": from.Status, + "status": from.Status, "comment": comment, }) oldContent, _ := json.Marshal(map[string]string{ @@ -316,7 +323,7 @@ func ApiPurchase(r *gin.RouterGroup) { } var jsondata From_purchase_getorders - if err := mapstructure.Decode(data, &jsondata); err == nil { + if err := decodeJSON(data, &jsondata); err == nil { fmt.Println(jsondata) is_data_ok := true @@ -366,7 +373,8 @@ func ApiPurchase(r *gin.RouterGroup) { //fmt.Println(user) //DebugPrintJson(data) var jsondata From_purchase_addorder - if err := mapstructure.Decode(data, &jsondata); err == nil { + fmt.Println(data) + if err := decodeJSON(data, &jsondata); err == nil { //jsonStr, _ := json.MarshalIndent(jsondata, "", " ") //fmt.Println("转换后数据:\n", string(jsonStr)) @@ -406,79 +414,79 @@ func ApiPurchase(r *gin.RouterGroup) { // fmt.Println("err5") // } - if is_data_ok { - //校验通过 - //photos, _ := json.Marshal(jsondata.Photos) - new_data := TabPurchaseOrder{ - UserID: user.ID, - Title: jsondata.Title, - Remark: jsondata.Remark, - Link: jsondata.Link, - Styles: jsondata.Styles, - OrderStatus: "pending", // 默认待处理 - } - models.DB.Create(&new_data) + if is_data_ok { + //校验通过 + //photos, _ := json.Marshal(jsondata.Photos) + new_data := TabPurchaseOrder{ + UserID: user.ID, + Title: jsondata.Title, + Remark: jsondata.Remark, + Link: jsondata.Link, + Styles: jsondata.Styles, + OrderStatus: "pending", // 默认待处理 + } + models.DB.Create(&new_data) - for i := 0; i < len(jsondata.Costs); i++ { - currencyType := jsondata.Costs[i].CurrencyType - if currencyType <= 0 { - currencyType = 1 // 默认 CNY - } - costType := jsondata.Costs[i].Type - if costType <= 0 { - costType = 1 // 默认单价 - } - new_cost_data := TabPurchaseCosts{ - Price: jsondata.Costs[i].Cost, - Quantity: jsondata.Costs[i].Int, - UserID: user.ID, - OrderID: new_data.ID, - CurrencyType: currencyType, - CostType: costType, - } - models.DB.Create(&new_cost_data) - } - - //绑定文件 - for i := 0; i < len(jsondata.Photos); i++ { - findFile := models.TabFileInfo_{ - Sha256: jsondata.Photos[i], - Type: "image", - } - if models.DB.Where(&findFile).First(&findFile).Error == nil { - bind := TabPurchaseFileBind{ - OrderID: new_data.ID, - FileID: findFile.ID, + for i := 0; i < len(jsondata.Costs); i++ { + currencyType := jsondata.Costs[i].CurrencyType + if currencyType <= 0 { + currencyType = 1 // 默认 CNY } - models.DB.Create(&bind) + costType := jsondata.Costs[i].Type + if costType <= 0 { + costType = 1 // 默认单价 + } + new_cost_data := TabPurchaseCosts{ + Price: jsondata.Costs[i].Cost, + Quantity: jsondata.Costs[i].Int, + UserID: user.ID, + OrderID: new_data.ID, + CurrencyType: currencyType, + CostType: costType, + } + models.DB.Create(&new_cost_data) } - } - // 写创建日志 - newContent, _ := json.Marshal(jsondata) - tosqllog := TabPurchaseLog{ - UserID: user.ID, - OrderID: new_data.ID, - ActionType: "create", - NewContent: string(newContent), - OldContent: "", - IP: ctx.ClientIP(), - } - models.DB.Create(&tosqllog) + //绑定文件 + for i := 0; i < len(jsondata.Photos); i++ { + findFile := models.TabFileInfo_{ + Sha256: jsondata.Photos[i], + Type: "image", + } + if models.DB.Where(&findFile).First(&findFile).Error == nil { + bind := TabPurchaseFileBind{ + OrderID: new_data.ID, + FileID: findFile.ID, + } + models.DB.Create(&bind) + } + } - // 写状态创建 commit - commitLog := TabPurchaseCommit{ - OrderID: new_data.ID, - UserID: user.ID, - Action: "create", - Status: "pending", - OldStatus: "", - Comment: "订单创建", - IP: ctx.ClientIP(), - } - models.DB.Create(&commitLog) + // 写创建日志 + newContent, _ := json.Marshal(jsondata) + tosqllog := TabPurchaseLog{ + UserID: user.ID, + OrderID: new_data.ID, + ActionType: "create", + NewContent: string(newContent), + OldContent: "", + IP: ctx.ClientIP(), + } + models.DB.Create(&tosqllog) - ReturnJson(ctx, "apiOK", nil) + // 写状态创建 commit + commitLog := TabPurchaseCommit{ + OrderID: new_data.ID, + UserID: user.ID, + Action: "create", + Status: "pending", + OldStatus: "", + Comment: "订单创建", + IP: ctx.ClientIP(), + } + models.DB.Create(&commitLog) + + ReturnJson(ctx, "apiOK", nil) } else { ReturnJson(ctx, "jsonErr_1", nil) diff --git a/frontend/ops_vue_js/src/i18n/en.json b/frontend/ops_vue_js/src/i18n/en.json index 318e9a2..11444c3 100644 --- a/frontend/ops_vue_js/src/i18n/en.json +++ b/frontend/ops_vue_js/src/i18n/en.json @@ -70,6 +70,8 @@ "status_ordered": "Ordered", "status_arrived": "Arrived", "status_received": "Received", + "status_lost": "Lost", + "status_returned": "Returned", "completed": "Completed", "pending": "Pending", "show": "Show", @@ -226,7 +228,8 @@ "type_cof_pass": "Confirm new password", "old_pass_incorrect": "Old password is incorrect", "confirm_password_incorrect": "Confirm password is incorrect", - "save_success": "Saved successfully" + "save_success": "Saved successfully", + "submit": "Submit" }, "settings": { "cancel": "Cancel", diff --git a/frontend/ops_vue_js/src/i18n/zh-CN.json b/frontend/ops_vue_js/src/i18n/zh-CN.json index a254c2a..bdf9431 100644 --- a/frontend/ops_vue_js/src/i18n/zh-CN.json +++ b/frontend/ops_vue_js/src/i18n/zh-CN.json @@ -70,6 +70,8 @@ "status_ordered": "已下单", "status_arrived": "已到达", "status_received": "已收件", + "status_lost": "丢件", + "status_returned": "退件", "completed": "已完成", "pending": "待处理", "show": "显示", @@ -226,7 +228,8 @@ "type_cof_pass": "确认新密码", "old_pass_incorrect": "旧密码不正确", "confirm_password_incorrect": "确认密码不正确", - "save_success": "保存成功" + "save_success": "保存成功", + "submit": "提交" }, "settings": { "cancel": "取消", diff --git a/frontend/ops_vue_js/src/stores/users.js b/frontend/ops_vue_js/src/stores/users.js index 231e576..6ef79f8 100644 --- a/frontend/ops_vue_js/src/stores/users.js +++ b/frontend/ops_vue_js/src/stores/users.js @@ -7,34 +7,33 @@ import { usersApi } from '@/api/users'; export const useUsersStore = defineStore('users', () => { const usersInfo =ref([]); - function getUsernameFromUserID(userID){ - //console.log(userID) - //先在usersInfo找找有没有 - const target = usersInfo.value?.find(item => item.UserID === userID) - if(target){ - return target.Username //有的话直接返回 - }else{ - //没有的话 询问后端 - usersApi.getUserInfoFromUserID(userID).then((r)=>{ - //console.log(r) - if(r.errCode==0) - { - switch(r.raw.err_code){ - case 0: - if(r.raw.return.userinfo){ - usersInfo.value.push(r.raw.return.userinfo) - } - break; - } - } - }) + function getUserFromUserID(userID){ + return usersInfo.value?.find(item => item.UserID === userID) ?? null + } - return "..." // 第一次返回这个,不会空白/报错 - } + function getUsernameFromUserID(userID){ + const target = getUserFromUserID(userID) + if (target) { + return target.Username + } + usersApi.getUserInfoFromUserID(userID).then((r) => { + if (r.errCode == 0 && r.raw.err_code == 0 && r.raw.return.userinfo) { + usersInfo.value.push(r.raw.return.userinfo) + } + }) + return "..." + } + + function getAvatarUrlFromUserID(userID) { + const target = getUserFromUserID(userID) + if (target?.AvatarPath) { + return `/api/static/avatar/${target.AvatarPath}` + } + return `/ava.svg` } return{ - usersInfo,getUsernameFromUserID, + usersInfo,getUsernameFromUserID,getAvatarUrlFromUserID, } }) \ No newline at end of file diff --git a/frontend/ops_vue_js/src/views/purchase/ShowOrder.vue b/frontend/ops_vue_js/src/views/purchase/ShowOrder.vue index af9b341..35a873e 100644 --- a/frontend/ops_vue_js/src/views/purchase/ShowOrder.vue +++ b/frontend/ops_vue_js/src/views/purchase/ShowOrder.vue @@ -6,6 +6,7 @@ import { useToastStore } from "@/stores/toast"; import { usePageTitle } from "@/composables/usePageTitle"; import { purchaseApi } from "@/api/purchase"; import { useUserStore } from "@/stores/user"; +import { useUsersStore } from "@/stores/users"; import { IconChevronLeft, IconExternalLink, @@ -22,6 +23,7 @@ const { t, locale } = useI18n(); const route = useRoute(); const router = useRouter(); const toast = useToastStore(); +const usersStore = useUsersStore(); const userStore = useUserStore(); const orderId = computed(() => parseInt(route.params.id)); @@ -47,6 +49,8 @@ const statusOptions = [ { value: "ordered", labelKey: "status_ordered", color: "blue" }, { value: "arrived", labelKey: "status_arrived", color: "purple" }, { value: "received", labelKey: "status_received", color: "green" }, + { value: "lost", labelKey: "status_lost", color: "red" }, + { value: "returned", labelKey: "status_returned", color: "gray" }, ]; // 状态颜色映射 @@ -58,6 +62,10 @@ const statusColorClass = computed(() => ({ "bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-400", received: "bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400", + lost: + "bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-400", + returned: + "bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-300", })); // 货币选项 @@ -278,6 +286,7 @@ onMounted(fetchOrder);