Quellcode durchsuchen

资源管理接口联调

zhangsq vor 8 Monaten
Ursprung
Commit
9314f60b9e

+ 53 - 0
src/api/organization/organization.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/college/${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')
+	}
+}

+ 101 - 0
src/api/organization/userCenterApi.js

@@ -0,0 +1,101 @@
+/**
+ *  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/sys/userCenter/${url}`, ...arg)
+/**
+ * 用户个人控制器
+ *
+ * @author yubaoshan
+ * @date 2022-09-22 22:33:20
+ */
+export default {
+	// 获取图片验证码
+	userGetPicCaptcha(data) {
+		return request('getPicCaptcha', data, 'get')
+	},
+	// 找回密码获取手机验证码
+	userFindPasswordGetPhoneValidCode(data) {
+		return request('findPasswordGetPhoneValidCode', data, 'get')
+	},
+	// 找回密码获取邮箱验证码
+	userFindPasswordGetEmailValidCode(data) {
+		return request('findPasswordGetEmailValidCode', data, 'get')
+	},
+	// 通过手机号找回用户密码
+	userFindPasswordByPhone(data) {
+		return request('findPasswordByPhone', data)
+	},
+	// 通过邮箱找回用户密码
+	userFindPasswordByEmail(data) {
+		return request('findPasswordByEmail', data)
+	},
+	// 修改用户密码
+	userUpdatePassword(data) {
+		return request('updatePassword', data)
+	},
+	// 修改用户头像
+	userUpdateAvatar(data) {
+		return request('updateAvatar', data)
+	},
+	// 修改用户签名图片
+	userUpdateSignature(data) {
+		return request('updateSignature', data)
+	},
+	// 获取登录用户的菜单
+	userLoginMenu(data) {
+		return request('loginMenu', data, 'get')
+	},
+	// 获取登录用户组织树
+	userLoginOrgTree(data) {
+		return request('loginOrgTree', data, 'get')
+	},
+	// 获取登录用户的职位信息
+	userLoginPositionInfo(data) {
+		return request('loginPositionInfo', data, 'get')
+	},
+	// 编辑个人信息
+	userUpdateUserInfo(data) {
+		return request('updateUserInfo', data)
+	},
+	// 编辑个人工作台
+	userUpdateUserWorkbench(data) {
+		return request('updateUserWorkbench', data)
+	},
+	// 获取登录用户的工作台
+	userLoginWorkbench(data) {
+		return request('loginWorkbench', data, 'get')
+	},
+	// 获取登录用户的站内信分页
+	userLoginUnreadMessagePage(data) {
+		return request('loginUnreadMessagePage', data, 'get')
+	},
+	// 读取登录用户站内信详情
+	userLoginUnreadMessageDetail(data) {
+		return request('loginUnreadMessageDetail', data, 'get')
+	},
+	// 根据id集合获取组织集合
+	userCenterGetOrgListByIdList(data) {
+		return request('getOrgListByIdList', data)
+	},
+	// 根据id集合获取用户集合
+	userCenterGetUserListByIdList(data) {
+		return request('getUserListByIdList', data)
+	},
+	// 根据id集合获取职位集合
+	userCenterGetPositionListByIdList(data) {
+		return request('getPositionListByIdList', data)
+	},
+	// 根据id集合获取角色集合
+	userCenterGetRoleListByIdList(data) {
+		return request('getRoleListByIdList', data)
+	}
+}

+ 28 - 0
src/api/resourceAudit.js

@@ -18,5 +18,33 @@ export default {
 	//更新状态(审核/删除/恢复)
 	updateStatus(data = {}) {
 		return request('courseauditrecord/updateStatus', data, 'post')
+	},
+	//编辑
+	edit(data = {}) {
+		return request('courseauditrecord/edit', data, 'post')
+	},
+	//编辑
+	detail(data = {}) {
+		return request('courseauditrecord/detail', data, 'get')
+	},
+	//院校下拉接口
+	orgTreeSelector(data = {}) {
+		return request('college/orgTreeSelector', data, 'get')
+	},
+	//根据院校id获取专业下拉接口
+	zyselect(data = {}) {
+		return request('major/select', data, 'get')
+	},
+	//获取热门关键词下拉接口
+	HotKeywords(data = {}) {
+		return request('word/select', data, 'get')
+	},
+	//添加热门关键词
+	addHotKeywords(data = {}) {
+		return request('word/add', data, 'post')
+	},
+	//获取课程下拉
+	courseAllList(data = {}) {
+		return request('courseinfo/allList', data, 'get')
 	}
 }

+ 1 - 1
src/api/resourceOverview.js

@@ -8,7 +8,7 @@ export default {
 		return request('operationLog/getList', data, 'get')
 	},
 	// 获取资源概览存储空间接口
-	queryList(data={}) {
+	queryList(data = {}) {
 		return request('fileStastic/queryList', data, 'get')
 	}
 }

+ 11 - 0
src/style/index.less

@@ -371,10 +371,21 @@ a, button, input, textarea {
 		display: none;
 	}
 }
+.dis-flex{
+	display: flex;
+}
 .dis-flex-end {
 	display: flex;
 	justify-content: flex-end;
 }
+.dis-flex-sb{
+	display: flex;
+	justify-content:space-between;
+}
+.dis-flex-start{
+	display: flex;
+	justify-content: flex-start;
+}
 .margin-top {
 	margin-top: 15px;
 }

+ 79 - 0
src/views/myResources/auditModal.vue

@@ -0,0 +1,79 @@
+<!-- auditModal.vue -->
+<template>
+	<a-modal v-model:visible="visibles" title="资源审核" @ok="handleOk" @cancel="handleCancel">
+		<div class="audit-content">
+			<video-player v-if="record.suffix === 'mp4'" :options="playerOptions" @ready="playerReadied"></video-player>
+			<!-- 其他格式文件的展示方式 -->
+			<div v-else-if="record.suffix === 'ppt'">PPT展示区域</div>
+			<div v-else-if="record.suffix === 'word'">Word展示区域</div>
+			<div v-else-if="record.suffix === 'pdf'">PDF展示区域</div>
+			<div v-else>其他格式文件展示区域</div>
+
+			<div class="audit-info">
+				<p><strong>授课老师:</strong>{{ record.teacherName }}</p>
+				<p><strong>所属院系:</strong>{{ record.collegeName }}</p>
+				<p><strong>所属专业:</strong>{{ record.majorName }}</p>
+				<p><strong>课程类型:</strong>{{ record.courseType }}</p>
+				<p><strong>课件格式:</strong>{{ record.suffix }}</p>
+				<p><strong>视频时长:</strong>{{ record.duration }}</p>
+				<p><strong>视频大小:</strong>{{ record.fileSize }}</p>
+				<p><strong>发布时间:</strong>{{ record.publishTime }}</p>
+				<p><strong>课程介绍:</strong>{{ record.courseDescription }}</p>
+			</div>
+
+			<a-radio-group v-model:value="auditResult">
+				<a-radio :value="1">通过</a-radio>
+				<a-radio :value="0">不通过</a-radio>
+			</a-radio-group>
+		</div>
+	</a-modal>
+</template>
+
+<script setup>
+	import { ref, defineProps, defineEmits, computed } from 'vue'
+	// import videoPlayer from 'vue-video-player'
+
+	const props = defineProps({
+		record: Object
+	})
+
+	const emit = defineEmits(['confirm'])
+
+	const auditResult = ref(1) // 默认为通过
+	const visibles = ref(true)
+
+	const playerOptions = computed(() => ({
+		sources: [
+			{
+				type: 'video/mp4',
+				src: props.record.filePath // 视频文件路径
+			}
+		],
+		poster: props.record.posterPath // 封面图片路径
+	}))
+
+	const handleOk = () => {
+		emit('confirm', { ...props.record, auditResult: auditResult.value })
+	}
+
+	const handleCancel = () => {
+		emit('update:visible', false)
+	}
+
+	const playerReadied = (player) => {
+		// player ready
+	}
+</script>
+
+<style scoped>
+	.audit-content {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+	}
+
+	.audit-info {
+		margin-top: 20px;
+		text-align: left;
+	}
+</style>

