Compare commits

..

No commits in common. "29cfc8f1881e51e18f7a88b5c556f841d9db9c8f" and "4856637aa3ddc45cbedda79caa370bc0a0a7febb" have entirely different histories.

13 changed files with 321 additions and 1379 deletions

View File

@ -1,127 +0,0 @@
<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="inputDescription3" class="col-sm-2 col-form-label">接口描述</label>
<div class="col-sm-10">
<input type="text" v-model="form.description" class="form-control" id="inputDescription3">
</div>
</div>
<fieldset class="row mb-3">
<legend class="col-form-label col-sm-2 pt-0">调用方法</legend>
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="radio" name="gridRadios" id="gridRadios1" v-model="form.method" value="0" :checked="form.method == 0 ? true : false">
<label class="form-check-label" for="gridRadios1">
GET
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="gridRadios" id="gridRadios2" v-model="form.method" value="1" :checked="form.method == 1 ? true : false">
<label class="form-check-label" for="gridRadios1">
POST
</label>
</div>
</div>
</fieldset>
<div class="row mb-3">
<label class="visually-hidden" for="PackageSelect">所属套餐</label>
<select class="form-select" id="PackageSelect" v-model="form.packageId">
<option v-for="(item,index) in packageList" :key="index" :value="item.id" :selected="form.packageId == item.id ? true : false">{{item.name}}</option>
</select>
</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: 'ApiFormModal',
props:{
title:{
type:String
},
formType: {
type: String,
default: 'edit'
}
},
data() {
return {
visible: false,
ApiId: -2,
packageList: [],
form: {
name: '',
description: '',
method: '0',
packageId: '0'
},
resolve: null
};
},
methods: {
open(apiId,apiInfo = null,packageList) {
this.resetForm();
this.visible = true;
this.apiId = apiId;
this.form.name = apiInfo.name;
this.form.description = apiInfo.description;
this.form.method = apiInfo.method.toString();
this.form.packageId = apiInfo.packageId.toString();
this.packageList = packageList
return new Promise((resolve) => {
this.resolve = resolve;
});
},
submit() {
this.visible = false;
this.form.method = Number(this.form.method)
this.form.packageId = Number(this.form.packageId)
this.resolve && this.resolve(this.form);
},
cancel() {
this.visible = false;
this.resolve && this.resolve(null);
},
resetForm() {
this.form = {
name: '',
description: '',
method: '0',
packageId: '0'
};
}
}
};
</script>
<style scoped>
.modal {
background: rgba(0, 0, 0, 0.5);
}
.formcontent {
padding: 0 30px;
}
</style>

View File

