mirror of
https://gitee.com/log4j/pig-ui.git
synced 2024-12-23 05:40:20 +08:00
Merge remote-tracking branch 'origin/lei_dev' into hui_dev
This commit is contained in:
commit
169bb4b072
@ -47,6 +47,7 @@
|
||||
"vite": "^4.0.0",
|
||||
"vite-plugin-style-import": "^2.0.0",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"pinia-plugin-persist": "^1.0.0",
|
||||
"vue-eslint-parser": "^9.1.0"
|
||||
},
|
||||
"browserslist": [
|
||||
|
@ -63,6 +63,14 @@ export function editInfo(obj: Object) {
|
||||
})
|
||||
}
|
||||
|
||||
export function password(obj: Object){
|
||||
return request({
|
||||
url: '/admin/user/password',
|
||||
method: 'put',
|
||||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
*/
|
||||
@ -107,3 +115,5 @@ export function validatePhone(rule: any, value: any, callback: any, isEdit: bool
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,6 +112,7 @@ export default {
|
||||
closeAll: 'closeAll',
|
||||
fullscreen: 'fullscreen',
|
||||
closeFullscreen: 'closeFullscreen',
|
||||
favorite: 'favorite'
|
||||
},
|
||||
notFound: {
|
||||
foundTitle: 'Wrong address input, please re-enter the address~',
|
||||
|
@ -14,14 +14,6 @@ export default {
|
||||
limitsFrontEndBtn: '按钮权限',
|
||||
limitsBackEnd: '后端控制',
|
||||
limitsBackEndEndPage: '页面权限',
|
||||
menu: '菜单嵌套',
|
||||
menu1: '菜单1',
|
||||
menu11: '菜单11',
|
||||
menu12: '菜单12',
|
||||
menu121: '菜单121',
|
||||
menu122: '菜单122',
|
||||
menu13: '菜单13',
|
||||
menu2: '菜单2',
|
||||
funIndex: '功能',
|
||||
funTagsView: 'tagsView 操作',
|
||||
funCountup: '数字滚动',
|
||||
@ -112,6 +104,7 @@ export default {
|
||||
closeAll: '全部关闭',
|
||||
fullscreen: '当前页全屏',
|
||||
closeFullscreen: '关闭全屏',
|
||||
favorite: '收藏'
|
||||
},
|
||||
notFound: {
|
||||
foundTitle: '地址输入错误,请重新输入地址~',
|
||||
|
@ -70,13 +70,14 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="/home">{{ $t('user.dropdown1') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="/personal">{{ $t('user.dropdown2') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="personal">{{ $t('user.dropdown2') }}</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut">{{ $t('user.dropdown5') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<Search ref="searchRef" />
|
||||
<global-websocket uri="/admin/ws/info" v-if="websocketEnable" @rollback="rollback" />
|
||||
<personal-drawer ref="personalDrawerRef"></personal-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -100,6 +101,8 @@ const GlobalWebsocket = defineAsyncComponent(() => import('/@/components/Websock
|
||||
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
|
||||
const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
|
||||
|
||||
const personalDrawer = defineAsyncComponent(() => import("/@/views/personal/index.vue"))
|
||||
|
||||
// 定义变量内容
|
||||
const { locale, t } = useI18n();
|
||||
const router = useRouter();
|
||||
@ -109,6 +112,7 @@ const { userInfos } = storeToRefs(stores);
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const searchRef = ref();
|
||||
const newsRef = ref();
|
||||
const personalDrawerRef = ref()
|
||||
|
||||
const state = reactive({
|
||||
isScreenfull: false,
|
||||
@ -179,8 +183,9 @@ const onHandleCommandClick = (path: string) => {
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
} else if (path === 'wareHouse') {
|
||||
window.open('https://gitee.com/lyt-top/vue-next-admin');
|
||||
} else if (path === 'personal') {
|
||||
// 打开个人页面
|
||||
personalDrawerRef.value.open()
|
||||
} else {
|
||||
router.push(path);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
aria-disabled="false"
|
||||
tabindex="-1"
|
||||
:key="k"
|
||||
v-if="!v.affix"
|
||||
v-if="!v.affix && v.show"
|
||||
@click="onCurrentContextmenuClick(v.contextMenuClickId)"
|
||||
>
|
||||
<SvgIcon :name="v.icon" />
|
||||
@ -31,6 +31,10 @@
|
||||
|
||||
<script setup lang="ts" name="layoutTagsViewContextmenu">
|
||||
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||
import {storeToRefs} from "pinia";
|
||||
import {useTagsViewRoutes} from "/@/stores/tagsViewRoutes";
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { favoriteRoutes } = storeToRefs(storesTagsViewRoutes);
|
||||
|
||||
// 定义父组件传过来的值
|
||||
const props = defineProps({
|
||||
@ -52,16 +56,24 @@ const emit = defineEmits(['currentContextmenuClick']);
|
||||
const state = reactive({
|
||||
isShow: false,
|
||||
dropdownList: [
|
||||
{ contextMenuClickId: 0, txt: 'tagsView.refresh', affix: false, icon: 'ele-RefreshRight' },
|
||||
{ contextMenuClickId: 1, txt: 'tagsView.close', affix: false, icon: 'ele-Close' },
|
||||
{ contextMenuClickId: 2, txt: 'tagsView.closeOther', affix: false, icon: 'ele-CircleClose' },
|
||||
{ contextMenuClickId: 3, txt: 'tagsView.closeAll', affix: false, icon: 'ele-FolderDelete' },
|
||||
{ contextMenuClickId: 0, txt: 'tagsView.refresh', affix: false,show: true, icon: 'ele-RefreshRight' },
|
||||
{ contextMenuClickId: 1, txt: 'tagsView.close', affix: false,show: true, icon: 'ele-Close' },
|
||||
{ contextMenuClickId: 2, txt: 'tagsView.closeOther', affix: false,show: true, icon: 'ele-CircleClose' },
|
||||
{ contextMenuClickId: 3, txt: 'tagsView.closeAll', affix: false,show: true, icon: 'ele-FolderDelete' },
|
||||
{
|
||||
contextMenuClickId: 4,
|
||||
txt: 'tagsView.fullscreen',
|
||||
affix: false,
|
||||
show: true,
|
||||
icon: 'iconfont icon-fullscreen',
|
||||
},
|
||||
{
|
||||
contextMenuClickId: 5,
|
||||
txt: 'tagsView.favorite',
|
||||
affix: false,
|
||||
show: true,
|
||||
icon: 'ele-Star',
|
||||
},
|
||||
],
|
||||
item: {},
|
||||
arrowLeft: 10,
|
||||
@ -87,6 +99,13 @@ const onCurrentContextmenuClick = (contextMenuClickId: number) => {
|
||||
const openContextmenu = (item: RouteItem) => {
|
||||
state.item = item;
|
||||
item.meta?.isAffix ? (state.dropdownList[1].affix = true) : (state.dropdownList[1].affix = false);
|
||||
if(!favoriteRoutes.value.find(route => route.path === item.path)){
|
||||
state.dropdownList[5].show = true
|
||||
}else{
|
||||
state.dropdownList[5].show = false
|
||||
}
|
||||
|
||||
|
||||
closeContextmenu();
|
||||
setTimeout(() => {
|
||||
state.isShow = true;
|
||||
|
@ -60,6 +60,7 @@ import { Session } from '/@/utils/storage';
|
||||
import { isObjectValueEqual } from '/@/utils/arrayOperation';
|
||||
import other from '/@/utils/other';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
|
||||
// 引入组件
|
||||
const Contextmenu = defineAsyncComponent(() => import('/@/layout/navBars/tagsView/contextmenu.vue'));
|
||||
@ -73,7 +74,7 @@ const stores = useTagsViewRoutes();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { tagsViewRoutes } = storeToRefs(storesTagsViewRoutes);
|
||||
const { tagsViewRoutes,favoriteRoutes } = storeToRefs(storesTagsViewRoutes);
|
||||
const storesKeepALiveNames = useKeepALiveNames();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@ -362,8 +363,20 @@ const onCurrentContextmenuClick = async (item: RouteItem) => {
|
||||
// 开启当前页面全屏
|
||||
openCurrenFullscreen(getThemeConfig.value.isShareTagsView ? path : url);
|
||||
break;
|
||||
case 5:
|
||||
favoriteRoute(item)
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const favoriteRoute = (item: RouteItem) => {
|
||||
if(!favoriteRoutes.value.find(o => o.path === item.path)){
|
||||
storesTagsViewRoutes.setFavoriteRoutes(item)
|
||||
}else{
|
||||
useMessage().error("已经存在收藏")
|
||||
}
|
||||
}
|
||||
|
||||
// 右键点击时:传 x,y 坐标值到子组件中(props)
|
||||
const onContextmenu = (v: RouteItem, e: MouseEvent) => {
|
||||
const { clientX, clientY } = e;
|
||||
|
@ -1,8 +1,10 @@
|
||||
// https://pinia.vuejs.org/
|
||||
import { createPinia } from 'pinia';
|
||||
import piniaPluginPersist from 'pinia-plugin-persist'
|
||||
|
||||
// 创建
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersist)
|
||||
|
||||
// 导出
|
||||
export default pinia;
|
||||
|
@ -10,7 +10,7 @@ export const useRoutesList = defineStore('routesList', {
|
||||
state: (): RoutesListState => ({
|
||||
routesList: [],
|
||||
isColumnsMenuHover: false,
|
||||
isColumnsNavHover: false,
|
||||
isColumnsNavHover: false
|
||||
}),
|
||||
actions: {
|
||||
async setRoutesList(data: Array<string>) {
|
||||
@ -21,6 +21,6 @@ export const useRoutesList = defineStore('routesList', {
|
||||
},
|
||||
async setColumnsNavHover(bool: Boolean) {
|
||||
this.isColumnsNavHover = bool;
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ export const useTagsViewRoutes = defineStore('tagsViewRoutes', {
|
||||
state: (): TagsViewRoutesState => ({
|
||||
tagsViewRoutes: [],
|
||||
isTagsViewCurrenFull: false,
|
||||
favoriteRoutes: []
|
||||
}),
|
||||
actions: {
|
||||
async setTagsViewRoutes(data: Array<string>) {
|
||||
@ -19,5 +20,20 @@ export const useTagsViewRoutes = defineStore('tagsViewRoutes', {
|
||||
Session.set('isTagsViewCurrenFull', bool);
|
||||
this.isTagsViewCurrenFull = bool;
|
||||
},
|
||||
async setFavoriteRoutes(item){
|
||||
this.favoriteRoutes.push(item)
|
||||
},
|
||||
async delFavoriteRoutes(item){
|
||||
this.favoriteRoutes.splice(this.favoriteRoutes.indexOf(item), 1)
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
key: 'tagsViewRoutes', //自定义 Key值
|
||||
storage: localStorage, // 选择存储方式
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
1
src/types/pinia.d.ts
vendored
1
src/types/pinia.d.ts
vendored
@ -29,6 +29,7 @@ declare interface RequestOldRoutesState {
|
||||
declare interface TagsViewRoutesState<T = any> {
|
||||
tagsViewRoutes: T[];
|
||||
isTagsViewCurrenFull: Boolean;
|
||||
favoriteRoutes: T[]
|
||||
}
|
||||
|
||||
// 路由列表
|
||||
|
@ -95,6 +95,7 @@ const menuDialogFormRef = ref();
|
||||
// 定义需要的数据
|
||||
const state = reactive({
|
||||
ruleForm: {
|
||||
id: '',
|
||||
menuId: '',
|
||||
name: '',
|
||||
permission: '',
|
||||
@ -160,7 +161,7 @@ const dataRules = reactive({
|
||||
})
|
||||
// 打开弹窗
|
||||
const openDialog = (type: string, row?: any) => {
|
||||
if (row?.id) {
|
||||
if (row?.id && type === 'edit') {
|
||||
state.ruleForm.id = row.id
|
||||
// 模拟数据,实际请走接口
|
||||
info(row.id).then(res => {
|
||||
@ -170,7 +171,9 @@ const openDialog = (type: string, row?: any) => {
|
||||
// 清空表单,此项需加表单验证才能使用
|
||||
nextTick(() => {
|
||||
menuDialogFormRef?.value?.resetFields();
|
||||
state.ruleForm.parentId = row?.id || '-1'
|
||||
});
|
||||
|
||||
}
|
||||
visible.value = true;
|
||||
getMenuData();
|
||||
|
@ -39,7 +39,7 @@
|
||||
:show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column :label="$t('common.action')" show-overflow-tooltip width="200">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" @click="onOpenAddMenu('add')" v-auth="'sys_menu_add'"> {{
|
||||
<el-button text type="primary" @click="onOpenAddMenu('add',scope.row)" v-auth="'sys_menu_add'"> {{
|
||||
$t('common.addBtn')
|
||||
}}</el-button>
|
||||
<el-button text type="primary" @click="onOpenEditMenu('edit', scope.row)"
|
||||
@ -63,7 +63,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemMenu">
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { pageList, delObj } from '/@/api/admin/menu'
|
||||
import { useTable, BasicTableProps } from "/@/hooks/table";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
@ -85,11 +84,11 @@ const {
|
||||
} = useTable(state)
|
||||
|
||||
// 打开新增菜单弹窗
|
||||
const onOpenAddMenu = (type: string) => {
|
||||
menuDialogRef.value.openDialog(type);
|
||||
const onOpenAddMenu = (type: string,row?: any) => {
|
||||
menuDialogRef.value.openDialog(type,row);
|
||||
};
|
||||
// 打开编辑菜单弹窗
|
||||
const onOpenEditMenu = (type: string, row: RouteRecordRaw) => {
|
||||
const onOpenEditMenu = (type: string, row: any) => {
|
||||
menuDialogRef.value.openDialog(type, row);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,29 @@
|
||||
<template>
|
||||
<div class="home-container layout-pd">
|
||||
<el-row :gutter="15" class="home-card-three">
|
||||
<el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8">
|
||||
<div class="home-card-item">
|
||||
<div class="home-card-item-title">快捷导航工具</div>
|
||||
<div class="home-monitor">
|
||||
<div class="flex-warp">
|
||||
<div class="flex-warp-item" v-for="(v, k) in favoriteRoutes" :key="k">
|
||||
<div class="flex-warp-item-box">
|
||||
<div class="flex-margin">
|
||||
<i :class="v.meta.icon"></i>
|
||||
<el-tag :key="v.path" @click="HandleRoute(v)" class="mx-1" closable :type="v.path" @close="handleCloseFavorite(v)">{{ $t(v.name) }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16" class="home-media">
|
||||
<div class="home-card-item">
|
||||
<div style="height: 100%" ref="homeBarRef"></div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="15" class="home-card-one mb15">
|
||||
<el-col
|
||||
:xs="24"
|
||||
@ -37,31 +61,6 @@
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="15" class="home-card-three">
|
||||
<el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8">
|
||||
<div class="home-card-item">
|
||||
<div class="home-card-item-title">快捷导航工具</div>
|
||||
<div class="home-monitor">
|
||||
<div class="flex-warp">
|
||||
<div class="flex-warp-item" v-for="(v, k) in state.homeThree" :key="k">
|
||||
<div class="flex-warp-item-box" :class="`home-animation${k}`">
|
||||
<div class="flex-margin">
|
||||
<i :class="v.icon" :style="{ color: v.iconColor }"></i>
|
||||
<span class="pl5">{{ v.label }}</span>
|
||||
<div class="mt10">{{ v.value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16" class="home-media">
|
||||
<div class="home-card-item">
|
||||
<div style="height: 100%" ref="homeBarRef"></div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -71,7 +70,8 @@ import * as echarts from 'echarts';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
// 定义变量内容
|
||||
const homeLineRef = ref();
|
||||
const homePieRef = ref();
|
||||
@ -79,7 +79,7 @@ const homeBarRef = ref();
|
||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||
const { isTagsViewCurrenFull,favoriteRoutes } = storeToRefs(storesTagsViewRoutes);
|
||||
const state = reactive({
|
||||
global: {
|
||||
homeChartOne: null,
|
||||
@ -125,62 +125,6 @@ const state = reactive({
|
||||
color3: '--el-color-danger',
|
||||
},
|
||||
],
|
||||
homeThree: [
|
||||
{
|
||||
icon: 'iconfont icon-yangan',
|
||||
label: '浅粉红',
|
||||
value: '2.1%OBS/M',
|
||||
iconColor: '#F72B3F',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-wendu',
|
||||
label: '深红(猩红)',
|
||||
value: '30℃',
|
||||
iconColor: '#91BFF8',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-shidu',
|
||||
label: '淡紫红',
|
||||
value: '57%RH',
|
||||
iconColor: '#88D565',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-shidu',
|
||||
label: '弱紫罗兰红',
|
||||
value: '107w',
|
||||
iconColor: '#88D565',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-zaosheng',
|
||||
label: '中紫罗兰红',
|
||||
value: '57DB',
|
||||
iconColor: '#FBD4A0',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-zaosheng',
|
||||
label: '紫罗兰',
|
||||
value: '57PV',
|
||||
iconColor: '#FBD4A0',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-zaosheng',
|
||||
label: '暗紫罗兰',
|
||||
value: '517Cpd',
|
||||
iconColor: '#FBD4A0',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-zaosheng',
|
||||
label: '幽灵白',
|
||||
value: '12kg',
|
||||
iconColor: '#FBD4A0',
|
||||
},
|
||||
{
|
||||
icon: 'iconfont icon-zaosheng',
|
||||
label: '海军蓝',
|
||||
value: '64fm',
|
||||
iconColor: '#FBD4A0',
|
||||
},
|
||||
],
|
||||
myCharts: [] as EmptyArrayType,
|
||||
charts: {
|
||||
theme: '',
|
||||
@ -189,6 +133,15 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const HandleRoute = (item: any) => {
|
||||
router.push(item.path)
|
||||
}
|
||||
|
||||
const handleCloseFavorite = (item: any) => {
|
||||
storesTagsViewRoutes.delFavoriteRoutes(item)
|
||||
}
|
||||
|
||||
|
||||
// 折线图
|
||||
const initLineChart = () => {
|
||||
if (!state.global.dispose.some((b: any) => b === state.global.homeChartOne)) state.global.homeChartOne.dispose();
|
||||
@ -600,7 +553,7 @@ $homeNavLengh: 8;
|
||||
height: 100%;
|
||||
.flex-warp-item {
|
||||
width: 25%;
|
||||
height: 111px;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
.flex-warp-item-box {
|
||||
margin: auto;
|
||||
|
6
src/views/personal/i18n/en.ts
Normal file
6
src/views/personal/i18n/en.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
personal: {
|
||||
name: 'personal info',
|
||||
passwordRule: 'The two passwords are inconsistent'
|
||||
}
|
||||
}
|
6
src/views/personal/i18n/zh-cn.ts
Normal file
6
src/views/personal/i18n/zh-cn.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
personal: {
|
||||
name: '个人信息',
|
||||
passwordRule: '两次输入密码不一致'
|
||||
}
|
||||
}
|
@ -1,161 +1,137 @@
|
||||
<template>
|
||||
<div class="personal layout-pd">
|
||||
<el-row>
|
||||
<!-- 个人信息 -->
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" header="个人信息">
|
||||
<div class="personal-user">
|
||||
<div class="personal-user-left">
|
||||
<image-upload class="h100 personal-user-left-upload" @change="handleAvatarSuccess">
|
||||
<img v-if="formData.avatar" :src="formData.avatar" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</image-upload>
|
||||
</div>
|
||||
<div class="personal-user-right">
|
||||
<el-row>
|
||||
<el-col :span="24" class="personal-title mb18">{{
|
||||
currentTime
|
||||
}},admin! </el-col>
|
||||
<el-col :span="24">
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="8" class="personal-item mb6">
|
||||
<div class="personal-item-label">昵称:</div>
|
||||
<div class="personal-item-value">{{ formData.nickname }}</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="16" class="personal-item mb6">
|
||||
<div class="personal-item-label">身份:</div>
|
||||
<div class="personal-item-value">超级管理</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="8" class="personal-item mb6">
|
||||
<div class="personal-item-label">登录IP:</div>
|
||||
<div class="personal-item-value">192.168.1.1</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="16" class="personal-item mb6">
|
||||
<div class="personal-item-label">登录时间:</div>
|
||||
<div class="personal-item-value">2021-02-05 18:47:26</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-drawer v-model="visible" :title="$t('personal.name')" size="50%">
|
||||
<el-tabs style="height: 200px" class="demo-tabs">
|
||||
<el-tab-pane label="基本信息">
|
||||
<el-card shadow="hover" class="layout-padding-auto">
|
||||
<el-form :model="formData" :rules="ruleForm" label-width="100px" class="mt35 mb35" ref="formdataRef">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="用户名" prop="avatar">
|
||||
<image-upload class="h100 personal-user-left-upload" @change="handleAvatarSuccess">
|
||||
<img v-if="formData.avatar" :src="formData.avatar" class="avatar" />
|
||||
<el-icon v-else class="avatar-uploader-icon">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</image-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="formData.username" clearable disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="手机" prop="phone">
|
||||
<el-input v-model="formData.phone" placeholder="请输入手机" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 更新信息 -->
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover" class="mt15 personal-edit" header="更新信息">
|
||||
<div class="personal-edit-title">基本信息</div>
|
||||
<el-form :model="formData" :rules="ruleForm" label-width="100px" class="mt35 mb35"
|
||||
ref="formdataRef">
|
||||
<el-row :gutter="35">
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="formData.username" clearable disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="手机" prop="phone">
|
||||
<el-input v-model="formData.phone" placeholder="请输入手机" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="formData.email" placeholder="请输入邮箱" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="formData.nickname" placeholder="请输入昵称" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入姓名" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="原密码" prop="password">
|
||||
<el-input v-model="formData.password" placeholder="请输入密码" clearable
|
||||
type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
|
||||
<el-form-item label="新密码" prop="newpassword1">
|
||||
<el-input v-model="formData.newpassword1" clearable type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
|
||||
<el-form-item label="确认密码" prop="newpassword2">
|
||||
<el-input v-model="formData.newpassword2" clearable type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
|
||||
<el-form-item label="社交登录" prop="social">
|
||||
<div @click="handleClick('wechat')">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="formData.email" placeholder="请输入邮箱" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="formData.nickname" placeholder="请输入昵称" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入姓名" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="社交登录" prop="social">
|
||||
<div @click="handleClick('wechat')">
|
||||
<span :style="{ backgroundColor: '#6ba2d6' }" class="container">
|
||||
<i class="iconfont icon-weixin" icon-class="wechat" />
|
||||
</span>
|
||||
<p class="title">微信</p>
|
||||
</div>
|
||||
<div @click="handleClick('tencent')">
|
||||
<p class="title">微信</p>
|
||||
</div>
|
||||
<div @click="handleClick('tencent')">
|
||||
<span :style="{ backgroundColor: '#8dc349' }" class="container">
|
||||
<i class="iconfont icon-qq" icon-class="qq" />
|
||||
</span>
|
||||
<p class="title">QQ</p>
|
||||
</div>
|
||||
<div @click="handleClick('gitee')">
|
||||
<p class="title">QQ</p>
|
||||
</div>
|
||||
<div @click="handleClick('gitee')">
|
||||
<span :style="{ backgroundColor: '#bf3030' }" class="container">
|
||||
<i class="iconfont icon-logo_gitee_icon" icon-class="qq" />
|
||||
</span>
|
||||
<p class="title">Gitee</p>
|
||||
</div>
|
||||
<div @click="handleClick('osc')">
|
||||
<p class="title">Gitee</p>
|
||||
</div>
|
||||
<div @click="handleClick('osc')">
|
||||
<span :style="{ backgroundColor: '#007B25' }" class="container">
|
||||
<i class="iconfont icon-oschina" icon-class="qq" />
|
||||
</span>
|
||||
<p class="title">开源中国</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<p class="title">开源中国</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :lg="24" :md="24" :sm="24" :xl="24" :xs="24">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSaveUser">
|
||||
<el-icon>
|
||||
<ele-Position />
|
||||
</el-icon>
|
||||
更新个人信息
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSaveUser">
|
||||
更新个人信息
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="安全信息">
|
||||
<el-card shadow="hover" class="layout-padding-auto">
|
||||
<el-form :model="passwordFormData" :rules="passwordRuleForm" label-width="100px" class="mt35 mb35" ref="passwordFormdataRef">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="原密码" prop="password">
|
||||
<el-input v-model="passwordFormData.password" placeholder="请输入密码" clearable
|
||||
type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="新密码" prop="newpassword1">
|
||||
<el-input v-model="passwordFormData.newpassword1" clearable type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="确认密码" prop="newpassword2">
|
||||
<el-input v-model="passwordFormData.newpassword2" clearable type="password"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleChangePassword">
|
||||
修改密码
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="personal">
|
||||
import { computed, reactive } from 'vue';
|
||||
import { formatAxis } from '/@/utils/formatTime';
|
||||
import { useUserInfo } from '/@/stores/userInfo';
|
||||
import { editInfo } from '/@/api/admin/user'
|
||||
import { editInfo, password } from '/@/api/admin/user'
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
import { rule } from "/@/utils/validate";
|
||||
import other from '/@/utils/other';
|
||||
import {Session} from "/@/utils/storage";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
||||
const ImageUpload = defineAsyncComponent(() => import('/@/components/Upload/Image.vue'))
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
// 定义变量内容
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
@ -164,38 +140,77 @@ const formData = reactive({
|
||||
avatar: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
password: '',
|
||||
newpassword1: '',
|
||||
newpassword2: ''
|
||||
});
|
||||
|
||||
const passwordFormData = reactive({
|
||||
password: '',
|
||||
newpassword1: '',
|
||||
newpassword2: ''
|
||||
})
|
||||
|
||||
const formdataRef = ref()
|
||||
const passwordFormdataRef = ref()
|
||||
|
||||
const ruleForm = reactive({
|
||||
password: [{ required: true, message: "密码不能为空", trigger: "blur" }],
|
||||
|
||||
phone: [{ required: true, message: "手机号不能为空", trigger: "blur" }, { validator: rule.validatePhone, trigger: 'blur' }],
|
||||
nickname: [{ required: true, message: "昵称不能为空", trigger: "blur" }],
|
||||
email: [{ required: true, message: "邮箱不能为空", trigger: "blur" }],
|
||||
name: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
|
||||
newpassword1: [{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "用户密码长度必须介于 6 和 20 之间",
|
||||
trigger: "blur"
|
||||
}]
|
||||
|
||||
})
|
||||
const validatorPassword2 = (rule: any, value: any, callback: any) => {
|
||||
if(value !== passwordFormData.newpassword1){
|
||||
callback(new Error(t('personal.passwordRule')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const passwordRuleForm = reactive({
|
||||
password: [{ required: true, message: "密码不能为空", trigger: "blur" }],
|
||||
newpassword1: [{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "用户密码长度必须介于 6 和 20 之间",
|
||||
trigger: "blur"
|
||||
}],
|
||||
newpassword2: [
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "用户密码长度必须介于 6 和 20 之间",
|
||||
trigger: "blur"
|
||||
},{ validator: validatorPassword2, trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const data = useUserInfo().userInfos
|
||||
Object.assign(formData, data.user)
|
||||
formData.password = ''
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 头像上传成功
|
||||
const handleAvatarSuccess = (url: any) => {
|
||||
formData.avatar = url;
|
||||
}
|
||||
|
||||
const handleChangePassword = () => {
|
||||
passwordFormdataRef.value.validate((valid: boolean) => {
|
||||
if (!valid) {
|
||||
return false
|
||||
}
|
||||
password(passwordFormData).then(() => {
|
||||
useMessage().success("修改成功")
|
||||
// 需要重新登录
|
||||
// 清除缓存/token等
|
||||
Session.clear();
|
||||
// 使用 reload 时,不需要调用 resetRoute() 重置路由
|
||||
window.location.reload();
|
||||
}).catch(err => {
|
||||
useMessage().error(err.msg)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 保存用户
|
||||
const handleSaveUser = () => {
|
||||
@ -214,12 +229,6 @@ const handleSaveUser = () => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 当前时间提示语
|
||||
const currentTime = computed(() => {
|
||||
return formatAxis(new Date());
|
||||
});
|
||||
|
||||
const handleClick = (thirdpart: string) => {
|
||||
let appid, client_id, redirect_uri, url;
|
||||
redirect_uri = encodeURIComponent(
|
||||
@ -241,6 +250,16 @@ const handleClick = (thirdpart: string) => {
|
||||
other.openWindow(url, thirdpart, 540, 540)
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
const data = useUserInfo().userInfos
|
||||
Object.assign(formData, data.user)
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* 消息通知
|
||||
* @returns 返回模拟数据
|
||||
*/
|
||||
export const newsInfoList = [
|
||||
{
|
||||
title: '[发布] 2021年02月28日发布基于 vue3.x + vite v1.0.0 版本',
|
||||
date: '02/28',
|
||||
link: 'https://gitee.com/lyt-top/vue-next-admin',
|
||||
},
|
||||
{
|
||||
title: '[发布] 2021年04月15日发布 vue2.x + webpack 重构版本',
|
||||
date: '04/15',
|
||||
link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
|
||||
},
|
||||
{
|
||||
title: '[重构] 2021年04月10日 重构 vue2.x + webpack v1.0.0 版本',
|
||||
date: '04/10',
|
||||
link: 'https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin/',
|
||||
},
|
||||
{
|
||||
title: '[预览] 2020年12月08日,基于 vue3.x 版本后台模板的预览',
|
||||
date: '12/08',
|
||||
link: 'http://lyt-top.gitee.io/vue-next-admin-preview/#/login',
|
||||
},
|
||||
{
|
||||
title: '[预览] 2020年11月15日,基于 vue2.x 版本后台模板的预览',
|
||||
date: '11/15',
|
||||
link: 'https://lyt-top.gitee.io/vue-prev-admin-preview/#/login',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 营销推荐
|
||||
* @returns 返回模拟数据
|
||||
*/
|
||||
export const recommendList = [
|
||||
{
|
||||
title: '优惠券',
|
||||
msg: '现金券、折扣券、营销必备',
|
||||
icon: 'ele-Food',
|
||||
bg: '#48D18D',
|
||||
iconColor: '#64d89d',
|
||||
},
|
||||
{
|
||||
title: '多人拼团',
|
||||
msg: '社交电商、开辟流量',
|
||||
icon: 'ele-ShoppingCart',
|
||||
bg: '#F95959',
|
||||
iconColor: '#F86C6B',
|
||||
},
|
||||
{
|
||||
title: '分销中心',
|
||||
msg: '轻松招募分销员,成功推广奖励',
|
||||
icon: 'ele-School',
|
||||
bg: '#8595F4',
|
||||
iconColor: '#92A1F4',
|
||||
},
|
||||
{
|
||||
title: '秒杀',
|
||||
msg: '超低价抢购引导更多销量',
|
||||
icon: 'ele-AlarmClock',
|
||||
bg: '#FEBB50',
|
||||
iconColor: '#FDC566',
|
||||
},
|
||||
];
|
12
yarn.lock
12
yarn.lock
@ -1621,6 +1621,13 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
|
||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pinia-plugin-persist@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmmirror.com/pinia-plugin-persist/-/pinia-plugin-persist-1.0.0.tgz#fc696f225527f30bd5955109fafadd43c725e888"
|
||||
integrity sha512-M4hBBd8fz/GgNmUPaaUsC29y1M09lqbXrMAHcusVoU8xlQi1TqgkWnnhvMikZwr7Le/hVyMx8KUcumGGrR6GVw==
|
||||
dependencies:
|
||||
vue-demi "^0.12.1"
|
||||
|
||||
pinia@^2.0.28:
|
||||
version "2.0.28"
|
||||
resolved "https://registry.npmjs.org/pinia/-/pinia-2.0.28.tgz"
|
||||
@ -2040,6 +2047,11 @@ vue-demi@*:
|
||||
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz"
|
||||
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
|
||||
|
||||
vue-demi@^0.12.1:
|
||||
version "0.12.5"
|
||||
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.12.5.tgz#8eeed566a7d86eb090209a11723f887d28aeb2d1"
|
||||
integrity sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==
|
||||
|
||||
vue-eslint-parser@^9.0.1, vue-eslint-parser@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user