feat(部门管理): 部门详情与统计的添加

This commit is contained in:
sheng
2023-08-02 17:40:57 +08:00
committed by 李强
parent 59b1b54da1
commit 01394c6904
4 changed files with 172 additions and 47 deletions

View File

@@ -1,6 +1,8 @@
import { request, downloadFile } from '/@/utils/service'; import { request, downloadFile } from '/@/utils/service';
import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud'; import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
type GetListType = PageQuery & { show_all: string }
export const apiPrefix = '/api/system/user/'; export const apiPrefix = '/api/system/user/';
export function GetDept(query: PageQuery) { export function GetDept(query: PageQuery) {
@@ -11,7 +13,7 @@ export function GetDept(query: PageQuery) {
}); });
} }
export function GetList(query: PageQuery) { export function GetList(query: GetListType) {
return request({ return request({
url: apiPrefix, url: apiPrefix,
method: 'get', method: 'get',
@@ -56,3 +58,10 @@ export function exportData(params: any) {
method: 'get' method: 'get'
}) })
} }
export function getDeptInfoById(id: string, type: string) {
return request({
url: `/api/system/dept/dept_info/?dept_id=${id}&show_all=${type}`,
method: 'get',
});
}

View File

@@ -5,9 +5,10 @@ import * as api from './api';
import { dictionary } from '/@/utils/dictionary'; import { dictionary } from '/@/utils/dictionary';
import { successMessage } from '/@/utils/message'; import { successMessage } from '/@/utils/message';
export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery) => { const pageRequest = async (query: UserPageQuery) => {
const res = await api.GetList(query); const show_all = context?.isShowChildFlag.value ? '1' : '0';
const res = await api.GetList({ ...query, show_all });
/** /**
* 处理crud警告Invalid prop: type check failed for prop "name". Expected String with value "2", got Number with value 2. * 处理crud警告Invalid prop: type check failed for prop "name". Expected String with value "2", got Number with value 2.
*/ */
@@ -24,10 +25,14 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
return await api.UpdateObj(form); return await api.UpdateObj(form);
}; };
const delRequest = async ({ row }: DelReq) => { const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id); const res = await api.DelObj(row.id);
context?.getDeptInfo();
return res;
}; };
const addRequest = async ({ form }: AddReq) => { const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form); const res = await api.AddObj(form);
context?.getDeptInfo();
return res;
}; };
const exportRequest = async (query: UserPageQuery) => { const exportRequest = async (query: UserPageQuery) => {

View File

@@ -1,26 +1,34 @@
<template> <template>
<div class="dept-user-com-box dept-info"> <div class="dept-user-com-box dept-info">
<div class="di-left"> <div class="di-left">
<h3>{{ deptInfo.dept_name || '' }}</h3>
<div class="di-cell"> <div class="di-cell">
<h3>技术</h3> <p>门负责人</p>
<!-- <el-switch <p class="content">{{ deptInfo.owner || '无' }}</p>
v-model="isShowChildFlag"
inline-prompt
active-text=""
inactive-text=""
style="--el-switch-on-color: var(--el-color-primary)"
/> -->
</div> </div>
<div class="di-cell"> <div class="di-cell">
<p>部门人数10</p> <p>部门人数</p>
<p class="di-margin">部门负责人test</p> <p class="content">{{ deptInfo.dept_user || 0 }}</p>
</div>
<div class="di-cell">
<p>部门简介</p>
<p class="content">{{ deptInfo.description || '无' }}</p>
</div>
<div class="di-cell">
<p>显示子级</p>
<el-switch
v-model="isShowChildFlag"
inline-prompt
active-text=""
inactive-text=""
:disabled="!currentDeptId"
@change="handleSwitchChange"
style="--el-switch-on-color: var(--el-color-primary)"
/>
</div> </div>
<p>部门简介</p>
</div>
<div style="height: 100px; width: 150px" ref="deptSexPie"></div>
<div class="dept-split">
<div class="ds-line"></div>
</div> </div>
<div style="height: 180px; width: 380px" ref="deptCountBar"></div>
<div style="height: 180px; width: 200px" ref="deptSexPie"></div>
</div> </div>
<fs-crud ref="crudRef" v-bind="crudBinding" customClass="dept-user-com-box dept-user-com-table"> <fs-crud ref="crudRef" v-bind="crudBinding" customClass="dept-user-com-box dept-user-com-table">
<!-- --> <!-- -->
@@ -35,9 +43,13 @@ import { ref, onMounted } from 'vue';
import { useExpose, useCrud } from '@fast-crud/fast-crud'; import { useExpose, useCrud } from '@fast-crud/fast-crud';
import { createCrudOptions } from './crud'; import { createCrudOptions } from './crud';
import importExcel from '/@/components/importExcel/index.vue'; import importExcel from '/@/components/importExcel/index.vue';
import * as echarts from 'echarts';
import { ECharts, EChartsOption, init } from 'echarts'; import { ECharts, EChartsOption, init } from 'echarts';
import { getDeptInfoById } from './api';
import { HeadDeptInfoType } from '../../types';
let chart: ECharts; let deptCountChart: ECharts;
let deptSexChart: ECharts;
// crud组件的ref // crud组件的ref
const crudRef = ref(); const crudRef = ref();
@@ -45,23 +57,66 @@ const crudRef = ref();
const crudBinding = ref(); const crudBinding = ref();
// 暴露的方法 // 暴露的方法
const { crudExpose } = useExpose({ crudRef, crudBinding }); const { crudExpose } = useExpose({ crudRef, crudBinding });
// 你的crud配置
const { crudOptions } = createCrudOptions({ crudExpose });
// 初始化crud配置
const { resetCrudOptions } = useCrud({
crudExpose,
crudOptions,
context: {},
});
let currentDeptId = ref('');
let deptCountBar = ref();
let deptSexPie = ref(); let deptSexPie = ref();
let isShowChildFlag = ref(false); let isShowChildFlag = ref(false);
let deptInfo = ref<Partial<HeadDeptInfoType>>({});
/** /**
* 部门切换刷新用户列表 * 初始化顶部部门折线图
*/ */
const handleDoRefreshUser = (id: string) => { const initDeptCountBarChart = () => {
crudExpose.doSearch({ form: { dept: id } }); const xAxisData = deptInfo.value.sub_dept_map?.map((item) => item.name) || [];
const yAxisData = deptInfo.value.sub_dept_map?.map((item) => item.count) || [];
const option: EChartsOption = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
xAxis: {
type: 'category',
data: xAxisData,
axisTick: {
alignWithLabel: true,
},
},
yAxis: {
type: 'value',
},
dataZoom: [
{
type: 'inside',
},
],
grid: {
top: '6%',
right: '5%',
bottom: '10%',
left: '10%',
},
series: [
{
data: yAxisData,
type: 'bar',
barWidth: '60%',
showBackground: true,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' },
]),
},
},
],
};
deptCountChart.setOption(option);
}; };
/** /**
@@ -75,7 +130,7 @@ const initDeptSexPieChart = () => {
legend: { legend: {
orient: 'vertical', orient: 'vertical',
right: '0%', right: '0%',
left: '58%', left: '65%',
top: 'center', top: 'center',
itemWidth: 12, itemWidth: 12,
itemHeight: 12, itemHeight: 12,
@@ -84,32 +139,68 @@ const initDeptSexPieChart = () => {
{ {
type: 'pie', type: 'pie',
radius: '65%', radius: '65%',
center: ['35%', '50%'], center: ['32%', '50%'],
label: { label: {
show: false, show: false,
position: 'center', position: 'center',
}, },
color: ['#51A3FC', '#E790E8', '#dcdfe6'], color: ['#188df0', '#f56c6c', '#dcdfe6'],
data: [ data: [
{ value: 1048, name: '男' }, { value: deptInfo.value.gender?.male || 0, name: '男' },
{ value: 735, name: '女' }, { value: deptInfo.value.gender?.female || 0, name: '女' },
{ value: 580, name: '未知' }, { value: deptInfo.value.gender?.unknown || 0, name: '未知' },
], ],
}, },
], ],
}; };
chart.setOption(option); deptSexChart.setOption(option);
};
/**
* 获取顶部部门信息
*/
const getDeptInfo = async () => {
const res = await getDeptInfoById(currentDeptId.value, isShowChildFlag.value ? '1' : '0');
if (res?.code === 2000) {
deptInfo.value = res.data;
initDeptCountBarChart();
initDeptSexPieChart();
}
};
/**
* 部门切换刷新用户列表
*/
const handleDoRefreshUser = (id: string) => {
currentDeptId.value = id;
crudExpose.doSearch({ form: { dept: id } });
getDeptInfo();
};
const handleSwitchChange = () => {
handleDoRefreshUser(currentDeptId.value);
}; };
onMounted(() => { onMounted(() => {
crudExpose.doRefresh(); crudExpose.doRefresh();
chart = init(deptSexPie.value as HTMLElement); deptCountChart = init(deptCountBar.value as HTMLElement);
initDeptSexPieChart(); deptSexChart = init(deptSexPie.value as HTMLElement);
getDeptInfo();
}); });
defineExpose({ defineExpose({
handleDoRefreshUser, handleDoRefreshUser,
}); });
// 你的crud配置
const { crudOptions } = createCrudOptions({ crudExpose, context: { getDeptInfo, isShowChildFlag } });
// 初始化crud配置
const { resetCrudOptions } = useCrud({
crudExpose,
crudOptions,
context: {},
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -136,14 +227,21 @@ defineExpose({
font-weight: 900; font-weight: 900;
} }
.di-cell { .di-cell {
margin-top: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
}
.di-margin { p:nth-child(1) {
margin-left: 20px; display: block;
} width: 85px;
p { text-align: left;
margin-top: 6px; }
.content {
max-width: 120px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
} }
} }
} }

View File

@@ -52,4 +52,17 @@ export interface DeptListType {
id: number; id: number;
name: string; name: string;
parent: number; parent: number;
}
export interface HeadDeptInfoType {
dept_name: string;
dept_user: number;
owner: string;
description: string;
gender: {
male: number;
female: number;
unknown: number;
};
sub_dept_map: { name: string; count: number }[]
} }