@ -39,7 +39,7 @@
</div>
</div>
<div class="col-sm-12 col-md-6 text-center">
<button class="btn btn-sm btn-primary ms-2" @click="handleAddDate">
<button class="btn btn-sm btn-primary ms-2" @click="handleAddUser">
添加
</button>
<button class="btn btn-sm btn-danger ms-2" @click="handleBatchDelete">
@ -109,20 +109,6 @@
<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>
</td>
<td>
<button
@ -273,8 +259,6 @@ export default {
pageCount: 0,
//[{text:'1',index:1},.....]
pageBtn: [],
//
callMethod:['GET','POST']
};
},
mounted() {},
@ -351,9 +335,7 @@ export default {
this.$emit("dataDelete", id);
},
handleSearch() {},
handleAddDate() {
this.$emit("dateAdd", {});
},
handleAddUser() {},
handleBatchDelete() {},
},
watch: {

View File

@ -1,159 +0,0 @@
<template>
<div
v-if="visible"
class="modal fade show"
id="packageModal"
tabindex="-1"
aria-labelledby="packageModalLabel"
style="display: block; padding-right: 15px"
aria-modal="true"
role="dialog"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="packageModalTitle">{{ title }}</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="关闭"
@click="cancel"
></button>
</div>
<div class="formcontent">
<form>
<div class="row mb-3">
<label for="packageName" class="col-sm-2 col-form-label">套餐名</label>
<div class="col-sm-10">
<input
type="text"
v-model="form.name"
class="form-control"
id="packageName"
/>
</div>
</div>
<div class="row mb-3">
<label for="packagePrice" class="col-sm-2 col-form-label">价格</label>
<div class="col-sm-10">
<input
type="number"
v-model="form.price"
class="form-control"
id="packagePrice"
/>
</div>
</div>
<div class="row mb-3">
<label for="callLimit" class="col-sm-2 col-form-label">调用次数限制</label>
<div class="col-sm-10">
<input
type="number"
v-model="form.callLimit"
class="form-control"
id="callLimit"
/>
</div>
</div>
<div class="row mb-3">
<label for="oneMinuteLimit" class="col-sm-2 col-form-label"
>一分钟调用限制</label
>
<div class="col-sm-10">
<input
type="number"
v-model="form.oneMinuteLimit"
class="form-control"
id="oneMinuteLimit"
/>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
@click="cancel"
>
关闭
</button>
<button type="button" class="btn btn-primary" @click="submit">保存更改</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "PackageFormModal",
props: {
title: {
type: String,
default: "编辑套餐",
},
},
data() {
return {
visible: false,
packageId: null,
form: {
name: "",
price: "",
callLimit: "",
oneMinuteLimit: "",
},
resolve: null,
};
},
methods: {
open(packageId, packageInfo = null) {
this.resetForm();
this.visible = true;
this.packageId = packageId;
if (packageInfo) {
this.form.name = packageInfo.name;
this.form.price = packageInfo.price;
this.form.callLimit = packageInfo.callLimit;
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: "",
price: "",
callLimit: "",
oneMinuteLimit: "",
};
},
},
};
</script>
<style scoped>
.modal {
background: rgba(0, 0, 0, 0.5);
}
.formcontent {
padding: 0 30px;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style>

View File

@ -28,35 +28,6 @@ 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 getPackageList =async (pageIndex,pageSize,desc)=> await request.get(`api/Package/GetPackageList?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`)
//获取指定套餐信息
const getPackageInfo = async (id) => await request.get(`/api/Package/GetPackageInfo?packageId=${id}`)
//删除指定套餐
const deletePackage = 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)
//获取api列表
const getApiList = async (pageIndex,pageSize,desc) => await request.get(`/api/apis/ApiList?pageIndex=${pageIndex}&pageSize=${pageSize}&desc=${desc}`)
//删除API
const deleteApi = async (id) => await request.delete(`/api/Apis/DeleteApi?apiId=${id}`)
//获取指定API信息
const getApiInfoById = async (id) => await request.get(`/api/Apis/ApiInfo?apiId=${id}`)
//更新API信息
const updateApiInfo = async (id,param) => await request.post(`/api/Apis/UpdateApi?apiId=${id}`,param)
//更新系统配置
const updateSystemConfig = async (configName,configBody) => await request.post('/api/SystemConfig/UpdateSystemConfig',{configName:configName,configBody:configBody})
export default {
login,
register,
@ -67,16 +38,5 @@ export default {
getUserCount,
deleteUser,
getUserInfoById,
updateUserInfo,
getPackageList,
getPackageInfo,
deletePackage,
updatePackage,
addPackage,
deleteApi,
getApiInfoById,
updateApiInfo,
getPackageList,
updateSystemConfig,
getApiList
updateUserInfo
}

View File

@ -1,134 +1,114 @@
<template>
<div class="container">
<div class="row justify-content-md-center">
<div class="col-md-12 col-lg-4">
<div class="card login-box-container">
<div class="card-body">
<div class="authent-logo">
<img src="../../assets/images/logo@2x.png" alt="" />
</div>
<div class="authent-text">
<p>欢迎访问{{ systemname }}!</p>
<p>请登录你的账户.</p>
</div>
<div class="container">
<div class="row justify-content-md-center">
<div class="col-md-12 col-lg-4">
<div class="card login-box-container">
<div class="card-body">
<div class="authent-logo">
<img src="../../assets/images/logo@2x.png" alt="">
</div>
<div class="authent-text">
<p>欢迎访问{{ systemname }}!</p>
<p>请登录你的账户.</p>
</div>
<form>
<div class="mb-3">
<div class="form-floating">
<input
v-model="formdata.username"
type="text"
class="form-control"
id="floatingInput"
placeholder="username"
/>
<label for="floatingInput">用户名</label>
<form>
<div class="mb-3">
<div class="form-floating">
<input v-model="formdata.username" type="text" class="form-control"
id="floatingInput" placeholder="username">
<label for="floatingInput">用户名</label>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input v-model="formdata.password" type="password" class="form-control"
id="floatingPassword" placeholder="Password">
<label for="floatingPassword">密码</label>
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">记住我</label>
</div>
<div class="d-grid">
<button type="button" class="btn btn-info m-b-xs" @click="login">登录</button>
<button class="btn btn-primary">三方登录</button>
</div>
</form>
<div class="authent-reg">
<p>没有账户<router-link to="register">点击创建</router-link></p>
</div>
</div>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input
v-model="formdata.password"
type="password"
class="form-control"
id="floatingPassword"
placeholder="Password"
/>
<label for="floatingPassword">密码</label>
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" />
<label class="form-check-label" for="exampleCheck1">记住我</label>
</div>
<div class="d-grid">
<button type="button" class="btn btn-info m-b-xs" @click="login">
登录
</button>
<button class="btn btn-primary">三方登录</button>
</div>
</form>
<div class="authent-reg">
<p>没有账户<router-link to="register">点击创建</router-link></p>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import md5 from "blueimp-md5";
import { mapGetters } from "vuex";
import auth from "@/utils/auth";
import md5 from 'blueimp-md5';
import { mapGetters } from 'vuex';
import auth from '@/utils/auth';
export default {
data() {
return {
formdata: {
username: "",
password: "",
},
};
},
methods: {
/**
* 用户登录
*/
async login() {
//MD5
const passwordOld = this.formdata.password;
this.formdata.password = md5(passwordOld);
try {
const res = await this.$api.login(this.formdata);
let msg = "";
let type = "danger";
switch (res.code) {
case 2000:
msg = "登录成功";
break;
case 2001:
msg = "用户名或密码错误";
break;
case 2002:
msg = "账户被禁用";
break;
case 2004:
msg = "用户不存在";
break;
default:
msg = "登录失败";
break;
data() {
return {
formdata: {
username: '',
password: ''
}
}
if (res.code == 2000) {
//
auth.setAccessToken(res.data.token);
auth.setRefreshToken(res.data.refreshToken);
auth.setUserId(res.data.userInfo.id);
this.$store.commit("userinfo/SET_USERINFO", res.data.userInfo);
type = "success";
this.$alert(msg, type);
this.$router.push("/layout/index");
} else {
this.$alert(msg, type);
}
} catch (e) {
console.log(e);
this.$alert("未知错误", "error");
} finally {
//
this.formdata.password = passwordOld;
}
},
},
computed: {
/**
* 初始化系统配置
*/
...mapGetters("config", ["systemname"]),
},
};
methods: {
/**
* 用户登录
*/
async login() {
//MD5
const passwordOld = this.formdata.password
this.formdata.password = md5(passwordOld)
try {
const res = await this.$api.login(this.formdata)
let msg = ''
let type = 'danger'
switch (res.code) {
case 2000: msg = '登录成功'; break
case 2001: msg = '用户名或密码错误'; break
case 2002: msg = '账户被禁用'; break
case 2004: msg = '用户不存在'; break
default: msg = '登录失败'; break
}
if (res.code == 2000) {
//
auth.setAccessToken(res.data.token)
auth.setRefreshToken(res.data.refreshToken)
auth.setUserId(res.data.userInfo.id)
this.$store.commit('userinfo/SET_USERINFO', res.data.userInfo)
type = 'success'
this.$alert(msg, type)
this.$router.push('/layout/index')
}else{
this.$alert(msg, type)
}
} catch (e) {
console.log(e)
this.$alert('未知错误', 'error')
} finally {
//
this.formdata.password = passwordOld
}
}
},
computed: {
/**
* 初始化系统配置
*/
...mapGetters('config', ['systemname'])
}
}
</script>
<style scoped></style>
<style scoped></style>

View File

@ -1,251 +1,194 @@
<template>
<div class="login-page" :class="{ 'no-loader': loader }">
<div class="loader">
<div class="spinner-grow text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="container">
<div class="row justify-content-md-center">
<div class="col-md-12 col-lg-4">
<div class="card login-box-container">
<div class="card-body">
<div class="authent-logo">
<img src="../../assets/images/logo@2x.png" alt="" />
</div>
<div class="authent-text">
<p>欢迎访问{{ systemname }}!</p>
<p>此处注册您的账户</p>
</div>
<form>
<div class="mb-3">
<div class="form-floating">
<input
type="text"
class="form-control"
:class="{ 'is-invalid': error.username }"
id="floatingInput"
placeholder="账号"
v-model="form.username"
@blur="verification_username"
/>
<label for="floatingInput">账号</label>
<div class="invalid-feedback" :class="{ 'd-none': !error.username }">
{{ error.username }}
</div>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input
type="email"
class="form-control"
:class="{ 'is-invalid': error.email }"
id="floatingInput1"
placeholder="邮箱地址"
v-model="form.email"
@blur="verification_email"
/>
<label for="floatingInput">邮箱地址</label>
<div class="invalid-feedback" :class="{ 'd-none': !error.email }">
{{ error.email }}
</div>
</div>
</div>
<div class="mb-3">
<div class="input-group">
<div class="form-floating">
<input
type="text"
class="form-control"
:class="{ 'is-invalid': error.validatecode }"
id="floatingPassword"
placeholder="验证码"
v-model="form.validatecode"
@blur="verification_validatecode"
/>
<label for="floatingPassword">验证码</label>
</div>
<button class="btn btn-primary ms-2" type="button" @click="GetCode">
{{ countdown > 0 ? `${countdown}秒后重试` : "获取验证码" }}
</button>
<div
class="invalid-feedback"
:class="{ 'd-none': !error.validatecode }"
>
{{ error.validatecode }}
</div>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input
type="password"
class="form-control"
:class="{ 'is-invalid': error.password }"
id="floatingPassword1"
placeholder="密码"
v-model="form.password"
@blur="verification_password"
/>
<label for="floatingPassword">密码</label>
<div class="invalid-feedback" :class="{ 'd-none': !error.password }">
{{ error.password }}
</div>
</div>
</div>
<div class="mb-3 form-check">
<input
type="checkbox"
class="form-check-input"
id="exampleCheck1"
v-model="form.check"
@blur="verification_check"
/>
<label class="form-check-label" for="exampleCheck1"
>我同意 <a href="#">条款与细则</a></label
>
<div class="invalid-feedback" :class="{ 'd-none': form.check }">
{{ error.agrement }}
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary m-b-xs" @click="submit">
注册
</button>
</div>
</form>
<div class="authent-login">
<p>已经有了账号? <RouterLink to="/login">登录</RouterLink></p>
</div>
<template>
<div class="login-page" :class="{'no-loader':loader}">
<div class='loader'>
<div class='spinner-grow text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<div class="container">
<div class="row justify-content-md-center">
<div class="col-md-12 col-lg-4">
<div class="card login-box-container">
<div class="card-body">
<div class="authent-logo">
<img src="../../assets/images/logo@2x.png" alt="">
</div>
<div class="authent-text">
<p>Welcome to IO!</p>
<p>Enter your details to create your account</p>
</div>
<form>
<div class="mb-3">
<div class="form-floating">
<input type="text" class="form-control" :class="{'is-invalid': error.username}" id="floatingInput" placeholder="账号" v-model="form.username" @blur="verification_username">
<label for="floatingInput">账号</label>
<div class="invalid-feedback" :class="{'d-none': !error.username}">
{{ error.username }}
</div>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input type="email" class="form-control" :class="{'is-invalid': error.email}" id="floatingInput1" placeholder="邮箱地址" v-model="form.email" @blur="verification_email">
<label for="floatingInput">邮箱地址</label>
<div class="invalid-feedback" :class="{'d-none': !error.email}">
{{ error.email }}
</div>
</div>
</div>
<div class="mb-3">
<div class="input-group">
<div class="form-floating">
<input type="text" class="form-control" :class="{'is-invalid': error.validatecode}" id="floatingPassword" placeholder="验证码" v-model="form.validatecode" @blur="verification_validatecode">
<label for="floatingPassword">验证码</label>
</div>
<button class="btn btn-primary ms-2" type="button" @click="GetCode"> {{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}</button>
<div class="invalid-feedback" :class="{'d-none': !error.validatecode}">
{{ error.validatecode }}
</div>
</div>
</div>
<div class="mb-3">
<div class="form-floating">
<input type="password" class="form-control" :class="{'is-invalid': error.password}" id="floatingPassword1" placeholder="密码" v-model="form.password" @blur="verification_password">
<label for="floatingPassword">密码</label>
<div class="invalid-feedback" :class="{'d-none': !error.password}">
{{ error.password }}
</div>
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" v-model="form.check" @blur="verification_check">
<label class="form-check-label" for="exampleCheck1">我同意 <a href="#">条款与细则</a></label>
<div class="invalid-feedback" :class="{'d-none': form.check}">
{{ error.agrement }}
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary m-b-xs" @click="submit">注册</button>
</div>
</form>
<div class="authent-login">
<p>已经有了账号? <RouterLink to="/login">登录</RouterLink></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { SendValidateCode_api,registered_api } from '@/request/api'
export default {
name: "Register",
data() {
return {
loader: false,
form: {
username: "",
password: "",
validatecode: "",
email: "",
check: false,
},
error: {
username: "",
password: "",
validatecode: "",
email: "",
agrement: "",
},
countdown: 0,
};
},
mounted() {
this.loader = true;
},
computed: {
/**
* 初始化系统配置
*/
...mapGetters("config", ["systemname"]),
},
methods: {
verification_username() {
if (!this.form.username || this.form.username.length > 20) {
this.error.username = "账号不能为空或超过20个字符";
} else {
this.error.username = "";
}
},
verification_email() {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!this.form.email) {
this.error.email = "邮箱不能为空";
} else if (!emailPattern.test(this.form.email)) {
this.error.email = "邮箱格式不正确";
} else {
this.error.email = "";
}
},
verification_password() {
if (!this.form.password || this.form.password.length < 6) {
this.error.password = "密码不能为空或小于6个字符";
} else {
this.error.password = "";
}
},
verification_validatecode() {
if (!this.form.validatecode || this.form.validatecode.length != 5) {
this.error.validatecode = "验证码错误";
} else {
this.error.validatecode = "";
}
},
verification_check() {
if (!this.form.check) {
this.error.agrement = "请同意条款与细则";
} else {
this.error.agrement = "";
}
},
async GetCode() {
this.verification_email();
if (!this.error.email) {
let res = await this.$api.SendValidateCode(this.form.email);
this.countdown = 60;
this.startCountdown();
}
},
startCountdown() {
const timer = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
} else {
clearInterval(timer);
name: 'Register',
data() {
return {
loader:false,
form:{
username: '',
password: '',
validatecode: '',
email: '',
check: false,
},
error: {
username: '',
password: '',
validatecode: '',
email: '',
agrement :''
},
countdown: 0
}
}, 1000);
},
async submit() {
this.verification_username();
this.verification_email();
this.verification_password();
this.verification_validatecode();
this.verification_check();
if (
!this.error.username &&
!this.error.email &&
!this.error.password &&
!this.error.validatecode &&
!this.error.agrement
) {
let res = await this.$api.register({
username: this.form.username,
password: this.form.password,
email: this.form.email,
verificationCode: this.form.validatecode,
});
if (res.code == 1000) {
this.$router.push("/login");
mounted() {
this.loader=true
},
methods: {
verification_username() {
if (!this.form.username || this.form.username.length >20) {
this.error.username = '账号不能为空或超过20个字符'
}else {
this.error.username = ''
}
},
verification_email() {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!this.form.email) {
this.error.email = '邮箱不能为空'
}else if (!emailPattern.test(this.form.email)) {
this.error.email = '邮箱格式不正确'
}else {
this.error.email = ''
}
},
verification_password() {
if (!this.form.password || this.form.password.length < 6) {
this.error.password = '密码不能为空或小于6个字符'
}else {
this.error.password = ''
}
},
verification_validatecode() {
if (!this.form.validatecode || this.form.validatecode.length != 5) {
this.error.validatecode = '验证码错误'
}else {
this.error.validatecode = ''
}
},
verification_check() {
if (!this.form.check) {
this.error.agrement = '请同意条款与细则'
}else {
this.error.agrement = ''
}
},
async GetCode() {
this.verification_email()
if (!this.error.email) {
let res=await this.$api.SendValidateCode(this.form.email)
this.countdown = 60
this.startCountdown()
}
},
startCountdown() {
const timer = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
} else {
clearInterval(timer);
}
}, 1000)
},
async submit() {
this.verification_username()
this.verification_email()
this.verification_password()
this.verification_validatecode()
this.verification_check()
if (!this.error.username && !this.error.email && !this.error.password && !this.error.validatecode && !this.error.agrement) {
let res=await this.$api.register({
username: this.form.username,
password: this.form.password,
email: this.form.email,
verificationCode: this.form.validatecode
})
if (res.code == 1000) {
this.$router.push('/login')
}
}
}
}
}
}
},
},
};
</script>
<style scoped>
.invalid-feedback {
display: block !important;
display: block !important;
}
</style>
</style>

