feat: convert panel setting components to composition API

This commit is contained in:
IchliebedichZhu 2024-03-07 13:52:54 +00:00
parent 3f7f0c9291
commit bbfb860c77
7 changed files with 239 additions and 189 deletions

View File

@ -43,6 +43,7 @@ export const getTempList = (params: IGetTempListParam) => fetch<IGetTempListResu
type TGetTempDetail = { type TGetTempDetail = {
id: number id: number
type?: number
} }
export const getTempDetail = (params: TGetTempDetail) => fetch<{data: string}>('design/temp', params, 'get') export const getTempDetail = (params: TGetTempDetail) => fetch<{data: string}>('design/temp', params, 'get')

View File

@ -32,12 +32,11 @@ export type TGetListData = {
updated_time: string updated_time: string
url: string url: string
width: number width: number
thumbUrl: string
imgUrl: string
} }
type TGetListResult = TCommResResult<{ export type TGetListResult = TPageRequestResult<TGetListData[]>
list: TGetListData
total: number
}>

View File

@ -39,6 +39,7 @@ const state = reactive({
active: true, active: true,
}) })
const clickClassify = (index: number) => { const clickClassify = (index: number) => {
console.log('index' ,index)
state.activeWidgetClassify = index state.activeWidgetClassify = index
state.active = true state.active = true
} }

View File

@ -17,7 +17,7 @@
<i class="icon sd-AI_zhineng" /> <i class="icon sd-AI_zhineng" />
<div class="text"><span>智能抠图</span> <span class="desc">上传图像一键去除背景</span></div> <div class="text"><span>智能抠图</span> <span class="desc">上传图像一键去除背景</span></div>
</div> </div>
<imageCutout ref="imageCutout" /> <imageCutout ref="imageCutoutRef" />
</div> </div>
</template> </template>

View File

@ -6,27 +6,27 @@
* @LastEditTime: 2023-06-29 17:53:39 * @LastEditTime: 2023-06-29 17:53:39
--> -->
<template> <template>
<el-card class="box-card" shadow="hover" :body-style="{ padding: effectSelect ? '20px' : 0 }"> <el-card class="box-card" shadow="hover" :body-style="{ padding: state.effectSelect ? '20px' : 0 }">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<template v-if="effectSelect"> <template v-if="state.effectSelect">
<component :is="effectSelect" class="demo" /> <component :is="state.effectSelect" class="demo" />
</template> </template>
<div v-show="!effectSelect"></div> <div v-show="!state.effectSelect"></div>
<span class="title">图片容器</span> <span class="title">图片容器</span>
<el-popover :visible="visiable" placement="bottom-end" :width="260" trigger="click"> <el-popover :visible="state.visiable" placement="bottom-end" :width="260" trigger="click">
<div class="box__header"> <div class="box__header">
<el-radio-group v-model="type" size="small"> <el-radio-group v-model="state.type" size="small">
<el-radio-button label="160">形状</el-radio-button> <el-radio-button label="160">形状</el-radio-button>
<el-radio-button label="166">框架</el-radio-button> <el-radio-button label="166">框架</el-radio-button>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="select__box"> <div class="select__box">
<div class="select__box__select-item" @click="select(null)"></div> <div class="select__box__select-item" @click="select()"></div>
<el-image v-for="(item, i) in list" :key="i + 'l'" class="select__box__select-item" :src="item.thumbUrl" fit="contain" @click="select(item.imgUrl)"></el-image> <el-image v-for="(item, i) in state.list" :key="i + 'l'" class="select__box__select-item" :src="item.thumbUrl" fit="contain" @click="select(item.imgUrl)"></el-image>
</div> </div>
<template #reference> <template #reference>
<el-button class="button" link @click="visiable = !visiable">{{ visiable ? '取消' : '选择' }}</el-button> <el-button class="button" link @click="state.visiable = !state.visiable">{{ state.visiable ? '取消' : '选择' }}</el-button>
</template> </template>
</el-popover> </el-popover>
</div> </div>
@ -38,58 +38,74 @@
</el-card> </el-card>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import api from '@/api' import api from '@/api'
import { defineComponent, toRefs, reactive, watch, onMounted, nextTick } from 'vue' import { toRefs, reactive, watch, onMounted, nextTick, defineProps, defineEmits, defineExpose } from 'vue'
import { ElRadioGroup, ElRadioButton } from 'element-plus' import { ElRadioGroup, ElRadioButton } from 'element-plus'
import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue' import wSvg from '@/components/modules/widgets/wSvg/wSvg.vue'
import { TGetListResult } from '@/api/material';
export default defineComponent({ type TProps = {
components: { ElRadioGroup, ElRadioButton }, modelValue?: string
props: ['modelValue', 'degree'], degree?: number
emits: ['change'], }
setup(props, context) {
const state = reactive({ type TEmits = {
(event: 'change', data: Record<string, any>): void
}
type TState = {
effectSelect: string
visiable: boolean
type: string
list: {thumbUrl: string, imgUrl: string}[]
}
const props = defineProps<TProps>()
const emit = defineEmits<TEmits>()
const state = reactive<TState>({
// strength: 20, // // strength: 20, //
effectSelect: '', // effectSelect: '', //
visiable: false, // visiable: false, //
type: '166', // type: '166', //
list: [], list: [],
}) })
const select = (value: string = '') => {
const select = (value: string = '') => {
state.visiable = false state.visiable = false
const setting = JSON.parse(JSON.stringify(wSvg.setting)) const setting = JSON.parse(JSON.stringify(wSvg.setting))
setting.svgUrl = value setting.svgUrl = value
context.emit('change', setting) emit('change', setting)
} }
onMounted(async () => {
onMounted(async () => {
await nextTick() await nextTick()
state.effectSelect = props?.modelValue || '' state.effectSelect = props?.modelValue || ''
// state.strength = props?.degree || state.strength // state.strength = props?.degree || state.strength
getList() getList()
}) })
async function getList() { async function getList() {
const res = await api.material.getList({ const res = await api.material.getList({
first_id: 2, first_id: 2,
second_id: state.type, second_id: state.type,
}) })
state.list = res.list.map(({ thumbUrl, imgUrl }: any) => { state.list = res.list.map(({ thumbUrl, imgUrl }) => {
return { thumbUrl, imgUrl } return { thumbUrl, imgUrl }
}) })
} }
watch(
watch(
() => state.type, () => state.type,
(value) => { (value) => {
getList() getList()
}, },
) )
return { defineExpose({
...toRefs(state),
select, select,
}
},
methods: {},
}) })
</script> </script>