+ 117 - 0
src/views/myResources/coverUpload/index.vue

@@ -0,0 +1,117 @@
+<template>
+	<div>
+		<div style="margin-bottom: 10px">
+			<!-- <a-button type="primary" @click="chooseFile" :disabled="coverFileList.length > 0 && isedit">选择图片</a-button> -->
+			<a-button
+				type="primary"
+				@click="chooseFile"
+				:disabled="isedit ? coverFileList.length > 0 && isedit : coverFileList.length > 0"
+				>选择图片</a-button
+			>
+			<span style="margin-left: 10px">仅支持上传jpg/png格式文件,单个文件不能超过500kb</span>
+		</div>
+		<a-upload
+			ref="upload"
+			:before-upload="beforeUploadCover"
+			:file-list="coverFileList"
+			:remove="handleRemoveCover"
+			:headers="headers"
+			:action="action"
+			:on-change="handleChangeCover"
+			list-type="picture-card"
+		>
+			<div v-if="coverFileList.length < 1">
+				<plus-outlined />
+				<div class="ant-upload-text">上传图片</div>
+			</div>
+		</a-upload>
+		<!-- 文件上传状态展示 -->
+		<ul v-if="fileList.length">
+			<li v-for="(file, index) in fileList" :key="index" class="file-item">
+				<span>{{ file.name }}</span>
+				<a-progress :percent="file.percent || 0" />
+				<span v-if="file.status === 'done'">已完成</span>
+				<span v-else-if="file.status === 'error'">上传失败</span>
+				<span v-else-if="file.status === 'uploading'">上传中...</span>
+			</li>
+		</ul>
+	</div>
+</template>
+
+<script setup>
+	import { ref, reactive, toRefs } from 'vue'
+	import tool from '@/utils/tool'
+	const emit = defineEmits(['handleRemoveCover', 'handleChangeCover'])
+	const headers = ref({
+		token: tool.data.get('TOKEN')
+	})
+	const props = defineProps({
+		coverImageId: {
+			type: Number,
+			required: true,
+			default: null
+		},
+		isedit: {
+			type: Boolean,
+			required: true,
+			default: false
+		}
+	})
+	const action = ref('http://192.168.31.80:9003/api/webapp/dev/file/uploadMinioReturnId')
+	// 封面文件列表
+	const coverFileList = ref([])
+	const fileList = ref([])
+	const coverImageId = ref('123')
+	// 上传封面前的钩子函数
+	const beforeUploadCover = (file) => {
+		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+		if (!isJpgOrPng) {
+			Modal.error({ content: '仅支持上传jpg/png格式文件!' })
+		}
+		const isLt500K = file.size / 1024 < 500
+		if (!isLt500K) {
+			Modal.error({ content: '单个文件不能超过500kb!' })
+		}
+		return isJpgOrPng && isLt500K
+	}
+
+	// 移除封面文件
+	const handleRemoveCover = (file) => {
+		const index = coverFileList.value.indexOf(file)
+		const newFileList = coverFileList.value.slice()
+		newFileList.splice(index, 1)
+		coverFileList.value = newFileList
+		// 如果移除的是当前封面文件,则清空coverImageId
+		if (coverImageId.value === file.id) {
+			coverImageId.value = null
+			emit('handleRemoveCover')
+		}
+	}
+
+	// 封面文件状态改变时的处理函数
+	const handleChangeCover = ({ file, fileList: newFileList }) => {
+		if (file.status === 'done') {
+			// 上传成功,获取文件ID
+			const fileId = file.response?.data || file.id
+			console.log('上传成功,获取文件ID', fileId)
+			if (fileId) {
+				coverImageId.value = fileId
+				emit('handleChangeCover', fileId)
+			}
+		}
+		if (file.status === 'error') {
+			// 延迟移除,确保用户能看到错误提示
+			setTimeout(() => {
+				coverFileList.value = coverFileList.value.filter((f) => f.uid !== file.uid)
+			}, 1500)
+		}
+		coverFileList.value = newFileList
+	}
+
+	// 选择文件按钮点击事件
+	const chooseFile = () => {
+		document.querySelector('.ant-upload input').click()
+	}
+</script>
+
+<style lang="scss"></style>

+ 588 - 0
src/views/myResources/myResources.vue

