Merge remote-tracking branch 'origin/lei_dev' into hui_dev

This commit is contained in:
dh186609 2023-02-20 08:51:06 +08:00
commit 169bb4b072
19 changed files with 322 additions and 329 deletions

View File

@ -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": [

View File

@ -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
}
})
}

View File

@ -112,6 +112,7 @@ export default {
closeAll: 'closeAll',
fullscreen: 'fullscreen',
closeFullscreen: 'closeFullscreen',
favorite: 'favorite'
},
notFound: {
foundTitle: 'Wrong address input, please re-enter the address~',

View File

@ -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: '地址输入错误,请重新输入地址~',

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
},
},
}
}
});

View File

@ -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, // 选择存储方式
},
],
},
});

View File

@ -29,6 +29,7 @@ declare interface RequestOldRoutesState {
declare interface TagsViewRoutesState<T = any> {
tagsViewRoutes: T[];
isTagsViewCurrenFull: Boolean;
favoriteRoutes: T[]
}
// 路由列表

View File

@ -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();

View File

@ -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);
};

View File

@ -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;

View File

@ -0,0 +1,6 @@
export default {
personal: {
name: 'personal info',
passwordRule: 'The two passwords are inconsistent'
}
}

View File

@ -0,0 +1,6 @@
export default {
personal: {
name: '个人信息',
passwordRule: '两次输入密码不一致'
}
}

View File

@ -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>

View File

@ -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',
},
];

View File

@ -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"