Order订单类型增加新建服务器和服务器续费,前端服务器列表点击新建服务器时弹出服务器配置选项

This commit is contained in:
jingrow 2025-07-27 17:35:00 +08:00
parent 48d03160cb
commit 94118baf15
5 changed files with 294 additions and 36 deletions

View File

@ -136,8 +136,13 @@
</svg>
</div>
</div>
<h3 class="text-xl font-medium text-gray-900 mb-2">服务器创建成功</h3>
<p class="text-gray-600 mb-2">您的 Jsite 服务器已成功开通</p>
<h3 class="text-xl font-medium text-gray-900 mb-2">支付成功</h3>
<p class="text-gray-600 mb-4">
您的订单已支付成功服务器正在创建中创建并启动需要 3-5 分钟请耐心等待
</p>
<p class="text-gray-500 text-sm">
创建完成后您将收到通知也可以在服务器列表中查看状态
</p>
</div>
<!-- 微信支付状态 -->
@ -437,9 +442,6 @@ export default {
this.isProcessingPayment = false;
this.paymentSuccess = true;
console.log('余额支付成功,更新状态:', {
paymentSuccess: this.paymentSuccess
});
},
onError(error) {
this.error = error.message || '余额支付处理失败';
@ -462,6 +464,7 @@ export default {
toast.success('支付页面已在新窗口打开');
//
this.startPaymentCheck();
},
onError(error) {
@ -483,6 +486,7 @@ export default {
this.paymentQrCode = response.payment_url;
this.paymentQrCodeImage = response.qr_code_image || null;
//
this.startPaymentCheck();
},
onError(error) {
@ -495,13 +499,17 @@ export default {
checkPaymentStatus() {
return {
url: 'jcloud.api.billing.check_server_order_payment_status',
params: {
order_id: this.order?.order_id
},
validate() {
if (!this.order || !this.order.order_id) {
throw new DashboardError('缺少订单信息');
}
},
onSuccess(data) {
if (data && data.status === '交易成功') {
if (data && data.status === '已支付') {
//
this.stopPaymentCheck();
const orderData = { ...this.order, ...(data.order || {}) };
@ -511,7 +519,11 @@ export default {
}
}
};
}
},
},
beforeUnmount() {
this.stopPaymentCheck();
},
mounted() {
console.log('组件mounted开始获取地域列表');
@ -558,6 +570,24 @@ export default {
this.isLoading = false;
},
startPaymentCheck() {
this.isProcessingPayment = false;
this.checkInterval = setInterval(() => {
this.$resources.checkPaymentStatus.submit();
}, 3000);
// 15
setTimeout(() => {
this.stopPaymentCheck();
}, 900000);
},
stopPaymentCheck() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
},
processPayment() {
this.isProcessingPayment = true;
this.error = null;
@ -588,26 +618,9 @@ export default {
});
}
},
startPaymentCheck() {
this.isProcessingPayment = false;
this.checkInterval = setInterval(() => {
this.$resources.checkPaymentStatus.submit();
}, 3000);
// 15
setTimeout(() => {
this.stopPaymentCheck();
}, 900000);
},
stopPaymentCheck() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
},
close() {
this.stopPaymentCheck();
this.show = false;
this.$emit('success');
},
@ -656,9 +669,7 @@ export default {
return name;
}
},
beforeUnmount() {
this.stopPaymentCheck();
}
};
</script>

View File

