Compare commits

..

2 Commits

13 changed files with 874 additions and 56 deletions

View File

@ -351,7 +351,10 @@ export default {
this.$emit("dataDelete", id); this.$emit("dataDelete", id);
}, },
handleSearch() {}, handleSearch() {},
handleAddUser() {}, handleAddUser() {
this.$emit("dataAdd");
}
,
handleBatchDelete() {}, handleBatchDelete() {},
}, },
watch: { watch: {

View 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 {
//21
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 });
}
//21
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>

View 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>

View File

@ -45,6 +45,7 @@
<script> <script>
export default { export default {
name: 'UserFormModal', name: 'UserFormModal',
props:{ props:{
@ -63,26 +64,29 @@ export default {
form: { form: {
userName: '', userName: '',
email: '', email: '',
balance: '', balance: '0',
password: '' password: ''
}, },
resolve: null resolve: null
}; };
}, },
methods: { methods: {
open(userId,userInfo = null) { open(userId = null,userInfo = null) {
this.resetForm(); this.resetForm();
this.visible = true; this.visible = true;
this.userId = userId; this.userId = userId;
if(userInfo != null){
this.form.email = userInfo.email; this.form.email = userInfo.email;
this.form.userName = userInfo.userName; this.form.userName = userInfo.userName;
this.form.balance = userInfo.balance; this.form.balance = userInfo.balance;
}
return new Promise((resolve) => { return new Promise((resolve) => {
this.resolve = resolve; this.resolve = resolve;
}); });
}, },
submit() { submit() {
this.visible = false; this.visible = false;
this.form.balance = Number(this.form.balance)
this.resolve && this.resolve(this.form); this.resolve && this.resolve(this.form);
}, },
cancel() { cancel() {
@ -93,7 +97,7 @@ export default {
this.form = { this.form = {
userName: '', userName: '',
email: '', email: '',
balance: '', balance: '0',
password: '' password: ''
}; };
} }

View File

@ -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 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列表 //获取api列表
const getApiList = async (pageIndex,pageSize,desc) => await request.get(`/api/apis/ApiList?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`) 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 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 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 { export default {
login, login,
register, register,
@ -63,5 +107,15 @@ export default {
getApiInfoById, getApiInfoById,
updateApiInfo, updateApiInfo,
getPackageList, getPackageList,
updateSystemConfig updateSystemConfig,
payNotice,
createPayment,
addUser,
getUserPackagesAdmin,
deletePackageById,
updatePackage,
addPackage,
getPackageInfoById,
getOrderList,
getMyOrderList
} }

View File

@ -30,6 +30,11 @@ const routes = [
} }
] ]
}, },
{
path: '/paynotice',
name: 'paynotice',
component: () => import('@/views/PayNotice.vue')
},
{ {
path: '/layout', path: '/layout',
component: () => import('@/views/layout/Home.vue'), component: () => import('@/views/layout/Home.vue'),
@ -112,17 +117,6 @@ const routes = [
isHome: false isHome: false
} }
}, },
{
path: 'records',
component: () => import('@/views/layout/Records.vue'),
meta: {
title: '消费记录',
icon: 'archive',
showInMenu: true,
showInUser: true,
isHome: false
}
},
{ {
path: 'system', path: 'system',
component: () => import('@/views/layout/SystemConfig.vue'), component: () => import('@/views/layout/SystemConfig.vue'),

36
src/views/PayNotice.vue Normal file
View 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>

View File

@ -11,7 +11,7 @@
<div class="balance-box"> <div class="balance-box">
<h5 class="balance-text"> <h5 class="balance-text">
<i class="fas fa-wallet balance-icon"></i> <i class="fas fa-wallet balance-icon"></i>
剩余余额<span class="balance-amount">{{ balance }}</span> 剩余余额<span class="balance-amount">{{ userInfo.balance }}</span>
</h5> </h5>
</div> </div>
</div> </div>
@ -36,14 +36,14 @@
<!-- 单选按钮 1 --> <!-- 单选按钮 1 -->
<div <div
class="col-6 d-flex justify-content-center mb-3 option-box" class="col-6 d-flex justify-content-center mb-3 option-box"
:class="{ 'selected-box': selectedpay === 'alipay' }" :class="{ 'selected-box': selectedpay === 0 }"
> >
<input <input
type="radio" type="radio"
id="option1" id="option1"
name="options" name="options"
class="hidden-radio" class="hidden-radio"
value="alipay" :value="0"
v-model="selectedpay" v-model="selectedpay"
/> />
<label for="option1" class="label-style"> <label for="option1" class="label-style">
@ -53,14 +53,14 @@
<!-- 单选按钮 2 --> <!-- 单选按钮 2 -->
<div <div
class="col-6 d-flex justify-content-center mb-3 option-box" class="col-6 d-flex justify-content-center mb-3 option-box"
:class="{ 'selected-box': selectedpay === 'wechat' }" :class="{ 'selected-box': selectedpay === 1 }"
> >
<input <input
type="radio" type="radio"
id="option2" id="option2"
name="options" name="options"
class="hidden-radio" class="hidden-radio"
value="wechat" :value="1"
v-model="selectedpay" v-model="selectedpay"
/> />
<label for="option2" class="label-style"> <label for="option2" class="label-style">
@ -80,53 +80,68 @@
</template> </template>
<script> <script>
import { mapState } from "vuex";
export default { export default {
name: "Balance", name: "Balance",
data() { data() {
return { return {
userInfo:{
balance:0
},
rechargeAmount: 0, rechargeAmount: 0,
selectedpay: "", selectedpay: 0,
}; };
}, },
computed: { computed: {
...mapState("userinfo", {
balance: (state) => (state.user ? state.user.balance : 0),
}),
formattedRechargeAmount: { formattedRechargeAmount: {
get() { 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) { set(val) {
this.rechargeAmount = value === "" ? 0 : Number(value); //
}, const num = parseFloat(val.replace(/,/g, ''));
}, if (!isNaN(num)) {
}, this.rechargeAmount = num;
created() { }
this.$store.dispatch("userinfo/fetchUserInfo"); }
}
}, },
methods: { methods: {
deposit() { async getUserInfo(){
if (this.rechargeAmount <= 0) { try{
this.$alert("充值金额必须大于0", "danger"); const res = await this.$api.getUserInfo();
return; if(res.code != 1000){
this.$alert('加载失败','danger')
return
} }
if (!this.selectedpay) { this.userInfo = res.data
this.$alert("请选择充值方式", "danger"); }catch(e){
return; this.$alert('加载失败','danger')
console.error(e)
} }
try {
console.log(`Depositing ${this.rechargeAmount} using ${this.selectedpay}`);
this.$alert("充值成功", "success");
} catch (error) {
console.error("充值失败:", error);
this.$alert("充值失败,请稍后再试", "danger");
}
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> </script>
<style scoped> <style scoped>

View File

@ -186,6 +186,7 @@ export default {
auth.clear() auth.clear()
this.$alert('登录状态失效,请重新登录...','info') this.$alert('登录状态失效,请重新登录...','info')
this.$router.push('/auth/login') this.$router.push('/auth/login')
} }
},watch:{ },watch:{
isAdmin:{ isAdmin:{

View File

@ -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>

View File

@ -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>

View File

@ -4,8 +4,10 @@
<div class="row"> <div class="row">
<div class="col" v-if="isLoaded"> <div class="col" v-if="isLoaded">
<DataTable title="用户管理" :headers="tableHeaders" :rows="tableData" :data-count="dataCount" <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="修改用户" ref="userModal" />
<user-form-modal title="添加用户" formType="add" ref="addUserModal" />
</div> </div>
</div> </div>
</div> </div>
@ -88,6 +90,22 @@ export default {
} catch (e) { } catch (e) {
this.$alert(e, 'danger') 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')
}
} }
}, },
async mounted() { async mounted() {