初始化版本,引入智慧食堂模块,第三方模块

This commit is contained in:
zjf committed 2024-12-06 18:48:18 +08:00
commit d22f88efd3
677 files changed
+69341

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
<template>
<el-dialog :title="dataForm.deptId ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible" width="600">
<el-form ref="deptDialogFormRef" :model="dataForm" label-width="90px" :rules="dataRules" v-loading="loading">
<el-form-item :label="$t('sysdept.parentId')" prop="parentId">
<el-tree-select
v-model="dataForm.parentId"
:data="parentData"
:props="{ value: 'id', label: 'name', children: 'children' }"
class="w100"
clearable
check-strictly
:render-after-expand="false"
:placeholder="$t('sysdept.inputparentIdTip')"
/>
</el-form-item>
<el-form-item :label="$t('sysdept.name')" prop="name">
<el-input v-model="dataForm.name" :placeholder="$t('sysdept.inputnameTip')" clearable />
</el-form-item>
<el-form-item :label="$t('sysdept.sortOrder')" prop="sortOrder">
<el-input-number v-model="dataForm.sortOrder" :placeholder="$t('sysdept.inputsortOrderTip')" clearable />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="systemDeptDialog">
import { useI18n } from 'vue-i18n';
import { getObj, deptTree, addObj, putObj } from '/@/api/admin/dept';
import { useMessage } from '/@/hooks/message';
import {rule} from "/@/utils/validate";
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
const { t } = useI18n();
// 定义变量内容
const deptDialogFormRef = ref();
const dataForm = reactive({
parentId: '',
deptId: '',
name: '',
sortOrder: 9999,
});
const parentData = ref<any[]>([]);
const visible = ref(false);
const loading = ref(false);
const dataRules = ref({
parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
name: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
sortOrder: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
});
// 打开弹窗
const openDialog = (type: string, id: string) => {
visible.value = true;
dataForm.deptId = '';
nextTick(() => {
deptDialogFormRef.value?.resetFields();
dataForm.parentId = id;
});
if (type === 'edit') {
getObj(id)
.then((res) => {
Object.assign(dataForm, res.data);
})
.catch((err) => {
useMessage().error(err.msg);
});
}
getDeptData();
};
// 提交
const onSubmit = async () => {
const valid = await deptDialogFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
loading.value = true;
dataForm.deptId ? await putObj(dataForm) : await addObj(dataForm);
useMessage().success(t(dataForm.deptId ? 'common.editSuccessText' : 'common.addSuccessText'));
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
// 从后端获取菜单信息
const getDeptData = async () => {
deptTree().then((res) => {
parentData.value = [];
const dept = {
id: '0',
name: '根部门',
children: [] as any[],
};
dept.children = res.data;
parentData.value.push(dept);
});
};
// 暴露变量
defineExpose({
openDialog,
});
</script>
+21
View File
@@ -0,0 +1,21 @@
export default {
sysdept: {
name: 'dept name',
parentId: 'parent dept',
createTime: 'createTime',
weight: 'weight',
leaderId: 'dept leader',
sortOrder: 'sortOrder',
inputdeptNameTip: 'input deptName',
inputnameTip: 'input deptName',
inputparentIdTip: 'select deptName',
inputLeaderIdTip: 'input leader',
inputsortOrderTip: 'input sortOrder',
importTip: 'import dept',
addNodeText:'add dept',
editNodeText:'edit dept',
delNodeText:'delete dept',
view: 'tree/table view',
tenantNodeErrorText: 'The current node cannot be operated. You need to maintain it in tenant management',
},
};
+21
View File
@@ -0,0 +1,21 @@
export default {
sysdept: {
name: '部门名称',
parentId: '上级部门',
createTime: '创建时间',
weight: '排序',
sortOrder: '排序',
leaderId: '部门负责人',
inputdeptNameTip: '请输入部门名称',
inputnameTip: '请输入部门名称',
inputLeaderIdTip: '请输入部门领导',
inputparentIdTip: '请选择上级部门',
inputsortOrderTip: '请输入排序',
importTip: '导入部门',
addNodeText: '添加部门',
editNodeText: '编辑部门',
delNodeText: '删除部门',
tenantNodeErrorText: '当前节点不可操作,请在租户管理功能中维护',
view: '树/表视图'
},
};
+130
View File
@@ -0,0 +1,130 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row shadow="hover" v-show="showSearch" class="ml10">
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="filter">
<el-form-item prop="deptName" :label="$t('sysdept.name')">
<el-input :placeholder="$t('sysdept.inputdeptNameTip')" style="max-width: 180px" v-model="state.queryForm.deptName"></el-input>
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="filter">
{{ $t('common.queryBtn') }}
</el-button>
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="top-right-btn" v-if="!defaultTreeViewRef" v-auth="'sys_dept_add'" @click="handleAdd">
{{ $t('common.addBtn') }}
</el-button>
<el-button plain icon="upload-filled" type="primary" class="ml10" @click="excelUploadRef.show()">
{{ $t('common.importBtn') }}
</el-button>
<el-button @click="handleExpand"> {{ $t('common.expandBtn') }}</el-button>
<right-toolbar
v-model:showSearch="showSearch"
:export="'sys_dept_add'"
@exportExcel="exportExcel"
class="ml10"
style="float: right; margin-right: 20px"
@queryTable="getDataList"
>
<el-tooltip class="item" effect="dark" :content="$t('queryTree.view')" placement="top">
<el-button circle icon="Grid" @click="handleView"></el-button>
</el-tooltip>
</right-toolbar>
</div>
</el-row>
<tree-view ref="treeViewRef" v-if="defaultTreeViewRef" />
<table-view ref="tableViewRef" v-if="!defaultTreeViewRef" />
<upload-excel
ref="excelUploadRef"
:title="$t('sysdept.importTip')"
url="/admin/dept/import"
temp-url="/admin/sys-file/local/file/dept.xlsx"
@refreshDataList="getDataList"
/>
</div>
</div>
</template>
<script lang="ts" name="systemDept" setup>
import { downBlobFile } from '/@/utils/other';
import { useI18n } from 'vue-i18n';
const TreeView = defineAsyncComponent(() => import('./tree-view.vue'));
const TableView = defineAsyncComponent(() => import('./table-view.vue'));
const { t } = useI18n();
// 默认树视图展示
const defaultTreeViewRef = ref(true);
const treeViewRef = ref();
const tableViewRef = ref();
const excelUploadRef = ref();
const showSearch = ref(true);
const isExpand = ref(false);
const queryRef = ref();
const state = reactive({
queryForm: {
deptName: '',
},
});
/**
* 过滤节点
*/
const filter = () => {
if (defaultTreeViewRef.value) {
treeViewRef.value.filter(state.queryForm.deptName);
} else {
tableViewRef.value.state.queryForm.deptName = state.queryForm.deptName;
tableViewRef.value.getDataList();
}
};
const handleAdd = () => {
tableViewRef.value.handleAdd();
};
const handleView = () => {
defaultTreeViewRef.value = !defaultTreeViewRef.value;
};
/**
* 处理展开/折叠树
*/
const handleExpand = () => {
if (defaultTreeViewRef.value) {
treeViewRef.value.handleExpand();
} else {
tableViewRef.value.handleExpand();
}
};
/**
* 导出Excel
*/
const exportExcel = () => {
downBlobFile('/admin/dept/export', state.queryForm, 'dept.xlsx');
};
const getDataList = () => {
if (defaultTreeViewRef.value) {
treeViewRef.value.getOrgData();
} else {
tableViewRef.value.getDataList();
}
};
/**
* 重置查询条件
*/
const resetQuery = () => {
queryRef.value.resetFields();
};
</script>
+137
View File
@@ -0,0 +1,137 @@
<template>
<el-table
ref="tableRef"
:data="state.dataList"
v-loading="state.loading"
style="width: 100%"
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle?.headerCellStyle"
>
<el-table-column :label="$t('sysdept.name')" prop="name" width="400" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('sysdept.weight')" prop="weight" show-overflow-tooltip width="80"></el-table-column>
<el-table-column prop="createTime" :label="$t('sysdept.createTime')" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('common.action')" show-overflow-tooltip width="250">
<template #default="scope">
<el-button text type="primary" icon="folder-add" @click="deptDialogRef.openDialog('add', scope.row?.id)"
v-auth="'sys_dept_add'">
{{ $t('common.addBtn') }}
</el-button
>
<el-button text type="primary" icon="edit-pen" @click="deptDialogRef.openDialog('edit', scope.row?.id)"
v-auth="'sys_dept_edit'">{{
$t('common.editBtn')
}}
</el-button>
<el-button text type="primary" icon="delete" @click="handleDelete(scope.row)" v-auth="'sys_dept_del'">
{{ $t('common.delBtn') }}
</el-button
>
</template>
</el-table-column>
</el-table>
<dept-form ref="deptDialogRef" @refresh="getDataList()"/>
</template>
<script setup lang="ts" name="systemDept">
import {BasicTableProps, useTable} from '/@/hooks/table';
import {deptTree, delObj} from '/@/api/admin/dept';
import {useMessage, useMessageBox} from '/@/hooks/message';
import {useI18n} from 'vue-i18n';
// 引入组件
const DeptForm = defineAsyncComponent(() => import('./form.vue'));
const {t} = useI18n();
// 定义变量内容
const tableRef = ref(); // 表格引用
const deptDialogRef = ref(); // 部门对话框引用
const excelUploadRef = ref(); // Excel上传引用
const showSearch = ref(true); // 是否显示搜索栏
const isExpand = ref(false); // 是否展开
/**
* 查询部门树方法,返回 Promise 对象
* @param params - 查询参数
* @returns Promise&lt;any&gt;
*/
const queryDeptTree = (params?: any) => {
return deptTree(params);
};
/**
* 定义响应式表格数据
*/
const state: BasicTableProps = reactive<BasicTableProps>({
pageList: queryDeptTree, // 页面列表数据
queryForm: {
deptName: '', // 部门名称
},
isPage: false, // 是否分页
descs: ['create_time'], // 排序字段
});
/**
* 使用 useTable 定义表格相关操作
*/
const {getDataList, tableStyle} = useTable(state);
/**
* 展开/折叠部门树方法
*/
const handleExpand = async () => {
isExpand.value = !isExpand.value;
const dataList = await deptTree();
toggleExpand(dataList.data, isExpand.value);
};
/**
* 递归方法,用于展开/折叠部门树
* @param children - 子节点
* @param unfold - 是否展开
*/
const toggleExpand = (children: any[], unfold = true) => {
for (const key in children) {
tableRef.value?.toggleRowExpansion(children[key], unfold);
if (children[key].children) {
toggleExpand(children[key].children!, unfold);
}
}
};
/**
* 删除当前行
* @param row - 当前行数据
*/
const handleDelete = async (row: any) => {
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(row.id);
getDataList();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
const handleAdd = ()=>{
deptDialogRef.value.openDialog('add')
}
/**
* 暴露组件中的一些方法和变量
*/
defineExpose({
handleAdd, // 新增时间
state, // 响应式表格数据
getDataList, // 获取列表数据方法
handleExpand // 展开/折叠部门树方法
});
</script>
+198
View File
@@ -0,0 +1,198 @@
<template>
<div style="height: 100%">
<vue3-tree-org
ref="treeOrgRef"
:props="props"
:data="data"
:label-style="style"
:define-menus="defineMenus"
:default-expand-level="expandLevel"
center
:horizontal="horizontal"
:collapsable="collapsable"
:only-one-node="onlyOneNode"
:filter-node-method="filterNodeMethod"
:clone-node-drag="cloneNodeDrag"
:node-add="addNode"
:node-delete="delNode"
:node-edit="editNode"
@on-node-click="onNodeClick"
/>
</div>
<dept-form ref="deptDialogRef" @refresh="getOrgData()" />
</template>
<script lang="ts" name="treeView" setup>
import { useMessage, useMessageBox } from '/@/hooks/message';
import { delObj, deptTree } from '/@/api/admin/dept';
import { getObj } from '/@/api/admin/tenant';
import { Session } from '/@/utils/storage';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { useThemeConfig } from '/@/stores/themeConfig';
const DeptForm = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n();
// 定义org组件key-value定义
const props = reactive({ id: 'id', pid: 'parentId', label: 'name', expand: 'expand', children: 'children' });
const data = reactive({});
// 定义org组件右键定义
const defineMenus = reactive([
{ name: t('sysdept.addNodeText'), command: 'add' },
{ name: t('sysdept.editNodeText'), command: 'edit' },
{ name: t('sysdept.delNodeText'), command: 'delete' },
]);
const cloneNodeDrag = ref(true);
const collapsable = ref(false);
const expandLevel = ref(2); //默认展开层级
const horizontal = ref(false);
const onlyOneNode = ref(false);
const treeOrgRef = ref();
const deptDialogRef = ref();
// 添加主题配置
const themeConfig = useThemeConfig();
const { themeConfig: theme } = storeToRefs(themeConfig);
// 添加 style 定义
const style = computed(() => ({
background: theme.value.isDark ? 'var(--el-bg-color-overlay)' : 'var(--el-bg-color-page)',
color: theme.value.isDark ? 'var(--el-text-color-primary)' : '#5e6d82',
}));
/**
* 过滤节点
*/
const filter = (deptName: string) => {
treeOrgRef.value.filter(deptName);
};
/**
* 节点过滤方法
* @param {string} value 过滤条件
* @param {object} data 节点数据
* @returns {boolean} 返回过滤结果
*/
const filterNodeMethod = (value, data) => {
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
/**
* 处理展开/折叠树
*/
const handleExpand = async () => {
collapsable.value = !collapsable.value;
};
/**
* 检查节点是否是根租户节点
* @param {object} node 节点对象
* @returns {boolean} 如果节点是根租户节点,返回true;否则返回false
*/
const checkNode = (node) => {
if (node?.id === '0') {
useMessage().error(t('sysdept.tenantNodeErrorText'));
return false;
}
return true;
};
/**
* 当用户左键点击节点,模拟触发组件的右键事件
* @param e
*/
const onNodeClick = (e: any) => {
const { clientX, clientY } = e;
const rightFun = new MouseEvent('contextmenu', {
bubbles: true,
cancelable: false,
view: window,
button: 2,
buttons: 0,
clientX,
clientY,
});
e.target.dispatchEvent(rightFun);
};
/**
* 添加部门
* @param {object} node 节点对象
*/
const addNode = (node) => {
deptDialogRef.value.openDialog('add', node?.id);
};
/**
* 编辑部门
* @param {object} node 节点对象
*/
const editNode = (node) => {
if (!checkNode(node)) {
return;
}
deptDialogRef.value.openDialog('edit', node?.id);
};
/**
* 删除部门
* @param {object} node 节点对象
*/
const delNode = async (node) => {
if (!checkNode(node)) {
return;
}
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(node.id);
await getOrgData();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
/**
* 查询部门数据
*/
const getOrgData = async () => {
// 查询当前租户信息
const tenant = await getObj(Session.getTenant());
deptTree().then((res) => {
Object.assign(data, { id: '0', name: tenant.data.name });
data.children = res.data;
});
};
onMounted(() => {
getOrgData();
});
// 暴露变量
defineExpose({
getOrgData,
handleExpand,
filter,
});
</script>
<style lang="scss" scoped>
:deep(.zm-tree-org) {
height: 100%;
padding: 15px;
position: relative;
background: var(--el-bg-color);
box-sizing: border-box;
}
</style>