mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
250 lines
9.0 KiB
Vue
250 lines
9.0 KiB
Vue
<!--
|
||
* @Author: ShawnPhang
|
||
* @Date: 2022-01-12 11:26:53
|
||
* @Description: 顶部操作按钮组
|
||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||
* @LastEditTime: 2023-12-11 12:40:59
|
||
-->
|
||
<template>
|
||
<div class="top-title"><el-input v-model="title" placeholder="未命名的设计" class="input-wrap" /></div>
|
||
<div class="top-icon-wrap">
|
||
<template v-if="tempEditing">
|
||
<span style="color: #999; font-size: 14px; margin-right: 0.5rem">{{ stateBollean ? '启用' : '停用' }}</span> <el-switch v-model="stateBollean" @change="stateChange" />
|
||
<div class="divide__line">|</div>
|
||
<el-button plain type="primary" @click="saveTemp">保存模板</el-button>
|
||
<el-button @click="$store.commit('managerEdit', false)">取消</el-button>
|
||
<div class="divide__line">|</div>
|
||
</template>
|
||
<!-- <el-button @click="draw">绘制(测试)</el-button> -->
|
||
<el-button size="large" class="primary-btn" :disabled="tempEditing" @click="save(false)">保存</el-button>
|
||
<copyRight>
|
||
<el-button :loading="loading" size="large" class="primary-btn" :disabled="tempEditing" plain type="primary" @click="download">下载作品</el-button>
|
||
</copyRight>
|
||
</div>
|
||
<!-- 生成图片组件 -->
|
||
<SaveImage ref="canvasImage" />
|
||
</template>
|
||
|
||
<script lang="ts">
|
||
import api from '@/api'
|
||
import { defineComponent, reactive, toRefs, getCurrentInstance, ComponentInternalInstance } from 'vue'
|
||
import { mapGetters, mapActions, useStore } from 'vuex'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import _dl from '@/common/methods/download'
|
||
import useNotification from '@/common/methods/notification'
|
||
import SaveImage from '@/components/business/save-download/CreateCover.vue'
|
||
import { useFontStore } from '@/common/methods/fonts'
|
||
import copyRight from './CopyRight.vue'
|
||
import _config from '@/config'
|
||
import useConfirm from '@/common/methods/confirm'
|
||
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
||
|
||
export default defineComponent({
|
||
components: { copyRight, SaveImage },
|
||
props: ['modelValue'],
|
||
emits: ['change', 'update:modelValue'],
|
||
setup(props, context) {
|
||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
const store = useStore()
|
||
const state = reactive({
|
||
stateBollean: false,
|
||
title: '',
|
||
loading: false,
|
||
})
|
||
|
||
// 保存作品
|
||
async function save(hasCover: boolean = false) {
|
||
// Bugs: 历史操作有问题,且page操作未及时入栈 proxy?.dPageHistory
|
||
if (proxy?.dHistory.length <= 0) {
|
||
return
|
||
}
|
||
store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||
// console.log(proxy?.dPage, proxy?.dWidgets)
|
||
const { id, tempid } = route.query
|
||
const cover = hasCover ? await proxy?.draw() : undefined
|
||
const widgets = proxy.dWidgets // 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 })
|
||
stat !== 0 ? useNotification('保存成功', '可在"我的作品"中查看') : useNotification('保存失败', msg, { type: 'error' })
|
||
!id && router.push({ path: '/home', query: { id: newId }, replace: true })
|
||
store.commit('setShowMoveable', true)
|
||
}
|
||
// 保存模板
|
||
async function saveTemp() {
|
||
const { tempid, tempType: type } = route.query
|
||
let res = null
|
||
if (type == 1) {
|
||
// 保存组件,组合元素要保证在最后一位,才能默认选中
|
||
if (proxy.dWidgets[0].type === 'w-group') {
|
||
const group = proxy.dWidgets.shift()
|
||
group.record.width = 0
|
||
group.record.height = 0
|
||
proxy.dWidgets.push(group)
|
||
}
|
||
// TODO:如果保存组件不存在组合,则添加组合。该功能待优化
|
||
if (!proxy.dWidgets.some((x) => x.type === 'w-group')) {
|
||
alert('提交组件必须为组合!')
|
||
return
|
||
// 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 })
|
||
} 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 })
|
||
res.stat != 0 && useNotification('保存成功', '模板内容已变更')
|
||
}
|
||
// 停用启用
|
||
async function stateChange(e: any) {
|
||
const { tempid, tempType: type } = route.query
|
||
const { stat } = await api.home.saveTemp({ id: tempid, type, state: e ? 1 : 0 })
|
||
stat != 0 && useNotification('保存成功', '模板内容已变更')
|
||
}
|
||
async function download() {
|
||
if (state.loading === true) {
|
||
return
|
||
}
|
||
// 临时提示
|
||
if (proxy.title === '自设计模板') {
|
||
const isPass = await useConfirm('提示', 'PSD自设计作品暂时保存在Github,下载可能失败', 'warning')
|
||
if (!isPass) {
|
||
return
|
||
}
|
||
}
|
||
state.loading = true
|
||
context.emit('update:modelValue', true)
|
||
context.emit('change', { downloadPercent: 1, downloadText: '正在处理封面' })
|
||
await save(true)
|
||
setTimeout(async () => {
|
||
const { id } = route.query
|
||
if (id) {
|
||
const { width, height } = proxy.dPage
|
||
context.emit('update:modelValue', true)
|
||
context.emit('change', { downloadPercent: 1, downloadText: '准备合成图片' })
|
||
state.loading = false
|
||
let timerCount = 0
|
||
const animation = setInterval(() => {
|
||
if (props.modelValue && timerCount < 75) {
|
||
timerCount += RandomNumber(1, 10)
|
||
context.emit('change', { downloadPercent: 1 + timerCount, downloadText: '正在合成图片' })
|
||
} else {
|
||
clearInterval(animation)
|
||
}
|
||
}, 800)
|
||
await _dl.downloadImg(api.home.download({ id, width, height }) + '&r=' + Math.random(), (progress: number, xhr: any) => {
|
||
if (props.modelValue) {
|
||
clearInterval(animation)
|
||
progress >= timerCount && context.emit('change', { downloadPercent: Number(progress.toFixed(0)), downloadText: '图片生成中' })
|
||
} else {
|
||
xhr.abort()
|
||
}
|
||
})
|
||
context.emit('change', { downloadPercent: 100, downloadText: '图片下载中' })
|
||
}
|
||
}, 100)
|
||
}
|
||
function RandomNumber(min: number, max: number) {
|
||
return Math.ceil(Math.random() * (max - min)) + min
|
||
}
|
||
|
||
return {
|
||
...toRefs(state),
|
||
download,
|
||
save,
|
||
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() // 初始化加载字体
|
||
}
|
||
const apiName = tempId && !id ? 'getTempDetail' : 'getWorks'
|
||
if (!id && !tempId) {
|
||
cb()
|
||
return
|
||
}
|
||
const { data: content, title, state, width, height } = await api.home[apiName]({ id: id || tempId, type })
|
||
if (content) {
|
||
const data = JSON.parse(content)
|
||
this.stateBollean = !!state
|
||
this.title = title
|
||
this.$store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||
// this.$store.commit('setDWidgets', [])
|
||
if (type == 1) {
|
||
// 加载文字组合组件
|
||
this.dPage.width = width
|
||
this.dPage.height = height
|
||
this.addGroup(data)
|
||
} else {
|
||
this.$store.commit('setDPage', data.page)
|
||
id ? this.$store.commit('setDWidgets', data.widgets) : this.$store.dispatch('setTemplate', data.widgets)
|
||
}
|
||
cb()
|
||
this.pushHistory('请求加载load')
|
||
}
|
||
},
|
||
draw() {
|
||
return new Promise((resolve) => {
|
||
this.$refs.canvasImage.createCover(({ key }) => {
|
||
resolve(_config.IMG_URL + key)
|
||
})
|
||
})
|
||
},
|
||
},
|
||
})
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.top-icon-wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
padding-right: 20px;
|
||
height: 54px;
|
||
.top-icon {
|
||
background-color: rgba(0, 0, 0, 0.4);
|
||
border-radius: 5px;
|
||
color: #ffffff;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
margin: 8px;
|
||
padding: 5px 8px;
|
||
&:hover {
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
}
|
||
}
|
||
}
|
||
.top-title {
|
||
color: @color-black;
|
||
flex: 1;
|
||
padding-left: 88px;
|
||
// font-weight: bold;
|
||
.input-wrap {
|
||
width: 15rem;
|
||
:deep(input) {
|
||
border-color: #ffffff;
|
||
// border-color: #e8eaec;
|
||
}
|
||
}
|
||
.input-wrap:hover {
|
||
:deep(input) {
|
||
border-color: #e8eaec;
|
||
}
|
||
}
|
||
}
|
||
.primary-btn {
|
||
font-weight: 600;
|
||
transform: scale(0.95);
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.divide__line {
|
||
margin: 0 1rem;
|
||
color: #e8eaec;
|
||
height: 20px;
|
||
}
|
||
</style>
|