@@ -0,0 +1,588 @@
+<template>
+	<a-card>
+		<!-- 标签页 -->
+		<a-tabs v-model:activeKey="formState.verifyStatus" @change="tabChange">
+			<a-tab-pane key="0" tab="未发布" v-if="pageType !== 'economize'"></a-tab-pane>
+			<a-tab-pane key="1" tab="待审核"></a-tab-pane>
+			<a-tab-pane key="2" tab="已发布" v-if="pageType !== 'economize'"></a-tab-pane>
+			<a-tab-pane key="3" tab="已审核" v-if="pageType == 'economize'"></a-tab-pane>
+			<a-tab-pane key="4" tab="回收站"></a-tab-pane>
+		</a-tabs>
+
+		<!-- 搜索和操作区域 -->
+		<a-row :gutter="16" style="margin-bottom: 16px">
+			<a-col :span="16">
+				<a-input v-model:value="formState.fileName" placeholder="请输入资源名称" style="width: 200px" />
+				<a-cascader
+					style="width: 200px; margin-left: 8px"
+					v-model:value="formState.majorIdName"
+					:options="collegeMajorOptions"
+					:fieldNames="{ label: 'name', value: 'parentId', children: 'children' }"
+					placeholder="请选择院系"
+					changeOnSelect
+					@change="changeCollegeMajor"
+				/>
+				<a-select
+					v-model:value="formState.courseTypeName"
+					style="width: 200px; margin-left: 8px"
+					:options="courseTypeOptions"
+					placeholder="请选择课程类型"
+				/>
+				<a-select v-model:value="formState.suffix" placeholder="课件格式" style="width: 200px; margin-left: 8px">
+					<a-select-option value="mp4">mp4</a-select-option>
+					<a-select-option value="ppt">ppt</a-select-option>
+					<a-select-option value="word">word</a-select-option>
+					<a-select-option value="pdf">pdf</a-select-option>
+				</a-select>
+				<a-button type="primary" style="margin-left: 8px" @click="handleSearch">查询</a-button>
+				<a-button style="margin-left: 8px" @click="handleReset">重置</a-button>
+			</a-col>
+			<a-col :span="8" style="text-align: right">
+				<a-button
+					type="primary"
+					style="margin-right: 8px"
+					v-if="formState.verifyStatus === '0'"
+					@click="batchPublish"
+					:disabled="selectedRowKeys.length === 0"
+				>
+					+ 批量发布
+				</a-button>
+				<a-button type="primary" @click="showUploadModal">+ 上传资源</a-button>
+			</a-col>
+		</a-row>
+
+		<!-- 表格 -->
+		<a-table
+			:columns="currentColumns"
+			:data-source="dataSource"
+			:pagination="false"
+			:loading="loading"
+			bordered
+			:row-key="(record) => record.id"
+			:row-selection="rowSelection"
+		>
+			<template #bodyCell="{ column, text, record }">
+				<template
+					v-if="
+						['fileName', 'collegeIdName', 'majorIdName', 'courseTypeName', 'suffix', 'uploadTime'].includes(
+							column.dataIndex
+						)
+					"
+				>
+					<div class="multiLine-ellipsis" :title="text">{{ text || '-' }}</div>
+				</template>
+				<!-- 状态列 -->
+				<template v-if="column.key === 'verifyStatus'">
+					<span v-if="record.verifyStatus === '0'">
+						<a-badge status="processing" text="处理中" />
+					</span>
+					<span v-else-if="record.verifyStatus === 'uploaded'">
+						<a-badge status="success" text="已上传" />
+					</span>
+					<span v-else-if="record.verifyStatus === '1'">
+						<a-badge status="default" text="待审核" />
+					</span>
+					<span v-else-if="record.verifyStatus === '2'">
+						<a-badge status="success" text="已发布" />
+					</span>
+					<span v-else-if="record.verifyStatus === '4'">
+						<a-badge status="error" text="已删除" />
+					</span>
+				</template>
+				<!-- 操作列 -->
+				<template v-else-if="column.key === 'action'">
+					<div class="editable-cell">
+						<a v-if="formState.verifyStatus === '0' && pageType !== 'economize'" @click="handlePublish(record)">发布</a>
+						<a v-if="formState.verifyStatus === '1' && pageType == 'economize'" @click="handleAudit(record)">审核</a>
+						<a v-if="formState.verifyStatus === '2' && pageType == 'economize'" @click="handlePermission(record)"
+							>权限</a
+						>
+						<a v-if="formState.verifyStatus === '4'" @click="handleRestore(record)">恢复</a>
+						<a-divider type="vertical" />
+						<a-dropdown>
+							<a class="ant-dropdown-link">
+								更多
+								<DownOutlined />
+							</a>
+							<template #overlay>
+								<a-menu>
+									<a-menu-item>
+										<a href="javascript:;">播放</a>
+									</a-menu-item>
+									<a-menu-item>
+										<a href="javascript:;">下载</a>
+									</a-menu-item>
+									<a-menu-item v-if="formState.verifyStatus === '2'">
+										<a href="javascript:;" @click="edit(record)">编辑</a>
+									</a-menu-item>
+									<a-menu-item>
+										<a-popconfirm title="确认删除吗?" @confirm="resourcesDelete(record)">
+											<a href="javascript:;">删除</a>
+										</a-popconfirm>
+
+									</a-menu-item>
+								</a-menu>
+							</template>
+						</a-dropdown>
+					</div>
+				</template>
+			</template>
+		</a-table>
+		<div class="dis-flex-sb margin-top">
+			<div>
+				<a-button @click="selectAll">选择全部</a-button>
+				<a-button @click="invertSelection" style="margin-left: 8px">反选选择</a-button>
+			</div>
+			<div>
+				<CustomPagination
+					:total="pagination.total"
+					:current="pagination.pageNum"
+					:pageSize="pagination.pageSize"
+					:showQuickJumper="true"
+					:showSizeChanger="true"
+					:showTotal="(total) => `共 ${total} 条数据`"
+					@change="handlePageChange"
+					@showSizeChange="handlePageSizeChange"
+				/>
+			</div>
+		</div>
+
+		<!-- 资源上传模态框 -->
+		<resourceUpload
+			v-if="uploadModalVisible"
+			:isState="isState"
+			:resourcesId="editResourcesId"
+			@close="uploadModalVisible = false"
+			@getList="getList"
+		></resourceUpload>
+		<!-- 发布模态框 -->
+		<releaseModal v-if="releaseVisible" @close="releaseVisible = false" @confirm="confirm"></releaseModal>
+	</a-card>
+</template>
+
+<script setup>
+	import { ref, onMounted } from 'vue'
+	import { DownOutlined } from '@ant-design/icons-vue'
+	import releaseModal from './releaseModal.vue'
+	import resourceUpload from './resourceUpload.vue'
+	import resourceAuditApi from '@/api/resourceAudit.js'
+	import CustomPagination from '@/components/customPagination.vue'
+	import tool from '@/utils/tool'
+	// eslint-disable-next-line vue/no-setup-props-destructure
+	const { pageType } = defineProps({
+		pageType: {
+			type: String,
+			default: () => {}
+		}
+	})
+	// 数据源
+	const dataSource = ref([])
+	//发布按钮状态
+	const releaseVisible = ref(false)
+	const isPublishBulk = ref(false) //是否批量发布
+	const loading = ref(false) // 列表loading
+	const isState = ref(0) //是否是编辑  0:新增 1:编辑
+	const editResourcesId = ref(null) //资源id
+	// 搜索值
+	const searchValue = ref('')
+	//课程类型
+	const courseTypeOptions = tool.dictList('COURSE_TYPE')
+	const pagination = reactive({
+		pageSize: 10,
+		pageNum: 1,
+		total: 0
+	})
+	const formState = reactive({
+		fileName: null,
+		verifyStatus: '0',
+		resourcesId: null,
+		majorIdName: null,
+		courseTypeName: null,
+		suffix: null
+	})
+	// 添加选择状态
+	const selectedRowKeys = ref([])
+	const selectedRows = ref([])
+	// 行选择配置
+	const rowSelection = computed(() => {
+		return {
+			selectedRowKeys: selectedRowKeys.value,
+			onChange: (keys, rows) => {
+				selectedRowKeys.value = keys
+				selectedRows.value = rows
+			},
+			onSelectAll: (selected, selectedRows, changeRows) => {
+				if (selected) {
+					// 全选当前页
+					selectedRowKeys.value = dataSource.value.map((item) => item.id)
+					selectedRows.value = dataSource.value
+				} else {
+					// 取消全选
+					selectedRowKeys.value = []
+					selectedRows.value = []
+				}
+			},
+			onSelectInvert: () => {
+				// 反选当前页
+				const allKeys = dataSource.value.map((item) => item.id)
+				const newSelectedKeys = allKeys.filter((key) => !selectedRowKeys.value.includes(key))
+				selectedRowKeys.value = newSelectedKeys
+				selectedRows.value = dataSource.value.filter((item) => newSelectedKeys.includes(item.id))
+			}
+		}
+	})
+	// 列定义
+	const columnsUnpublished = [
+		{
+			title: '编号',
+			align: 'center',
+			dataIndex: 'fileId',
+			key: 'fileId'
+		},
+		{
+			title: '资源名称',
+			align: 'center',
+			dataIndex: 'fileName',
+			key: 'fileName'
+		},
+		{
+			title: '课件格式',
+			align: 'center',
+			dataIndex: 'suffix',
+			key: 'suffix'
+		},
+		{
+			title: '上传时间',
+			dataIndex: 'uploadTime',
+			align: 'center',
+			key: 'uploadTime'
+		},
+		{
+			title: '状态',
+			align: 'center',
+			key: 'verifyStatus'
+		},
+		{
+			title: '操作',
+			align: 'center',
+			key: 'action'
+		},
+		{
+			title: '资源缩略图',
+			align: 'center',
+			key: 'image'
+		}
+	]
+
+	const columnsPending = [
+		{
+			title: '编号',
+			dataIndex: 'id',
+			align: 'center',
+			key: 'id'
+		},
+		{
+			title: '资源名称',
+			align: 'center',
+			dataIndex: 'fileName',
+			key: 'fileName'
+		},
+		{
+			title: '所属院系',
+			align: 'center',
+			dataIndex: 'collegeIdName',
+			key: 'collegeIdName'
+		},
+		{
+			title: '所属课程',
+			align: 'center',
+			dataIndex: 'collegeIdName',
+			key: 'collegeIdName'
+		},
+		{
+			title: '所属专业',
+			align: 'center',
+			dataIndex: 'majorIdName',
+			key: 'majorIdName'
+		},
+		{
+			title: '课程类型',
+			align: 'center',
+			dataIndex: 'courseTypeName',
+			key: 'courseTypeName'
+		},
+		{
+			title: '课件格式',
+			align: 'center',
+			dataIndex: 'suffix',
+			key: 'suffix'
+		},
+		{
+			title: '上传时间',
+			align: 'center',
+			dataIndex: 'uploadTime',
+			key: 'uploadTime'
+		},
+		{
+			title: '状态',
+			align: 'center',
+			key: 'verifyStatus'
+		},
+		{
+			title: '操作',
+			align: 'center',
+			key: 'action'
+		},
+		{
+			title: '资源缩略图',
+			align: 'center',
+			key: 'image'
+		}
+	]
+
+	const columnsPublished = [...columnsPending]
+	const columnsRecycle = [...columnsPending]
+	const collegeMajorOptions = ref([])
+	const currentColumns = computed(() => {
+		switch (formState.verifyStatus) {
+			case '0':
+				return columnsUnpublished
+			case '1':
+				return columnsPending
+			case '2':
+				return columnsPublished
+			case '3':
+				return columnsPublished
+			case '4':
+				return columnsRecycle
+			default:
+				return []
+		}
+	})
+	const getListData = () => {
+		loading.value = true
+		let params = {
+			current: pagination.pageNum,
+			size: pagination.pageSize,
+			verifyStatus: formState.verifyStatus,
+			fileName: formState.fileName,
+			majorIdName: formState.majorIdName?.join(','),
+			courseTypeName: formState.courseTypeName,
+			suffix: formState.suffix
+		}
+		resourceAuditApi
+			.page(params)
+			.then((res) => {
+				console.log(res, '资源审核列表')
+				dataSource.value = res.data.records
+				pagination.total = res.data.total
+				loading.value = false
+			})
+			.catch((err) => {
+				console.log(err)
+				dataSource.value = []
+				pagination.total = 0
+				loading.value = false
+			})
+	}
+	const getList = () => {
+		getListData()
+	}
+	//院系组织查询
+	const getOrgTreeSelector = () => {
+		resourceAuditApi
+			.orgTreeSelector()
+			.then((res) => {
+				console.log(res.data, '获取组织树选择器')
+				collegeMajorOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	// 方法
+	const handleSearch = () => {
+		console.log('Search:', searchValue.value)
+		getListData()
+	}
+
+	const handleReset = () => {
+		searchValue.value = null
+		formState.majorIdName = null
+		formState.fileName = null
+		formState.courseTypeName = null
+		formState.suffix = null
+		getListData()
+	}
+	const tabChange = () => {
+		dataSource.value = []
+		getListData()
+	}
+	const publishedData = ref(null) //当前点击数据
+	//发布
+	const handlePublish = (record) => {
+		publishedData.value = record
+		releaseVisible.value = true
+		isPublishBulk.value = false
+	}
+	// 批量发布方法
+	const batchPublish = () => {
+		if (selectedRows.value.length === 0) {
+			message.warning('请至少选择一条记录')
+			return
+		}
+		isState.value = 0
+		isPublishBulk.value = true
+		releaseVisible.value = true
+	}
+	// 全选当前页数据
+	const selectAll = () => {
+		selectedRowKeys.value = dataSource.value.map((item) => item.id)
+		selectedRows.value = dataSource.value
+	}
+
+	// 反选当前页数据
+	const invertSelection = () => {
+		const allKeys = dataSource.value.map((item) => item.id)
+		const newSelectedKeys = allKeys.filter((key) => !selectedRowKeys.value.includes(key))
+		selectedRowKeys.value = newSelectedKeys
+		selectedRows.value = dataSource.value.filter((item) => newSelectedKeys.includes(item.id))
+	}
+	//发布确定
+	const confirm = (obj) => {
+		console.log(obj, selectedRows.value, '传回来的数据')
+		releaseVisible.value = false
+		if (isPublishBulk.value) {
+			// const batchParams = selectedRows.value.map((item) => ({
+			// 	id: item.id,
+			// 	coverImage: item.coverImage,
+			// 	resourceDesc: item.resourceDesc,
+			// 	verifyStatus: 1
+			// }))
+			const params = {
+				ids: selectedRows.value.map((item) => item.id).join(','),
+				coverImage: obj.coverImageId,
+				resourceDesc: obj.resourceDesc,
+				verifyStatus: 1
+			}
+			console.log(params, '批量发布参数')
+			// handleRelease(params)
+		} else {
+			const params = {
+				ids: publishedData.value.id,
+				coverImage: obj.coverImageId,
+				resourceDesc: obj.resourceDesc,
+				verifyStatus: 1
+			}
+			console.log(params, '发布参数')
+			handleRelease(params)
+		}
+	}
+	// updateStatus接口调用
+	const handleRelease = (Params) => {
+		resourceAuditApi
+			.updateStatus(Params)
+			.then((res) => {
+				getListData()
+				selectedRowKeys.value = []
+			})
+			.catch((err) => {
+				console.error(err)
+			})
+	}
+	const handleAudit = (record) => {
+		console.log('Audit:', record)
+	}
+
+	const handlePermission = (record) => {
+		console.log('Permission:', record)
+	}
+
+	const handleDelete = (record) => {
+		console.log('Delete:', record)
+	}
+	const handleRestore = (record) => {
+		console.log('Restore:', record)
+	}
+	//资源编辑
+	const edit = (record) => {
+		console.log('Restore:', record)
+		uploadModalVisible.value = true
+		isState.value = 1
+		editResourcesId.value = record.id
+	}
+	//资源删除
+	const resourcesDelete = (record) => {
+		const params = {
+			ids: record.id,
+			verifyStatus: 4
+		}
+		resourceAuditApi
+			.updateStatus(params)
+			.then((res) => {
+				getListData()
+			})
+			.catch((err) => {
+				console.error(err)
+			})
+	}
+
+	// 上传资源模态框
+	const uploadModalVisible = ref(false)
+
+	// 显示上传模态框
+	const showUploadModal = () => {
+		isState.value = 0
+		uploadModalVisible.value = true
+	}
+	// 翻页
+	const handlePageChange = (page) => {
+		pagination.pageNum = page
+		getListData()
+	}
+	// 每页条数
+	const handlePageSizeChange = (pageNum, size) => {
+		pagination.pageNum = 1
+		pagination.pageSize = size
+		getListData()
+	}
+
+	onMounted(() => {
+		if (pageType == 'economize') {
+			formState.verifyStatus = '1'
+		}
+		getOrgTreeSelector()
+		getListData()
+	})
+</script>
+
+<style scoped>
+	.editable-cell {
+		position: relative;
+	}
+
+	.ant-dropdown-link {
+		margin-left: 8px;
+	}
+
+	.upload-area {
+		border: 2px dashed #3ca9f5;
+		padding: 40px;
+		text-align: center;
+	}
+
+	.upload-area p {
+		margin: 10px 0;
+	}
+
+	.file-item {
+		display: flex;
+		align-items: center;
+		margin: 10px 0;
+	}
+
+	.file-item .ant-progress {
+		flex: 1;
+		margin: 0 10px;
+	}
+</style>

+ 6 - 0
src/views/myResources/personalResources/index.vue

@@ -0,0 +1,6 @@
+<template>
+	<myResources />
+</template>
+<script setup>
+	import myResources from '../myResources.vue'
+</script>

+ 35 - 99
src/views/myResources/releaseModal.vue

@@ -1,7 +1,7 @@
 <template>
 	<!-- 上传资源模态框 -->
 	<a-modal
-		:title="isState == 0 ? '发布课程' : '编辑课程'"
+		title="发布课程"
 		style="width: 800px"
 		v-model:visible="uploadModalVisible"
 		@ok="handleUploadOk"
@@ -12,7 +12,7 @@
 				<a-input v-model:value="uploadForm.resourceName" placeholder="请输入资源名称" />
 			</a-form-item> -->
 
-			<a-form-item label="资源类型" name="resourceType">
+			<!-- <a-form-item label="资源类型" name="resourceType">
 				<a-select v-model:value="uploadForm.resourceType" placeholder="请选择资源类型">
 					<a-select-option value="type1">类型1</a-select-option>
 					<a-select-option value="type2">类型2</a-select-option>
@@ -21,45 +21,16 @@
 
 			<a-form-item label="课程名称" name="courseName">
 				<a-input v-model:value="uploadForm.courseName" placeholder="请输入课程名称" />
-			</a-form-item>
+			</a-form-item> -->
 
-			<a-form-item label="课程介绍" name="courseDesc">
-				<a-textarea v-model:value="uploadForm.courseDesc" placeholder="请输入课程介绍" :rows="4" />
+			<a-form-item label="资源描述" name="courseDesc">
+				<a-textarea v-model:value="uploadForm.resourceDesc" placeholder="请输入课程介绍" :rows="4" />
 			</a-form-item>
 
 			<a-form-item label="上传封面" name="coverImageId">
-				<div style="margin-bottom: 10px">
-					<a-button type="primary" @click="chooseFile" :disabled="coverFileList.length > 0">选择图片</a-button>
-					<span style="margin-left: 10px">仅支持上传jpg/png格式文件,单个文件不能超过500kb</span>
-				</div>
-				<a-upload
-					ref="upload"
-					:before-upload="beforeUploadCover"
-					:file-list="coverFileList"
-					:remove="handleRemoveCover"
-					:headers="headers"
-					:action="action"
-					:on-change="handleChangeCover"
-					list-type="picture-card"
-				>
-					<div v-if="coverFileList.length < 1">
-						<plus-outlined />
-						<div class="ant-upload-text">上传图片</div>
-					</div>
-				</a-upload>
+				<coverUpload @handleChangeCover="handleChangeCover" @handleRemoveCover="handleRemoveCover"></coverUpload>
 			</a-form-item>
 		</a-form>
-
-		<!-- 文件上传状态展示 -->
-		<ul v-if="fileList.length">
-			<li v-for="(file, index) in fileList" :key="index" class="file-item">
-				<span>{{ file.name }}</span>
-				<a-progress :percent="file.percent || 0" />
-				<span v-if="file.status === 'done'">已完成</span>
-				<span v-else-if="file.status === 'error'">上传失败</span>
-				<span v-else-if="file.status === 'uploading'">上传中...</span>
-			</li>
-		</ul>
 	</a-modal>
 </template>
 
@@ -67,14 +38,15 @@
 	import { ref, reactive } from 'vue'
 	import { Modal, Upload } from 'ant-design-vue'
 	import { PlusOutlined } from '@ant-design/icons-vue'
+	import coverUpload from './coverUpload/index.vue'
 	import tool from '@/utils/tool'
-	const props = defineProps({
-		isState: {
-			type: Number,
-			required: true,
-			default: 0
-		}
-	})
+	// const props = defineProps({
+	// 	isState: {
+	// 		type: Number,
+	// 		required: true,
+	// 		default: 0
+	// 	}
+	// })
 	const headers = ref({
 		token: tool.data.get('TOKEN')
 	})
@@ -84,10 +56,10 @@
 	// 表单数据
 	const uploadForm = reactive({
 		// resourceName: null,
-		resourceType: null,
-		courseName: null,
-		courseDesc: null,
-		coverImageId: null
+		// resourceType: null,
+		// courseName: null,
+		resourceDesc: null,
+		coverImageId: '123'
 	})
 
 	// 封面文件列表
@@ -103,12 +75,12 @@
 
 	// 关闭模态框
 	const handleUploadCancel = () => {
-		uploadModalVisible.value = false
+		// uploadModalVisible.value = false
 		Object.assign(uploadForm, {
 			// resourceName: null,
-			resourceType: null,
-			courseName: null,
-			courseDesc: null,
+			resourceDesc: null,
+			// courseName: null,
+			// courseDesc: null,
 			coverImageId: null
 		})
 		fileList.value = []
@@ -116,70 +88,30 @@
 		emit('close')
 	}
 
-	// 确认上传
 	const handleUploadOk = () => {
 		// 这里可以添加实际的上传逻辑
 		console.log('Upload confirmed:', uploadForm.fileId, fileList.value, coverFileList.value)
 		emit('confirm', uploadForm)
-		uploadModalVisible.value = false
+		// uploadModalVisible.value = false
 		Object.assign(uploadForm, {
 			// resourceName: null,
-			resourceType: null,
-			courseName: null,
-			courseDesc: null,
+			// resourceType: null,
+			// courseName: null,
+			resourceDesc: null,
 			coverImageId: null
 		})
 		fileList.value = []
 		coverFileList.value = []
 	}
 
-	// 上传封面前的钩子函数
-	const beforeUploadCover = (file) => {
-		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
-		if (!isJpgOrPng) {
-			Modal.error({ content: '仅支持上传jpg/png格式文件!' })
-		}
-		const isLt500K = file.size / 1024 < 500
-		if (!isLt500K) {
-			Modal.error({ content: '单个文件不能超过500kb!' })
-		}
-		return isJpgOrPng && isLt500K
+	// 封面文件id
+	const handleChangeCover = (fileId) => {
+		uploadForm.coverImageId = fileId
 	}
 
 	// 移除封面文件
-	const handleRemoveCover = (file) => {
-		const index = coverFileList.value.indexOf(file)
-		const newFileList = coverFileList.value.slice()
-		newFileList.splice(index, 1)
-		coverFileList.value = newFileList
-		// 如果移除的是当前封面文件,则清空coverImageId
-		if (uploadForm.coverImageId === file.id) {
-			uploadForm.coverImageId = null
-		}
-	}
-
-	// 封面文件状态改变时的处理函数
-	const handleChangeCover = ({ file, fileList: newFileList }) => {
-		if (file.status === 'done') {
-			// 上传成功,获取文件ID
-			const fileId = file.response?.data || file.id
-			console.log('上传成功,获取文件ID', fileId)
-			if (fileId) {
-				uploadForm.coverImageId = fileId
-			}
-		}
-		if (file.status === 'error') {
-			// 延迟移除,确保用户能看到错误提示
-			setTimeout(() => {
-				coverFileList.value = coverFileList.value.filter((f) => f.uid !== file.uid)
-			}, 1500)
-		}
-		coverFileList.value = newFileList
-	}
-
-	// 选择文件按钮点击事件
-	const chooseFile = () => {
-		document.querySelector('.ant-upload input').click()
+	const handleRemoveCover = () => {
+		uploadForm.coverImageId = null
 	}
 </script>
 
@@ -204,4 +136,8 @@
 		flex: 1;
 		margin: 0 10px;
 	}
+	.ant-upload-picture-card-wrapper .ant-upload-list-item-info .ant-upload-list-item-filename {
+		display: block; /* 确保文件名显示为块级元素 */
+		margin-top: 8px; /* 调整文件名与图片之间的间距 */
+	}
 </style>

+ 6 - 0
src/views/myResources/resourceManagement/index.vue

@@ -0,0 +1,6 @@
+<template>
+	<myResources pageType="economize" />
+</template>
+<script setup>
+	import myResources from '../myResources.vue'
+</script>

+ 363 - 41
src/views/myResources/resourceUpload.vue

@@ -1,71 +1,363 @@
 <template>
 	<!-- 上传资源模态框 -->
-	<a-modal v-model:visible="uploadModalVisible" title="上传资源" @ok="handleUploadOk" @cancel="handleUploadCancel">
-		<a-upload
-			:multiple="true"
-			:before-upload="beforeUpload"
-			:headers="headers"
-			:action="action"
-			:file-list="fileList"
-			:remove="handleRemove"
-			accept=".ppt,.pptx,.doc,.docx,.xls,.xlsx,.pdf,.mp4,.zip,.rar"
-			:on-change="handleChange"
-		>
-			<div class="upload-area">
-				<a-icon type="cloud-upload" style="font-size: 60px; color: #3ca9f5"></a-icon>
-				<p>将文件拖到此处或点击上传</p>
-				<p>按住Ctrl可同时多选,支持上传PPT/word/excel/pdf/mp4/zip/rar,单个文件不能超过2G</p>
-			</div>
-		</a-upload>
-		<!-- 文件上传状态展示 -->
-		<ul v-if="fileList.length">
-			<li v-for="(file, index) in fileList" :key="index" class="file-item">
-				<span>{{ file.name }}</span>
-				<a-progress :percent="file.percent || 0" />
-				<span v-if="file.response?.code == '200'">已完成</span>
-				<span v-if="file.response?.code == '500'">上传失败</span>
-				<span v-if="file.status === 'uploading'">上传中...</span>
-			</li>
-		</ul>
+	<a-modal
+		v-model:visible="uploadModalVisible"
+		:title="isState == 0 ? '上传资源' : '编辑'"
+		@ok="handleUploadOk"
+		@cancel="handleUploadCancel"
+		width="600px"
+	>
+		<a-form :model="formState">
+			<a-form-item label="院系" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-cascader
+					v-model:value="formState.majorIdName"
+					:options="collegeMajorOptions"
+					:fieldNames="{ label: 'name', value: 'id', children: 'children' }"
+					placeholder="请选择院系"
+					style="width: 300px"
+					changeOnSelect
+					@change="changeCollegeMajor"
+				/>
+			</a-form-item>
+			<a-form-item label="专业" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-select
+					v-model:value="formState.majorId"
+					style="width: 200px"
+					:fieldNames="{ label: 'createUserName', value: 'popular' }"
+					:options="majorOptions"
+					placeholder="请选择专业"
+				/>
+			</a-form-item>
+			<!-- <a-form-item label="课程" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-select
+					v-model:value="formState.courseId"
+					style="width: 200px"
+					:fieldNames="{ label: 'courseName', value: 'courseId' }"
+					:options="courseOptions"
+					placeholder="请选择课程"
+				/>
+			</a-form-item> -->
+			<a-form-item label="资源类型" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-select
+					v-model:value="formState.courseType"
+					style="width: 200px"
+					:options="courseTypeOptions"
+					placeholder="请选择资源类型"
+				/>
+			</a-form-item>
+			<a-form-item label="关键词(需添加2-5个关键词)" :label-col="{ span: 8 }" :wrapper-col="{ span: 10 }">
+				<div v-if="!formState.keywordValue.length" style="color: #ccc">请选择下方热门关键词</div>
+				<div v-if="formState.keywordValue.length">
+					<a-tag
+						v-for="(keyword, index) in formState.keywordValue"
+						:key="index"
+						closable
+						@close="handleRemoveKeyword(index)"
+					>
+						{{ keyword }}
+					</a-tag>
+				</div>
+			</a-form-item>
+			<a-form-item label="热门关键词" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-checkbox-group
+					v-model:value="formState.keyword"
+					:options="HotKeywordsOptions"
+					@change="handleChangeKeyword"
+				/>
+			</a-form-item>
+			<a-row>
+				<a-col :span="5"></a-col>
+				<a-col :span="8">
+					<a-input v-model:value="newKeyword" placeholder="请输入关键词" @pressEnter="handleAddKeyword" />
+				</a-col>
+				<a-col :span="9" style="line-height: 30px"> 按回车Enter创建新关键词 </a-col>
+			</a-row>
+			<a-form-item label="资源是否公开" style="margin-top: 10px" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<div class="public-status-buttons">
+					<button :class="['status-button', { active: formState.publicStatus === '0' }]" @click="setPublicStatus('0')">
+						公开
+					</button>
+					<button :class="['status-button', { active: formState.publicStatus === '1' }]" @click="setPublicStatus('1')">
+						部分人可见
+					</button>
+				</div>
+			</a-form-item>
+			<a-form-item label="是否热门" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-radio-group v-model:value="formState.isHot">
+					<a-radio :value="0">否</a-radio>
+					<a-radio :value="1">是</a-radio>
+				</a-radio-group>
+			</a-form-item>
+			<a-form-item label="是否推荐" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
+				<a-radio-group v-model:value="formState.isRecommend">
+					<a-radio :value="0">否</a-radio>
+					<a-radio :value="1">是</a-radio>
+				</a-radio-group>
+			</a-form-item>
+			<a-form-item v-if="isState == 1" label="资源描述" name="courseDesc">
+				<a-textarea v-model:value="formState.resourceDesc" placeholder="请输入课程介绍" :rows="4" />
+			</a-form-item>
+			<a-form-item v-if="isState == 1" label="上传封面" name="coverImage">
+				<coverUpload
+					:isedit="true"
+					:coverImageId="formState.coverImage"
+					@handleChangeCover="handleChangeCover"
+					@handleRemoveCover="handleRemoveCover"
+				></coverUpload>
+			</a-form-item>
+			<!-- 选择成员 -->
+			<userSelection
+				v-if="userReleaseVisible"
+				@close="userReleaseVisible = false"
+				@confirm="confirmUser"
+			></userSelection>
+		</a-form>
+		<template v-if="isState == 0">
+			<a-upload
+				:multiple="true"
+				:before-upload="beforeUpload"
+				:headers="headers"
+				:action="action"
+				:file-list="fileList"
+				:remove="handleRemove"
+				accept=".ppt,.pptx,.doc,.docx,.xls,.xlsx,.pdf,.mp4,.zip,.rar"
+				:on-change="handleChange"
+			>
+				<div class="upload-area">
+					<a-icon type="cloud-upload" style="font-size: 60px; color: #3ca9f5"></a-icon>
+					<p>将文件拖到此处或点击上传</p>
+					<p>按住Ctrl可同时多选,支持上传PPT/word/excel/pdf/mp4/zip/rar,单个文件不能超过2G</p>
+				</div>
+			</a-upload>
+			<!-- 文件上传状态展示 -->
+			<ul v-if="fileList.length">
+				<li v-for="(file, index) in fileList" :key="index" class="file-item">
+					<span>{{ file.name }}</span>
+					<a-progress :percent="file.percent || 0" />
+					<span v-if="file.response?.code == '200'">已完成</span>
+					<span v-if="file.response?.code == '500'">上传失败</span>
+					<span v-if="file.status === 'uploading'">上传中...</span>
+				</li>
+			</ul>
+		</template>
 	</a-modal>
 </template>
 
 <script setup>
-	import { ref, reactive } from 'vue'
-	import { Modal, Upload } from 'ant-design-vue'
+	import { ref, reactive, onMounted } from 'vue'
+	import { Modal, Upload, Form } from 'ant-design-vue'
 	import resourceAuditApi from '@/api/resourceAudit.js'
+	import userSelection from './userSelection.vue'
+	import coverUpload from './coverUpload/index.vue'
+	const props = defineProps({
+		isState: {
+			type: Number,
+			required: true,
+			default: 0
+		},
+		resourcesId: {
+			type: Number,
+			required: true,
+			default: null
+		}
+	})
 	const emit = defineEmits(['close', 'getList'])
+	import tool from '@/utils/tool'
+	const headers = ref({
+		token: tool.data.get('TOKEN')
+	})
+	//课程类型
+	const courseTypeOptions = tool.dictList('COURSE_TYPE')
+	const action = ref('http://192.168.31.80:9003/api/webapp/dev/file/uploadMinioReturnId')
 	const formState = reactive({
-		resourcesId: null
+		userfileIds: null, //资源文件id
+		coverImage: null, //封面id
+		// courseId: null, //课程
+		majorType: null, //专业
+		courseType: null, //课程类型
+		collegeId: null, //院校一级id
+		collegeTwoId: null, //院校二级id
+		collegeThreeId: null, //院校三级id
+		resourceDesc: null, //资源介绍
+		majorId: null, //专业id
+		courseTypeName: [], // 资源类型
+		keywordValue: [], // 添加关键词
+		keyword: [], // 热门关键词
+		publicStatus: 'public', // 资源是否公开
+		isRecommend: 0, // 资源是否推荐
+		isHot: 0 // 资源是否热门
 	})
+	const collegeMajorOptions = ref([]) //院系
+	const HotKeywordsOptions = ref([]) //热门关键词列表
+	const majorIdName = ref([]) //院系回显
+	const majorOptions = ref([]) //专业
+	const courseOptions = ref([]) //课程
 	// 上传资源模态框
 	const uploadModalVisible = ref(true)
+	// 用户选择模态框
+	const userReleaseVisible = ref(false)
 
 	// 文件列表
 	const fileList = ref([])
 
 	// 关闭模态框
 	const handleUploadCancel = () => {
-		// uploadModalVisible.value = false
 		emit('close')
 		fileList.value = []
 	}
+	const rules = {
+		courseTypeName: [{ required: true, message: '请选择资源类型', trigger: 'change' }],
+		keywordValue: [{ required: true, message: '请添加关键词', trigger: 'blur' }]
+	}
 
+	const newKeyword = ref('') //关键词
+	const handleAddKeyword = (e) => {
+		const newKeywords = newKeyword.value.trim()
+		resourceAuditApi
+			.addHotKeywords({
+				wordName: newKeywords,
+				popular: 0
+			})
+			.then((res) => {
+				console.log(res.data, '添加热门关键词')
+				getHotKeywords()
+				newKeyword.value = ''
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+		// if (newKeywords && !formState.keywordValue.includes(newKeywords)) {
+		// 	formState.keywordValue.push(newKeywords)
+		// }
+	}
+
+	const handleRemoveKeyword = (index) => {
+		formState.keywordValue.splice(index, 1)
+	}
+	const getHotKeywords = () => {
+		resourceAuditApi
+			.HotKeywords()
+			.then((res) => {
+				console.log(res.data, '获取热门关键词')
+				HotKeywordsOptions.value = res.data.map((it) => {
+					return {
+						value: it.wordName,
+						label: it.wordName
+					}
+				})
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	const handleChangeKeyword = (e) => {
+		console.log(e)
+		formState.keywordValue = e
+	}
+	const setPublicStatus = (status) => {
+		formState.publicStatus = status
+		if (status === '1') {
+			userReleaseVisible.value = true
+		}
+	}
+	//院系组织查询
+	const getOrgTreeSelector = () => {
+		resourceAuditApi
+			.orgTreeSelector()
+			.then((res) => {
+				console.log(res.data, '获取组织树选择器')
+				collegeMajorOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	//院系组织查询
+	const getCourseAllList = () => {
+		resourceAuditApi
+			.courseAllList()
+			.then((res) => {
+				console.log(res.data, '获取全部课程')
+				courseOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	const changeCollegeMajor = (value, selectedOptions) => {
+		console.log('Selected:', value, selectedOptions)
+		formState.collegeId = value[0] || null
+		formState.collegeTwoId = value[1] || null
+		formState.collegeThreeId = value[2] || null
+		if (selectedOptions.length) {
+			// 获取选中的最后一级
+			const lastSelected = selectedOptions[selectedOptions.length - 1]
+			// formState.selectedCollegeMajor = {
+			// 	id: lastSelected.id,
+			// 	name: lastSelected.name,
+			// 	fullPath: selectedOptions.map((opt) => opt.name).join(' / ')
+			// }
+			console.log(lastSelected, '最后一级id')
+			resourceAuditApi
+				.zyselect({ id: lastSelected.id })
+				.then((res) => {
+					console.log(res.data, '专业下拉数据')
+					majorOptions.value = res.data
+				})
+				.catch((err) => {
+					console.log(err)
+				})
+		}
+	}
 	// 确认上传
 	const handleUploadOk = () => {
-		// 这里可以添加实际的上传逻辑
-		console.log('Upload confirmed:', fileList.value)
-		// uploadModalVisible.value = false
-		emit('close')
-		fileList.value = []
+		if (!formState.userfileIds) {
+			Modal.error({ content: '请先上传文件!' })
+			return
+		}
+
+		const formData = {
+			userfileIds: formState.userfileIds,
+			courseTypeName: formState.courseTypeName,
+			keywordValue: formState.keywordValue
+				.split(',')
+				.map((keyword) => keyword.trim())
+				.filter((keyword) => keyword),
+			keyword: formState.keyword,
+			publicStatus: formState.publicStatus
+		}
+
 		resourceAuditApi
-			.add({ fileId: formState.resourcesId })
+			.add(formData)
 			.then((res) => {
 				emit('getList')
+				Modal.success({ content: '资源上传成功' })
 			})
 			.catch((err) => {
+				Modal.error({ content: '资源上传失败' })
 				console.log(err)
 			})
+			.finally(() => {
+				fileList.value = []
+				formState.userfileIds = null
+				formState.courseTypeName = ''
+				formState.keywordValue = ''
+				formState.hotKeywords = []
+				formState.publicStatus = 'public'
+			})
+	}
+	// 获取资源详情
+	const getDetail = () => {
+		resourceAuditApi.detail({ id: props.resourcesId }).then((res) => {
+			console.log(res.data, '资源详情')
+			formState.courseType = res.data.courseType
+			formState.collegeId = res.data.collegeId
+			formState.collegeTwoId = res.data.collegeTwoId
+			formState.collegeThreeId = res.data.collegeThreeId
+			majorIdName.value = [res.data.collegeId, res.data.collegeTwoId, res.data.collegeThreeId]
+			formState.resourceDesc = res.data.resourceDesc
+			formState.majorId = res.data.majorId
+		})
 	}
 	// 上传前的钩子函数
 	const beforeUpload = (file) => {
@@ -83,8 +375,8 @@
 		newFileList.splice(index, 1)
 		fileList.value = newFileList
 		// 如果移除的是当前封面文件,则清空coverImageId
-		if (formState.resourcesId === file.id) {
-			formState.resourcesId = null
+		if (formState.userfileIds === file.id) {
+			formState.userfileIds = null
 		}
 	}
 
@@ -101,7 +393,7 @@
 			const fileId = file.response?.data || file.id
 			console.log('上传成功,获取文件ID', fileId)
 			if (fileId) {
-				formState.resourcesId = fileId
+				formState.userfileIds = fileId
 			}
 		}
 		fileList.value = newFileList
@@ -116,8 +408,15 @@
 			file.percent = 0
 		}
 	}
+	onMounted(() => {
+		getOrgTreeSelector()
+		getCourseAllList()
+		getHotKeywords()
+		if (props.isState == 1) {
+			getDetail()
+		}
+	})
 </script>
-
 <style scoped>
 	.upload-area {
 		border: 2px dashed #3ca9f5;
@@ -139,4 +438,27 @@
 		flex: 1;
 		margin: 0 10px;
 	}
+
+	/* 新增表单样式 */
+	.ant-form-item {
+		margin-bottom: 16px;
+	}
+	.public-status-buttons {
+		display: flex;
+	}
+
+	.status-button {
+		padding: 5px 10px;
+		/* margin-right: 10px; */
+		border: 1px solid #ccc;
+		/* border-radius: 3px; */
+		cursor: pointer;
+		background-color: #fff;
+	}
+
+	.status-button.active {
+		background-color: #40a9ff;
+		color: #fff;
+		border-color: #40a9ff;
+	}
 </style>

+ 241 - 0
src/views/myResources/userSelection.vue

@@ -0,0 +1,241 @@
+<template>
+	<a-drawer
+		v-model:visible="visible"
+		title="选择可见成员"
+		placement="right"
+		width="50%"
+		:footer="null"
+		@close="handleCancel"
+	>
+		<!-- 左侧:树状结构成员列表 -->
+		<div class="left-panel">
+			<a-input-search
+				v-model:value="searchValue"
+				placeholder="输入部门或成员名称"
+				style="margin-bottom: 16px"
+				@search="onSearch"
+			/>
+			<a-tree
+				:tree-data="filteredTreeData"
+				:field-names="{ key: 'id', title: 'name', children: 'children' }"
+				:checked-keys="checkedKeys"
+				:expanded-keys="expandedKeys"
+				:auto-expand-parent="autoExpandParent"
+				checkable
+				show-icon
+				:selectable="false"
+				@check="onCheck"
+				@expand="onExpand"
+			>
+				<template #title="{ name, avatar }">
+					<span style="display: inline-flex; align-items: center">
+						<a-avatar :src="avatar" size="small" style="margin-right: 8px" />
+						{{ name }}
+					</span>
+				</template>
+				<template #switcherIcon="{ expanded }">
+					<caret-down-outlined v-if="expanded" />
+					<caret-right-outlined v-else />
+				</template>
+			</a-tree>
+		</div>
+
+		<!-- 右侧:已选择成员列表 -->
+		<div class="right-panel">
+			<div class="header">
+				<span>已选 {{ selectedUsers.length }} / 30</span>
+				<a-button type="link" @click="clearSelection">清空</a-button>
+			</div>
+			<a-list item-layout="horizontal" :data-source="selectedUsers">
+				<template #renderItem="{ item }">
+					<a-list-item>
+						<a-list-item-meta>
+							<template #avatar>
+								<a-avatar :src="item.avatar" />
+							</template>
+							<template #title>
+								<a>{{ item.name }}</a>
+							</template>
+							<template #description>
+								<span>{{ item.department }}</span>
+							</template>
+						</a-list-item-meta>
+						<template #actions>
+							<a @click="removeUser(item)">删除</a>
+						</template>
+					</a-list-item>
+				</template>
+			</a-list>
+		</div>
+
+		<!-- 底部按钮 -->
+		<template #footer>
+			<a-space>
+				<a-button @click="handleCancel">取消</a-button>
+				<a-button type="primary" @click="handleOk">确定</a-button>
+			</a-space>
+		</template>
+	</a-drawer>
+</template>
+
+<script setup>
+	import { ref, reactive, computed, watch } from 'vue'
+	import { Modal, Input, Tree, List, Avatar, Button } from 'ant-design-vue'
+	const emit = defineEmits(['close', 'confirm'])
+	const visible = ref(true)
+	const searchValue = ref('')
+	const treeData = ref([
+		{
+			id: '1',
+			name: '组织1',
+			children: [
+				{
+					id: '1-1',
+					name: '张小刚',
+					avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
+					isLeaf: true
+				},
+				{
+					id: '1-2',
+					name: '李小红',
+					avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
+					isLeaf: true
+				}
+			]
+		},
+		{
+			id: '2',
+			name: '组织2',
+			children: [
+				{
+					id: '2-1',
+					name: '研发部',
+					children: [
+						{
+							id: '2-1-1',
+							name: '王小明',
+							avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
+							isLeaf: true
+						}
+					]
+				}
+			]
+		}
+	])
+	const selectedKeys = ref([])
+	const selectedUsers = ref([])
+	const checkedKeys = ref([])
+	const expandedKeys = ref(['1']) // 默认展开第一层
+	const autoExpandParent = ref(true)
+	const filteredTreeData = computed(() => {
+		const filterFn = (node) => {
+			if (node.name.includes(searchValue.value)) {
+				return true
+			}
+			if (node.children && node.children.some(filterFn)) {
+				return true
+			}
+			return false
+		}
+		return treeData.value.filter(filterFn)
+	})
+
+	// 替换原来的onSelect方法
+	const onCheck = (checkedKeysValue, { checked, node, checkedNodes }) => {
+		checkedKeys.value = checkedKeysValue
+		selectedUsers.value = checkedNodes
+			.filter((node) => node.isLeaf) // 只保留叶子节点
+			.map((node) => ({
+				id: node.id,
+				name: node.name,
+				avatar: node.avatar,
+				department: findDepartmentName(node.id, treeData.value)
+			}))
+	}
+	// 查找部门名称的辅助函数
+	const findDepartmentName = (id, nodes) => {
+		for (const node of nodes) {
+			if (node.children) {
+				const found = node.children.find((child) => child.id === id)
+				if (found) return node.name
+				const result = findDepartmentName(id, node.children)
+				if (result) return result
+			}
+		}
+		return ''
+	}
+	const onExpand = (keys) => {
+		expandedKeys.value = keys
+		autoExpandParent.value = false
+	}
+
+	const onSearch = (value) => {
+		searchValue.value = value
+	}
+
+	const clearSelection = () => {
+		selectedKeys.value = []
+		selectedUsers.value = []
+		checkedKeys.value = []
+	}
+
+	const removeUser = (user) => {
+		const index = selectedUsers.value.findIndex((u) => u.id === user.id)
+		if (index !== -1) {
+			selectedUsers.value.splice(index, 1)
+			selectedKeys.value = selectedUsers.value.map((u) => u.id)
+			checkedKeys.value = selectedUsers.value.map((u) => u.id)
+		}
+		// selectedUsers.value = selectedUsers.value.filter((u) => u.id !== user.id)
+		// checkedKeys.value = selectedUsers.value.map((u) => u.id)
+	}
+
+	const showModal = () => {
+		visible.value = true
+	}
+
+	const handleOk = () => {
+		console.log('Selected Users:', selectedUsers.value)
+	}
+
+	const handleCancel = () => {
+		emit('close')
+	}
+</script>
+
+<style scoped>
+	.left-panel,
+	.right-panel {
+		display: inline-block;
+		vertical-align: top;
+		width: 48%;
+		height: calc(100vh - 200px);
+		overflow-y: auto;
+		padding: 0 10px;
+	}
+
+	.right-panel {
+		border-left: 1px solid #f0f0f0;
+	}
+
+	.header {
+		display: flex;
+		justify-content: space-between;
+		margin-bottom: 16px;
+	}
+
+	.ant-tree-switcher {
+		width: 24px;
+		height: 24px;
+		line-height: 24px;
+	}
+
+	.ant-tree-switcher-icon {
+		font-size: 12px;
+		transition: transform 0.3s;
+	}
+
+	.ant-tree-switcher_close .ant-tree-switcher-icon {
+		transform: rotate(-90deg);
+	}
+</style>

+ 183 - 0
src/views/organization/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/organization/organization'
+	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/organization/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/organization/organization'
+	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>