Quellcode durchsuchen

添加新增页面

yangg vor 2 Monaten
Ursprung
Commit
b3b64db772

+ 1 - 1
.env.development

@@ -3,7 +3,7 @@ ENV = 'development'
 #https://minlong.raycos.com.cn
 #线下:http://192.168.66.187:8083
 # 本地环境接口地址 121.36.251.245
-VITE_API_URL = 'https://minlong.raycos.com.cn'
+VITE_API_URL = 'http://192.168.66.187:8083'
 
 # 是否启用按钮权限
 VITE_PM_ENABLED = true

+ 1 - 1
src/router/index.ts

@@ -105,7 +105,7 @@ router.beforeEach(async (to, from, next) => {
     NProgress.configure({showSpinner: false});
     if (to.meta.title) NProgress.start();
     const token = Session.get('token');
-    if (to.path === '/login' && !token) {
+    if (to.path === '/login'|| to.path === '/superlogin' && !token) {
         next();
         NProgress.done();
     } else {

+ 8 - 0
src/router/route.ts

@@ -88,6 +88,14 @@ export const staticRoutes: Array<RouteRecordRaw> = [
 			title: '登录',
 		},
 	},
+	{
+		path: '/superlogin',
+		name: 'superlogin',
+		component: () => import('/@/views/system/login/superIndex.vue'),
+		meta: {
+			title: '登录',
+		},
+	},
 	{
 		path: '/demo',
 		name: 'demo',

+ 0 - 3
src/views/system/login/component/account.vue

@@ -2,14 +2,11 @@
 	<el-form ref="formRef" size="large" class="login-content-form" :model="state.ruleForm" :rules="rules"
 		@keyup.enter="loginClick">
 		<el-form-item class="login-animation1" prop="merchant_code">
-			<!-- <div class="merchant-input-container"> -->
 				<el-input type="text" :placeholder="'请输入商户号'" v-model="ruleForm.merchant_code" clearable autocomplete="off">
 					<template #prefix>
 						<el-icon class="el-input__icon"><ele-Shop /></el-icon>
 					</template>
 				</el-input>
-				<!-- <el-checkbox v-model="rememberMerchant" class="remember-merchant">记住商户号</el-checkbox> -->
-			<!-- </div> -->
 		</el-form-item>
 		<el-form-item class="login-animation1" prop="username">
 			<el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.username"

+ 549 - 0
src/views/system/login/superIndex.vue

@@ -0,0 +1,549 @@
+<template>
+	<div class="login-container flex z-10">
+		<div class="login-left">
+			<div class="login-left-logo">
+				<img :src="siteLogo" /><!-- siteLogo -->
+				<div class="login-left-logo-text">
+					<span>{{ getSystemConfig['login.site_title'] || getThemeConfig.globalViceTitle }}</span><!--   -->
+					<span class="login-left-logo-text-msg" style="margin-top: 5px">{{
+						getSystemConfig['login.site_name'] || getThemeConfig.globalViceTitleMsg
+					}}</span>
+				</div>
+			</div>
+		</div>
+		<div class="login-right flex z-10">
+			<div class="login-right-warp flex-margin">
+				<!--				<span class="login-right-warp-one"></span>-->
+				<!--				<span class="login-right-warp-two"></span>-->
+				<div class="login-right-warp-mian">
+					<div class="login-right-warp-main-title">
+						超级管理员登陆
+					</div>
+
+					<div class="login-right-warp-main-form pt-4">
+						<el-form ref="superformRef" size="large" class="login-content-form" :model="superForm"
+							:rules="superRules" @keyup.enter="loginClick">
+							<el-form-item class="login-animation1" prop="username">
+								<el-input type="text" placeholder="请输入登录账号" v-model="superForm.username" clearable>
+									<template #prefix>
+										<el-icon class="el-input__icon"><ele-User /></el-icon>
+									</template>
+								</el-input>
+							</el-form-item>
+							<el-form-item class="login-animation2" prop="password">
+								<el-input :type="isShowPassword ? 'text' : 'password'"
+									:placeholder="$t('message.account.accountPlaceholder4')"
+									v-model="superForm.password">
+									<template #prefix>
+										<el-icon class="el-input__icon"><ele-Unlock /></el-icon>
+									</template>
+									<template #suffix>
+										<i class="iconfont el-input__icon login-content-password"
+											:class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
+											@click="isShowPassword = !isShowPassword">
+										</i>
+									</template>
+								</el-input>
+							</el-form-item>
+							<el-form-item class="login-animation3" v-if="isShowCaptcha" prop="captcha">
+								<el-col :span="15">
+									<el-input type="text" maxlength="4"
+										:placeholder="$t('message.account.accountPlaceholder3')"
+										v-model="superForm.captcha" clearable autocomplete="off">
+										<template #prefix>
+											<el-icon class="el-input__icon"><ele-Position /></el-icon>
+										</template>
+									</el-input>
+								</el-col>
+								<el-col :span="1"></el-col>
+								<el-col :span="8">
+									<el-button class="login-content-captcha">
+										<el-image :src="superForm.captchaImgBase" @click="refreshCaptcha" />
+									</el-button>
+								</el-col>
+							</el-form-item>
+							<el-form-item class="login-animation4">
+								<el-button type="primary" class="login-content-submit w-full" round @click="loginClick"
+									:loading="loading.signIn">
+									<span>{{ $t('message.account.accountBtnText') }}</span>
+								</el-button>
+							</el-form-item>
+						</el-form>
+					</div>
+				</div>
+			</div>
+		</div>
+
+		<div class="login-authorization z-10">
+			<!-- <p>Copyright © {{ getSystemConfig['login.copyright'] || '2021-2024 北京信码新创科技有限公司' }} 版权所有</p> -->
+			<!-- <p class="la-other" style="margin-top: 5px">
+				<a href="https://beian.miit.gov.cn" target="_blank">{{ getSystemConfig['login.keep_record'] || '京ICP备2021031018号' }}</a>
+				|
+				<a :href="getSystemConfig['login.help_url'] ? getSystemConfig['login.help_url'] : '#'" target="_blank">帮助</a>
+				|
+				<a :href="getSystemConfig['login.privacy_url'] ? getBaseURL(getSystemConfig['login.privacy_url']) : '#'">隐私</a>
+				|
+				<a :href="getSystemConfig['login.clause_url'] ? getBaseURL(getSystemConfig['login.clause_url']) : '#'">条款</a>
+			</p> -->
+		</div>
+	</div>
+	<div v-if="loginBg">
+		<img :src="loginBg" class="loginBg fixed inset-0 z-1 w-full h-full" />
+	</div>
+</template>
+
+<script setup lang="ts" name="loginIndex">
+import { defineAsyncComponent, onMounted, reactive, computed, watch, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '/@/stores/themeConfig';
+import { NextLoading } from '/@/utils/loading';
+import logoMini from '/@/assets/logo-mini.svg';
+import loginMain from '/@/assets/login-main.svg';
+import loginBg from '/@/assets/login_background.jpg';
+import { SystemConfigStore } from '/@/stores/systemConfig';
+import { getBaseURL } from '/@/utils/baseUrl';
+import { useI18n } from 'vue-i18n';
+import * as api from './api';
+import * as loginApi from '/@/views/system/login/api';
+import { useUserInfo } from '/@/stores/userInfo';
+import { ElMessage } from 'element-plus';
+import { useRouter } from 'vue-router';
+import { Md5 } from 'ts-md5';
+import Cookies from 'js-cookie';
+import { Session } from '/@/utils/storage';
+import * as _ from 'lodash-es';
+
+// 引入组件
+const Account = defineAsyncComponent(() => import('/@/views/system/login/component/account.vue'));
+const Mobile = defineAsyncComponent(() => import('/@/views/system/login/component/mobile.vue'));
+const Scan = defineAsyncComponent(() => import('/@/views/system/login/component/scan.vue'));
+const ChangePwd = defineAsyncComponent(() => import('/@/views/system/login/component/changePwd.vue'));
+const { userInfos } = storeToRefs(useUserInfo());
+
+// 定义变量内容
+const storesThemeConfig = useThemeConfig();
+const { themeConfig } = storeToRefs(storesThemeConfig);
+const state = reactive({
+	tabsActiveName: 'account',
+	isScan: false,
+});
+const { t } = useI18n();
+watch(
+	() => userInfos.value.pwd_change_count,
+	(val) => {
+		if (val === 0) {
+			state.tabsActiveName = 'changePwd';
+		} else {
+			state.tabsActiveName = 'account';
+		}
+	},
+	{ deep: true, immediate: true }
+);
+
+// 获取布局配置信息
+const getThemeConfig = computed(() => {
+	return themeConfig.value;
+});
+
+const systemConfigStore = SystemConfigStore();
+const { systemConfig } = storeToRefs(systemConfigStore);
+const getSystemConfig = computed(() => {
+	return systemConfig.value;
+});
+
+const siteLogo = computed(() => {
+	if (!_.isEmpty(getSystemConfig.value['login.site_logo'])) {
+		return getSystemConfig.value['login.site_logo'];
+	}
+	return logoMini;
+});
+
+const siteBg = computed(() => {
+	if (!_.isEmpty(getSystemConfig.value['login.login_background'])) {
+		return getSystemConfig.value['login.login_background'];
+	}
+});
+const superLogin = ref(true);
+
+// 添加loading状态
+const loading = reactive({
+	signIn: false,
+});
+/* 超级管理员登录表单 */
+const superForm = ref({
+	username: '', // 设置默认用户名
+	password: '',
+	captcha: '',
+	captchaKey: '',
+	captchaImgBase: '',
+});
+// 添加表单校验规则
+const superRules = reactive({
+	username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
+	password: [
+		{
+			required: true,
+			message: '请填写密码',
+			trigger: 'blur',
+		},
+	],
+	captcha: [
+		{
+			required: true,
+			message: '请填写验证码',
+			trigger: 'blur',
+		},
+	],
+});
+
+const superformRef = ref();
+const router = useRouter();
+const formRef = ref();
+
+// 添加 formatAxis 函数定义
+const formatAxis = (date: Date): string => {
+	const hours = date.getHours();
+	const minutes = date.getMinutes();
+	// 格式化时间为 HH:MM 格式
+	return `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}`;
+};
+
+// 时间获取
+const currentTime = computed(() => {
+	return formatAxis(new Date());
+});
+
+// 是否关闭验证码
+const isShowCaptcha = computed(() => {
+	return SystemConfigStore().systemConfig['base.captcha_state'];
+});
+
+const getCaptcha = async () => {
+	loginApi.getCaptcha().then((ret: any) => {
+		console.log(ret);
+		superForm.value.captchaImgBase = ret.data.image_base;
+		superForm.value.captchaKey = ret.data.key;
+		console.log(superForm);
+	});
+};
+const applyBtnClick = async () => {
+	window.open(getBaseURL('/api/system/apply_for_trial/'));
+};
+const refreshCaptcha = async () => {
+	superForm.value.captcha = '';
+	loginApi.getCaptcha().then((ret: any) => {
+		superForm.value.captchaImgBase = ret.data.image_base;
+		superForm.value.captchaKey = ret.data.key;
+	});
+};
+// 添加登录方法
+const loginClick = async () => {
+	if (!superformRef.value) return;
+	await superformRef.value.validate(async (valid: boolean) => {
+		if (valid) {
+			try {
+				loading.signIn = true;
+				// 创建一个简单的登录数据对象,避免直接使用响应式对象
+				const loginData = {
+					username: superForm.value.username,
+					password: superForm.value.password,
+					captcha: superForm.value.captcha,
+					captchaKey: superForm.value.captchaKey,
+					captchaImgBase: superForm.value.captchaImgBase,
+				};
+				/* 	const res =  */
+				loginApi.login({ ...loginData, password: Md5.hashStr(loginData.password) }).then((res: any) => {
+					console.log(res);
+					if (res?.code === 2000) {
+						ElMessage.success('登录成功');
+						Cookies.set('username', res.data.username);
+						Session.set('token', res.data.access);
+						Session.set('superKey',res.data.role_info[0].key)
+						Session.set('merchant_info', res.data.merchant_info);
+						router.push('/');
+					} else {
+						ElMessage.error(res?.msg || '登录失败');
+					}
+				})
+
+			} catch (error: any) {
+				console.error('登录失败:', error);
+				ElMessage.error(error?.message || '登录失败,请稍后重试');
+			} finally {
+				loading.signIn = false;
+			}
+		}
+	});
+};
+
+const isShowPassword = ref(false);
+/* 跳转至超级管理员登录 */
+const goSuper = async () => {
+	superLogin.value = !superLogin.value;
+};
+
+// 页面加载时
+onMounted(() => {
+	getCaptcha();
+	NextLoading.done();
+});
+</script>
+
+<style scoped lang="scss">
+.login-container {
+	height: 100%;
+	background: var(--el-color-white);
+
+	.login-left {
+		flex: 1;
+		position: relative;
+		background-color: rgba(211, 239, 255, 1);
+		margin-right: 100px;
+
+		.login-left-logo {
+			display: flex;
+			align-items: center;
+			position: absolute;
+			top: 50px;
+			left: 80px;
+			z-index: 1;
+			animation: logoAnimation 0.3s ease;
+
+			img {
+				width: 52px;
+				height: 52px;
+			}
+
+			.login-left-logo-text {
+				display: flex;
+				flex-direction: column;
+
+				span {
+					margin-left: 10px;
+					font-size: 16px;
+					color: var(--el-color-primary);
+				}
+
+				.login-left-logo-text-msg {
+					font-size: 12px;
+					color: var(--el-color-primary);
+				}
+			}
+		}
+
+		.login-left-img {
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			transform: translate(-50%, -50%);
+			width: 100%;
+			height: 52%;
+
+			img {
+				width: 100%;
+				height: 100%;
+				animation: error-num 0.6s ease;
+			}
+		}
+
+		.login-left-waves {
+			position: absolute;
+			top: 0;
+			right: -100px;
+		}
+	}
+
+	.login-right {
+		width: 700px;
+
+		.login-right-warp {
+			//border: 1px solid var(--el-color-primary-light-3);
+			border-radius: 10px;
+			width: 450px;
+			height: 501px;
+			position: relative;
+			overflow: hidden;
+			//background-color: var(--el-color-white);
+
+			.login-right-warp-one,
+			.login-right-warp-two {
+				position: absolute;
+				display: block;
+				width: inherit;
+				height: inherit;
+
+				&::before,
+				&::after {
+					content: '';
+					position: absolute;
+					z-index: 1;
+				}
+			}
+
+			.login-right-warp-one {
+				&::before {
+					filter: hue-rotate(0deg);
+					top: 0px;
+					left: 0;
+					width: 100%;
+					height: 3px;
+					background: linear-gradient(90deg, transparent, var(--el-color-primary));
+					animation: loginLeft 3s linear infinite;
+				}
+
+				&::after {
+					filter: hue-rotate(60deg);
+					top: -100%;
+					right: 2px;
+					width: 3px;
+					height: 100%;
+					background: linear-gradient(180deg, transparent, var(--el-color-primary));
+					animation: loginTop 3s linear infinite;
+					animation-delay: 0.7s;
+				}
+			}
+
+			.login-right-warp-two {
+				&::before {
+					filter: hue-rotate(120deg);
+					bottom: 2px;
+					right: -100%;
+					width: 100%;
+					height: 3px;
+					background: linear-gradient(270deg, transparent, var(--el-color-primary));
+					animation: loginRight 3s linear infinite;
+					animation-delay: 1.4s;
+				}
+
+				&::after {
+					filter: hue-rotate(300deg);
+					bottom: -100%;
+					left: 0px;
+					width: 3px;
+					height: 100%;
+					background: linear-gradient(360deg, transparent, var(--el-color-primary));
+					animation: loginBottom 3s linear infinite;
+					animation-delay: 2.1s;
+				}
+			}
+
+			.login-right-warp-mian {
+				display: flex;
+				flex-direction: column;
+				height: 100%;
+				background: #fff;
+
+				.login-right-warp-main-title {
+					height: 130px;
+					line-height: 130px;
+					font-size: 32px;
+					font-weight: 600;
+					text-align: center;
+					letter-spacing: 3px;
+					animation: logoAnimation 0.3s ease;
+					animation-delay: 0.3s;
+					color: var(--el-text-color-primary);
+				}
+
+				.login-right-warp-main-form {
+					flex: 1;
+					padding: 0 50px 50px;
+
+					.login-content-main-sacn {
+						position: absolute;
+						top: 2px;
+						right: 12px;
+						width: 50px;
+						height: 50px;
+						overflow: hidden;
+						cursor: pointer;
+						transition: all ease 0.3s;
+						color: var(--el-color-primary);
+
+						&-delta {
+							position: absolute;
+							width: 35px;
+							height: 70px;
+							z-index: 2;
+							top: 2px;
+							right: 21px;
+							background: var(--el-color-white);
+							transform: rotate(-45deg);
+						}
+
+						&:hover {
+							opacity: 1;
+							transition: all ease 0.3s;
+							color: var(--el-color-primary) !important;
+						}
+
+						i {
+							width: 47px;
+							height: 50px;
+							display: inline-block;
+							font-size: 48px;
+							position: absolute;
+							right: 1px;
+							top: 0px;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	.login-authorization {
+		position: absolute;
+		bottom: 30px;
+		left: 0;
+		right: 0;
+		text-align: center;
+
+		p {
+			font-size: 14px;
+			color: rgba(0, 0, 0, 0.5);
+		}
+
+		a {
+			color: var(--el-color-primary);
+			margin: 0 5px;
+		}
+	}
+}
+
+.login-content-form {
+	@for $i from 1 through 4 {
+		.login-animation#{$i} {
+			opacity: 0;
+			animation-name: error-num;
+			animation-duration: 0.5s;
+			animation-fill-mode: forwards;
+			animation-delay: calc($i/10) + s;
+		}
+	}
+
+	.login-content-password {
+		display: inline-block;
+		width: 20px;
+		cursor: pointer;
+
+		&:hover {
+			color: #909399;
+		}
+	}
+
+	.login-content-captcha {
+		width: 100%;
+		padding: 0;
+		font-weight: bold;
+		letter-spacing: 5px;
+	}
+
+	.login-content-submit {
+		width: 100%;
+		letter-spacing: 2px;
+		font-weight: 800;
+		margin-top: 15px;
+	}
+}
+</style>

+ 10 - 1
src/views/system/menu/api.ts

@@ -1,7 +1,16 @@
 import { request } from '/@/utils/service';
 import { UserPageQuery, AddReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+import { Session } from '/@/utils/storage';
 
-export const apiPrefix = '/api/system/menu/';
+let apiPrefix = '/api/system/menu/';
+
+if (Session.get('superKey') === 'super_admin_role') {
+  apiPrefix = '/api/system/superadmin/menus/';
+} else {
+  apiPrefix = '/api/system/menu/';
+}
+
+export { apiPrefix };
 
 export function GetList(query: UserPageQuery) {
   return request({

+ 2 - 2
src/views/system/menu/components/MenuButtonCom/crud.tsx

@@ -244,7 +244,7 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
                     search: {show: false},
                     type: 'dict-select',
                     dict: dict({
-                        getData() {
+                        /* getData() {
                             return request({url: '/swagger.json'}).then((res: any) => {
                                 const ret = Object.keys(res.paths);
                                 const data = [];
@@ -256,7 +256,7 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
                                 }
                                 return data;
                             });
-                        },
+                        }, */
                     }),
                     column: {
                         minWidth: 250,