feat: add watermark & canvas size modification

This commit is contained in:
ShawnPhang 2024-04-10 18:11:42 +08:00
parent 2859efd0e7
commit f6903eee7c
31 changed files with 640 additions and 160 deletions

View File

@ -0,0 +1,75 @@
/*
* @Author: ShawnPhang
* @Date: 2024-04-07 17:49:06
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-10 00:37:33
*/
export default [
{
name: '手机海报',
width: 1242,
height: 2208,
icon: 'sd-shouji'
},
{
name: '横版海报',
width: 900,
height: 500,
icon: 'sd-wangye'
},
{
name: '公众号首图',
width: 900,
height: 383,
icon: 'sd-weixin'
},
{
name: '公众号次图',
width: 500,
height: 500,
icon: 'sd-weixin'
},
{
name: '小红书配图',
width: 1242,
height: 1660,
icon: 'sd-shouji'
},
{
name: '商品主图',
width: 800,
height: 800,
icon: 'sd-wangye'
},
{
name: '电商详情页',
width: 750,
height: 1000,
icon: 'sd-wangye'
},
{
name: '电商竖版海报',
width: 750,
height: 950,
icon: 'sd-shouji'
},
{
name: '电商横版海报',
width: 750,
height: 390,
icon: 'sd-wangye'
},
{
name: '小程序封面',
width: 520,
height: 416,
icon: 'sd-weixin'
},
{
name: '壁纸 / PPT(16:9)',
width: 1920,
height: 1080,
icon: 'sd-wangye'
}
]

View File

