公司业绩管理页面搭建

This commit is contained in:
BianLzhaoMin 2025-04-21 17:01:33 +08:00
parent 5a4e9fdba8
commit 711db26d31
18 changed files with 1152 additions and 603 deletions

2
.env
View File

@ -1 +1 @@
VITE_BASE_URI=/admin3
VITE_BASE_URI=/search_tool

2
components.d.ts vendored
View File

@ -9,6 +9,7 @@ declare module '@vue/runtime-core' {
export interface GlobalComponents {
AppIcon: typeof import('./src/components/AppIcon.vue')['default']
AvatarUpload: typeof import('./src/components/AvatarUpload.vue')['default']
DialogModel: typeof import('./src/components/DialogModel.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton']
@ -17,6 +18,7 @@ declare module '@vue/runtime-core' {
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']

67
package-lock.json generated
View File

@ -22,9 +22,11 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/node": "^22.14.1",
"@vitejs/plugin-vue": "^3.0.0",
"@vue/compiler-sfc": "^3.1.2",
"sass": "^1.49.7",
"sass-loader": "^16.0.5",
"typescript": "^4.6.4",
"unplugin-auto-import": "^0.11.5",
"unplugin-vue-components": "^0.22.12",
@ -249,6 +251,16 @@
"integrity": "sha512-jMN2moJ+lSf1VZXQo3VXeMCjoXuciVONig8+U0YNBop5aBvQw4qkolx1Nzn1i0T8L2l9IZ3jju6bS1pPwlaY1w==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.14.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/@types/node/-/node-22.14.1.tgz",
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.15",
"resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz",
@ -1506,6 +1518,13 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://repo.huaweicloud.com/repository/npm/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true,
"license": "MIT"
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -1744,6 +1763,47 @@
"node": ">=14.0.0"
}
},
"node_modules/sass-loader": {
"version": "16.0.5",
"resolved": "https://repo.huaweicloud.com/repository/npm/sass-loader/-/sass-loader-16.0.5.tgz",
"integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"neo-async": "^2.6.2"
},
"engines": {
"node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"@rspack/core": "0.x || 1.x",
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
"sass": "^1.3.0",
"sass-embedded": "*",
"webpack": "^5.0.0"
},
"peerDependenciesMeta": {
"@rspack/core": {
"optional": true
},
"node-sass": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"webpack": {
"optional": true
}
}
},
"node_modules/schart.js": {
"version": "3.0.4",
"resolved": "https://repo.huaweicloud.com/repository/npm/schart.js/-/schart.js-3.0.4.tgz",
@ -1860,6 +1920,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/unimport": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/unimport/-/unimport-1.3.0.tgz",

View File

@ -22,9 +22,11 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"sass": "^1.49.7",
"@types/node": "^22.14.1",
"@vitejs/plugin-vue": "^3.0.0",
"@vue/compiler-sfc": "^3.1.2",
"sass": "^1.49.7",
"sass-loader": "^16.0.5",
"typescript": "^4.6.4",
"unplugin-auto-import": "^0.11.5",
"unplugin-vue-components": "^0.22.12",

12
shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// 添加对 @/views 的路径支持(可选)
declare module '@/views/*' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View File

@ -1,17 +1,17 @@
import request from '../utils/request';
import {BASE_URI} from "./base";
import request from '../utils/request'
import { BASE_URI } from './base'
export function login(data: { username: string; password: string }) {
return request({
url: `${BASE_URI}/login`,
method: 'post',
data: data
});
data: data,
})
}
export function logout() {
return request({
url: `${BASE_URI}/logout`,
method: 'post',
});
})
}

View File

@ -0,0 +1,68 @@
<template>
<el-dialog
:title="props.dialogConfig.outerTitle"
:width="props.dialogConfig.outerWidth"
v-model="props.dialogConfig.outerVisible"
v-if="props.dialogConfig.outerVisible"
:before-close="handleCloseOuter"
append-to-body
>
<!-- 外层弹框内容 -->
<slot name="outerContent"></slot>
<!-- 内层对话框 -->
<el-dialog
:title="props.dialogConfig.innerTitle"
:width="props.dialogConfig.innerWidth"
v-model="props.dialogConfig.innerVisible"
v-if="props.dialogConfig.innerVisible"
:before-close="handleCloseInner"
append-to-body
>
<!-- 内层弹框内容 -->
<slot name="innerContent"></slot>
</el-dialog>
</el-dialog>
</template>
<script lang="ts" setup>
const props = defineProps({
dialogConfig: {
type: Object,
default: () => {
return {}
},
},
})
const emits = defineEmits(['closeDialogOuter', 'closeDialogInner'])
const handleCloseOuter = () => {
emits('closeDialogOuter', false)
}
const handleCloseInner = () => {
emits('closeDialogInner', false)
}
</script>
<style lang="scss">
.el-dialog {
display: flex;
flex-direction: column;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-height: 95vh;
min-height: 95vh;
.el-dialog__body {
flex: 1;
overflow-y: scroll;
padding: 20px 40px;
}
.dialog-content {
padding: 20px;
}
}
</style>

View File

