初始化admin pc端

This commit is contained in:
Mrtangl 2022-04-08 14:46:31 +08:00
parent 19665b64fb
commit 41ed86604f
6 changed files with 147 additions and 110 deletions

View File

@ -81,6 +81,7 @@ const tiny = reactive({
], //false ], //false
paste_data_images: true, // paste_data_images: true, //
file_picker_types: "file image media", file_picker_types: "file image media",
convert_urls : false, // false-
// //
file_picker_callback: (callback: any, value: any, meta: any) => { file_picker_callback: (callback: any, value: any, meta: any) => {
if (meta.filetype == "image") { if (meta.filetype == "image") {

View File

@ -1,40 +1,54 @@
<template> <template>
<div> <div>
<del-wrap @close="$emit('close')"> <del-wrap @close="$emit('close')">
<div class="file-item" :style="{ height: fileSize, width: fileSize }"> <div
<el-image v-if="type == 'image'" class="image" fit="contain" :src="uri"></el-image> class="file-item"
<video v-else-if="type == 'video'" class="video" :src="uri"></video> :style="{ height: fileSize, width: fileSize }"
>
<el-image
class="image"
v-if="type.type == 'image'"
fit="contain"
:src="uri"
></el-image>
<video
class="video"
v-else-if="type.type == 'video'"
:src="uri"
></video>
<slot></slot> <slot></slot>
</div> </div>
</del-wrap> </del-wrap>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import DelWrap from '@/components/del-wrap/index.vue' import DelWrap from '@/components/del-wrap/index.vue'
import { defineComponent, inject } from 'vue' import { defineComponent, inject } from 'vue'
export default defineComponent({ export default defineComponent({
components: { components: {
DelWrap DelWrap,
}, },
props: { props: {
// //
uri: { uri: {
type: String type: String,
}, },
// //
fileSize: { fileSize: {
type: String, type: String,
default: '100px' default: '100px',
} },
}, },
emits: ['close'], emits: ['close'],
setup() { setup() {
const type = inject('type') const type = inject<any>('type')
return { return {
type type
} }
} },
}) })
</script> </script>

View File

@ -5,24 +5,26 @@ import {
apiFileCateLists, apiFileCateLists,
apiFileDelete, apiFileDelete,
apiFileList, apiFileList,
apiFileMove apiFileMove,
} from '@/api/app' } from "@/api/app"
import { usePages } from '@/core/hooks/pages' import { usePages } from "@/core/hooks/pages"
import { ElMessage } from 'element-plus' import { ElMessage } from "element-plus"
import { computed, inject, reactive, ref, Ref } from 'vue' import { computed, inject, reactive, ref, Ref } from "vue"
// 左侧分组的钩子函数 // 左侧分组的钩子函数
export function useCate(typeValue: Ref<any>) { export function useCate(typeValue: Ref<any>) {
// 分组列表 // 分组列表
const cateLists: Ref<any[]> = ref([]) const cateLists: Ref<any[]> = ref([])
// 选中的分组id // 选中的分组id
const cateId = ref('') const cateId = ref("")
// 添加分组 // 添加分组
const handleAddCate = (val: string) => { const handleAddCate = (val: string) => {
apiFileCateAdd({ apiFileCateAdd({
type: typeValue.value, type: typeValue.value,
pid: 0, pid: 0,
name: val name: val,
}).then(() => { }).then(() => {
getCateLists() getCateLists()
}) })
@ -31,7 +33,7 @@ export function useCate(typeValue: Ref<any>) {
const handleEditCate = (val: string, id: number) => { const handleEditCate = (val: string, id: number) => {
apiFileCateEdit({ apiFileCateEdit({
id, id,
name: val name: val,
}).then(() => { }).then(() => {
getCateLists() getCateLists()
}) })
@ -39,7 +41,7 @@ export function useCate(typeValue: Ref<any>) {
// 删除分组 // 删除分组
const handleDeleteCate = (id: number) => { const handleDeleteCate = (id: number) => {
apiFileCateDelete({ apiFileCateDelete({
id id,
}).then(() => { }).then(() => {
getCateLists() getCateLists()
}) })
@ -49,17 +51,17 @@ export function useCate(typeValue: Ref<any>) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
apiFileCateLists({ apiFileCateLists({
type: typeValue.value, type: typeValue.value,
page_type: 1 page_type: 1,
}).then((res: any) => { }).then((res: any) => {
const item: any[] = [ const item: any[] = [
{ {
name: '全部', name: "全部",
id: '' id: "",
}, },
{ {
name: '未分组', name: "未分组",
id: 0 id: 0,
} },
] ]
cateLists.value = res?.lists cateLists.value = res?.lists
cateLists.value.unshift(...item) cateLists.value.unshift(...item)
@ -73,24 +75,26 @@ export function useCate(typeValue: Ref<any>) {
handleAddCate, handleAddCate,
handleEditCate, handleEditCate,
handleDeleteCate, handleDeleteCate,
getCateLists getCateLists,
} }
} }
// 处理文件的钩子函数 // 处理文件的钩子函数
export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>) { export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>) {
const moveId = ref(0) const moveId = ref(0)
const select: Ref<any[]> = ref([]) const select: Ref<any[]> = ref([])
const fileParams = reactive({ const fileParams = reactive({
name: '', name: "",
type: type, type: type,
cid: cateId cid: cateId,
}) })
const { pager, requestApi, resetPage } = usePages({ const { pager, requestApi, resetPage } = usePages({
callback: apiFileList, callback: apiFileList,
params: fileParams params: fileParams
}) })
const selectStatus = computed( const selectStatus = computed(
() => (id: number) => select.value.find((item: any) => item.id == id) () => (id: number) => select.value.find((item: any) => item.id == id)
) )
@ -102,20 +106,20 @@ export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>)
resetPage() resetPage()
} }
const batchFileDelete = (id?: number[]) => { const batchFileDelete = (id?: number[]) => {
const ids = id ? id : select.value.map((item: any) => item.id) let ids = id ? id : select.value.map((item: any) => item.id)
apiFileDelete({ apiFileDelete({
ids ids,
}).then(res => { }).then((res) => {
getFileList() getFileList()
clearSelect() clearSelect()
}) })
} }
const batchFileMove = () => { const batchFileMove = () => {
const ids = select.value.map((item: any) => item.id) let ids = select.value.map((item: any) => item.id)
apiFileMove({ apiFileMove({
ids, ids,
cid: moveId.value cid: moveId.value,
}).then(res => { }).then((res) => {
moveId.value = 0 moveId.value = 0
getFileList() getFileList()
clearSelect() clearSelect()
@ -123,7 +127,7 @@ export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>)
} }
const selectFile = (item: any) => { const selectFile = (item: any) => {
const index = select.value.findIndex((items: any) => items.id == item.id) let index = select.value.findIndex((items: any) => items.id == item.id)
if (index != -1) { if (index != -1) {
select.value.splice(index, 1) select.value.splice(index, 1)
return return
@ -134,7 +138,7 @@ export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>)
select.value.push(item) select.value.push(item)
return return
} }
ElMessage.warning('已达到选择上限') ElMessage.warning("已达到选择上限")
return return
} }
select.value.push(item) select.value.push(item)
@ -143,7 +147,7 @@ export function useFile(cateId: Ref<string>, type: Ref<any>, limit: Ref<number>)
select.value = [] select.value = []
} }
const cancelSelete = (id: number) => { const cancelSelete = (id: number) => {
select.value = select.value.filter(item => item.id != id) select.value = select.value.filter((item) => item.id != id)
} }
return { return {
moveId, moveId,

View File

@ -1,3 +1,4 @@
<template> <template>
<div class="material-select"> <div class="material-select">
<popup <popup
@ -7,41 +8,42 @@
:title="`选择${tipsText}`" :title="`选择${tipsText}`"
@confirm="handleConfirm" @confirm="handleConfirm"
> >
<template #trigger> <template v-if="!hiddenUpload" #trigger>
<div class="material-select__trigger clearfix" @click.stop> <div class="material-select__trigger clearfix" @click.stop>
<draggable v-model="fileList" class="draggable" animation="300" item-key="id"> <draggable
<template #item="{ element, index }"> class="draggable"
v-model="fileList"
animation="300"
item-key="id"
>
<template v-slot:item="{ element, index }">
<div <div
class="material-preview" class="material-preview"
:class="{ :class="{
'is-disabled': disabled, 'is-disabled': disabled,
'is-one': limit == 1 'is-one': limit == 1,
}" }"
@click="showPopup(index)" @click="showPopup(index)"
> >
<file-item <file-item :uri="element" :file-size="size" @close="deleteImg(index)" />
:uri="element"
:file-size="size"
@close="deleteImg(index)"
/>
</div> </div>
</template> </template>
</draggable> </draggable>
<div <div
v-show="showUpload"
class="material-upload" class="material-upload"
@click="showPopup(-1)"
v-show="showUpload"
:class="{ :class="{
'is-disabled': disabled, 'is-disabled': disabled,
'is-one': limit == 1 'is-one': limit == 1,
}" }"
@click="showPopup(-1)"
> >
<slot name="upload"> <slot name="upload">
<div <div
class="upload-btn flex flex-col flex-center" class="upload-btn flex flex-col flex-center"
:style="{ :style="{
width: size, width: size,
height: size height: size,
}" }"
> >
<el-icon :size="25"><plus /></el-icon> <el-icon :size="25"><plus /></el-icon>
@ -63,6 +65,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
provide, provide,
@ -74,7 +77,7 @@ import {
toRef, toRef,
toRefs, toRefs,
watch, watch,
nextTick nextTick,
} from 'vue' } from 'vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import Popup from '@/components/popup/index.vue' import Popup from '@/components/popup/index.vue'
@ -85,37 +88,42 @@ export default defineComponent({
Popup, Popup,
Draggable, Draggable,
FileItem, FileItem,
Material Material,
}, },
props: { props: {
modelValue: { modelValue: {
type: [String, Array], type: [String, Array],
default: () => [] default: () => [],
}, },
// //
type: { type: {
type: String, type: String,
default: 'image' default: 'image',
}, },
// //
size: { size: {
type: String, type: String,
default: '100px' default: '100px',
}, },
// //
fileSize: { fileSize: {
type: String, type: String,
default: '100px' default: '100px',
}, },
// //
limit: { limit: {
type: Number, // type: Number,
default: 1 default: 1,
}, },
// //
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false default: false,
},
// *(使)
hiddenUpload: {
type: Boolean,
default: false,
} }
}, },
@ -149,28 +157,24 @@ export default defineComponent({
const showUpload = computed(() => { const showUpload = computed(() => {
return props.limit - fileList.value.length > 0 return props.limit - fileList.value.length > 0
}) })
const meterialLimit = computed(() => { const meterialLimit: any = computed(() => {
if (!isAdd.value) { if (!isAdd.value) {
return 1 return 1
} }
if (!limit.value) { if (!limit.value) return null
return null
}
return limit.value - fileList.value.length return limit.value - fileList.value.length
}) })
const handleConfirm = () => { const handleConfirm = () => {
const selectUri = select.value.map(item => item.uri) const selectUri = select.value.map((item) => item.uri)
if (!isAdd.value) { if (!isAdd.value) {
fileList.value.splice(currentIndex.value, 1, selectUri.shift()) fileList.value.splice(currentIndex.value, 1, selectUri.shift())
} else { } else {
fileList.value = [...fileList.value, ...selectUri] fileList.value = [...fileList.value,...selectUri]
} }
handleChange() handleChange()
} }
const showPopup = (index: number) => { const showPopup = (index: number) => {
if (disabled.value) { if (disabled.value) return
return
}
if (index >= 0) { if (index >= 0) {
isAdd.value = false isAdd.value = false
currentIndex.value = index currentIndex.value = index
@ -184,7 +188,8 @@ export default defineComponent({
select.value = val select.value = val
} }
const handleChange = () => { const handleChange = () => {
const valueImg = limit.value != 1 ? fileList.value : fileList.value[0] || '' const valueImg =
limit.value != 1 ? fileList.value : fileList.value[0] || ''
emit('update:modelValue', valueImg) emit('update:modelValue', valueImg)
emit('change', valueImg) emit('change', valueImg)
nextTick(() => { nextTick(() => {
@ -198,13 +203,13 @@ export default defineComponent({
} }
watch(modelValue, (val: any[] | string) => { watch(modelValue, (val: any[] | string) => {
console.log(val)
fileList.value = Array.isArray(val) ? val : val == '' ? [] : [val] fileList.value = Array.isArray(val) ? val : val == '' ? [] : [val]
}) })
provide('type', props.type) provide('type', props)
provide('fileSize', props.fileSize) provide('fileSize', props.fileSize)
provide('limit', props.limit) provide('limit', props.limit)
provide('typeValue', typeValue) provide('typeValue', typeValue)
provide('hiddenUpload', props.hiddenUpload)
return { return {
popupRef, popupRef,
materialRefs, materialRefs,
@ -217,7 +222,7 @@ export default defineComponent({
selectChange, selectChange,
deleteImg deleteImg
} }
} },
}) })
</script> </script>

View File

@ -1,5 +1,6 @@
<template> <template>
<div v-loading="pager.loading" class="material flex col-stretch"> <div class="material flex col-stretch" v-loading="pager.loading">
<div class="material__left"> <div class="material__left">
<el-scrollbar class="ls-scrollbar" style="height: calc(100% - 40px)"> <el-scrollbar class="ls-scrollbar" style="height: calc(100% - 40px)">
<div class="material-left__content p-t-16 p-b-16"> <div class="material-left__content p-t-16 p-b-16">
@ -14,16 +15,17 @@
:current-node-key="cateId" :current-node-key="cateId"
@node-click="currentChange" @node-click="currentChange"
> >
<template #default="{ data }"> <template v-slot="{ data }">
<div class="flex flex-1 flex-center" style="min-width: 0"> <div class="flex flex-1 flex-center" style="min-width: 0">
<img <img
style="width: 20px; height: 16px" style="width: 20px; height: 16px"
src="@/assets/images/icon_folder.png" src="@/assets/images/icon_folder.png"
alt
class="m-r-10" class="m-r-10"
/> />
<span class="flex-1 line-1 m-r-10"> <span class="flex-1 line-1 m-r-10">
{{ data.name }} {{
data.name
}}
</span> </span>
<el-dropdown v-if="data.id > 0" :hide-on-click="false"> <el-dropdown v-if="data.id > 0" :hide-on-click="false">
<span class="muted m-r-10">···</span> <span class="muted m-r-10">···</span>
@ -33,12 +35,21 @@
<popover-input <popover-input
type="text" type="text"
tips="分类名称" tips="分类名称"
@confirm="handleEditCate($event, data.id)" @confirm="
handleEditCate(
$event,
data.id
)
"
> >
<el-dropdown-item>命名分组</el-dropdown-item> <el-dropdown-item>命名分组</el-dropdown-item>
</popover-input> </popover-input>
</div> </div>
<div @click="handleDeleteCate(data.id)"> <div
@click="
handleDeleteCate(data.id)
"
>
<el-dropdown-item>删除分组</el-dropdown-item> <el-dropdown-item>删除分组</el-dropdown-item>
</div> </div>
</el-dropdown-menu> </el-dropdown-menu>
@ -61,7 +72,7 @@
<upload <upload
class="m-r-10" class="m-r-10"
:data="{ cid: cateId }" :data="{ cid: cateId }"
:type="type" :type="type.type"
:show-progress="true" :show-progress="true"
@change="refresh" @change="refresh"
> >
@ -79,9 +90,9 @@
</popup> </popup>
<popup <popup
class="m-r-10 inline" class="m-r-10 inline"
@confirm="batchFileMove"
:disabled="!select.length" :disabled="!select.length"
title="移动文件" title="移动文件"
@confirm="batchFileMove"
> >
<template #trigger> <template #trigger>
<el-button size="small" :disabled="!select.length">移动</el-button> <el-button size="small" :disabled="!select.length">移动</el-button>
@ -102,10 +113,10 @@
</popup> </popup>
</div> </div>
<el-input <el-input
v-model="fileParams.name"
size="small" size="small"
placeholder="请输入名字" placeholder="请输入名字"
style="width: 280px" style="width: 280px"
v-model="fileParams.name"
@keyup.enter="refresh" @keyup.enter="refresh"
> >
<template #append> <template #append>
@ -116,9 +127,9 @@
<div class="material-center__content flex flex-col flex-1"> <div class="material-center__content flex flex-col flex-1">
<ul class="file-list flex flex-wrap m-t-14"> <ul class="file-list flex flex-wrap m-t-14">
<li <li
class="file-item-wrap"
v-for="item in pager.lists" v-for="item in pager.lists"
:key="item.id" :key="item.id"
class="file-item-wrap"
:style="{ width: fileSize }" :style="{ width: fileSize }"
@click="selectFile(item)" @click="selectFile(item)"
> >
@ -127,7 +138,7 @@
:file-size="fileSize" :file-size="fileSize"
@close="batchFileDelete([item.id])" @close="batchFileDelete([item.id])"
> >
<div v-if="selectStatus(item.id)" class="item-selected"> <div class="item-selected" v-if="selectStatus(item.id)">
<el-icon color="#fff" size="24"> <el-icon color="#fff" size="24">
<check /> <check />
</el-icon> </el-icon>
@ -138,17 +149,15 @@
</li> </li>
</ul> </ul>
<div <div
v-if="!pager.loading && !pager.lists.length"
class="flex flex-1 row-center col-center" class="flex flex-1 row-center col-center"
> v-if="!pager.loading && !pager.lists.length"
暂无数据~ >暂无数据~</div>
</div>
</div> </div>
<div class="material-center__footer flex row-right"> <div class="material-center__footer flex row-right">
<pagination <pagination
v-model="pager" v-model="pager"
layout="total, prev, pager, next, jumper"
@change="getFileList" @change="getFileList"
layout="total, prev, pager, next, jumper"
/> />
</div> </div>
</div> </div>
@ -163,13 +172,9 @@
<el-scrollbar class="ls-scrollbar" style="height: calc(100% - 32px)"> <el-scrollbar class="ls-scrollbar" style="height: calc(100% - 32px)">
<ul class="select-lists flex-col p-t-10"> <ul class="select-lists flex-col p-t-10">
<li v-for="item in select" :key="item.id" class="m-b-16"> <li class="m-b-16" v-for="item in select" :key="item.id">
<div class="select-item"> <div class="select-item">
<file-item <file-item :uri="item.uri" file-size="100px" @close="cancelSelete(item.id)"></file-item>
:uri="item.uri"
file-size="100px"
@close="cancelSelete(item.id)"
></file-item>
</div> </div>
</li> </li>
</ul> </ul>
@ -178,6 +183,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, inject, Ref, ref, toRefs, watch } from 'vue' import { defineComponent, inject, Ref, ref, toRefs, watch } from 'vue'
import { useCate, useFile } from './hook' import { useCate, useFile } from './hook'
@ -194,27 +200,33 @@ export default defineComponent({
Pagination, Pagination,
Popup, Popup,
Upload, Upload,
FileItem FileItem,
}, },
props: { props: {
fileSize: { fileSize: {
type: String, type: String,
default: '100px' default: '100px',
}, },
limit: { limit: {
type: Number, type: Number,
default: 1 default: 1,
} },
}, },
emits: ['change'], emits: ['change'],
setup(props, { emit }) { setup(props, { emit }) {
const treeRefs: Ref<typeof ElTree | null> = ref(null) const treeRefs: Ref<typeof ElTree | null> = ref(null)
const type = inject('type') as Ref<string> const type = inject('type') as Ref<any>
const { limit } = toRefs(props) const { limit } = toRefs(props)
const typeValue = inject('typeValue') as Ref<10 | 20 | 30> const typeValue = inject('typeValue') as Ref<10 | 20 | 30>
const visible = inject('visible') as Ref<boolean> const visible = inject('visible') as Ref<boolean>
const { cateId, cateLists, handleAddCate, handleEditCate, handleDeleteCate, getCateLists } = const {
useCate(typeValue) cateId,
cateLists,
handleAddCate,
handleEditCate,
handleDeleteCate,
getCateLists,
} = useCate(typeValue)
const { const {
moveId, moveId,
pager, pager,
@ -227,7 +239,7 @@ export default defineComponent({
selectFile, selectFile,
selectStatus, selectStatus,
clearSelect, clearSelect,
cancelSelete cancelSelete,
} = useFile(cateId, typeValue, limit) } = useFile(cateId, typeValue, limit)
const currentChange = (item: any) => { const currentChange = (item: any) => {
@ -244,7 +256,7 @@ export default defineComponent({
} }
}, },
{ {
immediate: true immediate: true,
} }
) )
watch(cateId, (val: string) => { watch(cateId, (val: string) => {
@ -282,9 +294,9 @@ export default defineComponent({
selectFile, selectFile,
selectStatus, selectStatus,
clearSelect, clearSelect,
cancelSelete cancelSelete,
} }
} },
}) })
</script> </script>

View File

@ -56,12 +56,13 @@
<div <div
v-for="item in workbenchData.menu" v-for="item in workbenchData.menu"
:key="item" :key="item"
class="nav-item flex flex-col flex-center m-t-10" class="nav-item flex-col m-t-10"
> >
<router-link :to="item.url"> <router-link :to="item.url">
<el-image style="width: 48px; height: 48px" :src="item.image"> <view class="flex flex-center">
</el-image> <el-image style="width: 48px; height: 48px" :src="item?.image"></el-image>
<div class="m-t-8 normal">{{ item.name }}</div> </view>
<div class="m-t-8 normal text-center">{{ item.name }}</div>
</router-link> </router-link>
</div> </div>
</div> </div>
@ -233,10 +234,10 @@ export default defineComponent({
.function { .function {
.nav-lists { .nav-lists {
display: flex; display: flex;
flex-wrap: wrap; // flex-wrap: wrap;
.nav-item { .nav-item {
min-width: 120px; min-width: 210px;
} }
} }
} }