View File

@ -27,7 +27,7 @@
:key="efi + 'effect'" :key="efi + 'effect'"
:style="{ :style="{
color: ef.filling && ef.filling.enable && ef.filling.type === 0 ? ef.filling.color : 'transparent', color: ef.filling && ef.filling.enable && ef.filling.type === 0 ? ef.filling.color : 'transparent',
webkitTextStroke: ef.stroke && ef.stroke.enable ? `${ef.stroke.width / coefficient}px ${ef.stroke.color}` : undefined, webkitTextStroke: ef.stroke && ef.stroke.enable ? `${ef.stroke.width / coefficient}px ${ef.stroke.color}` : '',
textShadow: ef.shadow && ef.shadow.enable ? `${ef.shadow.offsetX / coefficient}px ${ef.shadow.offsetY / coefficient}px ${ef.shadow.blur / coefficient}px ${ef.shadow.color}` : undefined, textShadow: ef.shadow && ef.shadow.enable ? `${ef.shadow.offsetX / coefficient}px ${ef.shadow.offsetY / coefficient}px ${ef.shadow.blur / coefficient}px ${ef.shadow.color}` : undefined,
backgroundImage: ef.filling && ef.filling.enable ? (ef.filling.type === 0 ? undefined : getGradientOrImg(ef)) : undefined, backgroundImage: ef.filling && ef.filling.enable ? (ef.filling.type === 0 ? undefined : getGradientOrImg(ef)) : undefined,
webkitBackgroundClip: ef.filling && ef.filling.enable ? (ef.filling.type === 0 ? undefined : 'text') : undefined, webkitBackgroundClip: ef.filling && ef.filling.enable ? (ef.filling.type === 0 ? undefined : 'text') : undefined,
@ -39,52 +39,61 @@
A A
</div> </div>
<span class="title">文字特效</span> <span class="title">文字特效</span>
<el-popover :visible="visiable" placement="left" :width="220" trigger="click"> <el-popover :visible="state.visiable" placement="left" :width="220" trigger="click">
<div class="select__box"> <div class="select__box">
<div class="select__box__select-item" @click="selectEffect(null)"></div> <div class="select__box__select-item" @click="selectEffect()"></div>
<div v-for="(l, li) in list" :key="'list' + li" class="select__box__select-item" @click="selectEffect(l.id)"> <div v-for="(l, li) in state.list" :key="'list' + li" class="select__box__select-item" @click="selectEffect(l.id)">
<img :src="l.cover" /> <img :src="l.cover" />
</div> </div>
</div> </div>
<template #reference> <template #reference>
<el-button class="button" link @click="openSet">{{ visiable ? '取消' : '选择' }}</el-button> <el-button class="button" link @click="openSet">{{ state.visiable ? '取消' : '选择' }}</el-button>
</template> </template>
</el-popover> </el-popover>
</div> </div>
</template> </template>
<!-- filling 描边 stroke 阴影 shadow --> <!-- filling 描边 stroke 阴影 shadow -->
<div v-show="layers && layers.length > 0" class="text item"><span style="width: 65px">强度</span> <el-slider v-model="strength" show-input :maxValue="100" input-size="small" :show-input-controls="false" @input="strengthChange"> </el-slider></div> <div v-show="state.layers && state.layers.length > 0" class="text item"><span style="width: 65px">强度</span> <el-slider v-model="state.strength" show-input :maxValue="100" input-size="small" :show-input-controls="false" @input="strengthChange"> </el-slider></div>
<el-collapse-item> <el-collapse-item>
<template #title> <template #title>
<b>高级编辑</b> <b>高级编辑</b>
</template> </template>
<div class="line"></div> <div class="line"></div>
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<el-button class="add-layer" size="small" type="primary" link @click="addLayer"> + 新建特效层</el-button> <el-button v-show="layers && layers.length > 0" class="add-layer" size="small" type="primary" link @click="unfold = !unfold">{{ unfold ? '收起' : '展开' }}全部</el-button> <el-button
class="add-layer" size="small" type="primary" link
@click="addLayer">
+ 新建特效层
</el-button>
<el-button
v-show="state.layers && state.layers.length > 0" class="add-layer" size="small"
type="primary" link @click="state.unfold = !state.unfold">
{{ state.unfold ? '收起' : '展开' }}全部
</el-button>
</div> </div>
<div class="line"></div> <div class="line"></div>
<draggable v-model="layers" handle=".sd-yidong" item-key="uuid" v-bind="dragOptions"> <draggable v-model="state.layers" handle=".sd-yidong" item-key="uuid" v-bind="dragOptions">
<template #item="{ element, index }"> <template #item="{ element, index }">
<div class="feature__grab-wrap"> <div class="feature__grab-wrap">
<div class="layer__title"> <div class="layer__title">
<i class="icon sd-yidong" /><span style="font-size: 12px"><b>特效层</b> {{ index + 1 }}</span> <i class="icon sd-yidong" /><span style="font-size: 12px"><b>特效层</b> {{ index + 1 }}</span>
<i class="icon sd-delete" @click="removeLayer(index)" /> <i class="icon sd-delete" @click="removeLayer(index)" />
</div> </div>
<div v-if="element.filling && [0, 2, '0', '2'].includes(element.filling.type)" v-show="unfold" class="feature__item"> <div v-if="element.filling && [0, 2, '0', '2'].includes(element.filling.type)" v-show="state.unfold" class="feature__item">
<el-checkbox v-model="element.filling.enable" label="填充" class="feature__header" /> <el-checkbox v-model="element.filling.enable" label="填充" class="feature__header" />
<color-select v-model="element.filling.color" width="28px" :modes="['纯色', '渐变']" label="" @change="colorChange($event, element.filling)" /> <color-select v-model="element.filling.color" width="28px" :modes="['纯色', '渐变']" label="" @change="colorChange($event, element.filling)" />
</div> </div>
<div v-if="element.stroke" v-show="unfold" class="feature__item"> <div v-if="element.stroke" v-show="state.unfold" class="feature__item">
<el-checkbox v-model="element.stroke.enable" label="描边" class="feature__header" /> <el-checkbox v-model="element.stroke.enable" label="描边" class="feature__header" />
<el-input-number v-model="element.stroke.width" style="width: 65px; margin-right: 0.5rem" :min="0" size="small" controls-position="right" /> <el-input-number v-model="element.stroke.width" style="width: 65px; margin-right: 0.5rem" :min="0" size="small" controls-position="right" />
<color-select v-model="element.stroke.color" width="28px" label="" @finish="(value) => finish('color', value)" /> <color-select v-model="element.stroke.color" width="28px" label="" @finish="(value) => finish('color', value)" />
</div> </div>
<div v-if="element.offset" v-show="unfold" class="feature__item"> <div v-if="element.offset" v-show="state.unfold" class="feature__item">
<el-checkbox v-model="element.offset.enable" label="偏移" class="feature__header" /> <el-checkbox v-model="element.offset.enable" label="偏移" class="feature__header" />
<numberInput v-model="element.offset.x" style="width: 49.5px; margin-right: 2px" prepend="x" type="simple" /> <numberInput v-model="element.offset.x" style="width: 49.5px; margin-right: 2px" prepend="x" type="simple" />
<numberInput v-model="element.offset.y" style="width: 49.5px" prepend="y" type="simple" /> <numberInput v-model="element.offset.y" style="width: 49.5px" prepend="y" type="simple" />
</div> </div>
<div v-if="element.shadow" v-show="unfold" class="feature__item"> <div v-if="element.shadow" v-show="state.unfold" class="feature__item">
<el-checkbox v-model="element.shadow.enable" label="阴影" class="feature__header" /> <el-checkbox v-model="element.shadow.enable" label="阴影" class="feature__header" />
<numberInput v-model="element.shadow.blur" prepend="blur" :minValue="0" style="width: 30px; margin-right: 2px" type="simple" /> <numberInput v-model="element.shadow.blur" prepend="blur" :minValue="0" style="width: 30px; margin-right: 2px" type="simple" />
<numberInput v-model="element.shadow.offsetX" prepend="x" style="width: 30px; margin-right: 2px" type="simple" /> <numberInput v-model="element.shadow.offsetX" prepend="x" style="width: 30px; margin-right: 2px" type="simple" />
@ -98,38 +107,63 @@
</el-card> </el-card>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, toRefs, reactive, watch, onMounted, nextTick, computed } from 'vue' import {
reactive, watch, onMounted, nextTick, computed,
defineProps, defineEmits, defineExpose
} from 'vue'
import colorSelect from '../colorSelect.vue' import colorSelect from '../colorSelect.vue'
import { ElInputNumber, ElCheckbox } from 'element-plus' import { ElInputNumber, ElCheckbox } from 'element-plus'
import numberInput from '../numberInput.vue' import numberInput from '../numberInput.vue'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import api from '@/api' import api from '@/api'
import getGradientOrImg from '../../widgets/wText/getGradientOrImg' import getGradientOrImg from '../../widgets/wText/getGradientOrImg'
let froze_font_effect_list: any = [] let froze_font_effect_list: Record<string, any>[] = []
export default defineComponent({ type TProps = {
components: { colorSelect, ElInputNumber, numberInput, ElCheckbox, draggable }, modelValue?: Record<string, any>
props: ['modelValue', 'degree', 'data'], degree?: string | number
emits: ['update:modelValue'], data: Record<string, any>
setup(props, { emit }) { }
const state = reactive({
type TEmits = {
(event: 'update:modelValue', data: Record<string, any>[]): void
}
type TState = {
strength: number
visiable: boolean
list: Record<string,any>[]
layers: Record<string, any>[]
draging: boolean
unfold: boolean
}
const props = withDefaults(defineProps<TProps>(), {
modelValue: () => ({}),
data: () => ({})
})
const emit = defineEmits<TEmits>()
const state = reactive<TState>({
strength: 50, // strength: 50, //
visiable: false, // visiable: false, //
list: [], list: [],
layers: [], layers: [],
draging: false, draging: false,
unfold: true, unfold: true,
}) })
const dragOptions = {
const dragOptions = {
animation: 300, animation: 300,
ghostClass: 'ghost', ghostClass: 'ghost',
chosenClass: 'choose', chosenClass: 'choose',
} }
const coefficient = computed(() => Math.round(160 / 27)) const coefficient = computed(() => Math.round(160 / 27))
let rawData: any = [] // let rawData: Record<string, any>[] = [] //
onMounted(async () => { onMounted(async () => {
await nextTick() await nextTick()
// console.log(props.data) // console.log(props.data)
if (!props.data.textEffects) { if (!props.data.textEffects) {
@ -143,8 +177,9 @@ export default defineComponent({
}) })
.reverse() .reverse()
rawData = JSON.parse(JSON.stringify(state.layers)) rawData = JSON.parse(JSON.stringify(state.layers))
}) })
watch(
watch(
() => state.layers, () => state.layers,
(v) => { (v) => {
const newEffect = v.map((x) => { const newEffect = v.map((x) => {
@ -154,42 +189,42 @@ export default defineComponent({
emit('update:modelValue', newEffect.reverse()) emit('update:modelValue', newEffect.reverse())
}, },
{ deep: true }, { deep: true },
) )
// //
const selectEffect = async (id) => { const selectEffect = async (id?: number) => {
state.visiable = false state.visiable = false
if (id) { if (id) {
const { data } = await api.home.getTempDetail({ id, type: 1 }) const { data } = await api.home.getTempDetail({ id, type: 1 })
state.layers = JSON.parse(data) state.layers = JSON.parse(data)
.textEffects.map((x) => { .textEffects.map((x: Record<string, any>) => {
x.uuid = String(Math.random()) x.uuid = String(Math.random())
return x return x
}) })
.reverse() .reverse()
} else state.layers = [] } else state.layers = []
} }
// //
const removeLayer = (i: number) => { const removeLayer = (i: number) => {
state.layers.splice(i, 1) state.layers.splice(i, 1)
rawData = JSON.parse(JSON.stringify(state.layers)) rawData = JSON.parse(JSON.stringify(state.layers))
} }
// //
const addLayer = () => { const addLayer = () => {
const filling = { enable: false, type: 0, color: '#000000ff' } const filling = { enable: false, type: 0, color: '#000000ff' }
const stroke = { enable: false, width: 0, color: '#000000ff', type: 'outer' } const stroke = { enable: false, width: 0, color: '#000000ff', type: 'outer' }
const offset = { enable: false, x: 0, y: 0 } const offset = { enable: false, x: 0, y: 0 }
const shadow = { enable: false, color: '#000000ff', offsetX: 0, offsetY: 0, blur: 0, opacity: 0 } const shadow = { enable: false, color: '#000000ff', offsetX: 0, offsetY: 0, blur: 0, opacity: 0 }
state.layers.unshift({ filling, stroke, shadow, offset, uuid: String(Math.random()) }) state.layers.unshift({ filling, stroke, shadow, offset, uuid: String(Math.random()) })
rawData = JSON.parse(JSON.stringify(state.layers)) rawData = JSON.parse(JSON.stringify(state.layers))
} }
const finish = () => {} const finish = (type?: string, value?: string) => {}
const colorChange = (e: any, item: any) => { const colorChange = (e: Record<string, any>, item: Record<string, any>) => {
const modeStr: any = { const modeStr: Record<string, number> = {
渐变: 2, 渐变: 2,
纯色: 0, 纯色: 0,
} }
@ -200,7 +235,7 @@ export default defineComponent({
setTimeout(() => { setTimeout(() => {
item.type = modeStr[e.mode] || 0 item.type = modeStr[e.mode] || 0
}, 100) }, 100)
} }
// const onMove = ({ relatedContext, draggedContext }: any) => { // const onMove = ({ relatedContext, draggedContext }: any) => {
// const relatedElement = relatedContext.element // const relatedElement = relatedContext.element
@ -223,8 +258,8 @@ export default defineComponent({
}) })
} }
// //
const openSet = async () => { const openSet = async () => {
state.visiable = !state.visiable state.visiable = !state.visiable
if (froze_font_effect_list.length <= 0) { if (froze_font_effect_list.length <= 0) {
const { list } = await api.home.getCompList({ const { list } = await api.home.getCompList({
@ -235,9 +270,9 @@ export default defineComponent({
state.list = list state.list = list
froze_font_effect_list = list froze_font_effect_list = list
} else state.list = froze_font_effect_list } else state.list = froze_font_effect_list
} }
return {
...toRefs(state), defineExpose({
selectEffect, selectEffect,
finish, finish,
coefficient, coefficient,
@ -249,9 +284,6 @@ export default defineComponent({
openSet, openSet,
colorChange, colorChange,
getGradientOrImg, getGradientOrImg,
}
},
methods: {},
}) })
</script> </script>

View File

@ -62,3 +62,4 @@ interface MouseEvent {
layerX: number layerX: number
layerY: number layerY: number
} }