@ -373,4 +373,129 @@ def get_aliyun_images(image_type='system', region_id='cn-shanghai'):
def get_aliyun_regions():
"""通过阿里云SDK实时获取可用地域列表"""
manager = _get_manager()
return manager.get_regions()
return manager.get_regions()
# 服务器订单和创建相关
@jingrow.whitelist()
def create_server_order(**kwargs):
"""创建服务器订单"""
try:
plan_id = kwargs.get('plan_id')
image_id = kwargs.get('image_id')
period = kwargs.get('period', 1)
region_id = kwargs.get('region_id', 'cn-shanghai')
if not plan_id or not image_id:
jingrow.throw("缺少必要参数")
from jcloud.utils import get_current_team
team = get_current_team(True)
# 获取套餐价格
plans_response = get_aliyun_plans(region_id)
selected_plan = None
if plans_response and plans_response.get('success'):
plans = plans_response['data'].get('plans', [])
selected_plan = next((p for p in plans if p.get('plan_id') == plan_id), None)
if not selected_plan:
jingrow.throw("套餐不存在")
# 计算价格
monthly_price = float(selected_plan.get('origin_price', 0))
total_amount = monthly_price * period
# 生成订单号
from datetime import datetime
import random
order_id = datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3] + ''.join(random.choices('0123456789', k=6))
# 创建订单
order = jingrow.get_pg({
"pagetype": "Order",
"order_id": order_id,
"order_type": "新建服务器",
"team": team.name,
"status": "待支付",
"total_amount": total_amount,
"title": f"新建服务器 - {region_id}",
"description": f"{selected_plan.get('core')}核/{selected_plan.get('memory')}GB/{selected_plan.get('disk_size')}GB, {period}个月",
"server_config": {
"plan_id": plan_id,
"image_id": image_id,
"period": period,
"region_id": region_id,
"monthly_price": monthly_price
}
})
order.insert(ignore_permissions=True)
jingrow.db.commit()
return {"success": True, "order": order.as_dict()}
except Exception as e:
jingrow.log_error("创建服务器订单失败", str(e))
return {"success": False, "message": str(e)}
def create_server_async(order_name):
"""异步创建服务器"""
try:
order = jingrow.get_pg("Order", order_name)
if not order:
raise Exception("订单不存在")
# 获取配置
config = order.server_config or {}
plan_id = config.get('plan_id')
image_id = config.get('image_id')
period = config.get('period', 1)
region_id = config.get('region_id', 'cn-shanghai')
# 调用阿里云API创建实例
result = create_aliyun_instance(plan_id, image_id, period, region_id)
if not result or not result.get('success'):
raise Exception(f"阿里云创建失败: {result.get('message', '未知错误')}")
instance_id = result['data']['instance_id']
# 创建服务器记录
server = jingrow.get_pg({
"pagetype": "Jsite Server",
"instance_id": instance_id,
"team": order.team,
"order": order.name,
"status": "Running",
"region_id": region_id,
"plan_id": plan_id,
"image_id": image_id,
"period": period,
"monthly_price": config.get('monthly_price', 0),
"total_amount": order.total_amount,
"payment_method": order.payment_method,
"created_at": jingrow.utils.now(),
"expires_at": jingrow.utils.add_months(jingrow.utils.nowdate(), period)
})
server.insert(ignore_permissions=True)
# 更新订单状态
order.status = "交易成功"
order.instance_id = instance_id
order.server_record = server.name
order.save(ignore_permissions=True)
jingrow.db.commit()
return True
except Exception as e:
jingrow.log_error("服务器创建失败", f"订单 {order_name}: {str(e)}")
# 更新订单状态为失败
try:
jingrow.db.set_value("Order", order_name, "status", "创建失败")
except:
pass
raise e

View File

@ -1088,6 +1088,9 @@ def handle_order_payment_complete(order_id):
process_balance_recharge(order)
elif order.order_type == "网站续费":
process_site_renew(order_id)
elif order.order_type == "Jsite Server":
# 异步创建服务器
jingrow.enqueue('jcloud.api.aliyun_server_light.create_server_async', order_name=order.name)
return True
except Exception as e:
@ -1869,3 +1872,121 @@ def get_balance_transactions(page=1, page_size=20, search=None):
"total": 0,
"error": str(e)
}
# Jsite Server 相关功能
@jingrow.whitelist()
def process_balance_payment_for_server_order(order_id):
"""使用余额支付服务器订单"""
try:
team = get_current_team(True)
order = jingrow.get_pg("Order", {"order_id": order_id})
if not order or order.team != team.name:
jingrow.throw("订单不存在或无权限")
if order.status != "待支付":
return {"success": False, "message": "订单已处理"}
balance = team.get_balance()
if balance < order.total_amount:
return {"success": False, "message": "余额不足"}
# 扣款
balance_transaction = jingrow.get_pg({
"pagetype": "Balance Transaction",
"team": team.name,
"type": "Adjustment",
"source": "Prepaid Credits",
"amount": -order.total_amount,
"description": f"服务器购买: {order.title}"
})
balance_transaction.insert(ignore_permissions=True)
balance_transaction.submit()
# 更新订单状态
order.status = "已支付"
order.payment_method = "余额支付"
order.save(ignore_permissions=True)
# 异步创建服务器
jingrow.enqueue('jcloud.api.aliyun_server_light.create_server_async', order_name=order.name)
return {"success": True, "message": "支付成功,服务器创建中"}
except Exception as e:
jingrow.log_error("服务器支付失败", str(e))
return {"success": False, "message": str(e)}
@jingrow.whitelist()
def process_alipay_server_order(order_id):
"""支付宝支付服务器订单"""
team = get_current_team(True)
order = jingrow.get_pg("Order", {"order_id": order_id})
if not order or order.team != team.name:
jingrow.throw("订单不存在或无权限")
if order.status != "待支付":
jingrow.throw("订单已处理")
from jcloud.api.payment.alipay import AlipayAPI
api = AlipayAPI()
payment_url = api.generate_payment_url(
order_id=order_id,
amount=order.total_amount,
subject=order.title,
team_name=team.name
)
order.payment_method = "支付宝"
order.save(ignore_permissions=True)
return {"payment_url": payment_url, "order_id": order_id}
@jingrow.whitelist()
def process_wechatpay_server_order(order_id):
"""微信支付服务器订单"""
team = get_current_team(True)
order = jingrow.get_pg("Order", {"order_id": order_id})
if not order or order.team != team.name:
jingrow.throw("订单不存在或无权限")
if order.status != "待支付":
jingrow.throw("订单已处理")
wechat_pay = WeChatPayAPI()
qr_code_url = wechat_pay.generate_payment_url(
order_id=order_id,
amount=order.total_amount,
subject=order.title,
team_name=team.name
)
order.payment_method = "微信支付"
order.save(ignore_permissions=True)
return {"qr_code_url": qr_code_url, "order_id": order_id}
@jingrow.whitelist()
def check_server_order_payment_status(order_id):
"""检查服务器订单支付状态"""
try:
order = jingrow.get_pg("Order", {"order_id": order_id})
if not order:
jingrow.throw(f"找不到订单: {order_id}")
return {
"success": True,
"status": order.status,
"order": order.as_dict()
}
except Exception as e:
jingrow.log_error("服务器订单错误", f"检查服务器订单状态失败: {str(e)}")
return {
"success": False,
"message": f"检查订单状态失败: {str(e)}"
}

