Переглянути джерело

Merge branch 'dev' of http://192.168.1.245:11111/shanming/onlineEducation-front into dev

zhangsq 8 місяців тому
батько
коміт
1262020233

+ 53 - 0
src/api/resourceType/resourceType.js

@@ -0,0 +1,53 @@
+/**
+ *  Copyright [2022] [https://www.xiaonuo.vip]
+ *	Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *	1.请不要删除和修改根目录下的LICENSE文件。
+ *	2.请不要删除和修改Snowy源码头部的版权声明。
+ *	3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ *	4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ *	5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ *	6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/api/webapp/disk/type/${url}`, ...arg)
+/**
+ * 机构
+ *
+ * @author yubaoshan
+ * @date 2022-09-22 22:33:20
+ */
+export default {
+	// 获取组织分页
+	orgPage(data) {
+		return request('page', data, 'get')
+	},
+	// 获取组织列表
+	orgList(data) {
+		return request('list', data, 'get')
+	},
+	// 获取组织树
+	orgTree(data) {
+		return request('tree', data, 'get')
+	},
+	// 提交表单 edit为true时为编辑,默认为新增
+	submitForm(data, edit = false) {
+		return request(edit ? 'edit' : 'add', data)
+	},
+	// 删除组织
+	orgDelete(data) {
+		return request('delete', data)
+	},
+	// 获取组织详情
+	orgDetail(data) {
+		return request('detail', data, 'get')
+	},
+	// 获取组织树选择器
+	orgOrgTreeSelector(data) {
+		return request('orgTreeSelector', data, 'get')
+	},
+	// 获取用户选择器
+	orgUserSelector(data) {
+		return request('userSelector', data, 'get')
+	}
+}

+ 2 - 0
src/router/portal.js

@@ -34,11 +34,13 @@ const portal = [
 			{
 				name: 'portal.resourceCenter',
 				path: '/portal/resourceCenter',
+				hide: true,
 				component: () => import('@/resourceCenter/index.vue')
 			},
 			{
 				name: 'portal.resourceDetails',
 				path: '/portal/resourceDetails',
+				hide: true,
 				component: () => import('@/resourceDetails/index.vue')
 			}
 		]

+ 3 - 3
src/views/portal/components/Footer.vue

@@ -1,13 +1,13 @@
 <template>
 	<footer class="footer">
 		<div class="footer-links">
-			<a href="#">网站首页</a>
+			<!-- <a href="#">网站首页</a>
 			<a href="#">帮助中心</a>
 			<a href="#">联系我们</a>
 			<a href="#">招聘信息</a>
-			<a href="#">客户服务</a>
+			<a href="#">客户服务</a> -->
 		</div>
-		<div class="footer-info">Copyright © www.AxureUX.com, All Rights Reserved.</div>
+		<div class="footer-info">占位</div>
 	</footer>
 </template>
 

+ 10 - 4
src/views/portal/components/Header.vue

@@ -4,9 +4,9 @@
 			<div style="display: flex; padding-left: 10%">
 				<div style="width: 120px; height: 55px; background-color: brown" />
 				<a-menu v-model:selectedKeys="current" mode="horizontal" theme="light" style="line-height: 55px">
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="1">首页</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="resourceCenter">资源中心</a-menu-item>
-					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="resourceDetails">资源管理</a-menu-item>
+					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal">首页</a-menu-item>
+					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceCenter">资源中心</a-menu-item>
+					<a-menu-item style="margin-left: 10px; margin-right: 10px" key="portal/resourceDetails">资源管理</a-menu-item>
 				</a-menu>
 			</div>
 
@@ -37,7 +37,9 @@
 
 <script setup>
 	import { ref } from 'vue'
-	const current = ref(['2']) // 默认选中“资源中心”
+	import { useRouter, useRoute } from 'vue-router'
+	const router = useRouter()
+	const current = ref(['1']) // 默认选中“资源中心”
 
 	const emit = defineEmits(['onChangeCurrent'])
 
@@ -47,6 +49,10 @@
 			console.log('新的是', newVal, '旧的是', oldVal)
 			if (newVal != oldVal) {
 				emit('onChangeCurrent', newVal)
+
+				// router.push({
+				// 	path: '/' + newVal
+				// })
 			}
 		}
 	)

