|
@@ -9,7 +9,7 @@
|
|
<div class="head-container">
|
|
<div class="head-container">
|
|
<el-tree
|
|
<el-tree
|
|
ref="treeRef"
|
|
ref="treeRef"
|
|
- :data="deptList"
|
|
|
|
|
|
+ :data="fileList"
|
|
:expand-on-click-node="false"
|
|
:expand-on-click-node="false"
|
|
:filter-node-method="filterNode"
|
|
:filter-node-method="filterNode"
|
|
:props="defaultProps"
|
|
:props="defaultProps"
|
|
@@ -19,62 +19,187 @@
|
|
@node-click="handleNodeClick"
|
|
@node-click="handleNodeClick"
|
|
@node-contextmenu="handleRightClick"
|
|
@node-contextmenu="handleRightClick"
|
|
style="height: 35em"
|
|
style="height: 35em"
|
|
- />
|
|
|
|
|
|
+ >
|
|
|
|
+ <template #default="{ node}">
|
|
|
|
+ <div class="custom-node">
|
|
|
|
+ <!-- 手动添加图标 -->
|
|
|
|
+<!-- <icon style="vertical-align: middle" icon="ep:search" />-->
|
|
|
|
+ <el-icon style="vertical-align: middle"><Folder /></el-icon> <!-- 文件夹图标 -->
|
|
|
|
+ <span style="vertical-align: middle;margin-left: 3px">{{ node.data.name }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </el-tree>
|
|
</div>
|
|
</div>
|
|
- <div
|
|
|
|
- v-show="menuVisible"
|
|
|
|
- class="custom-menu"
|
|
|
|
- :style="{ left: menuX + 'px', top: menuY + 'px' }"
|
|
|
|
- >
|
|
|
|
|
|
+ <div v-show="menuVisible" ref="contextMenuRef" class="custom-menu" :style="{ left: menuX + 'px', top: menuY + 'px' }">
|
|
<ul>
|
|
<ul>
|
|
- <li @click="handleMenuClick('add')">新增子节点</li>
|
|
|
|
- <li @click="handleMenuClick('edit')">重命名</li>
|
|
|
|
- <li @click="handleMenuClick('delete')">删除</li>
|
|
|
|
|
|
+ <li style="border-bottom: 1px solid #ccc;" @click="handleMenuClick('add')">新增子节点</li>
|
|
|
|
+ <li style="border-bottom: 1px solid #ccc;" @click="handleMenuClick('edit')">编辑节点</li>
|
|
|
|
+ <li @click="handleMenuClick('delete')">删除节点</li>
|
|
</ul>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
+
|
|
|
|
+ <Dialog v-model="dialogVisible" :title="dialogTitle" style="width: 40em">
|
|
|
|
+ <el-form
|
|
|
|
+ ref="formRef"
|
|
|
|
+ v-loading="formLoading"
|
|
|
|
+ :model="formData"
|
|
|
|
+ :rules="formRules"
|
|
|
|
+ label-width="80px"
|
|
|
|
+ >
|
|
|
|
+ <el-form-item label="资料分类名称" prop="name" label-width="110px">
|
|
|
|
+ <el-input v-model="formData.name" placeholder="请输入资料分类名称" />
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="显示排序" prop="sort" label-width="110px">
|
|
|
|
+ <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="备注" prop="remark" label-width="110px">
|
|
|
|
+ <el-input
|
|
|
|
+ v-model="formData.remark"
|
|
|
|
+ maxlength="11"
|
|
|
|
+ placeholder="请输入备注"
|
|
|
|
+ type="textarea"
|
|
|
|
+ />
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-form>
|
|
|
|
+ <template #footer>
|
|
|
|
+ <el-button type="primary" @click="submitForm">确 定</el-button>
|
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
|
+ </template>
|
|
|
|
+ </Dialog>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
-import { ElTree } from 'element-plus'
|
|
|
|
-import * as DeptApi from '@/api/system/dept'
|
|
|
|
|
|
+import { ElTree, FormRules } from 'element-plus'
|
|
|
|
+import * as FileClassifyApi from '@/api/pms/info'
|
|
|
|
+import * as InfoClassifyApi from '@/api/pms/info'
|
|
import { defaultProps, handleTree } from '@/utils/tree'
|
|
import { defaultProps, handleTree } from '@/utils/tree'
|
|
|
|
+import { CommonStatusEnum } from '@/utils/constants'
|
|
|
|
+import {IotInfoClassifyApi} from "@/api/pms/info";
|
|
|
|
+import { Document, Folder, Search } from '@element-plus/icons-vue'
|
|
|
|
+const { t } = useI18n() // 国际化
|
|
|
|
+const message = useMessage() // 消息弹窗
|
|
|
|
+const dialogVisible = ref(false) // 弹窗的是否展示
|
|
|
|
+const dialogTitle = ref('') // 弹窗的标题
|
|
|
|
+const formRef = ref() // 搜索的表单
|
|
|
|
+const openForm = (type: string, id?: number) => {
|
|
|
|
+ formRef.value.open(type, id)
|
|
|
|
+}
|
|
|
|
|
|
-defineOptions({ name: 'DeviceFileTree' })
|
|
|
|
|
|
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
|
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
|
|
|
+const formData = ref({
|
|
|
|
+ id: undefined,
|
|
|
|
+ parentId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ name: undefined,
|
|
|
|
+ sort: undefined,
|
|
|
|
+ status: CommonStatusEnum.ENABLE,
|
|
|
|
+ remark: undefined
|
|
|
|
+})
|
|
|
|
+const formRules = reactive<FormRules>({
|
|
|
|
+ name: [{ required: true, message: '资料分类名称不能为空', trigger: 'blur' }],
|
|
|
|
+ sort: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
|
|
|
|
+ status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
|
|
|
|
+})
|
|
|
|
+const submitForm = async () => {
|
|
|
|
+ // 校验表单
|
|
|
|
+ if (!formRef) return
|
|
|
|
+ const valid = await formRef.value.validate()
|
|
|
|
+ if (!valid) return
|
|
|
|
+ // 提交请求
|
|
|
|
+ formLoading.value = true
|
|
|
|
+ try {
|
|
|
|
+ const data = formData.value as unknown as InfoClassifyApi.IotInfoClassifyVO
|
|
|
|
+ debugger
|
|
|
|
+ if (formType.value === 'create') {
|
|
|
|
+ data.parentId = nodeInfo.value.id
|
|
|
|
+ data.deviceId = props.deviceId
|
|
|
|
+ await InfoClassifyApi.IotInfoClassifyApi.createIotInfoClassify(data)
|
|
|
|
+ message.success(t('common.createSuccess'))
|
|
|
|
+ } else {
|
|
|
|
+ await InfoClassifyApi.IotInfoClassifyApi.updateIotInfoClassify(data)
|
|
|
|
+ message.success(t('common.updateSuccess'))
|
|
|
|
+ }
|
|
|
|
+ dialogVisible.value = false
|
|
|
|
|
|
|
|
+ } finally {
|
|
|
|
+ await getTree()
|
|
|
|
+ formLoading.value = false
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/** 重置表单 */
|
|
|
|
+const resetForm = () => {
|
|
|
|
+ formData.value = {
|
|
|
|
+ id: undefined,
|
|
|
|
+ title: '',
|
|
|
|
+ parentId: undefined,
|
|
|
|
+ name: undefined,
|
|
|
|
+ sort: undefined,
|
|
|
|
+ leaderUserId: undefined,
|
|
|
|
+ phone: undefined,
|
|
|
|
+ email: undefined,
|
|
|
|
+ status: CommonStatusEnum.ENABLE
|
|
|
|
+ }
|
|
|
|
+ formRef.value?.resetFields()
|
|
|
|
+}
|
|
|
|
+defineOptions({ name: 'DeviceFileTree' })
|
|
|
|
+const props = defineProps({
|
|
|
|
+ deviceId: { type: Number, required: true }
|
|
|
|
+})
|
|
const deptName = ref('')
|
|
const deptName = ref('')
|
|
-const deptList = ref<Tree[]>([]) // 树形结构
|
|
|
|
|
|
+const nodeInfo = ref({})
|
|
|
|
+const fileList = ref<Tree[]>([]) // 树形结构
|
|
const treeRef = ref<InstanceType<typeof ElTree>>()
|
|
const treeRef = ref<InstanceType<typeof ElTree>>()
|
|
-const menuVisible = ref(false);
|
|
|
|
-const menuX = ref(0);
|
|
|
|
-const menuY = ref(0);
|
|
|
|
-let selectedNode = null;
|
|
|
|
-const handleRightClick = (event, { node, data }) => {
|
|
|
|
- event.preventDefault();
|
|
|
|
- menuX.value = event.clientX;
|
|
|
|
- menuY.value = event.clientY;
|
|
|
|
- selectedNode = data; // 存储当前操作的节点数据 :ml-citation{ref="7" data="citationList"}
|
|
|
|
- menuVisible.value = true;
|
|
|
|
-};
|
|
|
|
|
|
+const menuVisible = ref(false)
|
|
|
|
+const menuX = ref(0)
|
|
|
|
+const menuY = ref(0)
|
|
|
|
+const contextMenuRef = ref(null) // 弹窗DOM引用
|
|
|
|
+let selectedNode = null
|
|
|
|
+const handleRightClick = (event, node, data) => {
|
|
|
|
+ nodeInfo.value = node;
|
|
|
|
+ console.log(JSON.stringify(nodeInfo.value))
|
|
|
|
+ event.preventDefault()
|
|
|
|
+ menuX.value = event.clientX
|
|
|
|
+ menuY.value = event.clientY
|
|
|
|
+ selectedNode = data
|
|
|
|
+ menuVisible.value = true
|
|
|
|
+}
|
|
|
|
|
|
-const handleMenuClick = (action) => {
|
|
|
|
- switch(action) {
|
|
|
|
|
|
+const handleMenuClick = async (action) => {
|
|
|
|
+ switch (action) {
|
|
case 'add':
|
|
case 'add':
|
|
- // 调用新增节点逻辑 :ml-citation{ref="4" data="citationList"}
|
|
|
|
- break;
|
|
|
|
|
|
+ dialogVisible.value = true
|
|
|
|
+ dialogTitle.value = '新增资料分类'
|
|
|
|
+ formType.value = 'create'
|
|
|
|
+ resetForm()
|
|
|
|
+ break
|
|
case 'edit':
|
|
case 'edit':
|
|
- // 调用编辑节点逻辑 :ml-citation{ref="7" data="citationList"}
|
|
|
|
- break;
|
|
|
|
|
|
+ resetForm()
|
|
|
|
+ dialogVisible.value = true
|
|
|
|
+ dialogTitle.value = '编辑资料分类'
|
|
|
|
+ formType.value = 'update'
|
|
|
|
+ formData.value = nodeInfo.value
|
|
|
|
+ console.log(JSON.stringify(formData.value))
|
|
|
|
+ break
|
|
case 'delete':
|
|
case 'delete':
|
|
- // 调用删除节点逻辑 :ml-citation{ref="4" data="citationList"}
|
|
|
|
- break;
|
|
|
|
|
|
+ // 删除的二次确认
|
|
|
|
+ await message.delConfirm()
|
|
|
|
+ // 发起删除
|
|
|
|
+ await IotInfoClassifyApi.deleteIotInfoClassify(nodeInfo.value.id)
|
|
|
|
+ message.success(t('common.delSuccess'))
|
|
|
|
+ // 刷新列表
|
|
|
|
+ await getTree()
|
|
|
|
+ break
|
|
}
|
|
}
|
|
- menuVisible.value = false;
|
|
|
|
-};
|
|
|
|
|
|
+ menuVisible.value = false
|
|
|
|
+}
|
|
/** 获得部门树 */
|
|
/** 获得部门树 */
|
|
const getTree = async () => {
|
|
const getTree = async () => {
|
|
- const res = await DeptApi.getSimpleDeptList()
|
|
|
|
- deptList.value = []
|
|
|
|
- deptList.value.push(...handleTree(res))
|
|
|
|
|
|
+ const res = await FileClassifyApi.IotInfoClassifyApi.getSimpleInfotClassifyList(props.deviceId)
|
|
|
|
+ fileList.value = []
|
|
|
|
+ fileList.value.push(...handleTree(res))
|
|
|
|
+ console.log(JSON.stringify(fileList.value))
|
|
}
|
|
}
|
|
|
|
|
|
/** 基于名字过滤 */
|
|
/** 基于名字过滤 */
|
|
@@ -85,6 +210,7 @@ const filterNode = (name: string, data: Tree) => {
|
|
|
|
|
|
/** 处理部门被点击 */
|
|
/** 处理部门被点击 */
|
|
const handleNodeClick = async (row: { [key: string]: any }) => {
|
|
const handleNodeClick = async (row: { [key: string]: any }) => {
|
|
|
|
+ console.log(row)
|
|
emits('node-click', row)
|
|
emits('node-click', row)
|
|
}
|
|
}
|
|
const emits = defineEmits(['node-click'])
|
|
const emits = defineEmits(['node-click'])
|
|
@@ -93,7 +219,25 @@ const emits = defineEmits(['node-click'])
|
|
watch(deptName, (val) => {
|
|
watch(deptName, (val) => {
|
|
treeRef.value!.filter(val)
|
|
treeRef.value!.filter(val)
|
|
})
|
|
})
|
|
-
|
|
|
|
|
|
+const handleClickOutside = (event) => {
|
|
|
|
+ if (
|
|
|
|
+ menuVisible.value &&
|
|
|
|
+ contextMenuRef.value &&
|
|
|
|
+ !contextMenuRef.value.contains(event.target)
|
|
|
|
+ ) {
|
|
|
|
+ menuVisible.value = false
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+watch(menuVisible, (visible) => {
|
|
|
|
+ if (visible) {
|
|
|
|
+ document.addEventListener('click', handleClickOutside)
|
|
|
|
+ } else {
|
|
|
|
+ document.removeEventListener('click', handleClickOutside)
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
+ document.removeEventListener('click', handleClickOutside)
|
|
|
|
+})
|
|
/** 初始化 */
|
|
/** 初始化 */
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
await getTree()
|
|
await getTree()
|
|
@@ -104,7 +248,7 @@ onMounted(async () => {
|
|
position: fixed;
|
|
position: fixed;
|
|
background: white;
|
|
background: white;
|
|
border: 1px solid #ccc;
|
|
border: 1px solid #ccc;
|
|
- box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
|
|
|
|
|
|
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
|
|
z-index: 1000;
|
|
z-index: 1000;
|
|
}
|
|
}
|
|
.custom-menu ul {
|
|
.custom-menu ul {
|
|
@@ -115,8 +259,11 @@ onMounted(async () => {
|
|
.custom-menu li {
|
|
.custom-menu li {
|
|
padding: 8px 20px;
|
|
padding: 8px 20px;
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ margin: 5px
|
|
}
|
|
}
|
|
.custom-menu li:hover {
|
|
.custom-menu li:hover {
|
|
- background: #f5f5f5;
|
|
|
|
|
|
+ background: #77a0ec;
|
|
}
|
|
}
|
|
|
|
+
|
|
</style>
|
|
</style>
|