From cddc1e6ea28985fb5606fb6c9c7071c343e25950 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 13 Aug 2026 12:52:21 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E7=AE=A1=E7=90=86=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=AE=A2=E5=8D=95=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E4=B8=80=E9=94=AE=E9=94=81=E5=AE=9A?= =?UTF-8?q?=E6=89=80=E6=9C=89=E5=B7=B2=E5=AE=8C=E6=88=90=E8=AE=A2=E5=8D=95?= =?UTF-8?q?(=E5=B7=B2=E6=94=B6=E4=BB=B6/=E4=B8=A2=E4=BB=B6/=E9=80=80?= =?UTF-8?q?=E4=BB=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/my_work/routers/apiPurchase.go | 33 ++ frontend/ops_vue_js/src/api/purchase.js | 5 + frontend/ops_vue_js/src/i18n/en.json | 5 + frontend/ops_vue_js/src/i18n/zh-CN.json | 5 + .../src/views/sysadmin/PurchaseOrdersTab.vue | 313 ++++++++++++++++++ .../src/views/sysadmin/SysAdminView.vue | 4 + 6 files changed, 365 insertions(+) create mode 100644 frontend/ops_vue_js/src/views/sysadmin/PurchaseOrdersTab.vue diff --git a/backend/my_work/routers/apiPurchase.go b/backend/my_work/routers/apiPurchase.go index 1671d09..db22c07 100644 --- a/backend/my_work/routers/apiPurchase.go +++ b/backend/my_work/routers/apiPurchase.go @@ -812,6 +812,39 @@ func ApiPurchase(r *gin.RouterGroup) { ReturnJson(ctx, "apiOK", nil) }) + // 一键锁定所有已完成订单(已收件/丢件/退件) + r.POST("/lock_all_completed", func(ctx *gin.Context) { + isAuth, user, _ := AuthenticationAuthority(ctx) + if !isAuth { + ReturnJson(ctx, "userCookieError", nil) + return + } + + if !canUnlockPurchase(user.ID) { + ReturnJson(ctx, "no_permission", nil) + return + } + + result := models.DB.Model(&TabPurchaseOrder{}). + Where("order_status IN ? AND locked = ? AND deleted_at IS NULL", + []string{"received", "lost", "returned"}, false). + Update("locked", true) + + lockedCount := result.RowsAffected + + tosqllog := TabPurchaseLog{ + UserID: user.ID, + ActionType: "lock_all", + IP: ctx.ClientIP(), + Remark: parsefmt.Sprintf("一键锁定所有已完成订单,共 %d 个", lockedCount), + } + models.DB.Create(&tosqllog) + + ReturnJson(ctx, "apiOK", gin.H{ + "locked_count": lockedCount, + }) + }) + r.POST("/getorders", func(ctx *gin.Context) { isAuth, _, data := AuthenticationAuthority(ctx) if isAuth { diff --git a/frontend/ops_vue_js/src/api/purchase.js b/frontend/ops_vue_js/src/api/purchase.js index f4462a0..89d36d1 100644 --- a/frontend/ops_vue_js/src/api/purchase.js +++ b/frontend/ops_vue_js/src/api/purchase.js @@ -51,6 +51,11 @@ export const purchaseApi = { return api.post('/purchase/unlock', { id }) }, + /** 一键锁定所有已完成订单(管理员) */ + lockAllCompleted() { + return api.post('/purchase/lock_all_completed', {}) + }, + /** 搜索工单(用于采购订单关联) */ searchWorkOrders(search = '', limit = 5) { return api.post('/purchase/search_work_orders', { search, limit }) diff --git a/frontend/ops_vue_js/src/i18n/en.json b/frontend/ops_vue_js/src/i18n/en.json index 9025202..12bc63f 100644 --- a/frontend/ops_vue_js/src/i18n/en.json +++ b/frontend/ops_vue_js/src/i18n/en.json @@ -607,6 +607,11 @@ "tab_users": "User Management", "tab_groups": "User Groups", "tab_logs": "Login Logs", + "tab_purchase_orders": "Purchase Orders", + "lock_all_completed": "Lock All Completed Orders", + "lock_all_confirm": "Lock all unlocked orders with received/lost/returned status?", + "lock_all_success": "Locked {count} orders", + "lock_all_none": "No completed orders to lock", "total_users": "Total {count} users", "search_placeholder": "Search username or email...", "search": "Search", diff --git a/frontend/ops_vue_js/src/i18n/zh-CN.json b/frontend/ops_vue_js/src/i18n/zh-CN.json index 3713e57..b740b5e 100644 --- a/frontend/ops_vue_js/src/i18n/zh-CN.json +++ b/frontend/ops_vue_js/src/i18n/zh-CN.json @@ -607,6 +607,11 @@ "tab_users": "用户管理", "tab_groups": "用户组", "tab_logs": "登录日志", + "tab_purchase_orders": "订单管理", + "lock_all_completed": "一键锁定已完成订单", + "lock_all_confirm": "确定要锁定所有已收件/丢件/退件状态的未锁定订单吗?", + "lock_all_success": "已锁定 {count} 个订单", + "lock_all_none": "没有需要锁定的已完成订单", "total_users": "共 {count} 位用户", "search_placeholder": "搜索用户名或邮箱...", "search": "搜索", diff --git a/frontend/ops_vue_js/src/views/sysadmin/PurchaseOrdersTab.vue b/frontend/ops_vue_js/src/views/sysadmin/PurchaseOrdersTab.vue new file mode 100644 index 0000000..b913d8a --- /dev/null +++ b/frontend/ops_vue_js/src/views/sysadmin/PurchaseOrdersTab.vue @@ -0,0 +1,313 @@ + + + diff --git a/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue b/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue index 45beb11..42cc2c1 100644 --- a/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue +++ b/frontend/ops_vue_js/src/views/sysadmin/SysAdminView.vue @@ -9,6 +9,7 @@ import UsersTab from '@/views/sysadmin/UsersTab.vue' import GroupsTab from '@/views/sysadmin/GroupsTab.vue' import LogsTab from '@/views/sysadmin/LogsTab.vue' import OperationLogsTab from '@/views/sysadmin/OperationLogsTab.vue' +import PurchaseOrdersTab from '@/views/sysadmin/PurchaseOrdersTab.vue' const { t } = useI18n() const userStore = useUserStore() @@ -24,12 +25,14 @@ const usersTabRef = ref(null) const groupsTabRef = ref(null) const logsTabRef = ref(null) const operationLogsTabRef = ref(null) +const purchaseOrdersTabRef = ref(null) const tabs = [ { id: 'users', label: t('sysadmin.tab_users') }, { id: 'groups', label: t('sysadmin.tab_groups') }, { id: 'logs', label: t('sysadmin.tab_logs') }, { id: 'operation_logs', label: t('sysadmin.tab_operation_logs') }, + { id: 'purchase_orders', label: t('sysadmin.tab_purchase_orders') }, { id: 'customer', label: t('customer.title'), to: '/customer' }, { id: 'calendar', label: t('calendar.admin_title'), to: '/calendars/admin' }, { id: 'aiconfig', label: t('aiconfig.title'), to: '/admin/aiconfig' }, @@ -99,6 +102,7 @@ onMounted(() => { +