+ 6 - 2
src/views/portal/index.vue

@@ -4,8 +4,8 @@
 		<a-layout>
 			<Header @onChangeCurrent="onChangeCurrent" />
 			<div style="width: 71%; margin-left: 10%">
-				<BreadCrumb />
-				<ResourceCenter />
+				<!-- <BreadCrumb />
+				<ResourceCenter /> -->
 				<!-- <ResourceDetails v-if="indexType == 'resourceDetails'" ref="ResourceDetailsRef" /> -->
 			</div>
 		</a-layout>
@@ -28,6 +28,10 @@
 	const ResourceDetailsRef = ref(null)
 	const onChangeCurrent = (current) => {
 		indexType.value = current
+
+		router.push({
+			path: '/' + current
+		})
 	}
 
 	const handlerItemSidebar = (item) => {

+ 57 - 12
src/views/resourceCenter/index.vue

@@ -1,25 +1,46 @@
 <template>
-	<div>
-		<ComplexChoices />
-		<div style="height: 20px"></div>
-		<a-row :gutter="16">
-			<a-col :span="18">
-				<ResourceList />
-			</a-col>
-			<a-col :span="6">
-				<SidebarRecommend @handlerItem="handlerItemSidebar" />
-				<Correlation @handlerItem="handlerItemCorrelation" />
-			</a-col>
-		</a-row>
+	<div style="overflow-y: auto">
+		<a-layout>
+			<Header @onChangeCurrent="onChangeCurrent" />
+			<div style="width: 71%; margin-left: 10%">
+				<ComplexChoices />
+				<div style="height: 20px"></div>
+				<a-row :gutter="16">
+					<a-col :span="18">
+						<ResourceList />
+					</a-col>
+					<a-col :span="6">
+						<SidebarRecommend @handlerItem="handlerItemSidebar" />
+						<Correlation @handlerItem="handlerItemCorrelation" />
+					</a-col>
+				</a-row>
+			</div>
+		</a-layout>
+		<Footer />
 	</div>
 </template>
 
 <script setup>
+	import Header from '@/views/portal/components/Header.vue'
+	import BreadCrumb from '@/views/portal/components/BreadCrumb.vue'
+	import Footer from '@/views/portal/components/Footer.vue'
 	import ComplexChoices from './components/ComplexChoices.vue'
 	import ResourceList from './components/ResourceList.vue'
 	import SidebarRecommend from './components/SidebarRecommend.vue'
 	import Correlation from './components/Correlation.vue'
+	import { useRouter, useRoute } from 'vue-router'
 
+	import EventBus from '@/utils/EventBus'
+
+	const router = useRouter()
+	const indexType = ref('resourceCenter')
+	const onChangeCurrent = (current) => {
+		indexType.value = current
+
+		router.push({
+			path: '/' + current
+		})
+	}
 	const handlerItemSidebar = (item) => {
 		// emit('handlerItemSidebar', item)
 	}
@@ -27,6 +48,30 @@
 	const handlerItemCorrelation = (item) => {
 		// emit('handlerItemSidebar', item)
 	}
+	const handleOpenResourceDetails = (item) => {
+		// emit('handlerItemSidebar', item)
+		// indexType.value = 'resourceDetails'
+		// nextTick(() => {
+		// 	console.log('看看呢', ResourceDetailsRef.value, item) /
+		// 		// if (ResourceDetailsRef.value) {
+		// 		// 	ResourceDetailsRef.value.setData(item)
+		// 		// }
+		// })
+		console.log('看看呢', item)
+		router.push({
+			path: '/portal/resourceDetails',
+			query: {
+				id: item.id
+			}
+		})
+	}
+	onMounted(() => {
+		// setTimeout(() => {
+		// 	images.value = 'http://192.168.1.245:10005/education/2025/7/2/1940361083973906434.jpg'
+		// }, 10000)
+	})
+	EventBus.off('openResourceDetails', handleOpenResourceDetails)
+	EventBus.on('openResourceDetails', handleOpenResourceDetails)
 </script>
 
 <style scoped>

+ 34 - 20
src/views/resourceDetails/components/TallItem.vue

@@ -6,40 +6,41 @@
 				<div style="width: 100%">
 					<div style="display: flex; flex-direction: column; margin-bottom: 0px">
 						<span style="display: block; font-size: 14px; font-weight: bold; margin-bottom: 0px">{{
-							props.item.name
+							props.item.userName
 						}}</span>
-						<span style="display: block; font-size: 12px">{{ props.item.talk }}</span>
+						<span style="display: block; font-size: 12px">{{ props.item.commentName }}</span>
 					</div>
 					<div style="width: 100%; display: flex; justify-content: space-between">
 						<div>
-							<span style="font-size: 10px">1天前</span>
+							<span style="font-size: 10px">{{ props.item.commentTime }}</span>
 						</div>
 						<div style="display: flex">
 							<div>
-								<MessageOutlined @click="handerMessage" />
-								<span style="margin-left: 5px">10</span>
+								<MessageOutlined style="cursor: pointer" @click="handerMessage" />
+								<span style="margin-left: 5px">{{ props.item.childSize }}</span>
 							</div>
 							<div style="margin-left: 15px">
-								<LikeOutlined @click="handerfollw" />
-								<span style="margin-left: 5px">10</span>
+								<!-- <LikeFilled /> -->
+								<LikeOutlined style="cursor: pointer" @click="handerfollw" />
+								<span style="margin-left: 5px">{{ props.item.giveNum }}</span>
 							</div>
 						</div>
 					</div>
 				</div>
 			</div>
-			<div v-show="props.item.callBackTalk.length > 0" v-for="(item, index) in props.item.callBackTalk" :key="index">
+			<div v-show="props.item.child.length > 0" v-for="(item, index) in props.item.child" :key="index">
 				<div style="display: flex; margin-left: 50px; margin-right: 0px">
 					<div style="width: 40px; height: 40px; background: #1e90ff; border-radius: 50%; margin-right: 10px"></div>
 					<div style="width: 100%">
 						<div style="display: flex; flex-direction: column; margin-bottom: 0px">
 							<span style="display: block; font-size: 14px; font-weight: bold; margin-bottom: 5px">{{
-								item.name
+								item.userName
 							}}</span>
-							<span style="display: block; font-size: 12px">{{ item.talk }}</span>
+							<span style="display: block; font-size: 12px">{{ item.commentName }}</span>
 						</div>
 						<div style="width: 100%; display: flex; justify-content: space-between">
 							<div>
-								<span style="font-size: 10px">1天前</span>
+								<span style="font-size: 10px">{{ item.commentTime }}</span>
 							</div>
 							<div style="display: flex">
 								<!-- <div>
@@ -47,8 +48,9 @@
 								<span style="margin-left: 5px">10</span>
 							</div> -->
 								<div style="margin-left: 15px">
-									<LikeOutlined @click="handerfollw" />
-									<span style="margin-left: 5px">10</span>
+									<!-- <LikeFilled /> -->
+									<LikeOutlined style="cursor: pointer" @click="handerfollwChild(item)" />
+									<span style="margin-left: 5px">{{ item.giveNum }}</span>
 								</div>
 							</div>
 						</div>
@@ -58,9 +60,9 @@
 
 			<div v-if="tallTag">
 				<div>
-					<a-textarea placeholder="" :rows="4" style="margin-top: 5px" />
+					<a-textarea placeholder="" v-model:value="talk" :rows="4" style="margin-top: 5px" />
 					<div style="display: flex; justify-content: flex-end; margin-top: 10px">
-						<a-button style="width: 100px" @click="handerPublish">发布</a-button>
+						<a-button style="width: 100px" @click="handerPublish">回复</a-button>
 					</div>
 				</div>
 			</div>
@@ -72,6 +74,7 @@
 	import { ref } from 'vue'
 	import TabSwitcher from './TabSwitcher.vue'
 	import EventBus from '@/utils/EventBus'
+	import { addViewCount, detail, add, cancel, queryList, pageComment, addComment, giveComment } from '@/api/portal'
 	const emit = defineEmits(['selectTab'])
 
 	// id: 1,
@@ -83,11 +86,11 @@
 		item: {
 			type: Object,
 			default: () => {}
+		},
+		id: {
+			type: String,
+			default: () => ''
 		}
-		// name: {
-		// 	type: String,
-		// 	default: () => ''
-		// },
 		// talk: {
 		// 	type: String,
 		// 	default: () => ''
@@ -103,6 +106,7 @@
 	})
 	const listUnpublishedView = ref(null)
 	const tallTag = ref(false)
