Commit 4cd0e3246821edf2e53d68196802f2bc6490b5ca
1 parent
861809b7
退出登录 权限管理 基本信息 物业代理登录
Showing
24 changed files
with
824 additions
and
111 deletions
src/api/request.ts
| 1 | 1 | import axios from 'axios' |
| 2 | 2 | import * as store from "@/pinia/index"; |
| 3 | 3 | import router from '@/router' |
| 4 | +import { ElMessage } from "element-plus"; | |
| 4 | 5 | |
| 5 | 6 | // 不这样写报ts类型错误,import...有一个多余的boolean类型 |
| 6 | 7 | let url: any = import.meta.env |
| ... | ... | @@ -27,16 +28,20 @@ instance.interceptors.response.use( |
| 27 | 28 | response => { |
| 28 | 29 | if(response) { |
| 29 | 30 | console.log(response?.data?.errorCode) |
| 31 | + switch (~~response?.data?.errorCode) { | |
| 32 | + case 0: | |
| 33 | + return response | |
| 34 | + break; | |
| 35 | + case 10002: | |
| 36 | + ElMessage.error("登录失效"); | |
| 37 | + router.push({ | |
| 38 | + path: 'login' | |
| 39 | + }) | |
| 40 | + break; | |
| 41 | + default: | |
| 42 | + ElMessage.error(response?.data?.errorMessage || '操作失败'); | |
| 43 | + } | |
| 30 | 44 | } |
| 31 | - switch(~~response?.data?.errorCode) { | |
| 32 | - case 10002: | |
| 33 | - console.log('跳转') | |
| 34 | - router.push({ | |
| 35 | - path: 'login' | |
| 36 | - }) | |
| 37 | - break; | |
| 38 | - } | |
| 39 | - return response | |
| 40 | 45 | }, |
| 41 | 46 | error => { |
| 42 | 47 | return Promise.reject(error) | ... | ... |
src/api/user/permission/index.ts
0 → 100644
| 1 | +import request from '../../request' | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @description 权限列表 | |
| 5 | + * @function permissionList | |
| 6 | + */ | |
| 7 | +export const permissionList = async () => { | |
| 8 | + let res: any = await request.get( '/permission/list' ) | |
| 9 | + return res | |
| 10 | +} | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * @description 权限编辑 | |
| 14 | + * @function permissionSave | |
| 15 | + */ | |
| 16 | + export const permissionSave = async (data: any) => { | |
| 17 | + let res: any = await request.post( '/permission/add', data ) | |
| 18 | + return res | |
| 19 | +} | |
| 20 | + | ... | ... |
src/layout/enter.vue
| ... | ... | @@ -4,11 +4,18 @@ |
| 4 | 4 | * @module Enter |
| 5 | 5 | * @author Tengxi |
| 6 | 6 | */ |
| 7 | -import { ref } from "vue"; | |
| 7 | +import { onMounted, reactive, computed } from "vue"; | |
| 8 | 8 | import Header from "./header.vue"; |
| 9 | 9 | import Menu from "./menu.vue"; |
| 10 | 10 | import * as store from "@/pinia/index"; |
| 11 | -let key = ref("/"); | |
| 11 | +let asyncData = reactive({ | |
| 12 | + isCollapse: null | |
| 13 | +}) | |
| 14 | +onMounted(() => { | |
| 15 | + asyncData.isCollapse = computed(() => { | |
| 16 | + return store.family.appStore().isCollapse | |
| 17 | + }) | |
| 18 | +}); | |
| 12 | 19 | </script> |
| 13 | 20 | |
| 14 | 21 | <template> |
| ... | ... | @@ -24,11 +31,11 @@ let key = ref("/"); |
| 24 | 31 | <!-- TIP 右侧具体页面内容 --> |
| 25 | 32 | <div |
| 26 | 33 | class="view-container" |
| 27 | - :class="store.family.appStore().isCollapse ? 'thinMenu' : 'fatMenu'" | |
| 34 | + :class="asyncData.isCollapse ? 'thinMenu' : 'fatMenu'" | |
| 28 | 35 | > |
| 29 | 36 | <router-view v-slot="{ Component, route }"> |
| 30 | - <transition :name="route.meta.transitionName"> | |
| 31 | - <keep-alive v-if="route.meta.keepAlive"> | |
| 37 | + <transition :name="route.name"> | |
| 38 | + <keep-alive v-if="route?.meta?.keepAlive"> | |
| 32 | 39 | <component :is="Component" /> |
| 33 | 40 | </keep-alive> |
| 34 | 41 | <component :is="Component" v-else /> | ... | ... |
src/layout/header.vue
| ... | ... | @@ -4,26 +4,47 @@ |
| 4 | 4 | * @module Header |
| 5 | 5 | * @author Tengxi |
| 6 | 6 | */ |
| 7 | -import { getCurrentInstance } from "vue"; | |
| 7 | +import { getCurrentInstance, onMounted, reactive, computed } from "vue"; | |
| 8 | 8 | import * as store from "@/pinia/index"; |
| 9 | 9 | import { Fold, Expand } from "@element-plus/icons-vue"; |
| 10 | -import styles from '@/style/global.module.scss'; | |
| 10 | +import styles from "@/style/global.module.scss"; | |
| 11 | 11 | // TIP 获取全局变量,暂时只有坏图片占位图 |
| 12 | 12 | const { |
| 13 | 13 | appContext: { |
| 14 | 14 | config: { globalProperties }, |
| 15 | 15 | }, |
| 16 | 16 | } = getCurrentInstance(); |
| 17 | -// TIP 侧边菜单collapse状态切换 | |
| 17 | +/** | |
| 18 | + * 侧边菜单collapse状态切换 | |
| 19 | + */ | |
| 18 | 20 | const toggleMenu = () => { |
| 19 | 21 | store.family.appStore().toggleCollapse(); |
| 20 | 22 | }; |
| 23 | +/** | |
| 24 | + * 退出登录 | |
| 25 | + */ | |
| 26 | +const handleLogout = () => { | |
| 27 | + store.family.loginStore().removeToken(); | |
| 28 | +}; | |
| 29 | +let asyncData = reactive({ | |
| 30 | + userInfo: "", | |
| 31 | + isCollapse: null, | |
| 32 | +}); | |
| 33 | +onMounted(() => { | |
| 34 | + asyncData.userInfo = store.family.loginStore().userName; | |
| 35 | + asyncData.isCollapse = computed(() => { | |
| 36 | + return store.family.appStore().isCollapse | |
| 37 | + }) | |
| 38 | +}); | |
| 21 | 39 | </script> |
| 22 | 40 | |
| 23 | 41 | <template> |
| 24 | 42 | <div class="header-container clearfix"> |
| 25 | 43 | <!-- TIP logo --> |
| 26 | - <div class="left-logo" :class="store.family.appStore().isCollapse? 'thinLogo': 'fatLogo'"> | |
| 44 | + <div | |
| 45 | + class="left-logo" | |
| 46 | + :class="asyncData.isCollapse ? 'thinLogo' : 'fatLogo'" | |
| 47 | + > | |
| 27 | 48 | <router-link to="/"> |
| 28 | 49 | <el-image |
| 29 | 50 | :src="globalProperties.$cnliveLogo" |
| ... | ... | @@ -35,8 +56,8 @@ const toggleMenu = () => { |
| 35 | 56 | <!-- TIP logo结束 --> |
| 36 | 57 | <!-- TIP 控制菜单collapse的按钮 --> |
| 37 | 58 | <div class="menu-collapse-button" @click="toggleMenu"> |
| 38 | - <Expand class="font-style" v-if="store.family.appStore().isCollapse" /> | |
| 39 | - <Fold class="font-style" v-if="!store.family.appStore().isCollapse" /> | |
| 59 | + <Expand class="font-style" v-if="asyncData.isCollapse" /> | |
| 60 | + <Fold class="font-style" v-if="!asyncData.isCollapse" /> | |
| 40 | 61 | </div> |
| 41 | 62 | <!-- TIP 控制菜单collapse的按钮结束 --> |
| 42 | 63 | <!-- TIP 功能键 --> |
| ... | ... | @@ -44,8 +65,10 @@ const toggleMenu = () => { |
| 44 | 65 | <el-button type="text">站内消息</el-button> |
| 45 | 66 | <el-button type="text"><router-link to="/">首页</router-link></el-button> |
| 46 | 67 | <el-button type="text">帮助</el-button> |
| 47 | - <el-button type="text">用户:管理员</el-button> | |
| 48 | - <el-button type="text">退出</el-button> | |
| 68 | + <el-button type="text" | |
| 69 | + >当前用户:<b>{{ asyncData.userInfo }}</b></el-button | |
| 70 | + > | |
| 71 | + <el-button type="text" @click="handleLogout">退出</el-button> | |
| 49 | 72 | </div> |
| 50 | 73 | <!-- TIP 功能键结束 --> |
| 51 | 74 | </div> |
| ... | ... | @@ -61,7 +84,7 @@ const toggleMenu = () => { |
| 61 | 84 | width: 100%; |
| 62 | 85 | line-height: 60px; |
| 63 | 86 | background-color: white; |
| 64 | - box-shadow: 0 1px 4px rgba(0,21,41,.08); | |
| 87 | + box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); | |
| 65 | 88 | .left-logo { |
| 66 | 89 | float: left; |
| 67 | 90 | margin-top: 10px; | ... | ... |
src/layout/menu.vue
| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | * @module Menu |
| 5 | 5 | * @author Tengxi |
| 6 | 6 | */ |
| 7 | -import { ref, computed } from "vue"; | |
| 7 | +import { ref, computed, onMounted, reactive } from "vue"; | |
| 8 | 8 | import * as store from "@/pinia/index"; |
| 9 | 9 | import styles from "@/style/global.module.scss"; |
| 10 | 10 | // TIP 使用element plus ICON |
| ... | ... | @@ -18,15 +18,20 @@ import { |
| 18 | 18 | let styleData = computed(() => { |
| 19 | 19 | return styles; |
| 20 | 20 | }); |
| 21 | -let menuData = computed(() => { | |
| 22 | - let res = store.family.menuStore().menuList; | |
| 23 | - return res; | |
| 21 | +let asyncData = reactive({ | |
| 22 | + menuData: [], | |
| 23 | + isCollapse: null | |
| 24 | +}) | |
| 25 | +onMounted(() => { | |
| 26 | + asyncData.menuData = store.family.menuStore().menuList | |
| 27 | + asyncData.isCollapse = computed(() => { | |
| 28 | + return store.family.appStore().isCollapse | |
| 29 | + }) | |
| 24 | 30 | }); |
| 25 | 31 | </script> |
| 26 | 32 | |
| 27 | 33 | <template> |
| 28 | 34 | <el-scrollbar wrap-class="scrollbar-wrapper"> |
| 29 | - <!-- {{menuData}} --> | |
| 30 | 35 | <el-menu |
| 31 | 36 | default-active="2" |
| 32 | 37 | :background-color="styleData.menuBg" |
| ... | ... | @@ -35,11 +40,11 @@ let menuData = computed(() => { |
| 35 | 40 | class="el-menu-vertical-demo" |
| 36 | 41 | :router="true" |
| 37 | 42 | :collapse-transition="false" |
| 38 | - :collapse="store.family.appStore().isCollapse" | |
| 43 | + :collapse="asyncData.isCollapse" | |
| 39 | 44 | > |
| 40 | 45 | <el-sub-menu |
| 41 | 46 | :index="index + ''" |
| 42 | - v-for="(item, index) in menuData" | |
| 47 | + v-for="(item, index) in asyncData.menuData" | |
| 43 | 48 | :key="index" |
| 44 | 49 | > |
| 45 | 50 | <template #title> |
| ... | ... | @@ -91,6 +96,24 @@ let menuData = computed(() => { |
| 91 | 96 | <el-menu-item index="/role">角色列表</el-menu-item> |
| 92 | 97 | </el-menu-item-group> |
| 93 | 98 | </el-sub-menu> |
| 99 | + <el-sub-menu index="15"> | |
| 100 | + <template #title> | |
| 101 | + <el-icon><location /></el-icon> | |
| 102 | + <span>权限管理真菜单可点</span> | |
| 103 | + </template> | |
| 104 | + <el-menu-item-group> | |
| 105 | + <el-menu-item index="/permission">权限列表</el-menu-item> | |
| 106 | + </el-menu-item-group> | |
| 107 | + </el-sub-menu> | |
| 108 | + <el-sub-menu index="16"> | |
| 109 | + <template #title> | |
| 110 | + <el-icon><location /></el-icon> | |
| 111 | + <span>系统管理真菜单可点</span> | |
| 112 | + </template> | |
| 113 | + <el-menu-item-group> | |
| 114 | + <el-menu-item index="/system">基本信息</el-menu-item> | |
| 115 | + </el-menu-item-group> | |
| 116 | + </el-sub-menu> | |
| 94 | 117 | </el-menu> |
| 95 | 118 | </el-scrollbar> |
| 96 | 119 | </template> | ... | ... |
src/pinia/modules/login.ts
| 1 | +import router from '@/router' | |
| 2 | +import { ElMessage } from "element-plus"; | |
| 1 | 3 | interface LoginUser { |
| 2 | 4 | token: string, |
| 3 | 5 | organizationId: number, |
| ... | ... | @@ -31,6 +33,13 @@ const actions = { |
| 31 | 33 | this.organizationId = obj.organizationId |
| 32 | 34 | this.id = obj.id |
| 33 | 35 | this.userName = obj.userName |
| 36 | + }, | |
| 37 | + removeToken(msg: string | null) { | |
| 38 | + this.token = '' | |
| 39 | + ElMessage.success(msg || '已退出登录'); | |
| 40 | + setTimeout(() => { | |
| 41 | + router.replace('/login') | |
| 42 | + }, 500) | |
| 34 | 43 | } |
| 35 | 44 | } |
| 36 | 45 | ... | ... |
src/router/index.ts
| 1 | 1 | import { createRouter, createWebHashHistory } from 'vue-router' |
| 2 | +import System from './modules/system' | |
| 3 | +import Permission from './modules/permission' | |
| 2 | 4 | import Role from "./modules/role" |
| 3 | 5 | import User from "./modules/user" |
| 4 | 6 | import Resident from "./modules/resident" |
| ... | ... | @@ -37,6 +39,8 @@ const routes: Array<any> = [ |
| 37 | 39 | }] |
| 38 | 40 | // component: () => import(/* webpackChunkName: "About" */ '@/views/tengxi/about.vue') |
| 39 | 41 | }, |
| 42 | + System, | |
| 43 | + Permission, | |
| 40 | 44 | Role, |
| 41 | 45 | User, |
| 42 | 46 | Resident, | ... | ... |
src/router/modules/permission.ts
0 → 100644
| 1 | +import Layout from '@/layout/enter.vue' | |
| 2 | +const permission = { | |
| 3 | + path: '/', | |
| 4 | + component: Layout, | |
| 5 | + name: 'Permission', | |
| 6 | + children: [{ | |
| 7 | + path: 'permission', | |
| 8 | + name: 'permission', | |
| 9 | + component: () => import('@/views/permission/index.vue'), | |
| 10 | + meta: { title: '权限管理' } | |
| 11 | + }, { | |
| 12 | + path: '/permission/edit', | |
| 13 | + name: 'permissionEdit', | |
| 14 | + component: () => import('@/views/permission/edit.vue'), | |
| 15 | + meta: { title: '权限编辑' } | |
| 16 | + }] | |
| 17 | +} | |
| 18 | + | |
| 19 | +export default permission | ... | ... |
src/router/modules/system.ts
0 → 100644
| 1 | +import Layout from '@/layout/enter.vue' | |
| 2 | +const system = { | |
| 3 | + path: '/', | |
| 4 | + component: Layout, | |
| 5 | + name: 'System', | |
| 6 | + children: [{ | |
| 7 | + path: 'system', | |
| 8 | + name: 'system', | |
| 9 | + component: () => import('@/views/system/info.vue'), | |
| 10 | + meta: { title: '基本信息' } | |
| 11 | + }] | |
| 12 | +} | |
| 13 | + | |
| 14 | +export default system | ... | ... |
src/style/element.scss
| ... | ... | @@ -9,6 +9,16 @@ |
| 9 | 9 | .el-scrollbar { |
| 10 | 10 | width: 100%; |
| 11 | 11 | } |
| 12 | -.el-form--inline .el-form-item { | |
| 13 | - margin-right: 0; | |
| 12 | +// .el-form--inline .el-form-item { | |
| 13 | + // margin-right: 0; | |
| 14 | +// } | |
| 15 | + | |
| 16 | +// 一行内多个表单项布局 | |
| 17 | +.card-form { | |
| 18 | + display: flex; | |
| 19 | + flex-wrap: wrap; | |
| 20 | + width: 100%; | |
| 21 | + .el-form-item { | |
| 22 | + margin-right: 0; | |
| 23 | + } | |
| 14 | 24 | } |
| 15 | 25 | \ No newline at end of file | ... | ... |
src/utils/tool.ts
| ... | ... | @@ -157,7 +157,7 @@ export function globalFilters (value: number, groupData: EnumData[]) { |
| 157 | 157 | |
| 158 | 158 | /** |
| 159 | 159 | * 请求参数包formData |
| 160 | - * @param {object}} data | |
| 160 | + * @param {object} data | |
| 161 | 161 | * @returns {FormData} fd |
| 162 | 162 | */ |
| 163 | 163 | export function formDataWrapper (data: any) { |
| ... | ... | @@ -170,7 +170,7 @@ export function formDataWrapper (data: any) { |
| 170 | 170 | |
| 171 | 171 | /** |
| 172 | 172 | * 请求参数删除为null的 |
| 173 | - * @param {object}} data | |
| 173 | + * @param {object} data | |
| 174 | 174 | * @returns {FormData} fd |
| 175 | 175 | */ |
| 176 | 176 | export function deleteEmptyParam (params: any) { | ... | ... |
src/views/permission/edit.vue
0 → 100644
| 1 | +<script setup lang="ts"> | |
| 2 | +import { reactive, ref, getCurrentInstance, onMounted } from "vue"; | |
| 3 | +import { permissionSave } from "@/api/user/permission"; | |
| 4 | +import { useRoute } from "vue-router"; | |
| 5 | +import type { ElForm } from "element-plus"; | |
| 6 | +let instance: ComponentInternalInstance | null = getCurrentInstance(); | |
| 7 | +let tempPriority = ref(0); | |
| 8 | +let form = reactive({ | |
| 9 | + data: { | |
| 10 | + name: "", | |
| 11 | + keyword: "", | |
| 12 | + parentId: 0, | |
| 13 | + priority: 0, | |
| 14 | + type: null, | |
| 15 | + url: "", | |
| 16 | + id: null, | |
| 17 | + }, | |
| 18 | + dataType: "", | |
| 19 | +}); | |
| 20 | +const ruleFormRef = ref<InstanceType<typeof ElForm>>(); | |
| 21 | +/** | |
| 22 | + * 表单验证规则 | |
| 23 | + */ | |
| 24 | +const rules = reactive({ | |
| 25 | + name: [ | |
| 26 | + { | |
| 27 | + required: true, | |
| 28 | + message: "请填写名称", | |
| 29 | + trigger: "change", | |
| 30 | + }, | |
| 31 | + ], | |
| 32 | + keyword: [ | |
| 33 | + { | |
| 34 | + required: true, | |
| 35 | + message: "请填写关键字", | |
| 36 | + trigger: "change", | |
| 37 | + }, | |
| 38 | + ], | |
| 39 | +}); | |
| 40 | +/** | |
| 41 | + * 数字输入框,值改变,排序值赋给表单数据中priority | |
| 42 | + * el-input-number v-model 绑 reactive({a: 0})报类型错误警告,绑b=ref(0)不报警告 | |
| 43 | + * @param {number} data 输入的数字 | |
| 44 | + */ | |
| 45 | +const handleChange = (data: number) => { | |
| 46 | + form.data.priority = data; | |
| 47 | +}; | |
| 48 | +/** | |
| 49 | + * 表单重置 | |
| 50 | + */ | |
| 51 | +const resetForm = (formEl: InstanceType<typeof ElForm> | undefined) => { | |
| 52 | + if (!formEl) return; | |
| 53 | + tempPriority = 0; | |
| 54 | + formEl.resetFields(); | |
| 55 | +}; | |
| 56 | +/** | |
| 57 | + * 表单提交 | |
| 58 | + */ | |
| 59 | +const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { | |
| 60 | + if (!formEl) return; | |
| 61 | + formEl.validate((valid) => { | |
| 62 | + if (valid) { | |
| 63 | + permissionSave(form.data) | |
| 64 | + .then((res) => { | |
| 65 | + if (res) { | |
| 66 | + instance?.proxy?.$message.success("操作成功"); | |
| 67 | + history.go(-1); | |
| 68 | + } | |
| 69 | + }) | |
| 70 | + .catch((error) => { | |
| 71 | + console.log(error); | |
| 72 | + }); | |
| 73 | + } else { | |
| 74 | + instance?.proxy?.$message.error("请检查表单格式"); | |
| 75 | + return false; | |
| 76 | + } | |
| 77 | + }); | |
| 78 | +}; | |
| 79 | +onMounted(() => { | |
| 80 | + form.dataType = useRoute().query.dataType; | |
| 81 | + if (form.dataType === "add") { | |
| 82 | + form.data.parentId = useRoute().query.id; | |
| 83 | + } else { | |
| 84 | + Object.keys(form.data).map((key) => { | |
| 85 | + form.data[key] = useRoute().query[key]; | |
| 86 | + }); | |
| 87 | + form.data.type = form.data.type? form.data.type.toString(): '' | |
| 88 | + } | |
| 89 | +}); | |
| 90 | +</script> | |
| 91 | + | |
| 92 | +<template> | |
| 93 | + <div class="page-container"> | |
| 94 | + <el-card class="form_card" style="max-width: 1303px"> | |
| 95 | + <h1 v-show="form.dataType === 'add'">新增权限</h1> | |
| 96 | + <h1 v-show="form.dataType === 'edit'">编辑权限</h1> | |
| 97 | + <el-form | |
| 98 | + :inline="true" | |
| 99 | + :model="form.data" | |
| 100 | + :rules="rules" | |
| 101 | + ref="ruleFormRef" | |
| 102 | + label-width="120px" | |
| 103 | + class="card-form" | |
| 104 | + > | |
| 105 | + <el-form-item label="上级权限" prop="parentId" style="width: 100%"> | |
| 106 | + <el-input | |
| 107 | + disabled | |
| 108 | + v-model="useRoute().query.name" | |
| 109 | + placeholder="请填写上级权限" | |
| 110 | + maxlength="15" | |
| 111 | + /> | |
| 112 | + </el-form-item> | |
| 113 | + <el-form-item label="权限名称" prop="name" style="width: 100%"> | |
| 114 | + <el-input | |
| 115 | + v-model.trim="form.data.name" | |
| 116 | + placeholder="请填写角色名称" | |
| 117 | + maxlength="15" | |
| 118 | + /> | |
| 119 | + </el-form-item> | |
| 120 | + <el-form-item label="关键字" prop="keyword" style="width: 50%"> | |
| 121 | + <el-input | |
| 122 | + v-model.trim="form.data.keyword" | |
| 123 | + placeholder="请填写关键字" | |
| 124 | + maxlength="20" | |
| 125 | + /> | |
| 126 | + </el-form-item> | |
| 127 | + <el-form-item label="路径" prop="url" style="width: 50%"> | |
| 128 | + <el-input | |
| 129 | + v-model.trim="form.data.url" | |
| 130 | + placeholder="请填写路径" | |
| 131 | + maxlength="15" | |
| 132 | + /> | |
| 133 | + </el-form-item> | |
| 134 | + <el-form-item label="排序" prop="priority" style="width: 100%"> | |
| 135 | + <el-input-number | |
| 136 | + v-model="tempPriority" | |
| 137 | + placeholder="请填写排序值" | |
| 138 | + :min="0" | |
| 139 | + :max="1000" | |
| 140 | + @change="handleChange" | |
| 141 | + /> | |
| 142 | + </el-form-item> | |
| 143 | + <!-- 不支持创建一级菜单,编辑的时候不可以修改菜单类型 --> | |
| 144 | + <!-- 一级菜单下只能创建二级菜单 --> | |
| 145 | + <!-- 二级菜单可以创建三级菜单或者按钮 --> | |
| 146 | + <!-- 三级菜单只能创建按钮 --> | |
| 147 | + <el-form-item label="权限类型" prop="type" style="width: 100%"> | |
| 148 | + <el-radio-group v-model="form.data.type" :disabled="form.dataType === 'edit'"> | |
| 149 | + <el-radio label="1" disabled>一级菜单</el-radio> | |
| 150 | + <el-radio label="2" :disabled="useRoute().query.type !== '1'" | |
| 151 | + >二级菜单</el-radio | |
| 152 | + > | |
| 153 | + <el-radio label="3" :disabled="useRoute().query.type !== '2'" | |
| 154 | + >三级菜单</el-radio | |
| 155 | + > | |
| 156 | + <el-radio label="4" :disabled="useRoute().query.type === '1'" | |
| 157 | + >按钮</el-radio | |
| 158 | + > | |
| 159 | + </el-radio-group> | |
| 160 | + </el-form-item> | |
| 161 | + <el-form-item style="width: 100%"> | |
| 162 | + <el-button type="primary" @click="submitForm(ruleFormRef)" | |
| 163 | + >提交</el-button | |
| 164 | + > | |
| 165 | + </el-form-item> | |
| 166 | + </el-form> | |
| 167 | + </el-card> | |
| 168 | + </div> | |
| 169 | +</template> | ... | ... |
src/views/permission/index.vue
0 → 100644
| 1 | +<script setup lang="ts"> | |
| 2 | +import { reactive, ref, onMounted } from "vue"; | |
| 3 | +import { permissionList } from "@/api/user/permission"; | |
| 4 | +interface Data { | |
| 5 | + loading: boolean; | |
| 6 | + list: any[] | null; | |
| 7 | +} | |
| 8 | +let data: Data = reactive({ | |
| 9 | + list: [], | |
| 10 | + loading: false, | |
| 11 | +}); | |
| 12 | +/** | |
| 13 | + * 列表 | |
| 14 | + */ | |
| 15 | +const getList = async () => { | |
| 16 | + data.loading = true; | |
| 17 | + try { | |
| 18 | + const res = await permissionList(); | |
| 19 | + data.list = res.data.data; | |
| 20 | + } catch (e) { | |
| 21 | + console.log(e); | |
| 22 | + } finally { | |
| 23 | + data.loading = false; | |
| 24 | + } | |
| 25 | +}; | |
| 26 | +/** | |
| 27 | + * 权限枚举值 | |
| 28 | + */ | |
| 29 | +enum typeEnum { | |
| 30 | + '一级菜单' = 1, | |
| 31 | + '二级菜单', | |
| 32 | + '三级菜单', | |
| 33 | + '按钮', | |
| 34 | + '默认权限' | |
| 35 | +} | |
| 36 | +onMounted(() => { | |
| 37 | + getList(); | |
| 38 | +}); | |
| 39 | +</script> | |
| 40 | + | |
| 41 | +<template> | |
| 42 | + <div class="page-container"> | |
| 43 | + <h1>权限列表</h1> | |
| 44 | + <el-table | |
| 45 | + :data="data.list" | |
| 46 | + style="width: 100%" | |
| 47 | + border fit | |
| 48 | + row-key="id" | |
| 49 | + :indent="30" | |
| 50 | + :tree-props="{ children: 'menuList' }" | |
| 51 | + v-loading="data.loading" | |
| 52 | + align="center" | |
| 53 | + element-loading-text="拼命加载中" | |
| 54 | + > | |
| 55 | + <el-table-column prop="id" label="ID" align="center"></el-table-column> | |
| 56 | + <el-table-column prop="name" label="权限名称" align="center"></el-table-column> | |
| 57 | + <el-table-column prop="priority" label="优先级" align="center"></el-table-column> | |
| 58 | + <el-table-column prop="url" label="路径" align="center"></el-table-column> | |
| 59 | + <el-table-column prop="type" label="类型" align="center"> | |
| 60 | + <template #default="scope"> | |
| 61 | + {{ typeEnum[scope.row.type] }} | |
| 62 | + </template> | |
| 63 | + </el-table-column> | |
| 64 | + <el-table-column label="操作" align="center"> | |
| 65 | + <template #default="scope"> | |
| 66 | + <el-button type="text" | |
| 67 | + ><router-link :to="{ path: '/permission/edit', query: {...scope.row, ...{dataType: 'edit'}} }" | |
| 68 | + >编辑</router-link | |
| 69 | + ></el-button | |
| 70 | + > | |
| 71 | + <!-- type值为4,是按钮,按钮不可以再加按钮 --> | |
| 72 | + <el-button type="text" v-show="~~scope.row.type < 4" | |
| 73 | + ><router-link :to="{ path: '/permission/edit', query: {...scope.row, ...{dataType: 'add'}} }" | |
| 74 | + >添加</router-link | |
| 75 | + ></el-button | |
| 76 | + > | |
| 77 | + </template> | |
| 78 | + </el-table-column> | |
| 79 | + </el-table> | |
| 80 | + </div> | |
| 81 | +</template> | ... | ... |
src/views/property/edit.vue
| ... | ... | @@ -15,7 +15,7 @@ let form = reactive({ |
| 15 | 15 | name: "", |
| 16 | 16 | userName: "", |
| 17 | 17 | userPhone: "", |
| 18 | - location: "北京", | |
| 18 | + location: "", | |
| 19 | 19 | address: "", |
| 20 | 20 | businessLicense: "", |
| 21 | 21 | contractNumber: "", |
| ... | ... | @@ -27,7 +27,12 @@ let form = reactive({ |
| 27 | 27 | }, |
| 28 | 28 | }); |
| 29 | 29 | const ruleFormRef = ref<InstanceType<typeof ElForm>>(); |
| 30 | -// 校验手机号格式 | |
| 30 | +/** | |
| 31 | + * 手机号校验 | |
| 32 | + * @param {object} rules 验证规则 | |
| 33 | + * @param {string} value 用户输入的手机号 | |
| 34 | + * @callback checkPhone~checkCallback | |
| 35 | + */ | |
| 31 | 36 | const checkPhone = (rules, value, callback) => { |
| 32 | 37 | if (validMobile(value)) { |
| 33 | 38 | callback(); |
| ... | ... | @@ -35,7 +40,9 @@ const checkPhone = (rules, value, callback) => { |
| 35 | 40 | callback(new Error("请填写格式正确的手机号码")); |
| 36 | 41 | } |
| 37 | 42 | }; |
| 38 | -// 表单验证规则 | |
| 43 | +/** | |
| 44 | + * 表单验证 | |
| 45 | + */ | |
| 39 | 46 | const rules = reactive({ |
| 40 | 47 | name: [ |
| 41 | 48 | { |
| ... | ... | @@ -142,7 +149,7 @@ onMounted(() => { |
| 142 | 149 | :rules="rules" |
| 143 | 150 | ref="ruleFormRef" |
| 144 | 151 | label-width="120px" |
| 145 | - style="display: flex; flex-wrap: wrap; width: 100%" | |
| 152 | + class="card-form" | |
| 146 | 153 | > |
| 147 | 154 | <el-form-item label="物业名称" prop="name" style="width: 50%"> |
| 148 | 155 | <el-input |
| ... | ... | @@ -170,15 +177,21 @@ onMounted(() => { |
| 170 | 177 | v-model.trim="form.data.userPhone" |
| 171 | 178 | placeholder="请填写联系电话" |
| 172 | 179 | maxlength="11" |
| 180 | + :disabled="form.dataType === 'edit'" | |
| 173 | 181 | /> |
| 174 | 182 | </el-form-item> |
| 175 | 183 | <el-form-item label="地区" prop="location" style="width: 50%"> |
| 176 | - <el-input | |
| 177 | - v-model.trim="form.data.location" | |
| 178 | - placeholder="请填写地区" | |
| 179 | - maxlength="11" | |
| 180 | - disabled | |
| 181 | - /> | |
| 184 | + <el-select | |
| 185 | + v-model="form.data.location" | |
| 186 | + placeholder="请选择地区" | |
| 187 | + clearable | |
| 188 | + > | |
| 189 | + <el-option | |
| 190 | + label="北京" | |
| 191 | + value="北京" | |
| 192 | + > | |
| 193 | + </el-option> | |
| 194 | + </el-select> | |
| 182 | 195 | </el-form-item> |
| 183 | 196 | <el-form-item label="详细地址" prop="address" style="width: 100%"> |
| 184 | 197 | <el-input | ... | ... |
src/views/property/index.vue
| 1 | 1 | <script setup lang="ts"> |
| 2 | 2 | import { reactive, ref, onMounted, getCurrentInstance } from "vue"; |
| 3 | 3 | import { propertyList, propertyStatus } from "@/api/property"; |
| 4 | +import { userProxy } from '@/api/user/user'; | |
| 4 | 5 | import { parseTime } from "@/utils/tool"; |
| 5 | 6 | import Pagination from "@/components/Pagination/index.vue"; |
| 6 | 7 | const { |
| ... | ... | @@ -34,7 +35,9 @@ let data = reactive({ |
| 34 | 35 | }, |
| 35 | 36 | }, |
| 36 | 37 | }); |
| 37 | -// 列表 | |
| 38 | +/** | |
| 39 | + * 列表 | |
| 40 | + */ | |
| 38 | 41 | const getList = async () => { |
| 39 | 42 | data.loading = true; |
| 40 | 43 | try { |
| ... | ... | @@ -47,17 +50,24 @@ const getList = async () => { |
| 47 | 50 | data.loading = false; |
| 48 | 51 | } |
| 49 | 52 | }; |
| 50 | -// 分页 | |
| 53 | +/** | |
| 54 | + * 分页 | |
| 55 | + */ | |
| 51 | 56 | const handlePageChange = (page, size) => { |
| 52 | 57 | data.params.query.page = page; |
| 53 | 58 | data.params.query.pageSize = size; |
| 54 | 59 | getList(); |
| 55 | 60 | }; |
| 56 | -// 查询 | |
| 61 | +/** | |
| 62 | + * 查询 | |
| 63 | + */ | |
| 57 | 64 | const handleSearch = () => { |
| 58 | 65 | getList(); |
| 59 | 66 | }; |
| 60 | -// 切换状态 | |
| 67 | +/** | |
| 68 | + * 切换状态 | |
| 69 | + * @param {object} 单条数据对象 | |
| 70 | + */ | |
| 61 | 71 | const handleStatus = async (obj) => { |
| 62 | 72 | try { |
| 63 | 73 | const res = await propertyStatus({ |
| ... | ... | @@ -74,7 +84,26 @@ const handleStatus = async (obj) => { |
| 74 | 84 | console.log(e); |
| 75 | 85 | } |
| 76 | 86 | }; |
| 77 | -// 状态值 | |
| 87 | +/** | |
| 88 | + * 代理登录 | |
| 89 | + * @param {object} 单条数据对象 | |
| 90 | + */ | |
| 91 | +const handleProxy = (obj) => { | |
| 92 | + userProxy({oId: obj.id}).then(res => { | |
| 93 | + if(res?.data) { | |
| 94 | + globalProperties.$message.success("代理成功"); | |
| 95 | + setTimeout(() => { | |
| 96 | + location.href = '/' | |
| 97 | + }, 500) | |
| 98 | + } else { | |
| 99 | + globalProperties.$message.error("代理失败"); | |
| 100 | + } | |
| 101 | + }) | |
| 102 | +} | |
| 103 | +/** | |
| 104 | + * 状态值 | |
| 105 | + * @enum {number} | |
| 106 | + */ | |
| 78 | 107 | enum statusEnum { |
| 79 | 108 | "禁用" = 0, |
| 80 | 109 | "启用", |
| ... | ... | @@ -157,11 +186,10 @@ onMounted(() => { |
| 157 | 186 | >编辑</router-link |
| 158 | 187 | ></el-button |
| 159 | 188 | > |
| 160 | - <el-button type="text" disabled>代理登录</el-button> | |
| 189 | + <el-button type="text" @click="handleProxy(scope.row)">代理登录</el-button> | |
| 161 | 190 | <el-button type="text" @click="handleStatus(scope.row)">{{ |
| 162 | 191 | scope.row.status ? "禁用" : "启用" |
| 163 | 192 | }}</el-button> |
| 164 | - <el-button type="text" disabled>删除</el-button> | |
| 165 | 193 | </template> |
| 166 | 194 | </el-table-column> |
| 167 | 195 | </el-table> | ... | ... |
src/views/role/edit.vue
| ... | ... | @@ -17,7 +17,9 @@ let form = reactive({ |
| 17 | 17 | dataType: "", |
| 18 | 18 | }); |
| 19 | 19 | const ruleFormRef = ref<InstanceType<typeof ElForm>>(); |
| 20 | -// 表单验证规则 | |
| 20 | +/** | |
| 21 | + * 表单验证规则 | |
| 22 | + */ | |
| 21 | 23 | const rules = reactive({ |
| 22 | 24 | roleName: [ |
| 23 | 25 | { |
| ... | ... | @@ -34,12 +36,16 @@ const rules = reactive({ |
| 34 | 36 | }, |
| 35 | 37 | ], |
| 36 | 38 | }); |
| 37 | -// 表单重置 | |
| 39 | +/** | |
| 40 | + * 表单重置 | |
| 41 | + */ | |
| 38 | 42 | const resetForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 39 | 43 | if (!formEl) return; |
| 40 | 44 | formEl.resetFields(); |
| 41 | 45 | }; |
| 42 | -// 表单提交 | |
| 46 | +/** | |
| 47 | + * 表单提交 | |
| 48 | + */ | |
| 43 | 49 | const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 44 | 50 | if (!formEl) return; |
| 45 | 51 | formEl.validate((valid) => { |
| ... | ... | @@ -81,7 +87,7 @@ onMounted(() => { |
| 81 | 87 | :rules="rules" |
| 82 | 88 | ref="ruleFormRef" |
| 83 | 89 | label-width="120px" |
| 84 | - style="display: flex; flex-wrap: wrap; width: 100%" | |
| 90 | + class="card-form" | |
| 85 | 91 | > |
| 86 | 92 | <el-form-item label="角色名称" prop="roleName" style="width: 100%"> |
| 87 | 93 | <el-input | ... | ... |
src/views/role/index.vue
| ... | ... | @@ -3,6 +3,7 @@ import { reactive, ref, onMounted, getCurrentInstance } from "vue"; |
| 3 | 3 | import { roleList, roleStatus } from "@/api/user/role"; |
| 4 | 4 | import { parseTime } from "@/utils/tool"; |
| 5 | 5 | import Pagination from "@/components/Pagination/index.vue"; |
| 6 | +import { ElMessageBox } from "element-plus"; | |
| 6 | 7 | const { |
| 7 | 8 | appContext: { |
| 8 | 9 | config: { globalProperties }, |
| ... | ... | @@ -48,7 +49,9 @@ let data: Data = reactive({ |
| 48 | 49 | }, |
| 49 | 50 | }, |
| 50 | 51 | }); |
| 51 | -// 列表 | |
| 52 | +/** | |
| 53 | + * 列表 | |
| 54 | + */ | |
| 52 | 55 | const getList = async () => { |
| 53 | 56 | data.loading = true; |
| 54 | 57 | try { |
| ... | ... | @@ -61,17 +64,56 @@ const getList = async () => { |
| 61 | 64 | data.loading = false; |
| 62 | 65 | } |
| 63 | 66 | }; |
| 64 | -// 分页 | |
| 67 | +/** | |
| 68 | + * 分页回调 | |
| 69 | + * @param {number} page 当前页码 | |
| 70 | + * @param {number} size 每页内容条数 | |
| 71 | + */ | |
| 65 | 72 | const handlePageChange = (page, size) => { |
| 66 | 73 | data.params.query.page = page; |
| 67 | 74 | data.params.query.pageSize = size; |
| 68 | 75 | getList(); |
| 69 | 76 | }; |
| 70 | -// 查询 | |
| 77 | +/** | |
| 78 | + * 查询 | |
| 79 | + */ | |
| 71 | 80 | const handleSearch = () => { |
| 72 | 81 | getList(); |
| 73 | 82 | }; |
| 74 | -// 状态 | |
| 83 | +/** | |
| 84 | + * 删除 | |
| 85 | + * @param {object} obj 要删除的数据对象 | |
| 86 | + */ | |
| 87 | +const handleDelete = (obj: any) => { | |
| 88 | + ElMessageBox.confirm("确认删除吗?", "警告", { | |
| 89 | + confirmButtonText: "确认", | |
| 90 | + cancelButtonText: "取消", | |
| 91 | + type: "warning", | |
| 92 | + }) | |
| 93 | + .then(async () => { | |
| 94 | + try { | |
| 95 | + let res = await roleStatus({ | |
| 96 | + roleId: obj.id, | |
| 97 | + status: 2, | |
| 98 | + }); | |
| 99 | + if (res?.data) { | |
| 100 | + globalProperties.$message.success("操作成功"); | |
| 101 | + getList(); | |
| 102 | + } else { | |
| 103 | + globalProperties.$message.error("操作失败"); | |
| 104 | + } | |
| 105 | + } catch (e) { | |
| 106 | + console.log(e); | |
| 107 | + } | |
| 108 | + }) | |
| 109 | + .catch(() => { | |
| 110 | + console.log("取消"); | |
| 111 | + }); | |
| 112 | +}; | |
| 113 | +/** | |
| 114 | + * 状态 | |
| 115 | + * @param {object} obj 要操作的数据对象 | |
| 116 | + */ | |
| 75 | 117 | const handleStatus = async (obj) => { |
| 76 | 118 | try { |
| 77 | 119 | const res = await roleStatus({ |
| ... | ... | @@ -88,7 +130,10 @@ const handleStatus = async (obj) => { |
| 88 | 130 | console.log(e); |
| 89 | 131 | } |
| 90 | 132 | }; |
| 91 | -// 状态值 | |
| 133 | +/** | |
| 134 | + * 状态值 | |
| 135 | + * @enum {number} | |
| 136 | + */ | |
| 92 | 137 | enum statusEnum { |
| 93 | 138 | "禁用" = 0, |
| 94 | 139 | "启用", |
| ... | ... | @@ -160,6 +205,7 @@ onMounted(() => { |
| 160 | 205 | >权限</router-link |
| 161 | 206 | ></el-button |
| 162 | 207 | > |
| 208 | + <el-button type="text" @click="handleDelete(scope.row)">删除</el-button> | |
| 163 | 209 | </template> |
| 164 | 210 | </el-table-column> |
| 165 | 211 | </el-table> | ... | ... |
src/views/role/permission.vue
| ... | ... | @@ -21,14 +21,18 @@ let form = reactive({ |
| 21 | 21 | }); |
| 22 | 22 | const ruleFormRef = ref<InstanceType<typeof ElForm>>(); |
| 23 | 23 | const addTreeTest = ref<InstanceType<typeof ElTree>>() |
| 24 | -// 表单重置 | |
| 24 | +/** | |
| 25 | + * 表单重置 | |
| 26 | + */ | |
| 25 | 27 | const resetForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 26 | 28 | if (!formEl) return; |
| 27 | 29 | form.defaultPermissions = [] |
| 28 | 30 | addTreeTest.value!.setCheckedNodes([]) |
| 29 | 31 | formEl.resetFields(); |
| 30 | 32 | }; |
| 31 | -// 表单提交 | |
| 33 | +/** | |
| 34 | + * 表单提交 | |
| 35 | + */ | |
| 32 | 36 | const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 33 | 37 | if (!formEl) return; |
| 34 | 38 | formEl.validate((valid) => { |
| ... | ... | @@ -49,7 +53,10 @@ const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 49 | 53 | } |
| 50 | 54 | }); |
| 51 | 55 | }; |
| 52 | -// 获取角色权限 | |
| 56 | +/** | |
| 57 | + * 获取角色权限 | |
| 58 | + * @param {number | string} roleId 角色id | |
| 59 | + */ | |
| 53 | 60 | const getPermissions = async (roleId = useRoute().query.roleId) => { |
| 54 | 61 | try { |
| 55 | 62 | let res = await rolePermission({ roleId: roleId }); |
| ... | ... | @@ -63,10 +70,18 @@ interface Tree { |
| 63 | 70 | label: string |
| 64 | 71 | children?: Tree[] |
| 65 | 72 | } |
| 73 | +/** | |
| 74 | + * 树组件自定义属性 | |
| 75 | + */ | |
| 66 | 76 | const defaultProps: Tree = { |
| 67 | 77 | children: "menuList", |
| 68 | 78 | label: "name", |
| 69 | 79 | }; |
| 80 | +/** | |
| 81 | + * 选中树节点回显 | |
| 82 | + * @param {array} menuArray 树数组 | |
| 83 | + * @returns {array} | |
| 84 | + */ | |
| 70 | 85 | const getCheckedPermissions = (menuArray: Tree[]) => { |
| 71 | 86 | if (menuArray) { |
| 72 | 87 | menuArray.map((item: Tree) => { |
| ... | ... | @@ -80,6 +95,11 @@ const getCheckedPermissions = (menuArray: Tree[]) => { |
| 80 | 95 | } |
| 81 | 96 | return form.collections; |
| 82 | 97 | }; |
| 98 | +/** | |
| 99 | + * 获取选中的树节点 | |
| 100 | + * @param {object} node 树节点对象 | |
| 101 | + * @param {array} array 树数组 | |
| 102 | + */ | |
| 83 | 103 | const getCheckedRoles = (node: Node, data: Node[]) => { |
| 84 | 104 | form.data.permissionIds = [...data.checkedKeys, ...data.halfCheckedKeys]; |
| 85 | 105 | }; |
| ... | ... | @@ -97,7 +117,7 @@ onMounted(() => { |
| 97 | 117 | :model="form.data" |
| 98 | 118 | ref="ruleFormRef" |
| 99 | 119 | label-width="120px" |
| 100 | - style="display: flex; flex-wrap: wrap; width: 100%" | |
| 120 | + class="card-form" | |
| 101 | 121 | > |
| 102 | 122 | <el-form-item label="角色名称" prop="roleName" style="width: 100%"> |
| 103 | 123 | <el-input | ... | ... |
src/views/role/user.vue
| ... | ... | @@ -29,12 +29,16 @@ let data: Data = reactive({ |
| 29 | 29 | }, |
| 30 | 30 | }, |
| 31 | 31 | }); |
| 32 | -// 状态值 | |
| 32 | +/** | |
| 33 | + * 状态值 | |
| 34 | + */ | |
| 33 | 35 | enum statusEnum { |
| 34 | 36 | "禁用" = 0, |
| 35 | 37 | "启用", |
| 36 | 38 | } |
| 37 | -// 列表 | |
| 39 | +/** | |
| 40 | + * 列表 | |
| 41 | + */ | |
| 38 | 42 | const getList = async () => { |
| 39 | 43 | data.loading = true; |
| 40 | 44 | try { |
| ... | ... | @@ -47,7 +51,11 @@ const getList = async () => { |
| 47 | 51 | data.loading = false; |
| 48 | 52 | } |
| 49 | 53 | }; |
| 50 | -// 分页 | |
| 54 | +/** | |
| 55 | + * 分页 | |
| 56 | + * @param {number} page 当前页数 | |
| 57 | + * @param {number} size 每页内容条数 | |
| 58 | + */ | |
| 51 | 59 | const handlePageChange = (page, size) => { |
| 52 | 60 | data.params.query.page = page; |
| 53 | 61 | data.params.query.pageSize = size; | ... | ... |
src/views/system/info.vue
0 → 100644
| 1 | +<script setup lang="ts"> | |
| 2 | +import { reactive, ref, getCurrentInstance } from "vue"; | |
| 3 | +import * as store from "@/pinia/index"; | |
| 4 | +import { userPwdChange } from '@/api/user/user'; | |
| 5 | +import type { ElForm } from "element-plus"; | |
| 6 | + | |
| 7 | +const ruleFormRef = ref<InstanceType<typeof ElForm>>(); | |
| 8 | +let instance: ComponentInternalInstance | null = getCurrentInstance(); | |
| 9 | +let form = reactive({ | |
| 10 | + data: { | |
| 11 | + userId: store?.family?.loginStore()?.id, | |
| 12 | + oldPassword: "", | |
| 13 | + newPassword: "", | |
| 14 | + surePwd: "" | |
| 15 | + } | |
| 16 | +}); | |
| 17 | +/** | |
| 18 | + * 验证两次输入密码一致 | |
| 19 | + * @param {object} rules 验证规则 | |
| 20 | + * @param {string} value 确认密码文本 | |
| 21 | + * @callback checkPwd~checkDoublePwdCallback | |
| 22 | + */ | |
| 23 | +const checkPwd = (rules, value, callback) => { | |
| 24 | + if(value === form.data.newPassword) { | |
| 25 | + callback() | |
| 26 | + } else { | |
| 27 | + callback(new Error('请确认密码和新密码一致')) | |
| 28 | + } | |
| 29 | +} | |
| 30 | +/** | |
| 31 | + * 表单验证规则 | |
| 32 | + */ | |
| 33 | +const rules = reactive({ | |
| 34 | + oldPassword: [ | |
| 35 | + { | |
| 36 | + required: true, | |
| 37 | + message: "请填写旧密码", | |
| 38 | + trigger: "blur", | |
| 39 | + }, | |
| 40 | + ], | |
| 41 | + newPassword: [ | |
| 42 | + { | |
| 43 | + required: true, | |
| 44 | + message: "请填写新密码", | |
| 45 | + trigger: "blur", | |
| 46 | + }, | |
| 47 | + ], | |
| 48 | + surePwd: [ | |
| 49 | + { | |
| 50 | + required: true, | |
| 51 | + message: "请确认密码和新密码一致", | |
| 52 | + trigger: "blur", | |
| 53 | + validator: checkPwd | |
| 54 | + }, | |
| 55 | + ], | |
| 56 | +}) | |
| 57 | +/** | |
| 58 | + * 表单重置 | |
| 59 | + */ | |
| 60 | +const resetForm = (formEl: InstanceType<typeof ElForm> | undefined) => { | |
| 61 | + if (!formEl) return; | |
| 62 | + formEl.resetFields(); | |
| 63 | +}; | |
| 64 | +/** | |
| 65 | + * 表单提交 | |
| 66 | + */ | |
| 67 | +const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { | |
| 68 | + if (!formEl) return; | |
| 69 | + formEl.validate((valid) => { | |
| 70 | + if (valid) { | |
| 71 | + userPwdChange(form.data) | |
| 72 | + .then((res) => { | |
| 73 | + if (res) { | |
| 74 | + instance?.proxy?.$message.success("修改成功"); | |
| 75 | + store.family.loginStore().removeToken('请重新登录'); | |
| 76 | + } | |
| 77 | + }) | |
| 78 | + .catch((error) => { | |
| 79 | + console.log(error); | |
| 80 | + }); | |
| 81 | + } else { | |
| 82 | + instance?.proxy?.$message.error("请检查表单内容"); | |
| 83 | + return false; | |
| 84 | + } | |
| 85 | + }); | |
| 86 | +}; | |
| 87 | +</script> | |
| 88 | + | |
| 89 | +<template> | |
| 90 | + <div class="page-container"> | |
| 91 | + <el-card class="form_card" style="max-width: 1303px"> | |
| 92 | + <h1>基本信息</h1> | |
| 93 | + <el-form | |
| 94 | + :inline="true" | |
| 95 | + :model="form.data" | |
| 96 | + :rules="rules" | |
| 97 | + ref="ruleFormRef" | |
| 98 | + label-width="120px" | |
| 99 | + class="card-form" | |
| 100 | + > | |
| 101 | + <el-form-item label="旧密码" prop="oldPassword" style="width: 100%"> | |
| 102 | + <el-input | |
| 103 | + v-model.trim="form.data.oldPassword" | |
| 104 | + placeholder="请填写旧密码" | |
| 105 | + maxlength="15" | |
| 106 | + /> | |
| 107 | + </el-form-item> | |
| 108 | + <el-form-item label="新密码" prop="newPassword" style="width: 100%"> | |
| 109 | + <el-input | |
| 110 | + v-model.trim="form.data.newPassword" | |
| 111 | + placeholder="请填写新密码" | |
| 112 | + maxlength="15" | |
| 113 | + /> | |
| 114 | + </el-form-item> | |
| 115 | + <el-form-item label="确认密码" prop="surePwd" style="width: 100%"> | |
| 116 | + <el-input | |
| 117 | + v-model.trim="form.data.surePwd" | |
| 118 | + placeholder="请确认密码" | |
| 119 | + maxlength="15" | |
| 120 | + /> | |
| 121 | + </el-form-item> | |
| 122 | + <el-form-item style="width: 100%"> | |
| 123 | + <el-button type="primary" @click="submitForm(ruleFormRef)" | |
| 124 | + >提交</el-button | |
| 125 | + > | |
| 126 | + <el-button | |
| 127 | + type="info" | |
| 128 | + @click="resetForm(ruleFormRef)" | |
| 129 | + >取消</el-button | |
| 130 | + > | |
| 131 | + </el-form-item> | |
| 132 | + </el-form> | |
| 133 | + </el-card> | |
| 134 | + </div> | |
| 135 | +</template> | ... | ... |
src/views/user/edit.vue
| ... | ... | @@ -23,7 +23,12 @@ let form = reactive({ |
| 23 | 23 | checkList: [], |
| 24 | 24 | }); |
| 25 | 25 | const ruleFormRef = ref<InstanceType<typeof ElForm>>(); |
| 26 | -// 校验手机号格式 | |
| 26 | +/** | |
| 27 | + * 校验手机号格式 | |
| 28 | + * @param {object} rules 验证规则 | |
| 29 | + * @param {string} value 待验证手机号 | |
| 30 | + * @callback checkPhone~checkCallback | |
| 31 | + */ | |
| 27 | 32 | const checkPhone = (rules, value, callback) => { |
| 28 | 33 | if (validMobile(value)) { |
| 29 | 34 | callback(); |
| ... | ... | @@ -32,6 +37,9 @@ const checkPhone = (rules, value, callback) => { |
| 32 | 37 | } |
| 33 | 38 | }; |
| 34 | 39 | // 表单验证规则 |
| 40 | +/** | |
| 41 | + * 表单验证规则 | |
| 42 | + */ | |
| 35 | 43 | const rules = reactive({ |
| 36 | 44 | userName: [ |
| 37 | 45 | { |
| ... | ... | @@ -47,6 +55,13 @@ const rules = reactive({ |
| 47 | 55 | trigger: "blur", |
| 48 | 56 | }, |
| 49 | 57 | ], |
| 58 | + password: [ | |
| 59 | + { | |
| 60 | + required: true, | |
| 61 | + message: "请填写密码", | |
| 62 | + trigger: "blur", | |
| 63 | + }, | |
| 64 | + ], | |
| 50 | 65 | cellphone: [ |
| 51 | 66 | { |
| 52 | 67 | required: true, |
| ... | ... | @@ -56,13 +71,17 @@ const rules = reactive({ |
| 56 | 71 | }, |
| 57 | 72 | ], |
| 58 | 73 | }); |
| 59 | -// 表单重置 | |
| 74 | +/** | |
| 75 | + * 表单重置 | |
| 76 | + */ | |
| 60 | 77 | const resetForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 61 | 78 | if (!formEl) return; |
| 62 | 79 | form.checkList = []; |
| 63 | 80 | formEl.resetFields(); |
| 64 | 81 | }; |
| 65 | -// 表单提交 | |
| 82 | +/** | |
| 83 | + * 表单提交 | |
| 84 | + */ | |
| 66 | 85 | const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 67 | 86 | if (!formEl) return; |
| 68 | 87 | formEl.validate((valid) => { |
| ... | ... | @@ -83,7 +102,10 @@ const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 83 | 102 | } |
| 84 | 103 | }); |
| 85 | 104 | }; |
| 86 | -// 角色列表 | |
| 105 | +/** | |
| 106 | + * 角色列表 | |
| 107 | + * @param {number | null} pageSize 一次请求多少条数据 | |
| 108 | + */ | |
| 87 | 109 | const getRoleList = async (pageSize = 20) => { |
| 88 | 110 | try { |
| 89 | 111 | const res = await roleList({ |
| ... | ... | @@ -121,7 +143,7 @@ onMounted(() => { |
| 121 | 143 | :rules="rules" |
| 122 | 144 | ref="ruleFormRef" |
| 123 | 145 | label-width="120px" |
| 124 | - style="display: flex; flex-wrap: wrap; width: 100%" | |
| 146 | + class="card-form" | |
| 125 | 147 | > |
| 126 | 148 | <el-form-item label="用户名称" prop="userName" style="width: 100%"> |
| 127 | 149 | <el-input | ... | ... |
src/views/user/index.vue
| 1 | 1 | <script setup lang="ts"> |
| 2 | -import { reactive, ref, onMounted, getCurrentInstance } from "vue"; | |
| 2 | +import { reactive, ref, onMounted } from "vue"; | |
| 3 | 3 | import { userList, userPwd, userStatus } from "@/api/user/user"; |
| 4 | 4 | import { parseTime } from "@/utils/tool"; |
| 5 | 5 | import Pagination from "@/components/Pagination/index.vue"; |
| 6 | -const { | |
| 7 | - appContext: { | |
| 8 | - config: { globalProperties }, | |
| 9 | - }, | |
| 10 | -} = getCurrentInstance(); | |
| 6 | +import { ElMessageBox, ElMessage } from "element-plus"; | |
| 11 | 7 | interface Form { |
| 12 | 8 | page: number; |
| 13 | 9 | pageSize: number; |
| ... | ... | @@ -36,7 +32,9 @@ let data = reactive({ |
| 36 | 32 | }, |
| 37 | 33 | }, |
| 38 | 34 | }); |
| 39 | -// 列表 | |
| 35 | +/** | |
| 36 | + * 列表 | |
| 37 | + */ | |
| 40 | 38 | const getList = async () => { |
| 41 | 39 | data.loading = true; |
| 42 | 40 | try { |
| ... | ... | @@ -49,41 +47,96 @@ const getList = async () => { |
| 49 | 47 | data.loading = false; |
| 50 | 48 | } |
| 51 | 49 | }; |
| 52 | -// 分页 | |
| 50 | +/** | |
| 51 | + * 分页回调 | |
| 52 | + * @param {number} page 当前页码 | |
| 53 | + * @param {number} size 每页内容条数 | |
| 54 | + */ | |
| 53 | 55 | const handlePageChange = (page, size) => { |
| 54 | 56 | data.params.query.page = page; |
| 55 | 57 | data.params.query.pageSize = size; |
| 56 | 58 | getList(); |
| 57 | 59 | }; |
| 58 | -// 查询 | |
| 60 | +/** | |
| 61 | + * 查询 | |
| 62 | + */ | |
| 59 | 63 | const handleSearch = () => { |
| 60 | 64 | getList(); |
| 61 | 65 | }; |
| 62 | -// 初始化密码type=pwd、修改状态type=status | |
| 66 | +/** | |
| 67 | + * 删除 | |
| 68 | + * @param {object} obj 要删除的数据对象 | |
| 69 | + */ | |
| 70 | +const handleDelete = (obj: any) => { | |
| 71 | + ElMessageBox.confirm("确认删除吗?", "警告", { | |
| 72 | + confirmButtonText: "确认", | |
| 73 | + cancelButtonText: "取消", | |
| 74 | + type: "warning", | |
| 75 | + }) | |
| 76 | + .then(async () => { | |
| 77 | + try { | |
| 78 | + let res = await userStatus({ | |
| 79 | + userId: obj.id, | |
| 80 | + status: 2, | |
| 81 | + }); | |
| 82 | + if (res?.data) { | |
| 83 | + ElMessage({ | |
| 84 | + type: "success", | |
| 85 | + message: "操作成功", | |
| 86 | + }); | |
| 87 | + getList(); | |
| 88 | + } else { | |
| 89 | + ElMessage({ | |
| 90 | + type: "error", | |
| 91 | + message: "操作失败", | |
| 92 | + }); | |
| 93 | + } | |
| 94 | + } catch (e) { | |
| 95 | + console.log(e); | |
| 96 | + } | |
| 97 | + }) | |
| 98 | + .catch(() => { | |
| 99 | + console.log("取消"); | |
| 100 | + }); | |
| 101 | +}; | |
| 102 | +/** | |
| 103 | + * 修改 | |
| 104 | + * @param {object} obj 一条数据对象 | |
| 105 | + * @param {string} type 修改操作的类型,pwd修改密码,status修改状态 | |
| 106 | + */ | |
| 63 | 107 | const handleUpdate = async (obj: any, type: string) => { |
| 64 | 108 | try { |
| 65 | 109 | let res; |
| 66 | 110 | if (type === "status") { |
| 67 | 111 | res = await userStatus({ |
| 68 | - id: obj.id, | |
| 112 | + userId: obj.id, | |
| 69 | 113 | status: obj.status ? 0 : 1, |
| 70 | 114 | }); |
| 71 | 115 | } else if (type === "pwd") { |
| 72 | 116 | res = await userPwd({ |
| 73 | - id: obj.id, | |
| 117 | + userId: obj.id, | |
| 74 | 118 | }); |
| 75 | - } | |
| 119 | + } | |
| 76 | 120 | if (res?.data) { |
| 77 | - globalProperties.$message.success("操作成功"); | |
| 121 | + ElMessage({ | |
| 122 | + type: "success", | |
| 123 | + message: "操作成功", | |
| 124 | + }); | |
| 78 | 125 | getList(); |
| 79 | 126 | } else { |
| 80 | - globalProperties.$message.error("操作失败"); | |
| 127 | + ElMessage({ | |
| 128 | + type: "error", | |
| 129 | + message: "操作失败", | |
| 130 | + }); | |
| 81 | 131 | } |
| 82 | 132 | } catch (e) { |
| 83 | 133 | console.log(e); |
| 84 | 134 | } |
| 85 | 135 | }; |
| 86 | -// 状态值 | |
| 136 | +/** | |
| 137 | + * 状态值 | |
| 138 | + * @enum {number} | |
| 139 | + */ | |
| 87 | 140 | enum statusEnum { |
| 88 | 141 | "禁用" = 0, |
| 89 | 142 | "启用", |
| ... | ... | @@ -106,7 +159,7 @@ onMounted(() => { |
| 106 | 159 | @change="handleSearch" |
| 107 | 160 | /> |
| 108 | 161 | </el-form-item> |
| 109 | - <el-form-item label="用户名"> | |
| 162 | + <el-form-item label="手机号"> | |
| 110 | 163 | <el-input |
| 111 | 164 | v-model.trim="data.params.query.cellphone" |
| 112 | 165 | placeholder="请填写用户手机号" |
| ... | ... | @@ -159,10 +212,14 @@ onMounted(() => { |
| 159 | 212 | >初始密码</el-button |
| 160 | 213 | > |
| 161 | 214 | <el-button type="text" |
| 162 | - ><router-link :to="{ path: '/user/role', query: {id: scope.row.id}}" | |
| 215 | + ><router-link | |
| 216 | + :to="{ path: '/user/role', query: { id: scope.row.id } }" | |
| 163 | 217 | >角色</router-link |
| 164 | 218 | ></el-button |
| 165 | 219 | > |
| 220 | + <el-button type="text" @click="handleDelete(scope.row)" | |
| 221 | + >删除</el-button | |
| 222 | + > | |
| 166 | 223 | </template> |
| 167 | 224 | </el-table-column> |
| 168 | 225 | </el-table> | ... | ... |
src/views/user/login.vue
| ... | ... | @@ -14,15 +14,21 @@ interface Login { |
| 14 | 14 | userName: string; |
| 15 | 15 | password: string; |
| 16 | 16 | } |
| 17 | -// 登录表单数据 | |
| 17 | +/** | |
| 18 | + * 登录表单数据 | |
| 19 | + */ | |
| 18 | 20 | const loginForm: Login = reactive({ |
| 19 | 21 | userName: "123", |
| 20 | 22 | password: "cmnt123", |
| 21 | 23 | }); |
| 22 | -// 登录框上面标题 | |
| 24 | +/** | |
| 25 | + * 登录框上面标题 | |
| 26 | + */ | |
| 23 | 27 | const title = ref(import.meta.env.VITE_APP_TITLE).value; |
| 24 | 28 | const ruleFormRef = ref<InstanceType<typeof ElForm>>(); |
| 25 | -// 表单提交 | |
| 29 | +/** | |
| 30 | + * 表单提交 | |
| 31 | + */ | |
| 26 | 32 | const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 27 | 33 | if (!formEl) return; |
| 28 | 34 | formEl.validate((valid) => { |
| ... | ... | @@ -43,7 +49,9 @@ const submitForm = (formEl: InstanceType<typeof ElForm> | undefined) => { |
| 43 | 49 | } |
| 44 | 50 | }); |
| 45 | 51 | }; |
| 46 | -// 获取权限菜单 | |
| 52 | +/** | |
| 53 | + * 获取权限菜单 | |
| 54 | + */ | |
| 47 | 55 | const getMenu = async () => { |
| 48 | 56 | try { |
| 49 | 57 | let res = await menuData(); | ... | ... |
src/views/user/role.vue
| ... | ... | @@ -2,13 +2,11 @@ |
| 2 | 2 | import { reactive, ref, onMounted } from "vue"; |
| 3 | 3 | import { userRoles } from "@/api/user/user"; |
| 4 | 4 | import { parseTime } from "@/utils/tool"; |
| 5 | -import Pagination from "@/components/Pagination/index.vue"; | |
| 6 | 5 | interface Form { |
| 7 | 6 | page: number; |
| 8 | 7 | pageSize: number; |
| 9 | 8 | } |
| 10 | 9 | interface Params { |
| 11 | - total: number; | |
| 12 | 10 | query: Form; |
| 13 | 11 | } |
| 14 | 12 | interface Data { |
| ... | ... | @@ -20,32 +18,26 @@ let data = reactive({ |
| 20 | 18 | list: [], |
| 21 | 19 | loading: false, |
| 22 | 20 | params: { |
| 23 | - total: 0, | |
| 24 | 21 | query: { |
| 25 | 22 | page: 1, |
| 26 | 23 | pageSize: 10 |
| 27 | 24 | }, |
| 28 | 25 | }, |
| 29 | 26 | }); |
| 30 | -// 列表 | |
| 27 | +/** | |
| 28 | + * 列表 | |
| 29 | + */ | |
| 31 | 30 | const getList = async () => { |
| 32 | 31 | data.loading = true; |
| 33 | 32 | try { |
| 34 | 33 | const res = await userRoles(data.params.query); |
| 35 | 34 | data.list = res.data.data; |
| 36 | - data.params.total = res.data.data.length; | |
| 37 | 35 | } catch (e) { |
| 38 | 36 | console.log(e); |
| 39 | 37 | } finally { |
| 40 | 38 | data.loading = false; |
| 41 | 39 | } |
| 42 | 40 | }; |
| 43 | -// 分页 | |
| 44 | -const handlePageChange = (page, size) => { | |
| 45 | - data.params.query.page = page; | |
| 46 | - data.params.query.pageSize = size; | |
| 47 | - getList(); | |
| 48 | -}; | |
| 49 | 41 | onMounted(() => { |
| 50 | 42 | getList(); |
| 51 | 43 | }); |
| ... | ... | @@ -65,11 +57,5 @@ onMounted(() => { |
| 65 | 57 | <el-table-column prop="id" label="ID" align="center"> </el-table-column> |
| 66 | 58 | <el-table-column prop="roleName" label="角色名" align="center"> </el-table-column> |
| 67 | 59 | </el-table> |
| 68 | - <Pagination | |
| 69 | - :total="data.params.total" | |
| 70 | - :currentPage="data.params.query.page" | |
| 71 | - :pageSize="data.params.query.pageSize" | |
| 72 | - @pageChange="handlePageChange" | |
| 73 | - ></Pagination> | |
| 74 | 60 | </div> |
| 75 | 61 | </template> | ... | ... |