@ -1,124 +1,121 @@
<template>
<div class="sidebar">
<el-menu
class="sidebar-el-menu"
:default-active="onRoutes"
:collapse="sidebar.collapse"
background-color="#324157"
text-color="#bfcbd9"
active-text-color="#20a0ff"
unique-opened
router
>
<template v-for="item in items">
<template v-if="item.subs">
<el-sub-menu :index="item.index" :key="item.index">
<template #title>
<el-icon>
<component :is="item.icon"></component>
</el-icon>
<span>{{ item.title }}</span>
</template>
<template v-for="subItem in item.subs">
<el-sub-menu
v-if="subItem.subs"
:index="subItem.index"
:key="subItem.index"
>
<template #title>
<el-icon>
<component :is="subItem.icon"></component>
</el-icon>
{{ subItem.title }}
<div class="sidebar">
<el-menu
class="sidebar-el-menu"
:default-active="onRoutes"
:collapse="sidebar.collapse"
background-color="#324157"
text-color="#bfcbd9"
active-text-color="#20a0ff"
unique-opened
router
>
<template v-for="item in items">
<template v-if="item.subs">
<el-sub-menu :index="item.index" :key="item.index">
<template #title>
<el-icon>
<component :is="item.icon"></component>
</el-icon>
<span>{{ item.title }}</span>
</template>
<template v-for="subItem in item.subs">
<el-sub-menu v-if="subItem.subs" :index="subItem.index" :key="subItem.index">
<template #title>
<el-icon>
<component :is="subItem.icon"></component>
</el-icon>
{{ subItem.title }}
</template>
<el-menu-item v-for="(threeItem, i) in subItem.subs" :key="i" :index="threeItem.index">
<el-icon>
<component :is="threeItem.icon"></component>
</el-icon>
{{ threeItem.title }}
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :index="subItem.index">
<el-icon>
<component :is="subItem.icon"></component>
</el-icon>
{{ subItem.title }}
</el-menu-item>
</template>
</el-sub-menu>
</template>
<template v-else>
<el-menu-item :index="item.index" :key="item.index">
<el-icon>
<component :is="item.icon"></component>
</el-icon>
<template #title>{{ item?.title }}</template>
</el-menu-item>
</template>
<el-menu-item v-for="(threeItem, i) in subItem.subs" :key="i" :index="threeItem.index">
<el-icon>
<component :is="threeItem.icon"></component>
</el-icon>
{{ threeItem.title }}
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :index="subItem.index">
<el-icon>
<component :is="subItem.icon"></component>
</el-icon>
{{ subItem.title }}
</el-menu-item>
</template>
</el-sub-menu>
</template>
<template v-else>
<el-menu-item :index="item.index" :key="item.index">
<el-icon>
<component :is="item.icon"></component>
</el-icon>
<template #title>{{ item?.title }}</template>
</el-menu-item>
</template>
</template>
</el-menu>
</div>
</el-menu>
</div>
</template>
<script setup lang="ts">
import {computed, ref} from 'vue';
import {useSidebarStore} from '../store/sidebar';
import {useRoute} from 'vue-router';
import {getMenus} from "../api/resource";
import { computed, ref } from 'vue'
import { useSidebarStore } from '../store/sidebar'
import { useRoute } from 'vue-router'
import { getMenus } from '../api/resource'
interface MenuItem {
index: string;
icon: string;
title: string;
subs: MenuItem[] | undefined;
index: string
icon: string
title: string
subs: MenuItem[] | undefined
}
const items = ref<MenuItem[]>([]);
const items = ref<MenuItem[]>([])
getMenus().then(res => {
items.value = getDataNode(res.data, 1);
});
getMenus().then((res) => {
items.value = getDataNode(res.data, 1)
})
const getDataNode: any = (menus: any[], parentId: number) => {
return menus.filter(m => m.parentId === parentId).map((menu: any) => {
let subs: MenuItem[] = getDataNode(menus, menu.id);
return {
index: menu.url,
icon: menu.icon,
title: menu.name,
subs: subs?.length === 0 ? undefined : subs
}
});
return menus
.filter((m) => m.parentId === parentId)
.map((menu: any) => {
let subs: MenuItem[] = getDataNode(menus, menu.id)
return {
index: menu.url,
icon: menu.icon,
title: menu.name,
subs: subs?.length === 0 ? undefined : subs,
}
})
}
const route = useRoute();
const route = useRoute()
const onRoutes = computed(() => {
return route.path;
});
return route.path
})
const sidebar = useSidebarStore();
const sidebar = useSidebarStore()
</script>
<style scoped>
.sidebar {
display: block;
position: absolute;
left: 0;
top: 70px;
bottom: 0;
overflow-y: scroll;
display: block;
position: absolute;
left: 0;
top: 70px;
bottom: 0;
overflow-y: scroll;
}
.sidebar::-webkit-scrollbar {
width: 0;
width: 0;
}
.sidebar-el-menu:not(.el-menu--collapse) {
width: 250px;
width: 250px;
}
.sidebar > ul {
height: 100%;
height: 100%;
}
</style>

View File

@ -1,28 +1,33 @@
import {createApp} from 'vue';
import {createPinia} from 'pinia';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import App from './App.vue';
import router from './router';
import 'element-plus/dist/index.css';
import './assets/css/icon.css';
import {useBasicStore} from "./store/basic";
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import App from './App.vue'
import router from './router'
import 'element-plus/dist/index.css'
import './assets/css/icon.css'
import { useBasicStore } from './store/basic'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
const app = createApp(App);
app.use(createPinia());
app.use(router);
const app = createApp(App)
app.use(createPinia())
app.use(router)
// 注册element plus图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
app.component(key, component)
}
const basicStore = useBasicStore();
const basicStore = useBasicStore()
app.directive('action', {
mounted(el, binding) {
const permissions: string[] = basicStore?.userinfo?.permissions || [];
const actionName: string = binding.arg || '';
const permissions: string[] = basicStore?.userinfo?.permissions || []
const actionName: string = binding.arg || ''
if (permissions && !permissions.includes(actionName)) {
el['hidden'] = true;
el['hidden'] = true
}
},
});
app.mount('#app');
})
app.mount('#app')
app.use(ElementPlus, {
locale: zhCn,
})

View File

