diff --git a/src/api/admin/user.js b/src/api/admin/user.js index 62fcb46..0fd469a 100644 --- a/src/api/admin/user.js +++ b/src/api/admin/user.js @@ -105,6 +105,12 @@ export const getUserOperationRecord = (data) => { export const mockUserLogin = (data) => { return http2.get('/api/v1/admin/user/user/simulation_login?user_id='+data.user_id) } + +/**通过IDC代理商uid获取用户信息 */ +export const getUserByIdcAgentUid = (params) => { + return http2.get('/api/v1/admin/user/idc_agent/user', { params }) +} + /**新建任务 */ export const createTask = (data) => { return http2.post('/api/v1/admin/user/user/create', data,{ diff --git a/src/api/admin/userVm.js b/src/api/admin/userVm.js index 908ab33..5527691 100644 --- a/src/api/admin/userVm.js +++ b/src/api/admin/userVm.js @@ -109,6 +109,7 @@ export const getUserGoodsDetail = (params) => http2.get(`${GOODS_BASE}/detail`, 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' } }) export const deleteUserGoods = (params) => http2.delete(`${GOODS_BASE}/delete`, { params }) +export const renewUserGoods = (data) => http2.post(`${GOODS_BASE}/renew`, fd(data), { headers: { 'Content-Type': 'multipart/form-data' } }) export const getUserVmMetricsHistory = (params) => http2.get(`${BASE}/metrics_history`, { params }) export const getUserVmTrafficHourly = (params) => http2.get(`${BASE}/traffic_hourly`, { params }) diff --git a/src/views/order/OrderList.vue b/src/views/order/OrderList.vue index d552766..54ff4b8 100644 --- a/src/views/order/OrderList.vue +++ b/src/views/order/OrderList.vue @@ -1285,7 +1285,7 @@ const clearUser = () => { const handleProductSelect = (product) => { orderForm.commodity_id = product.id selectedProductInfo.value = product - if (product.table) orderForm.table = product.table + if (orderForm.type !== 'create' && product.table) orderForm.table = product.table orderForm.plan_id = null planFixedArgs.value = [] // 自动生成订单名称:商品名-时间戳 diff --git a/src/views/product/UserGoodsDetail.vue b/src/views/product/UserGoodsDetail.vue index b4e5b61..e396ce8 100644 --- a/src/views/product/UserGoodsDetail.vue +++ b/src/views/product/UserGoodsDetail.vue @@ -13,6 +13,9 @@ 刷新 + + 续费 + 编辑 @@ -233,6 +236,35 @@ + + + + + + + +
+ + +
+
不填则使用商品默认续费价格
+
+ + ¥{{ renewTotalPrice }} + + + + + + + +
+ +
+ @@ -289,7 +321,7 @@ import { ref, reactive, computed, onMounted, onActivated, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' import { ArrowLeft, ArrowDown, Refresh, Edit, Delete } from '@element-plus/icons-vue' -import { getUserGoodsDetail, updateUserGoods, deleteUserGoods } from '@/api/admin/userVm' +import { getUserGoodsDetail, updateUserGoods, deleteUserGoods, renewUserGoods } from '@/api/admin/userVm' import { extractApiError } from '@/utils/kvmErrorUtil' import VmSelectorPopup from '@/components/admin/VmSelectorPopup.vue' import KvmServiceSelector from '@/components/admin/KvmServiceSelector.vue' @@ -417,6 +449,41 @@ const goToOrder = () => { router.push({ path: '/order/list', query: { order_id: oid } }) } +// ---- 续费 ---- +const renewVisible = ref(false) +const renewLoading = ref(false) +const renewForm = reactive({ purchase_duration: 1, renew_price: 0, complete_pay: false, deduct_balance: false }) +const renewTotalPrice = computed(() => { + const price = renewForm.renew_price || (detail.value?.renewPrice || detail.value?.renew_price || 0) / 100 + return (price * renewForm.purchase_duration).toFixed(2) +}) +const openRenew = () => { + const rawRenew = detail.value?.renewPrice || detail.value?.renew_price || 0 + Object.assign(renewForm, { purchase_duration: 1, renew_price: rawRenew / 100, complete_pay: false, deduct_balance: false }) + renewVisible.value = true +} +const handleRenew = async () => { + renewLoading.value = true + try { + const data = { id: goodsId.value, purchase_duration: renewForm.purchase_duration } + if (renewForm.renew_price) data.renew_price = Math.round(renewForm.renew_price * 100) + if (renewForm.complete_pay) data.complete_pay = true + if (renewForm.complete_pay && renewForm.deduct_balance) data.deduct_balance = true + const res = await renewUserGoods(data) + if (res?.data?.code === 200) { + ElMessage.success('续费成功') + renewVisible.value = false + loadDetail() + } else { + ElMessage.error(extractApiError(res?.data, '续费失败')) + } + } catch (e) { + ElMessage.error(extractApiError(e?.response?.data, '续费失败')) + } finally { + renewLoading.value = false + } +} + const editVisible = ref(false) const editForm = reactive({ note: '', renew_price: 0, base_price: 0, expire_time: '', item_id: 0, _serviceId: 0, _serviceName: '', _itemName: '' }) const showVmSelector = ref(false) diff --git a/src/views/user/UserDetail.vue b/src/views/user/UserDetail.vue index efdd312..73fc0e0 100644 --- a/src/views/user/UserDetail.vue +++ b/src/views/user/UserDetail.vue @@ -116,6 +116,20 @@ {{ getRealNameTypeText(userInfo.RealName?.Type) }} + + + + + {{ userInfo.idc_agent.Uid || '-' }} + {{ userInfo.idc_agent.AgentLevelName || '-' }} + {{ userInfo.idc_agent.AgentLevent ?? '-' }} + {{ formatDate(userInfo.idc_agent.CreatedAt) }} + + diff --git a/src/views/user/UserList.vue b/src/views/user/UserList.vue index 0ce702f..5d9a616 100644 --- a/src/views/user/UserList.vue +++ b/src/views/user/UserList.vue @@ -32,10 +32,23 @@ @keyup.enter="handleJumpToUser" /> +
+ 代理商ID + +
跳转 + + 代理商查询 + 查询 @@ -653,7 +666,8 @@ import { updateUserGroup, updateUserRealName, getUserLoginRecord, - getUserOperationRecord + getUserOperationRecord, + getUserByIdcAgentUid } from '@/api/admin/user' import { getFileDetail } from '@/api/admin/file' import { closeAllMessage } from '../../utils/message' @@ -663,6 +677,10 @@ const router = useRouter() // 跳转用户ID const jumpUserId = ref('') +// 代理商ID查询 +const agentUid = ref('') +const agentSearchLoading = ref(false) + // 查询参数 const queryParams = reactive({ key: '', @@ -887,6 +905,33 @@ const handleJumpToUser = () => { }) } +// 通过代理商ID查询用户 +const handleSearchByAgentUid = async () => { + if (!agentUid.value || !agentUid.value.trim()) { + ElMessage.warning('请输入代理商ID') + return + } + agentSearchLoading.value = true + try { + const res = await getUserByIdcAgentUid({ uid: agentUid.value.trim() }) + if (res?.data?.code === 200 && res?.data?.data) { + const userId = res.data.data.UserId + if (userId) { + router.push({ path: '/user/detail', query: { user_id: userId } }) + } else { + ElMessage.warning('未找到绑定该代理商ID的用户') + } + } else { + ElMessage.warning(res?.data?.message || '未找到绑定该代理商ID的用户') + } + } catch (e) { + const msg = e?.response?.data?.message || '查询失败' + ElMessage.error(msg) + } finally { + agentSearchLoading.value = false + } +} + // 选择项变化 const handleSelectionChange = (selection) => { selectedRows.value = selection diff --git a/src/views/virtualization/VncNodeManage.vue b/src/views/virtualization/VncNodeManage.vue index ba53153..70310b3 100644 --- a/src/views/virtualization/VncNodeManage.vue +++ b/src/views/virtualization/VncNodeManage.vue @@ -39,6 +39,18 @@ {{ row.ip || '-' }}:{{ row.port || '-' }} + + + + + +