diff --git a/src/api/admin/kvmService.js b/src/api/admin/kvmService.js
index 8637786..a5d545f 100644
--- a/src/api/admin/kvmService.js
+++ b/src/api/admin/kvmService.js
@@ -816,3 +816,36 @@ export const removeUserNetworkingNetwork = (data) => {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
+
+/**
+ * ================================
+ * 回收站管理 API
+ * ================================
+ */
+
+/** 获取回收站列表 */
+export const getRecycleBinList = (params) => {
+ return http2.get('/api/v1/admin/server/host_service/point/recycle_bin/list', { params })
+}
+
+/** 获取回收站记录详情 */
+export const getRecycleBinDetail = (params) => {
+ return http2.get('/api/v1/admin/server/host_service/point/recycle_bin/detail', { params })
+}
+
+/** 从回收站恢复虚拟机 */
+export const restoreRecycleBin = (data) => {
+ return http2.post('/api/v1/admin/server/host_service/point/recycle_bin/restore', data, {
+ headers: { 'Content-Type': 'multipart/form-data' }
+ })
+}
+
+/** 永久删除回收站记录 */
+export const deleteRecycleBin = (params) => {
+ return http2.delete('/api/v1/admin/server/host_service/point/recycle_bin/delete', { params })
+}
+
+/** 清空回收站(all=true 全部清空,all=false 仅清理到期) */
+export const cleanRecycleBin = (params) => {
+ return http2.delete('/api/v1/admin/server/host_service/point/recycle_bin/clean', { params })
+}
diff --git a/src/api/admin/product.js b/src/api/admin/product.js
index 08676cc..082c7e9 100644
--- a/src/api/admin/product.js
+++ b/src/api/admin/product.js
@@ -57,6 +57,10 @@ export const deleteProductGroup = (data) => {
export const getProductList = (params) => {
return http2.get('/api/v1/admin/good/goods/list', {params: params})
}
+/**获取商品详情(含商品参数列表) */
+export const getProductDetail = (params) => {
+ return http2.get('/api/v1/admin/good/goods/detail', {params: params})
+}
/**获取商品标签列表 */
export const getProductTagList = () => {
return http2.get('/api/v1/admin/good/goods/tag_list')
diff --git a/src/api/admin/userVm.js b/src/api/admin/userVm.js
index 7804144..908ab33 100644
--- a/src/api/admin/userVm.js
+++ b/src/api/admin/userVm.js
@@ -103,6 +103,8 @@ export const deleteUserVmNetworking = (params) => http2.delete(`${BASE}/networki
// ========== 用户商品 ==========
export const getUserGoodsList = (params) => http2.get(`${GOODS_BASE}/list`, { params })
+// 用户商品数量统计(正常 / 已删除 / 已到期),参数与列表接口一致但不分页
+export const getUserGoodsCount = (params) => http2.get(`${GOODS_BASE}/count`, { params })
export const getUserGoodsDetail = (params) => http2.get(`${GOODS_BASE}/detail`, { params })
export const createUserGoods = (data) => http2.post(`${GOODS_BASE}/create`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } })
export const updateUserGoods = (data) => http2.post(`${GOODS_BASE}/update`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } })
diff --git a/src/components/layout/GlobalSearch.vue b/src/components/layout/GlobalSearch.vue
index 9b5d9d2..bb968b0 100644
--- a/src/components/layout/GlobalSearch.vue
+++ b/src/components/layout/GlobalSearch.vue
@@ -130,7 +130,10 @@
-
+
+
+ 已删除
+
用户: {{ item.user?.UserName || item.userId }} · 到期: {{ formatTime(item.expireTime) }}
@@ -225,7 +228,7 @@ const searchOrders = async (key) => {
results.order.loading = true
results.order.list = []
try {
- const res = await getOrderList({ page: results.order.page, count: pageSize, keyword: key })
+ const res = await getOrderList({ page: results.order.page, count: pageSize, key })
if (res.data?.code === 200) {
results.order.list = res.data.data?.list || []
results.order.total = res.data.data?.all_count || results.order.list.length
@@ -251,7 +254,7 @@ const searchGoods = async (key) => {
results.goods.loading = true
results.goods.list = []
try {
- const res = await getUserGoodsList({ page: results.goods.page, count: pageSize, keyword: key })
+ const res = await getUserGoodsList({ page: results.goods.page, count: pageSize, key })
if (res.data?.code === 200) {
results.goods.list = res.data.data?.data || []
results.goods.total = res.data.data?.all_count || results.goods.list.length
@@ -260,6 +263,9 @@ const searchGoods = async (key) => {
results.goods.loading = false
}
+// 判断用户商品是否已删除(后端返回 deleteAt 字段,有值即已删除)
+const isGoodsDeleted = (item) => !!(item?.deleteAt || item?.DeleteAt || item?.deleted_at)
+
const highlight = (text) => {
if (!text || !keyword.value) return text
const key = keyword.value.trim()
@@ -292,12 +298,7 @@ const goToTicket = (item) => {
const goToGoods = (item) => {
visible.value = false
- const tag = (item.tag || item.good?.tag || '').toLowerCase()
- if (tag === '云服务器') {
- router.push({ path: '/user-goods/vm-detail', query: { id: item.id } })
- } else {
- router.push({ name: 'UserGoodsDetail', params: { id: item.id } })
- }
+ router.push({ name: 'UserGoodsDetail', params: { id: item.id } })
}
const orderStatusText = (status) => {
@@ -528,6 +529,11 @@ onUnmounted(() => {
border-radius: 2px;
}
+.result-title .deleted-flag {
+ margin-left: 6px;
+ vertical-align: middle;
+}
+
.result-desc {
font-size: 12px;
color: #909399;
diff --git a/src/router/index.js b/src/router/index.js
index 432e704..a262f78 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -294,12 +294,6 @@ const routes = [
component: () => import('../views/user-vm/UserVmList.vue'),
meta: { title: '云服务器' }
},
- {
- path: 'vm-detail',
- name: 'UserVmDetail',
- component: () => import('../views/user-vm/UserVmDetail.vue'),
- meta: { title: '用户虚拟机详情', hidden: true, activeMenu: '/user-goods/vm-list' }
- }
]
},
// 订单管理路由
diff --git a/src/views/order/OrderList.vue b/src/views/order/OrderList.vue
index dd111e1..d552766 100644
--- a/src/views/order/OrderList.vue
+++ b/src/views/order/OrderList.vue
@@ -86,7 +86,7 @@
- {{ row.commodityId }}
+ {{ row.commodityId }}
-
@@ -173,38 +173,148 @@
-
- {{ orderDetail.id }}
- {{ orderDetail.name }}
-
- {{ getTypeText(orderDetail.type) }}
-
- {{ orderDetail.userId }}
- {{ orderDetail.commodityId }}
- {{ orderDetail.planId || '-' }}
- {{ orderDetail.table }}
- {{ orderDetail.payNum }}
- ¥{{ (orderDetail.price / 100).toFixed(2) }}
- ¥{{ (orderDetail.renewPrice / 100).toFixed(2) }}
-
-
- {{ getStatusText(orderDetail.state) }}
-
-
- {{ orderDetail.payType || '-' }}
- {{ formatDate(orderDetail.expireTime) }}
- {{ formatDate(orderDetail.CreatedAt) }}
- {{ formatDate(orderDetail.UpdatedAt) }}
- {{ orderDetail.args || '-' }}
-
- 异常
- {{ orderDetail.error }}
-
- {{ orderDetail.note || '无' }}
-
+
+
+
+
+
+ {{ orderDetail.name || '未命名订单' }}
+
+ {{ getStatusText(orderDetail.state) }}
+
+ {{ getTypeText(orderDetail.type) }}
+
+
+ 订单号 #{{ orderDetail.id }}
+
+ 创建于 {{ formatDate(orderDetail.createdAt || orderDetail.CreatedAt) }}
+
+
+
+ 订单金额
+ ¥{{ formatYuan(orderDetail.price) }}
+
+
+
+
+
+
订单信息
+
+ {{ orderDetail.id }}
+
+ {{ getTypeText(orderDetail.type) }}
+
+ {{ orderDetail.payNum }}
+ {{ orderDetail.table || '-' }}
+ ¥{{ formatYuan(orderDetail.price) }}
+ ¥{{ formatYuan(orderDetail.renewPrice) }}
+ {{ getPayTypeText(orderDetail.payType) }}
+
+ {{ orderDetail.paymentOrderId || '-' }}
+
+ {{ formatDate(orderDetail.expireTime) }}
+ {{ orderDetail.refundTime ? formatDate(orderDetail.refundTime) : '-' }}
+ {{ formatDate(orderDetail.createdAt || orderDetail.CreatedAt) }}
+ {{ formatDate(orderDetail.updatedAt || orderDetail.UpdatedAt) }}
+
+ {{ orderDetail.args || '-' }}
+
+ {{ orderDetail.note || '无' }}
+
+ 异常
+ {{ orderDetail.error }}
+
+
+
+
+
+
+
+
+
+ {{ orderDetail.userId || '-' }}
+
+ {{ orderDetail.user?.userName || '-' }}
+ {{ orderDetail.user?.email || '-' }}
+ {{ orderDetail.user?.phone || '-' }}
+
+
+
+
+
+
+
商品信息
+
{{ orderDetail.table === 'good' ? '查看商品' : '查看用户商品' }}
+
+
+
+ {{ orderDetail.commodityId || '-' }}
+
+ {{ orderDetail.good?.name || '-' }}
+
+ {{ orderDetail.good.tag }}
+ -
+
+ {{ orderDetail.good?.groupName || '-' }}
+
+
+
+
+
+
套餐信息
+
+ {{ orderDetail.plan?.id || orderDetail.planId || '-' }}
+ {{ orderDetail.plan?.name || '-' }}
+ {{ orderDetail.plan?.note || '-' }}
+
+
+
+
+
+
+
+
+ {{ orderDetail.userGoods.id || '-' }}
+
+ {{ orderDetail.userGoods.itemId || '-' }}
+ {{ formatDate(orderDetail.userGoods.expireTime) }}
+ ¥{{ formatYuan(orderDetail.userGoods.renewPrice) }}
+
+ {{ orderDetail.userGoods.tag }}
+ -
+
+ {{ orderDetail.userGoods.note || '-' }}
+
+
+
@@ -217,7 +327,7 @@
>
-
+
@@ -256,9 +366,6 @@
-
-
-
@@ -284,18 +391,43 @@
-
+
该商品暂无套餐,可直接进入下一步手动设置价格
+
+
+
-
+
+
+
+ 套餐固定参数
+
+
+
+ {{ arg.number !== undefined && arg.number !== null ? arg.number : (arg.value || '-') }}
+
+
+
+
+
- 商品参数配置
+ {{ orderForm.plan_id ? '额外配置参数' : '商品参数配置' }}
@@ -1200,6 +1473,26 @@ onMounted(() => {
border: 1px solid #ebeef5;
}
+.plan-fixed-args {
+ background: #f0f5ff;
+ border-color: #d6e4ff;
+}
+
+.plan-fixed-args .args-section-title {
+ color: #1d39c4;
+}
+
+.plan-fixed-args :deep(.el-descriptions__label) {
+ background: #e8edfb;
+ color: #1d39c4;
+ font-weight: 500;
+}
+
+.plan-fixed-args :deep(.el-descriptions__content) {
+ font-weight: 600;
+ color: #303133;
+}
+
.args-section-title {
display: flex;
align-items: center;
@@ -1319,4 +1612,99 @@ onMounted(() => {
.text-muted {
color: #c0c4cc;
}
+
+/* ===== 订单详情弹窗 ===== */
+.order-detail {
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+}
+
+/* 顶部概览 */
+.od-hero {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 18px 22px;
+ border-radius: 10px;
+ background: #f5f7fa;
+ border: 1px solid #e8eaed;
+ color: #303133;
+}
+.od-hero-main {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ min-width: 0;
+}
+.od-hero-title {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+.od-order-name {
+ font-size: 17px;
+ font-weight: 600;
+ color: #1a1a2e;
+}
+.od-hero-sub {
+ display: flex;
+ align-items: center;
+ font-size: 12px;
+ color: #909399;
+}
+.od-hero-sub :deep(.el-divider--vertical) {
+ background-color: #dcdfe6;
+}
+.od-hero-amount {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ flex-shrink: 0;
+}
+.od-amount-label {
+ font-size: 12px;
+ color: #909399;
+}
+.od-amount-value {
+ font-size: 26px;
+ font-weight: 700;
+ color: #1a1a2e;
+ line-height: 1.2;
+}
+
+/* 分区 */
+.od-section {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+.od-section-title {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 14px;
+ font-weight: 600;
+ color: #303133;
+}
+.od-section-title .el-icon {
+ color: #2563eb;
+}
+.od-section-link {
+ margin-left: auto;
+ font-size: 13px;
+ font-weight: 400;
+}
+.od-section-link .el-icon {
+ color: inherit;
+ margin-left: 2px;
+}
+.od-mono {
+ font-family: Consolas, Monaco, monospace;
+ font-size: 12px;
+}
+.od-args {
+ word-break: break-all;
+}
diff --git a/src/views/product/ProductGroup.vue b/src/views/product/ProductGroup.vue
index 631ce07..6ef24cd 100644
--- a/src/views/product/ProductGroup.vue
+++ b/src/views/product/ProductGroup.vue
@@ -711,6 +711,16 @@
/>
限制单用户最大购买数量,0 表示不限制
+
+
+ 限制用户首次购买的最大时长(单位:月),0 表示不限制
+
@@ -819,7 +829,8 @@
diff --git a/src/views/product/UserGoodsDetail.vue b/src/views/product/UserGoodsDetail.vue
index 6648f84..b4e5b61 100644
--- a/src/views/product/UserGoodsDetail.vue
+++ b/src/views/product/UserGoodsDetail.vue
@@ -3,94 +3,237 @@
-
-
重新加载
-
-