@ -1,4 +1,4 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHashHistory, RouteRecordRaw, createWebHistory } from 'vue-router'
import Home from '../views/home.vue'
import { useBasicStore } from '../store/basic'
@ -77,6 +77,16 @@ const routes: RouteRecordRaw[] = [
},
component: () => import(/* webpackChunkName: "user" */ '../views/user.vue'),
},
{
path: '/performance-manage',
name: 'performance-manage',
meta: {
title: '登录',
},
component: () =>
import(/* webpackChunkName: "login" */ '@/views/company-manage/performance-manage/index.vue'),
},
],
},
{
@ -87,6 +97,7 @@ const routes: RouteRecordRaw[] = [
},
component: () => import(/* webpackChunkName: "login" */ '../views/login.vue'),
},
{
path: '/403',
name: '403',
@ -98,12 +109,11 @@ const routes: RouteRecordRaw[] = [
]
const router = createRouter({
history: createWebHashHistory(),
history: createWebHistory(),
routes,
})
router.beforeEach(async (to, from, next) => {
// document.title = ` 市场部投标信息检索工具`
const token = localStorage.getItem('token')
const basicStore = useBasicStore()
if (!token && to.path !== '/login') {

View File

@ -1,45 +1,47 @@
import axios, {AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios';
import {ElMessage} from "element-plus";
import router from "../router";
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'
import router from '../router'
const service: AxiosInstance = axios.create({
timeout: 5000
});
timeout: 5000,
baseURL: '/dev-api',
})
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
const headerToken = localStorage.getItem('token');
const headerToken = localStorage.getItem('token')
if (headerToken) {
// @ts-ignore
config.headers['Authorization'] = 'Bearer ' + headerToken
}
return config;
return config
},
(error: AxiosError) => {
console.log(error);
return Promise.reject();
}
);
console.log(error)
return Promise.reject()
},
)
service.interceptors.response.use(
(response: AxiosResponse) => {
console.log('response', response)
if (response.status === 200) {
return response;
return response
} else {
Promise.reject();
Promise.reject()
}
},
(error: AxiosError) => {
console.log(error);
console.log('error', error)
if (error.response?.status === 401) {
localStorage.removeItem('token');
router.push('/login');
localStorage.removeItem('token')
// router.push('/login')
}
// @ts-ignore
ElMessage.error(error.response?.data?.message);
return Promise.reject();
}
);
ElMessage.error(error.response?.data?.message || '请求失败,请切换网络后尝试')
return Promise.reject()
},
)
export default service;
export default service

View File

@ -0,0 +1,192 @@
<template>
<el-form :model="addAndEditForm" :rules="addAndEditRules" ref="login" label-width="0px" label-position="top">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="工程名称" prop="proName">
<el-input v-model="addAndEditForm.proName" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="电压等级" prop="level">
<el-input v-model="addAndEditForm.level" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="起止时间" prop="startTime">
<el-input v-model="addAndEditForm.startTime" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="竣工日期" prop="endTime">
<el-input v-model="addAndEditForm.endTime" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="变电站座数" prop="num">
<el-input v-model="addAndEditForm.num" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="线路建设规模" prop="scale">
<el-input v-model="addAndEditForm.scale" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="承包范围" prop="fw">
<el-input v-model="addAndEditForm.fw" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="业主单位" prop="unit">
<el-input v-model="addAndEditForm.unit" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="业务单位联系方式" prop="unitPhone">
<el-input v-model="addAndEditForm.unitPhone" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div style="display: flex; align-items: center; padding: 8px 0">
<div> 项目关键人员 </div>
<el-button :icon="CirclePlus" type="primary" link @click="onHandleAdd">添加</el-button>
</div>
<el-table :data="addTableList" stripe style="width: 100%">
<el-table-column label="序号" width="55" type="index" />
<el-table-column align="center" label="担任职务" show-overflow-tooltip>
<template #default="{ row }">
<el-input v-model="row.zhiW" placeholder="请输入职务" clearable />
</template>
</el-table-column>
<el-table-column align="center" label="姓名">
<template #default="{ row }">
<el-select v-model="row.name" clearable>
<el-option label="张三" value="1" />
<el-option label="李四" value="2" />
<el-option label="王五" value="3" />
</el-select>
</template>
</el-table-column>
<el-table-column align="center" prop="zhiW" label="身份证号" show-overflow-tooltip />
<el-table-column align="center" prop="zhiW" label="电话" show-overflow-tooltip />
<el-table-column align="center" label="工作内容" show-overflow-tooltip>
<template #default="{ row }">
<el-input v-model="row.content" placeholder="请输入工作内容" clearable />
</template>
</el-table-column>
<el-table-column align="center" prop="zhiW" label="业绩证明材料" show-overflow-tooltip>
<template #default="scope">
<el-button link @click="uploadOuterVisible = true"> 上传 </el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button :icon="DeleteFilled" type="danger" link @click="onHandleDelete(scope)" />
</template>
</el-table-column>
</el-table>
<el-dialog
title="上传"
width="40%"
v-model="uploadOuterVisible"
v-if="uploadOuterVisible"
:before-close="(uploadOuterVisible = false)"
append-to-body
>
<!-- 外层弹框内容 -->
</el-dialog>
</template>
<script lang="ts" setup>
import { CirclePlus, DeleteFilled } from '@element-plus/icons-vue'
import { ref } from 'vue'
const uploadOuterVisible = ref(false)
const addAndEditForm = ref({
proName: '',
level: '',
startTime: [],
endTime: '',
num: '',
scale: '',
fw: '',
unit: '',
unitPhone: '',
})
const addAndEditRules = ref({
proName: [
{
required: true,
message: '请输入输工程名称',
trigger: 'blur',
},
],
level: [
{
required: true,
message: '请输入电压等级',
trigger: 'blur',
},
],
startTime: [
{
required: true,
message: '请选择起止时间',
trigger: 'blur',
},
],
endTime: [
{
required: true,
message: '请选择竣工时间',
trigger: 'blur',
},
],
fw: [
{
required: true,
message: '请输入承包范围',
trigger: 'blur',
},
],
unit: [
{
required: true,
message: '请输入业主单位',
trigger: 'blur',
},
],
unitPhone: [
{
required: true,
message: '请输入业主单位联系方式',
trigger: 'blur',
},
],
})
const addTableList: any = ref([])
const onHandleAdd = () => {
addTableList.value.push({
zhiW: '',
name: '',
content: '',
})
}
//
const onHandleDelete = (row: any) => {
console.log(row, 'row')
addTableList.value.splice(row.$index, 1)
}
</script>

View File