View File

@ -2,7 +2,6 @@
"actions": [],
"allow_rename": 1,
"creation": "2025-03-23 21:29:54.329381",
"pagetype": "PageType",
"engine": "InnoDB",
"field_order": [
"title",
@ -37,7 +36,7 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "\u5f85\u652f\u4ed8\n\u5df2\u652f\u4ed8\n\u4ea4\u6613\u6210\u529f\n\u5df2\u53d6\u6d88\n\u5df2\u9000\u6b3e",
"options": "待支付\n已支付\n交易成功\n已取消\n已退款",
"read_only": 1
},
{
@ -45,7 +44,7 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Payment Method",
"options": "\n\u652f\u4ed8\u5b9d\n\u5fae\u4fe1\u652f\u4ed8\n\u4f59\u989d\u652f\u4ed8\n\u94f6\u884c\u8f6c\u8d26\n\u5176\u4ed6",
"options": "\n支付宝\n微信支付\n余额支付\n银行转账\n其他",
"read_only": 1
},
{
@ -78,18 +77,19 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Order Type",
"options": "\n\u4f59\u989d\u5145\u503c\n\u65b0\u5efa\u7f51\u7ad9\n\u7f51\u7ad9\u7eed\u8d39\n\u57df\u540d\u7eed\u8d39",
"options": "\n余额充值\n新建网站\n网站续费\n域名续费\n新建服务器\n服务器续费",
"read_only": 1
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-03-26 03:34:52.624889",
"modified": "2025-07-27 17:29:16.088188",
"modified_by": "Administrator",
"module": "Jcloud",
"name": "Order",
"owner": "Administrator",
"pagetype": "PageType",
"permissions": [
{
"create": 1,
@ -104,6 +104,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -16,7 +16,7 @@ class Order(Document):
description: DF.Data | None
order_id: DF.Data | None
order_type: DF.Literal["", "\u4f59\u989d\u5145\u503c", "\u65b0\u5efa\u7f51\u7ad9", "\u7f51\u7ad9\u7eed\u8d39", "\u57df\u540d\u7eed\u8d39"]
order_type: DF.Literal["", "\u4f59\u989d\u5145\u503c", "\u65b0\u5efa\u7f51\u7ad9", "\u7f51\u7ad9\u7eed\u8d39", "\u57df\u540d\u7eed\u8d39", "\u65b0\u5efa\u670d\u52a1\u5668", "\u670d\u52a1\u5668\u7eed\u8d39"]
payment_method: DF.Literal["", "\u652f\u4ed8\u5b9d", "\u5fae\u4fe1\u652f\u4ed8", "\u4f59\u989d\u652f\u4ed8", "\u94f6\u884c\u8f6c\u8d26", "\u5176\u4ed6"]
status: DF.Literal["\u5f85\u652f\u4ed8", "\u5df2\u652f\u4ed8", "\u4ea4\u6613\u6210\u529f", "\u5df2\u53d6\u6d88", "\u5df2\u9000\u6b3e"]
team: DF.Link | None