@ -1,8 +1,8 @@
// element UI fix // element UI fix
.el-collapse-item__header { .el-collapse-item__header {
padding: 0; padding: 0;
font-size: 14px; font-size: 14px !important;
color: #666666; color: #666666 !important;
user-select: none; user-select: none;
} }
.el-collapse-item__wrap { .el-collapse-item__wrap {

View File

@ -61,6 +61,9 @@
// font-size: 18px; // font-size: 18px;
color: #333333; color: #333333;
} }
.iconfont {
font-size: 14px;
}
.text { .text {
font-weight: 600; font-weight: 600;
margin-left: .4rem; margin-left: .4rem;

View File

@ -2,17 +2,17 @@
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2022-02-03 16:30:18 * @Date: 2022-02-03 16:30:18
* @Description: Type: success / info / warning / error * @Description: Type: success / info / warning / error
* @LastEditors: ShawnPhang <site: book.palxp.com>, Jeremy Yu <https://github.com/JeremyYu-cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-02 11:50:00 * @LastEditTime: 2024-04-08 18:55:12
*/ */
import { ElMessageBox, messageType } from 'element-plus' import { ElMessageBox, messageType } from 'element-plus'
export default (title: string = '提示', message: string = '', type: messageType = 'success') => { export default (title: string = '提示', message: string = '', type: messageType = 'success', extra?: any) => {
return new Promise((resolve: Function) => { return new Promise((resolve: Function) => {
ElMessageBox.confirm(message, title, { ElMessageBox.confirm(message, title, Object.assign({
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type, type,
}) }, extra))
.then(() => { .then(() => {
resolve(true) resolve(true)
}) })

View File

@ -0,0 +1,112 @@
<!--
* @Author: ShawnPhang
* @Date: 2024-04-09 11:24:57
* @Description: 创建/编辑画布尺寸
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-10 17:29:15
-->
<template>
<div>
<el-dialog v-model="dialogVisible" center destroy-on-close :align-center="false" :title="params ? '编辑尺寸' : '新建空白设计'" width="380" draggable>
<!-- <el-divider content-position="left">自定义尺寸</el-divider> -->
<el-checkbox v-if="params" v-model="isAdaptive" label="自动调整元素大小位置" size="large" />
<sizeEditor :params="page" :class="params ? 'editor-mode' : 'add-mode'">
<el-button @click="finish" plain size="large" type="primary">{{ params ? '应用' : '创建' }}</el-button>
</sizeEditor>
<el-divider content-position="left">使用推荐尺寸</el-divider>
<ul class="pre-list">
<li @click="applySize(s)" class="item" v-for="(s, si) in sizes" :key="'s' + si">
<i :class="['icon', s.icon]" /> {{ s.name }} <span class="info">{{ s.width }} × {{ s.height }} px</span>
</li>
</ul>
<!-- <template #footer>
<el-button type="primary" @click="dialogVisible = false"> Confirm </el-button>
</template> -->
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref, Ref } from 'vue'
import { ElCheckbox } from 'element-plus'
import { useRouter } from 'vue-router'
import sizeEditor from './sizeEditor.vue'
import sizes from '@/assets/data/PageSizeData'
import { useWidgetStore } from '@/store';
const router = useRouter()
const widgetStore = useWidgetStore()
const props = withDefaults(
defineProps<{
params?: any
}>(),
{
params: undefined,
},
)
const dialogVisible: Ref<boolean> = ref(false)
const isAdaptive: Ref<boolean> = ref(true)
const page: any = ref({ width: 100, height: 100 })
const applySize = ({ width, height }: any) => {
page.value.width = width
page.value.height = height
}
const open = () => {
if (props.params) {
page.value.width = props.params.width
page.value.height = props.params.height
}
dialogVisible.value = true
}
function finish() {
const { width, height } = page.value
if (props.params) {
const lastPageData = JSON.parse(JSON.stringify(props.params))
props.params.width = width
props.params.height = height
isAdaptive.value && widgetStore.autoResizeAll(lastPageData)
} else window.open(router.resolve(`/home?mode=create&w_h=${width}*${height}`).href, '_blank')
}
defineExpose({
open,
})
</script>
<style lang="less" scoped>
:deep(.el-dialog__header) {
padding-bottom: 7px !important;
}
.editor-mode {
padding: 0 0 0.5rem 0;
}
.add-mode {
padding: 1rem 0 0.5rem 0;
}
.pre-list {
margin: 1rem 0;
height: 245px;
overflow-y: scroll;
.item {
padding: 10px 8px;
border-radius: 8px;
cursor: pointer;
font-size: 15px;
color: #333;
.icon {
margin-right: 0.2rem;
}
.info {
margin-left: 0.4rem;
font-size: 12px;
color: #b4b8bf;
}
}
.item:hover {
background-color: #f6f7f9;
}
}
</style>

View File

@ -0,0 +1,2 @@
import v from './createDesign.vue'
export default v

View File

@ -0,0 +1,101 @@
<!--
* @Author: ShawnPhang
* @Date: 2024-04-08 21:33:59
* @Description: 尺寸编辑
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-09 15:55:33
-->
<template>
<div class="position-size">
<number-input v-model="params.width" label="宽" :maxValue="5000" />
<el-tooltip :show-after="300" :hide-after="0" effect="dark" :content="lockRatio ? '锁定宽高比' : '自由改变'" placement="top">
<i @click="changeRatio" :class="['icon', lockRatio ? 'sd-db' : 'sd-fdb']" />
</el-tooltip>
<number-input v-model="params.height" label="高" :maxValue="5000" />
<slot />
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import numberInput from '@/components/modules/settings/numberInput.vue'
type TProps = {
params: any
}
const props = withDefaults(defineProps<TProps>(), {
params: {},
})
const lockRatio = ref(false) //
let scale = 0,
temp = { width: 0, height: 0 }
watch(
() => props.params.width,
(val, old) => {
if (scale && isNumber(val) && isNumber(old)) {
temp.width === 0 && (temp.width = props.params.width)
setChange()
}
},
)
watch(
() => props.params.height,
(val, old) => {
if (scale && isNumber(val) && isNumber(old)) {
temp.height === 0 && (temp.height = props.params.height)
setChange()
}
},
)
//
function changeRatio() {
lockRatio.value = !lockRatio.value
if (lockRatio.value) {
scale = props.params.width / props.params.height
} else scale = 0
}
//
let timer: any = null
function setChange() {
clearTimeout(timer)
timer = setTimeout(() => {
temp.width > 0 && temp.height === 0 && (props.params.height = props.params.width / scale)
temp.height > 0 && temp.width === 0 && (props.params.width = props.params.height * scale)
if (temp.width > 0 && temp.height > 0) {
temp = { width: 0, height: 0 }
}
}, 300)
}
function isNumber(val: any) {
return typeof val === 'number'
}
</script>
<style lang="less" scoped>
.position-size {
display: flex;
align-items: center;
// justify-content: space-between;
width: 100%;
.number-input {
flex: 0.2;
}
.icon {
cursor: pointer;
font-size: 19px;
}
.sd-fdb,
.sd-db {
color: #999999;
margin: 0 6px 0 -4px;
}
.sd-db {
color: #333333;
}
}
</style>

View File

@ -3,7 +3,7 @@
* @Date: 2021-08-04 11:46:39 * @Date: 2021-08-04 11:46:39
* @Description: 原版movable插件 * @Description: 原版movable插件
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-11-14 11:41:23 * @LastEditTime: 2024-04-06 14:56:35
--> -->
<template> <template>
<div id="empty" class="moveable__remove-item zk-moveable-style"></div> <div id="empty" class="moveable__remove-item zk-moveable-style"></div>
@ -275,7 +275,9 @@ onMounted(() => {
triggerAblesSimultaneously: true, triggerAblesSimultaneously: true,
} }
moveable = new Moveable(document.body, moveableOptions) // moveable = new Moveable(document.body, moveableOptions)
const containerEl = document.querySelector('#main') as HTMLElement | SVGElement;
moveable = new Moveable(containerEl, moveableOptions)
const helper = new MoveableHelper() const helper = new MoveableHelper()
@ -578,12 +580,6 @@ onMounted(() => {
key: 'left', key: 'left',
value: item.left, value: item.left,
}) })
// store.dispatch("updateWidgetData", {
// uuid: key,
// key: 'left',
// value: item.left,
// })
widgetStore.updateWidgetData({ widgetStore.updateWidgetData({
uuid: key, uuid: key,
key: 'top', key: 'top',

View File

@ -1,9 +1,9 @@
/* /*
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2021-07-13 22:51:29 * @Date: 2021-07-13 22:51:29
* @Description: require.context自动引用 * @Description: Widgetspanel中所有组件将会自动全局引入
* @LastEditors: ShawnPhang * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2022-04-08 10:28:47 * @LastEditTime: 2024-04-09 22:31:08
*/ */
import { App } from "vue" import { App } from "vue"

View File

@ -0,0 +1,34 @@
<!--
* @Author: ShawnPhang
* @Date: 2024-04-08 19:19:17
* @Description: 水印组件封装
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-08 21:30:12
-->
<template>
<slot v-if="isDrawPage" />
<el-watermark v-else :style="props.customStyle" :gap="[140, 120]" :content="watermark">
<slot />
</el-watermark>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { ElWatermark } from 'element-plus'
import { storeToRefs } from 'pinia'
import { useBaseStore } from '@/store'
import { useRoute } from 'vue-router'
const route = useRoute()
type TProps = {
customStyle: any
}
const props = withDefaults(defineProps<TProps>(), {
customStyle: {}
})
const isDrawPage = computed(() => route.name === 'Draw')
const baseStore = useBaseStore()
const { watermark } = storeToRefs(baseStore)
</script>

View File

@ -0,0 +1,133 @@
<!--
* @Author: ShawnPhang
* @Date: 2024-04-06 15:17:03
* @Description: 画布尺寸操作柄
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-08 12:28:15
-->
<template>
<div v-show="show" class="page-resize" :style="{ width: Math.floor(pw) + 'px', height: Math.floor(ph) + 'px' }">
<div @mousedown="handlemousedown($event, 'ns', true)" class="resize__bar resize__bar-top"></div>
<div @mousedown="handlemousedown($event, 'ew')" class="resize__bar resize__bar-right"></div>
<div @mousedown="handlemousedown($event, 'ns')" class="resize__bar resize__bar-bottom"></div>
<div @mousedown="handlemousedown($event, 'ew', true)" class="resize__bar resize__bar-left"></div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useWidgetStore, useCanvasStore } from '@/store'
import { storeToRefs } from 'pinia'
const widgetStore = useWidgetStore()
const canvasStore = useCanvasStore()
const props = defineProps<{
width: number
height: number
}>()
type Direction = 'ns' | 'ew' // |
const { dActiveElement } = storeToRefs(widgetStore)
const show = computed(() => dActiveElement.value?.uuid === '-1')
let initData = { x: 0, y: 0, w: 0, h: 0 }
let moveDir = ''
let moveRev: any = undefined
const handlemousedown = (e: any, dir: Direction, isReverse?: boolean) => {
moveDir = dir
moveRev = isReverse
e.stopPropagation()
e.preventDefault()
initData = { x: e.pageX, y: e.pageY, w: canvasStore.dPage.width, h: canvasStore.dPage.height }
document.addEventListener('mousemove', handlemousemove, true)
document.addEventListener('mouseup', stopMove, true)
}
const stopMove = () => {
document.removeEventListener('mousemove', handlemousemove, true)
document.removeEventListener('mouseup', stopMove, true)
}
function handlemousemove(e: any) {
const { x, y, w, h } = initData
if (moveDir === 'ew') {
const dx = e.pageX - x
const moveX = Math.floor((dx * 100) / canvasStore.dZoom)
const result = moveRev ? w - moveX * 2 : w + moveX * 2
result <= 5000 && result > 0 && (canvasStore.dPage.width = result)
} else {
const dy = e.pageY - y
const moveY = Math.floor((dy * 100) / canvasStore.dZoom)
const result = moveRev ? h - moveY * 2 : h + moveY * 2
result <= 5000 && result > 0 && (canvasStore.dPage.height = result)
}
}
const pw = computed(() => props.width)
const ph = computed(() => props.height)
</script>
<style lang="less" scoped>
@bar-color: rgba(0, 0, 0, 0.2);
.page-resize {
pointer-events: none;
position: absolute;
z-index: 10;
.resize__bar {
pointer-events: auto;
position: absolute;
&-left {
left: -14px;
}
&-right {
right: -14px;
}
&-left,
&-right {
position: reactive;
cursor: ew-resize;
width: 10px;
height: 24px;
top: 50%;
transform: translateY(-12px);
}
&-left:after,
&-right:after {
position: absolute;
content: '';
left: 3px;
width: 4px;
height: 24px;
border-radius: 12px;
background: @bar-color;
}
&-top {
top: -14px;
}
&-bottom {
bottom: -12px;
}
&-top,
&-bottom {
cursor: ns-resize;
width: 24px;
height: 10px;
left: 50%;
transform: translateX(-12px);
}
&-top:after,
&-bottom:after {
position: absolute;
content: '';
top: 4px;
width: 24px;
height: 4px;
border-radius: 12px;
background: @bar-color;
}
}
}
</style>

View File

@ -10,7 +10,9 @@
opacity: 1 - (dZoom < 100 ? dPage.tag : 0), opacity: 1 - (dZoom < 100 ? dPage.tag : 0),
}" }"
> >
<slot /> <slot />
<resize-page :width="(dPage.width * dZoom) / 100" :height="(dPage.height * dZoom) / 100" />
<watermark :customStyle="{ height: (dPage.height * dZoom) / 100 + 'px'}">
<div <div
:id="pageDesignCanvasId" :id="pageDesignCanvasId"
class="design-canvas" class="design-canvas"
@ -33,12 +35,6 @@
@mouseup="drop($event)" @mouseup="drop($event)"
> >
<!-- <grid-size /> --> <!-- <grid-size /> -->
<!-- :class="{
layer: true,
'layer-active': getIsActive(layer.uuid),
'layer-hover': layer.uuid === dHoverUuid || dActiveElement.parent === layer.uuid,
}" -->
<component <component
:is="layer.type" :is="layer.type"
v-for="layer in getlayers()" v-for="layer in getlayers()"
@ -69,6 +65,7 @@
<!-- <ref-line v-if="dSelectWidgets.length === 0" /> --> <!-- <ref-line v-if="dSelectWidgets.length === 0" /> -->
<!-- <size-control v-if="dSelectWidgets.length === 0" /> --> <!-- <size-control v-if="dSelectWidgets.length === 0" /> -->
</div> </div>
</watermark>
</div> </div>
</div> </div>
</div> </div>
@ -82,9 +79,11 @@ import PointImg from '@/utils/plugins/pointImg'
import getComponentsData from '@/common/methods/DesignFeatures/setComponents' import getComponentsData from '@/common/methods/DesignFeatures/setComponents'
import { debounce } from 'throttle-debounce' import { debounce } from 'throttle-debounce'
import { move, moveInit } from '@/mixins/move' import { move, moveInit } from '@/mixins/move'
import { useCanvasStore, useControlStore, useGroupStore, useWidgetStore } from '@/store' import { useCanvasStore, useControlStore, useWidgetStore } from '@/store'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { TPageState } from '@/store/design/canvas/d' import { TPageState } from '@/store/design/canvas/d'
import resizePage from './comps/resize.vue'
import watermark from './comps/pageWatermark.vue'
// //
type TProps = { type TProps = {
pageDesignCanvasId: string pageDesignCanvasId: string

View File

@ -8,10 +8,9 @@
</div> </div>
<el-collapse v-else v-model="state.activeNames"> <el-collapse v-else v-model="state.activeNames">
<el-collapse-item title="画布尺寸" name="1"> <el-collapse-item title="画布尺寸" name="1">
<div class="position-size"> <sizeEditor :params="state.innerElement">
<number-input v-model="state.innerElement.width" label="宽" :maxValue="5000" @finish="(value) => finish('width', value)" /> <i @click="openSizeEdit" class="icon sd-edit"></i>
<number-input v-model="state.innerElement.height" label="高" :maxValue="5000" @finish="(value) => finish('height', value)" /> </sizeEditor>
</div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item title="背景设置" name="2"> <el-collapse-item title="背景设置" name="2">
<el-button style="width: 100%; margin: 0 0 1rem 0;" type="primary" link @click="state.showBgLib = true">在背景库中选择</el-button> <el-button style="width: 100%; margin: 0 0 1rem 0;" type="primary" link @click="state.showBgLib = true">在背景库中选择</el-button>
@ -49,29 +48,27 @@
<el-button v-show="state.mode === '图片' && state.innerElement.backgroundImage" class="btn-wrap" @click="shiftOut">将背景分离为图层</el-button> <el-button v-show="state.mode === '图片' && state.innerElement.backgroundImage" class="btn-wrap" @click="shiftOut">将背景分离为图层</el-button>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<createDesign ref="sizeEditRef" :params="state.innerElement" />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// //
// const NAME = 'page-style' // const NAME = 'page-style'
import { nextTick, onMounted, reactive, watch } from 'vue' import { nextTick, onMounted, reactive, watch, ref, Ref } from 'vue'
import colorSelect, { colorChangeData } from '@/components/modules/settings/colorSelect.vue'
import numberInput from '../settings/numberInput.vue'
import colorSelect, { colorChangeData } from '../settings/colorSelect.vue'
import uploader, { TUploadDoneData } from '@/components/common/Uploader/index.vue' import uploader, { TUploadDoneData } from '@/components/common/Uploader/index.vue'
import api from '@/api' import api from '@/api'
import _dl from '@/common/methods/download' import _dl from '@/common/methods/download'
// import ColorPipette from '@/utils/plugins/color-pipette'
import Tabs from '@palxp/color-picker/comps/Tabs.vue' import Tabs from '@palxp/color-picker/comps/Tabs.vue'
import TabPanel from '@palxp/color-picker/comps/TabPanel.vue' import TabPanel from '@palxp/color-picker/comps/TabPanel.vue'
// import { useSetupMapGetters } from '@/common/hooks/mapGetters'
import { useCanvasStore, useWidgetStore } from '@/store' import { useCanvasStore, useWidgetStore } from '@/store'
import { TPageState } from '@/store/design/canvas/d' import { TPageState } from '@/store/design/canvas/d'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { Delete as iconDelete, Download as iconDownload } from '@element-plus/icons-vue' import { Delete as iconDelete, Download as iconDownload } from '@element-plus/icons-vue'
import wImageSetting from '@/components/modules/widgets/wImage/wImageSetting' import wImageSetting from '@/components/modules/widgets/wImage/wImageSetting'
// import setImageData from '@/common/methods/DesignFeatures/setImage' import sizeEditor from '@/components/business/create-design/sizeEditor.vue'
import createDesign from '@/components/business/create-design'
type TState = { type TState = {
activeNames: string[] activeNames: string[]
@ -84,7 +81,6 @@ type TState = {
showBgLib: boolean showBgLib: boolean
} }
const pageStore = useCanvasStore() const pageStore = useCanvasStore()
const widgetStore = useWidgetStore() const widgetStore = useWidgetStore()
const state = reactive<TState>({ const state = reactive<TState>({
@ -97,6 +93,7 @@ const state = reactive<TState>({
modes: ['颜色', '图片'], modes: ['颜色', '图片'],
showBgLib: false showBgLib: false
}) })
const sizeEditRef: Ref<typeof createDesign | null> = ref(null)
// const { dActiveElement } = useSetupMapGetters(['dActiveElement']) // const { dActiveElement } = useSetupMapGetters(['dActiveElement'])
const { dActiveElement } = storeToRefs(widgetStore) const { dActiveElement } = storeToRefs(widgetStore)
let _localTempBG: string | null = null let _localTempBG: string | null = null
@ -164,8 +161,6 @@ function changeValue() {
} }
function finish(key: keyof TPageState, value: string | number) { function finish(key: keyof TPageState, value: string | number) {
console.log('111');
pageStore.updatePageData({ pageStore.updatePageData({
key: key, key: key,
value: value, value: value,
@ -202,30 +197,32 @@ async function shiftOut() {
setting.width = state.innerElement.width setting.width = state.innerElement.width
setting.height = state.innerElement.height setting.height = state.innerElement.height
setting.imgUrl = state.innerElement.backgroundImage setting.imgUrl = state.innerElement.backgroundImage
// store.dispatch('addWidget', setting)
setting.uuid = `bg-${(new Date()).getTime()}` setting.uuid = `bg-${(new Date()).getTime()}`
widgetStore.dWidgets.unshift(setting) widgetStore.dWidgets.unshift(setting)
widgetStore.selectWidget({ widgetStore.selectWidget({
uuid: widgetStore.dWidgets[0].uuid, uuid: widgetStore.dWidgets[0].uuid,
}) })
// store.dispatch('selectWidget', {
// uuid: store.getters.dWidgets[0].uuid,
// })
deleteBg() deleteBg()
} }
//
function openSizeEdit() {
sizeEditRef.value?.open()
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
#page-style { #page-style {
height: 100%; height: 100%;
width: 100%; width: 100%;
} .sd-edit {
.position-size { cursor: pointer;
display: flex; color: #666666;
// justify-content: space-between; font-size: 22px;
width: 100%; }
.number-input { .sd-edit:hover {
flex: 0.25; color: #333333;
transform: scale(1.2);
} }
} }
.select { .select {

View File

@ -68,38 +68,12 @@ function alignAction(item: TIconItemSelectData) {
uuid: element.uuid, uuid: element.uuid,
group, group,
}) })
// store.dispatch('updateAlign', {
// align: item.value,
// uuid: element.uuid,
// group,
// })
}); });
historyStore.pushHistory() historyStore.pushHistory()
// store.dispatch('pushHistory')
// pushHistory()
}) })
// store.dispatch('getCombined').then((group) => {
// sWidgets.forEach((element: Record<string, any>) => {
// store.dispatch('updateAlign', {
// align: item.value,
// uuid: element.uuid,
// group,
// })
// // updateAlign({
// // align: item.value,
// // uuid: element.uuid,
// // group,
// // })
// });
// store.dispatch('pushHistory')
// // pushHistory()
// })
} }
function layerChange(newLayer: TdWidgetData[]) { function layerChange(newLayer: TdWidgetData[]) {
widgetStore.setDWidgets(newLayer.toReversed()) widgetStore.setDWidgets(newLayer.toReversed())
// store.commit('setDWidgets', newLayer.toReversed())
// store.commit('setShowMoveable', false)
controlStore.setShowMoveable(false) controlStore.setShowMoveable(false)
} }

View File

@ -3,7 +3,7 @@
* @Date: 2021-08-27 15:16:07 * @Date: 2021-08-27 15:16:07
* @Description: 背景图 * @Description: 背景图
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-11 01:42:36 * @LastEditTime: 2024-04-09 22:29:51
--> -->
<template> <template>
<div class="wrap"> <div class="wrap">
@ -50,13 +50,10 @@ type TState = {
bgList: TGetImageListResult[] bgList: TGetImageListResult[]
showList: boolean showList: boolean
colors: string[] colors: string[]
} }
const { model } = defineProps<TProps>() const { model } = defineProps<TProps>()
const pageStore = useCanvasStore() const pageStore = useCanvasStore()
const widgetStore = useWidgetStore() const widgetStore = useWidgetStore()

View File

@ -3,7 +3,7 @@
* @Date: 2021-08-27 15:16:07 * @Date: 2021-08-27 15:16:07
* @Description: 素材列表主要用于文字组合列表 * @Description: 素材列表主要用于文字组合列表
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-02-29 16:54:28 * @LastEditTime: 2024-04-09 22:30:10
--> -->
<template> <template>
<div class="wrap"> <div class="wrap">
@ -55,7 +55,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, onMounted } from 'vue' import { reactive, onMounted } from 'vue'
import api from '@/api' import api from '@/api'
import getComponentsData from '@/common/methods/DesignFeatures/setComponents' import getComponentsData from '@/common/methods/DesignFeatures/setComponents'
import DragHelper from '@/common/hooks/dragHelper' import DragHelper from '@/common/hooks/dragHelper'
import setItem2Data from '@/common/methods/DesignFeatures/setImage' import setItem2Data from '@/common/methods/DesignFeatures/setImage'

View File

@ -118,13 +118,14 @@ function checkHeight() {
isLess && load() isLess && load()
} }
let hideReplacePrompt: any = localStorage.getItem('hide_replace_prompt')
async function selectItem(item: IGetTempListData) { async function selectItem(item: IGetTempListData) {
controlStore.setShowMoveable(false) // controlStore.setShowMoveable(false) //
if (!hideReplacePrompt && dHistoryParams.value.length > 0) {
if (dHistoryParams.value.length > 0) { const doNotPrompt = await useConfirm('添加到作品', '模板内容将替换页面内容', 'warning', {confirmButtonText: '知道了',cancelButtonText: '不再提示'})
const isPass = await useConfirm('提示', '使用模板后,当前页面将会被替换,是否继续', 'warning') if (!doNotPrompt) {
if (!isPass) { localStorage.setItem('hide_replace_prompt', '1')
return false hideReplacePrompt = true
} }
} }
userStore.managerEdit(false) userStore.managerEdit(false)

View File

@ -2,14 +2,14 @@
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2021-07-29 18:31:27 * @Date: 2021-07-29 18:31:27
* @Description: * @Description:
* @LastEditors: ShawnPhang * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2022-04-07 23:26:51 * @LastEditTime: 2024-04-10 07:36:58
--> -->
<template> <template>
<div class="icon-item-select"> <div class="icon-item-select">
<span v-if="label" class="label">{{ label }}</span> <span v-if="label" class="label">{{ label }}</span>
<ul class="list btn__bar flex"> <ul class="list btn__bar flex">
<el-tooltip v-for="(item, index) in data" :key="index" class="item" effect="dark" :content="item.tip" placement="top" :auto-close="400"> <el-tooltip v-for="(item, index) in data" :key="index" class="item" effect="dark" :content="item.tip" placement="top" :show-after="300" >
<li :class="{ 'list-item': true, active: item.select }" @click="selectItem(item)"> <li :class="{ 'list-item': true, active: item.select }" @click="selectItem(item)">
<i :class="`${item.extraIcon ? 'icon' : 'iconfont'} ${item.icon}`"></i> <i :class="`${item.extraIcon ? 'icon' : 'iconfont'} ${item.icon}`"></i>
</li> </li>

View File

@ -1,3 +1,10 @@
/*
* @Author: ShawnPhang
* @Date: 2024-04-05 07:31:45
* @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-10 00:34:21
*/
// const prefix = import.meta.env // const prefix = import.meta.env
const prefix = process.env const prefix = process.env
@ -16,7 +23,7 @@ export default {
IMG_URL: 'https://store.palxp.cn/', // 七牛云资源地址 IMG_URL: 'https://store.palxp.cn/', // 七牛云资源地址
// ICONFONT_URL: '//at.alicdn.com/t/font_3223711_74mlzj4jdue.css', // ICONFONT_URL: '//at.alicdn.com/t/font_3223711_74mlzj4jdue.css',
ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap', ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap',
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_8r5ffak8d5q.css', ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_ljv2tbkwgqp.css',
QINIUYUN_PLUGIN: 'https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/qiniu-js/2.5.5/qiniu.min.js', QINIUYUN_PLUGIN: 'https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/qiniu-js/2.5.5/qiniu.min.js',
supportSubFont: true, // 是否开启服务端字体压缩 supportSubFont: true, // 是否开启服务端字体压缩
} }

View File

@ -2,13 +2,12 @@
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2022-03-03 14:13:16 * @Date: 2022-03-03 14:13:16
* @Description: * @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-02-26 17:54:00 * @LastEditTime: 2024-04-08 18:19:35
*/ */
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
// import store from './store'
import utils from './utils' import utils from './utils'
import 'normalize.css/normalize.css' import 'normalize.css/normalize.css'
import '@/assets/styles/index.less' import '@/assets/styles/index.less'

View File

@ -2,8 +2,8 @@
* @Author: Jeremy Yu * @Author: Jeremy Yu
* @Date: 2024-03-17 15:00:00 * @Date: 2024-03-17 15:00:00
* @Description: Base全局状态管理 * @Description: Base全局状态管理
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-18 21:00:00 * @LastEditTime: 2024-04-08 17:00:12
*/ */
import { Store, defineStore } from 'pinia' import { Store, defineStore } from 'pinia'
@ -13,7 +13,7 @@ import { Store, defineStore } from 'pinia'
type TStoreBaseState = { type TStoreBaseState = {
loading: boolean | null loading: boolean | null
scroll: boolean watermark: string | string[]
/** fonts */ /** fonts */
fonts: string[] fonts: string[]
} }
@ -21,13 +21,14 @@ type TStoreBaseState = {
type TUserAction = { type TUserAction = {
hideLoading: () => void hideLoading: () => void
setFonts: (list: string[]) => void setFonts: (list: string[]) => void
changeWatermark: (e: string[] | string) => void
} }
/** Base全局状态管理 */ /** Base全局状态管理 */
const useBaseStore = defineStore<'base', TStoreBaseState, {}, TUserAction>('base', { const useBaseStore = defineStore<'base', TStoreBaseState, {}, TUserAction>('base', {
state: () => ({ state: () => ({
loading: null, loading: null,
scroll: true, watermark: ['迅排设计', 'poster-design'],
fonts: [], // 缓存字体列表 fonts: [], // 缓存字体列表
}), }),
actions: { actions: {
@ -40,6 +41,9 @@ const useBaseStore = defineStore<'base', TStoreBaseState, {}, TUserAction>('base
setFonts(list: string[]) { setFonts(list: string[]) {
this.fonts = list this.fonts = list
}, },
changeWatermark(wm: any) {
this.watermark = wm
}
} }
}) })

View File

@ -4,7 +4,7 @@
* @Date: 2024-03-18 21:00:00 * @Date: 2024-03-18 21:00:00
* @Description: * @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-05 14:52:06 * @LastEditTime: 2024-04-08 21:23:38
*/ */
import { Store, defineStore } from 'pinia' import { Store, defineStore } from 'pinia'

View File

@ -2,13 +2,13 @@
* @Author: Jeremy Yu * @Author: Jeremy Yu
* @Date: 2024-03-18 21:00:00 * @Date: 2024-03-18 21:00:00
* @Description: Store方法export * @Description: Store方法export
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-28 14:00:00 * @LastEditTime: 2024-04-10 18:01:14
*/ */
import { useCanvasStore, useControlStore } from "@/store" import { useCanvasStore, useControlStore } from '@/store'
import { TWidgetStore } from ".." import { TWidgetStore } from '..'
import { updateGroupSize } from "." import { updateGroupSize } from '.'
export type TInitResize = { export type TInitResize = {
startX: number startX: number
@ -19,6 +19,18 @@ export type TInitResize = {
height: number height: number
} }
export type TSize = {
width: number
height: number
}
export type TdResizePayload = {
x: number
y: number
/** 方向 */
dirs: 'top' | 'left' | 'bottom' | 'right'
}
/** 设置 resize 操作的初始值 */ /** 设置 resize 操作的初始值 */
export function initDResize(store: TWidgetStore, payload: TInitResize) { export function initDResize(store: TWidgetStore, payload: TInitResize) {
const mouseXY = store.dMouseXY const mouseXY = store.dMouseXY
@ -32,24 +44,14 @@ export function initDResize(store: TWidgetStore, payload: TInitResize) {
resizeWH.height = payload.height resizeWH.height = payload.height
} }
export type TdResizePayload = {
x: number
y: number
/** 方向 */
dirs: "top" | "left" | "bottom" | "right"
}
/** 更新组件宽高 */ /** 更新组件宽高 */
export function dResize(store: TWidgetStore, { x, y, dirs }: TdResizePayload) { export function dResize(store: TWidgetStore, { x, y, dirs }: TdResizePayload) {
const pageStore = useCanvasStore()
const canvasStore = useCanvasStore() const canvasStore = useCanvasStore()
const controlStore = useControlStore() const controlStore = useControlStore()
controlStore.setdResizeing(true) controlStore.setdResizeing(true)
// store.state.dResizeing = true
const page = pageStore.dPage const page = canvasStore.dPage
const target = store.dActiveElement const target = store.dActiveElement
const mouseXY = store.dMouseXY const mouseXY = store.dMouseXY
const widgetXY = store.dActiveWidgetXY const widgetXY = store.dActiveWidgetXY
@ -105,22 +107,39 @@ export function dResize(store: TWidgetStore, { x, y, dirs }: TdResizePayload) {
} }
if (parent.uuid !== '-1') { if (parent.uuid !== '-1') {
updateGroupSize(store, parent.uuid) updateGroupSize(store, parent.uuid)
// store.dispatch('updateGroupSize', parent.uuid)
} }
canvasStore.reChangeCanvas() canvasStore.reChangeCanvas()
// store.dispatch('reChangeCanvas')
} }
export type TResize = { export function resize(store: TWidgetStore, size: TSize) {
width: number const { width, height } = size
height: number const target = store.dActiveElement
}
export function resize(state: TWidgetStore, data: TResize) {
const { width, height } = data
const target = state.dActiveElement
if (!target) return target if (!target) return target
target.width = width target.width = width
target.height = height target.height = height
} }
/** 自适应适配所有元素 */
export function autoResizeAll(store: TWidgetStore, lastPageSize: TSize) {
if (!lastPageSize) return
const canvasStore = useCanvasStore()
const { width: lastWidth, height: lastHeight } = lastPageSize
const { width: pageWidth, height: pageHeight } = canvasStore.dPage
const originWHRatio = lastWidth / lastHeight // 原始比例
const WHRatio = pageWidth / pageHeight // 当前比例
const changeFn = originWHRatio > WHRatio ? 'max' : 'min'
const degree = [pageWidth / lastWidth, pageHeight / lastHeight]
const ratio = Math[changeFn](...degree)
const pageDiff = (pageWidth - lastWidth) / 2
for (const widget of store.dWidgets) {
const originWidth = widget.width
let diff = 0
if (widget.type === 'w-text') {
widget.fontSize && (widget.fontSize *= ratio)
} else widget.height *= ratio
widget.width *= ratio
diff = (originWidth - widget.width) / 2
widget.left = widget.left + diff + pageDiff
widget.top *= degree[1]
}
}

View File

@ -44,8 +44,6 @@ export function selectWidget(store: TWidgetStore, { uuid }: TSelectWidgetData) {
return return
} }
store.dSelectWidgets = [] store.dSelectWidgets = []
console.log("uuid", uuid);
if (uuid === '-1') { if (uuid === '-1') {
store.dActiveElement = pageStore.dPage store.dActiveElement = pageStore.dPage
const pageHistory = historyStore.dPageHistory const pageHistory = historyStore.dPageHistory

View File

@ -2,14 +2,14 @@
* @Author: Jeremy Yu * @Author: Jeremy Yu
* @Date: 2024-03-18 21:00:00 * @Date: 2024-03-18 21:00:00
* @Description: Store方法export * @Description: Store方法export
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-03-28 14:00:00 * @LastEditTime: 2024-04-10 08:17:16
*/ */
import { Store, defineStore } from "pinia"; import { Store, defineStore } from "pinia";
import { TInidDMovePayload, TMovePayload, dMove, initDMove, setDropOver, setMouseEvent, setdActiveElement, updateGroupSize, updateHoverUuid } from "./actions"; import { TInidDMovePayload, TMovePayload, dMove, initDMove, setDropOver, setMouseEvent, setdActiveElement, updateGroupSize, updateHoverUuid } from "./actions";
import { TPageState } from "@/store/design/canvas/d"; import { TPageState } from "@/store/design/canvas/d";
import { TInitResize, TResize, TdResizePayload, dResize, initDResize, resize } from "./actions/resize"; import { TInitResize, TSize, TdResizePayload, dResize, initDResize, resize, autoResizeAll } from "./actions/resize";
import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets } from "./actions/widget"; import { TUpdateWidgetMultiplePayload, TUpdateWidgetPayload, TsetWidgetStyleData, addWidget, deleteWidget, setDWidgets, setWidgetStyle, updateWidgetData, updateWidgetMultiple, lockWidgets } from "./actions/widget";
import { addGroup } from "./actions/group"; import { addGroup } from "./actions/group";
import { setTemplate } from "./actions/template"; import { setTemplate } from "./actions/template";
@ -113,12 +113,13 @@ type TAction = {
/** 设置拖拽时在哪个图层 */ /** 设置拖拽时在哪个图层 */
setDropOver: (uuid: string) => void setDropOver: (uuid: string) => void
setSelectItem: (data: TselectItem) => void setSelectItem: (data: TselectItem) => void
resize: (data: TResize) => void resize: (data: TSize) => void
setWidgetStyle: (data: TsetWidgetStyleData) => void setWidgetStyle: (data: TsetWidgetStyleData) => void
setDWidgets: (data: TdWidgetData[]) => void setDWidgets: (data: TdWidgetData[]) => void
lockWidgets: () => void lockWidgets: () => void
setMouseEvent: (e: MouseEvent | null) => void setMouseEvent: (e: MouseEvent | null) => void
setdActiveElement: (data: TdWidgetData) => void setdActiveElement: (data: TdWidgetData) => void
autoResizeAll: (data: TSize) => void
} }
const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("widgetStore", { const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("widgetStore", {
@ -180,6 +181,7 @@ const WidgetStore = defineStore<"widgetStore", TWidgetState, TGetter, TAction>("
lockWidgets() { lockWidgets(this) }, lockWidgets() { lockWidgets(this) },
setMouseEvent(event) { setMouseEvent(this, event) }, setMouseEvent(event) { setMouseEvent(this, event) },
setdActiveElement(data) { setdActiveElement(this, data) }, setdActiveElement(data) { setdActiveElement(this, data) },
autoResizeAll(data) { autoResizeAll(this, data) }
} }
}) })

View File

@ -1,16 +1,16 @@
/* /*
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2021-07-14 11:43:13 * @Date: 2021-07-14 11:43:13
* @Description: * @Description:
* @LastEditors: ShawnPhang * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2021-08-10 17:39:01 * @LastEditTime: 2024-04-08 18:23:15
*/ */
// import { Button, Field, Divider, NavBar, Toast, Popup } from 'vant'
import coms from '@/components/modules' import coms from '@/components/modules'
import pageStyle from '@/components/modules/layout/designBoard/pageStyle.vue'
import { App } from 'vue' import { App } from 'vue'
export default (Vue: App) => { export default (Vue: App) => {
coms(Vue) coms(Vue)
// Vue.component(Button.name, Button) Vue.component('page-style', pageStyle) // 背景属性已不在 modules/widgets 中,单独注册
// Vue.use(Field).use(Divider).use(NavBar).use(Toast).use(Popup) // Vue.use(Field).use(Divider).use(NavBar).use(Toast).use(Popup)
} }

View File

@ -11,13 +11,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { StyleValue, onMounted, reactive, nextTick } from 'vue' import { StyleValue, onMounted, reactive, nextTick } from 'vue'
import api from '@/api' import api from '@/api'
// import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
import Preload from '@/utils/plugins/preload' import Preload from '@/utils/plugins/preload'
import FontFaceObserver from 'fontfaceobserver' 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' import { useRoute } from 'vue-router'
import { wGroupSetting } from '@/components/modules/widgets/wGroup/groupSetting' import { wGroupSetting } from '@/components/modules/widgets/wGroup/groupSetting'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
@ -50,7 +48,7 @@ onMounted(() => {
async function load() { async function load() {
let backgroundImage = '' let backgroundImage = ''
let loadFlag = false let loadFlag = false
const { id, tempid, tempType: type } = route.query const { id, tempid, tempType: type = 0 } = route.query
if (id || tempid) { if (id || tempid) {
const postData = { const postData = {
id: Number(id || tempid), id: Number(id || tempid),

View File

@ -4,7 +4,7 @@
* @Description: * @Description:
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastUpdateContent: Support typescript * @LastUpdateContent: Support typescript
* @LastEditTime: 2024-04-05 05:34:43 * @LastEditTime: 2024-04-10 07:16:48
--> -->
<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">
@ -59,6 +59,8 @@
/> />
<!-- 漫游导航 --> <!-- 漫游导航 -->
<Tour ref="tourRef" :steps="[ref1, ref2, ref3, ref4]" /> <Tour ref="tourRef" :steps="[ref1, ref2, ref3, ref4]" />
<!-- 创建设计 -->
<createDesign ref="createDesignRef" />
</div> </div>
</template> </template>
@ -66,7 +68,7 @@
import _config from '../config' import _config from '../config'
import { import {
CSSProperties, computed, nextTick, CSSProperties, computed, nextTick,
onBeforeUnmount, onMounted, reactive, ref, onBeforeUnmount, onMounted, reactive, ref, Ref
} from 'vue' } from 'vue'
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'
@ -74,18 +76,16 @@ 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 lineGuides from '@/components/modules/layout/lineGuides.vue' import lineGuides from '@/components/modules/layout/lineGuides.vue'
import shortcuts from '@/mixins/shortcuts' import shortcuts from '@/mixins/shortcuts'
// import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
import HeaderOptions from './components/HeaderOptions.vue' import HeaderOptions from './components/HeaderOptions.vue'
import Folder from './components/Folder.vue' import Folder from './components/Folder.vue'
import Helper from './components/Helper.vue' import Helper from './components/Helper.vue'
import ProgressLoading from '@/components/common/ProgressLoading/download.vue' import ProgressLoading from '@/components/common/ProgressLoading/download.vue'
// import { useSetupMapGetters } from '@/common/hooks/mapGetters'
import { useRoute } from 'vue-router'
import { wGroupSetting } from '@/components/modules/widgets/wGroup/groupSetting' import { wGroupSetting } from '@/components/modules/widgets/wGroup/groupSetting'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useCanvasStore, useControlStore, useHistoryStore, useWidgetStore, useGroupStore } from '@/store' import { useCanvasStore, useControlStore, useHistoryStore, useWidgetStore, useGroupStore } from '@/store'
import type { ButtonInstance } from 'element-plus' import type { ButtonInstance } from 'element-plus'
import Tour from './components/Tour.vue' import Tour from './components/Tour.vue'
import createDesign from '@/components/business/create-design'
const ref1 = ref<ButtonInstance>() const ref1 = ref<ButtonInstance>()
const ref2 = ref<ButtonInstance>() const ref2 = ref<ButtonInstance>()
@ -111,7 +111,6 @@ const groupStore = useGroupStore()
const { dPage } = storeToRefs(useCanvasStore()) const { dPage } = storeToRefs(useCanvasStore())
const { dZoom } = storeToRefs(useCanvasStore()) const { dZoom } = storeToRefs(useCanvasStore())
const { dHistoryParams } = storeToRefs(useHistoryStore()) const { dHistoryParams } = storeToRefs(useHistoryStore())
// const { dActiveElement, dCopyElement } = storeToRefs(widgetStore)
const state = reactive<TState>({ const state = reactive<TState>({
style: { style: {
@ -128,7 +127,7 @@ const state = reactive<TState>({
const optionsRef = ref<typeof HeaderOptions | null>(null) const optionsRef = ref<typeof HeaderOptions | null>(null)
const zoomControlRef = ref<typeof zoomControl | null>(null) const zoomControlRef = ref<typeof zoomControl | null>(null)
const controlStore = useControlStore() const controlStore = useControlStore()
const route = useRoute() const createDesignRef: Ref<typeof createDesign | null> = ref(null)
const beforeUnload = function (e: Event): any { const beforeUnload = function (e: Event): any {
if (dHistoryParams.value.length > 0) { if (dHistoryParams.value.length > 0) {
@ -211,16 +210,13 @@ function downloadCancel() {
function loadData() { function loadData() {
// //
const { id, tempid, tempType } = route.query
if (!optionsRef.value) return if (!optionsRef.value) return
optionsRef.value.load(id, tempid, tempType, async () => { optionsRef.value.load(async () => {
if (!zoomControlRef.value) return if (!zoomControlRef.value) return
// await nextTick() // await nextTick()
// zoomControlRef.value.screenChange() // zoomControlRef.value.screenChange()
// page // page
widgetStore.selectWidget({ uuid: '-1' }) widgetStore.selectWidget({ uuid: '-1' })
// store.dispatch('selectWidget', { uuid: '-1' })
}) })
} }
@ -246,7 +242,10 @@ const fns: any = {
download: () => { download: () => {
optionsRef.value?.download() optionsRef.value?.download()
}, },
changeLineGuides changeLineGuides,
newDesign: () => {
createDesignRef.value?.open()
}
} }
const dealWith = (fnName: string, params?: any) => { const dealWith = (fnName: string, params?: any) => {
fns[fnName](params) fns[fnName](params)

View File

@ -3,7 +3,7 @@
* @Date: 2024-04-03 19:15:21 * @Date: 2024-04-03 19:15:21
* @Description: 文件 * @Description: 文件
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-05 06:01:20 * @LastEditTime: 2024-04-10 07:16:00
--> -->
<template> <template>
<el-dropdown trigger="click" size="large" placement="bottom-start"> <el-dropdown trigger="click" size="large" placement="bottom-start">
@ -12,7 +12,7 @@
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item><div class="item">创建设计</div></el-dropdown-item> <el-dropdown-item><div @click="$emit('select', 'newDesign')" class="item">创建设计</div></el-dropdown-item>
<el-dropdown-item @click="openPSD">导入文件</el-dropdown-item> <el-dropdown-item @click="openPSD">导入文件</el-dropdown-item>
<el-dropdown-item @click="$emit('select', 'save')" divided>保存</el-dropdown-item> <el-dropdown-item @click="$emit('select', 'save')" divided>保存</el-dropdown-item>
<el-dropdown-item @click="$emit('select', 'download')">导出文件</el-dropdown-item> <el-dropdown-item @click="$emit('select', 'download')">导出文件</el-dropdown-item>
@ -25,8 +25,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// import { ref } from 'vue' // import { ref, Ref } from 'vue'
import { useRouter} from 'vue-router' import { useRouter } from 'vue-router'
import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus' import { ElDropdown, ElDropdownItem, ElDropdownMenu } from 'element-plus'
const router = useRouter() const router = useRouter()

View File

@ -3,7 +3,7 @@
* @Date: 2022-01-12 11:26:53 * @Date: 2022-01-12 11:26:53
* @Description: 顶部操作按钮组 * @Description: 顶部操作按钮组
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-05 05:37:53 * @LastEditTime: 2024-04-09 23:39:24
--> -->
<template> <template>
<div class="top-title"><el-input v-model="state.title" placeholder="未命名的设计" class="input-wrap" /></div> <div class="top-title"><el-input v-model="state.title" placeholder="未命名的设计" class="input-wrap" /></div>
@ -16,6 +16,7 @@
<!-- <el-button @click="$store.commit('managerEdit', false)">取消</el-button> --> <!-- <el-button @click="$store.commit('managerEdit', false)">取消</el-button> -->
<div class="divide__line">|</div> <div class="divide__line">|</div>
</template> </template>
<watermark-option style="margin-right: .5rem;" />
<!-- <el-button @click="draw">绘制(测试)</el-button> --> <!-- <el-button @click="draw">绘制(测试)</el-button> -->
<!-- <copyRight> --> <!-- <copyRight> -->
<slot /> <slot />
@ -39,6 +40,7 @@ import _config from '@/config'
import useConfirm from '@/common/methods/confirm' import useConfirm from '@/common/methods/confirm'
import { useControlStore, useHistoryStore, useCanvasStore, useUserStore, useWidgetStore } from '@/store/index' import { useControlStore, useHistoryStore, useCanvasStore, useUserStore, useWidgetStore } from '@/store/index'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import watermarkOption from './Watermark.vue'
type TProps = { type TProps = {
modelValue?: boolean modelValue?: boolean
@ -51,6 +53,7 @@ type TEmits = {
type TState= { type TState= {
stateBollean: boolean, stateBollean: boolean,
wmBollean: boolean,
title: string, title: string,
loading: boolean, loading: boolean,
} }
@ -80,6 +83,7 @@ const { dHistory, dPageHistory } = storeToRefs(useHistoryStore())
const state = reactive<TState>({ const state = reactive<TState>({
stateBollean: false, stateBollean: false,
wmBollean: false,
title: '', title: '',
loading: false, loading: false,
}) })
@ -91,7 +95,6 @@ async function save(hasCover: boolean = false) {
return return
} }
// store.commit('setShowMoveable', false) //
controlStore.setShowMoveable(false) // controlStore.setShowMoveable(false) //
// console.log(proxy?.dPage, proxy?.dWidgets) // console.log(proxy?.dPage, proxy?.dWidgets)
@ -189,11 +192,17 @@ async function saveTemp() {
// ...mapActions(['pushHistory', 'addGroup']), // ...mapActions(['pushHistory', 'addGroup']),
async function load(id: number, tempId: number, type: number, cb: () => void) { async function load(cb: () => void) {
const { id, tempid: tempId, tempType: type, w_h } = route.query
if (route.name !== 'Draw') { if (route.name !== 'Draw') {
await useFontStore.init() // await useFontStore.init() //
} }
const apiName = tempId && !id ? 'getTempDetail' : 'getWorks' const apiName = tempId && !id ? 'getTempDetail' : 'getWorks'
if (w_h) {
const wh: any = w_h.toString().split('*')
wh[0] && (dPage.value.width = wh[0])
wh[1] && (dPage.value.height = wh[1])
}
if (!id && !tempId) { if (!id && !tempId) {
cb() cb()
return return

View File

@ -0,0 +1,22 @@
<!--
* @Author: ShawnPhang
* @Date: 2024-04-08 16:50:04
* @Description: 画布加水印
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2024-04-08 18:00:37
-->
<template>
<el-switch v-model="wmBollean" @change="wmChange" size="large" inline-prompt style="--el-switch-off-color: #9999999e" active-text="移除水印" inactive-text="官方水印" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useBaseStore } from '@/store'
const baseStore = useBaseStore()
const wmBollean = ref(false)
function wmChange(isRemove: string | number | boolean) {
baseStore.changeWatermark(isRemove ? '' : ['迅排设计', 'poster-design'])
}
</script>