@ -0,0 +1,115 @@
<template>
<!-- 公司业绩管理 -->
<div class="container">
<el-form :model="queryParam" ref="login" label-width="0px" class="ms-content">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item>
<el-input v-model="queryParam.projectName" placeholder="请输入工程名称" clearable> </el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item>
<el-date-picker
v-model="timeValue"
type="daterange"
range-separator="~"
value-format="YYYY-MM-DD"
end-placeholder="结束时间"
start-placeholder="开始时间"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-button :icon="Search" type="primary">查询</el-button>
<el-button :icon="Refresh">重置</el-button>
<el-button :icon="Plus" type="primary" @click="onHandleAdd">新增业绩</el-button>
<el-button :icon="Download">导出数据</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-table :data="tableList" stripe style="width: 100%">
<el-table-column label="序号" width="55" type="index" />
<el-table-column
:key="index"
align="center"
:prop="item.prop"
:label="item.label"
show-overflow-tooltip
v-for="(item, index) in tableColumn"
/>
<el-table-column label="操作" width="200" align="center">
<template #default="{ row }">
<el-button :icon="WarningFilled" type="success" size="small" link>详情</el-button>
<el-button :icon="EditPen" type="primary" size="small" link>编辑</el-button>
<el-button :icon="DeleteFilled" type="danger" size="small" link>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<DialogModel :dialogConfig="dialogConfig" @closeDialogOuter="closeDialogOuter">
<template #outerContent>
<AddAndEditForm />
</template>
</DialogModel>
</template>
<script setup lang="ts">
import DialogModel from '@/components/DialogModel.vue'
import AddAndEditForm from './components/addAndEditForm.vue'
import { Search, Refresh, Download, Plus, WarningFilled, EditPen, DeleteFilled } from '@element-plus/icons-vue'
import { reactive, ref } from 'vue'
const dialogConfig = ref({
outerTitle: '新增',
innerTitle: false,
outerWidth: '80%',
outerVisible: false,
innerVisible: false,
})
const queryParam = ref({
projectName: '',
startTime: '',
endTime: '',
})
const timeValue = ref([])
const tableList = ref([
{
projectName: '测试工程1',
},
{
projectName: '测试工程2',
},
{
projectName: '测试工程3',
},
])
const tableColumn = ref([
{ label: '工程名称', prop: 'projectName' },
{ label: '电压等级', prop: '' },
{ label: '起止时间', prop: '' },
{ label: '竣工日期', prop: '' },
{ label: '变电站数量', prop: '' },
{ label: '线路建设规模(折单公里)', prop: '' },
{ label: '承包范围', prop: '' },
{ label: '业主单位', prop: '' },
{ label: '业主单位联系方式', prop: '' },
{ label: '关键人员', prop: '' },
])
const onHandleAdd = () => {
console.log('新增')
dialogConfig.value.outerVisible = true
}
const closeDialogOuter = () => {
dialogConfig.value.outerVisible = false
}
</script>
<style scoped lang="scss"></style>

View File

@ -4,7 +4,7 @@
<div class="ms-title">市场部投标信息检索工具</div>
<el-form :model="param" :rules="rules" ref="login" label-width="0px" class="ms-content">
<el-form-item prop="username">
<el-input v-model="param.username" placeholder="username">
<el-input v-model="param.username" placeholder="请输入登录账号" clearable>
<template #prepend>
<el-button :icon="User" disabled></el-button>
</template>
@ -13,9 +13,11 @@
<el-form-item prop="password">
<el-input
type="password"
placeholder="password"
placeholder="请输入密码"
v-model="param.password"
@keyup.enter="submitForm(login)"
show-password
clearable
>
<template #prepend>
<el-button :icon="Lock" disabled></el-button>

View File

