| | |
| | | <template> |
| | | <div class="login-container"> |
| | | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" |
| | | label-position="left"> |
| | | |
| | | <div class="title-container"> |
| | | <h3 class="title">鸿蒙智能电子锁管理平台</h3> |
| | | </div> |
| | | |
| | | <el-form-item prop="username"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="user" /> |
| | | </span> |
| | | <el-input ref="username" v-model="loginForm.username" placeholder="Username" name="username" type="text" |
| | | tabindex="1" autocomplete="on" /> |
| | | </el-form-item> |
| | | |
| | | <el-tooltip v-model="capsTooltip" :content="passwordType === 'password' ?'显示密码':'隐藏密码'" placement="right" manual> |
| | | <el-form-item prop="password"> |
| | | <div class="site-title"> |
| | | <svg-icon icon-class="lock1"></svg-icon>鸿蒙智能电子锁管理平台 |
| | | </div> |
| | | <div class="img-hm"></div> |
| | | <div class="login-wrap"> |
| | | <el-form |
| | | ref="loginFormRef" |
| | | :model="loginForm" |
| | | :rules="loginRules" |
| | | class="login-form" |
| | | autocomplete="on" |
| | | label-position="left" |
| | | > |
| | | <div class="title-container"> |
| | | <h3 class="title">用户登录</h3> |
| | | </div> |
| | | <el-form-item class="input-item" prop="username"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="password" /> |
| | | <svg-icon icon-class="user" /> |
| | | </span> |
| | | <el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType" |
| | | placeholder="Password" name="password" tabindex="2" autocomplete="on" @keyup="checkCapslock" |
| | | @blur="capsTooltip = false" @keyup.enter="handleLogin" /> |
| | | <span class="show-pwd" @click="showPwd"> |
| | | <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> |
| | | </span> |
| | | <el-input |
| | | ref="username" |
| | | v-model="loginForm.username" |
| | | placeholder="Username" |
| | | name="username" |
| | | type="text" |
| | | tabindex="1" |
| | | autocomplete="on" |
| | | /> |
| | | </el-form-item> |
| | | </el-tooltip> |
| | | |
| | | <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:40px;" |
| | | @click.prevent="handleLogin">登录</el-button> |
| | | </el-form> |
| | | <el-tooltip |
| | | v-model="capsTooltip" |
| | | :content="passwordType === 'password' ?'显示密码':'隐藏密码'" |
| | | placement="right" |
| | | manual |
| | | > |
| | | <el-form-item class="input-item" prop="password"> |
| | | <span class="svg-container"> |
| | | <svg-icon icon-class="password" /> |
| | | </span> |
| | | <el-input |
| | | :key="passwordType" |
| | | ref="password" |
| | | v-model="loginForm.password" |
| | | :type="passwordType" |
| | | placeholder="Password" |
| | | name="password" |
| | | tabindex="2" |
| | | autocomplete="on" |
| | | @keyup="checkCapslock" |
| | | @blur="capsTooltip = false" |
| | | @keyup.enter="handleLogin" |
| | | /> |
| | | <span class="show-pwd" @click="showPwd"> |
| | | <svg-icon |
| | | :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" |
| | | /> |
| | | </span> |
| | | </el-form-item> |
| | | </el-tooltip> |
| | | <el-button |
| | | :loading="loading" |
| | | type="primary" |
| | | style="width:100%; height:50px; margin-bottom:40px;" |
| | | @click.prevent="handleLogin" |
| | | >登录</el-button |
| | | > |
| | | </el-form> |
| | | </div> |
| | | <div class="tools-container"> |
| | | <div class="tools-item" :class="uKeyState" v-if="uKey" @click="uKeyVisible = true"> |
| | | <div |
| | | class="tools-item" |
| | | :class="uKeyState" |
| | | v-if="uKey" |
| | | @click="uKeyVisible = true" |
| | | > |
| | | <span class="ukey"></span> |
| | | </div> |
| | | <div class="tools-item" v-if="faceCfg" @click="faceVisible = true"> |
| | |
| | | </div> |
| | | </div> |
| | | <!-- uKey的验证 --> |
| | | <el-dialog title="uKey绑定" width="750px" v-model="uKeyVisible" :close-on-click-modal="false" top="0" |
| | | class="dialog-center" :modal-append-to-body="false"> |
| | | <el-dialog |
| | | title="uKey绑定" |
| | | width="750px" |
| | | v-model="uKeyVisible" |
| | | :close-on-click-modal="false" |
| | | top="0" |
| | | class="dialog-center" |
| | | :modal-append-to-body="false" |
| | | > |
| | | <ukey-bind v-if="uKeyVisible" v-model:visible="uKeyVisible"></ukey-bind> |
| | | </el-dialog> |
| | | |
| | | |
| | | <!-- 人脸登陆 --> |
| | | <el-dialog title="人脸登陆" width="480px" v-model="faceVisible" :close-on-click-modal="false" top="0" |
| | | class="dialog-center" :modal-append-to-body="false"> |
| | | <face-login v-if="faceVisible" ></face-login> |
| | | <el-dialog |
| | | title="人脸登陆" |
| | | width="480px" |
| | | v-model="faceVisible" |
| | | :close-on-click-modal="false" |
| | | top="0" |
| | | class="dialog-center" |
| | | :modal-append-to-body="false" |
| | | > |
| | | <face-login v-if="faceVisible"></face-login> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { defineComponent } from 'vue'; |
| | | import { ElMessage, type FormItemRule } from 'element-plus'; |
| | | import type { IForm } from '@/types/element-plus'; |
| | | import store from '@/store'; |
| | | import { mapState } from 'pinia'; |
| | | import config from '@/utils/config.js'; |
| | | import UkeyBind from './components/UKeyBind/index.vue'; |
| | | import useElement from '@/hooks/useElement.js'; |
| | | import { uKeyLogin } from '@/api/user'; |
| | | import FaceLogin from './components/face/FaceLogin.vue'; |
| | | import { getToken, removeToken, setToken, getUname, setUname, removeUname, getUrole, setUrole, removeUrole } from '@/utils/auth'; |
| | | <script setup name="Login"> |
| | | import { ref, computed, reactive, watch, onMounted, nextTick } from 'vue'; |
| | | import { ElMessage } from 'element-plus'; |
| | | |
| | | const { $loading, $confirm, $message } = useElement(); |
| | | const { ukey, face } = config; |
| | | import { mapState } from 'pinia'; |
| | | import config from '@/utils/config.js'; |
| | | import UkeyBind from './components/UKeyBind/index.vue'; |
| | | import useElement from '@/hooks/useElement.js'; |
| | | import { uKeyLogin } from '@/api/user'; |
| | | import FaceLogin from './components/face/FaceLogin.vue'; |
| | | import { getToken, removeToken, setToken, getUname, setUname, removeUname, getUrole, setUrole, removeUrole } from '@/utils/auth'; |
| | | import { useUserStore } from '@/store/user'; |
| | | import { useSettingsStore } from '@/store/settings'; |
| | | import { useUKeyStore } from '@/store/ukey'; |
| | | import { storeToRefs } from 'pinia'; |
| | | import { useRoute, useRouter } from 'vue-router'; |
| | | |
| | | interface QueryType { |
| | | // 自定义key 任意字符串 |
| | | [propname: string]: string |
| | | } |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | |
| | | export default defineComponent({ |
| | | name: 'Login', |
| | | data() { |
| | | const validateUsername: FormItemRule['validator'] = (_rule, value, callback) => { |
| | | if (!value.trim()) { |
| | | callback(new Error('请输入用户名')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | const validatePassword: FormItemRule['validator'] = (_rule, value, callback) => { |
| | | if (value.length < 1) { |
| | | callback(new Error('请输入密码,至少1位')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | return { |
| | | uKey: ukey, |
| | | faceCfg: face, |
| | | uKeyVisible: false, |
| | | faceVisible: false, |
| | | loginForm: { |
| | | username: '', |
| | | password: '' |
| | | }, |
| | | loginRules: { |
| | | username: [{ required: true, trigger: 'blur', validator: validateUsername }], |
| | | password: [{ required: true, trigger: 'blur', validator: validatePassword }] |
| | | }, |
| | | passwordType: 'password', |
| | | capsTooltip: false, |
| | | loading: false, |
| | | showDialog: false, |
| | | redirect: undefined, |
| | | otherQuery: {} |
| | | }; |
| | | }, |
| | | components: { |
| | | UkeyBind, |
| | | FaceLogin, |
| | | }, |
| | | computed: { |
| | | const userStore = useUserStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const ukeyStore = useUKeyStore(); |
| | | |
| | | uKeyState() { |
| | | let state = -1; |
| | | let uKey = store.ukey(); |
| | | let cls = "state-error"; |
| | | // 设置uKey的状态 |
| | | if (uKey.connect) { |
| | | if (uKey.isIn) { |
| | | state = 1; |
| | | } else { |
| | | state = 0; |
| | | } |
| | | } else { |
| | | state = -1; |
| | | } |
| | | // 根据状态确定uKey图表的颜色 |
| | | switch (state) { |
| | | case 0: |
| | | cls = "state-default"; |
| | | break; |
| | | case 1: |
| | | cls = ""; |
| | | break; |
| | | default: |
| | | cls = "state-error"; |
| | | break; |
| | | } |
| | | return cls; |
| | | }, |
| | | ...mapState(store.ukey, ['isIn', 'connect', 'id']) |
| | | }, |
| | | watch: { |
| | | $route: { |
| | | handler: function (route) { |
| | | const query = route.query; |
| | | if (query) { |
| | | this.redirect = query.redirect; |
| | | this.otherQuery = this.getOtherQuery(query); |
| | | } |
| | | }, |
| | | immediate: true |
| | | } |
| | | }, |
| | | created() { |
| | | // window.addEventListener('storage', this.afterQRScan) |
| | | }, |
| | | mounted() { |
| | | if (this.loginForm.username === '') { |
| | | (this.$refs.username as HTMLElement).focus(); |
| | | } else if (this.loginForm.password === '') { |
| | | (this.$refs.password as HTMLElement).focus(); |
| | | } |
| | | this.themeChange('blue-theme'); |
| | | }, |
| | | unmounted() { |
| | | // window.removeEventListener('storage', this.afterQRScan) |
| | | }, |
| | | methods: { |
| | | themeChange(val) { |
| | | store.settings().changeSetting({ |
| | | key: 'theme', |
| | | value: val |
| | | }); |
| | | }, |
| | | checkCapslock(e) { |
| | | const { key } = e; |
| | | this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z'); |
| | | }, |
| | | showPwd() { |
| | | if (this.passwordType === 'password') { |
| | | this.passwordType = ''; |
| | | } else { |
| | | this.passwordType = 'password'; |
| | | } |
| | | this.$nextTick(() => { |
| | | (this.$refs.password as HTMLElement).focus(); |
| | | }); |
| | | }, |
| | | handleLogin() { |
| | | if (ukey) { |
| | | this.uKeyLoginFn(); |
| | | } else { |
| | | this.normalLogin(); |
| | | } |
| | | }, |
| | | uKeyLoginFn() { |
| | | // |
| | | if (!this.connect) { |
| | | $message.error("请先安装uKey客户端服务"); |
| | | return; |
| | | } |
| | | if (!this.isIn) { |
| | | $message.warning("请先插入uKey"); |
| | | return; |
| | | } |
| | | const { isIn, connect, id } = storeToRefs(ukeyStore); |
| | | const { login } = userStore; |
| | | const { changeSetting } = settingsStore; |
| | | |
| | | // 校验用户 |
| | | if (this.loginForm.username && this.loginForm.password) { |
| | | // 开启等待框 |
| | | this.loading = true; |
| | | uKeyLogin( |
| | | this.loginForm.username, |
| | | this.loginForm.password, |
| | | this.id |
| | | ) |
| | | .then((res) => { |
| | | // 对结果进行处理 |
| | | console.log('res', res, '============='); |
| | | let { code, data, data2, msg } = res; |
| | | this.loading = false; |
| | | if (code && data) { |
| | | setUname(data2.uname); |
| | | setToken('admin'); |
| | | setUrole(data2.urole); |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'success' |
| | | }); |
| | | this.$router.push({ path: this.redirect || '/', query: this.otherQuery }); |
| | | } else { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'error' |
| | | }); |
| | | } |
| | | const { $loading, $confirm, $message } = useElement(); |
| | | const { ukey: _ukey, face } = config; |
| | | |
| | | }) |
| | | .catch((error) => { |
| | | // 关闭等待 |
| | | this.loading = false; |
| | | console.log(error); |
| | | $message.error("网络异常"); |
| | | }); |
| | | } else { |
| | | $message.error("用户名或密码不能为空"); |
| | | } |
| | | }, |
| | | normalLogin() { |
| | | (this.$refs.loginForm as IForm).validate(valid => { |
| | | return new Promise((resolve, reject) => { |
| | | if (valid) { |
| | | this.loading = true; |
| | | store.user().login(this.loginForm) |
| | | .then((res) => { |
| | | this.loading = false; |
| | | let { code, data, msg } = res; |
| | | if (code && data) { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'success' |
| | | }); |
| | | this.$router.push({ path: this.redirect || '/', query: this.otherQuery }); |
| | | } else { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'error' |
| | | }); |
| | | } |
| | | }).catch((error) => { |
| | | this.loading = false; |
| | | // 请求失败,处理错误 |
| | | if (error.message === 'Network Error') { |
| | | // 如果是网络错误,显示中文消息 |
| | | ElMessage({ |
| | | message: '网络错误,请检查您的网络连接或服务器状态。', |
| | | type: 'error' |
| | | }); |
| | | } else { |
| | | // 其他类型的错误,可以根据需要处理 |
| | | ElMessage({ |
| | | message: error, |
| | | type: 'warning' |
| | | }); |
| | | } |
| | | }).finally(() => { |
| | | resolve(); |
| | | }); |
| | | } else { |
| | | console.log('error submit!!'); |
| | | reject(); |
| | | } |
| | | }); |
| | | }); |
| | | }, |
| | | getOtherQuery(query: QueryType) { |
| | | return Object.keys(query).reduce((acc: QueryType, cur) => { |
| | | if (cur !== 'redirect') { |
| | | acc[cur] = query[cur]; |
| | | } |
| | | return acc; |
| | | }, {}); |
| | | } |
| | | // afterQRScan() { |
| | | // if (e.key === 'x-admin-oauth-code') { |
| | | // const code = getQueryObject(e.newValue) |
| | | // const codeMap = { |
| | | // wechat: 'code', |
| | | // tencent: 'code' |
| | | // } |
| | | // const type = codeMap[this.auth_type] |
| | | // const codeName = code[type] |
| | | // if (codeName) { |
| | | // store.user().LoginByThirdparty(codeName).then(() => { |
| | | // this.$router.push({ path: this.redirect || '/' }) |
| | | // }) |
| | | // } else { |
| | | // alert('第三方登录失败') |
| | | // } |
| | | // } |
| | | // } |
| | | const uKeyState = computed(() => { |
| | | let state = -1; |
| | | let cls = "state-error"; |
| | | // 设置uKey的状态 |
| | | if (connect.value) { |
| | | if (isIn.value) { |
| | | state = 1; |
| | | } else { |
| | | state = 0; |
| | | } |
| | | } else { |
| | | state = -1; |
| | | } |
| | | // 根据状态确定uKey图表的颜色 |
| | | switch (state) { |
| | | case 0: |
| | | cls = "state-default"; |
| | | break; |
| | | case 1: |
| | | cls = ""; |
| | | break; |
| | | default: |
| | | cls = "state-error"; |
| | | break; |
| | | } |
| | | return cls; |
| | | }); |
| | | |
| | | const validateUsername = (_rule, value, callback) => { |
| | | if (!value.trim()) { |
| | | callback(new Error('请输入用户名')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | const validatePassword = (_rule, value, callback) => { |
| | | if (value.length < 1) { |
| | | callback(new Error('请输入密码,至少1位')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | const uKey = ref(_ukey); |
| | | const faceCfg = ref(face); |
| | | |
| | | const uKeyVisible = ref(false); |
| | | const faceVisible = ref(false); |
| | | const loginFormRef = ref(); |
| | | const username = ref(); |
| | | const password = ref(); |
| | | const loginForm = reactive({ |
| | | username: '', |
| | | password: '' |
| | | }); |
| | | const loginRules = reactive({ |
| | | username: [{ required: true, trigger: 'blur', validator: validateUsername }], |
| | | password: [{ required: true, trigger: 'blur', validator: validatePassword }] |
| | | }); |
| | | |
| | | const passwordType = ref('password'); |
| | | const capsTooltip = ref(false); |
| | | const loading = ref(false); |
| | | const showDialog = ref(false); |
| | | const redirect = ref(undefined); |
| | | const otherQuery = ref({}); |
| | | |
| | | watch( |
| | | () => route.path, |
| | | () => { |
| | | let query = route.query; |
| | | if (query) { |
| | | redirect.value = query.redirect; |
| | | otherQuery.value = getOtherQuery(query); |
| | | } |
| | | }, |
| | | { |
| | | immediate: true |
| | | } |
| | | ); |
| | | |
| | | onMounted(() => { |
| | | if (loginForm.username === '') { |
| | | username.value.focus(); |
| | | } else if (loginForm.password === '') { |
| | | password.value.focus(); |
| | | } |
| | | themeChange('blue-theme'); |
| | | }); |
| | | |
| | | function themeChange(val) { |
| | | changeSetting({ |
| | | key: 'theme', |
| | | value: val |
| | | }); |
| | | } |
| | | |
| | | function checkCapslock(e) { |
| | | const { key } = e; |
| | | capsTooltip.value = key && key.length === 1 && (key >= 'A' && key <= 'Z'); |
| | | } |
| | | |
| | | function showPwd() { |
| | | if (passwordType.value === 'password') { |
| | | passwordType.value = ''; |
| | | } else { |
| | | passwordType.value = 'password'; |
| | | } |
| | | nextTick(() => { |
| | | password.value.focus(); |
| | | }) |
| | | } |
| | | |
| | | function handleLogin() { |
| | | if (uKey.value) { |
| | | uKeyLoginFn(); |
| | | } else { |
| | | normalLogin(); |
| | | } |
| | | } |
| | | |
| | | function uKeyLoginFn() { |
| | | if (!connect.value) { |
| | | $message.error("请先安装uKey客户端服务"); |
| | | return; |
| | | } |
| | | if (!isIn.value) { |
| | | $message.warning("请先插入uKey"); |
| | | return; |
| | | } |
| | | // 校验用户 |
| | | if (loginForm.username && loginForm.password) { |
| | | // 开启等待框 |
| | | loading.value = true; |
| | | uKeyLogin( |
| | | loginForm.username, |
| | | loginForm.password, |
| | | id.value |
| | | ) |
| | | .then((res) => { |
| | | let { code, data, data2, msg } = res; |
| | | loading.value = false; |
| | | if (code && data) { |
| | | setUname(data2.uname); |
| | | setToken('admin'); |
| | | setUrole(data2.urole); |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'success' |
| | | }); |
| | | router.push({ path: redirect.value || '/', query: otherQuery.value }); |
| | | } else { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'error' |
| | | }); |
| | | } |
| | | }).catch((error) => { |
| | | loading.value = false; |
| | | console.log(error); |
| | | $message.error("网络异常"); |
| | | }) |
| | | } else { |
| | | $message.error("用户名或密码不能为空"); |
| | | } |
| | | } |
| | | |
| | | function normalLogin() { |
| | | loginFormRef.value.validate(valid => { |
| | | return new Promise((resolve, reject) => { |
| | | if (valid) { |
| | | loading.value = true; |
| | | login(loginForm) |
| | | .then((res) => { |
| | | loading.value = false; |
| | | let { code, data, msg } = res; |
| | | if (code && data) { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'success' |
| | | }); |
| | | router.push({ path: redirect.value || '/', query: otherQuery.value }); |
| | | } else { |
| | | ElMessage({ |
| | | message: msg, |
| | | type: 'error' |
| | | }); |
| | | } |
| | | }).catch((error) => { |
| | | loading.value = false; |
| | | console.log('error', error, '============='); |
| | | |
| | | if (error?.message === 'Network Error') { |
| | | // 如果是网络错误,显示中文消息 |
| | | ElMessage({ |
| | | message: '网络错误,请检查您的网络连接或服务器状态。', |
| | | type: 'error' |
| | | }); |
| | | } else { |
| | | ElMessage({ |
| | | message: error, |
| | | type: 'warning' |
| | | }); |
| | | } |
| | | }).finally(() => { |
| | | loading.value = false; |
| | | resolve(); |
| | | }); |
| | | } else { |
| | | reject(); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | function getOtherQuery(query) { |
| | | return Object.keys(query).reduce((acc, cur) => { |
| | | if (cur !== 'redirect') { |
| | | acc[cur] = query[cur]; |
| | | } |
| | | return acc; |
| | | }, {}); |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | |
| | | |
| | | $bg: #283443; |
| | | $light_gray: #fff; |
| | | $cursor: #fff; |
| | | $cursor: #999; |
| | | $input_bg: rgba(0, 0, 0, 0.1); |
| | | $input_color: #000; |
| | | |
| | | @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { |
| | | .login-container .el-input input { |
| | |
| | | |
| | | input { |
| | | padding: 12px 5px 12px 15px; |
| | | color: $light_gray; |
| | | color: $input_color; |
| | | height: 47px; |
| | | caret-color: $cursor; |
| | | |
| | | &:-webkit-autofill { |
| | | box-shadow: 0 0 0px 1000px $bg inset !important; |
| | | -webkit-text-fill-color: $cursor !important; |
| | | box-shadow: 0 0 0px 1000px $input_bg inset !important; |
| | | -webkit-text-fill-color: $input_color !important; |
| | | } |
| | | } |
| | | } |
| | |
| | | .login-container { |
| | | min-height: 100%; |
| | | width: 100%; |
| | | background-image: url("./images/login_bg.jpg"); |
| | | background-image: url("@/assets/images/login-bg.jpg"); |
| | | background-size: 100% 100%; |
| | | background-repeat: no-repeat; |
| | | overflow: hidden; |
| | | |
| | | .login-form { |
| | | .login-wrap { |
| | | // display: none; |
| | | position: relative; |
| | | width: 520px; |
| | | max-width: 100%; |
| | | padding: 36px 35px 36px; |
| | | // margin: 260px 10% 0 auto; |
| | | margin: 260px auto 0; |
| | | transform: translate(clamp(0px, calc(36vw - 50%), 50vw), 0); |
| | | padding: 8px; |
| | | overflow: hidden; |
| | | background-color: #1d4167; |
| | | // background-color: #1d4167; |
| | | background: rgba(255, 255, 255, 0.2); |
| | | border: 2px solid #0d3c68; |
| | | |
| | | .login-form { |
| | | background: #fff; |
| | | padding: 36px 70px 36px; |
| | | border: 2px solid #064ec3; |
| | | } |
| | | .input-item { |
| | | margin-bottom: 28px; |
| | | } |
| | | } |
| | | |
| | | .site-title { |
| | | font-size: 30px; |
| | | font-weight: 700; |
| | | color: #07fcff; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 12%; |
| | | transform: translate(clamp(0px, calc(18vw - 50%), 50vw), -50%); |
| | | } |
| | | |
| | | .tips { |
| | |
| | | } |
| | | } |
| | | |
| | | .img-hm { |
| | | position: absolute; |
| | | width: clamp(500px, 50vw, 800px); |
| | | height: clamp(300px, 80vh, 80vh); |
| | | background: url(@/assets/images/img-hm.png) center center / contain no-repeat; |
| | | left: 0; |
| | | top: 20%; |
| | | transform: translate(clamp(0px, calc(24vw - 50%), 50vw), 0); |
| | | } |
| | | |
| | | .svg-container { |
| | | padding: 6px 5px 6px 15px; |
| | | color: $dark_gray; |
| | |
| | | position: relative; |
| | | |
| | | .title { |
| | | font-size: 26px; |
| | | color: $light_gray; |
| | | font-size: 18px; |
| | | color: #0296f3; |
| | | margin: 0px auto 40px auto; |
| | | text-align: center; |
| | | // text-align: center; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | |
| | | .tools-container .state-error .iconfont { |
| | | color: #ff0000; |
| | | } |
| | | |
| | | :deep(.dialog-center) { |
| | | box-sizing: content-box; |
| | | } |