mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
Merge pull request #72 from JeremyYu-cn/feat-upgrade-vue3
Feat: Convert views and components to composition API
This commit is contained in:
commit
db962af514
@ -39,6 +39,7 @@
|
|||||||
"vuex": "^4.0.0-0"
|
"vuex": "^4.0.0-0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/fontfaceobserver": "^2.1.3",
|
||||||
"@types/node": "^20.11.24",
|
"@types/node": "^20.11.24",
|
||||||
"@types/throttle-debounce": "^2.1.0",
|
"@types/throttle-debounce": "^2.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
|
||||||
}>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ type TProps = {
|
|||||||
title: string
|
title: string
|
||||||
width: number
|
width: number
|
||||||
content: string
|
content: string
|
||||||
position: "bottom" | "auto" | "auto-start" | "auto-end" | "top" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end"
|
position?: "bottom" | "auto" | "auto-start" | "auto-end" | "top" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end"
|
||||||
offset?: number
|
offset?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ type TProps = {
|
|||||||
percent: number
|
percent: number
|
||||||
text: string
|
text: string
|
||||||
cancelText: string
|
cancelText: string
|
||||||
msg: string
|
msg?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TEmits = {
|
type TEmits = {
|
||||||
|
@ -35,9 +35,9 @@ export type TUploadDoneData = {
|
|||||||
type TQiNiuUploadReturn = { hash: string, key: string }
|
type TQiNiuUploadReturn = { hash: string, key: string }
|
||||||
|
|
||||||
type TProps = {
|
type TProps = {
|
||||||
modelValue: TModelData
|
modelValue?: TModelData
|
||||||
options: { bucket: string, prePath: string }
|
options?: { bucket: string, prePath: string }
|
||||||
hold: boolean
|
hold?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type TEmits = {
|
type TEmits = {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ import { TUploadDoneData } from '@/components/common/Uploader/index.vue'
|
|||||||
import { IGetTempListData } from '@/api/home'
|
import { IGetTempListData } from '@/api/home'
|
||||||
|
|
||||||
type TProps = {
|
type TProps = {
|
||||||
active: number
|
active?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type TState = {
|
type TState = {
|
||||||
@ -104,7 +104,6 @@ const load = (init?: boolean) => {
|
|||||||
} else {
|
} else {
|
||||||
state.imgList = state.imgList.concat(list)
|
state.imgList = state.imgList.concat(list)
|
||||||
}
|
}
|
||||||
console.log('state.imgList', state.imgList)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading = false
|
loading = false
|
||||||
if (!imgListRef.value) return
|
if (!imgListRef.value) return
|
||||||
@ -133,11 +132,9 @@ const loadDesign = (init: boolean = false) => {
|
|||||||
return x
|
return x
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
console.log('state.designList', state.designList)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading = false
|
loading = false
|
||||||
if (!listRef.value) return
|
if (!listRef.value) return
|
||||||
console.log('listRef.value', listRef.value)
|
|
||||||
checkHeight(listRef.value, loadDesign)
|
checkHeight(listRef.value, loadDesign)
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
|
@ -30,7 +30,7 @@ export type TClassHeaderTypeData = {
|
|||||||
|
|
||||||
type TProps = {
|
type TProps = {
|
||||||
types: TClassHeaderTypeData[]
|
types: TClassHeaderTypeData[]
|
||||||
isBack: boolean
|
isBack?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type TEmits = {
|
type TEmits = {
|
||||||
|
@ -46,9 +46,9 @@ import { IGetTempListData } from '@/api/home';
|
|||||||
|
|
||||||
type TProps = {
|
type TProps = {
|
||||||
listData: IGetTempListData[]
|
listData: IGetTempListData[]
|
||||||
edit: Record<string, any>
|
edit?: Record<string, any>
|
||||||
isDone: boolean
|
isDone?: boolean
|
||||||
isShort: boolean
|
isShort?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type TEmits = {
|
type TEmits = {
|
||||||
@ -64,7 +64,8 @@ type TState = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<TProps>(), {
|
const props = withDefaults(defineProps<TProps>(), {
|
||||||
isShort: false
|
isShort: false,
|
||||||
|
listData: () => ([])
|
||||||
})
|
})
|
||||||
const emit = defineEmits<TEmits>()
|
const emit = defineEmits<TEmits>()
|
||||||
const listRef = ref<HTMLElement | null>(null)
|
const listRef = ref<HTMLElement | null>(null)
|
||||||
|
@ -37,7 +37,7 @@ import api from '@/api'
|
|||||||
|
|
||||||
type TProps = {
|
type TProps = {
|
||||||
type?: string
|
type?: string
|
||||||
modelValue: string
|
modelValue?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TEmits = {
|
type TEmits = {
|
||||||
|
@ -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,30 +38,49 @@
|
|||||||
</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 || ''
|
||||||
@ -74,22 +93,19 @@ export default defineComponent({
|
|||||||
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>
|
||||||
|
|
||||||
|
@ -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,22 +107,46 @@
|
|||||||
</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: [],
|
||||||
@ -121,13 +154,14 @@ export default defineComponent({
|
|||||||
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()
|
||||||
@ -144,6 +178,7 @@ 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) => {
|
||||||
@ -157,12 +192,12 @@ export default defineComponent({
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 选中加载特效预设
|
// 选中加载特效预设
|
||||||
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
|
||||||
})
|
})
|
||||||
@ -186,10 +221,10 @@ export default defineComponent({
|
|||||||
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,
|
||||||
}
|
}
|
||||||
@ -236,8 +271,8 @@ export default defineComponent({
|
|||||||
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>
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export default defineComponent({
|
|||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const state: any = reactive({
|
const state: any = reactive({
|
||||||
innerColor: '#ffffffff',
|
innerColor: '',
|
||||||
// colorLength: 0,
|
// colorLength: 0,
|
||||||
// hasEyeDrop: 'EyeDropper' in window,
|
// hasEyeDrop: 'EyeDropper' in window,
|
||||||
})
|
})
|
||||||
|
@ -14,6 +14,7 @@ _this.dHistoryParams = store.getters.dHistoryParams
|
|||||||
|
|
||||||
import keyCodeOptions from './methods/keyCodeOptions'
|
import keyCodeOptions from './methods/keyCodeOptions'
|
||||||
import dealWithCtrl from './methods/dealWithCtrl'
|
import dealWithCtrl from './methods/dealWithCtrl'
|
||||||
|
import { useStore, Store } from 'vuex'
|
||||||
|
|
||||||
const ignoreNode = ['INPUT', 'TEXTAREA']
|
const ignoreNode = ['INPUT', 'TEXTAREA']
|
||||||
|
|
||||||
@ -36,7 +37,8 @@ let hadDown = false
|
|||||||
|
|
||||||
const shortcuts = {
|
const shortcuts = {
|
||||||
methods: {
|
methods: {
|
||||||
handleKeydowm(e: any) {
|
handleKeydowm(store: Store<any>, checkCtrl: number | undefined, instance: any, dealCtrl: (e: any, instance: any) => void) {
|
||||||
|
return (e: any) => {
|
||||||
const nodeName = e.target.nodeName
|
const nodeName = e.target.nodeName
|
||||||
if (ignoreNode.indexOf(nodeName) !== -1 || (nodeName === 'DIV' && e.target.contentEditable === 'true')) {
|
if (ignoreNode.indexOf(nodeName) !== -1 || (nodeName === 'DIV' && e.target.contentEditable === 'true')) {
|
||||||
return
|
return
|
||||||
@ -56,14 +58,14 @@ const shortcuts = {
|
|||||||
// hadDown = false
|
// hadDown = false
|
||||||
// }
|
// }
|
||||||
if (shift || ctrl) {
|
if (shift || ctrl) {
|
||||||
this.$store.dispatch('updateAltDown', true)
|
store.dispatch('updateAltDown', true)
|
||||||
clearInterval(this.checkCtrl)
|
clearInterval(checkCtrl)
|
||||||
this.checkCtrl = setInterval(() => {
|
checkCtrl = setInterval(() => {
|
||||||
// TODO: 防止组合键导致页面失焦无法操作
|
// TODO: 防止组合键导致页面失焦无法操作
|
||||||
if (!document.hasFocus()) {
|
if (!document.hasFocus()) {
|
||||||
clearInterval(this.checkCtrl)
|
clearInterval(checkCtrl)
|
||||||
hadDown = false
|
hadDown = false
|
||||||
this.$store.dispatch('updateAltDown', false)
|
store.dispatch('updateAltDown', false)
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
@ -91,7 +93,7 @@ const shortcuts = {
|
|||||||
// }
|
// }
|
||||||
const withCtrl = e.ctrlKey || e.metaKey
|
const withCtrl = e.ctrlKey || e.metaKey
|
||||||
if (withCtrl && !(ctrl || alt || shift)) {
|
if (withCtrl && !(ctrl || alt || shift)) {
|
||||||
this.dealCtrl(e)
|
dealCtrl(e, instance)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// const withAlt = e.altKey
|
// const withAlt = e.altKey
|
||||||
@ -113,17 +115,20 @@ const shortcuts = {
|
|||||||
// e.preventDefault()
|
// e.preventDefault()
|
||||||
const f = withShift ? 10 : 1
|
const f = withShift ? 10 : 1
|
||||||
keyCodeOptions(e, { f })
|
keyCodeOptions(e, { f })
|
||||||
},
|
|
||||||
handleKeyup(e) {
|
|
||||||
console.log(e)
|
|
||||||
clearInterval(this.checkCtrl)
|
|
||||||
hadDown = false
|
|
||||||
if (e.key === 'Alt' || e.key === 'Shift' || e.key === 'Control' || e.key === 'Meta') {
|
|
||||||
this.$store.dispatch('updateAltDown', false)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dealCtrl(e: any) {
|
handleKeyup(store: Store<any>, checkCtrl: number | undefined) {
|
||||||
dealWithCtrl(e, this)
|
return (e: any) => {
|
||||||
|
console.log(e)
|
||||||
|
clearInterval(checkCtrl)
|
||||||
|
hadDown = false
|
||||||
|
if (e.key === 'Alt' || e.key === 'Shift' || e.key === 'Control' || e.key === 'Meta') {
|
||||||
|
store.dispatch('updateAltDown', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dealCtrl(e: any, instance: any) {
|
||||||
|
dealWithCtrl(e, instance)
|
||||||
console.log(e.key, e.keyCode)
|
console.log(e.key, e.keyCode)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
1
src/types/global.d.ts
vendored
1
src/types/global.d.ts
vendored
@ -62,3 +62,4 @@ interface MouseEvent {
|
|||||||
layerX: number
|
layerX: number
|
||||||
layerY: number
|
layerY: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
import { StyleValue, onMounted, reactive, nextTick } from 'vue'
|
||||||
import { mapActions, mapGetters } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
||||||
import Preload from '@/utils/plugins/preload'
|
import Preload from '@/utils/plugins/preload'
|
||||||
@ -18,57 +18,66 @@ import FontFaceObserver from 'fontfaceobserver'
|
|||||||
import { fontWithDraw, font2style } from '@/utils/widgets/loadFontRule'
|
import { fontWithDraw, font2style } from '@/utils/widgets/loadFontRule'
|
||||||
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
||||||
import zoomControl from '@/components/modules/layout/zoomControl/index.vue'
|
import zoomControl from '@/components/modules/layout/zoomControl/index.vue'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
type TState = {
|
||||||
|
style: StyleValue
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { designBoard, zoomControl },
|
|
||||||
// mixins: [shortcuts],
|
// mixins: [shortcuts],
|
||||||
setup() {
|
const store = useStore()
|
||||||
const state = reactive({
|
const route = useRoute()
|
||||||
|
const state = reactive<TState>({
|
||||||
style: {
|
style: {
|
||||||
left: '0px',
|
left: '0px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const { dPage } = useSetupMapGetters(['dPage'])
|
||||||
|
|
||||||
return {
|
onMounted(() => {
|
||||||
...toRefs(state),
|
store.dispatch('initGroupJson', JSON.stringify(wGroup.setting))
|
||||||
}
|
// initGroupJson(JSON.stringify(wGroup.setting))
|
||||||
},
|
nextTick(() => {
|
||||||
computed: {
|
load()
|
||||||
...mapGetters(['dPage']),
|
})
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.initGroupJson(JSON.stringify(wGroup.setting))
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.load()
|
|
||||||
})
|
})
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(['initGroupJson', 'setTemplate', 'addGroup']),
|
|
||||||
async load() {
|
|
||||||
let loadFlag = false
|
|
||||||
const { id, tempid, tempType: type } = this.$route.query
|
|
||||||
if (id || tempid) {
|
|
||||||
const { data, width, height } = await api.home[id ? 'getWorks' : 'getTempDetail']({ id: id || tempid, type })
|
|
||||||
const content = JSON.parse(data)
|
|
||||||
const widgets = type == 1 ? content : content.widgets
|
|
||||||
|
|
||||||
if (type == 1) {
|
// ...mapActions(['initGroupJson', 'setTemplate', 'addGroup']),
|
||||||
this.dPage.width = width
|
async function load() {
|
||||||
this.dPage.height = height
|
let loadFlag = false
|
||||||
this.dPage.backgroundColor = '#ffffff00'
|
const { id, tempid, tempType: type } = route.query
|
||||||
this.addGroup(content)
|
if (id || tempid) {
|
||||||
|
const postData = {
|
||||||
|
id: Number(id || tempid),
|
||||||
|
type: Number(type)
|
||||||
|
}
|
||||||
|
const { data, width, height } = await api.home[id ? 'getWorks' : 'getTempDetail'](postData)
|
||||||
|
const content = JSON.parse(data)
|
||||||
|
const widgets = Number(type) == 1 ? content : content.widgets
|
||||||
|
|
||||||
|
if (Number(type) == 1) {
|
||||||
|
dPage.value.width = width
|
||||||
|
dPage.value.height = height
|
||||||
|
dPage.value.backgroundColor = '#ffffff00'
|
||||||
|
store.dispatch('addGroup', content)
|
||||||
|
// addGroup(content)
|
||||||
} else {
|
} else {
|
||||||
this.$store.commit('setDPage', content.page)
|
store.commit('setDPage', content.page)
|
||||||
id ? this.$store.commit('setDWidgets', widgets) : this.setTemplate(widgets)
|
if (id) {
|
||||||
|
store.commit('setDWidgets', widgets)
|
||||||
|
} else {
|
||||||
|
store.dispatch('setTemplate', widgets)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$nextTick()
|
await nextTick()
|
||||||
|
|
||||||
const imgsData: any = []
|
const imgsData: HTMLImageElement[] = []
|
||||||
const svgsData: any = []
|
const svgsData: HTMLImageElement[] = []
|
||||||
const fontLoaders: any = []
|
const fontLoaders: Promise<void>[] = []
|
||||||
const fontContent: any = {}
|
const fontContent: Record<string, string> = {}
|
||||||
let fontData: any = []
|
let fontData: string[] = []
|
||||||
widgets.forEach((item: any) => {
|
widgets.forEach((item: any) => {
|
||||||
if (item.fontClass && item.fontClass.value) {
|
if (item.fontClass && item.fontClass.value) {
|
||||||
const loader = new FontFaceObserver(item.fontClass.value)
|
const loader = new FontFaceObserver(item.fontClass.value)
|
||||||
@ -131,9 +140,7 @@ export default defineComponent({
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
!loadFlag && (window as any).loadFinishToInject('done')
|
!loadFlag && (window as any).loadFinishToInject('done')
|
||||||
}, 60000)
|
}, 60000)
|
||||||
},
|
}
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div id="page-design-index" ref="pageDesignIndex" class="page-design-bg-color">
|
<div id="page-design-index" ref="pageDesignIndex" class="page-design-bg-color">
|
||||||
<div :style="style" class="top-nav">
|
<div :style="state.style" class="top-nav">
|
||||||
<div class="top-nav-wrap">
|
<div class="top-nav-wrap">
|
||||||
<div class="top-left">
|
<div class="top-left">
|
||||||
<div class="name" @click="jump2home">{{ APP_NAME }}</div>
|
<div class="name" @click="jump2home">{{ state.APP_NAME }}</div>
|
||||||
<div class="operation">
|
<div class="operation">
|
||||||
<div :class="['operation-item', { disable: !undoable }]" @click="undoable ? handleHistory('undo') : ''"><i class="iconfont icon-undo" /></div>
|
<div :class="['operation-item', { disable: !undoable }]" @click="undoable ? handleHistory('undo') : ''"><i class="iconfont icon-undo" /></div>
|
||||||
<div :class="['operation-item', { disable: !redoable }]" @click="redoable ? handleHistory('redo') : ''"><i class="iconfont icon-redo" /></div>
|
<div :class="['operation-item', { disable: !redoable }]" @click="redoable ? handleHistory('redo') : ''"><i class="iconfont icon-redo" /></div>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<i style="font-size: 20px" class="icon sd-biaochi extra-operation" @click="changeLineGuides" />
|
<i style="font-size: 20px" class="icon sd-biaochi extra-operation" @click="changeLineGuides" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<HeaderOptions ref="options" v-model="isContinue" @change="optionsChange" />
|
<HeaderOptions ref="optionsRef" v-model="state.isContinue" @change="optionsChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="page-design-index-wrap">
|
<div class="page-design-index-wrap">
|
||||||
@ -34,28 +34,32 @@
|
|||||||
<style-panel></style-panel>
|
<style-panel></style-panel>
|
||||||
</div>
|
</div>
|
||||||
<!-- 标尺 -->
|
<!-- 标尺 -->
|
||||||
<line-guides :show="showLineGuides" />
|
<line-guides :show="state.showLineGuides" />
|
||||||
<!-- 缩放控制 -->
|
<!-- 缩放控制 -->
|
||||||
<zoom-control ref="zoomControl" />
|
<zoom-control ref="zoomControlRef" />
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<right-click-menu />
|
<right-click-menu />
|
||||||
<!-- 旋转缩放组件 -->
|
<!-- 旋转缩放组件 -->
|
||||||
<Moveable />
|
<Moveable />
|
||||||
<!-- 遮罩百分比进度条 -->
|
<!-- 遮罩百分比进度条 -->
|
||||||
<ProgressLoading
|
<ProgressLoading
|
||||||
:percent="downloadPercent"
|
:percent="state.downloadPercent"
|
||||||
:text="downloadText"
|
:text="state.downloadText"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
@cancel="downloadCancel"
|
@cancel="downloadCancel"
|
||||||
@done="downloadPercent = 0"
|
@done="state.downloadPercent = 0"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import _config from '../config'
|
import _config from '../config'
|
||||||
import { defineComponent, reactive, toRefs } from 'vue'
|
import {
|
||||||
import { mapActions, mapGetters } from 'vuex'
|
CSSProperties, computed, nextTick,
|
||||||
|
onBeforeUnmount, onMounted, reactive, ref,
|
||||||
|
getCurrentInstance
|
||||||
|
} from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
import RightClickMenu from '@/components/business/right-click-menu/RcMenu.vue'
|
import RightClickMenu from '@/components/business/right-click-menu/RcMenu.vue'
|
||||||
import Moveable from '@/components/business/moveable/Moveable.vue'
|
import Moveable from '@/components/business/moveable/Moveable.vue'
|
||||||
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
||||||
@ -66,28 +70,33 @@ import shortcuts from '@/mixins/shortcuts'
|
|||||||
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
||||||
import HeaderOptions from './components/HeaderOptions.vue'
|
import HeaderOptions from './components/HeaderOptions.vue'
|
||||||
import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
|
import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const beforeUnload = function (e: any) {
|
type TState = {
|
||||||
const confirmationMessage = '系统不会自动保存您未修改的内容'
|
style: CSSProperties
|
||||||
;(e || window.event).returnValue = confirmationMessage // Gecko and Trident
|
downloadPercent: number // 下载进度
|
||||||
|
downloadText: string
|
||||||
|
isContinue: boolean
|
||||||
|
APP_NAME: string
|
||||||
|
showLineGuides: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const beforeUnload = function (e: Event): string {
|
||||||
|
const confirmationMessage: string = '系统不会自动保存您未修改的内容';
|
||||||
|
|
||||||
|
(e || window.event).returnValue = (confirmationMessage as any) // Gecko and Trident
|
||||||
return confirmationMessage // Gecko and WebKit
|
return confirmationMessage // Gecko and WebKit
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
RightClickMenu,
|
|
||||||
Moveable,
|
|
||||||
HeaderOptions,
|
|
||||||
ProgressLoading,
|
|
||||||
designBoard,
|
|
||||||
zoomControl,
|
|
||||||
lineGuides,
|
|
||||||
},
|
|
||||||
// mixins: [shortcuts],
|
// mixins: [shortcuts],
|
||||||
setup() {
|
|
||||||
!_config.isDev && window.addEventListener('beforeunload', beforeUnload)
|
!_config.isDev && window.addEventListener('beforeunload', beforeUnload)
|
||||||
|
|
||||||
const state = reactive({
|
const {
|
||||||
|
dActiveElement, dHistoryParams, dCopyElement, dPage, dZoom
|
||||||
|
} = useSetupMapGetters(['dActiveElement', 'dHistoryParams', 'dCopyElement', 'dPage', 'dZoom'])
|
||||||
|
|
||||||
|
const state = reactive<TState>({
|
||||||
style: {
|
style: {
|
||||||
left: '0px',
|
left: '0px',
|
||||||
},
|
},
|
||||||
@ -98,93 +107,122 @@ export default defineComponent({
|
|||||||
APP_NAME: _config.APP_NAME,
|
APP_NAME: _config.APP_NAME,
|
||||||
showLineGuides: false,
|
showLineGuides: false,
|
||||||
})
|
})
|
||||||
|
const optionsRef = ref<typeof HeaderOptions | null>(null)
|
||||||
|
const zoomControlRef = ref<typeof zoomControl | null>(null)
|
||||||
|
const store = useStore()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
// const draw = () => {
|
// const draw = () => {
|
||||||
// state.openDraw = true
|
// state.openDraw = true
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function jump2home() {
|
function jump2home() {
|
||||||
// const fullPath = window.location.href.split('/')
|
// const fullPath = window.location.href.split('/')
|
||||||
// window.open(fullPath[0] + '//' + fullPath[2])
|
// window.open(fullPath[0] + '//' + fullPath[2])
|
||||||
window.open('https://xp.palxp.cn/')
|
window.open('https://xp.palxp.cn/')
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
...toRefs(state),
|
defineExpose({
|
||||||
jump2home,
|
jump2home,
|
||||||
}
|
})
|
||||||
},
|
|
||||||
computed: {
|
const undoable = computed(() => {
|
||||||
...mapGetters(['dActiveElement', 'dHistoryParams', 'dCopyElement', 'dPage', 'dZoom']),
|
return !(
|
||||||
undoable() {
|
dHistoryParams.value.index === -1 ||
|
||||||
return !(this.dHistoryParams.index === -1 || (this.dHistoryParams === 0 && this.dHistoryParams.length === this.dHistoryParams.maxLength))
|
(dHistoryParams.value === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
|
||||||
},
|
})
|
||||||
redoable() {
|
|
||||||
return !(this.dHistoryParams.index === this.dHistoryParams.length - 1)
|
const redoable = computed(() => {
|
||||||
},
|
return !(dHistoryParams.value.index === dHistoryParams.value.length - 1)
|
||||||
},
|
})
|
||||||
// watch: {
|
// watch: {
|
||||||
// $route() {
|
// $route() {
|
||||||
// console.log('change route', this.$route.query)
|
// console.log('change route', this.$route.query)
|
||||||
// this.loadData()
|
// this.loadData()
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
mounted() {
|
|
||||||
this.initGroupJson(JSON.stringify(wGroup.setting))
|
const { handleKeydowm, handleKeyup, dealCtrl } = shortcuts.methods
|
||||||
window.addEventListener('scroll', this.fixTopBarScroll)
|
let checkCtrl: number | undefined
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.dispatch('initGroupJson', JSON.stringify(wGroup.setting))
|
||||||
|
// initGroupJson(JSON.stringify(wGroup.setting))
|
||||||
|
window.addEventListener('scroll', fixTopBarScroll)
|
||||||
// window.addEventListener('click', this.clickListener)
|
// window.addEventListener('click', this.clickListener)
|
||||||
document.addEventListener('keydown', this.handleKeydowm, false)
|
const instance = getCurrentInstance()
|
||||||
document.addEventListener('keyup', this.handleKeyup, false)
|
document.addEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
|
||||||
this.loadData()
|
document.addEventListener('keyup', handleKeyup(store, checkCtrl), false)
|
||||||
},
|
loadData()
|
||||||
beforeUnmount() {
|
})
|
||||||
window.removeEventListener('scroll', this.fixTopBarScroll)
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('scroll', fixTopBarScroll)
|
||||||
|
const instance = getCurrentInstance()
|
||||||
// window.removeEventListener('click', this.clickListener)
|
// window.removeEventListener('click', this.clickListener)
|
||||||
document.removeEventListener('keydown', this.handleKeydowm, false)
|
document.removeEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
|
||||||
document.removeEventListener('keyup', this.handleKeyup, false)
|
document.removeEventListener('keyup', handleKeyup(store, checkCtrl), false)
|
||||||
document.oncontextmenu = null
|
document.oncontextmenu = null
|
||||||
},
|
})
|
||||||
methods: {
|
// ...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
|
||||||
...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
|
|
||||||
...shortcuts.methods,
|
function handleHistory(data: string) {
|
||||||
changeLineGuides() {
|
store.dispatch('handleHistory', data)
|
||||||
this.showLineGuides = !this.showLineGuides
|
}
|
||||||
},
|
|
||||||
downloadCancel() {
|
function changeLineGuides() {
|
||||||
this.downloadPercent = 0
|
state.showLineGuides = !state.showLineGuides
|
||||||
this.isContinue = false
|
}
|
||||||
},
|
|
||||||
loadData() {
|
function downloadCancel() {
|
||||||
|
state.downloadPercent = 0
|
||||||
|
state.isContinue = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
// 初始化加载页面
|
// 初始化加载页面
|
||||||
const { id, tempid, tempType } = this.$route.query
|
const { id, tempid, tempType } = route.query
|
||||||
;(this.$refs as any).options.load(id, tempid, tempType, async () => {
|
if (!optionsRef.value) return
|
||||||
;(this.$refs as any).zoomControl.screenChange()
|
optionsRef.value.load(id, tempid, tempType, async () => {
|
||||||
await this.$nextTick()
|
if (!zoomControlRef.value) return
|
||||||
|
zoomControlRef.value.screenChange()
|
||||||
|
await nextTick()
|
||||||
// 初始化激活的控件为page
|
// 初始化激活的控件为page
|
||||||
this.selectWidget({
|
store.dispatch('selectWidget', { uuid: '-1' })
|
||||||
uuid: '-1',
|
// selectWidget({
|
||||||
|
// uuid: '-1',
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
},
|
|
||||||
zoomSub() {
|
function zoomSub() {
|
||||||
;(this.$refs as any).zoomControl.sub()
|
if (!zoomControlRef.value) return
|
||||||
},
|
zoomControlRef.value.sub()
|
||||||
zoomAdd() {
|
}
|
||||||
;(this.$refs as any).zoomControl.add()
|
|
||||||
},
|
function zoomAdd() {
|
||||||
save() {
|
if (!zoomControlRef.value) return
|
||||||
;(this.$refs as any).options.save()
|
zoomControlRef.value.add()
|
||||||
},
|
}
|
||||||
fixTopBarScroll() {
|
|
||||||
|
function save() {
|
||||||
|
if (!optionsRef.value) return
|
||||||
|
optionsRef.value.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixTopBarScroll() {
|
||||||
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
|
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
|
||||||
this.style.left = `-${scrollLeft}px`
|
state.style.left = `-${scrollLeft}px`
|
||||||
},
|
}
|
||||||
clickListener(e: Event) {
|
|
||||||
|
function clickListener(e: Event) {
|
||||||
console.log('click listener', e)
|
console.log('click listener', e)
|
||||||
},
|
}
|
||||||
optionsChange({ downloadPercent, downloadText }: any) {
|
|
||||||
this.downloadPercent = downloadPercent
|
function optionsChange({ downloadPercent, downloadText }: { downloadPercent: number, downloadText: string }) {
|
||||||
this.downloadText = downloadText
|
state.downloadPercent = downloadPercent
|
||||||
},
|
state.downloadText = downloadText
|
||||||
},
|
}
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -12,10 +12,12 @@
|
|||||||
<div class="top-left">
|
<div class="top-left">
|
||||||
<div class="name" style="font-size: 15px">在线PSD解析</div>
|
<div class="name" style="font-size: 15px">在线PSD解析</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1"><el-button plain type="primary" @click="jump2word">说明文档及PSD规范</el-button></div>
|
<div style="flex: 1">
|
||||||
<el-button v-show="isDone" @click="clear">清空模板</el-button>
|
<el-button plain type="primary" @click="jump2word">说明文档及PSD规范</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button v-show="state.isDone" @click="clear">清空模板</el-button>
|
||||||
<div class="v-tips">
|
<div class="v-tips">
|
||||||
<HeaderOptions :isDone="isDone" @change="optionsChange" />
|
<HeaderOptions :isDone="state.isDone" @change="optionsChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -23,28 +25,38 @@
|
|||||||
<div class="page-design-index-wrap">
|
<div class="page-design-index-wrap">
|
||||||
<!-- <widget-panel></widget-panel> -->
|
<!-- <widget-panel></widget-panel> -->
|
||||||
<design-board class="page-design-wrap" pageDesignCanvasId="page-design-canvas">
|
<design-board class="page-design-wrap" pageDesignCanvasId="page-design-canvas">
|
||||||
<div v-if="isDone" class="shelter" :style="{ width: (dPage.width * dZoom) / 100 + 'px', height: (dPage.height * dZoom) / 100 + 'px' }"></div>
|
<div v-if="state.isDone" class="shelter" :style="{ width: (dPage.width * dZoom) / 100 + 'px', height: (dPage.height * dZoom) / 100 + 'px' }"></div>
|
||||||
<uploader v-else accept=".psd" :hold="true" :drag="true" class="uploader" @load="selectFile">
|
<uploader v-else accept=".psd" :hold="true" :drag="true" class="uploader" @load="selectFile">
|
||||||
<div class="uploader__box"><img style="margin-right: 1rem" src="https://cdn.dancf.com/design/svg/icon_psdimport.37e6f23e.svg" /> 在此拖入或选择PSD文件</div>
|
<div class="uploader__box">
|
||||||
|
<img
|
||||||
|
style="margin-right: 1rem"
|
||||||
|
src="https://cdn.dancf.com/design/svg/icon_psdimport.37e6f23e.svg"
|
||||||
|
alt="upload"
|
||||||
|
/> 在此拖入或选择PSD文件
|
||||||
|
</div>
|
||||||
</uploader>
|
</uploader>
|
||||||
</design-board>
|
</design-board>
|
||||||
<style-panel v-show="isDone"></style-panel>
|
<style-panel v-show="state.isDone"></style-panel>
|
||||||
</div>
|
</div>
|
||||||
<!-- 缩放控制 -->
|
<!-- 缩放控制 -->
|
||||||
<zoom-control v-if="isDone" ref="zoomControl" />
|
<zoom-control v-if="state.isDone" ref="zoomControlRef" />
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<right-click-menu />
|
<right-click-menu />
|
||||||
<!-- 旋转缩放组件 -->
|
<!-- 旋转缩放组件 -->
|
||||||
<Moveable />
|
<Moveable />
|
||||||
<!-- 遮罩百分比进度条 -->
|
<!-- 遮罩百分比进度条 -->
|
||||||
<ProgressLoading :percent="downloadPercent" :text="downloadText" :cancelText="cancelText" :msg="downloadMsg" @cancel="cancel" @done="downloadPercent = 0" />
|
<ProgressLoading
|
||||||
|
:percent="state.downloadPercent" :text="state.downloadText"
|
||||||
|
:cancelText="state.cancelText" :msg="state.downloadMsg"
|
||||||
|
@cancel="cancel" @done="state.downloadPercent = 0"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, onMounted, nextTick } from 'vue'
|
import { reactive, onMounted, nextTick, onBeforeMount, ref, getCurrentInstance } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { mapActions, mapGetters, useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import RightClickMenu from '@/components/business/right-click-menu/RcMenu.vue'
|
import RightClickMenu from '@/components/business/right-click-menu/RcMenu.vue'
|
||||||
import Moveable from '@/components/business/moveable/Moveable.vue'
|
import Moveable from '@/components/business/moveable/Moveable.vue'
|
||||||
import shortcuts from '@/mixins/shortcuts'
|
import shortcuts from '@/mixins/shortcuts'
|
||||||
@ -54,16 +66,22 @@ import useLoading from '@/common/methods/loading'
|
|||||||
import uploader from '@/components/common/Uploader/index.vue'
|
import uploader from '@/components/common/Uploader/index.vue'
|
||||||
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
import designBoard from '@/components/modules/layout/designBoard/index.vue'
|
||||||
import zoomControl from '@/components/modules/layout/zoomControl/index.vue'
|
import zoomControl from '@/components/modules/layout/zoomControl/index.vue'
|
||||||
import HeaderOptions from './components/UploadTemplate.vue'
|
import HeaderOptions, { TEmitChangeData } from './components/UploadTemplate.vue'
|
||||||
import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
|
import ProgressLoading from '@/components/common/ProgressLoading/index.vue'
|
||||||
// import MyWorker from '@/utils/plugins/webWorker'
|
// import MyWorker from '@/utils/plugins/webWorker'
|
||||||
import { processPSD2Page } from '@/utils/plugins/psd'
|
import { processPSD2Page } from '@/utils/plugins/psd'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
|
||||||
export default defineComponent({
|
type TState = {
|
||||||
components: { RightClickMenu, Moveable, uploader, designBoard, zoomControl, HeaderOptions, ProgressLoading },
|
isDone: boolean
|
||||||
mixins: [shortcuts],
|
downloadPercent: number // 下载进度
|
||||||
setup() {
|
downloadText: string
|
||||||
const state = reactive({
|
downloadMsg: string
|
||||||
|
cancelText: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// mixins: [shortcuts],
|
||||||
|
const state = reactive<TState>({
|
||||||
isDone: true,
|
isDone: true,
|
||||||
downloadPercent: 0, // 下载进度
|
downloadPercent: 0, // 下载进度
|
||||||
downloadText: '',
|
downloadText: '',
|
||||||
@ -72,12 +90,18 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
|
||||||
let loading: any = null
|
const { dPage, dZoom } = useSetupMapGetters(['dPage', 'dZoom'])
|
||||||
|
const zoomControlRef = ref<typeof zoomControl | null>()
|
||||||
|
|
||||||
|
let loading: ReturnType<typeof useLoading> | null = null
|
||||||
// const myWorker = new MyWorker('loadPSD')
|
// const myWorker = new MyWorker('loadPSD')
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
if (zoomControlRef.value){
|
||||||
|
zoomControlRef.value.screenChange()
|
||||||
|
}
|
||||||
state.isDone = false
|
state.isDone = false
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -86,13 +110,15 @@ export default defineComponent({
|
|||||||
link_element.setAttribute('src', '/psd.js')
|
link_element.setAttribute('src', '/psd.js')
|
||||||
document.head.appendChild(link_element)
|
document.head.appendChild(link_element)
|
||||||
}
|
}
|
||||||
async function selectFile(file: any) {
|
|
||||||
|
async function selectFile(file: File) {
|
||||||
loading = useLoading()
|
loading = useLoading()
|
||||||
await loadPSD(file)
|
await loadPSD(file)
|
||||||
loading.close()
|
loading.close()
|
||||||
state.isDone = true
|
state.isDone = true
|
||||||
}
|
}
|
||||||
async function loadPSD(file: any) {
|
|
||||||
|
async function loadPSD(file: File) {
|
||||||
// const { compositeBuffer, psdFile } = await myWorker.start(file)
|
// const { compositeBuffer, psdFile } = await myWorker.start(file)
|
||||||
const data = await processPSD2Page(file)
|
const data = await processPSD2Page(file)
|
||||||
|
|
||||||
@ -111,7 +137,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const { width, height, background: bg } = data
|
const { width, height, background: bg } = data
|
||||||
store.commit('setDPage', Object.assign(store.getters.dPage, { width, height, backgroundColor: bg.color, backgroundImage: bg.image }))
|
store.commit('setDPage', Object.assign(store.getters.dPage, { width, height, backgroundColor: bg.color, backgroundImage: bg.image }))
|
||||||
await proxy?.loadDone()
|
await loadDone()
|
||||||
}, 10)
|
}, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,56 +149,62 @@ export default defineComponent({
|
|||||||
state.isDone = false
|
state.isDone = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionsChange = ({ downloadPercent, downloadText, downloadMsg = '', cancelText = '' }: any) => {
|
const optionsChange = ({ downloadPercent, downloadText, downloadMsg = '', cancelText = '' }: TEmitChangeData) => {
|
||||||
typeof downloadPercent === 'number' && (state.downloadPercent = downloadPercent)
|
typeof downloadPercent === 'number' && (state.downloadPercent = downloadPercent)
|
||||||
state.downloadText = downloadText
|
state.downloadText = downloadText
|
||||||
state.downloadMsg = downloadMsg
|
state.downloadMsg = downloadMsg
|
||||||
state.cancelText = cancelText
|
state.cancelText = cancelText
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
state.downloadPercent = 100
|
state.downloadPercent = 100
|
||||||
window.open(`${window.location.protocol + '//' + window.location.host}/home?id=${route.query.id}`)
|
window.open(`${window.location.protocol + '//' + window.location.host}/home?id=${route.query.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const {handleKeydowm, handleKeyup, dealCtrl} = shortcuts.methods
|
||||||
...toRefs(state),
|
|
||||||
|
// ...mapGetters(['dPage', 'dZoom']),
|
||||||
|
|
||||||
|
let checkCtrl: number | undefined
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const instance = getCurrentInstance()
|
||||||
|
document.addEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
|
||||||
|
document.addEventListener('keyup', handleKeyup(store, checkCtrl), false)
|
||||||
|
loadJS()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const instance = getCurrentInstance()
|
||||||
|
document.removeEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
|
||||||
|
document.removeEventListener('keyup', handleKeyup(store, checkCtrl), false)
|
||||||
|
document.oncontextmenu = null
|
||||||
|
})
|
||||||
|
// ...mapActions(['selectWidget']),
|
||||||
|
|
||||||
|
async function loadDone() {
|
||||||
|
await nextTick()
|
||||||
|
if (!zoomControlRef.value) return
|
||||||
|
zoomControlRef.value.screenChange()
|
||||||
|
setTimeout(() => {
|
||||||
|
store.dispatch('selectWidget', { uuid: '-1' })
|
||||||
|
// selectWidget({
|
||||||
|
// uuid: '-1',
|
||||||
|
// })
|
||||||
|
// this.$store.commit('setShowMoveable', false)
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
function jump2word() {
|
||||||
|
window.open('https://xp.palxp.cn/#/articles/1687855172725')
|
||||||
|
// window.open('https://kdocs.cn/l/clmBsIkhve8d')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
loadJS,
|
loadJS,
|
||||||
selectFile,
|
selectFile,
|
||||||
clear,
|
clear,
|
||||||
cancel,
|
cancel,
|
||||||
optionsChange,
|
optionsChange,
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(['dPage', 'dZoom']),
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
document.addEventListener('keydown', this.handleKeydowm, false)
|
|
||||||
document.addEventListener('keyup', this.handleKeyup, false)
|
|
||||||
this.loadJS()
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
document.removeEventListener('keydown', this.handleKeydowm, false)
|
|
||||||
document.removeEventListener('keyup', this.handleKeyup, false)
|
|
||||||
document.oncontextmenu = null
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(['selectWidget']),
|
|
||||||
async loadDone() {
|
|
||||||
await this.$nextTick()
|
|
||||||
;(this.$refs as any).zoomControl.screenChange()
|
|
||||||
setTimeout(() => {
|
|
||||||
this.selectWidget({
|
|
||||||
uuid: '-1',
|
|
||||||
})
|
|
||||||
// this.$store.commit('setShowMoveable', false)
|
|
||||||
}, 100)
|
|
||||||
},
|
|
||||||
jump2word() {
|
|
||||||
window.open('https://xp.palxp.cn/#/articles/1687855172725')
|
|
||||||
// window.open('https://kdocs.cn/l/clmBsIkhve8d')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -13,19 +13,10 @@
|
|||||||
</tool-tip>
|
</tool-tip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import toolTip from '@/components/common/PopoverTip.vue'
|
import toolTip from '@/components/common/PopoverTip.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { toolTip },
|
|
||||||
setup() {
|
|
||||||
const content = '本站为个人项目,所使用素材图片等均为网络收集而来,下载之作品仅供学习研究或欣赏目的而使用,无法提供商用授权哦。'
|
const content = '本站为个人项目,所使用素材图片等均为网络收集而来,下载之作品仅供学习研究或欣赏目的而使用,无法提供商用授权哦。'
|
||||||
return {
|
|
||||||
content,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
* @LastEditTime: 2023-12-11 12:40:59
|
* @LastEditTime: 2023-12-11 12:40:59
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="top-title"><el-input v-model="title" placeholder="未命名的设计" class="input-wrap" /></div>
|
<div class="top-title"><el-input v-model="state.title" placeholder="未命名的设计" class="input-wrap" /></div>
|
||||||
<div class="top-icon-wrap">
|
<div class="top-icon-wrap">
|
||||||
<template v-if="tempEditing">
|
<template v-if="tempEditing">
|
||||||
<span style="color: #999; font-size: 14px; margin-right: 0.5rem">{{ stateBollean ? '启用' : '停用' }}</span> <el-switch v-model="stateBollean" @change="stateChange" />
|
<span style="color: #999; font-size: 14px; margin-right: 0.5rem">{{ state.stateBollean ? '启用' : '停用' }}</span> <el-switch v-model="state.stateBollean" @change="stateChange" />
|
||||||
<div class="divide__line">|</div>
|
<div class="divide__line">|</div>
|
||||||
<el-button plain type="primary" @click="saveTemp">保存模板</el-button>
|
<el-button plain type="primary" @click="saveTemp">保存模板</el-button>
|
||||||
<el-button @click="$store.commit('managerEdit', false)">取消</el-button>
|
<el-button @click="$store.commit('managerEdit', false)">取消</el-button>
|
||||||
@ -18,16 +18,16 @@
|
|||||||
<!-- <el-button @click="draw">绘制(测试)</el-button> -->
|
<!-- <el-button @click="draw">绘制(测试)</el-button> -->
|
||||||
<el-button size="large" class="primary-btn" :disabled="tempEditing" @click="save(false)">保存</el-button>
|
<el-button size="large" class="primary-btn" :disabled="tempEditing" @click="save(false)">保存</el-button>
|
||||||
<copyRight>
|
<copyRight>
|
||||||
<el-button :loading="loading" size="large" class="primary-btn" :disabled="tempEditing" plain type="primary" @click="download">下载作品</el-button>
|
<el-button :loading="state.loading" size="large" class="primary-btn" :disabled="tempEditing" plain type="primary" @click="download">下载作品</el-button>
|
||||||
</copyRight>
|
</copyRight>
|
||||||
</div>
|
</div>
|
||||||
<!-- 生成图片组件 -->
|
<!-- 生成图片组件 -->
|
||||||
<SaveImage ref="canvasImage" />
|
<SaveImage ref="canvasImage" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { defineComponent, reactive, toRefs, getCurrentInstance, ComponentInternalInstance } from 'vue'
|
import { reactive, toRefs, defineEmits, defineProps, ref } from 'vue'
|
||||||
import { mapGetters, mapActions, useStore } from 'vuex'
|
import { mapGetters, mapActions, useStore } from 'vuex'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import _dl from '@/common/methods/download'
|
import _dl from '@/common/methods/download'
|
||||||
@ -38,17 +38,34 @@ import copyRight from './CopyRight.vue'
|
|||||||
import _config from '@/config'
|
import _config from '@/config'
|
||||||
import useConfirm from '@/common/methods/confirm'
|
import useConfirm from '@/common/methods/confirm'
|
||||||
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
|
||||||
export default defineComponent({
|
type TProps = {
|
||||||
components: { copyRight, SaveImage },
|
modelValue?: boolean
|
||||||
props: ['modelValue'],
|
}
|
||||||
emits: ['change', 'update:modelValue'],
|
|
||||||
setup(props, context) {
|
type TEmits = {
|
||||||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
(event: 'change', data: {downloadPercent: number, downloadText: string}): void
|
||||||
|
(event: 'update:modelValue', data: boolean): void
|
||||||
|
}
|
||||||
|
|
||||||
|
type TState= {
|
||||||
|
stateBollean: boolean,
|
||||||
|
title: string,
|
||||||
|
loading: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<TProps>()
|
||||||
|
const emit = defineEmits<TEmits>()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const state = reactive({
|
const canvasImage = ref<typeof SaveImage | null>(null)
|
||||||
|
const {
|
||||||
|
dPage, dWidgets, tempEditing, dHistory, dPageHistory
|
||||||
|
} = useSetupMapGetters(['dPage', 'dWidgets', 'tempEditing', 'dHistory', 'dPageHistory'])
|
||||||
|
|
||||||
|
const state = reactive<TState>({
|
||||||
stateBollean: false,
|
stateBollean: false,
|
||||||
title: '',
|
title: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -57,43 +74,45 @@ export default defineComponent({
|
|||||||
// 保存作品
|
// 保存作品
|
||||||
async function save(hasCover: boolean = false) {
|
async function save(hasCover: boolean = false) {
|
||||||
// Bugs: 历史操作有问题,且page操作未及时入栈 proxy?.dPageHistory
|
// Bugs: 历史操作有问题,且page操作未及时入栈 proxy?.dPageHistory
|
||||||
if (proxy?.dHistory.length <= 0) {
|
if (dHistory.value.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||||
// console.log(proxy?.dPage, proxy?.dWidgets)
|
// console.log(proxy?.dPage, proxy?.dWidgets)
|
||||||
const { id, tempid } = route.query
|
const { id, tempid } = route.query
|
||||||
const cover = hasCover ? await proxy?.draw() : undefined
|
const cover = hasCover ? await draw() : undefined
|
||||||
const widgets = proxy.dWidgets // reviseData()
|
const widgets = dWidgets.value // reviseData()
|
||||||
const { id: newId, stat, msg } = await api.home.saveWorks({ cover, id, title: proxy.title || '未命名设计', data: JSON.stringify({ page: proxy.dPage, widgets }), temp_id: tempid, width: proxy.dPage.width, height: proxy.dPage.height })
|
const { id: newId, stat, msg } = await api.home.saveWorks({ cover, id, title: state.title || '未命名设计', data: JSON.stringify({ page: dPage.value, widgets }), temp_id: tempid, width: dPage.value.width, height: dPage.value.height })
|
||||||
stat !== 0 ? useNotification('保存成功', '可在"我的作品"中查看') : useNotification('保存失败', msg, { type: 'error' })
|
stat !== 0 ? useNotification('保存成功', '可在"我的作品"中查看') : useNotification('保存失败', msg, { type: 'error' })
|
||||||
!id && router.push({ path: '/home', query: { id: newId }, replace: true })
|
!id && router.push({ path: '/home', query: { id: newId }, replace: true })
|
||||||
store.commit('setShowMoveable', true)
|
store.commit('setShowMoveable', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
async function saveTemp() {
|
async function saveTemp() {
|
||||||
const { tempid, tempType: type } = route.query
|
const { tempid, tempType: type } = route.query
|
||||||
let res = null
|
let res = null
|
||||||
if (type == 1) {
|
if (Number(type) == 1) {
|
||||||
// 保存组件,组合元素要保证在最后一位,才能默认选中
|
// 保存组件,组合元素要保证在最后一位,才能默认选中
|
||||||
if (proxy.dWidgets[0].type === 'w-group') {
|
if (dWidgets.value[0].type === 'w-group') {
|
||||||
const group = proxy.dWidgets.shift()
|
const group = dWidgets.value.shift()
|
||||||
group.record.width = 0
|
group.record.width = 0
|
||||||
group.record.height = 0
|
group.record.height = 0
|
||||||
proxy.dWidgets.push(group)
|
dWidgets.value.push(group)
|
||||||
}
|
}
|
||||||
// TODO:如果保存组件不存在组合,则添加组合。该功能待优化
|
// TODO:如果保存组件不存在组合,则添加组合。该功能待优化
|
||||||
if (!proxy.dWidgets.some((x) => x.type === 'w-group')) {
|
if (!dWidgets.value.some((x: Record<string, any>) => x.type === 'w-group')) {
|
||||||
alert('提交组件必须为组合!')
|
alert('提交组件必须为组合!')
|
||||||
return
|
return
|
||||||
// proxy.dWidgets.push(wGroup.setting)
|
// proxy.dWidgets.push(wGroup.setting)
|
||||||
}
|
}
|
||||||
res = await api.home.saveTemp({ id: tempid, type, title: proxy.title || '未命名组件', content: JSON.stringify(proxy.dWidgets), width: proxy.dPage.width, height: proxy.dPage.height })
|
res = await api.home.saveTemp({ id: tempid, type, title: state.title || '未命名组件', content: JSON.stringify(dWidgets.value), width: dPage.value.width, height: dPage.value.height })
|
||||||
} else res = await api.home.saveTemp({ id: tempid, title: proxy.title || '未命名模板', content: JSON.stringify({ page: proxy.dPage, widgets: proxy.dWidgets }), width: proxy.dPage.width, height: proxy.dPage.height })
|
} else res = await api.home.saveTemp({ id: tempid, title: state.title || '未命名模板', content: JSON.stringify({ page: dPage.value, widgets: dWidgets.value }), width: dPage.value.width, height: dPage.value.height })
|
||||||
res.stat != 0 && useNotification('保存成功', '模板内容已变更')
|
res.stat != 0 && useNotification('保存成功', '模板内容已变更')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停用启用
|
// 停用启用
|
||||||
async function stateChange(e: any) {
|
async function stateChange(e: string | number | boolean) {
|
||||||
const { tempid, tempType: type } = route.query
|
const { tempid, tempType: type } = route.query
|
||||||
const { stat } = await api.home.saveTemp({ id: tempid, type, state: e ? 1 : 0 })
|
const { stat } = await api.home.saveTemp({ id: tempid, type, state: e ? 1 : 0 })
|
||||||
stat != 0 && useNotification('保存成功', '模板内容已变更')
|
stat != 0 && useNotification('保存成功', '模板内容已变更')
|
||||||
@ -103,28 +122,28 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 临时提示
|
// 临时提示
|
||||||
if (proxy.title === '自设计模板') {
|
if (state.title === '自设计模板') {
|
||||||
const isPass = await useConfirm('提示', 'PSD自设计作品暂时保存在Github,下载可能失败', 'warning')
|
const isPass = await useConfirm('提示', 'PSD自设计作品暂时保存在Github,下载可能失败', 'warning')
|
||||||
if (!isPass) {
|
if (!isPass) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.loading = true
|
state.loading = true
|
||||||
context.emit('update:modelValue', true)
|
emit('update:modelValue', true)
|
||||||
context.emit('change', { downloadPercent: 1, downloadText: '正在处理封面' })
|
emit('change', { downloadPercent: 1, downloadText: '正在处理封面' })
|
||||||
await save(true)
|
await save(true)
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const { id } = route.query
|
const { id } = route.query
|
||||||
if (id) {
|
if (id) {
|
||||||
const { width, height } = proxy.dPage
|
const { width, height } = dPage.value
|
||||||
context.emit('update:modelValue', true)
|
emit('update:modelValue', true)
|
||||||
context.emit('change', { downloadPercent: 1, downloadText: '准备合成图片' })
|
emit('change', { downloadPercent: 1, downloadText: '准备合成图片' })
|
||||||
state.loading = false
|
state.loading = false
|
||||||
let timerCount = 0
|
let timerCount = 0
|
||||||
const animation = setInterval(() => {
|
const animation = setInterval(() => {
|
||||||
if (props.modelValue && timerCount < 75) {
|
if (props.modelValue && timerCount < 75) {
|
||||||
timerCount += RandomNumber(1, 10)
|
timerCount += RandomNumber(1, 10)
|
||||||
context.emit('change', { downloadPercent: 1 + timerCount, downloadText: '正在合成图片' })
|
emit('change', { downloadPercent: 1 + timerCount, downloadText: '正在合成图片' })
|
||||||
} else {
|
} else {
|
||||||
clearInterval(animation)
|
clearInterval(animation)
|
||||||
}
|
}
|
||||||
@ -132,12 +151,12 @@ export default defineComponent({
|
|||||||
await _dl.downloadImg(api.home.download({ id, width, height }) + '&r=' + Math.random(), (progress: number, xhr: any) => {
|
await _dl.downloadImg(api.home.download({ id, width, height }) + '&r=' + Math.random(), (progress: number, xhr: any) => {
|
||||||
if (props.modelValue) {
|
if (props.modelValue) {
|
||||||
clearInterval(animation)
|
clearInterval(animation)
|
||||||
progress >= timerCount && context.emit('change', { downloadPercent: Number(progress.toFixed(0)), downloadText: '图片生成中' })
|
progress >= timerCount && emit('change', { downloadPercent: Number(progress.toFixed(0)), downloadText: '图片生成中' })
|
||||||
} else {
|
} else {
|
||||||
xhr.abort()
|
xhr.abort()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
context.emit('change', { downloadPercent: 100, downloadText: '图片下载中' })
|
emit('change', { downloadPercent: 100, downloadText: '图片下载中' })
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
@ -145,21 +164,10 @@ export default defineComponent({
|
|||||||
return Math.ceil(Math.random() * (max - min)) + min
|
return Math.ceil(Math.random() * (max - min)) + min
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// ...mapActions(['pushHistory', 'addGroup']),
|
||||||
...toRefs(state),
|
|
||||||
download,
|
async function load(id: number, tempId: number, type: number, cb: () => void) {
|
||||||
save,
|
if (route.name !== 'Draw') {
|
||||||
saveTemp,
|
|
||||||
stateChange,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(['dPage', 'dWidgets', 'tempEditing', 'dHistory', 'dPageHistory']),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(['pushHistory', 'addGroup']),
|
|
||||||
async load(id: any, tempId: any, type: any, cb: Function) {
|
|
||||||
if (this.$route.name !== 'Draw') {
|
|
||||||
await useFontStore.init() // 初始化加载字体
|
await useFontStore.init() // 初始化加载字体
|
||||||
}
|
}
|
||||||
const apiName = tempId && !id ? 'getTempDetail' : 'getWorks'
|
const apiName = tempId && !id ? 'getTempDetail' : 'getWorks'
|
||||||
@ -170,31 +178,43 @@ export default defineComponent({
|
|||||||
const { data: content, title, state, width, height } = await api.home[apiName]({ id: id || tempId, type })
|
const { data: content, title, state, width, height } = await api.home[apiName]({ id: id || tempId, type })
|
||||||
if (content) {
|
if (content) {
|
||||||
const data = JSON.parse(content)
|
const data = JSON.parse(content)
|
||||||
this.stateBollean = !!state
|
state.stateBollean = !!state
|
||||||
this.title = title
|
state.title = title
|
||||||
this.$store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||||
// this.$store.commit('setDWidgets', [])
|
// this.$store.commit('setDWidgets', [])
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
// 加载文字组合组件
|
// 加载文字组合组件
|
||||||
this.dPage.width = width
|
dPage.value.width = width
|
||||||
this.dPage.height = height
|
dPage.value.height = height
|
||||||
this.addGroup(data)
|
store.dispatch('addGroup', data)
|
||||||
|
// addGroup(data)
|
||||||
} else {
|
} else {
|
||||||
this.$store.commit('setDPage', data.page)
|
store.commit('setDPage', data.page)
|
||||||
id ? this.$store.commit('setDWidgets', data.widgets) : this.$store.dispatch('setTemplate', data.widgets)
|
id ? store.commit('setDWidgets', data.widgets) : store.dispatch('setTemplate', data.widgets)
|
||||||
}
|
}
|
||||||
cb()
|
cb()
|
||||||
this.pushHistory('请求加载load')
|
store.dispatch('pushHistory', '请求加载load')
|
||||||
|
// pushHistory('请求加载load')
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
draw() {
|
|
||||||
|
function draw() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.$refs.canvasImage.createCover(({ key }) => {
|
if (!canvasImage.value) resolve('')
|
||||||
|
else {
|
||||||
|
canvasImage.value.createCover(({ key }: {key: string}) => {
|
||||||
resolve(_config.IMG_URL + key)
|
resolve(_config.IMG_URL + key)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
},
|
|
||||||
|
defineExpose({
|
||||||
|
download,
|
||||||
|
save,
|
||||||
|
saveTemp,
|
||||||
|
stateChange,
|
||||||
|
load,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -11,31 +11,55 @@
|
|||||||
<SaveImage ref="canvasImage" />
|
<SaveImage ref="canvasImage" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { defineComponent, reactive, toRefs, getCurrentInstance, ComponentInternalInstance } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { mapGetters, useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import useNotification from '@/common/methods/notification'
|
import useNotification from '@/common/methods/notification'
|
||||||
import SaveImage from '@/components/business/save-download/CreateCover.vue'
|
import SaveImage from '@/components/business/save-download/CreateCover.vue'
|
||||||
import { useFontStore } from '@/common/methods/fonts'
|
import { useFontStore } from '@/common/methods/fonts'
|
||||||
import _config from '@/config'
|
import _config from '@/config'
|
||||||
import github from '@/api/github'
|
import github from '@/api/github'
|
||||||
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||||
|
|
||||||
export default defineComponent({
|
type TProps = {
|
||||||
components: { SaveImage },
|
modelValue?: string
|
||||||
props: ['modelValue', 'isDone'],
|
isDone?: boolean
|
||||||
emits: ['change', 'update:modelValue'],
|
}
|
||||||
setup(props, context) {
|
|
||||||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
export type TEmitChangeData = {
|
||||||
const route = useRoute()
|
downloadPercent: number | null
|
||||||
const router = useRouter()
|
downloadText: string
|
||||||
const store = useStore()
|
downloadMsg?: string
|
||||||
const state: any = reactive({
|
cancelText?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TEmits = {
|
||||||
|
(event: 'change', data: TEmitChangeData): void
|
||||||
|
(event: 'update:modelValue', data: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
type TState = {
|
||||||
|
stateBollean: false,
|
||||||
|
title: '',
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { dPage, dWidgets } = useSetupMapGetters(['dPage', 'dWidgets'])
|
||||||
|
|
||||||
|
const props = defineProps<TProps>()
|
||||||
|
const emit = defineEmits<TEmits>()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const canvasImage = ref<typeof SaveImage | null>(null)
|
||||||
|
const state = reactive<TState>({
|
||||||
stateBollean: false,
|
stateBollean: false,
|
||||||
title: '',
|
title: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
canvasImage: null,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
useFontStore.init() // 初始化加载字体
|
useFontStore.init() // 初始化加载字体
|
||||||
@ -43,28 +67,32 @@ export default defineComponent({
|
|||||||
// 生成封面
|
// 生成封面
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
state.canvasImage.createCover(({ key }: any) => {
|
if (!canvasImage.value) {
|
||||||
|
resolve('')
|
||||||
|
} else {
|
||||||
|
canvasImage.value.createCover(({ key }: { key: string }) => {
|
||||||
resolve(_config.IMG_URL + key)
|
resolve(_config.IMG_URL + key)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let addition = 0 // 累加大小
|
let addition = 0 // 累加大小
|
||||||
let lenCount = 0 // 全部大小
|
let lenCount = 0 // 全部大小
|
||||||
let lens = 0 // 任务数
|
let lens = 0 // 任务数
|
||||||
const queue: any[] = [] // 队列
|
const queue: { type: string, imgUrl: string }[] = [] // 队列
|
||||||
let widgets: any = []
|
let widgets: { type: string, imgUrl: string }[] = []
|
||||||
let page: any = {}
|
let page: Record<string, any> = {}
|
||||||
|
|
||||||
async function prepare() {
|
async function prepare() {
|
||||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||||
addition = 0
|
addition = 0
|
||||||
lenCount = 0
|
lenCount = 0
|
||||||
widgets = proxy.dWidgets
|
widgets = dWidgets.value
|
||||||
page = proxy.dPage
|
page = dPage.value
|
||||||
|
|
||||||
if (page.backgroundImage) {
|
if (page.backgroundImage) {
|
||||||
context.emit('change', { downloadPercent: 1, downloadText: '正在准备上传', downloadMsg: '请等待..' })
|
emit('change', { downloadPercent: 1, downloadText: '正在准备上传', downloadMsg: '请等待..' })
|
||||||
page.backgroundImage = await github.putPic(page.backgroundImage.split(',')[1])
|
page.backgroundImage = await github.putPic(page.backgroundImage.split(',')[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,11 +109,12 @@ export default defineComponent({
|
|||||||
async function uploadImgs() {
|
async function uploadImgs() {
|
||||||
if (queue.length > 0) {
|
if (queue.length > 0) {
|
||||||
const item = queue.pop()
|
const item = queue.pop()
|
||||||
|
if (!item) return
|
||||||
const url = await github.putPic(item.imgUrl.split(',')[1])
|
const url = await github.putPic(item.imgUrl.split(',')[1])
|
||||||
addition += item.imgUrl.length
|
addition += item.imgUrl.length
|
||||||
let downloadPercent: any = (addition / lenCount) * 100
|
let downloadPercent: number | null = (addition / lenCount) * 100
|
||||||
downloadPercent >= 100 && (downloadPercent = null)
|
downloadPercent >= 100 && (downloadPercent = null)
|
||||||
context.emit('change', { downloadPercent, downloadText: '上传资源中', downloadMsg: `已完成:${lens - queue.length} / ${lens}` })
|
emit('change', { downloadPercent, downloadText: '上传资源中', downloadMsg: `已完成:${lens - queue.length} / ${lens}` })
|
||||||
item.imgUrl = url
|
item.imgUrl = url
|
||||||
uploadImgs()
|
uploadImgs()
|
||||||
} else {
|
} else {
|
||||||
@ -94,22 +123,16 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uploadTemplate = async () => {
|
const uploadTemplate = async () => {
|
||||||
context.emit('change', { downloadPercent: 95, downloadText: '正在处理封面', downloadMsg: '即将结束...' })
|
emit('change', { downloadPercent: 95, downloadText: '正在处理封面', downloadMsg: '即将结束...' })
|
||||||
const cover = await draw()
|
const cover = await draw()
|
||||||
const { id, stat, msg } = await api.home.saveWorks({ cover, title: '自设计模板', data: JSON.stringify({ page, widgets }), width: page.width, height: page.height })
|
const { id, stat, msg } = await api.home.saveWorks({ cover, title: '自设计模板', data: JSON.stringify({ page, widgets }), width: page.width, height: page.height })
|
||||||
stat !== 0 ? useNotification('保存成功', '可在"我的模板"中查看') : useNotification('保存失败', msg, { type: 'error' })
|
stat !== 0 ? useNotification('保存成功', '可在"我的模板"中查看') : useNotification('保存失败', msg, { type: 'error' })
|
||||||
router.push({ path: '/psd', query: { id }, replace: true })
|
router.push({ path: '/psd', query: { id }, replace: true })
|
||||||
context.emit('change', { downloadPercent: 99.99, downloadText: '上传完成', cancelText: '查看我的作品' }) // 关闭弹窗
|
emit('change', { downloadPercent: 99.99, downloadText: '上传完成', cancelText: '查看我的作品' }) // 关闭弹窗
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
defineExpose({
|
||||||
...toRefs(state),
|
|
||||||
prepare,
|
prepare,
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(['dPage', 'dWidgets']),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user