up
This commit is contained in:
@@ -13,5 +13,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lastUpdated": 1776083682738
|
"lastUpdated": 1776086663736
|
||||||
}
|
}
|
||||||
@@ -8,28 +8,33 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"gorm.io/gorm"
|
"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 {
|
type CostItem struct {
|
||||||
Cost int `json:"cost"` // 费用(分)
|
Cost int `json:"cost"` // 费用(分)
|
||||||
CostT int `json:"costt"` // 总价
|
CostT int `json:"costt"` // 总价
|
||||||
CurrencyType int `json:"currencytype"` // 货币类型: 1-CNY 2-MOP 3-HKD 4-USD
|
CurrencyType int `json:"currencytype"` // 货币类型: 1-CNY 2-MOP 3-HKD 4-USD
|
||||||
Int int `json:"int"` // 数量
|
Int int `json:"int"` // 数量
|
||||||
Type int `json:"type"` // 费用类型: 1-单价 2-运费
|
Type int `json:"type"` // 费用类型: 1-单价 2-运费
|
||||||
}
|
}
|
||||||
type From_purchase_addorder struct {
|
type From_purchase_addorder struct {
|
||||||
Costs []CostItem `json:"costs"` // 成本
|
Costs []CostItem `json:"costs"` // 成本
|
||||||
Link string `json:"link"` // 链接
|
Link string `json:"link"` // 链接
|
||||||
OrderStatus string `json:"order_status"` // 订单状态
|
OrderStatus string `json:"order_status"` // 订单状态
|
||||||
//PartName string `json:"partname"` // 物件名称
|
Photos []string `json:"photos"` // 图片备注
|
||||||
Photos []string `json:"photos"` // 图片备注
|
Remark string `json:"remark"` // 备注
|
||||||
Remark string `json:"remark"` // 备注
|
Styles string `json:"styles"` // 样式备注
|
||||||
Styles string `json:"styles"` // 样式备注
|
Title string `json:"title"` // 标题
|
||||||
Title string `json:"title"` // 标题
|
|
||||||
//TrackingNumber string `json:"tracking_number"` // 快递单号
|
|
||||||
//UpdateTime string `json:"update_time"` // 更新时间
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabPurchaseOrder struct {
|
type TabPurchaseOrder struct {
|
||||||
@@ -39,21 +44,21 @@ type TabPurchaseOrder struct {
|
|||||||
Remark string `gorm:"type:text;comment:备注"`
|
Remark string `gorm:"type:text;comment:备注"`
|
||||||
Link string `gorm:"size:1000;comment:链接"`
|
Link string `gorm:"size:1000;comment:链接"`
|
||||||
Styles string `gorm:"type:text;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"`
|
CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"`
|
||||||
UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime"`
|
UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabPurchaseCosts struct {
|
type TabPurchaseCosts struct {
|
||||||
ID uint `gorm:"primarykey"`
|
ID uint `gorm:"primarykey"`
|
||||||
OrderID uint `gorm:"not null"`
|
OrderID uint `gorm:"not null"`
|
||||||
UserID uint `gorm:"not null"`
|
UserID uint `gorm:"not null"`
|
||||||
Price int `gorm:"not null"`
|
Price int `gorm:"not null"`
|
||||||
Quantity int `gorm:"not null"`
|
Quantity int `gorm:"not null"`
|
||||||
CurrencyType int `gorm:"default:1;comment:货币类型: 1-CNY 2-MOP 3-HKD 4-USD"`
|
CurrencyType int `gorm:"default:1;comment:货币类型: 1-CNY 2-MOP 3-HKD 4-USD"`
|
||||||
CostType int `gorm:"default:1;comment:费用类型: 1-单价 2-运费"`
|
CostType int `gorm:"default:1;comment:费用类型: 1-单价 2-运费"`
|
||||||
CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"`
|
CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabPurchaseFileBind struct {
|
type TabPurchaseFileBind struct {
|
||||||
@@ -113,7 +118,7 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
}
|
}
|
||||||
var from FromGetOrder
|
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)
|
ReturnJson(ctx, "jsonErr", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -212,7 +217,7 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
Photos []string `json:"photos"` // 变更附带的图片哈希
|
Photos []string `json:"photos"` // 变更附带的图片哈希
|
||||||
}
|
}
|
||||||
var from FromUpdateStatus
|
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)
|
ReturnJson(ctx, "jsonErr", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -231,6 +236,8 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
"ordered": true,
|
"ordered": true,
|
||||||
"arrived": true,
|
"arrived": true,
|
||||||
"received": true,
|
"received": true,
|
||||||
|
"lost": true,
|
||||||
|
"returned": true,
|
||||||
}
|
}
|
||||||
if !validStatuses[from.Status] {
|
if !validStatuses[from.Status] {
|
||||||
ReturnJson(ctx, "invalid_status", nil)
|
ReturnJson(ctx, "invalid_status", nil)
|
||||||
@@ -283,7 +290,7 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
|
|
||||||
// 写操作日志
|
// 写操作日志
|
||||||
newContent, _ := json.Marshal(map[string]string{
|
newContent, _ := json.Marshal(map[string]string{
|
||||||
"status": from.Status,
|
"status": from.Status,
|
||||||
"comment": comment,
|
"comment": comment,
|
||||||
})
|
})
|
||||||
oldContent, _ := json.Marshal(map[string]string{
|
oldContent, _ := json.Marshal(map[string]string{
|
||||||
@@ -316,7 +323,7 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var jsondata From_purchase_getorders
|
var jsondata From_purchase_getorders
|
||||||
if err := mapstructure.Decode(data, &jsondata); err == nil {
|
if err := decodeJSON(data, &jsondata); err == nil {
|
||||||
fmt.Println(jsondata)
|
fmt.Println(jsondata)
|
||||||
|
|
||||||
is_data_ok := true
|
is_data_ok := true
|
||||||
@@ -366,7 +373,8 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
//fmt.Println(user)
|
//fmt.Println(user)
|
||||||
//DebugPrintJson(data)
|
//DebugPrintJson(data)
|
||||||
var jsondata From_purchase_addorder
|
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, "", " ")
|
//jsonStr, _ := json.MarshalIndent(jsondata, "", " ")
|
||||||
//fmt.Println("转换后数据:\n", string(jsonStr))
|
//fmt.Println("转换后数据:\n", string(jsonStr))
|
||||||
@@ -406,79 +414,79 @@ func ApiPurchase(r *gin.RouterGroup) {
|
|||||||
// fmt.Println("err5")
|
// fmt.Println("err5")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if is_data_ok {
|
if is_data_ok {
|
||||||
//校验通过
|
//校验通过
|
||||||
//photos, _ := json.Marshal(jsondata.Photos)
|
//photos, _ := json.Marshal(jsondata.Photos)
|
||||||
new_data := TabPurchaseOrder{
|
new_data := TabPurchaseOrder{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
Title: jsondata.Title,
|
Title: jsondata.Title,
|
||||||
Remark: jsondata.Remark,
|
Remark: jsondata.Remark,
|
||||||
Link: jsondata.Link,
|
Link: jsondata.Link,
|
||||||
Styles: jsondata.Styles,
|
Styles: jsondata.Styles,
|
||||||
OrderStatus: "pending", // 默认待处理
|
OrderStatus: "pending", // 默认待处理
|
||||||
}
|
}
|
||||||
models.DB.Create(&new_data)
|
models.DB.Create(&new_data)
|
||||||
|
|
||||||
for i := 0; i < len(jsondata.Costs); i++ {
|
for i := 0; i < len(jsondata.Costs); i++ {
|
||||||
currencyType := jsondata.Costs[i].CurrencyType
|
currencyType := jsondata.Costs[i].CurrencyType
|
||||||
if currencyType <= 0 {
|
if currencyType <= 0 {
|
||||||
currencyType = 1 // 默认 CNY
|
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,
|
|
||||||
}
|
}
|
||||||
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)
|
for i := 0; i < len(jsondata.Photos); i++ {
|
||||||
tosqllog := TabPurchaseLog{
|
findFile := models.TabFileInfo_{
|
||||||
UserID: user.ID,
|
Sha256: jsondata.Photos[i],
|
||||||
OrderID: new_data.ID,
|
Type: "image",
|
||||||
ActionType: "create",
|
}
|
||||||
NewContent: string(newContent),
|
if models.DB.Where(&findFile).First(&findFile).Error == nil {
|
||||||
OldContent: "",
|
bind := TabPurchaseFileBind{
|
||||||
IP: ctx.ClientIP(),
|
OrderID: new_data.ID,
|
||||||
}
|
FileID: findFile.ID,
|
||||||
models.DB.Create(&tosqllog)
|
}
|
||||||
|
models.DB.Create(&bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 写状态创建 commit
|
// 写创建日志
|
||||||
commitLog := TabPurchaseCommit{
|
newContent, _ := json.Marshal(jsondata)
|
||||||
OrderID: new_data.ID,
|
tosqllog := TabPurchaseLog{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
Action: "create",
|
OrderID: new_data.ID,
|
||||||
Status: "pending",
|
ActionType: "create",
|
||||||
OldStatus: "",
|
NewContent: string(newContent),
|
||||||
Comment: "订单创建",
|
OldContent: "",
|
||||||
IP: ctx.ClientIP(),
|
IP: ctx.ClientIP(),
|
||||||
}
|
}
|
||||||
models.DB.Create(&commitLog)
|
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 {
|
} else {
|
||||||
ReturnJson(ctx, "jsonErr_1", nil)
|
ReturnJson(ctx, "jsonErr_1", nil)
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
"status_ordered": "Ordered",
|
"status_ordered": "Ordered",
|
||||||
"status_arrived": "Arrived",
|
"status_arrived": "Arrived",
|
||||||
"status_received": "Received",
|
"status_received": "Received",
|
||||||
|
"status_lost": "Lost",
|
||||||
|
"status_returned": "Returned",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"show": "Show",
|
"show": "Show",
|
||||||
@@ -226,7 +228,8 @@
|
|||||||
"type_cof_pass": "Confirm new password",
|
"type_cof_pass": "Confirm new password",
|
||||||
"old_pass_incorrect": "Old password is incorrect",
|
"old_pass_incorrect": "Old password is incorrect",
|
||||||
"confirm_password_incorrect": "Confirm password is incorrect",
|
"confirm_password_incorrect": "Confirm password is incorrect",
|
||||||
"save_success": "Saved successfully"
|
"save_success": "Saved successfully",
|
||||||
|
"submit": "Submit"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
"status_ordered": "已下单",
|
"status_ordered": "已下单",
|
||||||
"status_arrived": "已到达",
|
"status_arrived": "已到达",
|
||||||
"status_received": "已收件",
|
"status_received": "已收件",
|
||||||
|
"status_lost": "丢件",
|
||||||
|
"status_returned": "退件",
|
||||||
"completed": "已完成",
|
"completed": "已完成",
|
||||||
"pending": "待处理",
|
"pending": "待处理",
|
||||||
"show": "显示",
|
"show": "显示",
|
||||||
@@ -226,7 +228,8 @@
|
|||||||
"type_cof_pass": "确认新密码",
|
"type_cof_pass": "确认新密码",
|
||||||
"old_pass_incorrect": "旧密码不正确",
|
"old_pass_incorrect": "旧密码不正确",
|
||||||
"confirm_password_incorrect": "确认密码不正确",
|
"confirm_password_incorrect": "确认密码不正确",
|
||||||
"save_success": "保存成功"
|
"save_success": "保存成功",
|
||||||
|
"submit": "提交"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
|
|||||||
@@ -7,34 +7,33 @@ import { usersApi } from '@/api/users';
|
|||||||
export const useUsersStore = defineStore('users', () => {
|
export const useUsersStore = defineStore('users', () => {
|
||||||
const usersInfo =ref([]);
|
const usersInfo =ref([]);
|
||||||
|
|
||||||
function getUsernameFromUserID(userID){
|
function getUserFromUserID(userID){
|
||||||
//console.log(userID)
|
return usersInfo.value?.find(item => item.UserID === userID) ?? null
|
||||||
//先在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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{
|
return{
|
||||||
usersInfo,getUsernameFromUserID,
|
usersInfo,getUsernameFromUserID,getAvatarUrlFromUserID,
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
@@ -6,6 +6,7 @@ import { useToastStore } from "@/stores/toast";
|
|||||||
import { usePageTitle } from "@/composables/usePageTitle";
|
import { usePageTitle } from "@/composables/usePageTitle";
|
||||||
import { purchaseApi } from "@/api/purchase";
|
import { purchaseApi } from "@/api/purchase";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import { useUsersStore } from "@/stores/users";
|
||||||
import {
|
import {
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
IconExternalLink,
|
IconExternalLink,
|
||||||
@@ -22,6 +23,7 @@ const { t, locale } = useI18n();
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToastStore();
|
const toast = useToastStore();
|
||||||
|
const usersStore = useUsersStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const orderId = computed(() => parseInt(route.params.id));
|
const orderId = computed(() => parseInt(route.params.id));
|
||||||
@@ -47,6 +49,8 @@ const statusOptions = [
|
|||||||
{ value: "ordered", labelKey: "status_ordered", color: "blue" },
|
{ value: "ordered", labelKey: "status_ordered", color: "blue" },
|
||||||
{ value: "arrived", labelKey: "status_arrived", color: "purple" },
|
{ value: "arrived", labelKey: "status_arrived", color: "purple" },
|
||||||
{ value: "received", labelKey: "status_received", color: "green" },
|
{ 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",
|
"bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-400",
|
||||||
received:
|
received:
|
||||||
"bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400",
|
"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);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div class="mx-auto max-w-6xl px-6 py-6">
|
<div class="mx-auto max-w-6xl px-6 py-6">
|
||||||
<!-- 返回按钮 -->
|
<!-- 返回按钮 -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
@@ -349,6 +358,18 @@ onMounted(fetchOrder);
|
|||||||
</span>
|
</span>
|
||||||
{{ getStatusLabel(order.OrderStatus) }}
|
{{ getStatusLabel(order.OrderStatus) }}
|
||||||
</span>
|
</span>
|
||||||
|
<!-- 创建者 -->
|
||||||
|
<span
|
||||||
|
v-if="order?.UserID"
|
||||||
|
class="ml-1 flex items-center gap-1.5 rounded-full border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs text-gray-500 dark:border-dk-muted dark:bg-dk-base dark:text-gray-400"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="usersStore.getAvatarUrlFromUserID(order.UserID)"
|
||||||
|
class="rounded-full object-cover"
|
||||||
|
style="width:18px;height:18px;"
|
||||||
|
/>
|
||||||
|
{{ usersStore.getUsernameFromUserID(order.UserID) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm text-gray-400">{{
|
<span class="text-sm text-gray-400">{{
|
||||||
formatDate(order?.CreatedAt)
|
formatDate(order?.CreatedAt)
|
||||||
@@ -363,7 +384,24 @@ onMounted(fetchOrder);
|
|||||||
>{{ t("purchase.change_status") }}:</span
|
>{{ t("purchase.change_status") }}:</span
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-for="opt in statusOptions"
|
v-for="opt in statusOptions.slice(0, 4)"
|
||||||
|
:key="opt.value"
|
||||||
|
class="inline-flex items-center gap-1 rounded-full border px-3 py-1 text-xs font-medium transition-all"
|
||||||
|
:class="
|
||||||
|
order?.OrderStatus === opt.value
|
||||||
|
? [getStatusColorClass(opt.value), 'border-transparent']
|
||||||
|
: 'border-gray-200 text-gray-500 hover:border-gray-300 hover:bg-gray-50 dark:border-dk-muted dark:text-gray-400 dark:hover:bg-dk-base'
|
||||||
|
"
|
||||||
|
:disabled="updatingStatus"
|
||||||
|
@click="openStatusDialog(opt.value)"
|
||||||
|
>
|
||||||
|
<IconCheck v-if="order?.OrderStatus === opt.value" :size="12" />
|
||||||
|
{{ t("purchase." + opt.labelKey) }}
|
||||||
|
</button>
|
||||||
|
<!-- 异常状态右对齐 -->
|
||||||
|
<span class="flex-1" />
|
||||||
|
<button
|
||||||
|
v-for="opt in statusOptions.slice(4)"
|
||||||
:key="opt.value"
|
:key="opt.value"
|
||||||
class="inline-flex items-center gap-1 rounded-full border px-3 py-1 text-xs font-medium transition-all"
|
class="inline-flex items-center gap-1 rounded-full border px-3 py-1 text-xs font-medium transition-all"
|
||||||
:class="
|
:class="
|
||||||
@@ -574,22 +612,33 @@ onMounted(fetchOrder);
|
|||||||
<div
|
<div
|
||||||
v-for="commit in commits"
|
v-for="commit in commits"
|
||||||
:key="commit.id"
|
:key="commit.id"
|
||||||
class="flex items-start gap-4 py-3"
|
class="flex items-start gap-3 py-3"
|
||||||
>
|
>
|
||||||
<!-- 时间线点 -->
|
<!-- 左侧:头像 + 用户名 -->
|
||||||
<div class="mt-1 flex-shrink-0">
|
<div class="flex w-20 flex-shrink-0 flex-col items-center gap-1">
|
||||||
|
<img
|
||||||
|
:src="usersStore.getAvatarUrlFromUserID(commit.userId)"
|
||||||
|
class="rounded-full border border-gray-200 object-cover dark:border-dk-muted"
|
||||||
|
style="width:32px;height:32px;"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="w-full truncate text-center"
|
||||||
|
style="font-size:11px;color:var(--text-secondary,#6b7280);"
|
||||||
|
:title="usersStore.getUsernameFromUserID(commit.userId)"
|
||||||
|
>
|
||||||
|
{{ usersStore.getUsernameFromUserID(commit.userId) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 中间:时间线点 -->
|
||||||
|
<div class="flex flex-shrink-0 flex-col items-center pt-1">
|
||||||
<div
|
<div
|
||||||
class="h-2.5 w-2.5 rounded-full"
|
class="h-3 w-3 rounded-full border-2 border-white dark:border-dk-base"
|
||||||
:class="{
|
:class="getStatusColorClass(commit.status)"
|
||||||
'bg-yellow-400': commit.status === 'pending',
|
|
||||||
'bg-blue-400': commit.status === 'ordered',
|
|
||||||
'bg-purple-400': commit.status === 'arrived',
|
|
||||||
'bg-green-400': commit.status === 'received',
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 内容 -->
|
<!-- 右侧:状态 + 备注 + 图片 -->
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex-1 min-w-0">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span
|
<span
|
||||||
@@ -611,7 +660,7 @@ onMounted(fetchOrder);
|
|||||||
: ""
|
: ""
|
||||||
}}{{ getStatusLabel(commit.status) }}
|
}}{{ getStatusLabel(commit.status) }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs text-gray-400">{{
|
<span class="ml-auto text-xs text-gray-400">{{
|
||||||
formatDate(commit.createdAt)
|
formatDate(commit.createdAt)
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -621,7 +670,6 @@ onMounted(fetchOrder);
|
|||||||
>
|
>
|
||||||
{{ commit.comment }}
|
{{ commit.comment }}
|
||||||
</p>
|
</p>
|
||||||
<!-- 变更图片 -->
|
|
||||||
<div
|
<div
|
||||||
v-if="commit.photos?.length"
|
v-if="commit.photos?.length"
|
||||||
class="mt-2 flex flex-wrap gap-1.5"
|
class="mt-2 flex flex-wrap gap-1.5"
|
||||||
@@ -632,7 +680,7 @@ onMounted(fetchOrder);
|
|||||||
:href="`/api/files/get/${hash}`"
|
:href="`/api/files/get/${hash}`"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="block overflow-hidden rounded border border-gray-200 dark:border-dk-muted transition-transform hover:scale-105"
|
class="block overflow-hidden rounded border border-gray-200 dark:border-dk-muted transition-transform hover:scale-105"
|
||||||
style="width: 48px; height: 48px"
|
style="width:48px;height:48px;"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/files/get/${hash}`"
|
:src="`/api/files/get/${hash}`"
|
||||||
@@ -810,7 +858,7 @@ onMounted(fetchOrder);
|
|||||||
:size="14"
|
:size="14"
|
||||||
class="animate-spin"
|
class="animate-spin"
|
||||||
/>
|
/>
|
||||||
{{ t("message.save_ok") }}
|
{{ t("message.submit") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ const costEntries = reactive([]);
|
|||||||
* 用户填写完表单后点击"添加"按钮加入 costEntries
|
* 用户填写完表单后点击"添加"按钮加入 costEntries
|
||||||
*/
|
*/
|
||||||
const newCost = reactive({
|
const newCost = reactive({
|
||||||
type: "1", // 费用类型:默认"单价"
|
type: 1, // 费用类型:默认"单价"
|
||||||
int: 1, // 数量:默认1
|
int: 1, // 数量:默认1
|
||||||
cost: 0, // 单价:默认0
|
cost: 0, // 单价:默认0
|
||||||
currencyType: "1", // 货币类型:默认人民币
|
currencyType: 1, // 货币类型:默认人民币
|
||||||
});
|
});
|
||||||
|
|
||||||
// 费用验证错误状态:点击添加按钮后发现费用为0时触发
|
// 费用验证错误状态:点击添加按钮后发现费用为0时触发
|
||||||
@@ -166,10 +166,10 @@ function addCostEntry() {
|
|||||||
currencytype: newCost.currencyType,
|
currencytype: newCost.currencyType,
|
||||||
});
|
});
|
||||||
// 添加后重置表单,以便继续添加下一条
|
// 添加后重置表单,以便继续添加下一条
|
||||||
newCost.type = "1";
|
newCost.type = 1;
|
||||||
newCost.int = 1;
|
newCost.int = 1;
|
||||||
newCost.cost = 0;
|
newCost.cost = 0;
|
||||||
newCost.currencyType = "1";
|
newCost.currencyType = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user