View File

@ -6,11 +6,7 @@
<DataTable title="API管理"
:headers="tableHeaders"
:rows="tableData"
:data-count="dataCount"
@pageChanged="pageChangedHandle"
@dataDelete="deleteHandle"
@dataModify="modifyHandle" />
<api-form-modal title="修改接口" ref="apiModal" />
:data-count="dataCount" />
</div>
</div>
</div>
@ -18,104 +14,27 @@
<script>
import DataTable from '@/components/DataTable.vue';
import ApiFormModal from '../../components/ApiFormModal.vue';
export default {
name: "APIs",
components: {
DataTable,
ApiFormModal
DataTable
},
data() {
return {
isLoaded: false,
packageList: [],
tableHeaders: [
{ text: "编号", value: "id", width: "100px" },
{ text: "名称", value: "name", width: "100px" },
{ text: "描述", value: "description", width: "100px" },
{ text: "路径", value: "endpoint", width: "100px" },
{ text: "调用方法", value: "method", width: "100px", type: "method" },
{ text: "状态", value: "isactive", width: "100px", type: "bool" },
{ text: "所属套餐", value: "packageId", width: "100px", type: "find", findProperty: "id", findValue: [] },
{ text: "", value: "", width: "" }
],
tableData: [],
dataCount: 0
}
},
methods: {
async loadApiList(pageIndex = 1, pageSize = 10, desc = false) {
try {
const res = await this.$api.getApiList(pageIndex, pageSize, desc)
if (res.code == '1000') {
this.tableData = res.data
}
} catch (e) {
this.$alert('API列表数据加载失败!', 'danger')
console.error(e)
}
},
async pageChangedHandle(newval) {
await this.loadApiList(newval.pageIndex, newval.pageSize, false)
},
async modifyHandle(id) {
try {
//API
const apiinfoRes = await this.$api.getApiInfoById(id)
if (apiinfoRes.code != 1000) {
this.$alert(apiinfoRes.message, 'danger')
return
}
//
const res = await this.$refs.apiModal.open(id, apiinfoRes.data, this.packageList)
//null
if (res == null) return
const modifyRes = await this.$api.updateApiInfo(id, res)
if (modifyRes.code != 1000) {
this.$alert(modifyRes.message, 'danger')
return
}
this.$alert('修改成功', 'success')
} catch (e) {
this.$alert(e, 'danger')
}
},
async deleteHandle(id) {
const confirmRes = await this.$confirm('删除', '是否删除API')
if (!confirmRes) return;
try {
const res = await this.$api.deleteApi(id)
if (res.code != 1000) {
this.$alert(res.message, 'danger')
return;
}
this.$alert('删除成功', 'success')
} catch (e) {
this.$alert(e, 'danger')
}
},
async loadPackageList(pageIndex = 1, pageSize = 10, desc = false) {
//
try{
const packageRes = await this.$api.getPackageList(1, 1000, false)
if (packageRes.code != 1000) {
this.$alert(packageRes.message, 'danger')
}
this.packageList = packageRes.data
}catch(e){
this.$alert('加载套餐列表失败!', 'danger')
console.error(e)
}
}
},
async mounted() {
await this.loadApiList()
await this.loadPackageList()
this.tableHeaders.find(x => x.value == 'packageId').findValue = this.packageList
mounted(){
this.isLoaded = true
}
}

View File

@ -1,6 +1,5 @@
<template>
<div class="main-wrapper">
<div class="row justify-content-center">
<div class="row justify-content-center mt-5">
<div class="card custom-card">
<div class="card-header text-center">
<h3 class="card-title">充值中心</h3>
@ -76,7 +75,6 @@
</div>
</div>
</div>
</div>
</template>
<script>

View File

@ -1,64 +0,0 @@
<template>
<div class="main-wrapper">
<div class="row">
<div class="col">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col m-b-sm" v-for="(item,index) in packageList" :key="index">
<ul class="list-group io-pricing-table">
<li class="list-group-item">
<h3>{{ item.name }}</h3>
</li>
<li class="list-group-item">每分钟调用次数限制{{ item.oneMinuteLimit }} </li>
<li class="list-group-item">周期总调用次数{{ item.callLimit }} </li>
<li class="list-group-item">
<h3>{{ item.price }}</h3>
<span>每月</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-primary">购买</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'BuyPackage',
data(){
return {
packageList: []
}
},
methods: {
//
async loadPackageList(){
try{
const res = await this.$api.getPackageList(1,100,false)
if(res.code != 1000){
this.$alert(res.message,'danger')
return
}
this.packageList = res.data
return
}catch(e){
this.$alert('加载套餐列表失败!','danger')
console.error('套餐列表加载失败:',e)
}
}
},
async mounted(){
await this.loadPackageList()
}
}
</script>

