feat: 用户列表代理商查询、商品续费、VNC节点access_mode、IDC信息展示、新购订单table修复
Build and Deploy Vue3 / build (push) Successful in 1m32s
Build and Deploy Vue3 / deploy (push) Successful in 42s

- 用户列表新增通过IDC代理商uid查询用户信息

- 用户商品详情新增续费功能(admin/good/user_goods/renew)

- VNC节点管理新增access_mode和use_ssl参数

- 用户详情左栏新增IDC平台信息展示

- 新购订单选择商品后所属表不再被覆盖,固定为good

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shiran
2026-07-07 18:00:20 +08:00
co-authored by Cursor
parent 0155715278
commit 2e3574a182
7 changed files with 166 additions and 9 deletions
+68 -1
View File
@@ -13,6 +13,9 @@
<el-button plain @click="loadDetail" :loading="loading">
<el-icon><Refresh /></el-icon> 刷新
</el-button>
<el-button type="success" plain @click="openRenew" :disabled="!detail || isDeleted">
续费
</el-button>
<el-button type="primary" plain @click="openEdit" :disabled="!detail">
<el-icon><Edit /></el-icon> 编辑
</el-button>
@@ -233,6 +236,35 @@
</template>
</div>
<!-- 续费弹窗 -->
<el-dialog v-model="renewVisible" title="用户商品续费" width="480px" destroy-on-close>
<el-form :model="renewForm" label-width="110px">
<el-form-item label="续费月数">
<el-input-number v-model="renewForm.purchase_duration" :min="1" :max="120" controls-position="right" style="width: 100%" />
</el-form-item>
<el-form-item label="续费单价">
<div class="unit-input-row">
<el-input-number v-model="renewForm.renew_price" :min="0" :precision="2" controls-position="right" style="flex:1" />
<span class="unit-text"></span>
</div>
<div style="font-size: 12px; color: #909399; margin-top: 4px">不填则使用商品默认续费价格</div>
</el-form-item>
<el-form-item label="总计费用">
<span style="font-size: 16px; font-weight: 600; color: #409eff">¥{{ renewTotalPrice }}</span>
</el-form-item>
<el-form-item label="直接完成支付">
<el-switch v-model="renewForm.complete_pay" />
</el-form-item>
<el-form-item v-if="renewForm.complete_pay" label="扣除用户余额">
<el-switch v-model="renewForm.deduct_balance" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="renewVisible = false">取消</el-button>
<el-button type="primary" :loading="renewLoading" @click="handleRenew">确认续费</el-button>
</template>
</el-dialog>
<!-- 编辑弹窗 -->
<el-dialog v-model="editVisible" title="编辑用户商品" width="520px" destroy-on-close>
<el-form :model="editForm" label-width="110px">
@@ -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)