mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-02-02 08:35:25 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
19
jeecgboot-vue3/src/views/system/address/address.api.ts
Normal file
19
jeecgboot-vue3/src/views/system/address/address.api.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
export enum Api {
|
||||
list = '/sys/user/queryByOrgCodeForAddressList',
|
||||
positionList = '/sys/position/list',
|
||||
queryDepartTreeSync = '/sys/sysDepart/queryDepartTreeSync',
|
||||
}
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
export const queryDepartTreeSync = (params?) => defHttp.get({ url: Api.queryDepartTreeSync, params });
|
||||
/**
|
||||
* 部门用户信息
|
||||
*/
|
||||
export const list = (params?) => defHttp.get({ url: Api.list, params });
|
||||
/**
|
||||
* 职务list
|
||||
*/
|
||||
export const positionList = (params?) => defHttp.get({ url: Api.positionList, params });
|
||||
51
jeecgboot-vue3/src/views/system/address/address.data.ts
Normal file
51
jeecgboot-vue3/src/views/system/address/address.data.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { FormSchema } from '/@/components/Form';
|
||||
import { BasicColumn } from '/@/components/Table';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'realname',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '工号',
|
||||
dataIndex: 'workNo',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
dataIndex: 'departName',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '职务',
|
||||
dataIndex: 'post',
|
||||
width: 150,
|
||||
slots: { customRender: 'post' },
|
||||
},
|
||||
{
|
||||
title: '手机',
|
||||
width: 150,
|
||||
dataIndex: 'telephone',
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
width: 150,
|
||||
dataIndex: 'email',
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '姓名',
|
||||
field: 'realname',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
label: '工号',
|
||||
field: 'workNo',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<a-card :bordered="false" style="height: 100%">
|
||||
<a-spin :spinning="loading">
|
||||
<a-input-search placeholder="按部门名称搜索…" style="margin-bottom: 10px" @search="onSearch" allowClear />
|
||||
<!--组织机构树-->
|
||||
<template v-if="treeData.length > 0">
|
||||
<a-tree
|
||||
v-if="!treeReloading"
|
||||
showLine
|
||||
:clickRowToExpand="false"
|
||||
:treeData="treeData"
|
||||
:selectedKeys="selectedKeys"
|
||||
:load-data="loadChildrenTreeData"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
@select="onSelect"
|
||||
></a-tree>
|
||||
</template>
|
||||
<a-empty v-else description="暂无数据" />
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { inject, nextTick, ref, unref } from 'vue';
|
||||
import { queryDepartTreeSync } from '../address.api';
|
||||
import { searchByKeywords } from '/@/views/system/departUser/depart.user.api';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
|
||||
const prefixCls = inject('prefixCls');
|
||||
const emit = defineEmits(['select', 'rootTreeData']);
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
// 部门树列表数据
|
||||
const treeData = ref<any[]>([]);
|
||||
// 当前展开的项
|
||||
const expandedKeys = ref<any[]>([]);
|
||||
// 当前选中的项
|
||||
const selectedKeys = ref<any[]>([]);
|
||||
// 树组件重新加载
|
||||
const treeReloading = ref<boolean>(false);
|
||||
// 当前选中的部门
|
||||
const currentDepart = ref<any>(null);
|
||||
// 搜索关键字
|
||||
const searchKeyword = ref('');
|
||||
|
||||
// 加载顶级部门信息
|
||||
async function loadRootTreeData() {
|
||||
try {
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
const result = await queryDepartTreeSync();
|
||||
if (Array.isArray(result)) {
|
||||
treeData.value = result;
|
||||
}
|
||||
if (expandedKeys.value.length === 0) {
|
||||
autoExpandParentNode();
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
loadRootTreeData();
|
||||
|
||||
// 加载子级部门信息
|
||||
async function loadChildrenTreeData(treeNode) {
|
||||
try {
|
||||
const result = await queryDepartTreeSync({
|
||||
pid: treeNode.dataRef.id,
|
||||
});
|
||||
if (result.length == 0) {
|
||||
treeNode.dataRef.isLeaf = true;
|
||||
} else {
|
||||
treeNode.dataRef.children = result;
|
||||
if (expandedKeys.value.length > 0) {
|
||||
// 判断获取的子级是否有当前展开的项
|
||||
let subKeys: any[] = [];
|
||||
for (let key of expandedKeys.value) {
|
||||
if (result.findIndex((item) => item.id === key) !== -1) {
|
||||
subKeys.push(key);
|
||||
}
|
||||
}
|
||||
if (subKeys.length > 0) {
|
||||
expandedKeys.value = [...expandedKeys.value];
|
||||
}
|
||||
}
|
||||
}
|
||||
treeData.value = [...treeData.value];
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// 自动展开父节点,只展开一级
|
||||
function autoExpandParentNode() {
|
||||
let item = treeData.value[0];
|
||||
if (item) {
|
||||
if (!item.isLeaf) {
|
||||
expandedKeys.value = [item.key];
|
||||
}
|
||||
reloadTree();
|
||||
}
|
||||
}
|
||||
|
||||
// 重新加载树组件,防止无法默认展开数据
|
||||
async function reloadTree() {
|
||||
await nextTick();
|
||||
treeReloading.value = true;
|
||||
await nextTick();
|
||||
treeReloading.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前选中的行
|
||||
*/
|
||||
function setSelectedKey(key: string, data?: object) {
|
||||
selectedKeys.value = [key];
|
||||
if (data) {
|
||||
currentDepart.value = data;
|
||||
emit('select', data);
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索事件
|
||||
async function onSearch(value: string) {
|
||||
if (value) {
|
||||
try {
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
let result = await searchByKeywords({ keyWord: value });
|
||||
if (Array.isArray(result)) {
|
||||
treeData.value = result;
|
||||
}
|
||||
autoExpandParentNode();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
} else {
|
||||
loadRootTreeData();
|
||||
}
|
||||
searchKeyword.value = value;
|
||||
}
|
||||
|
||||
// 树选择事件
|
||||
function onSelect(selKeys, event) {
|
||||
if (selKeys.length > 0 && selectedKeys.value[0] !== selKeys[0]) {
|
||||
setSelectedKey(selKeys[0], event.selectedNodes[0]);
|
||||
} else {
|
||||
// 这样可以防止用户取消选择
|
||||
setSelectedKey(selectedKeys.value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
loadRootTreeData,
|
||||
});
|
||||
</script>
|
||||
13
jeecgboot-vue3/src/views/system/address/index.less
Normal file
13
jeecgboot-vue3/src/views/system/address/index.less
Normal file
@ -0,0 +1,13 @@
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-address-list';
|
||||
|
||||
.@{prefix-cls} {
|
||||
// update-begin-author:liusq date:20230625 for: [issues/563]暗色主题部分失效
|
||||
background-color: @component-background;
|
||||
// update-end-author:liusq date:20230625 for: [issues/563]暗色主题部分失效
|
||||
&--box {
|
||||
.ant-tabs-nav {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
jeecgboot-vue3/src/views/system/address/index.vue
Normal file
89
jeecgboot-vue3/src/views/system/address/index.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<a-row :class="['p-4', `${prefixCls}--box`]" type="flex" :gutter="10" style="max-height: 800px">
|
||||
<a-col :xl="6" :lg="24" :md="24" style="margin-bottom: 10px">
|
||||
<DepartLeftTree ref="leftTree" @select="onTreeSelect" />
|
||||
</a-col>
|
||||
<a-col :xl="18" :lg="24" :md="24" style="margin-bottom: 10px">
|
||||
<div style="height: 100%;" class="address-book">
|
||||
<!--引用表格-->
|
||||
<BasicTable @register="registerTable">
|
||||
<template #post="{ text }">
|
||||
{{
|
||||
(text || '')
|
||||
.split(',')
|
||||
.map((t) => (positionInfo[t] ? positionInfo[t] : t))
|
||||
.join(',')
|
||||
}}
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { provide, ref, unref } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import DepartLeftTree from './components/DepartLeftTree.vue';
|
||||
import { BasicTable } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns, searchFormSchema } from './address.data';
|
||||
import { list, positionList } from './address.api';
|
||||
|
||||
const { prefixCls } = useDesign('address-list');
|
||||
provide('prefixCls', prefixCls);
|
||||
|
||||
// 给子组件定义一个ref变量
|
||||
const leftTree = ref();
|
||||
|
||||
// 当前选中的部门code
|
||||
const orgCode = ref('');
|
||||
const positionInfo = ref({});
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
tableProps: {
|
||||
api: list,
|
||||
columns,
|
||||
//update-begin---author:wangshuai ---date:20220629 for:[VUEN-1485]进入系统管理--通讯录页面后,网页命令行报错------------
|
||||
rowKey: 'userId',
|
||||
//update-end---author:wangshuai ---date:20220629 for:[VUEN-1485]进入系统管理--通讯录页面后,网页命令行报错--------------
|
||||
showIndexColumn: true,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
canResize: false,
|
||||
actionColumn: null,
|
||||
showTableSetting: false,
|
||||
// 请求之前对参数做处理
|
||||
beforeFetch(params) {
|
||||
params.orgCode = orgCode.value;
|
||||
},
|
||||
},
|
||||
});
|
||||
//注册table数据
|
||||
const [registerTable, { reload }] = tableContext;
|
||||
|
||||
// 左侧树选择后触发
|
||||
function onTreeSelect(data) {
|
||||
orgCode.value = data.orgCode;
|
||||
reload();
|
||||
}
|
||||
|
||||
// 查询职务信息
|
||||
async function queryPositionInfo() {
|
||||
const result = await positionList({ pageSize: 99999 });
|
||||
if (result) {
|
||||
let obj = {};
|
||||
result.records.forEach((position) => {
|
||||
obj[position['id']] = position['name'];
|
||||
});
|
||||
positionInfo.value = obj;
|
||||
}
|
||||
}
|
||||
queryPositionInfo();
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import './index.less';
|
||||
</style>
|
||||
Reference in New Issue
Block a user