mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
Merge pull request #70 from JeremyYu-cn/feat-upgrade-vue3
Feat: Convert panel/wrap components to composition API
This commit is contained in:
commit
05cde577b2
@ -15,22 +15,31 @@ type IGetTempListParam = {
|
|||||||
search: string
|
search: string
|
||||||
page: number
|
page: number
|
||||||
pageSize: number
|
pageSize: number
|
||||||
cate:number
|
cate: number | string
|
||||||
}
|
}
|
||||||
type IGetTempListData = {
|
export type IGetTempListData = {
|
||||||
cover: string
|
cover: string
|
||||||
height: number
|
height: number
|
||||||
id: number
|
id: number
|
||||||
state: number
|
state: number
|
||||||
title: string
|
title: string
|
||||||
width: number
|
width: number
|
||||||
|
isDelect: boolean
|
||||||
|
fail: boolean
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
data?: string
|
||||||
}
|
}
|
||||||
type IGetTempListResult = TCommResResult<IGetTempListData>
|
type IGetTempListResult = TPageRequestResult<IGetTempListData[]>
|
||||||
|
|
||||||
// 获取模板列表
|
// 获取模板列表
|
||||||
export const getTempList = (params: IGetTempListParam) => fetch<IGetTempListResult>('design/list', params, 'get')
|
export const getTempList = (params: IGetTempListParam) => fetch<IGetTempListResult>('design/list', params, 'get')
|
||||||
|
|
||||||
export const getTempDetail = (params: Type.Object = {}) => fetch('design/temp', params, 'get')
|
type TGetTempDetail = {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTempDetail = (params: TGetTempDetail) => fetch<{data: string}>('design/temp', params, 'get')
|
||||||
|
|
||||||
type TGetCategoriesParams = {
|
type TGetCategoriesParams = {
|
||||||
type?: number
|
type?: number
|
||||||
|
@ -13,9 +13,16 @@ export type TItem2DataParam = {
|
|||||||
height: number
|
height: number
|
||||||
url: string
|
url: string
|
||||||
model?: string
|
model?: string
|
||||||
|
canvasWidth?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function setItem2Data(item: TItem2DataParam) {
|
export type TItem2DataResult = {
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
canvasWidth: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function setItem2Data(item: TItem2DataParam): Promise<Required<TItem2DataParam>> {
|
||||||
const cloneItem = JSON.parse(JSON.stringify(item))
|
const cloneItem = JSON.parse(JSON.stringify(item))
|
||||||
const { width: screenWidth, height: screenHeight } = store.getters.dPage
|
const { width: screenWidth, height: screenHeight } = store.getters.dPage
|
||||||
let { width: imgWidth, height: imgHeight } = item
|
let { width: imgWidth, height: imgHeight } = item
|
||||||
|
24
src/components/modules/panel/types/wrap.d.ts
vendored
Normal file
24
src/components/modules/panel/types/wrap.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
type TCommonImgListData = {
|
||||||
|
isDelect: boolean
|
||||||
|
cover: string
|
||||||
|
fail: boolean
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TCommonPhotoListData = {
|
||||||
|
listWidth: number
|
||||||
|
gap: number
|
||||||
|
thumb?: string
|
||||||
|
url: string
|
||||||
|
color: string
|
||||||
|
isDelect: boolean
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
model: string
|
||||||
|
}
|
@ -2,137 +2,148 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-27 15:16:07
|
* @Date: 2021-08-27 15:16:07
|
||||||
* @Description: 模板列表
|
* @Description: 模板列表
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2023-11-22 09:55:59
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<search-header v-model="searchKeyword" @change="cateChange" />
|
<search-header v-model="state.searchKeyword" @change="cateChange" />
|
||||||
<el-divider v-show="title" style="margin-top: 1.7rem" content-position="left">
|
<el-divider v-show="state.title" style="margin-top: 1.7rem" content-position="left">
|
||||||
<span style="font-weight: bold">{{ title }}</span>
|
<span style="font-weight: bold">{{ state.title }}</span>
|
||||||
</el-divider>
|
</el-divider>
|
||||||
|
|
||||||
<ul ref="listRef" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
|
<ul ref="listRef" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
|
||||||
<img-water-fall :listData="list" @select="selectItem" />
|
<img-water-fall :listData="state.list" @select="selectItem" />
|
||||||
<div v-show="loading" class="loading"><i class="el-icon-loading"></i> 拼命加载中</div>
|
<div v-show="state.loading" class="loading"><i class="el-icon-loading"></i> 拼命加载中</div>
|
||||||
<div v-show="loadDone" class="loading">全部加载完毕</div>
|
<div v-show="state.loadDone" class="loading">全部加载完毕</div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, onMounted, ref } from 'vue'
|
import { reactive, ref, defineExpose } from 'vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { mapActions, mapGetters, useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { useRoute } from 'vue-router'
|
import { LocationQueryValue, useRoute, useRouter } from 'vue-router'
|
||||||
// import chooseType from './components/chooseType.vue'
|
// import chooseType from './components/chooseType.vue'
|
||||||
// import editModel from './components/editModel.vue'
|
// import editModel from './components/editModel.vue'
|
||||||
import searchHeader from './components/searchHeader.vue'
|
import searchHeader from './components/searchHeader.vue'
|
||||||
import useConfirm from '@/common/methods/confirm'
|
import useConfirm from '@/common/methods/confirm'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
import imgWaterFall from './components/imgWaterFall.vue'
|
||||||
|
import { IGetTempListData } from '@/api/home'
|
||||||
|
|
||||||
export default defineComponent({
|
type TState = {
|
||||||
components: { searchHeader },
|
loading: boolean
|
||||||
setup() {
|
loadDone: boolean
|
||||||
const listRef = ref(null)
|
list: IGetTempListData[]
|
||||||
const route = useRoute()
|
title: string
|
||||||
const store = useStore()
|
searchKeyword: string
|
||||||
const state: any = reactive({
|
}
|
||||||
loading: false,
|
|
||||||
loadDone: false,
|
|
||||||
list: [],
|
|
||||||
title: '推荐模板',
|
|
||||||
searchKeyword: '',
|
|
||||||
})
|
|
||||||
const pageOptions: any = { page: 0, pageSize: 20, cate: 1 }
|
|
||||||
const { cate, edit } = route.query
|
|
||||||
cate && (pageOptions.cate = cate)
|
|
||||||
edit && store.commit('managerEdit', true)
|
|
||||||
|
|
||||||
// onMounted(async () => {})
|
type TPageOptions = {
|
||||||
|
page: number,
|
||||||
|
pageSize: number,
|
||||||
|
cate: number | string
|
||||||
|
state?: string
|
||||||
|
}
|
||||||
|
|
||||||
const load = async (init: boolean = false, stat?: string) => {
|
const listRef = ref<HTMLElement | null>(null)
|
||||||
stat && (pageOptions.state = stat)
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const store = useStore()
|
||||||
|
const state = reactive<TState>({
|
||||||
|
loading: false,
|
||||||
|
loadDone: false,
|
||||||
|
list: [],
|
||||||
|
title: '推荐模板',
|
||||||
|
searchKeyword: '',
|
||||||
|
})
|
||||||
|
|
||||||
if (init) {
|
const { tempEditing, dHistoryParams } = useSetupMapGetters(['tempEditing', 'dHistoryParams'])
|
||||||
listRef.value.scrollTop = 0
|
|
||||||
state.list = []
|
|
||||||
pageOptions.page = 0
|
|
||||||
state.loadDone = false
|
|
||||||
}
|
|
||||||
if (state.loadDone || state.loading) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
state.loading = true
|
const pageOptions: TPageOptions = { page: 0, pageSize: 20, cate: 1 }
|
||||||
pageOptions.page += 1
|
const { cate, edit } = route.query
|
||||||
|
cate && (pageOptions.cate = (cate as LocationQueryValue) || 1)
|
||||||
|
edit && store.commit('managerEdit', true)
|
||||||
|
|
||||||
const res = await api.home.getTempList({ search: state.searchKeyword, ...pageOptions })
|
// onMounted(async () => {})
|
||||||
res.list.length <= 0 && (state.loadDone = true)
|
|
||||||
state.list = state.list.concat(res.list)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
const load = async (init: boolean = false, stat?: string) => {
|
||||||
state.loading = false
|
stat && (pageOptions.state = stat)
|
||||||
checkHeight()
|
|
||||||
}, 100)
|
if (init && listRef.value) {
|
||||||
|
listRef.value.scrollTop = 0
|
||||||
|
state.list = []
|
||||||
|
pageOptions.page = 0
|
||||||
|
state.loadDone = false
|
||||||
|
}
|
||||||
|
if (state.loadDone || state.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state.loading = true
|
||||||
|
pageOptions.page += 1
|
||||||
|
|
||||||
|
const res = await api.home.getTempList({ search: state.searchKeyword, ...pageOptions })
|
||||||
|
res.list.length <= 0 && (state.loadDone = true)
|
||||||
|
state.list = state.list.concat(res.list)
|
||||||
|
setTimeout(() => {
|
||||||
|
state.loading = false
|
||||||
|
checkHeight()
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cateChange(type: any) {
|
||||||
|
state.title = type.name
|
||||||
|
const init = pageOptions.cate != type.id
|
||||||
|
pageOptions.cate = type.id
|
||||||
|
load(init, pageOptions.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkHeight() {
|
||||||
|
if (!listRef.value) return
|
||||||
|
// 检查高度是否占满,否则继续请求下一页
|
||||||
|
const isLess = listRef.value.offsetHeight > (listRef.value.firstElementChild as HTMLElement)?.offsetHeight
|
||||||
|
isLess && load()
|
||||||
|
}
|
||||||
|
// ...mapActions(['selectWidget', 'updatePageData', 'setTemplate', 'pushHistory']),
|
||||||
|
async function selectItem(item: IGetTempListData) {
|
||||||
|
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||||
|
if (dHistoryParams.value.length > 0) {
|
||||||
|
const isPass = await useConfirm('提示', '使用模板后,当前页面将会被替换,是否继续', 'warning')
|
||||||
|
if (!isPass) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
store.commit('managerEdit', false)
|
||||||
|
store.commit('setDWidgets', [])
|
||||||
|
|
||||||
function cateChange(type: any) {
|
setTempId(item.id)
|
||||||
state.title = type.name
|
|
||||||
const init = pageOptions.cate != type.id
|
|
||||||
pageOptions.cate = type.id
|
|
||||||
load(init, pageOptions.stat)
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkHeight() {
|
let result = null
|
||||||
// 检查高度是否占满,否则继续请求下一页
|
if (!item.data) {
|
||||||
const isLess = listRef.value.offsetHeight > listRef.value.firstElementChild.offsetHeight
|
const res = await api.home.getTempDetail({ id: item.id })
|
||||||
isLess && load()
|
result = JSON.parse(res.data)
|
||||||
}
|
} else {
|
||||||
|
result = JSON.parse(item.data)
|
||||||
|
}
|
||||||
|
const { page, widgets } = result
|
||||||
|
console.log(widgets)
|
||||||
|
|
||||||
return {
|
store.commit('setDPage', page)
|
||||||
...toRefs(state),
|
store.dispatch('setTemplate', widgets)
|
||||||
load,
|
// setTemplate(widgets)
|
||||||
cateChange,
|
setTimeout(() => {
|
||||||
listRef,
|
store.commit('zoomScreenChange')
|
||||||
}
|
}, 300)
|
||||||
},
|
store.dispatch('selectWidget', {
|
||||||
computed: {
|
uuid: '-1'
|
||||||
...mapGetters(['tempEditing', 'dHistoryParams']),
|
})
|
||||||
},
|
// selectWidget({
|
||||||
methods: {
|
// uuid: '-1',
|
||||||
...mapActions(['selectWidget', 'updatePageData', 'setTemplate', 'pushHistory']),
|
// })
|
||||||
async selectItem(item: any) {
|
}
|
||||||
this.$store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
|
||||||
if (this.dHistoryParams.length > 0) {
|
|
||||||
const isPass = await useConfirm('提示', '使用模板后,当前页面将会被替换,是否继续', 'warning')
|
|
||||||
if (!isPass) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$store.commit('managerEdit', false)
|
|
||||||
this.$store.commit('setDWidgets', [])
|
|
||||||
|
|
||||||
this.setTempId(item.id)
|
|
||||||
|
|
||||||
let result = null
|
|
||||||
if (!item.data) {
|
|
||||||
const res = await api.home.getTempDetail({ id: item.id })
|
|
||||||
result = JSON.parse(res.data)
|
|
||||||
} else {
|
|
||||||
result = JSON.parse(item.data)
|
|
||||||
}
|
|
||||||
const { page, widgets } = result
|
|
||||||
console.log(widgets)
|
|
||||||
|
|
||||||
this.$store.commit('setDPage', page)
|
|
||||||
this.setTemplate(widgets)
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$store.commit('zoomScreenChange')
|
|
||||||
}, 300)
|
|
||||||
this.selectWidget({
|
|
||||||
uuid: '-1',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// action({ name, value }: any, item: any, index: number) {
|
// action({ name, value }: any, item: any, index: number) {
|
||||||
// switch (name) {
|
// switch (name) {
|
||||||
// case 'edit':
|
// case 'edit':
|
||||||
@ -158,12 +169,17 @@ export default defineComponent({
|
|||||||
// setTempStat({ id }: any, stat: string) {
|
// setTempStat({ id }: any, stat: string) {
|
||||||
// api.home.setTempStat({ id, stat })
|
// api.home.setTempStat({ id, stat })
|
||||||
// },
|
// },
|
||||||
setTempId(tempId: number | string) {
|
function setTempId(tempId: number | string) {
|
||||||
const { id } = this.$route.query
|
const { id } = route.query
|
||||||
this.$router.push({ path: '/home', query: { tempid: tempId, id }, replace: true })
|
router.push({ path: '/home', query: { tempid: tempId, id }, replace: true })
|
||||||
},
|
}
|
||||||
},
|
|
||||||
|
defineExpose({
|
||||||
|
load,
|
||||||
|
cateChange,
|
||||||
|
listRef,
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2023-10-04 02:04:04
|
* @Date: 2023-10-04 02:04:04
|
||||||
* @Description: 列表分类头部
|
* @Description: 列表分类头部
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2023-10-04 02:30:59
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!isBack" class="content__wrap">
|
<div v-if="!isBack" class="content__wrap">
|
||||||
@ -21,22 +21,34 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue'
|
import { defineProps, defineEmits } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export type TClassHeaderTypeData = {
|
||||||
props: ['types', 'isBack'],
|
name: string
|
||||||
emits: ['select', 'back'],
|
}
|
||||||
setup(props, { emit }) {
|
|
||||||
const select = (item: any) => {
|
type TProps = {
|
||||||
emit('select', item)
|
types: TClassHeaderTypeData[]
|
||||||
}
|
isBack: boolean
|
||||||
const back = () => {
|
}
|
||||||
emit('back')
|
|
||||||
}
|
type TEmits = {
|
||||||
return { select, back }
|
(event: 'select', data: string[]): void
|
||||||
},
|
(event: 'back'): void
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const { types, isBack } = defineProps<TProps>()
|
||||||
|
const emit = defineEmits<TEmits>()
|
||||||
|
|
||||||
|
const select = (item: any) => {
|
||||||
|
emit('select', item)
|
||||||
|
}
|
||||||
|
const back = () => {
|
||||||
|
emit('back')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ select, back })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2023-10-04 19:12:40
|
* @Date: 2023-10-04 19:12:40
|
||||||
* @Description: 图片描述ToolTip
|
* @Description: 图片描述ToolTip
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2023-10-04 22:51:06
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<el-tooltip :disabled="!detail.author" :offset="1" effect="light" placement="bottom-start" :hide-after="0" :enterable="false" raw-content>
|
<el-tooltip :disabled="!detail.author" :offset="1" effect="light" placement="bottom-start" :hide-after="0" :enterable="false" raw-content>
|
||||||
@ -17,15 +17,18 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue'
|
import { defineProps } from 'vue'
|
||||||
|
|
||||||
|
export type TImageTipDetailData = {
|
||||||
|
author: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tprops = {
|
||||||
|
detail: TImageTipDetailData
|
||||||
|
}
|
||||||
|
|
||||||
|
const { detail } = defineProps<Tprops>()
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: {
|
|
||||||
detail: {},
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,14 +2,18 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-12-16 16:20:16
|
* @Date: 2021-12-16 16:20:16
|
||||||
* @Description: 瀑布流组件
|
* @Description: 瀑布流组件
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2023-12-11 11:45:24
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div ref="imgWaterFall" :style="{ height: countHeight + 'px' }" class="img-water-fall">
|
<div ref="imgWaterFall" :style="{ height: state.countHeight + 'px' }" class="img-water-fall">
|
||||||
<!-- backgroundImage: `url(${item.cover})` -->
|
<!-- backgroundImage: `url(${item.cover})` -->
|
||||||
<div v-for="(item, i) in list" :key="i + 'iwf'" :style="{ top: item.top + 'px', left: item.left + 'px', width: width + 'px', height: item.height + 'px' }" class="img-box" @click.stop="selectItem(item, i)">
|
<div
|
||||||
<edit-model v-if="edit" :options="edit" :data="{ item, i }">
|
v-for="(item, i) in state.list" :key="i + 'iwf'"
|
||||||
|
:style="{ top: item.top + 'px', left: item.left + 'px', width: state.width + 'px', height: item.height + 'px' }"
|
||||||
|
class="img-box" @click.stop="selectItem(item, i)"
|
||||||
|
>
|
||||||
|
<edit-model v-if="edit" :options="props.edit" :data="{ item, i }">
|
||||||
{{ item.isDelect }}
|
{{ item.isDelect }}
|
||||||
<div v-if="item.isDelect" class="list__mask">已删除</div>
|
<div v-if="item.isDelect" class="list__mask">已删除</div>
|
||||||
<el-image v-if="!item.fail" class="img" :src="item.cover" lazy loading="lazy" @error="loadError(item)" />
|
<el-image v-if="!item.fail" class="img" :src="item.cover" lazy loading="lazy" @error="loadError(item)" />
|
||||||
@ -20,76 +24,82 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts" setup>
|
||||||
const NAME = 'img-water-fall'
|
// const NAME = 'img-water-fall'
|
||||||
import { defineComponent, toRefs, reactive, watch } from 'vue'
|
import { IGetTempListData } from '@/api/home';
|
||||||
|
import { reactive, watch, defineProps, defineExpose, defineEmits } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
type TProps = {
|
||||||
name: NAME,
|
listData: IGetTempListData[]
|
||||||
props: {
|
edit?: Record<string, any>
|
||||||
listData: {
|
}
|
||||||
type: Array,
|
|
||||||
required: true,
|
type TState = {
|
||||||
},
|
width: number
|
||||||
edit: {}
|
countHeight: number
|
||||||
|
list: IGetTempListData[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type TEmits = {
|
||||||
|
(event: 'select', data: IGetTempListData): void
|
||||||
|
(event: 'load'): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TProps>()
|
||||||
|
const emit = defineEmits<TEmits>()
|
||||||
|
|
||||||
|
const state = reactive<TState>({
|
||||||
|
width: 146, // 图片的宽度
|
||||||
|
list: [],
|
||||||
|
countHeight: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const columnHeights: number[] = [] // 列的高度
|
||||||
|
const columnNums = 2 // 总共有多少列
|
||||||
|
const gap = 7 // 图片之间的间隔
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.listData,
|
||||||
|
() => {
|
||||||
|
columnHeights.length = 0
|
||||||
|
const widthLimit = state.width * columnNums // + gap * (columnNums - 1) // 每行宽度
|
||||||
|
const cloneList = JSON.parse(JSON.stringify(props.listData))
|
||||||
|
for (let i = 0; i < cloneList.length; i++) {
|
||||||
|
let index = i % columnNums
|
||||||
|
const item = cloneList[i]
|
||||||
|
item.height = (item.height / item.width) * state.width // 图片高度
|
||||||
|
item.left = index * (widthLimit / columnNums + gap) // 定位
|
||||||
|
item.top = columnHeights[index] + gap || 0 // 定位
|
||||||
|
// columnHeights[index] = isNaN(columnHeights[index]) ? item.height : item.height + columnHeights[index] + gap // 记录列高度
|
||||||
|
// 找出最短边
|
||||||
|
if (isNaN(columnHeights[index])) {
|
||||||
|
columnHeights[index] = item.height
|
||||||
|
} else {
|
||||||
|
index = columnHeights.indexOf(Math.min(...columnHeights))
|
||||||
|
item.left = index * (widthLimit / columnNums + gap)
|
||||||
|
item.top = columnHeights[index] + gap || 0
|
||||||
|
columnHeights[index] = item.height + columnHeights[index] + gap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.countHeight = Math.max(...columnHeights)
|
||||||
|
state.list = cloneList
|
||||||
},
|
},
|
||||||
emits: ['select', 'load'],
|
)
|
||||||
setup(props, { emit }) {
|
|
||||||
const state = reactive({
|
|
||||||
width: 146, // 图片的宽度
|
|
||||||
list: [],
|
|
||||||
countHeight: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
const columnHeights = [] // 列的高度
|
const load = () => {
|
||||||
const columnNums = 2 // 总共有多少列
|
emit('load')
|
||||||
const gap = 7 // 图片之间的间隔
|
}
|
||||||
|
const selectItem = (value: IGetTempListData, index: number) => {
|
||||||
|
emit('select', value)
|
||||||
|
}
|
||||||
|
const loadError = (item: IGetTempListData) => {
|
||||||
|
item.fail = true
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
defineExpose({
|
||||||
() => props.listData,
|
load,
|
||||||
() => {
|
selectItem,
|
||||||
columnHeights.length = 0
|
loadError,
|
||||||
const widthLimit = state.width * columnNums // + gap * (columnNums - 1) // 每行宽度
|
|
||||||
const cloneList = JSON.parse(JSON.stringify(props.listData))
|
|
||||||
for (let i = 0; i < cloneList.length; i++) {
|
|
||||||
let index = i % columnNums
|
|
||||||
const item = cloneList[i]
|
|
||||||
item.height = (item.height / item.width) * state.width // 图片高度
|
|
||||||
item.left = index * (widthLimit / columnNums + gap) // 定位
|
|
||||||
item.top = columnHeights[index] + gap || 0 // 定位
|
|
||||||
// columnHeights[index] = isNaN(columnHeights[index]) ? item.height : item.height + columnHeights[index] + gap // 记录列高度
|
|
||||||
// 找出最短边
|
|
||||||
if (isNaN(columnHeights[index])) {
|
|
||||||
columnHeights[index] = item.height
|
|
||||||
} else {
|
|
||||||
index = columnHeights.indexOf(Math.min(...columnHeights))
|
|
||||||
item.left = index * (widthLimit / columnNums + gap)
|
|
||||||
item.top = columnHeights[index] + gap || 0
|
|
||||||
columnHeights[index] = item.height + columnHeights[index] + gap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.countHeight = Math.max(...columnHeights)
|
|
||||||
state.list = cloneList
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const load = () => {
|
|
||||||
emit('load')
|
|
||||||
}
|
|
||||||
const selectItem = (value, index) => {
|
|
||||||
emit('select', value)
|
|
||||||
}
|
|
||||||
const loadError = (item) => {
|
|
||||||
item.fail = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
load,
|
|
||||||
selectItem,
|
|
||||||
loadError,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -2,13 +2,22 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2022-02-23 15:48:52
|
* @Date: 2022-02-23 15:48:52
|
||||||
* @Description: 图片列表组件 Bookshelf Layout
|
* @Description: 图片列表组件 Bookshelf Layout
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2024-02-29 16:52:37
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<ul ref="listRef" class="img-list-wrap" :style="{ paddingBottom: isShort ? '15px' : '200px' }" @scroll="scrollEvent($event)">
|
<ul ref="listRef" class="img-list-wrap" :style="{ paddingBottom: isShort ? '15px' : '200px' }" @scroll="scrollEvent($event)">
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div v-for="(item, i) in list" :key="i + 'i'" :style="{ width: item.listWidth + 'px', marginRight: item.gap + 'px' }" class="list__img" draggable="false" @mousedown="dragStart($event, i)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="select(i)" @dragstart="dragStart($event, i)">
|
<div
|
||||||
|
v-for="(item, i) in state.list" :key="i + 'i'"
|
||||||
|
:style="{ width: item.listWidth + 'px', marginRight: item.gap + 'px' }"
|
||||||
|
class="list__img" draggable="false"
|
||||||
|
@mousedown="dragStart($event, i)"
|
||||||
|
@mousemove="mousemove"
|
||||||
|
@mouseup="mouseup"
|
||||||
|
@click.stop="select(i)"
|
||||||
|
@dragstart="dragStart($event, i)"
|
||||||
|
>
|
||||||
<edit-model v-if="edit" :options="edit" :data="{ item, i }">
|
<edit-model v-if="edit" :options="edit" :data="{ item, i }">
|
||||||
<div v-if="item.isDelect" class="list__mask">已删除</div>
|
<div v-if="item.isDelect" class="list__mask">已删除</div>
|
||||||
<el-image class="img transparent-bg" :src="item.thumb || item.url" :style="{ height: getInnerHeight(item) + 'px' }" lazy loading="lazy" />
|
<el-image class="img transparent-bg" :src="item.thumb || item.url" :style="{ height: getInnerHeight(item) + 'px' }" lazy loading="lazy" />
|
||||||
@ -24,163 +33,182 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isDone" v-show="loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div>
|
<div v-if="!isDone" v-show="state.loading" class="loading"><i class="el-icon-loading" /> 拼命加载中</div>
|
||||||
<div v-else class="loading">全部加载完毕</div>
|
<div v-else class="loading">全部加载完毕</div>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, toRefs, reactive, watch, nextTick } from 'vue'
|
import { reactive, watch, nextTick, defineProps, defineExpose, defineEmits, ref } from 'vue'
|
||||||
import DragHelper from '@/common/hooks/dragHelper'
|
import DragHelper from '@/common/hooks/dragHelper'
|
||||||
import setImageData from '@/common/methods/DesignFeatures/setImage'
|
import setImageData, { TItem2DataParam } from '@/common/methods/DesignFeatures/setImage'
|
||||||
|
|
||||||
export default defineComponent({
|
type TProps = {
|
||||||
props: {
|
listData: TCommonPhotoListData[]
|
||||||
listData: {},
|
edit: Record<string, any>
|
||||||
edit: {},
|
isDone: Record<string, any>
|
||||||
isDone: {},
|
isShort: boolean
|
||||||
isShort: {
|
}
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['load', 'drag', 'select'],
|
|
||||||
setup(props, context) {
|
|
||||||
const state: any = reactive({
|
|
||||||
loading: true,
|
|
||||||
list: [],
|
|
||||||
listRef: null,
|
|
||||||
})
|
|
||||||
|
|
||||||
const dragHelper = new DragHelper()
|
type TEmits = {
|
||||||
let isDrag = false
|
(event: 'load'): void
|
||||||
let startPoint = { x: 99999, y: 99999 }
|
(event: 'select', data: number): void
|
||||||
const mouseup = (e: any) => {
|
(event: 'drag', data: number): void
|
||||||
e.preventDefault()
|
|
||||||
setTimeout(() => {
|
}
|
||||||
isDrag = false
|
|
||||||
startPoint = { x: 99999, y: 99999 }
|
type TState = {
|
||||||
}, 10)
|
loading: boolean
|
||||||
|
list: TCommonPhotoListData[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const { listData, edit, isDone, isShort } = withDefaults(defineProps<TProps>(), {
|
||||||
|
isShort: false
|
||||||
|
})
|
||||||
|
const emit = defineEmits<TEmits>()
|
||||||
|
const listRef = ref<HTMLElement | null>(null)
|
||||||
|
const state = reactive<TState>({
|
||||||
|
loading: true,
|
||||||
|
list: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const dragHelper = new DragHelper()
|
||||||
|
let isDrag = false
|
||||||
|
let startPoint = { x: 99999, y: 99999 }
|
||||||
|
|
||||||
|
const mouseup = (e: MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
setTimeout(() => {
|
||||||
|
isDrag = false
|
||||||
|
startPoint = { x: 99999, y: 99999 }
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mousemove = (e: MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (e.x - startPoint.x > 2 || e.y - startPoint.y > 2) {
|
||||||
|
isDrag = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => listData,
|
||||||
|
async (newList: TCommonPhotoListData[], oldList: TCommonPhotoListData[]) => {
|
||||||
|
!oldList && (oldList = [])
|
||||||
|
if (newList.length <= 0) {
|
||||||
|
state.list.length = 0
|
||||||
|
return
|
||||||
}
|
}
|
||||||
const mousemove = (e: any) => {
|
let list = newList.filter((v: TCommonPhotoListData) => !newList.includes(v) || !oldList.includes(v)) // difference
|
||||||
e.preventDefault()
|
list = JSON.parse(JSON.stringify(list))
|
||||||
if (e.x - startPoint.x > 2 || e.y - startPoint.y > 2) {
|
const marginRight = 6 // 间距
|
||||||
isDrag = true
|
const limitWidth = (await getFatherWidth()) - marginRight
|
||||||
}
|
const standardHeight = 280 // 高度阈值
|
||||||
}
|
const neatArr: TCommonPhotoListData[][] = [] // 整理后的数组
|
||||||
|
function factory(cutArr: TCommonPhotoListData[]) {
|
||||||
watch(
|
return new Promise<{ height: number, list: TCommonPhotoListData[] }>((resolve) => {
|
||||||
() => props.listData,
|
const lineup = list.shift()
|
||||||
async (newList: any, oldList: any) => {
|
if (!lineup) {
|
||||||
!oldList && (oldList = [])
|
resolve({ height: calculate(cutArr), list: cutArr })
|
||||||
if (newList.length <= 0) {
|
|
||||||
state.list.length = 0
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let list = newList.filter((v: any) => !newList.includes(v) || !oldList.includes(v)) // difference
|
cutArr.push(lineup)
|
||||||
list = JSON.parse(JSON.stringify(list))
|
const finalHeight = calculate(cutArr)
|
||||||
const marginRight = 6 // 间距
|
if (finalHeight > standardHeight) {
|
||||||
const limitWidth = (await getFatherWidth()) - marginRight
|
resolve(factory(cutArr))
|
||||||
const standardHeight = 280 // 高度阈值
|
} else {
|
||||||
const neatArr: any = [] // 整理后的数组
|
resolve({ height: finalHeight, list: cutArr })
|
||||||
function factory(cutArr: any) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const lineup = list.shift()
|
|
||||||
if (!lineup) {
|
|
||||||
resolve({ height: calculate(cutArr), list: cutArr })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cutArr.push(lineup)
|
|
||||||
const finalHeight = calculate(cutArr)
|
|
||||||
if (finalHeight > standardHeight) {
|
|
||||||
resolve(factory(cutArr))
|
|
||||||
} else {
|
|
||||||
resolve({ height: finalHeight, list: cutArr })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
function calculate(cutArr: any) {
|
|
||||||
let cumulate = 0
|
|
||||||
for (const iterator of cutArr) {
|
|
||||||
const { width, height } = iterator
|
|
||||||
cumulate += width / height
|
|
||||||
}
|
|
||||||
return (limitWidth - marginRight * (cutArr.length - 1)) / cumulate
|
|
||||||
}
|
|
||||||
async function handleList() {
|
|
||||||
if (list.length <= 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const { list: newList, height }: any = await factory([list.shift()])
|
|
||||||
neatArr.push(
|
|
||||||
newList.map((x: any, index) => {
|
|
||||||
x.listWidth = (x.width / x.height) * height
|
|
||||||
x.gap = index !== newList.length - 1 ? marginRight : 0
|
|
||||||
return x
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
if (list.length > 0) {
|
|
||||||
await handleList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function calculate(cutArr: TCommonPhotoListData[]) {
|
||||||
|
let cumulate = 0
|
||||||
|
for (const iterator of cutArr) {
|
||||||
|
const { width, height } = iterator
|
||||||
|
cumulate += width / height
|
||||||
|
}
|
||||||
|
return (limitWidth - marginRight * (cutArr.length - 1)) / cumulate
|
||||||
|
}
|
||||||
|
async function handleList() {
|
||||||
|
if (list.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { list: newList, height } = await factory([(list.shift() as TCommonPhotoListData)])
|
||||||
|
neatArr.push(
|
||||||
|
newList.map((x: TCommonPhotoListData, index: number) => {
|
||||||
|
x.listWidth = (x.width / x.height) * height
|
||||||
|
x.gap = index !== newList.length - 1 ? marginRight : 0
|
||||||
|
return x
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
if (list.length > 0) {
|
||||||
await handleList()
|
await handleList()
|
||||||
state.list = state.list.concat(neatArr.flat(1))
|
|
||||||
state.loading = false
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
async function getFatherWidth() {
|
|
||||||
await nextTick()
|
|
||||||
const dom = state.listRef
|
|
||||||
const father = dom.parentElement || dom.parentNode
|
|
||||||
return father.offsetWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRef() {
|
|
||||||
// 用于在组件外调用内部ref
|
|
||||||
return state.listRef
|
|
||||||
}
|
|
||||||
|
|
||||||
const load = () => {
|
|
||||||
state.loading = true
|
|
||||||
context.emit('load')
|
|
||||||
}
|
|
||||||
const select = (i: number) => {
|
|
||||||
!isDrag && !state.list[i].isDelect && context.emit('select', i)
|
|
||||||
}
|
|
||||||
const dragStart = async (e: Event | any, i: number) => {
|
|
||||||
e.preventDefault()
|
|
||||||
startPoint = { x: e.x, y: e.y }
|
|
||||||
if (!state.list[i].isDelect) {
|
|
||||||
const img = await setImageData(state.list[i])
|
|
||||||
dragHelper.start(e, img.canvasWidth)
|
|
||||||
context.emit('drag', i)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function delItem(i: number) {
|
await handleList()
|
||||||
state.list[i].isDelect = true
|
state.list = state.list.concat(neatArr.flat(1))
|
||||||
}
|
state.loading = false
|
||||||
|
|
||||||
const scrollEvent = (e: any) => {
|
|
||||||
if (e.target.scrollTop + e.target.offsetHeight + 200 >= e.target.scrollHeight) {
|
|
||||||
load()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getInnerHeight = ({ height, listWidth, width }: any) => (height * listWidth) / width
|
|
||||||
|
|
||||||
return {
|
|
||||||
load,
|
|
||||||
dragStart,
|
|
||||||
select,
|
|
||||||
...toRefs(state),
|
|
||||||
delItem,
|
|
||||||
scrollEvent,
|
|
||||||
getRef,
|
|
||||||
mouseup,
|
|
||||||
mousemove,
|
|
||||||
getInnerHeight,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
async function getFatherWidth() {
|
||||||
|
await nextTick()
|
||||||
|
if (!listRef.value) return 0
|
||||||
|
const father = listRef.value.parentElement || listRef.value.parentNode
|
||||||
|
if (!father) return 0
|
||||||
|
return (father as HTMLElement).offsetWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRef() {
|
||||||
|
// 用于在组件外调用内部ref
|
||||||
|
return listRef
|
||||||
|
}
|
||||||
|
|
||||||
|
const load = () => {
|
||||||
|
state.loading = true
|
||||||
|
emit('load')
|
||||||
|
}
|
||||||
|
const select = (i: number) => {
|
||||||
|
!isDrag && !state.list[i].isDelect && emit('select', i)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dragStart = async (e: Event | any, i: number) => {
|
||||||
|
e.preventDefault()
|
||||||
|
startPoint = { x: e.x, y: e.y }
|
||||||
|
if (!state.list[i].isDelect) {
|
||||||
|
const setImageParams: TItem2DataParam = {
|
||||||
|
width: state.list[i].width,
|
||||||
|
height: state.list[i].height,
|
||||||
|
url: state.list[i].url || '',
|
||||||
|
model: state.list[i].model
|
||||||
|
}
|
||||||
|
const img = await setImageData(setImageParams)
|
||||||
|
dragHelper.start(e, img.canvasWidth)
|
||||||
|
emit('drag', i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function delItem(i: number) {
|
||||||
|
state.list[i].isDelect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollEvent = (e: any) => {
|
||||||
|
if (e.target.scrollTop + e.target.offsetHeight + 200 >= e.target.scrollHeight) {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInnerHeight = ({ height, listWidth, width }: any) => (height * listWidth) / width
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
load,
|
||||||
|
dragStart,
|
||||||
|
select,
|
||||||
|
delItem,
|
||||||
|
scrollEvent,
|
||||||
|
getRef,
|
||||||
|
mouseup,
|
||||||
|
mousemove,
|
||||||
|
getInnerHeight,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2022-01-27 11:05:48
|
* @Date: 2022-01-27 11:05:48
|
||||||
* @Description:
|
* @Description:
|
||||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||||
* @LastEditTime: 2023-10-04 01:53:10
|
* @Date: 2024-03-06 21:16:00
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="search__wrap">
|
<div class="search__wrap">
|
||||||
@ -11,66 +11,85 @@
|
|||||||
<div class="search__type"><i class="iconfont icon-ego-caidan" /></div>
|
<div class="search__type"><i class="iconfont icon-ego-caidan" /></div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item v-for="type in materialCates" :key="type.id" @click="action('change', type, type.id)">
|
<el-dropdown-item
|
||||||
<span :class="['cate__text', { 'cate--select': +currentIndex === type.id }]">{{ type.name }}</span>
|
v-for="type in state.materialCates" :key="type.id"
|
||||||
|
@click="action('change', type, type.id)"
|
||||||
|
>
|
||||||
|
<span :class="['cate__text', { 'cate--select': + state.currentIndex === type.id }]">{{ type.name }}</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<span v-else style="width: 1rem"></span>
|
<span v-else style="width: 1rem"></span>
|
||||||
|
|
||||||
<el-input v-model="searchValue" size="large" placeholder="输入关键词搜索" class="input-with-select">
|
<el-input v-model="state.searchValue" size="large" placeholder="输入关键词搜索" class="input-with-select">
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button><i class="iconfont icon-search"></i></el-button>
|
<el-button><i class="iconfont icon-search"></i></el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, watch } from 'vue'
|
import { reactive, toRefs, watch, defineProps, defineEmits, defineExpose } from 'vue'
|
||||||
import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus'
|
import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
|
|
||||||
export default defineComponent({
|
type TProps = {
|
||||||
components: { ElDropdown, ElDropdownItem, ElDropdownMenu },
|
type: string
|
||||||
props: ['type', 'modelValue'],
|
modelValue: string
|
||||||
emits: ['update:modelValue'],
|
}
|
||||||
setup(props, context) {
|
|
||||||
const route = useRoute()
|
|
||||||
const state: any = reactive({
|
|
||||||
searchValue: '',
|
|
||||||
materialCates: [],
|
|
||||||
currentIndex: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (props.type != 'none') {
|
type TEmits = {
|
||||||
api.home.getCategories({ type: 1 }).then((list: any) => {
|
(event: 'update:modelValue', data: string): void
|
||||||
list.unshift({ id: 0, name: '全部' })
|
(event: 'change', data: TMaterialCatesData): void
|
||||||
state.materialCates = list
|
}
|
||||||
const { cate } = route.query
|
|
||||||
cate && (state.currentIndex = cate)
|
|
||||||
cate && action('change', state.materialCates[Number(cate)], Number(cate))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
type TMaterialCatesData = {id: string | number, name: string}
|
||||||
() => state.searchValue,
|
|
||||||
() => {
|
|
||||||
context.emit('update:modelValue', state.searchValue)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
function action(fn: string, type: any, currentIndex: number | string) {
|
type TState = {
|
||||||
currentIndex && (state.currentIndex = currentIndex)
|
searchValue: string
|
||||||
context.emit(fn, type)
|
materialCates: TMaterialCatesData[]
|
||||||
}
|
currentIndex: number | string
|
||||||
return {
|
}
|
||||||
...toRefs(state),
|
|
||||||
action,
|
const props = defineProps<TProps>()
|
||||||
}
|
|
||||||
},
|
const emit = defineEmits<TEmits>()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const state = reactive<TState>({
|
||||||
|
searchValue: '',
|
||||||
|
materialCates: [],
|
||||||
|
currentIndex: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (props.type != 'none') {
|
||||||
|
api.home.getCategories({ type: 1 }).then((list: any) => {
|
||||||
|
list.unshift({ id: 0, name: '全部' })
|
||||||
|
state.materialCates = list
|
||||||
|
const { cate } = route.query
|
||||||
|
cate && (state.currentIndex = cate as string)
|
||||||
|
cate && action('change', state.materialCates[Number(cate)], Number(cate))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => state.searchValue,
|
||||||
|
() => {
|
||||||
|
emit('update:modelValue', state.searchValue)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
function action(fn: 'change', type: TMaterialCatesData, currentIndex: number | string) {
|
||||||
|
currentIndex && (state.currentIndex = currentIndex)
|
||||||
|
emit(fn, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
action
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user