Merge pull request 'add(订单、支付):添加了订单,支付模块,并完善了一些功能' (#8) from dev into main
Reviewed-on: #8
This commit is contained in:
commit
3def498f4a
@ -351,7 +351,10 @@ export default {
|
||||
this.$emit("dataDelete", id);
|
||||
},
|
||||
handleSearch() {},
|
||||
handleAddUser() {},
|
||||
handleAddUser() {
|
||||
this.$emit("dataAdd");
|
||||
}
|
||||
,
|
||||
handleBatchDelete() {},
|
||||
},
|
||||
watch: {
|
||||
|
||||
396
src/components/OrderDataTable.vue
Normal file
396
src/components/OrderDataTable.vue
Normal file
@ -0,0 +1,396 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-center card-header">{{ title }}</h5>
|
||||
<div id="zero-conf_wrapper" class="dataTables_wrapper dt-bootstrap4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-sm-12 col-md-6 d-flex align-items-center">
|
||||
<div class="dataTables_length" id="zero-conf_length">
|
||||
<label class="d-flex align-items-center" style="white-space: nowrap">
|
||||
展示
|
||||
<select
|
||||
name="zero-conf_length"
|
||||
aria-controls="zero-conf"
|
||||
class="custom-select custom-select-sm form-control form-control-sm mx-2"
|
||||
v-model="pageSize"
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
条数据
|
||||
</label>
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
<label class="d-flex align-items-center" style="white-space: nowrap">
|
||||
搜索:
|
||||
<input
|
||||
type="search"
|
||||
class="form-control form-control-sm ms-2"
|
||||
placeholder="请输入关键字"
|
||||
aria-controls="zero-conf"
|
||||
/>
|
||||
<button class="btn btn-sm btn-secondary ms-2" @click="handleSearch">
|
||||
搜索
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6 text-center">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<table
|
||||
id="zero-conf"
|
||||
class="display dataTable"
|
||||
style="width: 100%"
|
||||
role="grid"
|
||||
aria-describedby="zero-conf_info"
|
||||
>
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th
|
||||
class="sorting_asc"
|
||||
tabindex="0"
|
||||
aria-controls="zero-conf"
|
||||
rowspan="1"
|
||||
colspan="1"
|
||||
aria-sort="ascending"
|
||||
aria-label="Name: activate to sort column descending"
|
||||
style="width: 85.5469px"
|
||||
v-for="(item, index) in headers"
|
||||
:key="index"
|
||||
>
|
||||
{{ item.text }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
role="row"
|
||||
v-for="(item, rowIndex) in rows"
|
||||
:key="rowIndex"
|
||||
:class="rowIndex % 2 ? 'even' : 'odd'"
|
||||
>
|
||||
<td v-for="(header, colIndex) in headers" :key="colIndex">
|
||||
<div v-if="header.type == null">
|
||||
<span>{{ item[header.value] ? item[header.value] : '空' }}</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'bool'">
|
||||
<span
|
||||
:class="[
|
||||
'badge',
|
||||
item[header.value] ? 'bg-danger' : 'bg-success',
|
||||
]"
|
||||
>{{ item[header.value] ? "禁用" : "正常" }}</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="header.type == 'arrObj'">
|
||||
<span
|
||||
class="badge bg-info"
|
||||
v-for="(objItem, objIndex) in item[header.value]"
|
||||
:key="objIndex"
|
||||
>
|
||||
{{ objItem[header.child] }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'money'">
|
||||
<span>{{ item[header.value].toFixed(2) }}</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'datetime'">
|
||||
<span>{{ formatDateTime(item[header.value]) }}</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'method'">
|
||||
<span
|
||||
:class="[
|
||||
'badge',
|
||||
'bg-warning',
|
||||
]"
|
||||
>{{ callMethod[item[header.value]] }}</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="header.type == 'find'">
|
||||
<span class="badge bg-info">
|
||||
{{ header.findValue.find(x => x.id == item[header.value]).name }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'orderStatus'">
|
||||
<span class="badge bg-info" v-if="item[header.value] == 0">
|
||||
待支付
|
||||
</span>
|
||||
<span class="badge bg-success" v-if="item[header.value] == 1">
|
||||
已支付
|
||||
</span>
|
||||
<span class="badge bg-warning" v-if="item[header.value] == 2">
|
||||
已取消
|
||||
</span>
|
||||
<span class="badge bg-danger" v-if="item[header.value] == 3">
|
||||
失败
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="header.type == 'orderType'">
|
||||
<span class="badge bg-primary" v-if="item[header.value] == 0">
|
||||
充值
|
||||
</span>
|
||||
<span class="badge bg-success" v-if="item[header.value] == 1">
|
||||
购买
|
||||
</span>
|
||||
<span class="badge bg-info" v-if="item[header.value] == 2">
|
||||
退款
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="1"
|
||||
colspan="1"
|
||||
v-for="(header, index) in headers"
|
||||
:key="index"
|
||||
>
|
||||
{{ header.value }}
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-5">
|
||||
<div
|
||||
class="dataTables_info"
|
||||
id="zero-conf_info"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
正在展示 {{ currentPageIndex * pageSize - (pageSize - 1) }} 到
|
||||
{{ currentPageIndex * pageSize }} 条数据 总计 {{ dataCount }} 条
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-7">
|
||||
<div
|
||||
class="dataTables_paginate paging_simple_numbers"
|
||||
id="zero-conf_paginate"
|
||||
>
|
||||
<ul class="pagination">
|
||||
<li
|
||||
:class="[
|
||||
'paginate_button',
|
||||
'page-item',
|
||||
'previous',
|
||||
currentPageIndex == 1 ? 'disabled' : '',
|
||||
]"
|
||||
id="zero-conf_previous"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
aria-controls="zero-conf"
|
||||
data-dt-idx="0"
|
||||
tabindex="0"
|
||||
class="page-link"
|
||||
@click.prevent="previousPage"
|
||||
>上一页</a
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
:class="[
|
||||
'paginate_button',
|
||||
'page-item',
|
||||
item.index == currentPageIndex ? 'active' : '',
|
||||
]"
|
||||
v-for="(item, index) in pageBtn"
|
||||
:key="index"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
aria-controls="zero-conf"
|
||||
:data-dt-idx="item.index"
|
||||
tabindex="0"
|
||||
class="page-link"
|
||||
@click.prevent="currentPageIndex = item.index"
|
||||
>{{ item.text }}</a
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
:class="[
|
||||
'paginate_button',
|
||||
'page-item',
|
||||
'next',
|
||||
currentPageIndex == pageCount ? 'disabled' : '',
|
||||
]"
|
||||
id="zero-conf_next"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
aria-controls="zero-conf"
|
||||
data-dt-idx="7"
|
||||
tabindex="0"
|
||||
class="page-link"
|
||||
@click.prevent="nextPage"
|
||||
>下一页</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "OrderDataTable",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: "标题",
|
||||
},
|
||||
headers: {
|
||||
// 表头数组 [{ text: '名字', value: 'name'}, ...]
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
rows: {
|
||||
// 数据数组 [{ name: '佐藤爱理', position: '会计', office: '东京', age: 33, startDate: '2008/11/28', salary: '162,700 元' }, ...]
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
dataCount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//当前页索引
|
||||
currentPageIndex: 1,
|
||||
//单页大小
|
||||
pageSize: 10,
|
||||
//总页数
|
||||
pageCount: 0,
|
||||
//分页按钮数据,[{text:'1',index:1},.....]
|
||||
pageBtn: [],
|
||||
//调用方法
|
||||
callMethod:['GET','POST']
|
||||
};
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
//下一页
|
||||
nextPage() {
|
||||
if (this.currentPageIndex < this.pageCount) this.currentPageIndex++;
|
||||
},
|
||||
//上一页
|
||||
previousPage() {
|
||||
if (this.currentPageIndex > 1) {
|
||||
this.currentPageIndex--;
|
||||
}
|
||||
},
|
||||
changePage(pageIndex) {
|
||||
this.currentPageIndex == pageIndex;
|
||||
},
|
||||
//更新总页数
|
||||
updatePageCount(newPageSize) {
|
||||
this.pageCount = Math.floor(this.dataCount / newPageSize);
|
||||
this.pageCount += this.dataCount % newPageSize == 0 ? 0 : 1;
|
||||
},
|
||||
//更新分页按钮数据
|
||||
updatePageBtn(newPageIndex) {
|
||||
this.pageBtn = [];
|
||||
//初始化首页
|
||||
this.pageBtn.push({ text: "1", index: 1 });
|
||||
//总页数小于8时显示全部页码
|
||||
if (this.pageCount <= 8) {
|
||||
for (let i = 2; i < this.pageCount; i++) {
|
||||
this.pageBtn.push({ text: `${i}`, index: i });
|
||||
}
|
||||
} else {
|
||||
//当前页左侧显示2格页码,当显示最小页码距离首页中间间隔大于1时隐藏间隔页面
|
||||
if (newPageIndex - 2 > 3) {
|
||||
this.pageBtn.push({ text: "...", index: newPageIndex });
|
||||
}
|
||||
//渲染当前页码左右各两格页码
|
||||
const numleft = newPageIndex - 2 < 2 ? newPageIndex - 2 : 2;
|
||||
const numright =
|
||||
newPageIndex + 2 < this.pageCount ? 2 : this.pageCount - newPageIndex - 1;
|
||||
for (let i = newPageIndex - numleft; i <= newPageIndex + numright; i++) {
|
||||
this.pageBtn.push({ text: `${i}`, index: i });
|
||||
}
|
||||
//当前页右侧显示2格页码,当显示最大页码距离尾页中间间隔大于1时隐藏间隔页面
|
||||
if (newPageIndex + 2 < this.pageCount - 2) {
|
||||
this.pageBtn.push({ text: "...", index: newPageIndex });
|
||||
}
|
||||
}
|
||||
//渲染尾页
|
||||
this.pageBtn.push({ text: `${this.pageCount}`, index: this.pageCount });
|
||||
},
|
||||
formatDateTime(str) {
|
||||
if (!str) return "-";
|
||||
|
||||
const date = new Date(str);
|
||||
if (isNaN(date)) return "-"; // 防止 Safari 报 Invalid Date
|
||||
|
||||
const pad = (n) => n.toString().padStart(2, "0");
|
||||
|
||||
const Y = date.getFullYear();
|
||||
const M = pad(date.getMonth() + 1);
|
||||
const D = pad(date.getDate());
|
||||
const h = pad(date.getHours());
|
||||
const m = pad(date.getMinutes());
|
||||
const s = pad(date.getSeconds());
|
||||
|
||||
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
||||
},
|
||||
modify(id) {
|
||||
this.$emit("dataModify", id);
|
||||
},
|
||||
deleteData(id) {
|
||||
this.$emit("dataDelete", id);
|
||||
},
|
||||
handleSearch() {},
|
||||
handleAddUser() {
|
||||
this.$emit("dataAdd");
|
||||
}
|
||||
,
|
||||
handleBatchDelete() {},
|
||||
},
|
||||
watch: {
|
||||
//监听分页大小变化
|
||||
pageSize: {
|
||||
handler(newVal) {
|
||||
this.updatePageCount(newVal);
|
||||
//单页显示数据量改变时重置当前索引,防止数据以及控件异常
|
||||
this.currentPageIndex = 1;
|
||||
this.$emit("pageChanged", { pageIndex: this.currentPageIndex, pageSize: newVal });
|
||||
this.updatePageBtn(this.currentPageIndex);
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
//监听页索引,用于切换数据
|
||||
currentPageIndex: {
|
||||
handler(newVal) {
|
||||
this.$emit("pageChanged", { pageIndex: newVal, pageSize: this.pageSize });
|
||||
this.updatePageBtn(newVal);
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 可自定义样式 */
|
||||
.card-title {
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
123
src/components/PackageFormModal.vue
Normal file
123
src/components/PackageFormModal.vue
Normal file
@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div v-if="visible" class="modal fade show" id="exampleModalCenter" tabindex="-1"
|
||||
aria-labelledby="exampleModalLabel" style="display: block; padding-right: 15px;" _mstvisible="0"
|
||||
aria-modal="true" role="dialog">
|
||||
<div class="modal-dialog modal-dialog-centered" _mstvisible="1">
|
||||
<div class="modal-content" _mstvisible="2">
|
||||
<div class="modal-header" _mstvisible="3">
|
||||
<h5 class="modal-title" id="exampleModalCenterTitle" _msttexthash="13222534" _msthash="147"
|
||||
_mstvisible="4">{{ title }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"
|
||||
_mstaria-label="59709" _msthash="148" _mstvisible="4" @click="cancel"></button>
|
||||
</div>
|
||||
<div class="formcontent">
|
||||
<form>
|
||||
<div class="row mb-3">
|
||||
<label for="inputName3" class="col-sm-2 col-form-label">套餐名称</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="form.name" class="form-control" id="inputName3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="inpuCallLimit3" class="col-sm-2 col-form-label">月调用次数</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="form.callLimit" class="form-control" id="inputCallLimit3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="inputPrice3" class="col-sm-2 col-form-label">价格</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="form.price" class="form-control" id="inputPrice3" v-money>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="inputOneMinuteLimit3" class="col-sm-2 col-form-label">调用频率限制</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="form.oneMinuteLimit" class="form-control"
|
||||
id="inputOneMinuteLimit3">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer" _mstvisible="3">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" _msttexthash="5889065"
|
||||
_msthash="150" _mstvisible="4" @click="cancel">关闭</button>
|
||||
<button type="button" class="btn btn-primary" _msttexthash="10744773" _msthash="151" _mstvisible="4"
|
||||
@click="submit">保存更改</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'PackageFormModal',
|
||||
props: {
|
||||
title: {
|
||||
type: String
|
||||
},
|
||||
formType: {
|
||||
type: String,
|
||||
default: 'edit'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
packageId: -2,
|
||||
packageList: [],
|
||||
form: {
|
||||
name: '',
|
||||
callLimit: 0,
|
||||
price: '0',
|
||||
oneMinuteLimit: 0
|
||||
},
|
||||
resolve: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open(packageId = null, packageInfo = null) {
|
||||
this.resetForm();
|
||||
this.visible = true;
|
||||
if (packageInfo != null) {
|
||||
this.packageId = packageId;
|
||||
this.form.name = packageInfo.name;
|
||||
this.form.callLimit = packageInfo.callLimit;
|
||||
this.form.price = packageInfo.price.toString();
|
||||
this.form.oneMinuteLimit = packageInfo.oneMinuteLimit;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
this.resolve = resolve;
|
||||
});
|
||||
},
|
||||
submit() {
|
||||
this.visible = false;
|
||||
this.resolve && this.resolve(this.form);
|
||||
},
|
||||
cancel() {
|
||||
this.visible = false;
|
||||
this.resolve && this.resolve(null);
|
||||
},
|
||||
resetForm() {
|
||||
this.form = {
|
||||
name: '',
|
||||
callLimit: 0,
|
||||
price: '0',
|
||||
oneMinuteLimit: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.formcontent {
|
||||
padding: 0 30px;
|
||||
}
|
||||
</style>
|
||||
@ -45,6 +45,7 @@
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: 'UserFormModal',
|
||||
props:{
|
||||
@ -63,26 +64,29 @@ export default {
|
||||
form: {
|
||||
userName: '',
|
||||
email: '',
|
||||
balance: '',
|
||||
balance: '0',
|
||||
password: ''
|
||||
},
|
||||
resolve: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open(userId,userInfo = null) {
|
||||
open(userId = null,userInfo = null) {
|
||||
this.resetForm();
|
||||
this.visible = true;
|
||||
this.userId = userId;
|
||||
if(userInfo != null){
|
||||
this.form.email = userInfo.email;
|
||||
this.form.userName = userInfo.userName;
|
||||
this.form.balance = userInfo.balance;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
this.resolve = resolve;
|
||||
});
|
||||
},
|
||||
submit() {
|
||||
this.visible = false;
|
||||
this.form.balance = Number(this.form.balance)
|
||||
this.resolve && this.resolve(this.form);
|
||||
},
|
||||
cancel() {
|
||||
@ -93,7 +97,7 @@ export default {
|
||||
this.form = {
|
||||
userName: '',
|
||||
email: '',
|
||||
balance: '',
|
||||
balance: '0',
|
||||
password: ''
|
||||
};
|
||||
}
|
||||
|
||||
@ -29,6 +29,9 @@ const getUserInfoById = async (id) => await request.get(`/api/Admin/UserInfo?use
|
||||
//更新用户信息
|
||||
const updateUserInfo = async (id,param) => await request.post(`/api/Admin/UpdateUser?userId=${id}`,param)
|
||||
|
||||
//添加用户
|
||||
const addUser =async (param) => await request.post('/api/admin/adduser',param)
|
||||
|
||||
//获取api列表
|
||||
const getApiList = async (pageIndex,pageSize,desc) => await request.get(`/api/apis/ApiList?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`)
|
||||
|
||||
@ -44,9 +47,50 @@ const updateApiInfo = async (id,param) => await request.post(`/api/Apis/UpdateAp
|
||||
//获取套餐列表
|
||||
const getPackageList = async (pageIndex,pageSize,desc) => await request.get(`/api/Package/GetPackageList?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`)
|
||||
|
||||
|
||||
//删除套餐
|
||||
const deletePackageById = async (id) => await request.delete(`/api/Package/DeletePackage?packageId=${id}`)
|
||||
|
||||
//更新套餐信息
|
||||
const updatePackage = async (id,param) => await request.post(`/api/Package/UpdatePackage?packageId=${id}`,param)
|
||||
|
||||
//添加套餐
|
||||
const addPackage = async (param) => await request.post("/api/Package/AddPackage",param)
|
||||
|
||||
//获取套餐信息
|
||||
const getPackageInfoById = async (id) => await request.get(`/api/Package/GetPackageInfo?packageId=${id}`)
|
||||
|
||||
//更新系统配置
|
||||
const updateSystemConfig = async (configName,configBody) => await request.post('/api/SystemConfig/UpdateSystemConfig',{configName:configName,configBody:configBody})
|
||||
|
||||
//创建支付
|
||||
const createPayment = async (PaymentType,Amount,ReturnUrl) => await request.post('/api/pay/createpayment',{PaymentType:PaymentType,Amount:Amount,ReturnUrl:ReturnUrl});
|
||||
//支付通知
|
||||
const payNotice = async (pid, trade_no, out_trade_no, type, name, money, trade_status, sign, sign_type) => {
|
||||
|
||||
const query = new URLSearchParams({
|
||||
pid,
|
||||
trade_no,
|
||||
out_trade_no,
|
||||
type,
|
||||
name,
|
||||
money,
|
||||
trade_status,
|
||||
sign,
|
||||
sign_type
|
||||
}).toString();
|
||||
|
||||
return await request.get(`/api/pay/notice?${query}`);
|
||||
};
|
||||
|
||||
//获取用户套餐列表
|
||||
const getUserPackagesAdmin = async (pageIndex,pageSize,desc) => await request.get(`/api/Package/GetUserPackageListAdmin?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`);
|
||||
|
||||
//获取订单列表
|
||||
const getOrderList = async (pageIndex,pageSize,desc) => await request.get(`/api/ordergetorders?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`);
|
||||
|
||||
//获取个人订单列表
|
||||
const getMyOrderList = async (pageIndex,pageSize,desc) => await request.get(`/api/ordergetmyorders?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`);
|
||||
export default {
|
||||
login,
|
||||
register,
|
||||
@ -63,5 +107,15 @@ export default {
|
||||
getApiInfoById,
|
||||
updateApiInfo,
|
||||
getPackageList,
|
||||
updateSystemConfig
|
||||
updateSystemConfig,
|
||||
payNotice,
|
||||
createPayment,
|
||||
addUser,
|
||||
getUserPackagesAdmin,
|
||||
deletePackageById,
|
||||
updatePackage,
|
||||
addPackage,
|
||||
getPackageInfoById,
|
||||
getOrderList,
|
||||
getMyOrderList
|
||||
}
|
||||
@ -30,6 +30,11 @@ const routes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/paynotice',
|
||||
name: 'paynotice',
|
||||
component: () => import('@/views/PayNotice.vue')
|
||||
},
|
||||
{
|
||||
path: '/layout',
|
||||
component: () => import('@/views/layout/Home.vue'),
|
||||
@ -112,17 +117,6 @@ const routes = [
|
||||
isHome: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'records',
|
||||
component: () => import('@/views/layout/Records.vue'),
|
||||
meta: {
|
||||
title: '消费记录',
|
||||
icon: 'archive',
|
||||
showInMenu: true,
|
||||
showInUser: true,
|
||||
isHome: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'system',
|
||||
component: () => import('@/views/layout/SystemConfig.vue'),
|
||||
|
||||
36
src/views/PayNotice.vue
Normal file
36
src/views/PayNotice.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="pay-redirect">
|
||||
<h2>正在处理支付结果,请稍候...</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'PayRedirect',
|
||||
data(){
|
||||
return {
|
||||
text:'正在处理支付结果,请稍候...'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
const query = this.$route.query;
|
||||
// 校验必要字段
|
||||
if (!query || !query.out_trade_no || !query.trade_status) {
|
||||
alert('参数不完整,无法确认支付结果');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$api.payNotice(query.pid,query.trade_no,query.out_trade_no,query.type,query.name,query.money,query.trade_status,query.sign,query.sign_type)
|
||||
.then(res => {
|
||||
console.log('通知后端成功', res.data);
|
||||
this.$router.push('/layout/balance');
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('通知后端失败', err);
|
||||
this.text = '支付失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -11,7 +11,7 @@
|
||||
<div class="balance-box">
|
||||
<h5 class="balance-text">
|
||||
<i class="fas fa-wallet balance-icon"></i>
|
||||
剩余余额:<span class="balance-amount">{{ balance }}</span>
|
||||
剩余余额:<span class="balance-amount">{{ userInfo.balance }}</span>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,14 +36,14 @@
|
||||
<!-- 单选按钮 1 -->
|
||||
<div
|
||||
class="col-6 d-flex justify-content-center mb-3 option-box"
|
||||
:class="{ 'selected-box': selectedpay === 'alipay' }"
|
||||
:class="{ 'selected-box': selectedpay === 0 }"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
id="option1"
|
||||
name="options"
|
||||
class="hidden-radio"
|
||||
value="alipay"
|
||||
:value="0"
|
||||
v-model="selectedpay"
|
||||
/>
|
||||
<label for="option1" class="label-style">
|
||||
@ -53,14 +53,14 @@
|
||||
<!-- 单选按钮 2 -->
|
||||
<div
|
||||
class="col-6 d-flex justify-content-center mb-3 option-box"
|
||||
:class="{ 'selected-box': selectedpay === 'wechat' }"
|
||||
:class="{ 'selected-box': selectedpay === 1 }"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
id="option2"
|
||||
name="options"
|
||||
class="hidden-radio"
|
||||
value="wechat"
|
||||
:value="1"
|
||||
v-model="selectedpay"
|
||||
/>
|
||||
<label for="option2" class="label-style">
|
||||
@ -80,53 +80,68 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "Balance",
|
||||
data() {
|
||||
return {
|
||||
userInfo:{
|
||||
balance:0
|
||||
},
|
||||
rechargeAmount: 0,
|
||||
selectedpay: "",
|
||||
selectedpay: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState("userinfo", {
|
||||
balance: (state) => (state.user ? state.user.balance : 0),
|
||||
}),
|
||||
formattedRechargeAmount: {
|
||||
get() {
|
||||
return this.rechargeAmount === 0 ? "" : this.rechargeAmount;
|
||||
if (typeof this.rechargeAmount !== 'number') return '0.00';
|
||||
return this.rechargeAmount
|
||||
.toFixed(2)
|
||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
},
|
||||
set(value) {
|
||||
this.rechargeAmount = value === "" ? 0 : Number(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch("userinfo/fetchUserInfo");
|
||||
set(val) {
|
||||
// 去除千分位并转换为数字
|
||||
const num = parseFloat(val.replace(/,/g, ''));
|
||||
if (!isNaN(num)) {
|
||||
this.rechargeAmount = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deposit() {
|
||||
if (this.rechargeAmount <= 0) {
|
||||
this.$alert("充值金额必须大于0", "danger");
|
||||
return;
|
||||
}
|
||||
if (!this.selectedpay) {
|
||||
this.$alert("请选择充值方式", "danger");
|
||||
return;
|
||||
}
|
||||
async getUserInfo(){
|
||||
try{
|
||||
console.log(`Depositing ${this.rechargeAmount} using ${this.selectedpay}`);
|
||||
this.$alert("充值成功", "success");
|
||||
} catch (error) {
|
||||
console.error("充值失败:", error);
|
||||
this.$alert("充值失败,请稍后再试", "danger");
|
||||
const res = await this.$api.getUserInfo();
|
||||
if(res.code != 1000){
|
||||
this.$alert('加载失败','danger')
|
||||
return
|
||||
}
|
||||
this.userInfo = res.data
|
||||
}catch(e){
|
||||
this.$alert('加载失败','danger')
|
||||
console.error(e)
|
||||
}
|
||||
this.rechargeAmount = 0;
|
||||
this.selectedpay = "";
|
||||
},
|
||||
async deposit(){
|
||||
const returnUrl = `${window.location.protocol}//${window.location.host}/paynotice`;
|
||||
try{
|
||||
const res = await this.$api.createPayment(this.selectedpay,this.rechargeAmount,returnUrl);
|
||||
if(!res.success){
|
||||
this.$alert('跳转支付失败','danger')
|
||||
return
|
||||
}
|
||||
window.location.href = res.payUrl
|
||||
}catch(e){
|
||||
this.$alert('跳转支付失败','danger')
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
async created(){
|
||||
await this.getUserInfo()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -186,6 +186,7 @@ export default {
|
||||
auth.clear()
|
||||
this.$alert('登录状态失效,请重新登录...','info')
|
||||
this.$router.push('/auth/login')
|
||||
|
||||
}
|
||||
},watch:{
|
||||
isAdmin:{
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="main-wrapper">
|
||||
|
||||
<div class="row">
|
||||
<div class="col" v-if="isLoaded">
|
||||
<order-data-table title="订单管理" :headers="tableHeaders" :rows="tableData" :data-count="dataCount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OrderDataTable from '@/components/OrderDataTable.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
OrderDataTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataCount: 0,
|
||||
isLoaded: false,
|
||||
tableHeaders: [
|
||||
{ text: "编号", value: "id", width: "155px" },
|
||||
{ text: "用户", value: "userId", width: "214px" },
|
||||
{ text: "订单号", value: "orderNumber", width: "48px" },
|
||||
{ text: "商户订单号", value: "thirdPartyOrderId", width: "82px" },
|
||||
{ text: "金额", value: "amount", width: "103px", type: "money"},
|
||||
{ text: "订单类型", value: "orderType", width: "103px",type:"orderType"},
|
||||
{ text: "订单状态", value: "status", width: "103px",type:"orderStatus"},
|
||||
{ text: "创建时间", value: "createdAt", width: "103px",type:"datetime"},
|
||||
],
|
||||
tableData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async loadOrderList(pageIndex = 1, pageSize = 10, desc = false) {
|
||||
try {
|
||||
const res = await this.$api.getOrderList(pageIndex, pageSize, desc)
|
||||
if (res.code == '1000') {
|
||||
this.tableData = res.data
|
||||
}
|
||||
} catch (e) {
|
||||
this.$alert('订单列表数据加载失败!', 'danger')
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
async pageChangedHandle(newval) {
|
||||
await this.loadUserList(newval.pageIndex, newval.pageSize, false)
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadOrderList()
|
||||
this.dataCount = 100
|
||||
this.isLoaded = true
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="main-wrapper">
|
||||
|
||||
<div class="row">
|
||||
<div class="col" v-if="isLoaded">
|
||||
<DataTable title="套餐管理" :headers="tableHeaders" :rows="tableData" :data-count="dataCount"
|
||||
@pageChanged="pageChangedHandle" @dataDelete="deleteHandle" @dataModify="modifyHandle" @dataAdd="addHandle"
|
||||
/>
|
||||
<package-form-modal title="修改套餐" ref="userModal" />
|
||||
<package-form-modal title="添加套餐" formType="add" ref="addUserModal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DataTable from '@/components/DataTable.vue';
|
||||
import PackageFormModal from '../../components/PackageFormModal.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DataTable,
|
||||
PackageFormModal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataCount: 0,
|
||||
isLoaded: false,
|
||||
tableHeaders: [
|
||||
{ text: "编号", value: "id", width: "155px" },
|
||||
{ text: "套餐名", value: "name", width: "214px" },
|
||||
{ text: "套餐月限额", value: "callLimit", width: "48px" },
|
||||
{ text: "价格", value: "price", width: "29px", type: "money" },
|
||||
{ text: "限速", value: "oneMinuteLimit", width: "82px" },
|
||||
],
|
||||
tableData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async loadPackageList(pageIndex = 1, pageSize = 10, desc = false) {
|
||||
try {
|
||||
const res = await this.$api.getPackageList(pageIndex, pageSize, desc)
|
||||
if (res.code == '1000') {
|
||||
this.tableData = res.data
|
||||
}
|
||||
} catch (e) {
|
||||
this.$alert('套餐列表数据加载失败!', 'danger')
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
async pageChangedHandle(newval) {
|
||||
await this.loadPackageList(newval.pageIndex, newval.pageSize, false)
|
||||
},
|
||||
async deleteHandle(id) {
|
||||
const confirmRes = await this.$confirm('删除', '是否删除套餐?')
|
||||
if (!confirmRes) return;
|
||||
try {
|
||||
const res = await this.$api.deletePackage(id)
|
||||
if (res.code != 1000) {
|
||||
this.$alert(res.message, 'danger')
|
||||
return;
|
||||
}
|
||||
this.$alert('删除成功', 'success')
|
||||
|
||||
} catch (e) {
|
||||
this.$alert(e, 'danger')
|
||||
}
|
||||
},
|
||||
async modifyHandle(id) {
|
||||
try {
|
||||
//加载用户信息到新窗口
|
||||
const packageInfoRes = await this.$api.getPackageInfoById(id)
|
||||
if(packageInfoRes.code != 1000){
|
||||
this.$alert(packageInfoRes.message,'danger')
|
||||
return
|
||||
}
|
||||
//拉起修改弹窗
|
||||
const res = await this.$refs.userModal.open(id,packageInfoRes.data)
|
||||
//弹窗返回为null表示用户关闭了窗口,不执行操作
|
||||
if(res == null) return
|
||||
const modifyRes = await this.$api.updatePackage(id,res)
|
||||
if(modifyRes.code != 1000){
|
||||
this.$alert(modifyRes.message, 'danger')
|
||||
return
|
||||
}
|
||||
this.$alert('修改成功', 'success')
|
||||
|
||||
} catch (e) {
|
||||
this.$alert(e, 'danger')
|
||||
}
|
||||
},
|
||||
async addHandle(){
|
||||
//拉起添加弹窗
|
||||
const res = await this.$refs.addUserModal.open()
|
||||
if(res == null) return
|
||||
try{
|
||||
const modifyRes = await this.$api.addPackage(res)
|
||||
if(modifyRes.code != 1000){
|
||||
this.$alert(modifyRes.message, 'danger')
|
||||
return
|
||||
}
|
||||
this.$alert('添加成功', 'success')
|
||||
|
||||
}catch (e) {
|
||||
this.$alert(e, 'danger')
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadPackageList()
|
||||
this.dataCount = 10
|
||||
this.isLoaded = true
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -4,8 +4,10 @@
|
||||
<div class="row">
|
||||
<div class="col" v-if="isLoaded">
|
||||
<DataTable title="用户管理" :headers="tableHeaders" :rows="tableData" :data-count="dataCount"
|
||||
@pageChanged="pageChangedHandle" @dataDelete="deleteHandle" @dataModify="modifyHandle" />
|
||||
@pageChanged="pageChangedHandle" @dataDelete="deleteHandle" @dataModify="modifyHandle" @dataAdd="addHandle"
|
||||
/>
|
||||
<user-form-modal title="修改用户" ref="userModal" />
|
||||
<user-form-modal title="添加用户" formType="add" ref="addUserModal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,6 +87,22 @@ export default {
|
||||
}
|
||||
this.$alert('修改成功', 'success')
|
||||
|
||||
} catch (e) {
|
||||
this.$alert(e, 'danger')
|
||||
}
|
||||
},
|
||||
async addHandle(){
|
||||
//拉起添加弹窗
|
||||
const res = await this.$refs.addUserModal.open()
|
||||
if(res == null) return
|
||||
try{
|
||||
const modifyRes = await this.$api.addUser(res)
|
||||
if(modifyRes.code != 1000){
|
||||
this.$alert(modifyRes.message, 'danger')
|
||||
return
|
||||
}
|
||||
this.$alert('添加成功', 'success')
|
||||
|
||||
}catch (e) {
|
||||
this.$alert(e, 'danger')
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user