+	const talk = ref('')
 	const handerMessage = (form) => {
 		console.log('查询内容', form)
 		tallTag.value == true ? (tallTag.value = false) : (tallTag.value = true)
@@ -117,15 +121,25 @@
 			console.log('item有变化吗', val)
 		}
 	)
+
+	const handerfollw = async () => {
+		await giveComment({ id: props.item.id })
+		EventBus.emit('onGetPageComment')
+	}
+	const handerfollwChild = async (item) => {
+		await giveComment({ id: item.id })
+		EventBus.emit('onGetPageComment')
+	}
 	const handerPublish = () => {
 		tallTag.value = false
-		emit('publish')
+		emit('publish', { resourceId: props.id, id: props.item.id, talk: talk.value })
 
 		//....
 		// listUnpublishedView.value.setData(tableData.value)
 	}
 	const handleCloseInput = (data, tag) => {
 		if (props.item.id != tag) {
+			talk.value = ''
 			tallTag.value = false
 		}
 	}

+ 37 - 17
src/views/resourceDetails/components/TallList.vue

@@ -81,7 +81,7 @@
 			<div class="line"></div>
 
 			<div>
-				<TallItem v-for="(item, index) in list" :key="index" :item="item" @publish="publish"></TallItem>
+				<TallItem v-for="(item, index) in list" :key="index" :item="item" :id="id" @publish="publish"></TallItem>
 			</div>
 		</div>
 
