mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
Merge pull request #89 from JeremyYu-cn/feat-pinia
Rebuilt: base store to pinia
This commit is contained in:
commit
8372b3d893
40
README.md
40
README.md
@ -1,19 +1,21 @@
|
||||
**[在线体验网址](https://design.palxp.cn/)** | **[中文文档](https://xp.palxp.cn/)** | [常见问题](https://xp.palxp.cn/#/articles/1689323321667) | [架构说明](https://xp.palxp.cn/#/articles/1689321259854)
|
||||
**[在线体验网站](https://design.palxp.cn/)** | **[在线文档](https://xp.palxp.cn/)** | [常见问题](https://xp.palxp.cn/#/articles/1689323321667)
|
||||
|
||||
---
|
||||
|
||||
## Poster Design
|
||||
## 迅排设计
|
||||
|
||||
迅排设计是一款漂亮易用且功能强大的开源创意图片编辑器,是对标稿定设计、创客贴、Canva 等商业产品的免费在线设计工具。
|
||||
一款漂亮易用且功能强大的创意图片编辑器,对标稿定设计、创客贴、Canva 等商业产品。
|
||||
|
||||
适用于多种场景:海报图片生成、电商分享图、文章长图、视频/公众号封面等,无需下载软件即可轻松实现云端编辑、迅速完成图文排版。
|
||||
|
||||
[](https://design.palxp.cn/)
|
||||
|
||||
适用于多种场景:海报图片生成、电商分享图、文章长图、视频/公众号封面等,无需下载软件即可轻松实现云端编辑、迅速完成图文排版。
|
||||
### 特点
|
||||
|
||||
- 丝滑的页面操作体验,丰富的交互细节,基础功能完善
|
||||
- 采用服务端生成图片,能确保多端出图统一性,支持各种 CSS 特性
|
||||
- 简易 AI 抠图工具,上传图片一键去除背景
|
||||
- 技术栈:Vue3 、Vite2 、Vuex 、ElementPlus,开发体验畅快
|
||||
- 技术栈:Vue3 、Vite5 、Vuex 、ElementPlus,开发体验畅快
|
||||
- 图片生成:Puppeteer、Express
|
||||
|
||||
### 支持功能
|
||||
@ -35,25 +37,35 @@
|
||||
git clone https://github.com/palxiao/poster-design.git
|
||||
cd poster-design
|
||||
npm run prepared
|
||||
npm run serve
|
||||
npm run dev
|
||||
cd screreenshot
|
||||
npm run dev
|
||||
```
|
||||
|
||||

|
||||
|
||||
访问 http://127.0.0.1:5173/ 查看网页。点此查看[完整说明文档](https://xp.palxp.cn/#/articles/1689319644311)。
|
||||
访问 http://127.0.0.1:5173/ 查看网页。点此查看[更多说明文档](https://xp.palxp.cn/#/articles/1689319644311)。
|
||||
|
||||
### 图片生成服务
|
||||
|
||||
代码位于根目录 [/screenshot](https://github.com/palxiao/poster-design/tree/main/screenshot),接口API文档点此查看:[接口 API 文档](https://xp.palxp.cn/apidoc/screenshot.html)。
|
||||
|
||||
> 更多相关事项请进入该目录下查看 [README.md](https://github.com/palxiao/poster-design/blob/main/screenshot/README.md) 文件。 Docker 部署:[参考说明](https://xp.palxp.cn/#/articles/1689319644311?id=docker%e5%ae%b9%e5%99%a8)。
|
||||
|
||||
### 服务端
|
||||
|
||||
目前本项目演示 Demo 中的后端接口参考:[接口 API 文档](https://xp.palxp.cn/apidoc/index.html)。
|
||||
后端需要自己开发,目前本项目演示 Demo 中的后端接口参考:[接口 API 文档](https://xp.palxp.cn/apidoc/index.html)。
|
||||
|
||||
## 其它
|
||||
|
||||
我们尝试沉淀一个高质量内容社区,形成可持续学习的平台,同时解决开发者在项目中遇到的疑难和困惑,帮大家少走一些弯路。
|
||||
|
||||
<img style="width: 380px;" src="https://github.com/palxiao/poster-design/assets/21021314/643dcc8b-ef73-4c76-a78c-a7c377b5f268" />
|
||||
|
||||
也欢迎关注公众号:品味前端,回复“加群”进行交流。
|
||||
|
||||
<img style="width: 380px;" src="https://xp.palxp.cn/images/2024-3-1-1709306365949.png" />
|
||||
|
||||
-----
|
||||
|
||||
本项目最早使用 Vue2 开发,现改用 Vue3 重构中。[一些迭代计划记录](https://xp.palxp.cn/#/articles/1689319986889?id=%e8%bf%ad%e4%bb%a3%e8%ae%a1%e5%88%92).
|
||||
|
||||
目前开源版仍在持续迭代中,还有很多的不足,可以将你遇到的问题在 Issues 中提出,或者提交 Pull Request 帮助完善。
|
||||
@ -67,13 +79,7 @@ npm run serve
|
||||
- [qr-code-styling](https://qr-code-styling.com/): 风格化二维码
|
||||
- [rembg](https://github.com/danielgatis/rembg): 图片抠图,使用 u2net 预训练模型
|
||||
|
||||
### 交流群
|
||||
|
||||
| 作者微信:备注加群 | 关注公众号 |
|
||||
| --- | --- |
|
||||
| <img style="width: 240px;" src="https://xp.palxp.cn/images/2024-3-1-1709306328344.png" /> | <img style="width: 320px;" src="https://xp.palxp.cn/images/2024-3-1-1709306365949.png" /> |
|
||||
|
||||
开源不易,别忘了给本项目点个 **Star** ~
|
||||
开源不易,最后别忘了给本项目点个 **Star** ~
|
||||
|
||||
[](https://star-history.com/#palxiao/poster-design&Date)
|
||||
|
||||
|
51
package-lock.json
generated
51
package-lock.json
generated
@ -25,6 +25,7 @@
|
||||
"moveable-helper": "^0.4.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"selecto": "^1.13.0",
|
||||
"throttle-debounce": "^3.0.1",
|
||||
@ -3276,6 +3277,56 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz",
|
||||
"integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.5.0",
|
||||
"vue-demi": ">=0.14.5"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.4.0",
|
||||
"typescript": ">=4.4.4",
|
||||
"vue": "^2.6.14 || ^3.3.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pinia/node_modules/vue-demi": {
|
||||
"version": "0.14.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
|
||||
"integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.35",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||
|
@ -28,6 +28,7 @@
|
||||
"moveable-helper": "^0.4.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"qr-code-styling": "^1.6.0-rc.1",
|
||||
"selecto": "^1.13.0",
|
||||
"throttle-debounce": "^3.0.1",
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div id="page-design" ref="page_design" :style="{ paddingTop: dPaddingTop + 'px' }">
|
||||
<!-- <el-scrollbar> -->
|
||||
<div
|
||||
id="out-page"
|
||||
class="out-page"
|
||||
@ -54,6 +55,7 @@
|
||||
<!-- <size-control v-if="dSelectWidgets.length === 0" /> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- </el-scrollbar> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -61,7 +63,7 @@
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import { mapGetters, mapActions, useStore } from 'vuex'
|
||||
import { getTarget } from '@/common/methods/target'
|
||||
|
||||
// import { ElScrollbar } from 'element-plus'
|
||||
import setWidgetData from '@/common/methods/DesignFeatures/setWidgetData'
|
||||
import PointImg from '@/utils/plugins/pointImg'
|
||||
import getComponentsData from '@/common/methods/DesignFeatures/setComponents'
|
||||
|
@ -32,6 +32,7 @@ import useConfirm from '@/common/methods/confirm'
|
||||
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||
import imgWaterFall from './components/imgWaterFall.vue'
|
||||
import { IGetTempListData } from '@/api/home'
|
||||
import useUserStore from '@/store/modules/base/user'
|
||||
|
||||
type TState = {
|
||||
loading: boolean
|
||||
@ -52,6 +53,7 @@ const listRef = ref<HTMLElement | null>(null)
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const userStore = useUserStore()
|
||||
const state = reactive<TState>({
|
||||
loading: false,
|
||||
loadDone: false,
|
||||
@ -64,8 +66,9 @@ const { tempEditing, dHistoryParams } = useSetupMapGetters(['tempEditing', 'dHis
|
||||
|
||||
const pageOptions: TPageOptions = { page: 0, pageSize: 20, cate: 1 }
|
||||
const { cate, edit } = route.query
|
||||
cate && (pageOptions.cate = (cate as LocationQueryValue) || 1)
|
||||
edit && store.commit('managerEdit', true)
|
||||
cate && (pageOptions.cate = (cate as LocationQueryValue) ?? 1)
|
||||
// edit && store.commit('managerEdit', true)
|
||||
edit && userStore.managerEdit(true)
|
||||
|
||||
// onMounted(async () => {})
|
||||
|
||||
@ -116,7 +119,8 @@ async function selectItem(item: IGetTempListData) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
store.commit('managerEdit', false)
|
||||
// store.commit('managerEdit', false)
|
||||
userStore.managerEdit(false)
|
||||
store.commit('setDWidgets', [])
|
||||
|
||||
setTempId(item.id)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-02 19:10:06
|
||||
* @Description: 选项选择(未拆分字体选择器)
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-11-20 18:21:55
|
||||
* @LastEditTime: 2024-03-15 17:34:00
|
||||
-->
|
||||
<template>
|
||||
<div ref="select" class="value-select" :style="{ width: inputWidth }">
|
||||
@ -65,7 +65,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||
|
||||
type TProps = {
|
||||
label?: string
|
||||
modelValue?: Record<string, any>
|
||||
modelValue?: Record<string, any> | string | number
|
||||
suffix?: string
|
||||
data: Record<string, any>
|
||||
disable?: boolean
|
||||
@ -189,9 +189,8 @@ function down() {
|
||||
</style>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// Color variables (appears count calculates by raw css)
|
||||
@color0: #e1e1e1; // Appears 2 times
|
||||
@color1: #d1d1d1; // Appears 2 times
|
||||
@color0: #e1e1e1;
|
||||
@color1: #d1d1d1;
|
||||
|
||||
.value-select {
|
||||
// height: 60px;
|
||||
|
@ -13,7 +13,9 @@ import utils from './utils'
|
||||
import 'normalize.css/normalize.css'
|
||||
import '@/assets/styles/index.less'
|
||||
import elementConfig from './utils/widgets/elementConfig'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
const pinia = createPinia()
|
||||
const app = createApp(App)
|
||||
|
||||
elementConfig.components.forEach((component) => {
|
||||
@ -26,6 +28,7 @@ elementConfig.plugins.forEach((plugin) => {
|
||||
|
||||
app
|
||||
.use(store)
|
||||
.use(pinia)
|
||||
.use(router)
|
||||
.use(utils)
|
||||
.mount('#app')
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-03-09 16:29:54
|
||||
* @Description: 处理和ctrl建相关的操作
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-09 09:49:54
|
||||
* @LastEditTime: 2024-03-15 17:34:51
|
||||
*/
|
||||
import store from '@/store'
|
||||
import handlePaste from './handlePaste'
|
||||
@ -50,7 +50,7 @@ function checkGroupChild(pid: number | string, key: any) {
|
||||
return itHas
|
||||
}
|
||||
/**
|
||||
* 复制
|
||||
* 复制元素
|
||||
*/
|
||||
function copy() {
|
||||
if (store.getters.dActiveElement.uuid === '-1') {
|
||||
@ -64,13 +64,14 @@ function copy() {
|
||||
* 粘贴
|
||||
*/
|
||||
function paste() {
|
||||
handlePaste()
|
||||
if (store.getters.dCopyElement.length === 0) {
|
||||
return
|
||||
} else if (store.getters.dActiveElement.isContainer && checkGroupChild(store.getters.dActiveElement.uuid, 'editable')) {
|
||||
return
|
||||
}
|
||||
!store.getters.dActiveElement.editable && store.dispatch('pasteWidget')
|
||||
handlePaste().then(() => {
|
||||
if (store.getters.dCopyElement.length === 0) {
|
||||
return
|
||||
} else if (store.getters.dActiveElement.isContainer && checkGroupChild(store.getters.dActiveElement.uuid, 'editable')) {
|
||||
return
|
||||
}
|
||||
!store.getters.dActiveElement.editable && store.dispatch('pasteWidget')
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 撤销
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2023-10-09 09:47:40
|
||||
* @Description: 处理剪贴板
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-09 10:35:21
|
||||
* @LastEditTime: 2024-03-15 17:35:18
|
||||
*/
|
||||
|
||||
// window.addEventListener('paste', (e: any) => {
|
||||
@ -17,45 +17,56 @@ import Qiniu from '@/common/methods/QiNiu'
|
||||
import _config from '@/config'
|
||||
import { getImage } from '@/common/methods/getImgDetail'
|
||||
import wImage from '@/components/modules/widgets/wImage/wImage.vue'
|
||||
// import wText from '@/components/modules/widgets/wText/wText.vue'
|
||||
import { wTextSetting } from '@/components/modules/widgets/wText/wTextSetting'
|
||||
import wText from '@/components/modules/widgets/wText/wText.vue'
|
||||
|
||||
export default () => {
|
||||
navigator.clipboard
|
||||
.read()
|
||||
.then(async (dataTransfer: any) => {
|
||||
for (let i = 0; i < dataTransfer.length; i++) {
|
||||
const item = dataTransfer[i]
|
||||
if (item.types.toString().indexOf('image') !== -1) {
|
||||
const imageBlob = await item.getType(item.types[0])
|
||||
const file = new File([imageBlob], 'screenshot.png', { type: 'image/png' })
|
||||
// 上传图片
|
||||
const qnOptions = { bucket: 'xp-design', prePath: 'user' }
|
||||
const result: any = await Qiniu.upload(file, qnOptions)
|
||||
const { width, height }: any = await getImage(file)
|
||||
const url = _config.IMG_URL + result.key
|
||||
await api.material.addMyPhoto({ width, height, url })
|
||||
// 添加图片到画布中
|
||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
const setting = JSON.parse(JSON.stringify(wImage.setting))
|
||||
setting.width = width
|
||||
setting.height = height
|
||||
setting.imgUrl = url
|
||||
const { width: pW, height: pH } = store.getters.dPage
|
||||
setting.left = pW / 2 - width / 2
|
||||
setting.top = pH / 2 - height / 2
|
||||
store.dispatch('addWidget', setting)
|
||||
break
|
||||
} else if (item.types.toString().indexOf('text') !== -1) {
|
||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
const setting = JSON.parse(JSON.stringify(wTextSetting))
|
||||
setting.text = await navigator.clipboard.readText()
|
||||
store.dispatch('addWidget', setting)
|
||||
break
|
||||
return new Promise<void>((resolve) => {
|
||||
navigator.clipboard
|
||||
.read()
|
||||
.then(async (dataTransfer: any) => {
|
||||
if (store.getters.dActiveElement.editable) {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('无法读取剪贴板内容:', error)
|
||||
})
|
||||
for (let i = 0; i < dataTransfer.length; i++) {
|
||||
const item = dataTransfer[i]
|
||||
if (item.types.toString().indexOf('image') !== -1) {
|
||||
const imageBlob = await item.getType(item.types[0])
|
||||
const file = new File([imageBlob], 'screenshot.png', { type: 'image/png' })
|
||||
// 上传图片
|
||||
const qnOptions = { bucket: 'xp-design', prePath: 'user' }
|
||||
const result: any = await Qiniu.upload(file, qnOptions)
|
||||
const { width, height }: any = await getImage(file)
|
||||
const url = _config.IMG_URL + result.key
|
||||
await api.material.addMyPhoto({ width, height, url })
|
||||
// 添加图片到画布中
|
||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
const setting = JSON.parse(JSON.stringify(wImage.setting))
|
||||
setting.width = width
|
||||
setting.height = height
|
||||
setting.imgUrl = url
|
||||
const { width: pW, height: pH } = store.getters.dPage
|
||||
setting.left = pW / 2 - width / 2
|
||||
setting.top = pH / 2 - height / 2
|
||||
store.dispatch('addWidget', setting)
|
||||
// 清空剪贴板,防止多次上传图片
|
||||
navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
'text/plain': new Blob([''], {type: 'text/plain'})
|
||||
})
|
||||
])
|
||||
break
|
||||
} else if (item.types.toString().indexOf('text') !== -1) {
|
||||
store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
const setting = JSON.parse(JSON.stringify(wText.setting))
|
||||
setting.text = await navigator.clipboard.readText()
|
||||
store.dispatch('addWidget', setting)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 剪贴板内容为空
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
import base from './modules/base'
|
||||
// import base from './modules/base'
|
||||
import design from './modules/design'
|
||||
|
||||
export default createStore({
|
||||
...base,
|
||||
// ...base,
|
||||
modules: {
|
||||
design,
|
||||
},
|
||||
|
@ -2,18 +2,19 @@
|
||||
* 异步操作 store.dispatch() 调用
|
||||
*/
|
||||
|
||||
interface Iprops {
|
||||
commit: (a: any, b: any) => void
|
||||
state: any
|
||||
}
|
||||
// interface Iprops {
|
||||
// commit: (a: any, b: any) => void
|
||||
// state: any
|
||||
// }
|
||||
|
||||
export default {
|
||||
hideLoading(props: Iprops, data: Type.Object) {
|
||||
setTimeout(() => {
|
||||
props.commit('loading', false)
|
||||
}, 600)
|
||||
},
|
||||
setFonts(store: Iprops, list: Type.Object) {
|
||||
store.state.fonts = list
|
||||
},
|
||||
}
|
||||
// export default {
|
||||
// hideLoading(props: Iprops, data: Type.Object) {
|
||||
// setTimeout(() => {
|
||||
// props.commit('loading', false)
|
||||
// }, 600)
|
||||
// },
|
||||
// setFonts(store: Iprops, list: Type.Object) {
|
||||
// store.state.fonts = list
|
||||
// },
|
||||
|
||||
// }
|
||||
|
@ -2,48 +2,86 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-12-16 16:20:16
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-09-28 17:42:25
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-17 15:00:00
|
||||
*/
|
||||
import mutations from './mutations'
|
||||
import actions from './actions'
|
||||
import _config from '@/config'
|
||||
|
||||
const all = {
|
||||
state: {
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
// import actions from './actions'
|
||||
// import _config from '@/config'
|
||||
|
||||
type TStoreBaseState = {
|
||||
loading: boolean | null
|
||||
scroll: boolean
|
||||
/** fonts */
|
||||
fonts: string[]
|
||||
/** 抠图服务 */
|
||||
app: string | null
|
||||
}
|
||||
|
||||
type TUserAction = {
|
||||
hideLoading: () => void
|
||||
setFonts: (list: string[]) => void
|
||||
}
|
||||
|
||||
const useBaseStore = defineStore<'base', TStoreBaseState, {}, TUserAction>('base', {
|
||||
state: () => ({
|
||||
loading: null,
|
||||
online: true, // 登录状态,
|
||||
user: {
|
||||
name: localStorage.getItem('username'),
|
||||
}, // 储存用户信息
|
||||
scroll: true,
|
||||
manager: '', // 是否为管理员模式
|
||||
tempEditing: false, // 管理员是否正在编辑模板
|
||||
fonts: [], // 缓存字体列表
|
||||
app: null, // 抠图服务
|
||||
},
|
||||
getters: {
|
||||
online: (state: Type.Object) => {
|
||||
return state.online
|
||||
},
|
||||
user: (state: Type.Object) => {
|
||||
return state.user
|
||||
},
|
||||
manager: (state: Type.Object) => {
|
||||
return state.manager
|
||||
},
|
||||
tempEditing: (state: Type.Object) => {
|
||||
return state.tempEditing
|
||||
},
|
||||
fonts: (state: Type.Object) => {
|
||||
return state.fonts
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
...mutations,
|
||||
},
|
||||
}),
|
||||
actions: {
|
||||
...actions,
|
||||
},
|
||||
}
|
||||
export default all
|
||||
/** 隐藏loading */
|
||||
hideLoading() {
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 600)
|
||||
},
|
||||
setFonts(list: string[]) {
|
||||
this.fonts = list
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export default useBaseStore
|
||||
|
||||
// const all = {
|
||||
// state: {
|
||||
// loading: null,
|
||||
// online: true, // 登录状态,
|
||||
// user: {
|
||||
// name: localStorage.getItem('username'),
|
||||
// }, // 储存用户信息
|
||||
// scroll: true,
|
||||
// manager: '', // 是否为管理员模式
|
||||
// tempEditing: false, // 管理员是否正在编辑模板
|
||||
// fonts: [], // 缓存字体列表
|
||||
// app: null, // 抠图服务
|
||||
// },
|
||||
// getters: {
|
||||
// online: (state: Type.Object) => {
|
||||
// return state.online
|
||||
// },
|
||||
// user: (state: Type.Object) => {
|
||||
// return state.user
|
||||
// },
|
||||
// manager: (state: Type.Object) => {
|
||||
// return state.manager
|
||||
// },
|
||||
// tempEditing: (state: Type.Object) => {
|
||||
// return state.tempEditing
|
||||
// },
|
||||
// fonts: (state: Type.Object) => {
|
||||
// return state.fonts
|
||||
// },
|
||||
// },
|
||||
// mutations: {
|
||||
// ...mutations,
|
||||
// },
|
||||
// actions: {
|
||||
// ...actions,
|
||||
// },
|
||||
// }
|
||||
|
||||
|
@ -8,35 +8,35 @@
|
||||
|
||||
// import { Toast } from 'vant'
|
||||
|
||||
export default {
|
||||
loading(state: Type.Object, data: any) {
|
||||
// Toast.clear();
|
||||
// let msg = ''
|
||||
// if (typeof data === 'string') {
|
||||
// msg = data
|
||||
// } else {
|
||||
// Toast.clear();
|
||||
// return false
|
||||
// }
|
||||
// Toast.loading({
|
||||
// duration: 0, // 持续展示 toast
|
||||
// loadingType: 'spinner',
|
||||
// message: msg
|
||||
// });
|
||||
},
|
||||
changeRoute(state: Type.Object, from: string) {
|
||||
state.routeFrom = from
|
||||
},
|
||||
changeOnline(state: Type.Object, status: string) {
|
||||
state.online = status
|
||||
},
|
||||
changeUser(state: Type.Object, name: string) {
|
||||
state.user.name = name
|
||||
// state.user = Object.assign({}, state.user)
|
||||
state.user = { ...state.user }
|
||||
localStorage.setItem('username', name)
|
||||
},
|
||||
managerEdit(state: Type.Object, status: string) {
|
||||
state.tempEditing = status
|
||||
},
|
||||
}
|
||||
// export default {
|
||||
// loading(state: Type.Object, data: any) {
|
||||
// // Toast.clear();
|
||||
// // let msg = ''
|
||||
// // if (typeof data === 'string') {
|
||||
// // msg = data
|
||||
// // } else {
|
||||
// // Toast.clear();
|
||||
// // return false
|
||||
// // }
|
||||
// // Toast.loading({
|
||||
// // duration: 0, // 持续展示 toast
|
||||
// // loadingType: 'spinner',
|
||||
// // message: msg
|
||||
// // });
|
||||
// },
|
||||
// changeRoute(state: Type.Object, from: string) {
|
||||
// state.routeFrom = from
|
||||
// },
|
||||
// changeOnline(state: Type.Object, status: string) {
|
||||
// state.online = status
|
||||
// },
|
||||
// changeUser(state: Type.Object, name: string) {
|
||||
// state.user.name = name
|
||||
// // state.user = Object.assign({}, state.user)
|
||||
// state.user = { ...state.user }
|
||||
// localStorage.setItem('username', name)
|
||||
// },
|
||||
// managerEdit(state: Type.Object, status: string) {
|
||||
// state.tempEditing = status
|
||||
// },
|
||||
// }
|
||||
|
58
src/store/modules/base/user.ts
Normal file
58
src/store/modules/base/user.ts
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-17 15:00:00
|
||||
* @Description: User全局状态管理
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-17 15:00:00
|
||||
*/
|
||||
|
||||
import { defineStore } from "pinia"
|
||||
|
||||
type TUserStoreState = {
|
||||
/** 登录状态 */
|
||||
online: boolean
|
||||
/** 储存用户信息 */
|
||||
user: {
|
||||
name: string | null
|
||||
}
|
||||
/**是否为管理员模式 */
|
||||
manager: string
|
||||
/** 管理员是否正在编辑模板 */
|
||||
tempEditing: boolean
|
||||
}
|
||||
|
||||
type TUserAction = {
|
||||
/** 修改登录状态 */
|
||||
changeOnline: (state: boolean) => void
|
||||
/** 修改登录用户 */
|
||||
changeUser: (userName: string) => void
|
||||
managerEdit: (status: boolean) => void
|
||||
}
|
||||
|
||||
const useUserStore = defineStore<'userStore', TUserStoreState, {}, TUserAction>('userStore', {
|
||||
state: () => ({
|
||||
online: true, // 登录状态,
|
||||
user: {
|
||||
name: localStorage.getItem('username'),
|
||||
}, // 储存用户信息
|
||||
manager: '', // 是否为管理员模式
|
||||
tempEditing: false, // 管理员是否正在编辑模板
|
||||
}),
|
||||
actions: {
|
||||
changeOnline(status: boolean) {
|
||||
this.online = status
|
||||
},
|
||||
changeUser(name: string) {
|
||||
this.user.name = name
|
||||
// state.user = Object.assign({}, state.user)
|
||||
// state.user = { ...state.user }
|
||||
localStorage.setItem('username', name)
|
||||
},
|
||||
managerEdit(status: boolean) {
|
||||
this.tempEditing = status
|
||||
},
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
export default useUserStore
|
@ -237,7 +237,7 @@ export default {
|
||||
if (activeElement.type === 'page') {
|
||||
return
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText('') // 清空系统剪贴板内容
|
||||
const container = []
|
||||
const selectWidgets = store.state.dSelectWidgets
|
||||
if (selectWidgets.length === 0) {
|
||||
|
@ -29,7 +29,6 @@ const all = {
|
||||
dDraging: false, // 是否正在抓取组件
|
||||
dResizeing: false, // 是否正在调整组件宽高
|
||||
dShowRefLine: true, // 是否显示参考线
|
||||
|
||||
dResizeWH: {
|
||||
// 初始化调整大小时组件的宽高
|
||||
width: 0,
|
||||
|
0
src/store/pinia.ts
Normal file
0
src/store/pinia.ts
Normal file
@ -6,8 +6,10 @@
|
||||
* @LastEditTime: 2024-02-26 17:54:00
|
||||
*/
|
||||
import axios, { AxiosRequestConfig, AxiosResponse, AxiosStatic } from 'axios'
|
||||
import store from '@/store'
|
||||
// import store from '@/store'
|
||||
import app_config, { LocalStorageKey } from '@/config'
|
||||
import useUserStore from '@/store/modules/base/user';
|
||||
import useBaseStore from '@/store/modules/base';
|
||||
|
||||
axios.defaults.timeout = 30000
|
||||
axios.defaults.headers.authorization = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAwMDEsImV4cCI6MTc4ODU3NDc1MDU4NX0.L_t6DFD48Dm6rUPfgIgOWJkz18En1m_-hhMHcpbxliY';
|
||||
@ -53,7 +55,8 @@ axios.interceptors.response.use((res: AxiosResponse<any>) => {
|
||||
}
|
||||
if (res.data.code === 401) {
|
||||
console.log('登录失效')
|
||||
store.commit('changeOnline', false)
|
||||
useUserStore().changeOnline(false)
|
||||
// store.commit('changeOnline', false)
|
||||
}
|
||||
|
||||
if (res.data.result && res.data.code === 200) {
|
||||
@ -67,7 +70,8 @@ axios.interceptors.response.use((res: AxiosResponse<any>) => {
|
||||
(error) => {
|
||||
// if (error.response.status === 401) {
|
||||
// }
|
||||
store.dispatch('hideLoading')
|
||||
useBaseStore().hideLoading()
|
||||
// store.dispatch('hideLoading')
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
@ -12,7 +12,8 @@
|
||||
<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>
|
||||
<el-button plain type="primary" @click="saveTemp">保存模板</el-button>
|
||||
<el-button @click="$store.commit('managerEdit', false)">取消</el-button>
|
||||
<el-button @click="userStore.managerEdit(false)">取消</el-button>
|
||||
<!-- <el-button @click="$store.commit('managerEdit', false)">取消</el-button> -->
|
||||
<div class="divide__line">|</div>
|
||||
</template>
|
||||
<!-- <el-button @click="draw">绘制(测试)</el-button> -->
|
||||
@ -39,6 +40,7 @@ import _config from '@/config'
|
||||
import useConfirm from '@/common/methods/confirm'
|
||||
import wGroup from '@/components/modules/widgets/wGroup/wGroup.vue'
|
||||
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||
import useUserStore from '@/store/modules/base/user'
|
||||
|
||||
type TProps = {
|
||||
modelValue?: boolean
|
||||
@ -60,6 +62,7 @@ const emit = defineEmits<TEmits>()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const userStore = useUserStore()
|
||||
const canvasImage = ref<typeof SaveImage | null>(null)
|
||||
const {
|
||||
dPage, dWidgets, tempEditing, dHistory, dPageHistory
|
||||
|
@ -58,6 +58,7 @@ export default defineConfig({
|
||||
},
|
||||
server: {
|
||||
hmr: { overlay: false },
|
||||
host: '127.0.0.1'
|
||||
// proxy: {
|
||||
// '/api': {
|
||||
// target: '',
|
||||
|
Loading…
x
Reference in New Issue
Block a user