Commit 6f366395 authored by hangjun83's avatar hangjun83

前端更新

parent af574bbc
// 统一请求路径前缀在libs/axios.js中修改
import { getRequest, getNoAuthRequest, postNoAuthRequest, postRequest, putRequest } from '@/libs/axios';
// 认证
export const siteInfo = (id, params) => {
return getNoAuthRequest('/oauth2/info/' + id, params)
}
// 认证
export const authorize = (params) => {
return postNoAuthRequest('/oauth2/authorize', params)
}
// 认证过
export const authorized = (params) => {
return postRequest('/oauth2/authorized', params)
}
// 获取token
export const token = (params) => {
return getNoAuthRequest('/oauth2/token', params)
}
// 获取随机secretKey
export const getSecretKey = (params) => {
return getRequest('/client/getSecretKey', params)
}
// 获取客户端
export const getClientDataList = (params) => {
return getRequest('/client/getByCondition', params)
}
// 添加客户端
export const addClient = (params) => {
return postRequest('/client/save', params)
}
// 编辑客户端
export const updateClient = (params) => {
return putRequest('/client/update', params)
}
// 删除客户端
export const deleteClient = (params) => {
return postRequest('/client/delByIds', params)
}
\ No newline at end of file
......@@ -28,14 +28,14 @@ export const loginRouter = {
component: () => import('@/views/regist-result.vue')
};*/
export const authorizeRouter = {
/*export const authorizeRouter = {
path: '/authorize',
name: 'authorize',
meta: {
title: 'XBoot统一认证平台 - X-Boot前后端分离开发平台 '
},
component: () => import('@/views/authorize.vue')
};
};*/
// export const page404 = {
// path: '/*',
......@@ -83,7 +83,6 @@ export const appRouter = [];
// 所有上面定义的路由都要写在下面的routers里
export const routers = [
loginRouter,
authorizeRouter,
otherRouter,
...appRouter,
page500,
......
......@@ -45,11 +45,7 @@
<div class="header-left">
<!-- 固定图标 -->
<div v-if="fixNav && showLogo" style="width: 220px" class="fix-logo">
<img
src="@/assets/logo-black.png"
v-if="navTheme == 'light' && mainTheme != 'darkMode'"
/>
<img src="@/assets/logo-white.png" key="max-logo" v-else />
<span style='font-size:22px;font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;'>System</span>
</div>
<!-- 收缩图标 -->
<div
......
.authorize {
height: 100%;
background: url('../assets/background.svg');
background-color: #f0f2f5;
.other-thing {
margin-top: 3vh;
}
.ivu-tabs-nav-container {
line-height: 2;
font-size: 17px;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
position: relative;
zoom: 1;
}
.form {
padding-top: 1vh;
.input-verify {
width: 70%;
}
}
.code-image {
.ivu-spin-fix .ivu-spin-main {
height: 20px;
}
}
.back,
.forget-pass,
.other-way {
font-size: 14px;
}
.icons {
display: flex;
align-items: center;
}
.other-icon {
cursor: pointer;
margin-left: 10px;
display: flex;
align-items: center;
color: rgba(0, 0, 0, .2);
:hover {
color: #2d8cf0;
}
}
.layout {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}
.logos-wrap {
margin-top: 8vh;
margin-bottom: 5vh;
display: flex;
flex-direction: column;
align-items: center;
.logos {
width: 300px;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
.site-logo {
box-shadow: 0 1px 5px rgba(27, 31, 35, .15);
}
.top {
z-index: 1;
}
.line {
position: absolute;
top: 50%;
left: 0;
width: 100%;
content: "";
border-bottom: 2px dashed #e1e4e8;
}
}
.auth-title {
color: #24292e;
font-size: 24px;
font-weight: 400;
margin-top: 20px;
}
}
.auth-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
.auth-info-wrap {
width: 100%;
border-bottom: 1px solid #e1e4e8;
padding: 24px;
.auth-detail {
height: 40px;
display: flex;
align-items: center;
.auth-pic {
margin-right: 16px;
}
.auth-detail-href {
font-weight: 500;
}
.auth-detail-title {
font-weight: 500;
color: #24292e;
}
.auth-detail-sub-title {
font-size: 12px;
color: #586069
}
.auth-detail-strong {
font-weight: 500;
}
}
}
.button-confirm {
width: 100%;
padding: 0 24px;
margin-top: 24px;
}
.to-wrap {
display: flex;
flex-direction: column;
align-items: center;
font-size: 12px;
margin: 16px 0 24px 0;
color: #586069;
}
.to-strong {
font-size: 12px;
color: #24292e;
font-weight: 600;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
}
}
}
\ No newline at end of file
<template>
<div class="authorize">
<Row
type="flex"
justify="center"
align="middle"
@keydown.enter.native="submit"
style="height: 100%"
>
<Col class="content" :style="{ width: userInfo ? '450px' : '390px' }">
<div>
<div class="logos-wrap">
<div class="logos">
<Avatar
:src="site.logo"
:style="{ background: '#fff' }"
size="96"
class="top site-logo"
/>
<Icon
type="ios-checkmark-circle"
color="#52c41a"
size="32"
class="top"
></Icon>
<Avatar
:src="require('@/assets/logo-min.png')"
:style="{ background: '#f1f2f5' }"
size="96"
class="top"
/>
<div class="line"></div>
</div>
<div class="auth-title">{{ $t("authorize") }} {{ site.name }}</div>
</div>
<div v-if="!error && !authLoading && !userInfo">
<Tabs value="1">
<TabPane :label="$t('sso')" name="1" icon="md-people">
<Form ref="loginForm" :model="form" :rules="rules" class="form">
<FormItem prop="username">
<Input
v-model="form.username"
prefix="ios-contact"
size="large"
clearable
placeholder="账号/邮箱/手机号"
autocomplete="off"
/>
</FormItem>
<FormItem prop="password">
<Input
type="password"
v-model="form.password"
prefix="ios-lock"
size="large"
clearable
placeholder="请输入密码"
autocomplete="off"
/>
</FormItem>
<FormItem prop="code">
<Row
type="flex"
justify="space-between"
style="align-items: center; overflow: hidden"
>
<Input
v-model="form.code"
size="large"
clearable
placeholder="请输入图片验证码"
:maxlength="10"
style="width: 67%"
/>
<div
class="code-image"
style="position: relative; font-size: 12px"
>
<Spin v-if="loadingCaptcha" fix></Spin>
<img
:src="captchaImg"
@click="getCaptchaImg"
alt="加载验证码失败"
style="width: 110px; cursor: pointer; display: block"
/>
</div>
</Row>
</FormItem>
</Form>
</TabPane>
</Tabs>
<Row>
<Button
type="primary"
size="large"
:loading="loading"
@click="submit"
long
>
<span v-if="!loading">{{ $t("authorizeAndSignin") }}</span>
<span v-else>{{ $t("authorizing") }}</span>
</Button>
</Row>
<Row type="flex" justify="space-between" class="other-thing">
<router-link to="/reset" class="back">{{
$t("forgetPass")
}}</router-link>
<router-link to="/regist" class="back">
{{ $t("registerNow") }}
</router-link>
</Row>
</div>
<div v-if="!error && !authLoading && userInfo">
<Card dis-hover :padding="0" v-if="!error">
<div class="auth-card">
<div class="auth-info-wrap">
<div class="auth-detail" style="margin-bottom: 25px">
<Avatar
:src="userInfo.avatar"
:style="{ background: '#fff' }"
size="40"
class="auth-pic"
/>
<div>
<a
:href="site.homeUri"
target="_blank"
class="auth-detail-href"
>{{ site.name }}</a
>
<div class="auth-detail-sub-title">
{{ $t("wants") }}
<span class="auth-detail-strong">{{
userInfo.username
}}</span>
{{ $t("wants2") }}
</div>
</div>
</div>
<div class="auth-detail" style="margin-bottom: 15px">
<Icon
type="md-person"
color="#6a737d"
size="40"
class="auth-pic"
></Icon>
<div>
<div class="auth-detail-title">
{{ $t("authAquire") }}
</div>
<div class="auth-detail-sub-title">
{{ $t("aquireInfo") }}
</div>
</div>
</div>
</div>
<Row class="button-confirm">
<Button
type="primary"
size="large"
:loading="loading"
@click="confirm"
long
>
<span v-if="!loading">{{ $t("authorize") }}</span>
<span v-else>{{ $t("authorizing") }}</span>
</Button>
</Row>
<Row class="to-wrap">
<div>{{ $t("afterAuth") }}</div>
<div class="to-strong">{{ site.homeUri }}</div>
</Row>
</div>
</Card>
</div>
<div v-if="error && !authLoading" style="margin-top: 15vh">
<Alert type="error" show-icon>
{{ title }}
<span slot="desc">{{ msg }}</span>
</Alert>
</div>
<div v-if="authLoading">
<RectLoading />
</div>
</div>
<Footer />
</Col>
<LangSwitch />
</Row>
</div>
</template>
<script>
import Cookies from "js-cookie";
import { initCaptcha, drawCodeImage, userInfo } from "@/api/index";
import { siteInfo, authorize, authorized } from "@/api/open";
import Footer from "@/views/main-components/footer";
import LangSwitch from "@/views/main-components/lang-switch";
import RectLoading from "@/views/my-components/xboot/rect-loading";
export default {
components: {
LangSwitch,
Footer,
RectLoading,
},
data() {
return {
authLoading: false,
title: "",
msg: "",
error: false,
loadingCaptcha: true,
captchaImg: "",
loading: false,
userInfo: {},
site: {
name: "",
homeUri: "",
logo: "",
autoApprove: false,
},
form: {
username: "",
password: "",
code: "",
client_id: "",
redirect_uri: "",
state: "",
response_type: "",
captchaId: this.captchaId,
},
rules: {
username: [
{
required: true,
message: "账号不能为空",
trigger: "change",
},
],
password: [
{
required: true,
message: "密码不能为空",
trigger: "change",
},
],
code: [
{
required: true,
message: "验证码不能为空",
trigger: "change",
},
],
},
};
},
methods: {
init() {
let q = this.$route.query;
if (!q.client_id) {
this.title = "参数client_id非法";
this.msg = "The parameter client_id is illegal.";
this.error = true;
return;
}
if (!q.redirect_uri) {
this.title = "参数redirect_uri非法";
this.msg = "The parameter redirect_uri is illegal.";
this.error = true;
return;
}
if (!q.state) {
this.title = "参数state非法";
this.msg = "The parameter state is illegal.";
this.error = true;
return;
}
this.form.client_id = q.client_id;
this.form.redirect_uri = q.redirect_uri;
this.form.state = q.state;
this.form.responseType = q.responseType;
this.getSiteInfo(this.form.client_id);
},
getSiteInfo(v) {
siteInfo(v).then((res) => {
if (res.success) {
this.site = res.result;
this.isAuthed();
} else {
this.error = true;
this.title = res.message;
this.authLoading = false;
}
});
},
isAuthed() {
// 判断是否认证过
let userInfo = Cookies.get("userInfo");
this.userInfo = userInfo;
if (userInfo) {
this.userInfo = JSON.parse(userInfo);
// 自动授权
if (this.site.autoApprove) {
authorized(this.form).then((res) => {
if (res.success) {
let url =
res.result.redirect_uri +
"?code=" +
res.result.code +
"&state=" +
res.result.state;
window.location.href = url;
} else {
this.authLoading = false;
}
});
} else {
this.authLoading = false;
}
} else {
this.authLoading = false;
}
},
confirm() {
this.loading = true;
authorized(this.form).then((res) => {
this.loading = false;
if (res.success) {
let url =
res.result.redirect_uri +
"?code=" +
res.result.code +
"&state=" +
res.result.state;
window.location.href = url;
}
});
},
getCaptchaImg() {
this.loadingCaptcha = true;
initCaptcha().then((res) => {
this.loadingCaptcha = false;
if (res.success) {
this.form.captchaId = res.result;
this.captchaImg = drawCodeImage + res.result;
}
});
},
submit() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.loading = true;
authorize(this.form).then((res) => {
if (res.success) {
// 存储accessToken
this.setStore("accessToken", res.result.accessToken);
let redictInfo = res.result;
// 获取用户信息
userInfo().then((res) => {
if (res.success) {
// 避免超过大小限制
delete res.result.permissions;
let roles = [];
res.result.roles.forEach((e) => {
roles.push(e.name);
});
this.setStore("roles", roles);
Cookies.set("userInfo", JSON.stringify(res.result), {
expires: 7,
});
this.setStore("userInfo", res.result);
this.$store.commit("setUserInfo", res.result);
// 跳转
let url =
redictInfo.redirect_uri +
"?code=" +
redictInfo.code +
"&state=" +
redictInfo.state;
window.location.href = url;
} else {
this.loading = false;
this.getCaptchaImg();
}
});
} else {
this.loading = false;
this.getCaptchaImg();
}
});
}
});
},
},
mounted() {
this.init();
this.getCaptchaImg();
},
};
</script>
<style lang="less">
@import "./authorize.less";
</style>
<template>
<Card :padding="0" :style="{ backgroundColor: backgroundColor }">
<div
class="card-content card2"
:style="{ backgroundImage: backgroundImage }"
>
<div class="card-body">
<div :style="{ color: color }" class="card-title">{{ title }}</div>
<div class="card-data">
<count-up
:prefix="prefix"
:suffix="suffix"
:id="id"
:end-val="endVal"
:color="dataColor"
:countSize="countSize"
:countWeight="countWeight"
/>
<span
class="card-description"
:style="{
color: descriptionColor,
fontSize: descriptionSize,
fontWeight: descriptionWeight,
}"
>{{ description }}</span
>
</div>
<Progress
:percent="endVal"
:stroke-color="color"
:stroke-width="strokeWidth"
hide-info
/>
</div>
</div>
</Card>
</template>
<script>
import countUp from "@/views/my-components/widget/countUp.vue";
export default {
name: "card2",
components: {
countUp,
},
props: {
id: String,
backgroundColor: String,
backgroundImage: String,
title: String,
prefix: String,
suffix: String,
endVal: Number,
color: {
type: String,
default: "#19be6b",
},
dataColor: {
type: String,
default: "#3f4255",
},
countSize: {
type: String,
default: "24px",
},
countWeight: {
type: Number,
default: 600,
},
description: String,
strokeWidth: {
type: Number,
default: 6.5,
},
descriptionColor: {
type: String,
default: "#b5b5c5",
},
descriptionSize: {
type: String,
default: "12px",
},
descriptionWeight: {
type: Number,
default: 500,
},
},
};
</script>
<style lang="less" scoped>
.card-content {
height: 150px;
padding: 26px 30px;
}
.card2 {
background-position: right top;
background-size: 30% auto;
background-repeat: no-repeat;
.card-body {
display: flex;
flex-direction: column;
height: 102px;
justify-content: space-around;
align-items: flex-start;
.card-title {
font-weight: 600;
}
.card-data {
display: flex;
align-items: flex-end;
.card-description {
margin: 0 0 5px 5px;
}
}
}
}
</style>
<template>
<Card
:padding="0"
:bordered="bordered"
:style="{ backgroundColor: realBackgroundColor }"
>
<div
class="card-app card-content"
@click="click"
@mouseover="itemHover"
@mouseout="removeHover"
>
<div class="card-body">
<Icon
class="card-icon"
:type="icon"
:color="realIconColor"
:size="iconSize"
v-if="icon"
></Icon>
<img :src="image" :width="width" :height="height" v-else />
<div
class="card-title"
:style="{
color: realTitleColor,
fontSize: titleSize,
fontWeight: titleWeight,
}"
>
{{ title }}
</div>
</div>
</div>
</Card>
</template>
<script>
export default {
name: "card-app",
components: {},
props: {
idName: String,
backgroundColor: String,
activeColor: {
type: String,
default: "#2d8cf0",
},
openBackColorChange: {
type: Boolean,
default: true,
},
bordered: {
type: Boolean,
default: true,
},
icon: String,
iconSize: {
type: Number,
default: 40,
},
iconColor: {
type: String,
default: "#b5b5c5",
},
image: String,
width: {
type: String,
default: "40px",
},
height: {
type: String,
default: "40px",
},
title: String,
titleColor: {
type: String,
default: "#7e8299",
},
titleSize: {
type: String,
default: "16px",
},
titleWeight: {
type: Number,
default: 600,
},
},
data() {
return {
clicked: false,
realIconColor: this.iconColor,
realTitleColor: this.titleColor,
realBackgroundColor: this.backgroundColor,
};
},
methods: {
click() {
this.clicked = !this.clicked;
if (this.clicked) {
if (this.openBackColorChange) {
this.realBackgroundColor = this.activeColor;
this.bordered = false;
this.realIconColor = "#fff";
this.realTitleColor = "#fff";
} else {
this.realIconColor = this.activeColor;
this.realTitleColor = this.activeColor;
}
} else {
if (this.openBackColorChange) {
this.realBackgroundColor = this.backgroundColor;
this.bordered = false;
this.realIconColor = this.iconColor;
this.realTitleColor = this.titleColor;
} else {
this.realIconColor = this.iconColor;
this.realTitleColor = this.titleColor;
}
}
},
itemHover() {
if (!this.clicked) {
this.realIconColor = this.activeColor;
this.realTitleColor = this.activeColor;
}
},
removeHover() {
if (!this.clicked) {
this.realIconColor = this.iconColor;
this.realTitleColor = this.titleColor;
}
},
},
};
</script>
<style lang="less" scoped>
.card-content {
height: 150px;
padding: 26px 30px;
}
.card-app {
cursor: pointer;
.card-body {
display: flex;
flex-direction: column;
height: 102px;
justify-content: center;
align-items: center;
.card-icon {
transition: all 0.2s ease;
}
.card-title {
transition: all 0.2s ease;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-top: 10px;
}
}
}
</style>
<template>
<div>
<Card>
<p slot="title" class="card-title">
<Icon type="md-locate" style="margin-right: 5px"></Icon>访问用户分布
</p>
<Row type="flex" justify="center" align="middle" style="height: 273px">
<apexchart
type="donut"
width="350"
:options="chartOptions"
:series="series"
/>
</Row>
</Card>
</div>
</template>
<script>
export default {
name: "visitSeparation",
data() {
return {
series: [],
chartOptions: {
labels: ["移动端", "PC", "平板", "IOS", "其他"],
plotOptions: {
pie: {
donut: {
size: "70%",
},
},
},
dataLabels: {
enabled: false,
},
legend: {
position: "right",
},
},
};
},
methods: {
init() {
this.series = [45, 18, 27, 15, 13];
},
},
mounted() {
this.init();
},
};
</script>
<template>
<div class="visit">
<Card>
<p slot="title" class="card-title">
<Icon type="md-map" style="margin-right: 5px"></Icon>每日来访量统计
</p>
<div slot="extra">
<DatePicker
:options="options"
type="daterange"
placeholder="选择日期范围"
style="width: 250px"
></DatePicker>
</div>
<div style="height: 273px">
<apexchart
type="bar"
height="280"
:options="chartOptions"
:series="series"
/>
</div>
</Card>
</div>
</template>
<script>
import { addDays, subDays } from "date-fns";
import { shortcuts } from "@/libs/shortcuts";
var zh = require("../../../libs/zh.json");
export default {
name: "visitVolume",
data() {
return {
options: {
shortcuts: shortcuts,
},
series: [
{
name: "",
data: [],
},
],
chartOptions: {
colors: ["#398af7", "#63a3f9", "#b3d1fd"],
chart: {
stacked: true,
toolbar: {
show: false,
},
zoom: {
enabled: false,
},
locales: [zh],
defaultLocale: "zh",
},
plotOptions: {
bar: {
columnWidth: "40%",
horizontal: false,
},
},
xaxis: {
type: "datetime",
labels: {
datetimeFormatter: {
year: "yyyy年",
month: "yyyy年MMM",
day: "MMMdd日",
},
},
categories: [],
},
legend: {
show: false,
},
dataLabels: {
enabled: false,
},
tooltip: {
enabled: true,
x: {
show: true,
format: "MMM dd日",
},
},
},
};
},
methods: {
init() {
this.series = [
{
name: "登录次数",
data: [44, 55, 41, 67, 22, 43, 27, 45, 15, 44, 30, 44, 30, 15],
},
{
name: "浏览量",
data: [13, 23, 20, 8, 13, 27, 23, 20, 8, 13, 27, 13, 27, 50],
},
{
name: "注册用户",
data: [11, 17, 15, 15, 21, 14, 17, 15, 15, 21, 14, 21, 14, 35],
},
];
let categories = [];
let num = 14;
let start = subDays(new Date(), num);
for (let i = 0; i < num; i++) {
categories.push(addDays(start, i).getTime());
}
this.chartOptions.xaxis.categories = categories;
},
},
created() {
this.init();
},
};
</script>
<style lang="less">
.visit {
.ivu-card-head {
border-bottom: none !important;
}
}
</style>
......@@ -10,14 +10,6 @@
</template>
<script>
import { ipInfo } from "@/api/index";
import visitVolume from "./components/visitVolume.vue";
import visitSeparation from "./components/visitSeparation.vue";
import card1 from "@/views/my-components/widget/card1.vue";
import card2 from "./components/card2.vue";
import card3 from "@/views/my-components/widget/card3.vue";
import card4 from "@/views/my-components/widget/card4.vue";
import cardApp from "./components/cardApp.vue";
import Cookies from "js-cookie";
export default {
name: "home",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment