Commit e587586e by 孙美琪

支付提交

parent eccdf7fa
...@@ -28,11 +28,13 @@ ...@@ -28,11 +28,13 @@
"jsencrypt": "3.3.2", "jsencrypt": "3.3.2",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"qrcode": "^1.5.3",
"vue": "3.3.9", "vue": "3.3.9",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-router": "4.2.5" "vue-router": "4.2.5"
}, },
"devDependencies": { "devDependencies": {
"@types/qrcode": "^1.5.5",
"@vitejs/plugin-vue": "4.5.0", "@vitejs/plugin-vue": "4.5.0",
"@vue/compiler-sfc": "3.3.9", "@vue/compiler-sfc": "3.3.9",
"sass": "1.69.5", "sass": "1.69.5",
......
...@@ -9,11 +9,20 @@ export function computilityMenu (query) { ...@@ -9,11 +9,20 @@ export function computilityMenu (query) {
}) })
} }
// 获取计算资源菜单
export function categoryMenuNew (query) {
return request({
url: '/product/category/list-computility',
method: 'get',
params: query
})
}
// 根据应用类别返回对应计算机资源列表 // 根据应用类别返回对应计算机资源列表
export function getRListByCategory (query) { export function getRListByCategory (query) {
return request({ return request({
url: '/api/v1/getRListByCategory', url: '/product/sku/page',
method: 'get', method: 'get',
params: query params: query
}) })
...@@ -23,7 +32,7 @@ export function getRListByCategory (query) { ...@@ -23,7 +32,7 @@ export function getRListByCategory (query) {
// 计算资源详情 // 计算资源详情
export function getRDetail (query) { export function getRDetail (query) {
return request({ return request({
url: '/api/v1/getRDetail', url: '/product/sku/get-detail',
method: 'get', method: 'get',
params: query params: query
}) })
...@@ -47,6 +56,33 @@ export function orderBuy (query) { ...@@ -47,6 +56,33 @@ export function orderBuy (query) {
}) })
} }
export function createOrderSubmit(query){
return request({
url: '/trade/order/create',
method: 'post',
data: query
})
}
export function createPay(query){
return request({
url: '/pay/order/submit',
method: 'post',
data: query
})
}
// export async function getOrder(id, sync){
// return await request({
// url: '/pay/order/get',
// method: 'get',
// params: {
// id,
// sync
// }
// })
// }
export function bizOrderSubmit(query){ export function bizOrderSubmit(query){
return request({ return request({
url: '/api/v1/bizOrderSubmit', url: '/api/v1/bizOrderSubmit',
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<template #title>计算资源</template> <template #title>计算资源</template>
<el-menu-item <el-menu-item
v-for="item in computilityMenuData" v-for="item in computilityMenuData"
:index="'/computingResource/resourceList?type='+item.value"> :index="'/computingResource/resourceList?type='+item.id">
{{ item.name }} {{ item.name }}
</el-menu-item> </el-menu-item>
</el-sub-menu> </el-sub-menu>
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
import {computed} from 'vue' import {computed} from 'vue'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import AppMain from '@/layout/components/AppMain.vue' import AppMain from '@/layout/components/AppMain.vue'
import {computilityMenu} from '@/api/computingResource.js' import {categoryMenuNew} from '@/api/computingResource.js'
import {industryMenu} from '@/api/industry.js' import {industryMenu} from '@/api/industry.js'
import useUserStore from '@/store/modules/user.js' import useUserStore from '@/store/modules/user.js'
import {ElMessageBox} from 'element-plus' import {ElMessageBox} from 'element-plus'
...@@ -102,7 +102,8 @@ const computilityMenuData = ref([]) ...@@ -102,7 +102,8 @@ const computilityMenuData = ref([])
const industryMenuData = ref([]) const industryMenuData = ref([])
function getComputilityMenu() { function getComputilityMenu() {
computilityMenu().then(res => { categoryMenuNew().then(res => {
console.log(res, 'res')
computilityMenuData.value = res.data computilityMenuData.value = res.data
}) })
} }
......
/**
* 支付订单状态
*/
export const PayOrderStatusEnum = {
WAITING: {
status: 0,
name: '未支付'
},
SUCCESS: {
status: 10,
name: '已支付'
},
CLOSED: {
status: 20,
name: '未支付'
}
}
...@@ -52,18 +52,24 @@ ...@@ -52,18 +52,24 @@
<el-tabs v-model="tabActive" @tab-change="tabChange"> <el-tabs v-model="tabActive" @tab-change="tabChange">
<el-tab-pane <el-tab-pane
v-for="productType in productTypes" v-for="productType in productTypes"
:key="productType.value" :key="productType.id"
:label="productType.name" :label="productType.name"
:name="productType.value"> :name="productType.id">
<div v-if="showVersion === 1" class="version-1"> <div v-if="showVersion === 1" class="version-1">
<el-table :data="tableData" :max-height="490" style="width: 100%"> <el-table :data="tableData" :max-height="490" style="width: 100%">
<el-table-column prop="model" label="型号" width="190px" sortable/> <el-table-column prop="name" label="型号" width="190px" sortable/>
<el-table-column prop="cpu" label="CPU" sortable/> <!-- <el-table-column v-for="item in productType" prop="cpu" label="CPU" sortable/>-->
<el-table-column prop="gpu" label="GPU" sortable/> <el-table-column
<el-table-column prop="memory" label="内存" sortable/> v-for="(item, index) in tableData[0].properties.length!==0?tableData[0].properties.slice(0,6):tableData[0].properties"
<el-table-column prop="storage" label="存储" sortable/> :key="index"
<el-table-column prop="publicPrice" label="报价" sortable/> :label="item.propertyName"
<el-table-column prop="term" label="时长" sortable/> sortable
>
<template #default="{ row }">
{{ row.properties[index].valueName }}
</template>
</el-table-column>
<el-table-column label="操作" width="204px"> <el-table-column label="操作" width="204px">
<template #default="{row}"> <template #default="{row}">
<!-- <el-button class="action-button" @click="selectedProduct(1,row.id)">加入购物车</el-button>--> <!-- <el-button class="action-button" @click="selectedProduct(1,row.id)">加入购物车</el-button>-->
...@@ -79,8 +85,8 @@ ...@@ -79,8 +85,8 @@
<el-col v-for="(item,index) in tableData" :key="index" :span="6"> <el-col v-for="(item,index) in tableData" :key="index" :span="6">
<div class="product-card"> <div class="product-card">
<div class="top-info"> <div class="top-info">
<div class="title">{{ item.model }}</div> <div class="title">{{ item.name }}</div>
<div class="title">{{ item.term }}</div> <!-- <div class="title">{{ item.term }}</div>-->
<div class="tag"> <div class="tag">
<!--<el-tag type="warning" effect="dark">性价比</el-tag>--> <!--<el-tag type="warning" effect="dark">性价比</el-tag>-->
<!--<el-tag type="info" effect="plain">专家推荐</el-tag>--> <!--<el-tag type="info" effect="plain">专家推荐</el-tag>-->
...@@ -88,38 +94,18 @@ ...@@ -88,38 +94,18 @@
<div class="desc">{{ item.remark }}</div> <div class="desc">{{ item.remark }}</div>
</div> </div>
<div class="bottom-info"> <div class="bottom-info">
<!--<div class="label">型号</div>-->
<!--<div class="value">{{ item.model }}</div>-->
<!--<el-divider></el-divider>-->
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24"
<div class="parameter-item"> v-for="(i,x) in item.properties.length!==0?item.properties.slice(0,4):item.properties"
<div class="label">CPU</div> :key="x">
<div class="value">{{ item.cpu }}</div>
</div>
</el-col>
<el-col :span="24">
<div class="parameter-item">
<div class="label">GPU</div>
<div class="value">{{ item.gpu }}</div>
</div>
</el-col>
<el-col :span="24">
<div class="parameter-item"> <div class="parameter-item">
<div class="label">内存</div> <div class="label">{{ i.propertyName }}</div>
<div class="value">{{ item.memory }}</div> <div class="value">{{ i.valueName }}</div>
</div>
</el-col>
<el-col :span="24">
<div class="parameter-item">
<div class="label">存储</div>
<div class="value">{{ item.storage }}</div>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-divider></el-divider> <el-divider></el-divider>
<div class="flex-justify-end price">¥{{ item.publicPrice }}{{ item.unitTypeName }}</div> <div class="flex-justify-end price">¥{{ item.price }}/{{ item.feeInfo }}</div>
<!--<div class="flex-justify-end month-expenses">约¥15/月</div>--> <!--<div class="flex-justify-end month-expenses">约¥15/月</div>-->
<el-divider></el-divider> <el-divider></el-divider>
<div class="footer-action flex"> <div class="footer-action flex">
...@@ -146,55 +132,22 @@ ...@@ -146,55 +132,22 @@
<el-drawer v-model="showDrawer" class="drawer" direction="rtl" :size="694" title="资源申请详情"> <el-drawer v-model="showDrawer" class="drawer" direction="rtl" :size="694" title="资源申请详情">
<template #default> <template #default>
<div class="info-block"> <div class="info-block">
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between">
<div class="label">类别</div> <div class="label">类别</div>
<div class="value">{{ productDetail.category }}</div> <div class="value">{{ productDetail.name }}</div>
</div> </div>
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between">
<div class="label">型号</div> <div class="label">型号</div>
<div class="value">{{ productDetail.model }}</div> <div class="value">{{ productDetail.name }}</div>
</div> </div>
</div> </div>
<div class="info-block"> <div class="info-block">
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between" v-for="(i,index) in productDetail.properties">
<div class="label">CPU</div> <div class="label">{{ i.propertyName }}</div>
<div class="value">{{ productDetail.cpu }}</div> <div class="value">{{ i.valueName }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">GPU</div>
<div class="value">{{ productDetail.gpu }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">内存</div>
<div class="value">{{ productDetail.memory }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">存储</div>
<div class="value">{{ productDetail.storage }}</div>
</div>
</div>
<div class="info-block">
<div v-for="item in productDetail.options" :key="item.id"
class="info-item flex-align-center flex-space-between">
<div class="label">{{ item.label }}</div>
<div class="value">
<el-input-number v-if="item.type === 2" v-model="item.value" :min="0" @change="orderComputerPrice"
style="width: 110px"/>
<el-radio-group v-if="[0,1,4].includes(item.type)" v-model="item.value" @change="orderComputerPrice">
<el-radio-button v-for="option in item.options" :label="option.id">
{{ option.model + option.unit }}
</el-radio-button>
</el-radio-group>
</div>
</div> </div>
</div> </div>
...@@ -203,7 +156,7 @@ ...@@ -203,7 +156,7 @@
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between">
<div class="label">使用数量(个)</div> <div class="label">使用数量(个)</div>
<div class="value"> <div class="value">
<el-input-number v-model="form.num" :min="0" @change="orderComputerPrice" style="width: 110px"/> <el-input-number v-model="form.num" :min="0" @change="orderComputerPrice" style="width: 110px" disabled/>
</div> </div>
</div> </div>
</div> </div>
...@@ -217,37 +170,50 @@ ...@@ -217,37 +170,50 @@
<div class="mr20"> <div class="mr20">
<div class="price">{{ orderPrice }}</div> <div class="price">{{ orderPrice }}</div>
</div> </div>
<el-button type="primary" @click="submit">{{ selectedType === 1 ? '加入购物车' : '立即申请' }} <el-button type="primary" @click="create">{{ selectedType === 1 ? '加入购物车' : '立即购买' }}
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
</el-drawer> </el-drawer>
<div class="shopping-trolley" @click="$router.push('/computingResource/shoppingCart')"> <!-- <div class="shopping-trolley" @click="$router.push('/computingResource/shoppingCart')">-->
<el-icon size="24px"> <!-- <el-icon size="24px">-->
<ShoppingTrolley/> <!-- <ShoppingTrolley/>-->
</el-icon> <!-- </el-icon>-->
<div></div> <!-- <div>购</div>-->
<div></div> <!-- <div>物</div>-->
<div></div> <!-- <div>车</div>-->
</div> <!-- </div>-->
<el-dialog
:title="qrCode.title"
v-model="qrCode.visible"
width="385px"
append-to-body
:align-center="true"
:close-on-click-modal="false"
@closed="clearQueryInterval"
>
<img :src="qrCode.url" alt=""/>
</el-dialog>
</div> </div>
</template> </template>
<script name="ResourceList" setup> <script name="ResourceList" setup>
import {ref, watch} from 'vue' import {ref, watch} from 'vue'
import {ElMessageBox} from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import SvgIcon from '@/components/SvgIcon/index.vue' import SvgIcon from '@/components/SvgIcon/index.vue'
import { import {
computilityMenu, computilityMenu,
getRListByCategory, getRListByCategory,
getRDetail, getRDetail,
// orderBuy,
shoppingAdd, shoppingAdd,
orderComputer, bizOrderSubmit orderComputer, bizOrderSubmit, categoryMenuNew, createOrderSubmit, createPay
} from '@/api/computingResource.js' } from '@/api/computingResource.js'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import QRCode from 'qrcode'
import request from '@/utils/request'
import {PayOrderStatusEnum} from "@/utils/constants.js";
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
...@@ -260,14 +226,21 @@ const pageSize = ref(10) ...@@ -260,14 +226,21 @@ const pageSize = ref(10)
const productTypes = ref([]) const productTypes = ref([])
const tableData = ref([]) const tableData = ref([])
const interval = ref(undefined)
const qrCode = ref({
url: '',
title: '请使用微信”扫一扫“扫码支付',
visible: false
})
function getTypeData() { function getTypeData() {
computilityMenu().then(res => { categoryMenuNew().then(res => {
productTypes.value = res.data productTypes.value = res.data
if (route.query.type) { if (route.query.type) {
tabActive.value = route.query.type tabActive.value = Number(route.query.type)
} else { } else {
tabActive.value = res.data[0].value tabActive.value = Number(res.data[0].id)
} }
getList() getList()
}) })
...@@ -277,7 +250,7 @@ getTypeData() ...@@ -277,7 +250,7 @@ getTypeData()
watch(() => route.query.type, (value, oldValue) => { watch(() => route.query.type, (value, oldValue) => {
if (value) { if (value) {
tabActive.value = value tabActive.value = Number(value)
} }
}) })
...@@ -287,10 +260,9 @@ function tabChange() { ...@@ -287,10 +260,9 @@ function tabChange() {
} }
function getList() { function getList() {
getRListByCategory({categoryId: tabActive.value, pageNum: pageNum.value, pageSize: pageSize.value}).then(res => { getRListByCategory({categoryId: tabActive.value, pageNo: pageNum.value, pageSize: pageSize.value}).then(res => {
total.value = res.total total.value = res.total
// tableData.value = res.rows tableData.value = res.data.list
tableData.value = res.data
}) })
} }
...@@ -307,44 +279,12 @@ function selectedProduct(type, id) { ...@@ -307,44 +279,12 @@ function selectedProduct(type, id) {
selectedType.value = type selectedType.value = type
selectedId.value = id selectedId.value = id
getRDetail({id}).then(res => { getRDetail({id}).then(res => {
// res.data.options.forEach(item => {
// if ([0, 1, 4].includes(item.type)) {
// item.value = item.options[0].id
// }
// if (item.type === 2) {
// item.value = 1
// }
// })
productDetail.value = res.data productDetail.value = res.data
// orderComputerPrice() orderPrice.value = res.data.price;
orderPrice.value=res.data.publicPrice;
showDrawer.value = true showDrawer.value = true
}) })
} }
// function initSubmitData() {
// return {
// id: selectedId.value,
// num: form.value.num,
// computerItems: productDetail.value.options.map(item => {
// if ([0, 1, 4].includes(item.type)) {
// return {
// id: item.id,
// name: item.label,
// valueId: item.value
// }
// }
// return {
// id: item.id,
// name: item.label,
// valueId: item.options[0].id,
// value: item.value.toString()
// }
// })
// }
// }
const orderPrice = ref(0) const orderPrice = ref(0)
function orderComputerPrice() { function orderComputerPrice() {
...@@ -353,51 +293,125 @@ function orderComputerPrice() { ...@@ -353,51 +293,125 @@ function orderComputerPrice() {
}) })
} }
function getSubmitData(){ function getCreateData() {
return{ return {
skuId : selectedId.value, skuId: selectedId.value,
} }
} }
function submit() { function create() {
// 弹出确认对话框 // 用户点击“确认”时执行
ElMessageBox.confirm( const createData = getCreateData();
'确定购买吗?', // 对话框提示文字 //创建订单
'购买确认', // 对话框标题 createOrderSubmit({items: [{skuId: createData.skuId, count: 1}]}).then(res => {
{ if (res.data.payOrderId !== '') {
confirmButtonText: '确认', // 确认按钮文字 // 弹出确认对话框
cancelButtonText: '取消', // 取消按钮文字 ElMessageBox.confirm(
type: 'warning' // 对话框类型(警告样式) '确定购买吗?', // 对话框提示文字
'购买确认', // 对话框标题
{
confirmButtonText: '确认', // 确认按钮文字
cancelButtonText: '取消', // 取消按钮文字
type: 'warning' // 对话框类型(警告样式)
}
)
.then(() => {
createPay({id: res.data.payOrderId, channelCode: 'wx_native'}).then(i => {
if (i.code === 0) {
getCode(i.data.displayContent, res.data.payOrderId)
}
})
// showDrawer.value = false;
})
.catch(() => {
ElMessageBox.confirm(
'提示',
'订单已创建,请前往控制台-我的订单查看',
{
confirmButtonText: '确认',
showCancelButton: false,
type: 'success'
}
).then(() => {
showDrawer.value = false;
})
});
}
}).catch(err => {
// 接口调用失败的处理(如提示错误)
});
}
function getCode(value, payOrderId) {
QRCode.toDataURL(value, {errorCorrectionLevel: 'L', margin: 2, width: 350}, (err, url) => {
if (err) throw err
qrCode.value = {
url: url,
title: '请使用微信“扫一扫”扫码支付',
visible: true
}
} }
) )
.then(() => { createQueryInterval(payOrderId)
// 用户点击“确认”时执行
// 1. 获取提交数据(复用之前的 initSubmitData 函数)
const submitData = getSubmitData();
// 2. 调用购买接口(此处用 TODO 标记实际接口逻辑)
// TODO: 实际接口调用代码,例如:
bizOrderSubmit(submitData).then(res => {
// 接口调用成功后的处理(如跳转订单页)
}).catch(err => {
// 接口调用失败的处理(如提示错误)
});
// 3. 关闭抽屉(如果需要)
showDrawer.value = false;
})
.catch(() => {
// 用户点击“取消”时执行(不做任何操作)
// console.log('用户取消购买');
// 可以添加取消后的提示(可选)
// ElMessage({
// type: 'info',
// message: '已取消购买'
// });
});
} }
// function submit() {
/** 轮询查询任务 */
const createQueryInterval = (id) => {
if (interval.value) {
return
}
interval.value = setInterval(async () => {
const res = await getOrder(id)
console.log(res, 'res')
// 已支付
if (res.data.status === PayOrderStatusEnum.SUCCESS.status) {
clearQueryInterval()
// ElMessage.success('支付成功!')
ElMessageBox.confirm(
'支付成功',
'请前往控制台-我的订单查看',
{
confirmButtonText: '确认',
showCancelButton: false,
type: 'success'
}
).then(() => {})
}
// 已取消
if (res.data.status === PayOrderStatusEnum.CLOSED.status) {
clearQueryInterval()
ElMessage.error('支付已关闭!')
}
}, 1000 * 2)
}
// 查询详情支付订单
const getOrder = async (id, sync) => {
return await request({
url: '/pay/order/get',
method: 'get',
params: {
id,
sync
}
})
}
/** 清空查询任务 */
const clearQueryInterval = () => {
// 清空各种弹窗
qrCode.value = {
title: '',
url: '请使用微信“扫一扫”扫码支付',
visible: false
}
showDrawer.value = false
// 清空任务
clearInterval(interval.value)
interval.value = undefined
}
// function create() {
// const data = initSubmitData() // const data = initSubmitData()
// if (selectedType.value === 1) { // if (selectedType.value === 1) {
// shoppingAdd(data).then(res => { // shoppingAdd(data).then(res => {
...@@ -529,7 +543,7 @@ function submit() { ...@@ -529,7 +543,7 @@ function submit() {
} }
.version-2 { .version-2 {
height: 490px; height: 492px;
margin: 0 -12px; margin: 0 -12px;
overflow-x: auto; overflow-x: auto;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment