main
lizhong 2 years ago
parent b9b4fa7473
commit d1d9098a64

@ -2,6 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/main" vcs="Git" />
</component>
</project>

@ -41,11 +41,10 @@ npm run preview
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
## 项目相关资料
[后台地址](http://research.mcnetmart.com/NEBnKkdLDW.php)
账号admin
密码a147258"
[原型图](https://eqbh1l.axshare.com)
[设计稿](https://lanhuapp.com/web/#/item/project/stage?tid=279a1988-b0b6-4aac-9ef2-c066ece4ddcf&pid=6cb69861-790d-4f5b-9e80-8c059a873c9a
)
[设计稿](https://lanhuapp.com/web/#/item/project/stage?tid=279a1988-b0b6-4aac-9ef2-c066ece4ddcf&pid=6cb69861-790d-4f5b-9e80-8c059a873c9a )

@ -5,6 +5,7 @@ export default new class Common extends Http<ResOptions<any>> {
private readonly upload = '/common/upload'
private readonly caseList = '/cases/lists'
private readonly bottomMenu = '/index/bottomMenu'
private readonly login_url = '/user/login'
handleUpload(file: any) {
const formData = new FormData();
formData.append('file', file)
@ -17,5 +18,9 @@ export default new class Common extends Http<ResOptions<any>> {
getBottomMenu() {
return this.get(this.bottomMenu)
}
login(data: any) {
return this.post(this.login_url,this.toFormData(data))
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -1,50 +1,73 @@
<template>
<el-header height="100px" :class="[prefixCls, 'flex', 'justify-between', store.getMenuTheme === 'dark'? 'is-host' : 'is-white']">
<ApplicationAppLogo />
<el-header height="100px"
:class="[prefixCls, 'flex', 'justify-between', store.getMenuTheme === 'dark'? 'is-host' : 'is-white']">
<ApplicationAppLogo/>
<el-menu
:default-active="$route.meta.parentPath || $route.path"
class="el-menu-demo"
mode="horizontal"
:ellipsis="false"
router
:default-active="$route.meta.parentPath || $route.path"
class="el-menu-demo"
mode="horizontal"
:ellipsis="false"
router
>
<el-menu-item @click="handleChange(item)" v-for="item in routes" :index="item.path" :key="item.path">{{ item.name }}</el-menu-item>
<el-menu-item @click="handleChange(item)" v-for="item in routes" :index="item.path"
:key="item.path">{{ item.name }}
</el-menu-item>
</el-menu>
<div v-if="!token" @click="setLoginVisible(true)"></div>
<el-dropdown v-else trigger="click">
<span class="el-dropdown-link">
登录
<el-icon class="el-icon--right"><ElIconCaretBottom/></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>OCR识别</el-dropdown-item>
<el-dropdown-item>优化翻译</el-dropdown-item>
<el-dropdown-item>翻译文本</el-dropdown-item>
<el-dropdown-item>翻译文件</el-dropdown-item>
<el-dropdown-item>推出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
</template>
<script setup>
import {useDesign} from "/composables/useDesign";
// import {useAppStore} from "/stores/app";
const { prefixCls } = useDesign('header-wrap')
const {prefixCls} = useDesign('header-wrap')
const route = useRoute()
const router = useRouter();
const routes = ref(router.getRoutes().filter(it=> !it.meta.hidden));
routes.value.sort((a,b)=> a.meta.order - b.meta.order);
const routes = ref(router.getRoutes().filter(it => !it.meta.hidden));
routes.value.sort((a, b) => a.meta.order - b.meta.order);
const activeRoute = ref(route.path)
const store = useAppStore()
const { setLoginVisible } = useUserInfo()
const token = computed(()=> useUserInfo().$state.token);
onMounted(()=>{
console.log('token>>>>>', token)
})
function handleChange(val) {
activeRoute.value = val.path;
if(val.meta.hasOwnProperty('headerHost') && val.meta.headerHost) {
if (val.meta.hasOwnProperty('headerHost') && val.meta.headerHost) {
store.setMenuTheme('dark')
}else {
} else {
store.setMenuTheme('light')
}
}
watch(()=> route, (val)=>{
watch(() => route, (val) => {
activeRoute.value = val.path;
if(val.meta.hasOwnProperty('headerHost') && val.meta.headerHost) {
if (val.meta.hasOwnProperty('headerHost') && val.meta.headerHost) {
store.setMenuTheme('dark')
}else {
} else {
store.setMenuTheme('light')
}
}, {deep: true})
watchEffect(()=>{
watchEffect(() => {
handleChange(route)
})
</script>
@ -57,13 +80,14 @@ $prefix-cls: '#{$name-prefix}-header-wrap';
:deep(.el-menu) {
@apply bg-transparent;
border-bottom: unset;
.el-menu-item {
border-bottom: unset;
//font-size: 20px;
transition: font-size .5s;
background-color: unset;
@apply relative text-xl;
&:after{
&:after {
content: '';
width: 50%;
height: 8px;
@ -73,36 +97,43 @@ $prefix-cls: '#{$name-prefix}-header-wrap';
transform: translateX(-50%);
@apply bg-transparent absolute;
}
&:hover{
&:hover {
color: unset;
}
&.is-active {
color: #333 !important;
@apply font-bold text-2xl;
&:after{
&:after {
@apply bg-black;
}
}
}
}
&.is-host{
&.is-host {
:deep(.el-menu) {
.el-menu-item {
color: $white !important;
&:hover{
&:hover {
color: unset;
}
&.is-active {
&:after{
&:after {
@apply bg-white;
}
}
}
}
:deep(.yangliu-app-logo__title){
:deep(.yangliu-app-logo__title) {
color: $white;
}
}
//height: 100px;
}
</style>

@ -0,0 +1,171 @@
<template>
<el-dialog
class="mai-login-modal"
v-model="loginVisible"
footer=""
header=""
:closable="false"
@close="onClose"
>
<el-form
class="p-4 enter-x"
:model="formData"
:rules="formRules"
ref="formRef"
>
<el-form-item name="account" class="enter-x">
<el-input
size="large"
v-model="formData.account"
placeholder="请输入账号"
class="fix-auto-fill"
/>
</el-form-item>
<el-form-item name="password" class="enter-x">
<el-input
type="password"
size="large"
v-model="formData.password"
placeholder="请输入密码"
/>
</el-form-item>
<el-form-item name="captcha" class="enter-x">
<el-input
size="large"
v-model="formData.captcha"
placeholder="请输入验证码"
>
<template #append>
<img src="~@/assets/images/testCode.jpg" alt="" />
</template>
</el-input>
</el-form-item>
<el-form-item class="enter-x">
<el-button type="primary" size="large" block @click="handleLogin(formRef)" :loading="loading">
登录
</el-button>
<!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
{{ t('sys.login.registerButton') }}
</Button> -->
</el-form-item>
</el-form>
</el-dialog>
</template>
<script lang="ts" setup>
import { computed, reactive, ref, unref } from 'vue';
import {FormInstance} from "element-plus";
const userStore = useUserInfo();
const formRules = ref({
})
const formRef = ref<FormInstance>();
const loading = ref(false);
const formData = reactive({
account: 'vben',
password: '123456',
captcha: '123456',
});
const prefixCls = useDesign('login');
async function handleLogin(formEl: FormInstance | undefined) {
if (!formEl) return;
await formEl.validate(async (vail: boolean) => {
if (vail) {
loading.value = true;
const userInfo = await userStore.login({
...formData
});
if (userInfo) {
userStore.setLoginVisible(false);
ElMessage.success('登录成功');
}
loading.value = false;
}
})
}
const loginVisible = ref(userStore.getLoginVisible);
watchEffect(()=>{
loginVisible.value = userStore.getLoginVisible;
console.log('loginStatus>>>', loginVisible.value)
})
const onClose = () => {
userStore.setLoginVisible(false);
};
</script>
<style lang="less">
.mai-login-modal {
width: 1105px !important;
max-width: 1105px !important;
min-width: 1105px !important;
.ant-modal-content {
padding: 0 105px;
border-radius: 16px;
box-sizing: border-box;
h2 {
font-size: 48px;
line-height: 67px;
text-align: center;
padding-top: 54px;
p {
color: #999;
font-size: 28px;
line-height: 30px;
margin-top: 12px;
}
}
.ant-input {
height: 117px;
font-size: 32px;
border-radius: 8px;
padding: 0 60px;
}
.ant-input-suffix {
height: 100%;
.anticon {
font-size: 32px;
margin: 0 20px;
}
img {
width: 100%;
height: 100%;
}
}
.ant-input-password {
border-radius: 8px;
}
.ant-input-affix-wrapper {
display: flex;
align-items: center;
height: 119px;
padding: 0;
border-radius: 8px;
overflow: hidden;
}
.ant-btn {
font-size: 28px;
height: 106px;
margin-bottom: 107px;
background-color: #14417a;
border-radius: 8px;
}
}
}
</style>

@ -51,7 +51,7 @@ export default defineComponent({
]}
>
<span class="title">{item.name}</span>
<el-icon><el-ArrowRightBold /></el-icon>
<el-icon><el-icon-ArrowRightBold /></el-icon>
</div>
))}
</div>

@ -13,7 +13,7 @@ const useAppStore = defineStore('app', {
getters:{
getMenuTheme: (state)=> state.menuTheme,
getBannerTitle: (state)=> state.bannerTitle
getBannerTitle: (state)=> state.bannerTitle,
},
actions: {

@ -0,0 +1,49 @@
import {acceptHMRUpdate, createPinia, defineStore} from 'pinia';
type menu = 'light' | 'dark'
export interface UserState {
token: string;
info: any;
loginVisible: boolean;
}
const useUserInfo = defineStore('user', {
state: (): UserState => ({
token: '',
info: {},
loginVisible: false,
}),
actions: {
setToken(token: string):void {
this.token = token;
},
setInfo(info: any):void {
this.info = info;
},
setLoginVisible(val: boolean):void {
this.loginVisible = val;
},
async login(data: any){
const { commonApi } = useApi()
const res = await commonApi.login(data);
// if (res.data)
console.log('login>>>>', res)
return res;
}
},
getters:{
getLoginVisible:(state)=> state.loginVisible,
},
persist: process.client && {
storage: localStorage,
paths: ['info', 'token']
}
})
export default useUserInfo;
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useUserInfo, import.meta.hot))
}

@ -5,12 +5,20 @@
<!-- <div :style="`transition:margin .2s;height: 500px;background-color: tan;margin-top: ${store.getMenuTheme === 'dark' ? '-100px': 0}`"></div>-->
<slot />
<Footer />
<Login v-if="loginStatus" />
</template>
<script setup>
const store = useAppStore()
console.log('store>>>', store.getMenuTheme)
const loginStatus = ref(useUserInfo().getLoginVisible)
watchEffect(()=>{
loginStatus.value = useUserInfo().getLoginVisible;
console.log('loginStatus>>>', loginStatus.value)
})
// console.log()
</script>

@ -10,6 +10,9 @@ export default defineNuxtConfig({
'@nuxtjs/tailwindcss',
'@element-plus/nuxt',
],
plugins:[
{src: '~~/plugins/persits', mode: 'client'}
],
// routeRules: {
// "/": { static: true }, // ssr
// "/about": { static: false }, // spa 应用

@ -24,6 +24,7 @@
"element-plus": "^2.2.35",
"lodash-es": "^4.17.21",
"pinia": "^2.0.33",
"pinia-plugin-persistedstate": "^3.1.0",
"qs": "^6.11.1",
"sass": "^1.58.3",
"vue-i18n": "^9.2.2"

@ -0,0 +1,4 @@
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.$pinia.use(piniaPluginPersistedstate)
})

@ -77,8 +77,8 @@ export default class Http<T> {
return fetch<T>(url, {method: 'get', params, headers})
}
post(url: string, params?: any, headers?: any) {
return fetch<T>(url, {method: 'post', body:params, headers})
post(url: string, data?: any, headers?: any) {
return fetch<T>(url, {method: 'post', body:data, headers})
}
put(url: string, params?: any, headers?: any){

@ -4467,6 +4467,11 @@ pify@^4.0.1:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pinia-plugin-persistedstate@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-3.1.0.tgz#eada2b61ecd478fce88e490a685210415cd7a1b4"
integrity sha512-8UN+vYMEPBdgNLwceY08mi5olI0wkYaEb8b6hD6xW7SnBRuPydWHlEhZvUWgNb/ibuf4PvufpvtS+dmhYjJQOw==
pinia@>=2.0.31, pinia@^2.0.33:
version "2.0.33"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.33.tgz#b70065be697874d5824e9792f59bd5d87ddb5e7d"

Loading…
Cancel
Save