@@ -104,11 +104,18 @@
 	import EqualItem from './EqualItem.vue'
 	import { addViewCount, detail, add, cancel, queryList, pageComment, addComment } from '@/api/portal'
 	import { useRoute } from 'vue-router'
+	import EventBus from '@/utils/EventBus'
 	const emit = defineEmits(['selectTab'])
 	const listUnpublishedView = ref(null)
 	const route = useRoute()
 	const id = route.query.id
 	const talk = ref('')
+
+	const pagers = ref({
+		pages: 1,
+		size: 20
+	})
+
 	const equalList = ref([
 		{
 			id: 1,
@@ -156,22 +163,32 @@
 		}
 	])
 
-	const publish = () => {
-		list.value[0].callBackTalk.push({
-			id: 1,
-			name: '张三',
-			talk: '今天,我被你给打赏了1000元,请给我一个好评,谢谢123123123',
-			follw: 0
-		})
-
-		list.value = [...list.value]
-
-		console.log('最后的', list.value)
+	const publish = (data) => {
+		// { pid: props.item.id, talk }
+		addComment({ pid: data.id, resourceId: data.resourceId, commentName: data.talk })
+			.then((res) => {
+				getPageComment()
+				talk.value = ''
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+		// list.value[0].callBackTalk.push({
+		// 	id: 1,
+		// 	name: '张三',
+		// 	talk: '今天,我被你给打赏了1000元,请给我一个好评,谢谢123123123',
+		// 	follw: 0
+		// })
+		// list.value = [...list.value]
+		// console.log('最后的', list.value)
 	}
 
 	const handerPublish = () => {
 		addComment({ resourceId: id, commentName: talk.value })
-			.then((res) => {})
+			.then((res) => {
+				getPageComment()
+				talk.value = ''
+			})
 			.catch((err) => {
 				console.log(err)
 			})
@@ -190,13 +207,13 @@
 		// listUnpublishedView.value.setData(tableData.value)
 	}
 	const getPageComment = () => {
-		pageComment({ resourceId: id })
+		pageComment({ resourceId: id, ...pagers.value })
 			.then((res) => {
 				if (res.code == 200) {
-					res.value = res.data.records
+					list.value = res.data.records
 
-					res.data.pages
-					res.data.size
+					pagers.value.pages = res.data.pages
+					pagers.value.size = res.data.size
 				}
 			})
 			.catch((err) => {
@@ -208,6 +225,9 @@
 		getList()
 		getPageComment()
 	})
+
+	EventBus.off('onGetPageComment', getPageComment)
+	EventBus.on('onGetPageComment', getPageComment)
 </script>
 
 <style scoped>

+ 14 - 1
src/views/resourceDetails/index.vue

@@ -18,9 +18,15 @@
 	import BreadCrumb from '@/views/portal/components/BreadCrumb.vue'
 	import Footer from '@/views/portal/components/Footer.vue'
 	import VideoDetails from './components/VideoDetails.vue'
-	import { useRoute } from 'vue-router'
+	import { useRoute, useRouter } from 'vue-router'
 	import TallList from './components/TallList.vue'
 	import { addViewCount, detail, add, queryList } from '@/api/portal'
+
+	import EventBus from '@/utils/EventBus'
+
+	const router = useRouter()
+
+	const indexType = ref('resourceCenter')
 	const itemData = ref({})
 	const VideoDetailsRef = ref(null)
 	const route = useRoute()
@@ -57,6 +63,13 @@
 	const handlerItemSidebar = (item) => {
 		// emit('handlerItemSidebar', item)
 	}
+	const onChangeCurrent = (current) => {
+		indexType.value = current
+
+		router.push({
+			path: '/' + current
+		})
+	}
 
 	const setData = (item) => {
 		// emit('handlerItemSidebar', item)

+ 183 - 0
src/views/resourceType/form.vue

@@ -0,0 +1,183 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑资源类型' : '增加资源类型'"
+		:width="550"
+		:visible="visible"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="上级资源类型:" name="parentId">
+				<a-tree-select
+					v-model:value="formData.parentId"
+					style="width: 100%"
+					:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
+					placeholder="请选择上级资源类型"
+					allow-clear
+					tree-default-expand-all
+					:tree-data="treeData"
+					:field-names="{
+						children: 'children',
+						label: 'name',
+						value: 'id'
+					}"
+					selectable="false"
+					tree-line
+				/>
+			</a-form-item>
+			<a-form-item label="类型名称:" name="name">
+				<a-input v-model:value="formData.name" placeholder="请输入组织名称" allow-clear />
+			</a-form-item>
+			<!-- <a-form-item label="组织分类:" name="category">
+				<a-select
+					v-model:value="formData.category"
+					:options="orgCategoryOptions"
+					style="width: 100%"
+					placeholder="请选择组织分类"
+				/>
+			</a-form-item> -->
+			<a-form-item label="排序:" name="sortCode">
+				<a-input-number style="width: 100%" v-model:value="formData.sortCode" :max="100" />
+			</a-form-item>
+			<!-- <a-form-item label="指定主管:" name="directorId">
+				<a-button type="link" style="padding-left: 0px" @click="openSelector(formData.directorId)">选择</a-button>
+				<a-tag v-if="formData.directorId && formData.directorName" color="orange" closable @close="closeUserTag">{{
+					formData.directorName
+				}}</a-tag>
+				<a-input v-show="false" v-model:value="formData.directorId" />
+			</a-form-item> -->
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" :loading="submitLoading" @click="onSubmit">保存</a-button>
+		</template>
+		<user-selector-plus
+			ref="userSelectorPlusRef"
+			:org-tree-api="selectorApiFunction.orgTreeApi"
+			:user-page-api="selectorApiFunction.userPageApi"
+			:checked-user-list-api="selectorApiFunction.checkedUserListApi"
+			:radio-model="true"
+			@onBack="userBack"
+		/>
+	</xn-form-container>
+</template>
+
+<script setup name="orgForm">
+	import { required } from '@/utils/formRules'
+	import orgApi from '@/api/resourceType/resourceType'
+	import userCenterApi from '@/api/sys/userCenterApi'
+	import UserSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
+	import tool from '@/utils/tool'
+
+	// 定义emit事件
+	const emit = defineEmits({ successful: null })
+	// 默认是关闭状态
+	let visible = $ref(false)
+	let userSelectorPlusRef = ref()
+	const formRef = ref()
+	// 表单数据,也就是默认给一些数据
+	const formData = ref({})
+	// 定义机构元素
+	const treeData = ref([])
+	const submitLoading = ref(false)
+
+	// 打开抽屉
+	const onOpen = (record, parentId) => {
+		visible = true
+		formData.value = {
+			sortCode: 99
+		}
+		if (parentId) {
+			formData.value.parentId = parentId
+		}
+		if (record) {
+			const param = {
+				id: record.id
+			}
+			orgApi.orgDetail(param).then((data) => {
+				formData.value = Object.assign({}, data)
+			})
+		}
+		// 获取机构树并加入顶级
+		orgApi.orgOrgTreeSelector().then((res) => {
+			treeData.value = [
+				{
+					id: 0,
+					parentId: '-1',
+					name: '顶级',
+					children: res
+				}
+			]
+		})
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		visible = false
+	}
+	// 默认要校验的
+	const formRules = {
+		name: [required('请输入资源名称')],
+		// category: [required('请选择组织分类')],
+		sortCode: [required('请选择排序')]
+	}
+	// 机构分类字典
+	const orgCategoryOptions = tool.dictList('ORG_CATEGORY')
+	// 打开人员选择器,选择主管
+	const openSelector = (id) => {
+		let checkedUserIds = []
+		checkedUserIds.push(id)
+		userSelectorPlusRef.value.showUserPlusModal(checkedUserIds)
+	}
+	// 人员选择器回调
+	const userBack = (value) => {
+		if (value.length > 0) {
+			formData.value.directorId = value[0].id
+			formData.value.directorName = value[0].name
+		} else {
+			formData.value.directorId = ''
+			formData.value.directorName = ''
+		}
+	}
+	// 通过小标签删除主管
+	const closeUserTag = () => {
+		formData.value.directorId = ''
+		formData.value.directorName = ''
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value.validate().then(() => {
+			submitLoading.value = true
+			orgApi
+				.submitForm(formData.value, formData.value.id)
+				.then(() => {
+					visible = false
+					emit('successful')
+				})
+				.finally(() => {
+					submitLoading.value = false
+				})
+		})
+	}
+	// 传递设计器需要的API
+	const selectorApiFunction = {
+		orgTreeApi: (param) => {
+			return orgApi.orgOrgTreeSelector(param).then((data) => {
+				return Promise.resolve(data)
+			})
+		},
+		userPageApi: (param) => {
+			return orgApi.orgUserSelector(param).then((data) => {
+				return Promise.resolve(data)
+			})
+		},
+		checkedUserListApi: (param) => {
+			return userCenterApi.userCenterGetUserListByIdList(param).then((data) => {
+				return Promise.resolve(data)
+			})
+		}
+	}
+	// 调用这个函数将子组件的一些数据和方法暴露出去
+	defineExpose({
+		onOpen
+	})
+</script>

+ 204 - 0
src/views/resourceType/index.vue

@@ -0,0 +1,204 @@
+<template>
+	<a-row :gutter="10">
+		<a-col :xs="24" :sm="24" :md="24" :lg="5" :xl="5">
+			<a-card :bordered="false" :loading="cardLoading">
+				<a-tree
+					v-if="treeData.length > 0"
+					v-model:expandedKeys="defaultExpandedKeys"
+					:tree-data="treeData"
+					:field-names="treeFieldNames"
+					@select="treeSelect"
+				/>
+				<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
+			</a-card>
+		</a-col>
+		<a-col :xs="24" :sm="24" :md="24" :lg="19" :xl="19">
+			<a-card :bordered="false" style="margin-bottom: 10px">
+				<a-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
+					<a-row :gutter="24">
+						<a-col :span="8">
+							<a-form-item name="searchKey" label="资源类型">
+								<a-input v-model:value="searchFormState.searchKey" placeholder="请输入资源类型" />
+							</a-form-item>
+						</a-col>
+						<a-col :span="8">
+							<a-button type="primary" @click="table.refresh(true)">
+								<template #icon><SearchOutlined /></template>
+								查询
+							</a-button>
+							<a-button class="snowy-buttom-left" @click="reset">
+								<template #icon><redo-outlined /></template>
+								重置
+							</a-button>
+						</a-col>
+					</a-row>
+				</a-form>
+			</a-card>
+			<a-card :bordered="false">
+				<s-table
+					ref="table"
+					:columns="columns"
+					:data="loadData"
+					:expand-row-by-click="true"
+					:alert="options.alert.show"
+					bordered
+					:row-key="(record) => record.id"
+					:row-selection="options.rowSelection"
+				>
+					<template #operator class="table-operator">
+						<a-space>
+							<a-button type="primary" @click="formRef.onOpen(undefined, searchFormState.parentId)">
+								<template #icon><plus-outlined /></template>
+								新增
+							</a-button>
+							<xn-batch-delete :selectedRowKeys="selectedRowKeys" @batchDelete="deleteBatchOrg" />
+						</a-space>
+					</template>
+					<template #bodyCell="{ column, record }">
+						<template v-if="column.dataIndex === 'category'">
+							{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
+						</template>
+						<template v-if="column.dataIndex === 'action'">
+							<a @click="formRef.onOpen(record)">编辑</a>
+							<a-divider type="vertical" />
+							<a-popconfirm title="删除此资源类型吗?" @confirm="removeOrg(record)">
+								<a-button type="link" danger size="small">删除</a-button>
+							</a-popconfirm>
+						</template>
+					</template>
+				</s-table>
+			</a-card>
+		</a-col>
+	</a-row>
+	<Form ref="formRef" @successful="table.refresh()" />
+</template>
+
+<script setup name="sysOrg">
+	import { Empty } from 'ant-design-vue'
+	import { isEmpty } from 'lodash-es'
+	import orgApi from '@/api/resourceType/resourceType'
+	import Form from './form.vue'
+
+	const columns = [
+		{
+			title: '资源类型',
+			dataIndex: 'name'
+		},
+		// {
+		// 	title: '分类',
+		// 	dataIndex: 'category'
+		// },
+		{
+			title: '排序',
+			dataIndex: 'sortCode',
+			width: 100
+		},
+		{
+			title: '操作',
+			dataIndex: 'action',
+			align: 'center',
+			width: '150px'
+		}
+	]
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		alert: {
+			show: false,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	// 定义tableDOM
+	const table = ref(null)
+	const formRef = ref()
+	const searchFormRef = ref()
+	const searchFormState = ref({})
+	// 默认展开的节点
+	const defaultExpandedKeys = ref([])
+	const treeData = ref([])
+	// 替换treeNode 中 title,key,children
+	const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
+	const cardLoading = ref(true)
+
+	// 表格查询 返回 Promise 对象
+	const loadData = (parameter) => {
+		loadTreeData()
+		return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
+			return res
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+	// 加载左侧的树
+	const loadTreeData = () => {
+		orgApi.orgTree().then((res) => {
+			cardLoading.value = false
+			if (res !== null) {
+				treeData.value = res
+				if (isEmpty(defaultExpandedKeys.value)) {
+					// 默认展开2级
+					treeData.value.forEach((item) => {
+						// 因为0的顶级
+						if (item.parentId === '0') {
+							defaultExpandedKeys.value.push(item.id)
+							// 取到下级ID
+							if (item.children) {
+								item.children.forEach((items) => {
+									defaultExpandedKeys.value.push(items.id)
+								})
+							}
+						}
+					})
+				}
+			}
+		})
+	}
+	// 点击树查询
+	const treeSelect = (selectedKeys) => {
+		if (selectedKeys.length > 0) {
+			searchFormState.value.parentId = selectedKeys.toString()
+		} else {
+			delete searchFormState.value.parentId
+		}
+		table.value.refresh(true)
+	}
+	// 删除
+	const removeOrg = (record) => {
+		let params = [
+			{
+				id: record.id
+			}
+		]
+		orgApi.orgDelete(params).then(() => {
+			table.value.refresh(true)
+		})
+	}
+	// 批量删除
+	const deleteBatchOrg = (params) => {
+		orgApi.orgDelete(params).then(() => {
+			table.value.clearRefreshSelected()
+		})
+	}
+</script>
+
+<style scoped>
+	.ant-form-item {
+		margin-bottom: 0 !important;
+	}
+	.primaryAdd {
+		margin-right: 10px;
+	}
+	.snowy-buttom-left {
+		margin-left: 8px;
+	}
+</style>