@ -1,511 +1,548 @@
<template>
<div class="data-center-wrap">
<el-card shadow="never" style="height: 100%">
<el-row :gutter="20" style="height: 100%">
<el-col :xl="4" :lg="4" style="border-right: 1px solid #dcdfe6">
<div style="margin-bottom: 24px; font-weight: 700">角色管理</div>
<el-divider></el-divider>
<el-button @click="addVisible = true;Object.assign(form, new Role());" type="primary" link
v-action:role:create>新建角色
</el-button>
<div style="margin-top: 16px">
<div
class="role-item"
:class="{ 'role-item-active': item.id === activeRoleId }"
v-for="(item, index) in roleList"
:key="index"
@click="handleRoleChange(item)"
>
<div>
<div>{{ item.name }}</div>
</div>
<el-dropdown trigger="hover">
<el-icon>
<setting/>
</el-icon>
<template #dropdown>
<el-dropdown-menu>
<span v-action:role:update>
<el-dropdown-item @click="handleEdit" v-action:role:update>编辑</el-dropdown-item>
</span>
<span v-action:role:delete>
<el-dropdown-item @click="handleDelete(roleList.find(r => r?.id === activeRoleId))">
<span class="del-btn">删除</span>
</el-dropdown-item>
</span>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</el-col>
<el-col :xl="20" :lg="20">
<el-col :span="24">
<el-col :span="24" style="padding-left: 0px;">
{{ roleList.find(r => r?.id === activeRoleId)?.name }}
<el-button text :icon="Edit" @click="handleEdit" v-action:role:update>
编辑
</el-button>
<el-button text :icon="Delete" class="red"
@click="handleDelete(roleList.find(r => r?.id === activeRoleId))" v-action:role:delete>
删除
</el-button>
</el-col>
<el-col style="font-size: 8px;color: #777777;padding-left: 0px;" :span="24">
{{ roleList.find(r => r?.id === activeRoleId)?.description }}
</el-col>
</el-col>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleChangeRoleUserClient">
<el-tab-pane label="角色成员" name="first">
<div style="margin-bottom: 24px">
<el-button type="primary" @click="isOrgSelectShow = true" v-action:role:update>调整成员</el-button>
</div>
<el-table :data="tableData" border class="table" ref="multipleTable"
header-cell-class-name="table-header">
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
<el-table-column prop="username" label="用户名"></el-table-column>
<el-table-column prop="gender" label="性别">
<template #default="{ row }">
<span>{{ row.gender === 'MALE' ? '男' : '女' }}</span>
</template>
</el-table-column>
<el-table-column label="头像" align="center">
<template #default="scope">
<el-image
class="table-td-thumb"
:src="scope.row.avatar"
:z-index="10"
:preview-src-list="[scope?.row?.avatar]"
preview-teleported
>
</el-image>
</template>
</el-table-column>
<el-table-column label="拥有的角色">
<template #default="scope">
<sppan v-for="(role, index) in scope.row?.roles">
<template v-if="index > 0">, </template>
{{ role.name }}
</sppan>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
layout="total, prev, pager, next"
:current-page="userQuery.pageIndex"
:page-size="userQuery.pageSize"
:total="pageTotal"
@current-change="handlePageChange"
></el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="权限设置" name="second">
<div style="margin-bottom: 24px">
<el-button type="primary" @click="savePermission" v-action:role:update>保存</el-button>
</div>
<div v-for="(menu, index) in rolePermission" :key="index">
<el-row>
<el-col :span="18" :style="{fontWeight:'bold'}">{{ menu.name }}</el-col>
<el-col :span="6" :style="{textAlign:'right'}">
<el-switch
size="small"
v-model="menu.enabled"
@change="onChangeSwitch($event,menu)"/>
</el-col>
</el-row>
<el-divider type="horizontal" :style="{margin: '5px'}"/>
<el-row :gutter="16" v-for="(checkbox, tab) in menu.children" :key="tab">
<el-col :xl="4" :lg="4">
{{ checkbox.name }}
</el-col>
<el-col :xl="20" :lg="20">
<el-checkbox
:disabled="!menu.enabled"
v-model="checkbox.checkedAll"
:indeterminate="checkbox.indeterminate"
@change="onChangeCheckAll($event,checkbox)"
>全选
</el-checkbox>
<el-checkbox-group :disabled="!menu.enabled" v-model="checkbox.selected"
@change="onChangeCheck($event,checkbox)">
<el-checkbox v-for="btn in checkbox?.actionsOptions" :key="btn.id" :label="btn.id">
{{ btn.name }}
</el-checkbox>
</el-checkbox-group>
</el-col>
</el-row>
</div>
<div class="data-center-wrap">
<el-card shadow="never" style="height: 100%">
<el-row :gutter="20" style="height: 100%">
<el-col :xl="4" :lg="4" style="border-right: 1px solid #dcdfe6">
<div style="margin-bottom: 24px; font-weight: 700">角色管理</div>
<el-divider></el-divider>
<el-button
@click="
() => {
addVisible = true
Object.assign(form, new Role())
}
"
type="primary"
link
v-action:role:create
>新建角色
</el-button>
<div style="margin-top: 16px">
<div
class="role-item"
:class="{ 'role-item-active': item.id === activeRoleId }"
v-for="(item, index) in roleList"
:key="index"
@click="handleRoleChange(item)"
>
<div>
<div>{{ item.name }}</div>
</div>
<el-dropdown trigger="hover">
<el-icon>
<setting />
</el-icon>
<template #dropdown>
<el-dropdown-menu>
<span v-action:role:update>
<el-dropdown-item @click="handleEdit" v-action:role:update
>编辑</el-dropdown-item
>
</span>
<span v-action:role:delete>
<el-dropdown-item
@click="handleDelete(roleList.find((r) => r?.id === activeRoleId))"
>
<span class="del-btn">删除</span>
</el-dropdown-item>
</span>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</el-col>
<el-col :xl="20" :lg="20">
<el-col :span="24">
<el-col :span="24" style="padding-left: 0px">
{{ roleList.find((r) => r?.id === activeRoleId)?.name }}
<el-button text :icon="Edit" @click="handleEdit" v-action:role:update> 编辑 </el-button>
<el-button
text
:icon="Delete"
class="red"
@click="handleDelete(roleList.find((r) => r?.id === activeRoleId))"
v-action:role:delete
>
删除
</el-button>
</el-col>
<el-col style="font-size: 8px; color: #777777; padding-left: 0px" :span="24">
{{ roleList.find((r) => r?.id === activeRoleId)?.description }}
</el-col>
</el-col>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleChangeRoleUserClient">
<el-tab-pane label="角色成员" name="first">
<div style="margin-bottom: 24px">
<el-button type="primary" @click="isOrgSelectShow = true" v-action:role:update
>调整成员</el-button
>
</div>
<el-table
:data="tableData"
border
class="table"
ref="multipleTable"
header-cell-class-name="table-header"
>
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
<el-table-column prop="username" label="用户名"></el-table-column>
<el-table-column prop="gender" label="性别">
<template #default="{ row }">
<span>{{ row.gender === 'MALE' ? '男' : '女' }}</span>
</template>
</el-table-column>
<el-table-column label="头像" align="center">
<template #default="scope">
<el-image
class="table-td-thumb"
:src="scope.row.avatar"
:z-index="10"
:preview-src-list="[scope?.row?.avatar]"
preview-teleported
>
</el-image>
</template>
</el-table-column>
<el-table-column label="拥有的角色">
<template #default="scope">
<sppan v-for="(role, index) in scope.row?.roles">
<template v-if="index > 0">, </template>
{{ role.name }}
</sppan>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
layout="total, prev, pager, next"
:current-page="userQuery.pageIndex"
:page-size="userQuery.pageSize"
:total="pageTotal"
@current-change="handlePageChange"
></el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="权限设置" name="second">
<div style="margin-bottom: 24px">
<el-button type="primary" @click="savePermission" v-action:role:update>保存</el-button>
</div>
<div v-for="(menu, index) in rolePermission" :key="index">
<el-row>
<el-col :span="18" :style="{ fontWeight: 'bold' }">{{ menu.name }}</el-col>
<el-col :span="6" :style="{ textAlign: 'right' }">
<el-switch
size="small"
v-model="menu.enabled"
@change="onChangeSwitch($event, menu)"
/>
</el-col>
</el-row>
<el-divider type="horizontal" :style="{ margin: '5px' }" />
<el-row :gutter="16" v-for="(checkbox, tab) in menu.children" :key="tab">
<el-col :xl="4" :lg="4"> {{ checkbox.name }} </el-col>
<el-col :xl="20" :lg="20">
<el-checkbox
:disabled="!menu.enabled"
v-model="checkbox.checkedAll"
:indeterminate="checkbox.indeterminate"
@change="onChangeCheckAll($event, checkbox)"
>全选
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</el-card>
{{ checkbox.id }}
</el-checkbox>
<el-checkbox-group
:disabled="!menu.enabled"
v-model="checkbox.selected"
@change="onChangeCheck($event, checkbox)"
>
<el-checkbox
v-for="btn in checkbox?.actionsOptions"
:key="btn.id"
:label="btn.id"
>
{{ btn.name }}
</el-checkbox>
</el-checkbox-group>
</el-col>
</el-row>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</el-card>
<!-- 组织架构选择弹出框 -->
<OrgSelect
append-to-body
v-if="isOrgSelectShow"
:visible="isOrgSelectShow"
:activeRoleId="activeRoleId"
@on-cancel="handleOrgSelectCancel"
@on-submit="handleOrgSelectSubmit"
/>
<!-- 组织架构选择弹出框 -->
<OrgSelect
append-to-body
v-if="isOrgSelectShow"
:visible="isOrgSelectShow"
:activeRoleId="activeRoleId"
@on-cancel="handleOrgSelectCancel"
@on-submit="handleOrgSelectSubmit"
/>
<!-- 新增弹出框 -->
<el-dialog title="新增" v-model="addVisible" width="30%">
<el-form label-width="70px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addVisible = false"> </el-button>
<el-button type="primary" @click="saveAdd"> </el-button>
</span>
</template>
</el-dialog>
<!-- 新增弹出框 -->
<el-dialog title="新增" v-model="addVisible" width="30%">
<el-form label-width="70px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addVisible = false"> </el-button>
<el-button type="primary" @click="saveAdd"> </el-button>
</span>
</template>
</el-dialog>
<!-- 编辑弹出框 -->
<el-dialog title="编辑" v-model="editVisible" width="30%">
<el-form label-width="70px">
<el-form label-width="70px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea"></el-input>
</el-form-item>
</el-form>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="editVisible = false"> </el-button>
<el-button type="primary" @click="saveEdit"> </el-button>
</span>
</template>
</el-dialog>
</div>
<!-- 编辑弹出框 -->
<el-dialog title="编辑" v-model="editVisible" width="30%">
<el-form label-width="70px">
<el-form label-width="70px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input v-model="form.description" type="textarea"></el-input>
</el-form-item>
</el-form>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="editVisible = false"> </el-button>
<el-button type="primary" @click="saveEdit"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import {reactive, ref} from "vue";
import { reactive, ref } from 'vue'
import {
changeResources,
changeUsers,
createRole,
deleteRole,
getRoleList,
getRoleUserList,
updateRole
} from "../api/role";
import {ElMessage, ElMessageBox, TabsPaneContext} from "element-plus";
import {getResourceTree as reqResourceTree} from "../api/resource";
import {Delete, Edit} from '@element-plus/icons-vue';
import OrgSelect, {OrgSelectedData} from "../components/OrgSelect.vue";
changeResources,
changeUsers,
createRole,
deleteRole,
getRoleList,
getRoleUserList,
updateRole,
} from '../api/role'
import { ElMessage, ElMessageBox, TabsPaneContext } from 'element-plus'
import { getResourceTree as reqResourceTree } from '../api/resource'
import { Delete, Edit } from '@element-plus/icons-vue'
import OrgSelect, { OrgSelectedData } from '../components/OrgSelect.vue'
const isOrgSelectShow = ref(false)
interface Resource {
id: number;
name: string;
type: string;
permission: string;
url: string;
children?: Resource[]
id: number
name: string
type: string
permission: string
url: string
children?: Resource[]
}
interface RoleInterface {
id: number;
name?: string;
description?: string;
resourceIds?: number[];
id: number
name?: string
description?: string
resourceIds?: number[]
}
class Role implements RoleInterface {
id = 0;
name = '';
description = '';
resourceIds = [];
id = 0
name = ''
description = ''
resourceIds = []
}
interface Permission {
id: number;
name: string;
enabled: boolean,
children: {
id: number;
name: string;
checkedAll: boolean;
indeterminate: boolean;
selected: number[];
actionsOptions: {
id: number;
name: string;
id: number
name: string
enabled: boolean
children: {
id: number
name: string
checkedAll: boolean
indeterminate: boolean
selected: number[]
actionsOptions: {
id: number
name: string
}[]
}[]
}[];
}
interface UserTableItem {
id: number;
userName: string;
gender: string;
state: string;
roles: { id: number, name: string }
id: number
userName: string
gender: string
state: string
roles: { id: number; name: string }
}
interface RoleSelectable extends RoleInterface {
value: number;
label?: string;
value: number
label?: string
}
const roleList = ref<RoleInterface[]>([]);
const activeRoleId = ref<number>(1);
const roleList = ref<RoleInterface[]>([])
const activeRoleId = ref<number>(1)
const reqRoleList = async () => {
try {
const { data, } = await getRoleList();
roleList.value = data;
getResourceTree(); //
} catch (error) {
ElMessage.error(error as Error);
}
};
try {
const { data } = await getRoleList()
roleList.value = data
getResourceTree() //
} catch (error) {
ElMessage.error(error as Error)
}
}
reqRoleList();
reqRoleList()
const handleRoleChange = (role: RoleInterface) => {
activeRoleId.value = role.id;
getUserData(role.id);
handlePermission();
activeRoleId.value = role.id
getUserData(role.id)
handlePermission()
}
//
const userQuery = reactive({
username: '',
state: '',
pageIndex: 1,
pageSize: 10
});
const tableData = ref<UserTableItem[]>([]);
const pageTotal = ref(0);
username: '',
state: '',
pageIndex: 1,
pageSize: 10,
})
const tableData = ref<UserTableItem[]>([])
const pageTotal = ref(0)
const getUserData = (roleId: number) => {
getRoleUserList(roleId, {
page: userQuery.pageIndex,
size: userQuery.pageSize,
username: userQuery.username || undefined,
state: userQuery.state || undefined,
}).then(res => {
tableData.value = res.data.list;
pageTotal.value = res.data.total;
});
getRoleUserList(roleId, {
page: userQuery.pageIndex,
size: userQuery.pageSize,
username: userQuery.username || undefined,
state: userQuery.state || undefined,
}).then((res) => {
tableData.value = res.data.list
pageTotal.value = res.data.total
})
}
getUserData(activeRoleId.value);
getUserData(activeRoleId.value)
//
const handlePageChange = (val: number) => {
userQuery.pageIndex = val;
getUserData(activeRoleId.value);
};
userQuery.pageIndex = val
getUserData(activeRoleId.value)
}
//
const activeName = ref('first');
const rolePermission = ref<Permission[]>([]);
const activeName = ref('first')
const rolePermission = ref<Permission[]>([])
const getResourceTree = () => {
//
reqResourceTree().then((res) => {
console.log(res.data, '--996')
rolePermission.value = res.data.map((menu: Resource) => {
return {
id: menu.id,
name: menu.name,
enabled: true,
children:
menu.children?.map((checkbox: Resource) => {
return {
id: checkbox.id,
name: checkbox.name,
checkedAll: false,
indeterminate: false,
selected: [],
actionsOptions:
checkbox.children?.map((p: Resource) => {
return {
id: p.id,
name: p.name,
}
}) || [],
}
}) || [],
}
})
//
reqResourceTree().then(res => {
rolePermission.value = res.data.map((menu: Resource) => {
return {
id: menu.id,
name: menu.name,
enabled: true,
children: menu.children?.map((checkbox: Resource) => {
return {
id: checkbox.id,
name: checkbox.name,
checkedAll: false,
indeterminate: false,
selected: [],
actionsOptions: checkbox.children?.map((p: Resource) => {
return {
id: p.id,
name: p.name
};
}) || []
};
}) || []
};
});
//
handlePermission();
});
//
handlePermission()
})
}
function handlePermission() {
let role: any = roleList.value.find(r => r.id == activeRoleId.value);
const resourceIds: number[] = role.resourceIds || [];
rolePermission.value.forEach(p => {
onChangeSwitch(resourceIds.includes(p.id), p);
p.children.forEach(pp => {
const selected: any[] = pp.actionsOptions.filter(action => resourceIds.includes(action.id)).map(action => action.id);
onChangeCheckAll(selected.length === pp.actionsOptions.length, pp);
pp.selected = selected;
onChangeCheck(selected, pp);
});
});
let role: any = roleList.value.find((r) => r.id == activeRoleId.value)
const resourceIds: number[] = role.resourceIds || []
rolePermission.value.forEach((p) => {
onChangeSwitch(resourceIds.includes(p.id), p)
p.children.forEach((pp) => {
const selected: any[] = pp.actionsOptions
.filter((action) => resourceIds.includes(action.id))
.map((action) => action.id)
onChangeCheckAll(selected.length === pp.actionsOptions.length, pp)
pp.selected = selected
onChangeCheck(selected, pp)
})
})
}
const onChangeSwitch = (enabled: boolean, permission: any) => {
permission.enabled = enabled;
permission.enabled = enabled
}
const onChangeCheckAll = (checked: boolean, permission: any) => {
Object.assign(permission, {
selected: checked ? permission.actionsOptions.map((obj: any) => obj.id) : [],
indeterminate: false,
checkedAll: checked
});
Object.assign(permission, {
selected: checked ? permission.actionsOptions.map((obj: any) => obj.id) : [],
indeterminate: false,
checkedAll: checked,
})
}
const onChangeCheck = (selected: number[], permission: any) => {
permission.indeterminate = !!permission.selected.length && (permission.selected.length < permission.actionsOptions.length);
permission.checkedAll = permission.selected.length === permission.actionsOptions.length;
permission.indeterminate =
!!permission.selected.length && permission.selected.length < permission.actionsOptions.length
permission.checkedAll = permission.selected.length === permission.actionsOptions.length
}
const handleChangeRoleUserClient = (tab: TabsPaneContext, event: Event) => {
}
const handleChangeRoleUserClient = (tab: TabsPaneContext, event: Event) => {}
const handleEdit = () => {
let role: any = roleList.value?.find(r => r?.id === activeRoleId.value);
form.name = role.name;
form.description = role.description;
editVisible.value = true;
};
let role: any = roleList.value?.find((r) => r?.id === activeRoleId.value)
form.name = role.name
form.description = role.description
editVisible.value = true
}
const addVisible = ref<boolean>(false);
const editVisible = ref<boolean>(false);
let form = reactive(new Role());
const addVisible = ref<boolean>(false)
const editVisible = ref<boolean>(false)
let form = reactive(new Role())
const saveAdd = () => {
createRole(form).then(res => {
reqRoleList();
ElMessage.success(`新增成功`);
addVisible.value = false;
});
};
createRole(form).then((res) => {
reqRoleList()
ElMessage.success(`新增成功`)
addVisible.value = false
})
}
const saveEdit = () => {
updateRole(activeRoleId.value, form).then(res => {
reqRoleList();
ElMessage.success(`修改成功`);
editVisible.value = false;
});
};
updateRole(activeRoleId.value, form).then((res) => {
reqRoleList()
ElMessage.success(`修改成功`)
editVisible.value = false
})
}
const savePermission = () => {
let resourceIds: number[] = [];
rolePermission.value.forEach(p => {
if (p.enabled) {
resourceIds.push(p.id);
}
p.children.forEach(pp => {
if (pp.selected?.length) {
resourceIds.push(pp.id);
}
pp.selected.forEach(sel => resourceIds.push(sel));
console.log('rolePermission', rolePermission)
let resourceIds: number[] = []
rolePermission.value.forEach((p) => {
if (p.enabled) {
resourceIds.push(p.id)
}
p.children.forEach((pp) => {
if (pp.selected?.length) {
resourceIds.push(pp.id)
}
if (pp.checkedAll) {
resourceIds.push(pp.id)
}
pp.selected.forEach((sel) => resourceIds.push(sel))
})
})
changeResources(activeRoleId.value, resourceIds).then((res) => {
reqRoleList()
ElMessage.success(`修改角色权限成功`)
editVisible.value = false
})
});
changeResources(activeRoleId.value, resourceIds).then(res => {
reqRoleList();
ElMessage.success(`修改角色权限成功`);
editVisible.value = false;
});
}
//
const handleDelete = (role: any) => {
//
ElMessageBox.confirm('确定要删除吗?', '提示', {
type: 'warning'
}).then(() => {
deleteRole(role.id).then(res => {
reqRoleList();
ElMessage.success('删除成功');
});
}).catch(() => {
});
};
//
ElMessageBox.confirm('确定要删除吗?', '提示', {
type: 'warning',
})
.then(() => {
deleteRole(role.id).then((res) => {
reqRoleList()
ElMessage.success('删除成功')
})
})
.catch(() => {})
}
const handleOrgSelectCancel = () => {
isOrgSelectShow.value = false;
isOrgSelectShow.value = false
}
const handleOrgSelectSubmit = (p: OrgSelectedData) => {
isOrgSelectShow.value = false;
console.log(p);
debugger
let userIds: number[] = p.selected?.map((u: { id: number; }) => u.id);
changeUsers(activeRoleId.value, userIds).then(res => {
getUserData(activeRoleId.value);
ElMessage.success(`修改角色成员成功`);
editVisible.value = false;
});
isOrgSelectShow.value = false
console.log(p)
debugger
let userIds: number[] = p.selected?.map((u: { id: number }) => u.id)
changeUsers(activeRoleId.value, userIds).then((res) => {
getUserData(activeRoleId.value)
ElMessage.success(`修改角色成员成功`)
editVisible.value = false
})
}
</script>
<style scoped lang="scss">
.data-center-wrap {
position: relative;
position: relative;
.role-item {
font-size: 14px;
height: 32px;
line-height: 32px;
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
padding: 0 4px;
.role-item {
font-size: 14px;
height: 32px;
line-height: 32px;
cursor: pointer;
white-space: nowrap;
display: flex;
align-items: center;
padding: 0 4px;
&:hover {
background-color: #f5f7fa;
&:hover {
background-color: #f5f7fa;
}
&-active {
background-color: #ecf5ff;
}
.el-icon {
margin-left: 4px;
}
}
&-active {
background-color: #ecf5ff;
.el-pagination {
display: flex;
justify-content: flex-end;
margin: 20px 0;
padding-bottom: 20px;
}
.el-icon {
margin-left: 4px;
}
}
.el-pagination {
display: flex;
justify-content: flex-end;
margin: 20px 0;
padding-bottom: 20px;
}
}
.red {
color: #F56C6C;
color: #f56c6c;
}
.table-td-thumb {
display: block;
margin: auto;
width: 40px;
height: 40px;
display: block;
margin: auto;
width: 40px;
height: 40px;
}
</style>

View File

@ -1,18 +1,22 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts","src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -1,32 +1,42 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'
export default defineConfig({
base: './',
plugins: [
vue(),
VueSetupExtend(),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
})
],
server: {
host: '0.0.0.0',
port: 8080,
proxy: {
'/admin3': {
target: `http://192.168.0.38:8080`,
},
},
},
optimizeDeps: {
include: ['schart.js']
}
});
base: '/',
plugins: [
vue(),
VueSetupExtend(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
server: {
host: '0.0.0.0',
port: 8080,
proxy: {
'/dev-api': {
// target: `http://192.168.0.38:8080/search_tool`,
target: `http://192.168.0.60:8080`,
secure: false,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/dev-api/, ''),
},
},
},
optimizeDeps: {
include: ['schart.js'],
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})

View File

@ -111,6 +111,13 @@
resolved "https://repo.huaweicloud.com/repository/npm/@types/marked/-/marked-4.0.5.tgz"
integrity sha512-jMN2moJ+lSf1VZXQo3VXeMCjoXuciVONig8+U0YNBop5aBvQw4qkolx1Nzn1i0T8L2l9IZ3jju6bS1pPwlaY1w==
"@types/node@^22.14.1", "@types/node@>= 14":
version "22.14.1"
resolved "https://repo.huaweicloud.com/repository/npm/@types/node/-/node-22.14.1.tgz"
integrity sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==
dependencies:
undici-types "~6.21.0"
"@types/web-bluetooth@^0.0.15":
version "0.0.15"
resolved "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz"
@ -687,6 +694,11 @@ nanoid@^3.3.6:
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
neo-async@^2.6.2:
version "2.6.2"
resolved "https://repo.huaweicloud.com/repository/npm/neo-async/-/neo-async-2.6.2.tgz"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
@ -797,7 +809,14 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
sass@*, sass@^1.49.7:
sass-loader@^16.0.5:
version "16.0.5"
resolved "https://repo.huaweicloud.com/repository/npm/sass-loader/-/sass-loader-16.0.5.tgz"
integrity sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==
dependencies:
neo-async "^2.6.2"
sass@*, sass@^1.3.0, sass@^1.49.7:
version "1.62.1"
resolved "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz"
integrity sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==
@ -872,6 +891,11 @@ ufo@^1.1.2:
resolved "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz"
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
undici-types@~6.21.0:
version "6.21.0"
resolved "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.21.0.tgz"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
unimport@^1.0.1:
version "1.3.0"
resolved "https://registry.npmjs.org/unimport/-/unimport-1.3.0.tgz"