feat: 资源联调
This commit is contained in:
parent
36ae82efa2
commit
51bbd8c170
@ -1,10 +1,12 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import login from './login'
|
import login from './login'
|
||||||
import commodity from './commodity'
|
import commodity from './commodity'
|
||||||
|
import resource from './resource'
|
||||||
|
|
||||||
const totalApiConfig = {
|
const totalApiConfig = {
|
||||||
login,
|
login,
|
||||||
commodity
|
commodity,
|
||||||
|
resource
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.values(totalApiConfig).forEach((apiConfig) => {
|
Object.values(totalApiConfig).forEach((apiConfig) => {
|
||||||
|
|||||||
12
src/api/resource.ts
Normal file
12
src/api/resource.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const resource = {
|
||||||
|
/**
|
||||||
|
* 资源列表
|
||||||
|
*/
|
||||||
|
getResourceList: ['/resource/list'], // 获取资源列表
|
||||||
|
uploadFile: ['/upload/file', { headers: { 'Content-Type': 'multipart/form-data' } }], // 上传文件
|
||||||
|
addOrEditResource: ['/resource/addOrUpdate'], // 新增和编辑资源
|
||||||
|
sortResource: ['/resource/sort'], // 资源排序
|
||||||
|
deleteResource: ['/resource/delete'] // 资源删除
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resource
|
||||||
154
src/auto-import.d.ts
vendored
154
src/auto-import.d.ts
vendored
@ -6,77 +6,95 @@
|
|||||||
// biome-ignore lint: disable
|
// biome-ignore lint: disable
|
||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: (typeof import('vue'))['EffectScope']
|
||||||
const api: typeof import('../../../../../../src/api/index')['api']
|
const api: (typeof import('src/api/index'))['api']
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: (typeof import('vue'))['computed']
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: (typeof import('vue'))['createApp']
|
||||||
const customRef: typeof import('vue')['customRef']
|
const customRef: (typeof import('vue'))['customRef']
|
||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
const defineAsyncComponent: (typeof import('vue'))['defineAsyncComponent']
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
const defineComponent: (typeof import('vue'))['defineComponent']
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
const effectScope: (typeof import('vue'))['effectScope']
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
const getCurrentInstance: (typeof import('vue'))['getCurrentInstance']
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
const getCurrentScope: (typeof import('vue'))['getCurrentScope']
|
||||||
const getCurrentWatcher: typeof import('vue')['getCurrentWatcher']
|
const getCurrentWatcher: (typeof import('vue'))['getCurrentWatcher']
|
||||||
const h: typeof import('vue')['h']
|
const h: (typeof import('vue'))['h']
|
||||||
const handleInit: typeof import('../../../../../../src/utils/page/index')['handleInit']
|
const handleInit: (typeof import('src/utils/page/index'))['handleInit']
|
||||||
const handleMessageBox: typeof import('../../../../../../src/utils/page/index')['handleMessageBox']
|
const handleMessageBox: (typeof import('src/utils/page/index'))['handleMessageBox']
|
||||||
const inject: typeof import('vue')['inject']
|
const inject: (typeof import('vue'))['inject']
|
||||||
const isProxy: typeof import('vue')['isProxy']
|
const isProxy: (typeof import('vue'))['isProxy']
|
||||||
const isReactive: typeof import('vue')['isReactive']
|
const isReactive: (typeof import('vue'))['isReactive']
|
||||||
const isReadonly: typeof import('vue')['isReadonly']
|
const isReadonly: (typeof import('vue'))['isReadonly']
|
||||||
const isRef: typeof import('vue')['isRef']
|
const isRef: (typeof import('vue'))['isRef']
|
||||||
const isShallow: typeof import('vue')['isShallow']
|
const isShallow: (typeof import('vue'))['isShallow']
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
const markRaw: (typeof import('vue'))['markRaw']
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const nextTick: (typeof import('vue'))['nextTick']
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
const onActivated: (typeof import('vue'))['onActivated']
|
||||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
const onBeforeMount: (typeof import('vue'))['onBeforeMount']
|
||||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
const onBeforeRouteLeave: (typeof import('vue-router'))['onBeforeRouteLeave']
|
||||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
const onBeforeRouteUpdate: (typeof import('vue-router'))['onBeforeRouteUpdate']
|
||||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
const onBeforeUnmount: (typeof import('vue'))['onBeforeUnmount']
|
||||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
const onBeforeUpdate: (typeof import('vue'))['onBeforeUpdate']
|
||||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
const onDeactivated: (typeof import('vue'))['onDeactivated']
|
||||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
const onErrorCaptured: (typeof import('vue'))['onErrorCaptured']
|
||||||
const onMounted: typeof import('vue')['onMounted']
|
const onMounted: (typeof import('vue'))['onMounted']
|
||||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
const onRenderTracked: (typeof import('vue'))['onRenderTracked']
|
||||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
const onRenderTriggered: (typeof import('vue'))['onRenderTriggered']
|
||||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
const onScopeDispose: (typeof import('vue'))['onScopeDispose']
|
||||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
const onServerPrefetch: (typeof import('vue'))['onServerPrefetch']
|
||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
const onUnmounted: (typeof import('vue'))['onUnmounted']
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
const onUpdated: (typeof import('vue'))['onUpdated']
|
||||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
const onWatcherCleanup: (typeof import('vue'))['onWatcherCleanup']
|
||||||
const pageConfig: typeof import('../../../../../../src/utils/page/config')['pageConfig']
|
const pageConfig: (typeof import('src/utils/page/config'))['pageConfig']
|
||||||
const provide: typeof import('vue')['provide']
|
const provide: (typeof import('vue'))['provide']
|
||||||
const reactive: typeof import('vue')['reactive']
|
const reactive: (typeof import('vue'))['reactive']
|
||||||
const readonly: typeof import('vue')['readonly']
|
const readonly: (typeof import('vue'))['readonly']
|
||||||
const ref: typeof import('vue')['ref']
|
const ref: (typeof import('vue'))['ref']
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
const resolveComponent: (typeof import('vue'))['resolveComponent']
|
||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
const shallowReactive: (typeof import('vue'))['shallowReactive']
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
const shallowReadonly: (typeof import('vue'))['shallowReadonly']
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
const shallowRef: (typeof import('vue'))['shallowRef']
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
const toRaw: (typeof import('vue'))['toRaw']
|
||||||
const toRef: typeof import('vue')['toRef']
|
const toRef: (typeof import('vue'))['toRef']
|
||||||
const toRefs: typeof import('vue')['toRefs']
|
const toRefs: (typeof import('vue'))['toRefs']
|
||||||
const toValue: typeof import('vue')['toValue']
|
const toValue: (typeof import('vue'))['toValue']
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
const triggerRef: (typeof import('vue'))['triggerRef']
|
||||||
const unref: typeof import('vue')['unref']
|
const unref: (typeof import('vue'))['unref']
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: (typeof import('vue'))['useAttrs']
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCssModule: (typeof import('vue'))['useCssModule']
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssVars: (typeof import('vue'))['useCssVars']
|
||||||
const useId: typeof import('vue')['useId']
|
const useId: (typeof import('vue'))['useId']
|
||||||
const useLink: typeof import('vue-router')['useLink']
|
const useLink: (typeof import('vue-router'))['useLink']
|
||||||
const useModel: typeof import('vue')['useModel']
|
const useModel: (typeof import('vue'))['useModel']
|
||||||
const useRoute: typeof import('vue-router')['useRoute']
|
const useRoute: (typeof import('vue-router'))['useRoute']
|
||||||
const useRouter: typeof import('vue-router')['useRouter']
|
const useRouter: (typeof import('vue-router'))['useRouter']
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
const useSlots: (typeof import('vue'))['useSlots']
|
||||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
const useTemplateRef: (typeof import('vue'))['useTemplateRef']
|
||||||
const watch: typeof import('vue')['watch']
|
const watch: (typeof import('vue'))['watch']
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
const watchEffect: (typeof import('vue'))['watchEffect']
|
||||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
const watchPostEffect: (typeof import('vue'))['watchPostEffect']
|
||||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
const watchSyncEffect: (typeof import('vue'))['watchSyncEffect']
|
||||||
}
|
}
|
||||||
// for type re-export
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
export type {
|
||||||
|
Component,
|
||||||
|
Slot,
|
||||||
|
Slots,
|
||||||
|
ComponentPublicInstance,
|
||||||
|
ComputedRef,
|
||||||
|
DirectiveBinding,
|
||||||
|
ExtractDefaultPropTypes,
|
||||||
|
ExtractPropTypes,
|
||||||
|
ExtractPublicPropTypes,
|
||||||
|
InjectionKey,
|
||||||
|
PropType,
|
||||||
|
Ref,
|
||||||
|
ShallowRef,
|
||||||
|
MaybeRef,
|
||||||
|
MaybeRefOrGetter,
|
||||||
|
VNode,
|
||||||
|
WritableComputedRef
|
||||||
|
} from 'vue'
|
||||||
import('vue')
|
import('vue')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,14 +55,14 @@ export const getTableData = (
|
|||||||
.$api(params)
|
.$api(params)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const result = res as {
|
const result = res as {
|
||||||
data: {}[]
|
data: { rows: [] }
|
||||||
code: string
|
code: string
|
||||||
resultMsg: string
|
resultMsg: string
|
||||||
totalRows: number
|
totalPage: number
|
||||||
}
|
}
|
||||||
table.$loading = false
|
table.$loading = false
|
||||||
table.$data = result.data
|
table.$data = result.data.rows
|
||||||
table.$pages.total = result.totalRows
|
table.$pages.total = result.totalPage
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
table.$loading = false
|
table.$loading = false
|
||||||
|
|||||||
@ -55,7 +55,7 @@ service.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
if ([200].includes(response.data.code) || response.config.third) {
|
if (['200'].includes(response.data.code) || response.config.third) {
|
||||||
return response.data
|
return response.data
|
||||||
} else {
|
} else {
|
||||||
if (response.data.code === 401) {
|
if (response.data.code === 401) {
|
||||||
|
|||||||
@ -59,5 +59,5 @@ const { commodityType, onChangeCommodityType, commodityTypeOptions } = useCommod
|
|||||||
onChangeCommodityType(commodityType.value)
|
onChangeCommodityType(commodityType.value)
|
||||||
|
|
||||||
/** 页面缓存 */
|
/** 页面缓存 */
|
||||||
defineOptions({ name: 'supplier-config' })
|
defineOptions({ name: 'Commodity' })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -49,5 +49,5 @@ setTimeout(() => {
|
|||||||
}, 2000)
|
}, 2000)
|
||||||
|
|
||||||
/** 页面缓存 */
|
/** 页面缓存 */
|
||||||
defineOptions({ name: 'supplier-config' })
|
defineOptions({ name: 'HomeGoods' })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
131
src/views/resource/list copy/index.vue
Normal file
131
src/views/resource/list copy/index.vue
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<template>
|
||||||
|
<div id="category-tree" class="p-2 bg-white">
|
||||||
|
<p>资源展示:</p>
|
||||||
|
<el-tree
|
||||||
|
style="max-width: 600px"
|
||||||
|
:data="transformedDataSource"
|
||||||
|
node-key="id"
|
||||||
|
draggable
|
||||||
|
show-checkbox
|
||||||
|
:default-expanded-keys="[2, 3]"
|
||||||
|
:default-checked-keys="[5]"
|
||||||
|
default-expand-all
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
@node-drag-start="handleDragStart"
|
||||||
|
@node-drag-enter="handleDragEnter"
|
||||||
|
@node-drag-leave="handleDragLeave"
|
||||||
|
@node-drag-over="handleDragOver"
|
||||||
|
@node-drag-end="handleDragEnd"
|
||||||
|
@node-drop="handleDrop"
|
||||||
|
>
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<div class="category-tree-node">
|
||||||
|
<span v-if="curId !== data.id">{{ data.fileName }}</span>
|
||||||
|
<el-input
|
||||||
|
ref="inputRef"
|
||||||
|
v-else
|
||||||
|
v-model="data.label2"
|
||||||
|
size="small"
|
||||||
|
class="w-40"
|
||||||
|
@keyup.enter="handleInputConfirm(data)"
|
||||||
|
@blur="handleInputCancel(node, data)"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" link @click="edit(data)" size="small">编辑 </el-button>
|
||||||
|
<el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button>
|
||||||
|
<el-button type="danger" size="small" link @click="remove(node, data)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElButton } from 'element-plus'
|
||||||
|
import type { RenderContentContext } from 'element-plus'
|
||||||
|
import { transformedDataSource } from './mock'
|
||||||
|
import {
|
||||||
|
handleDragStart,
|
||||||
|
handleDragEnter,
|
||||||
|
handleDragOver,
|
||||||
|
handleDragLeave,
|
||||||
|
handleDragEnd,
|
||||||
|
handleDrop
|
||||||
|
} from './use-drag'
|
||||||
|
|
||||||
|
interface Tree {
|
||||||
|
id: number
|
||||||
|
label: string
|
||||||
|
children?: Tree[]
|
||||||
|
}
|
||||||
|
type Node = RenderContentContext['node']
|
||||||
|
type Data = RenderContentContext['data']
|
||||||
|
|
||||||
|
const curId = ref(NaN)
|
||||||
|
const inputRef = ref()
|
||||||
|
|
||||||
|
const edit = (data: Data) => {
|
||||||
|
data.label2 = data.label
|
||||||
|
curId.value = data.id
|
||||||
|
nextTick(() => {
|
||||||
|
inputRef.value.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回车确认
|
||||||
|
const handleInputConfirm = (data: any) => {
|
||||||
|
if (curId.value === Infinity) {
|
||||||
|
// 新增接口
|
||||||
|
} else {
|
||||||
|
// 修改接口
|
||||||
|
}
|
||||||
|
data.label = data.label2
|
||||||
|
data.label2 = ''
|
||||||
|
curId.value = NaN
|
||||||
|
}
|
||||||
|
|
||||||
|
// 失焦
|
||||||
|
const handleInputCancel = (node: Node, data: Data) => {
|
||||||
|
if (data.id === Infinity) {
|
||||||
|
remove(node, data)
|
||||||
|
}
|
||||||
|
curId.value = NaN
|
||||||
|
}
|
||||||
|
|
||||||
|
const append = (data: Data) => {
|
||||||
|
curId.value = Infinity
|
||||||
|
const newChild = { id: curId.value, label2: 'test', children: [] }
|
||||||
|
if (!data.children) {
|
||||||
|
data.children = []
|
||||||
|
}
|
||||||
|
data.children.push(newChild)
|
||||||
|
transformedDataSource.value = [...transformedDataSource.value]
|
||||||
|
nextTick(() => {
|
||||||
|
inputRef.value.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const remove = (node: Node, data: Data) => {
|
||||||
|
const parent = node.parent
|
||||||
|
const children: Tree[] = parent?.data.children || parent?.data
|
||||||
|
const index = children.findIndex((d) => d.id === data.id)
|
||||||
|
children.splice(index, 1)
|
||||||
|
transformedDataSource.value = [...transformedDataSource.value]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#category-tree {
|
||||||
|
.category-tree-node {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
162
src/views/resource/list copy/mock.ts
Normal file
162
src/views/resource/list copy/mock.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
interface Tree {
|
||||||
|
id: number
|
||||||
|
resourceUrl: string
|
||||||
|
type: string
|
||||||
|
fileName: string
|
||||||
|
defaultSort: number
|
||||||
|
children?: Tree[]
|
||||||
|
}
|
||||||
|
interface OriginDataItem {
|
||||||
|
id: number
|
||||||
|
resourceUrl: string
|
||||||
|
fileName: string
|
||||||
|
type: string
|
||||||
|
defaultSort: number
|
||||||
|
parentId?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const originData: OriginDataItem[] = [
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 10,
|
||||||
|
defaultSort: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 78,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 77,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 80,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 78,
|
||||||
|
defaultSort: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 82,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 81,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 84,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 83,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 86,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 85,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 88,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 87,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 90,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 89,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 92,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 91,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 94,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 93,
|
||||||
|
defaultSort: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 originData 转换为 dataSource 的树形结构
|
||||||
|
* @param data 原始数据数组
|
||||||
|
* @returns 转换后的树形结构数据
|
||||||
|
*/
|
||||||
|
export function transformToTreeData(data: OriginDataItem[]): Tree[] {
|
||||||
|
// 创建映射表,用于快速查找
|
||||||
|
const itemMap = new Map<number, Tree>()
|
||||||
|
const result: Tree[] = []
|
||||||
|
|
||||||
|
// 首先创建所有节点
|
||||||
|
data.forEach((item) => {
|
||||||
|
itemMap.set(item.id, {
|
||||||
|
id: item.id,
|
||||||
|
resourceUrl: item.resourceUrl,
|
||||||
|
type: item.type,
|
||||||
|
fileName: item.fileName,
|
||||||
|
defaultSort: item.defaultSort,
|
||||||
|
children: []
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构建树形结构
|
||||||
|
data.forEach((item) => {
|
||||||
|
const treeNode = itemMap.get(item.id)!
|
||||||
|
|
||||||
|
if (item.parentId) {
|
||||||
|
const parentNode = itemMap.get(item.parentId)
|
||||||
|
if (parentNode) {
|
||||||
|
parentNode.children!.push(treeNode)
|
||||||
|
} else {
|
||||||
|
// 如果找不到父节点,作为根节点处理
|
||||||
|
result.push(treeNode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 没有父节点,作为根节点
|
||||||
|
result.push(treeNode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 递归排序函数
|
||||||
|
function sortChildren(node: Tree) {
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
// 重新排列 children
|
||||||
|
node.children = node.children.sort((a, b) => a.defaultSort - b.defaultSort)
|
||||||
|
|
||||||
|
// 递归处理子节点
|
||||||
|
node.children.forEach((child) => sortChildren(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新排列根节点
|
||||||
|
const sortedResult = result.sort((a, b) => a.defaultSort - b.defaultSort)
|
||||||
|
|
||||||
|
// 递归排序所有子节点
|
||||||
|
sortedResult.forEach((node) => sortChildren(node))
|
||||||
|
|
||||||
|
return sortedResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
export const transformedDataSource = ref(transformToTreeData(originData))
|
||||||
39
src/views/resource/list copy/use-drag.ts
Normal file
39
src/views/resource/list copy/use-drag.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
|
||||||
|
import type { NodeDropType, RenderContentContext } from 'element-plus'
|
||||||
|
|
||||||
|
type Node = RenderContentContext['node']
|
||||||
|
|
||||||
|
// 开始拖拽
|
||||||
|
export const handleDragStart = (node: Node, ev: DragEvents) => {
|
||||||
|
console.log('drag start', node)
|
||||||
|
}
|
||||||
|
// 拖拽进入其他节点时触发的事件
|
||||||
|
export const handleDragEnter = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
|
||||||
|
console.log('tree drag enter:', dropNode.label)
|
||||||
|
}
|
||||||
|
// 拖拽离开某个节点时触发的事件
|
||||||
|
export const handleDragLeave = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
|
||||||
|
console.log('tree drag leave:', dropNode.label)
|
||||||
|
}
|
||||||
|
// 在拖拽节点时触发的事件(类似浏览器的 mouseover 事件)
|
||||||
|
export const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
|
||||||
|
console.log('tree drag over:', dropNode.label)
|
||||||
|
}
|
||||||
|
// 拖拽结束时(可能未成功)触发的事件
|
||||||
|
export const handleDragEnd = (
|
||||||
|
draggingNode: Node,
|
||||||
|
dropNode: Node,
|
||||||
|
dropType: NodeDropType,
|
||||||
|
ev: DragEvents
|
||||||
|
) => {
|
||||||
|
console.log('tree drag end:', dropNode && dropNode.label, dropType)
|
||||||
|
}
|
||||||
|
// 拖拽成功完成时触发的事件
|
||||||
|
export const handleDrop = (
|
||||||
|
draggingNode: Node,
|
||||||
|
dropNode: Node,
|
||||||
|
dropType: NodeDropType,
|
||||||
|
ev: DragEvents
|
||||||
|
) => {
|
||||||
|
console.log('tree drop:', dropNode.label, dropType)
|
||||||
|
}
|
||||||
33
src/views/resource/list/config.ts
Normal file
33
src/views/resource/list/config.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { handleData } from 'lz-utils-lib'
|
||||||
|
const configData = ref()
|
||||||
|
export const initConfig = () => {
|
||||||
|
configData.value = pageConfig({
|
||||||
|
search: {
|
||||||
|
fileName: { label: '文件名称', clearable: true }
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
selection: { width: 50 },
|
||||||
|
fileName: { label: '文件名称', slot: 'fileName', width: 500 },
|
||||||
|
pathname: {
|
||||||
|
label: '路径',
|
||||||
|
width: 160,
|
||||||
|
formatter: (row: any) => row.locations.map((item: any) => item.fileName).join('/')
|
||||||
|
},
|
||||||
|
modifyTime: {
|
||||||
|
label: '修改时间',
|
||||||
|
width: 160,
|
||||||
|
formatter: (row: any) => handleData.formatTime(row.modifyTime, 'YYYY-MM-DD hh:mm:ss')
|
||||||
|
},
|
||||||
|
btn: {
|
||||||
|
types: ['warning', 'danger', ''],
|
||||||
|
names: ['重命名', '删除', '跳转'],
|
||||||
|
width: 150
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
parentId: { label: '父级文件夹', slot: 'parentId' },
|
||||||
|
files: { label: '上传文件', slot: 'files' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return configData
|
||||||
|
}
|
||||||
@ -1,128 +1,328 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="category-tree" class="p-2 bg-white">
|
<div>
|
||||||
<p>类目展示:</p>
|
<search-module :search="search" :table="table">
|
||||||
<el-tree
|
<template #btn>
|
||||||
style="max-width: 600px"
|
<el-button @click="onAddFolder" type="success">新增文件夹</el-button>
|
||||||
:data="dataSource"
|
<el-button @click="onAddFiles" type="success">添加文件</el-button>
|
||||||
node-key="id"
|
<el-button @click="onMove" type="warning">移动</el-button>
|
||||||
draggable
|
|
||||||
default-expand-all
|
|
||||||
:expand-on-click-node="false"
|
|
||||||
@node-drag-start="handleDragStart"
|
|
||||||
@node-drag-enter="handleDragEnter"
|
|
||||||
@node-drag-leave="handleDragLeave"
|
|
||||||
@node-drag-over="handleDragOver"
|
|
||||||
@node-drag-end="handleDragEnd"
|
|
||||||
@node-drop="handleDrop"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<div class="category-tree-node">
|
|
||||||
<span v-if="curId !== data.id">{{ data.label }}</span>
|
|
||||||
<el-input
|
|
||||||
ref="inputRef"
|
|
||||||
v-else
|
|
||||||
v-model="data.label2"
|
|
||||||
size="small"
|
|
||||||
class="w-40"
|
|
||||||
@keyup.enter="handleInputConfirm(data)"
|
|
||||||
@blur="handleInputCancel(node, data)"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<el-button type="primary" link @click="edit(data)" size="small">编辑 </el-button>
|
|
||||||
<el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button>
|
|
||||||
<el-button type="danger" size="small" link @click="remove(node, data)">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</search-module>
|
||||||
|
<div id="table-drag-wrap">
|
||||||
|
<table-module :table="table" @selection-change="onChangeSelection">
|
||||||
|
<template #headerBtn>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<p v-for="(item, i) in parentPaths" :key="item.value">
|
||||||
|
<button
|
||||||
|
:class="[
|
||||||
|
'text-[13px] text-[#09aaff] mx-1',
|
||||||
|
{ '!text-[#666] cursor-default': i === parentPaths.length - 1 }
|
||||||
|
]"
|
||||||
|
@click="onGoParentFile(item.value)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</button>
|
||||||
|
<span :class="['text-xs text-[#666]', { hidden: i === parentPaths.length - 1 }]"
|
||||||
|
>></span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #fileName="scope">
|
||||||
|
<div>
|
||||||
|
<div v-if="curRenameId !== scope.row.id" class="flex items-center">
|
||||||
|
<p>
|
||||||
|
<el-icon class="mt-1" v-if="scope.row.type === 'file'"><Files /></el-icon>
|
||||||
|
<img
|
||||||
|
class="w-4 h-4"
|
||||||
|
v-else-if="scope.row.type === 'image'"
|
||||||
|
:src="scope.row.resourceUrl"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
class="w-4 h-4"
|
||||||
|
v-else-if="scope.row.type === 'video'"
|
||||||
|
:src="scope.row.resourceUrl"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<span class="ml-2 cursor-pointer" @click="onGoFolder(scope.row)">{{
|
||||||
|
scope.row.fileName
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<el-input
|
||||||
|
ref="inputRef"
|
||||||
|
v-else
|
||||||
|
v-model="renameInputVal"
|
||||||
|
size="small"
|
||||||
|
class="w-40"
|
||||||
|
@keyup.enter="handleInputConfirm(scope.row)"
|
||||||
|
@blur="handleInputCancel(scope.row)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</table-module>
|
||||||
|
</div>
|
||||||
|
<dialog-module :dialog="$dialog">
|
||||||
|
<template #parentId>
|
||||||
|
<el-tree-select
|
||||||
|
show-checkbox
|
||||||
|
v-model="$dialog.data.parentId"
|
||||||
|
:data="treeData"
|
||||||
|
:render-after-expand="false"
|
||||||
|
check-strictly
|
||||||
|
:load="handleLoadNode"
|
||||||
|
lazy
|
||||||
|
style="width: 240px"
|
||||||
|
>
|
||||||
|
</el-tree-select>
|
||||||
|
</template>
|
||||||
|
<template #files>
|
||||||
|
<el-upload
|
||||||
|
multiple
|
||||||
|
:auto-upload="false"
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
list-type="picture-card"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
</dialog-module>
|
||||||
|
<el-dialog v-model="showReviewImgDialog">
|
||||||
|
<img w-full :src="reviewImageUrl" alt="Preview Image" />
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ElButton } from 'element-plus'
|
import { useDraggable } from 'vue-draggable-plus'
|
||||||
import type { RenderContentContext } from 'element-plus'
|
import { initConfig } from './config'
|
||||||
import { dataSource } from './mock'
|
import { ElMessage } from 'element-plus'
|
||||||
import {
|
import type { UploadProps } from 'element-plus'
|
||||||
handleDragStart,
|
import { Plus, Files } from '@element-plus/icons-vue'
|
||||||
handleDragEnter,
|
|
||||||
handleDragOver,
|
|
||||||
handleDragLeave,
|
|
||||||
handleDragEnd,
|
|
||||||
handleDrop
|
|
||||||
} from './use-drag'
|
|
||||||
|
|
||||||
interface Tree {
|
const dialogType = ref('')
|
||||||
id: number
|
|
||||||
label: string
|
// 增加文件
|
||||||
children?: Tree[]
|
const treeData = ref<any[]>([])
|
||||||
|
const onAddFiles = async () => {
|
||||||
|
const dialog = $dialog.value
|
||||||
|
dialog.title = '新增'
|
||||||
|
dialog.show = true
|
||||||
|
$dialog.value.config.files.show = true
|
||||||
|
dialogType.value = 'add'
|
||||||
|
dialog.data = {}
|
||||||
}
|
}
|
||||||
type Node = RenderContentContext['node']
|
|
||||||
type Data = RenderContentContext['data']
|
|
||||||
|
|
||||||
const curId = ref(NaN)
|
// 加载子文件夹
|
||||||
const inputRef = ref()
|
const handleLoadNode = (node, resolve) => {
|
||||||
|
api.resource.getResourceList.post!<any>({ parentId: node.data.value || 0 }).then((res) => {
|
||||||
const edit = (data: Data) => {
|
resolve(
|
||||||
data.label2 = data.label
|
res.data.rows
|
||||||
curId.value = data.id
|
.filter((item) => item.type === 'file')
|
||||||
nextTick(() => {
|
.map((item) => ({ label: item.fileName, value: item.id }))
|
||||||
inputRef.value.focus()
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const addFileType = ref('')
|
||||||
|
// 添加文件夹
|
||||||
|
const onAddFolder = () => {
|
||||||
|
curRenameId.value = Infinity
|
||||||
|
renameInputVal.value = ''
|
||||||
|
addFileType.value = 'folder'
|
||||||
|
table.value.$data.push({
|
||||||
|
id: Infinity,
|
||||||
|
parentId: search.value.$data.parentId,
|
||||||
|
defaultSort: 0,
|
||||||
|
type: 'file',
|
||||||
|
fileName: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const onDelete = (row: any) => {
|
||||||
|
handleMessageBox({
|
||||||
|
msg: `是否确认删除吗?`,
|
||||||
|
success: api.resource.deleteResource.post!,
|
||||||
|
data: { resourceIds: [row.id] }
|
||||||
|
}).then(() => {
|
||||||
|
table.value.$onGetData(table.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转
|
||||||
|
const onJump = (row: any) => {
|
||||||
|
search.value.$data.parentId = row.locations[row.locations.length - 1].id
|
||||||
|
table.value.$onGetData(table.value, 1, search)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动
|
||||||
|
const onMove = () => {
|
||||||
|
if (!selectFiles.value.length) {
|
||||||
|
return ElMessage.error('请先选择文件')
|
||||||
|
}
|
||||||
|
dialogType.value = 'move'
|
||||||
|
$dialog.value.config.files.show = false
|
||||||
|
$dialog.value.data = {}
|
||||||
|
$dialog.value.show = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentPaths = ref([{ label: '全部文件', value: 0 }])
|
||||||
|
|
||||||
|
// 去上一页
|
||||||
|
const onGoParentFile = (id: number) => {
|
||||||
|
parentPaths.value = parentPaths.value.slice(
|
||||||
|
0,
|
||||||
|
parentPaths.value.findIndex((item) => item.value === id) + 1
|
||||||
|
)
|
||||||
|
search.value.$data.parentId = id
|
||||||
|
table.value.$onGetData(table.value, 1, search)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重命名
|
||||||
|
const curRenameId = ref(NaN)
|
||||||
|
const renameInputVal = ref('')
|
||||||
|
const onRename = (row: any) => {
|
||||||
|
renameInputVal.value = row.fileName
|
||||||
|
curRenameId.value = row.id
|
||||||
|
addFileType.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
// 回车确认
|
// 回车确认
|
||||||
const handleInputConfirm = (data: any) => {
|
const handleInputConfirm = async (row: any) => {
|
||||||
if (curId.value === Infinity) {
|
if (addFileType.value === 'folder') {
|
||||||
// 新增接口
|
delete row.id
|
||||||
} else {
|
|
||||||
// 修改接口
|
|
||||||
}
|
}
|
||||||
data.label = data.label2
|
await api.resource.addOrEditResource.post!([{ ...row, fileName: renameInputVal.value }])
|
||||||
data.label2 = ''
|
ElMessage.success('操作成功')
|
||||||
curId.value = NaN
|
row.fileName = renameInputVal.value
|
||||||
|
curRenameId.value = NaN
|
||||||
}
|
}
|
||||||
|
|
||||||
// 失焦
|
// 失焦
|
||||||
const handleInputCancel = (node: Node, data: Data) => {
|
const handleInputCancel = (row: any) => {
|
||||||
if (data.id === Infinity) {
|
curRenameId.value = row.fileName
|
||||||
remove(node, data)
|
addFileType.value = ''
|
||||||
}
|
|
||||||
curId.value = NaN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const append = (data: Data) => {
|
// 跳子文件夹
|
||||||
curId.value = Infinity
|
const onGoFolder = (row: any) => {
|
||||||
const newChild = { id: curId.value, label2: 'test', children: [] }
|
search.value.$data.parentId = row.id
|
||||||
if (!data.children) {
|
parentPaths.value.push({ label: row.fileName, value: row.id })
|
||||||
data.children = []
|
table.value.$onGetData(table.value, 1, search)
|
||||||
}
|
|
||||||
data.children.push(newChild)
|
|
||||||
dataSource.value = [...dataSource.value]
|
|
||||||
nextTick(() => {
|
|
||||||
inputRef.value.focus()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const remove = (node: Node, data: Data) => {
|
const selectFiles = ref([])
|
||||||
const parent = node.parent
|
// 勾选文件
|
||||||
const children: Tree[] = parent?.data.children || parent?.data
|
const onChangeSelection = (data: any) => {
|
||||||
const index = children.findIndex((d) => d.id === data.id)
|
selectFiles.value = data
|
||||||
children.splice(index, 1)
|
|
||||||
dataSource.value = [...dataSource.value]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fileList = ref([])
|
||||||
|
const showReviewImgDialog = ref(false)
|
||||||
|
const reviewImageUrl = ref('')
|
||||||
|
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||||
|
console.log(uploadFile, uploadFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||||
|
reviewImageUrl.value = uploadFile.url!
|
||||||
|
showReviewImgDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽完成处理
|
||||||
|
const handleDragEnd = async (evt: any) => {
|
||||||
|
const { oldIndex, newIndex } = evt
|
||||||
|
// 检查是否真的发生了位置变化
|
||||||
|
if (oldIndex === newIndex) {
|
||||||
|
console.log('位置没有变化,无需更新')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await api.resource.sortResource.post!({ resourceIds: table.value.$data.map((item) => item.id) })
|
||||||
|
ElMessage.success('排序更新成功')
|
||||||
|
// 可选:刷新数据
|
||||||
|
// table.value.$onGetData(table.value, 1, search)
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('排序更新失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化页面 */
|
||||||
|
const ConfigData = initConfig()
|
||||||
|
const { search, table, $dialog } = handleInit(ConfigData, api.resource.getResourceList.post, [
|
||||||
|
onRename,
|
||||||
|
onDelete,
|
||||||
|
onJump
|
||||||
|
])
|
||||||
|
search.value.$default = { parentId: 0 }
|
||||||
|
table.value.$onGetData(table.value, 1, search)
|
||||||
|
$dialog.value['item-width'] = '100%'
|
||||||
|
$dialog.value.submit = async () => {
|
||||||
|
if (dialogType.value === 'add') {
|
||||||
|
const form = new FormData()
|
||||||
|
// 关键:一次性把所有文件塞到同一个键 'files'
|
||||||
|
fileList.value.forEach((f) => {
|
||||||
|
form.append('files', f.raw as File)
|
||||||
|
})
|
||||||
|
const res = await api.resource.uploadFile.post!<any>(form)
|
||||||
|
const params = res.data.map((item) => ({
|
||||||
|
fileName: item.srcFileName,
|
||||||
|
resourceUrl: item.url,
|
||||||
|
defaultSort: 0,
|
||||||
|
parentId: $dialog.value.data.parentId,
|
||||||
|
type: 'image'
|
||||||
|
}))
|
||||||
|
await api.resource.addOrEditResource.post!(params)
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
$dialog.value.show = false
|
||||||
|
} else {
|
||||||
|
const params = selectFiles.value.map((item: any) => ({
|
||||||
|
...item,
|
||||||
|
parentId: $dialog.value.data.parentId
|
||||||
|
}))
|
||||||
|
await api.resource.addOrEditResource.post!(params)
|
||||||
|
ElMessage.success('操作成功')
|
||||||
|
$dialog.value.show = false
|
||||||
|
table.value.$onGetData(table.value, 1, search)
|
||||||
|
selectFiles.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// table.value.$data = originData
|
||||||
|
|
||||||
|
// 拖拽实例
|
||||||
|
let draggableInstance: any = null
|
||||||
|
|
||||||
|
// 初始化拖拽功能
|
||||||
|
const initDraggable = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const tbody = document.querySelector('#table-drag-wrap .el-table__body tbody')
|
||||||
|
if (tbody && table.value.$data.length > 0) {
|
||||||
|
// 如果已有实例,先销毁
|
||||||
|
if (draggableInstance) {
|
||||||
|
draggableInstance.destroy?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的拖拽实例
|
||||||
|
draggableInstance = useDraggable(tbody, table.value.$data, {
|
||||||
|
onEnd: (evt) => {
|
||||||
|
handleDragEnd(evt)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听表格数据变化,自动重新初始化拖拽
|
||||||
|
watch(
|
||||||
|
() => table.value.$data,
|
||||||
|
(val) => {
|
||||||
|
initDraggable()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 页面缓存 */
|
||||||
|
defineOptions({ name: 'ResourceList' })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
#category-tree {
|
|
||||||
.category-tree-node {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 14px;
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,56 +1,91 @@
|
|||||||
interface Tree {
|
interface OriginDataItem {
|
||||||
id: number
|
id: number
|
||||||
label: string
|
resourceUrl: string
|
||||||
children?: Tree[]
|
fileName: string
|
||||||
|
type: string
|
||||||
|
defaultSort: number
|
||||||
|
parentId?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dataSource = ref<Tree[]>([
|
export const originData: OriginDataItem[] = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 12,
|
||||||
label: 'Level one 1',
|
resourceUrl: 'bbb',
|
||||||
children: [
|
type: 'image',
|
||||||
{
|
fileName: '张三',
|
||||||
id: 4,
|
parentId: 10,
|
||||||
label: 'Level two 1-1',
|
defaultSort: 2
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
label: 'Level three 1-1-1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
label: 'Level three 1-1-2'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 78,
|
||||||
label: 'Level one 2',
|
resourceUrl: 'bbb',
|
||||||
children: [
|
type: 'image',
|
||||||
{
|
fileName: '张三',
|
||||||
id: 5,
|
parentId: 77,
|
||||||
label: 'Level two 2-1'
|
defaultSort: 1
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
label: 'Level two 2-2'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 80,
|
||||||
label: 'Level one 3',
|
resourceUrl: 'bbb',
|
||||||
children: [
|
type: 'image',
|
||||||
{
|
fileName: '张三',
|
||||||
id: 7,
|
parentId: 78,
|
||||||
label: 'Level two 3-1'
|
defaultSort: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 82,
|
||||||
label: 'Level two 3-2'
|
resourceUrl: 'bbb',
|
||||||
}
|
type: 'image',
|
||||||
]
|
fileName: '张三',
|
||||||
|
parentId: 81,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 84,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 83,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 86,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 85,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 88,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 87,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 90,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 89,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 92,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 91,
|
||||||
|
defaultSort: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 94,
|
||||||
|
resourceUrl: 'bbb',
|
||||||
|
type: 'image',
|
||||||
|
fileName: '张三',
|
||||||
|
parentId: 93,
|
||||||
|
defaultSort: 1
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user