View File

@ -1,118 +0,0 @@
<template>
<div class="main-wrapper">
<div class="row">
<div class="col" v-if="isLoaded">
<DataTable
title="套餐管理"
:headers="tableHeaders"
:rows="tableData"
:data-count="tableData.length"
@pageChanged="pageChangedHandle"
@dataDelete="deleteHandle"
@dataModify="modifyHandle"
@dateAdd="addHandle"
/>
<PackageFormModal ref="packageFormModal" :title="message" />
</div>
</div>
</div>
</template>
<script>
import DataTable from "@/components/DataTable.vue";
import PackageFormModal from "@/components/PackageFormModal.vue";
export default {
components: {
DataTable,
PackageFormModal,
},
data() {
return {
message: "",
dataCount: 0,
isLoaded: false,
tableHeaders: [
{ text: "编号", value: "id", width: "155px" },
{ text: "套餐名", value: "name", width: "214px" },
{ text: "价格", value: "price", width: "82px" },
{ text: "调用次数限制", value: "callLimit", width: "103px" },
{ text: "一分钟调用限制", value: "oneMinuteLimit", width: "300px" },
],
tableData: [],
};
},
methods: {
async loadPackesList(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.loadPackesList(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 {
//
this.message = "修改套餐";
const userinfoRes = await this.$api.getPackageInfo(id);
if (userinfoRes.code != 1000) {
this.$alert(userinfoRes.message, "danger");
return;
}
//
const res = await this.$refs.packageFormModal.open(id, userinfoRes.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() {
try {
this.message = "添加套餐";
const res = await this.$refs.packageFormModal.open(null);
//null
if (res == null) return;
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");
}
},
},
mounted() {
this.isLoaded = true;
this.loadPackesList();
},
};
</script>

View File

@ -1,186 +0,0 @@
<template>
<div class="main-wrapper">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm border-0 mt-4">
<div class="card-header bg-gradient text-white py-4">
<h4 class="mb-0">个人中心</h4>
<p class="mb-0 small">管理您的账户信息与安全设置</p>
</div>
<div class="card-body">
<!-- 用户头像 -->
<div class="text-center mb-4">
<img :src="user.avatar" class="rounded-circle border" width="100" height="100" />
<div class="mt-2">
<button class="btn btn-outline-primary btn-sm" @click="editingSection = 'avatar'">修改头像</button>
</div>
</div>
<!-- 用户信息列表 -->
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>昵称</strong>{{ user.nickname }}</span>
<button class="btn btn-link" @click="openEdit('nickname')">修改</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>邮箱</strong>{{ user.email }}</span>
<button class="btn btn-link" @click="openEdit('email')">修改</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>手机号</strong>{{ user.phone }}</span>
<button class="btn btn-link" @click="openEdit('phone')">修改</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>性别</strong>{{ getGenderLabel(user.gender) }}</span>
<button class="btn btn-link" @click="openEdit('gender')">修改</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>个人简介</strong>{{ user.bio || '未填写' }}</span>
<button class="btn btn-link" @click="openEdit('bio')">修改</button>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span><strong>登录密码</strong>********</span>
<button class="btn btn-link" @click="openEdit('password')">修改</button>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 弹出框 -->
<div v-if="editingSection" class="modal fade show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">修改 {{ getSectionTitle(editingSection) }}</h5>
<button type="button" class="btn-close" @click="closeEdit"></button>
</div>
<div class="modal-body">
<!-- 各字段弹出表单内容 -->
<div v-if="editingSection === 'nickname'">
<input type="text" class="form-control" v-model="form.nickname" placeholder="请输入昵称" />
</div>
<div v-else-if="editingSection === 'email'">
<input type="email" class="form-control" v-model="form.email" placeholder="请输入邮箱" />
</div>
<div v-else-if="editingSection === 'phone'">
<input type="text" class="form-control" v-model="form.phone" placeholder="请输入手机号" />
</div>
<div v-else-if="editingSection === 'gender'">
<select class="form-control" v-model="form.gender">
<option value="male"></option>
<option value="female"></option>
<option value="other">其他</option>
</select>
</div>
<div v-else-if="editingSection === 'bio'">
<textarea class="form-control" rows="3" v-model="form.bio" placeholder="简单介绍一下你自己"></textarea>
</div>
<div v-else-if="editingSection === 'password'">
<input type="password" class="form-control mb-2" v-model="form.oldPassword" placeholder="当前密码" />
<input type="password" class="form-control mb-2" v-model="form.newPassword" placeholder="新密码" />
<input type="password" class="form-control" v-model="form.confirmPassword" placeholder="确认新密码" />
<div class="text-danger mt-1" v-if="form.newPassword !== form.confirmPassword">两次密码不一致</div>
</div>
<div v-else-if="editingSection === 'avatar'">
<input type="file" class="form-control" @change="onAvatarChange" accept="image/*" />
<img :src="previewAvatar" class="mt-3 rounded-circle" width="80" v-if="previewAvatar" />
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="closeEdit">取消</button>
<button class="btn btn-primary" @click="saveEdit">保存</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "UserProfilePanel",
data() {
return {
user: {
avatar: "https://via.placeholder.com/100",
nickname: "张三",
email: "zhangsan@example.com",
phone: "13800000000",
gender: "male",
bio: "热爱开源,热爱技术"
},
editingSection: null,
form: {},
previewAvatar: null
};
},
methods: {
openEdit(section) {
this.editingSection = section;
this.form = { ...this.user }; // clone
},
closeEdit() {
this.editingSection = null;
this.previewAvatar = null;
},
saveEdit() {
if (this.editingSection === 'password') {
if (this.form.newPassword !== this.form.confirmPassword) {
return;
}
//
this.$alert && this.$alert("密码已修改", "success");
} else if (this.editingSection === 'avatar') {
if (this.previewAvatar) {
this.user.avatar = this.previewAvatar;
}
} else {
Object.assign(this.user, this.form);
}
this.closeEdit();
},
getGenderLabel(value) {
return value === 'male' ? '男' : value === 'female' ? '女' : '其他';
},
getSectionTitle(section) {
const map = {
nickname: "昵称",
email: "邮箱",
phone: "手机号",
gender: "性别",
bio: "个人简介",
password: "密码",
avatar: "头像"
};
return map[section] || "信息";
},
onAvatarChange(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
this.previewAvatar = event.target.result;
};
reader.readAsDataURL(file);
}
}
};
</script>
<style scoped>
.bg-gradient {
background: linear-gradient(to right, #4e73df, #1cc88a);
}
.modal {
z-index: 1050;
}
.btn-close {
background: none;
border: none;
font-size: 1.2rem;
}
</style>

View File

@ -1,182 +0,0 @@
<template>
<div class="main-wrapper">
<div class="row">
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title">系统设置</h5>
<p class="card-description">在此页面中配置系统的基本参数</p>
<form>
<!-- 系统名称 -->
<div class="mb-3">
<label for="systemName" class="form-label">系统名称</label>
<input type="text" class="form-control" id="systemName" v-model="systemName"
placeholder="请输入系统名称">
</div>
<!-- 管理员邮箱 -->
<div class="mb-3">
<label for="adminEmail" class="form-label">管理员邮箱</label>
<input type="email" v-model="systemEmail" class="form-control" id="adminEmail"
aria-describedby="emailHelp" placeholder="admin@example.com">
<div id="emailHelp" class="form-text">我们将在网站显示此邮箱</div>
</div>
<!-- 管理员手机号 -->
<div class="mb-3">
<label for="adminPhone" class="form-label">管理员手机号</label>
<input type="text" v-model="systemPhone" class="form-control" id="adminPhone"
aria-describedby="PhoneHelp" placeholder="13800000000">
<div id="PhoneHelp" class="form-text">我们将在网站显示此邮箱</div>
</div>
<!-- 系统描述 -->
<div class="mb-3">
<label for="adminDescription" class="form-label">系统描述</label>
<textarea class="form-control" v-model="systemDescription"
aria-label="With textarea"></textarea>
</div>
<!--网站LOGO-->
<div class="mb-3">
<label for="formFile" class="form-label">网站LOGO</label>
<input class="form-control" type="file" id="formFile" accept="image/*">
</div>
<!--网站Favorite-->
<div class="mb-3">
<label for="formFile" class="form-label">网站Favorite</label>
<input class="form-control" type="file" id="formFile" accept="image/*">
</div>
<!-- 启用用户注册 -->
<div class="mb-3 form-check">
<input type="checkbox" v-model="enableSystemRegister" class="form-check-input" id="enableRegistration">
<label class="form-check-label" for="enableRegistration">启用用户注册功能</label>
</div>
<!-- 启用注册邮箱验证 -->
<div class="mb-3 form-check">
<input type="checkbox" v-model="enableSystemRegisterEmailValidate" class="form-check-input" id="enableRegistrationValidate">
<label class="form-check-label" for="enableRegistrationValidate">启用用户注册邮箱验证</label>
</div>
<!-- 提交按钮 -->
<button type="button" class="btn btn-primary" @click="submit">保存设置</button>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SystemConfig",
data() {
return {
systemConfig: []
}
},
methods: {
async submit() {
for (const item of this.systemConfig) {
const configName = item.configName
const configBody = item.configBody
try {
const res = await this.$api.updateSystemConfig(configName, configBody)
if(res.code != 1000) this.$alert(res.message,'danger')
} catch (err) {
this.$alert('更新配置失败','danger')
console.error(`更新 ${configName} 失败`, err)
}
}
//
this.$alert('系统配置已保存','success')
}
},
computed: {
systemName: {
get() {
const systemName = this.systemConfig.find(x => x.configName == 'SystemName')
return systemName ? systemName.configBody : ''
},
set(newValue) {
const systemName = this.systemConfig.find(x => x.configName == 'SystemName')
if (systemName) {
systemName.configBody = newValue
}
}
},
systemEmail: {
get() {
const item = this.systemConfig.find(x => x.configName == 'Email')
return item ? item.configBody : ''
},
set(newValue) {
const item = this.systemConfig.find(x => x.configName == 'Email')
if (item) {
item.configBody = newValue
}
}
},
systemPhone: {
get() {
const item = this.systemConfig.find(x => x.configName == 'Phone')
return item ? item.configBody : ''
},
set(newValue) {
const item = this.systemConfig.find(x => x.configName == 'Phone')
if (item) {
item.configBody = newValue
}
}
},
systemDescription: {
get() {
const item = this.systemConfig.find(x => x.configName == 'SystemDescription')
return item ? item.configBody : ''
},
set(newValue) {
const item = this.systemConfig.find(x => x.configName == 'SystemDescription')
if (item) {
item.configBody = newValue
}
}
},
enableSystemRegister:{
get(){
const item = this.systemConfig.find(x => x.configName == 'RegisterConfig')
return item ? JSON.parse(item.configBody).RegisterOn : false
},
set(newValue){
const item = this.systemConfig.find(x => x.configName == 'RegisterConfig')
if (item) {
let jsonBody = JSON.parse(item.configBody)
jsonBody.RegisterOn = newValue
item.configBody = JSON.stringify(jsonBody)
}
}
},
enableSystemRegisterEmailValidate:{
get(){
const item = this.systemConfig.find(x => x.configName == 'RegisterConfig')
return item ? JSON.parse(item.configBody).Emailvalidate : false
},
set(newValue){
const item = this.systemConfig.find(x => x.configName == 'RegisterConfig')
if (item) {
let jsonBody = JSON.parse(item.configBody)
jsonBody.Emailvalidate = newValue
item.configBody = JSON.stringify(jsonBody)
}
}
}
},
created() {
this.systemConfig = this.$store.state.config.systemconfig
}
}
</script>

View File

@ -1,16 +1,10 @@
<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"
/>
<DataTable title="用户管理" :headers="tableHeaders" :rows="tableData" :data-count="dataCount"
@pageChanged="pageChangedHandle" @dataDelete="deleteHandle" @dataModify="modifyHandle" />
<user-form-modal title="修改用户" ref="userModal" />
</div>
</div>
@ -18,13 +12,13 @@
</template>
<script>
import DataTable from "@/components/DataTable.vue";
import UserFormModal from "../../components/UserFormModal.vue";
import DataTable from '@/components/DataTable.vue';
import UserFormModal from '../../components/UserFormModal.vue';
export default {
components: {
DataTable,
UserFormModal,
UserFormModal
},
data() {
return {
@ -37,7 +31,7 @@ export default {
{ text: "余额", value: "balance", width: "29px", type: "money" },
{ text: "状态", value: "isBan", width: "82px", type: "bool" },
{ text: "角色", value: "roles", width: "103px", type: "arrObj", child: "role" },
{ text: "创建时间", value: "created", width: "103px", type: "datetime" },
{ text: "创建时间", value: "created", width: "103px", type: "datetime" }
],
tableData: [],
};
@ -45,59 +39,61 @@ export default {
methods: {
async loadUserList(pageIndex = 1, pageSize = 10, desc = false) {
try {
const res = await this.$api.getUserList(pageIndex, pageSize, desc);
if (res.code == "1000") {
this.tableData = res.data;
const res = await this.$api.getUserList(pageIndex, pageSize, desc)
if (res.code == '1000') {
this.tableData = res.data
}
} catch (e) {
this.$alert("用户列表数据加载失败!", "danger");
console.error(e);
this.$alert('用户列表数据加载失败!', 'danger')
console.error(e)
}
},
async pageChangedHandle(newval) {
await this.loadUserList(newval.pageIndex, newval.pageSize, false);
await this.loadUserList(newval.pageIndex, newval.pageSize, false)
},
async deleteHandle(id) {
const confirmRes = await this.$confirm("删除", "是否删除用户?");
const confirmRes = await this.$confirm('删除', '是否删除用户?')
if (!confirmRes) return;
try {
const res = await this.$api.deleteUser(id);
const res = await this.$api.deleteUser(id)
if (res.code != 1000) {
this.$alert(res.message, "danger");
this.$alert(res.message, 'danger')
return;
}
this.$alert("删除成功", "success");
this.$alert('删除成功', 'success')
} catch (e) {
this.$alert(e, "danger");
this.$alert(e, 'danger')
}
},
async modifyHandle(id) {
try {
//
const userinfoRes = await this.$api.getUserInfoById(id);
if (userinfoRes.code != 1000) {
this.$alert(userinfoRes.message, "danger");
return;
const userinfoRes = await this.$api.getUserInfoById(id)
if(userinfoRes.code != 1000){
this.$alert(userinfoRes.message,'danger')
return
}
//
const res = await this.$refs.userModal.open(id, userinfoRes.data);
const res = await this.$refs.userModal.open(id,userinfoRes.data)
//null
if (res == null) return;
const modifyRes = await this.$api.updateUserInfo(id, res);
if (modifyRes.code != 1000) {
this.$alert(modifyRes.message, "danger");
return;
if(res == null) return
const modifyRes = await this.$api.updateUserInfo(id,res)
if(modifyRes.code != 1000){
this.$alert(modifyRes.message, 'danger')
return
}
this.$alert("修改成功", "success");
this.$alert('修改成功', 'success')
} catch (e) {
this.$alert(e, "danger");
this.$alert(e, 'danger')
}
},
}
},
async mounted() {
await this.loadUserList();
this.dataCount = (await this.$api.getUserCount()).data;
this.isLoaded = true;
},
await this.loadUserList()
this.dataCount = (await this.$api.getUserCount()).data
this.isLoaded = true
}
};
</script>