Merge pull request #72 from JeremyYu-cn/feat-upgrade-vue3

Feat: Convert views and components to composition API
This commit is contained in:
Jeremy Yu 2024-03-07 16:35:05 +00:00 committed by GitHub
commit db962af514
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 1009 additions and 844 deletions

View File

@ -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",

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

@ -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
} }

View File

@ -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 = {

View File

@ -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 = {

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

@ -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)
}) })

View File

@ -30,7 +30,7 @@ export type TClassHeaderTypeData = {
type TProps = { type TProps = {
types: TClassHeaderTypeData[] types: TClassHeaderTypeData[]
isBack: boolean isBack?: boolean
} }
type TEmits = { type TEmits = {

View File

@ -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)

View File

@ -37,7 +37,7 @@ import api from '@/api'
type TProps = { type TProps = {
type?: string type?: string
modelValue: string modelValue?: string
} }
type TEmits = { type TEmits = {

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

@ -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,
}) })

View File

@ -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)
}, },
}, },

View File

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

View File

@ -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'
export default defineComponent({ type TState = {
components: { designBoard, zoomControl }, style: StyleValue
// mixins: [shortcuts], }
setup() {
const state = reactive({ // mixins: [shortcuts],
const store = useStore()
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']), // ...mapActions(['initGroupJson', 'setTemplate', 'addGroup']),
async load() { async function load() {
let loadFlag = false let loadFlag = false
const { id, tempid, tempType: type } = this.$route.query const { id, tempid, tempType: type } = route.query
if (id || tempid) { if (id || tempid) {
const { data, width, height } = await api.home[id ? 'getWorks' : 'getTempDetail']({ id: id || tempid, type }) 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 content = JSON.parse(data)
const widgets = type == 1 ? content : content.widgets const widgets = Number(type) == 1 ? content : content.widgets
if (type == 1) { if (Number(type) == 1) {
this.dPage.width = width dPage.value.width = width
this.dPage.height = height dPage.value.height = height
this.dPage.backgroundColor = '#ffffff00' dPage.value.backgroundColor = '#ffffff00'
this.addGroup(content) 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>

View File

@ -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({ // mixins: [shortcuts],
components: { !_config.isDev && window.addEventListener('beforeunload', beforeUnload)
RightClickMenu,
Moveable,
HeaderOptions,
ProgressLoading,
designBoard,
zoomControl,
lineGuides,
},
// mixins: [shortcuts],
setup() {
!_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',
}, },
@ -97,94 +106,123 @@ export default defineComponent({
isContinue: true, isContinue: true,
APP_NAME: _config.APP_NAME, APP_NAME: _config.APP_NAME,
showLineGuides: false, showLineGuides: false,
}) })
// const draw = () => { const optionsRef = ref<typeof HeaderOptions | null>(null)
// state.openDraw = true const zoomControlRef = ref<typeof zoomControl | null>(null)
// } const store = useStore()
function jump2home() { const route = useRoute()
// const draw = () => {
// state.openDraw = true
// }
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: {
...mapGetters(['dActiveElement', 'dHistoryParams', 'dCopyElement', 'dPage', 'dZoom']),
undoable() {
return !(this.dHistoryParams.index === -1 || (this.dHistoryParams === 0 && this.dHistoryParams.length === this.dHistoryParams.maxLength))
},
redoable() {
return !(this.dHistoryParams.index === this.dHistoryParams.length - 1)
},
},
// watch: {
// $route() {
// console.log('change route', this.$route.query)
// this.loadData()
// },
// },
mounted() {
this.initGroupJson(JSON.stringify(wGroup.setting))
window.addEventListener('scroll', this.fixTopBarScroll)
// window.addEventListener('click', this.clickListener)
document.addEventListener('keydown', this.handleKeydowm, false)
document.addEventListener('keyup', this.handleKeyup, false)
this.loadData()
},
beforeUnmount() {
window.removeEventListener('scroll', this.fixTopBarScroll)
// window.removeEventListener('click', this.clickListener)
document.removeEventListener('keydown', this.handleKeydowm, false)
document.removeEventListener('keyup', this.handleKeyup, false)
document.oncontextmenu = null
},
methods: {
...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
...shortcuts.methods,
changeLineGuides() {
this.showLineGuides = !this.showLineGuides
},
downloadCancel() {
this.downloadPercent = 0
this.isContinue = false
},
loadData() {
//
const { id, tempid, tempType } = this.$route.query
;(this.$refs as any).options.load(id, tempid, tempType, async () => {
;(this.$refs as any).zoomControl.screenChange()
await this.$nextTick()
// page
this.selectWidget({
uuid: '-1',
})
})
},
zoomSub() {
;(this.$refs as any).zoomControl.sub()
},
zoomAdd() {
;(this.$refs as any).zoomControl.add()
},
save() {
;(this.$refs as any).options.save()
},
fixTopBarScroll() {
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
this.style.left = `-${scrollLeft}px`
},
clickListener(e: Event) {
console.log('click listener', e)
},
optionsChange({ downloadPercent, downloadText }: any) {
this.downloadPercent = downloadPercent
this.downloadText = downloadText
},
},
}) })
const undoable = computed(() => {
return !(
dHistoryParams.value.index === -1 ||
(dHistoryParams.value === 0 && dHistoryParams.value.length === dHistoryParams.value.maxLength))
})
const redoable = computed(() => {
return !(dHistoryParams.value.index === dHistoryParams.value.length - 1)
})
// watch: {
// $route() {
// console.log('change route', this.$route.query)
// this.loadData()
// },
// },
const { handleKeydowm, handleKeyup, dealCtrl } = shortcuts.methods
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)
const instance = getCurrentInstance()
document.addEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
document.addEventListener('keyup', handleKeyup(store, checkCtrl), false)
loadData()
})
onBeforeUnmount(() => {
window.removeEventListener('scroll', fixTopBarScroll)
const instance = getCurrentInstance()
// window.removeEventListener('click', this.clickListener)
document.removeEventListener('keydown', handleKeydowm(store, checkCtrl, instance, dealCtrl), false)
document.removeEventListener('keyup', handleKeyup(store, checkCtrl), false)
document.oncontextmenu = null
})
// ...mapActions(['selectWidget', 'initGroupJson', 'handleHistory']),
function handleHistory(data: string) {
store.dispatch('handleHistory', data)
}
function changeLineGuides() {
state.showLineGuides = !state.showLineGuides
}
function downloadCancel() {
state.downloadPercent = 0
state.isContinue = false
}
function loadData() {
//
const { id, tempid, tempType } = route.query
if (!optionsRef.value) return
optionsRef.value.load(id, tempid, tempType, async () => {
if (!zoomControlRef.value) return
zoomControlRef.value.screenChange()
await nextTick()
// page
store.dispatch('selectWidget', { uuid: '-1' })
// selectWidget({
// uuid: '-1',
// })
})
}
function zoomSub() {
if (!zoomControlRef.value) return
zoomControlRef.value.sub()
}
function zoomAdd() {
if (!zoomControlRef.value) return
zoomControlRef.value.add()
}
function save() {
if (!optionsRef.value) return
optionsRef.value.save()
}
function fixTopBarScroll() {
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
state.style.left = `-${scrollLeft}px`
}
function clickListener(e: Event) {
console.log('click listener', e)
}
function optionsChange({ downloadPercent, downloadText }: { downloadPercent: number, downloadText: string }) {
state.downloadPercent = downloadPercent
state.downloadText = downloadText
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -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,45 +66,59 @@ 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: '',
downloadMsg: '', downloadMsg: '',
cancelText: '', cancelText: '',
}) })
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
}) })
function loadJS() { function loadJS() {
const link_element = document.createElement('script') const link_element = document.createElement('script')
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,68 +137,74 @@ 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)
} }
async function clear() { async function clear() {
store.commit('setDWidgets', []) store.commit('setDWidgets', [])
store.commit('setDPage', Object.assign(store.getters.dPage, { width: 1920, height: 1080, backgroundColor: '#ffffff', backgroundImage: '' })) store.commit('setDPage', Object.assign(store.getters.dPage, { width: 1920, height: 1080, backgroundColor: '#ffffff', backgroundImage: '' }))
store.commit('setShowMoveable', false) store.commit('setShowMoveable', false)
await nextTick() await nextTick()
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>

View File

@ -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({ const content = '本站为个人项目,所使用素材图片等均为网络收集而来,下载之作品仅供学习研究或欣赏目的而使用,无法提供商用授权哦。'
components: { toolTip },
setup() {
const content = '本站为个人项目,所使用素材图片等均为网络收集而来,下载之作品仅供学习研究或欣赏目的而使用,无法提供商用授权哦。'
return {
content,
}
},
})
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -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,62 +38,81 @@ 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
const route = useRoute() (event: 'update:modelValue', data: boolean): void
const router = useRouter() }
const store = useStore()
const state = reactive({ type TState= {
stateBollean: boolean,
title: string,
loading: boolean,
}
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 {
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,
}) })
// //
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>

View File

@ -11,60 +11,88 @@
<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, stateBollean: false,
title: '', title: '',
loading: false, loading: false,
canvasImage: null, }
})
useFontStore.init() // const { dPage, dWidgets } = useSetupMapGetters(['dPage', 'dWidgets'])
// const props = defineProps<TProps>()
const draw = () => { 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,
title: '',
loading: false,
})
useFontStore.init() //
//
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])
} }
@ -76,40 +104,35 @@ export default defineComponent({
} }
lens = queue.length lens = queue.length
uploadImgs() uploadImgs()
} }
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 {
uploadTemplate() uploadTemplate()
} }
} }
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>