mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-28 04:10:31 +08:00
code: color input use blur
This commit is contained in:
parent
aac211eafa
commit
6d42f3a6ab
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
config.json
|
config.json
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
screenshot/node_modules/
|
screenshot/node_modules/
|
||||||
screenshot/dist/
|
screenshot/dist/
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 ShawnPhang
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
90
README.md
90
README.md
@ -1,4 +1,6 @@
|
|||||||
[在线体验](https://design.palxp.com/) | [文档网站](https://xp.palxp.com/) | [项目架构及目录](https://xp.palxp.com/#/articles/1689321259854)
|
**[在线体验](https://design.palxp.com/)** | **[中文文档网站](https://xp.palxp.com/)** | [架构及目录说明](https://xp.palxp.com/#/articles/1689321259854)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 迅排设计
|
## 迅排设计
|
||||||
|
|
||||||
@ -29,7 +31,7 @@
|
|||||||
|
|
||||||
### 拉取源码
|
### 拉取源码
|
||||||
|
|
||||||
> 环境需求:**Node.js v16** 以上版本
|
> 环境需求:**Node.js v16.18** 以上版本
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/palxiao/poster-design.git
|
git clone https://github.com/palxiao/poster-design.git
|
||||||
@ -50,78 +52,33 @@ npm run prepared
|
|||||||
npm run serve
|
npm run serve
|
||||||
```
|
```
|
||||||
|
|
||||||
> 将会同时运行前端界面与图片生成服务:
|
> 将会同时运行前端界面与图片生成服务(`3000`端口为前端项目,`7001`端口为图片生成服务):
|
||||||
>
|
>
|
||||||
> 
|
> 
|
||||||
> 如果你本地没有成功启动两个服务,可能是 win 系统不兼容,手动进 `screenshot` 目录安装依赖并启动服务,或是使用 VSCode 自带的终端来运行命令,不要使用 CMD。
|
> 如果你本地没有成功启动两个服务,可能是 win 系统不兼容,手动进 `screenshot` 目录安装依赖(`npm install`)并启动服务(`npm run dev`)
|
||||||
|
> 或者使用 VSCode 自带的终端来运行命令,不要使用 CMD。
|
||||||
|
|
||||||
合成图片时本地会启动一个 Chrome 浏览器实例。
|
合成图片时本地会启动一个 Chrome 浏览器实例。
|
||||||
|
|
||||||
### 打包
|
### 打包
|
||||||
|
|
||||||
```
|
| 前端页面 | 图片生成服务 |
|
||||||
npm run v-build <- 前端页面
|
| ----------------- | ------------------------------------- |
|
||||||
npm run build <- 图片生成服务( sreenshot 目录下)
|
| `npm run v-build` | `cd sreenshot` <br /> `npm run build` |
|
||||||
```
|
|
||||||
|
|
||||||
### 服务端
|
### 后端
|
||||||
|
|
||||||
可参考[接口 API 文档](https://xp.palxp.com/apidoc/index.html)自行实现服务端。
|
根据你的具体场景自行实现,目前本项目中的所有服务端接口可参考:[接口 API 文档](https://xp.palxp.com/apidoc/index.html)。
|
||||||
|
|
||||||
### 图片生成服务
|
### 图片生成服务
|
||||||
|
|
||||||
代码位于 `screenshots` 目录下,查看[接口 API 文档](https://xp.palxp.com/apidoc/screenshot.html)。
|
代码位于 [screenshots/](https://github.com/palxiao/poster-design/tree/main/screenshot) 目录下,查看[接口 API 文档](https://xp.palxp.com/apidoc/screenshot.html)。
|
||||||
|
|
||||||
目录结构比较简单,主要就实现了三个接口,其中 api/screenshots 即是项目中所使用到的图片生成接口,在真实生产项目中可以把该服务单独部署,于内网调用,这样利于做一些鉴权之类的处理。
|
> 打包注意事项与服务器配置相关请进入该目录下查看 README 文件说明。
|
||||||
|
|
||||||
另外 api/printscreen 这个接口实现的是网页截图的 API,该接口可以传入一个 URL 对整个网页进行截图,本项目中不依赖此接口。
|
|
||||||
|
|
||||||
### 服务器配置
|
|
||||||
|
|
||||||
在 Linux 环境下,npm 自动安装的 Chrome 浏览器有可能会出错,所以推荐从外部安装好浏览器,再给项目中的配置文件 `config.js` 设置好路径,例如:
|
|
||||||
|
|
||||||
```js
|
|
||||||
exports.executablePath = '/opt/google/chrome-unstable/chrome'
|
|
||||||
```
|
|
||||||
|
|
||||||
一些可能用到的 linux 命令参考:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
google-chrome --version # 查看浏览器版本号
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y google-chrome-stable // 安装最新稳定版谷歌浏览器
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker 容器部署
|
### Docker 容器部署
|
||||||
|
|
||||||
可以通过 Docker 运行一个带 Linux 浏览器的容器,然后暴露一个截图服务以供使用,我所使用的基础镜像为:
|
可以通过 Docker 运行一个带 Linux 浏览器的容器,[参考说明](https://xp.palxp.com/#/articles/1689319644311?id=docker%e5%ae%b9%e5%99%a8)。
|
||||||
|
|
||||||
```
|
|
||||||
docker pull howard86/puppeteer_node:12
|
|
||||||
```
|
|
||||||
|
|
||||||
运行容器命令参考(其中映射了 `/cache` 为临时目录,放生成图片用):
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -itd -v /data/docker-home:/home -v /data/cache:/cache -p 7001:7001 --name screenshot howard86/puppeteer_node:12
|
|
||||||
```
|
|
||||||
|
|
||||||
运行后可以手动进入容器中查看谷歌浏览器版本,看需不需要升级,然后安装 pm2 作为服务管理工具,服务启动/重部署相关脚本命令可参考:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker exec screenshot /bin/bash -c 'pm2 delete screenshot-service'
|
|
||||||
docker exec screenshot /bin/bash -c 'cd /home/ && yarn'
|
|
||||||
docker exec screenshot /bin/bash -c 'pm2 start /home/screenshot-service.js'
|
|
||||||
docker exec screenshot /bin/bash -c 'pm2 flush'
|
|
||||||
```
|
|
||||||
|
|
||||||
如果不想像上面这样直接操作容器,可以在本地/服务器先运行镜像,进入容器中照例配置好 pm2,然后把该容器导出为新的镜像,例如:new-design/screenshot,命令运行参考:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -itd -u root -v ~/data/tmp/screenshot:/cache -p 9001:9001 --name screenshot2 new-design/screenshot /bin/sh -c "/usr/local/bin/pm2 start /home/dist/server.js && /usr/local/bin/pm2 flush"
|
|
||||||
```
|
|
||||||
|
|
||||||
这种方式只需要一个镜像以及一个启动命令即可部署,重新跑一遍命令也就相当于重启整个容器。
|
|
||||||
|
|
||||||
### 感谢
|
### 感谢
|
||||||
|
|
||||||
@ -130,24 +87,27 @@ docker run -itd -u root -v ~/data/tmp/screenshot:/cache -p 9001:9001 --name scre
|
|||||||
- [moveable](https://github.com/daybrush/moveable): 提供了画布中选择、拖动缩放等能力
|
- [moveable](https://github.com/daybrush/moveable): 提供了画布中选择、拖动缩放等能力
|
||||||
- [html2canvas](https://github.com/niklasvh/html2canvas): 前端生成图片兜底方案
|
- [html2canvas](https://github.com/niklasvh/html2canvas): 前端生成图片兜底方案
|
||||||
- [qr-code-styling](https://qr-code-styling.com/): 风格化二维码
|
- [qr-code-styling](https://qr-code-styling.com/): 风格化二维码
|
||||||
- [sky](https://github.com/cfour-hi/sky): 参考了其 PSD 解析的实现
|
- [sky](https://github.com/cfour-hi/sky): 参考了其 PSD 解析的代码实现
|
||||||
|
- [rembg](https://github.com/danielgatis/rembg): 图片删除背景,使用 u2net 预训练模型
|
||||||
|
|
||||||
### Q&A
|
### Q&A
|
||||||
|
|
||||||
Q:**我想二次开发,但是不会编写代码,可以付费开发吗?**
|
Q:**我想二次开发,但是不会编写代码,可以付费开发吗?**
|
||||||
|
|
||||||
A:抱歉,本人时间精力有限,无法提供私有化部署或二次开发的服务,不接受定制化开发的需求。如果您对项目有任何建议或意见,非常欢迎与我交流。
|
A:抱歉,因本人时间精力有限,无法提供私有化部署或二次开发的服务,故不接受定制化开发的需求。如果您对项目有任何建议,非常欢迎与我交流。
|
||||||
|
|
||||||
Q:**服务端源码不开源吗?**
|
Q:**后端源码不开源吗?**
|
||||||
|
|
||||||
A:考虑到服务端的开发语言、数据库类型都可能不尽相同,且分离代码出来有一定成本,所以暂时不考虑直接开源,只提供接口 API 文档供参考。目前服务端仅是一些简单的增删改查,自行实现的技术难度并不高。
|
A:考虑到服务端的开发语言、数据库类型都可能不尽相同,且本项目中实现简单,代码不具备参考性,所以暂时只提供接口 API 文档。(仅是一些增删改查,实现的技术难度并不高)
|
||||||
|
|
||||||
### 其它
|
### 其它
|
||||||
|
|
||||||
项目最早使用 Vue2 开发,后改用 Vue3 重构,所以有部分代码混合了 Options 写法。
|
项目最早使用 Vue2 开发,后改用 Vue3 重构,所以有部分代码混合了 Options 写法。
|
||||||
|
|
||||||
如果你也对开发图片编辑器感兴趣,欢迎一起共建项目!
|
或许你在工作中有这类需求,这个项目能给到你一些微薄帮助的话,那就再好不过了!
|
||||||
|
|
||||||
或许你在工作中有这类需求,如果能给到你一些微薄的帮助,那就更好不过了!
|
目前本项目也还在不断迭代中,有很多的不足之处,我也是一边学习一边成长。开源不易,希望看到这里的你可以给本项目点个 **Star** 支持一下~ 感谢!
|
||||||
|
|
||||||
目前本项目也还在不断迭代中,有很多的不足之处,我也是一边学习一边成长。开源不易,希望看到这里的你可以给本项目点个 Star 支持一下~ 感谢!
|
### LICENSE
|
||||||
|
|
||||||
|
[MIT License](https://github.com/palxiao/poster-design/blob/main/LICENSE)
|
||||||
|
28999
package-lock.json
generated
28999
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gradio/client": "^0.1.4",
|
"@gradio/client": "^0.1.4",
|
||||||
"@palxp/color-picker": "^1.2.5",
|
"@palxp/color-picker": "^1.3.1",
|
||||||
"@scena/guides": "^0.18.1",
|
"@scena/guides": "^0.18.1",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: ShawnPhang
|
|
||||||
* @Date: 2023-07-12 09:51:07
|
|
||||||
* @Description: AI接口
|
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
|
||||||
* @LastEditTime: 2023-07-13 16:59:21
|
|
||||||
*/
|
|
||||||
import fetch from '@/utils/axios'
|
|
||||||
|
|
||||||
export const kt = (params: Type.Object = {}) => fetch('https://kt.palxp.com/api/remove', params, 'post', {}, { responseType: 'arraybuffer' })
|
|
@ -3,13 +3,12 @@
|
|||||||
* @Date: 2023-07-13 17:01:37
|
* @Date: 2023-07-13 17:01:37
|
||||||
* @Description: github api
|
* @Description: github api
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2023-07-14 00:01:05
|
* @LastEditTime: 2023-08-10 10:33:59
|
||||||
*/
|
*/
|
||||||
import fetch from '@/utils/axios'
|
import fetch from '@/utils/axios'
|
||||||
const reader = new FileReader()
|
const cutToken = 'ghp_qpV8PUxwY7as4jc'
|
||||||
const knock = 'qpV8PUxwY7as4jc'
|
|
||||||
const cut = 'AqYfNFb6G2f2OVl4IVFOY'
|
|
||||||
|
|
||||||
|
const reader = new FileReader()
|
||||||
function getBase64(file: File) {
|
function getBase64(file: File) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
reader.onload = function (event: any) {
|
reader.onload = function (event: any) {
|
||||||
@ -21,22 +20,17 @@ function getBase64(file: File) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const putPic = async (file: any) => {
|
const putPic = async (file: any) => {
|
||||||
const content = typeof file === 'string' ? file : await getBase64(file)
|
|
||||||
const repo = 'shawnphang/files'
|
const repo = 'shawnphang/files'
|
||||||
const d = new Date()
|
const d = new Date()
|
||||||
|
const content = typeof file === 'string' ? file : await getBase64(file)
|
||||||
const path = `${d.getFullYear()}/${d.getMonth()}/${d.getTime()}${file.name?.split('.').pop() || '.png'}`
|
const path = `${d.getFullYear()}/${d.getMonth()}/${d.getTime()}${file.name?.split('.').pop() || '.png'}`
|
||||||
const imageUrl = 'https://api.github.com/repos/' + repo + '/contents/' + path
|
const imageUrl = 'https://api.github.com/repos/' + repo + '/contents/' + path
|
||||||
const body = {
|
const body = { branch: 'main', message: 'upload', content, path }
|
||||||
branch: 'main',
|
const res = await fetch(imageUrl, body, 'put', {
|
||||||
message: 'upload',
|
Authorization: `token ${cutToken}AqYfNFb6G2f2OVl4IVFOY`,
|
||||||
content,
|
|
||||||
path,
|
|
||||||
}
|
|
||||||
await fetch(imageUrl, body, 'put', {
|
|
||||||
Authorization: 'token ' + 'ghp_' + knock + cut,
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
})
|
})
|
||||||
return `https://fastly.jsdelivr.net/gh/shawnphang/files@main/${path}`
|
return res?.content?.download_url || `https://fastly.jsdelivr.net/gh/shawnphang/files@main/${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { putPic }
|
export default { putPic }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: TitleFont;
|
font-family: TitleFont;
|
||||||
src: url(../fonts/xpsj.subset.woff2) format('woff2');
|
src: url(../fonts/xpsj.subset.woff2) format('woff2');
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
--el-color-primary: #2254f4;
|
--el-color-primary: #2254f4;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<!--
|
<!--
|
||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-01 11:12:17
|
* @Date: 2021-08-01 11:12:17
|
||||||
* @Description: 前端出图 - 生成封面
|
* @Description: 前端出图 - 用于封面
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2023-07-11 19:47:24
|
* @LastEditTime: 2023-07-26 10:22:17
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div id="cover-wrap">
|
<div id="cover-wrap">
|
||||||
@ -24,21 +24,6 @@ export default defineComponent({
|
|||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
let gridSizeIndex: number = 0
|
let gridSizeIndex: number = 0
|
||||||
|
|
||||||
// function fileOrBlobToDataURL(obj: any, cb: Function) {
|
|
||||||
// let a = new FileReader()
|
|
||||||
// a.readAsDataURL(obj)
|
|
||||||
// a.onload = (e: any) => {
|
|
||||||
// cb(e.target.result)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// function blobToImage(blob: any) {
|
|
||||||
// return new Promise((resolve) => {
|
|
||||||
// fileOrBlobToDataURL(blob, (dataurl: string) => {
|
|
||||||
// resolve(dataurl)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
||||||
|
|
||||||
async function createCover(cb: any) {
|
async function createCover(cb: any) {
|
||||||
|
@ -1,253 +0,0 @@
|
|||||||
<!--
|
|
||||||
* @Author: ShawnPhang
|
|
||||||
* @Date: 2021-08-01 11:12:17
|
|
||||||
* @Description: 前端出图 - 已废弃
|
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
|
||||||
* @LastEditTime: 2023-07-11 16:58:34
|
|
||||||
-->
|
|
||||||
<template>
|
|
||||||
<div v-show="fillInfoing" class="fill-info-wrap">
|
|
||||||
<div v-loading="loading" class="fill-info-content">
|
|
||||||
<div class="fill-info-step">
|
|
||||||
<div id="cover-wrap">
|
|
||||||
<img id="cover" />
|
|
||||||
</div>
|
|
||||||
<div class="publish-btn" @click="saveImg">
|
|
||||||
<span v-show="!publishing">下载图片</span>
|
|
||||||
<i v-show="publishing" class="el-icon-loading"></i>
|
|
||||||
</div>
|
|
||||||
<div class="close-publish" @click="closePublish">关闭</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, reactive, toRefs, watch, getCurrentInstance, ComponentInternalInstance } from 'vue'
|
|
||||||
import { mapGetters, mapActions } from 'vuex'
|
|
||||||
import html2canvas from 'html2canvas'
|
|
||||||
import api from '@/api'
|
|
||||||
import useLoading from '@/common/methods/loading'
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: ['modelValue'],
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
setup(props, context) {
|
|
||||||
let gridSizeIndex: number = 0
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
fillInfoing: false,
|
|
||||||
loading: false,
|
|
||||||
publishing: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(open) => {
|
|
||||||
if (open) {
|
|
||||||
save()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const closePublish = () => {
|
|
||||||
state.fillInfoing = false
|
|
||||||
context.emit('update:modelValue', false)
|
|
||||||
}
|
|
||||||
|
|
||||||
function fileOrBlobToDataURL(obj: any, cb: Function) {
|
|
||||||
let a = new FileReader()
|
|
||||||
a.readAsDataURL(obj)
|
|
||||||
a.onload = (e: any) => {
|
|
||||||
cb(e.target.result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function blobToImage(blob: any) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
fileOrBlobToDataURL(blob, (dataurl: string) => {
|
|
||||||
resolve(dataurl)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const { proxy }: any = getCurrentInstance() as ComponentInternalInstance
|
|
||||||
|
|
||||||
async function save() {
|
|
||||||
// state.loading = true
|
|
||||||
// state.fillInfoing = true
|
|
||||||
let nowGrideSizeIndex = gridSizeIndex
|
|
||||||
let nowZoom = proxy?.dZoom
|
|
||||||
// 取消选中元素
|
|
||||||
proxy?.selectWidget({
|
|
||||||
uuid: '-1',
|
|
||||||
})
|
|
||||||
gridSizeIndex = 0
|
|
||||||
proxy?.updateZoom(100)
|
|
||||||
const opts = {
|
|
||||||
useCORS: true, // 跨域图片
|
|
||||||
scale: 0.4,
|
|
||||||
}
|
|
||||||
setTimeout(async () => {
|
|
||||||
html2canvas(document.getElementById('page-design-canvas'), opts).then((canvas) => {
|
|
||||||
canvas.toBlob(
|
|
||||||
async (blob: any) => {
|
|
||||||
const data = await blobToImage(blob)
|
|
||||||
document.getElementById('cover').src = data
|
|
||||||
state.loading = false
|
|
||||||
gridSizeIndex = nowGrideSizeIndex
|
|
||||||
proxy?.updateZoom(nowZoom)
|
|
||||||
proxy?.saveImg()
|
|
||||||
},
|
|
||||||
'image/jpeg',
|
|
||||||
0.2,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveImg() {
|
|
||||||
if (state.publishing) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
state.publishing = true
|
|
||||||
let image = new Image()
|
|
||||||
// 解决跨域 Canvas 污染问题
|
|
||||||
image.setAttribute('crossOrigin', 'anonymous')
|
|
||||||
image.onload = function () {
|
|
||||||
let canvas = document.createElement('canvas')
|
|
||||||
canvas.width = image.width
|
|
||||||
canvas.height = image.height
|
|
||||||
|
|
||||||
const context = canvas.getContext('2d')
|
|
||||||
context?.drawImage(image, 0, 0, image.width, image.height)
|
|
||||||
let url = canvas.toDataURL('image/png')
|
|
||||||
|
|
||||||
let a = document.createElement('a')
|
|
||||||
let event = new MouseEvent('click')
|
|
||||||
|
|
||||||
// 将a的download属性设置为我们想要下载的图片名称,若name不存在则使用‘ ’作为默认名称
|
|
||||||
a.download = name || '生成图片'
|
|
||||||
a.href = url
|
|
||||||
|
|
||||||
// 触发a的单击事件
|
|
||||||
a.dispatchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
image.src = document.getElementById('cover').src
|
|
||||||
state.publishing = false
|
|
||||||
state.fillInfoing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createImg(cb: any) {
|
|
||||||
let loading: any = useLoading('保存封面中')
|
|
||||||
let nowGrideSizeIndex = gridSizeIndex
|
|
||||||
let nowZoom = proxy?.dZoom
|
|
||||||
// 取消选中元素
|
|
||||||
proxy?.selectWidget({
|
|
||||||
uuid: '-1',
|
|
||||||
})
|
|
||||||
gridSizeIndex = 0
|
|
||||||
proxy?.updateZoom(100)
|
|
||||||
const opts = {
|
|
||||||
useCORS: true, // 跨域图片
|
|
||||||
scale: 0.4,
|
|
||||||
}
|
|
||||||
setTimeout(async () => {
|
|
||||||
html2canvas(document.getElementById('page-design-canvas'), opts).then(async (canvas) => {
|
|
||||||
cb(canvas.toDataURL('image/jpeg', 0.6))
|
|
||||||
gridSizeIndex = nowGrideSizeIndex
|
|
||||||
proxy?.updateZoom(nowZoom)
|
|
||||||
loading.close()
|
|
||||||
})
|
|
||||||
}, 301)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
save,
|
|
||||||
closePublish,
|
|
||||||
saveImg,
|
|
||||||
createImg,
|
|
||||||
...toRefs(state),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(['dZoom', 'dPage']),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(['selectWidget', 'updateZoom']),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
// Width variables (appears count calculates by raw css)
|
|
||||||
@width00: 400px; // Appears 2 times
|
|
||||||
@width20: 100%; // Appears 2 times
|
|
||||||
|
|
||||||
// Height variables (appears count calculates by raw css)
|
|
||||||
@height20: 400px; // Appears 2 times
|
|
||||||
|
|
||||||
.fill-info-wrap {
|
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
|
||||||
height: 100%;
|
|
||||||
padding: 50px;
|
|
||||||
position: absolute;
|
|
||||||
width: @width20;
|
|
||||||
z-index: 9999;
|
|
||||||
.fill-info-content {
|
|
||||||
background-color: @color-white;
|
|
||||||
border-radius: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-height: 861px;
|
|
||||||
min-height: 600px;
|
|
||||||
padding: 20px;
|
|
||||||
width: 600px;
|
|
||||||
.fill-info-step {
|
|
||||||
flex: 1;
|
|
||||||
width: @width20;
|
|
||||||
#cover-wrap {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
height: @height20;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 20px auto;
|
|
||||||
width: @width00;
|
|
||||||
#cover {
|
|
||||||
box-shadow: 1px 1px 10px 3px rgba(0, 0, 0, 0.1);
|
|
||||||
max-height: @height20;
|
|
||||||
max-width: @width00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.publish-btn {
|
|
||||||
background-color: @color-main;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: @color-white;
|
|
||||||
cursor: pointer;
|
|
||||||
margin: 20px auto;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
&:hover {
|
|
||||||
background-color: @color-dark-gray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.close-publish {
|
|
||||||
background-color: @color-white;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: @color-main;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
margin: 20px auto;
|
|
||||||
outline: 1px solid @color-main;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
&:hover {
|
|
||||||
background-color: @color-dark-gray;
|
|
||||||
color: @color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -7,6 +7,7 @@
|
|||||||
<p>{{ item.name }}</p>
|
<p>{{ item.name }}</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<a href="https://github.com/palxiao/poster-design" target="_blank" class="github"><img src="https://fe-doc.palxp.com/images/github.svg" alt="Github" title="Github" /> 源码</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="active" class="widget-wrap">
|
<div v-show="active" class="widget-wrap">
|
||||||
<temp-list-wrap :style="getStyle(0)" />
|
<temp-list-wrap :style="getStyle(0)" />
|
||||||
@ -109,6 +110,7 @@ export default {
|
|||||||
position: relative;
|
position: relative;
|
||||||
// width: 360px;
|
// width: 360px;
|
||||||
.widget-classify {
|
.widget-classify {
|
||||||
|
position: relative;
|
||||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -212,4 +214,20 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.github {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
img {
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<el-popover placement="left-end" width="auto">
|
<el-popover placement="left-end" width="auto">
|
||||||
<!-- eslint-disable-next-line vue/no-v-model-argument -->
|
<!-- eslint-disable-next-line vue/no-v-model-argument -->
|
||||||
<color-picker v-model:value="innerColor" :modes="['纯色']" @nativePick="dropColor" />
|
<color-picker v-model:value="innerColor" :modes="['纯色']" @blur="inputBlur" @nativePick="dropColor" />
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="color__bar" :style="{ background: innerColor }"></div>
|
<div class="color__bar" :style="{ background: innerColor }"></div>
|
||||||
</template>
|
</template>
|
||||||
@ -19,10 +19,11 @@
|
|||||||
const NAME = 'color-select'
|
const NAME = 'color-select'
|
||||||
import { defineComponent, toRefs, reactive, computed, onMounted, watch } from 'vue'
|
import { defineComponent, toRefs, reactive, computed, onMounted, watch } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { debounce } from 'throttle-debounce'
|
// import { debounce } from 'throttle-debounce'
|
||||||
import { toolTip } from '@/common/methods/helper'
|
// import { toolTip } from '@/common/methods/helper'
|
||||||
// import colorPicker from '@/utils/plugins/color-picker/index.vue'
|
// import colorPicker from '@/utils/plugins/color-picker/index.vue'
|
||||||
import colorPicker from '@palxp/color-picker'
|
// import colorPicker from '@palxp/color-picker'
|
||||||
|
import colorPicker from '@palxp/color-picker/index.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: NAME,
|
name: NAME,
|
||||||
@ -90,12 +91,17 @@ export default defineComponent({
|
|||||||
// state.innerColor = e + (e.length === 7 ? 'ff' : '')
|
// state.innerColor = e + (e.length === 7 ? 'ff' : '')
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
const inputBlur = (color: string) => {
|
||||||
|
state.innerColor = color
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
// dColorHistory,
|
// dColorHistory,
|
||||||
activeChange,
|
activeChange,
|
||||||
onChange,
|
onChange,
|
||||||
dropColor,
|
dropColor,
|
||||||
|
inputBlur,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -45,6 +45,7 @@ export default {
|
|||||||
step: {
|
step: {
|
||||||
default: 1,
|
default: 1,
|
||||||
},
|
},
|
||||||
|
maxValue: {},
|
||||||
},
|
},
|
||||||
emits: ['finish', 'update:modelValue'],
|
emits: ['finish', 'update:modelValue'],
|
||||||
data() {
|
data() {
|
||||||
@ -66,12 +67,18 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
fixedNum() {
|
fixedNum() {
|
||||||
// 小数点过长时
|
// 小数点过长时
|
||||||
const num = String(this.modelValue).split('.')[1]
|
const decimal = String(this.modelValue).split('.')[1]
|
||||||
if (num && num.length > 2) {
|
if (decimal && decimal.length > 2) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.updateValue(Number(this.modelValue).toFixed(2))
|
this.updateValue(Number(this.modelValue).toFixed(2))
|
||||||
}, 10)
|
}, 10)
|
||||||
}
|
}
|
||||||
|
// 超过阈值时
|
||||||
|
if (this.maxValue && this.modelValue > this.maxValue) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateValue(Number(this.maxValue))
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
updateValue(value) {
|
updateValue(value) {
|
||||||
this.$emit('update:modelValue', value)
|
this.$emit('update:modelValue', value)
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<el-collapse v-model="activeNames">
|
<el-collapse v-model="activeNames">
|
||||||
<el-collapse-item title="画布尺寸" name="1">
|
<el-collapse-item title="画布尺寸" name="1">
|
||||||
<div class="position-size">
|
<div class="position-size">
|
||||||
<number-input v-model="innerElement.width" label="宽" @finish="(value) => finish('width', value)" />
|
<number-input v-model="innerElement.width" label="宽" :maxValue="5000" @finish="(value) => finish('width', value)" />
|
||||||
<number-input v-model="innerElement.height" label="高" @finish="(value) => finish('height', value)" />
|
<number-input v-model="innerElement.height" label="高" :maxValue="5000" @finish="(value) => finish('height', value)" />
|
||||||
</div>
|
</div>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="背景设置" name="2">
|
<el-collapse-item title="背景设置" name="2">
|
||||||
@ -25,10 +25,6 @@
|
|||||||
<!-- <el-collapse-item title="其他设置" name="3">
|
<!-- <el-collapse-item title="其他设置" name="3">
|
||||||
<el-input v-model="innerElement.name" label="名称" @finish="(value) => finish('name', value)" />
|
<el-input v-model="innerElement.name" label="名称" @finish="(value) => finish('name', value)" />
|
||||||
</el-collapse-item> -->
|
</el-collapse-item> -->
|
||||||
<!-- <el-collapse-item title="客户端配置(设置客户端是否允许修改)" name="4">
|
|
||||||
<setting-switch v-for="item in dActiveElement.setting" :key="item.key" v-model="item.value" :label="item.label" />
|
|
||||||
</el-collapse-item> -->
|
|
||||||
<!-- <el-button v-loading="canvasRunning" size="small" @click="pickColor">取色器测试</el-button> -->
|
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -14,7 +14,7 @@ export default {
|
|||||||
SCREEN_URL: isDev ? 'http://localhost:7001' : '${SCREEN_URL}',
|
SCREEN_URL: isDev ? 'http://localhost:7001' : '${SCREEN_URL}',
|
||||||
IMG_URL: 'https://store.palxp.com/',
|
IMG_URL: 'https://store.palxp.com/',
|
||||||
// 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',
|
ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap',
|
||||||
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_6qsac4kteu7.css',
|
ICONFONT_EXTRA: '//at.alicdn.com/t/c/font_3228074_6qsac4kteu7.css?&display=swap',
|
||||||
QINIUYUN_PLUGIN: 'https://cdn.jsdelivr.net/npm/qiniu-js@2.5.5/dist/qiniu.min.js',
|
QINIUYUN_PLUGIN: 'https://cdn.jsdelivr.net/npm/qiniu-js@2.5.5/dist/qiniu.min.js',
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: ShawnPhang
|
|
||||||
* @Date: 2022-03-28 09:23:10
|
|
||||||
* @Description: 全局拖动检测
|
|
||||||
* @LastEditors: ShawnPhang
|
|
||||||
* @LastEditTime: 2022-03-28 10:08:38
|
|
||||||
*/
|
|
||||||
import store from '@/store'
|
|
||||||
import { onMounted, onBeforeUnmount, nextTick } from 'vue'
|
|
||||||
|
|
||||||
export default async (elName: string | Element) => {
|
|
||||||
onMounted(async () => {
|
|
||||||
await nextTick()
|
|
||||||
|
|
||||||
const el: any = typeof elName === 'string' ? document.querySelector(elName) : elName
|
|
||||||
|
|
||||||
el.onmousedown = function(ev: any) {
|
|
||||||
console.log('点击')
|
|
||||||
|
|
||||||
const distanceX = ev.clientX - el.offsetLeft
|
|
||||||
const distanceY = ev.clientY - el.offsetTop
|
|
||||||
document.onmousemove = function(ev) {
|
|
||||||
console.log('拖动')
|
|
||||||
|
|
||||||
// var oevent = ev || event;
|
|
||||||
// entrance.style.left = oevent.clientX - distanceX + 'px';
|
|
||||||
// entrance.style.top = oevent.clientY - distanceY + 'px';
|
|
||||||
}
|
|
||||||
document.onmouseup = function(ev) {
|
|
||||||
console.log('释放')
|
|
||||||
|
|
||||||
document.onmousemove = null
|
|
||||||
document.onmouseup = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -2,23 +2,19 @@
|
|||||||
* @Author: ShawnPhang
|
* @Author: ShawnPhang
|
||||||
* @Date: 2021-08-19 18:43:22
|
* @Date: 2021-08-19 18:43:22
|
||||||
* @Description:
|
* @Description:
|
||||||
* @LastEditors: ShawnPhang
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2021-10-08 18:27:13
|
* @LastEditTime: 2023-07-31 09:31:52
|
||||||
*/
|
*/
|
||||||
// import { moveByDom, resizeByDom, initLine } from 'view-line'
|
|
||||||
// import 'view-line/dist/view-line.css'
|
|
||||||
// let isDraging = false
|
|
||||||
// const offset = { top: 0, left: 0 }
|
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
const move = {
|
const move = {
|
||||||
methods: {
|
methods: {
|
||||||
initmovement(e: any) {
|
initmovement(e: any) {
|
||||||
// let target = this.$store.state.pageDesign.dActiveElement
|
// let target = store.state.pageDesign.dActiveElement
|
||||||
const target = this.$store.getters.dActiveElement
|
const target = store.getters.dActiveElement
|
||||||
|
|
||||||
// 设置移动状态初始值
|
// 设置移动状态初始值
|
||||||
this.$store.dispatch('initDMove', {
|
store.dispatch('initDMove', {
|
||||||
startX: e.pageX,
|
startX: e.pageX,
|
||||||
startY: e.pageY,
|
startY: e.pageY,
|
||||||
originX: target.left,
|
originX: target.left,
|
||||||
@ -32,11 +28,11 @@ const move = {
|
|||||||
document.addEventListener('mouseup', this.handlemouseup, true)
|
document.addEventListener('mouseup', this.handlemouseup, true)
|
||||||
},
|
},
|
||||||
|
|
||||||
handlemousemove(e) {
|
handlemousemove(e: any) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
this.$store.dispatch('dMove', {
|
store.dispatch('dMove', {
|
||||||
x: e.pageX,
|
x: e.pageX,
|
||||||
y: e.pageY,
|
y: e.pageY,
|
||||||
})
|
})
|
||||||
@ -45,7 +41,7 @@ const move = {
|
|||||||
handlemouseup() {
|
handlemouseup() {
|
||||||
document.removeEventListener('mousemove', this.handlemousemove, true)
|
document.removeEventListener('mousemove', this.handlemousemove, true)
|
||||||
document.removeEventListener('mouseup', this.handlemouseup, true)
|
document.removeEventListener('mouseup', this.handlemouseup, true)
|
||||||
this.$store.dispatch('stopDMove')
|
store.dispatch('stopDMove')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -56,11 +52,11 @@ const moveInit = {
|
|||||||
if (!store.getters.dAltDown) {
|
if (!store.getters.dAltDown) {
|
||||||
// 设置mouseevent给moveable初始
|
// 设置mouseevent给moveable初始
|
||||||
// 在组合操作时排除
|
// 在组合操作时排除
|
||||||
this.$store.commit('setMouseEvent', e)
|
store.commit('setMouseEvent', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = this.$store.getters.dActiveElement
|
const target = store.getters.dActiveElement
|
||||||
this.$store.dispatch('initDMove', {
|
store.dispatch('initDMove', {
|
||||||
startX: e.pageX,
|
startX: e.pageX,
|
||||||
startY: e.pageY,
|
startY: e.pageY,
|
||||||
originX: target.left,
|
originX: target.left,
|
||||||
@ -69,7 +65,7 @@ const moveInit = {
|
|||||||
|
|
||||||
const handlemouseup = () => {
|
const handlemouseup = () => {
|
||||||
// 销毁选中即刻移动
|
// 销毁选中即刻移动
|
||||||
this.$store.commit('setMouseEvent', null)
|
store.commit('setMouseEvent', null)
|
||||||
document.removeEventListener('mouseup', handlemouseup, true)
|
document.removeEventListener('mouseup', handlemouseup, true)
|
||||||
}
|
}
|
||||||
document.addEventListener('mouseup', handlemouseup, true)
|
document.addEventListener('mouseup', handlemouseup, true)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @Date: 2021-07-13 02:48:38
|
* @Date: 2021-07-13 02:48:38
|
||||||
* @Description: 接口规则:只有正确code为200时返回result结果对象,错误返回整个结果对象
|
* @Description: 接口规则:只有正确code为200时返回result结果对象,错误返回整个结果对象
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2023-07-12 10:43:34
|
* @LastEditTime: 2023-07-31 09:34:34
|
||||||
*/
|
*/
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
@ -11,8 +11,6 @@ import app_config from '@/config'
|
|||||||
|
|
||||||
axios.defaults.timeout = 30000
|
axios.defaults.timeout = 30000
|
||||||
// axios.defaults.headers.Authorization = 'Bearer ';
|
// axios.defaults.headers.Authorization = 'Bearer ';
|
||||||
// axios.defaults.headers.AppKey = '9e8nbMCqDkMhSRkTo8nYb7VF3qUa43EI'
|
|
||||||
|
|
||||||
// const version = app_config.VERSION;
|
// const version = app_config.VERSION;
|
||||||
const baseUrl = app_config.API_URL
|
const baseUrl = app_config.API_URL
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @Date: 2022-03-25 15:19:02
|
* @Date: 2022-03-25 15:19:02
|
||||||
* @Description: 版权声明
|
* @Description: 版权声明
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2023-07-06 16:48:12
|
* @LastEditTime: 2023-08-08 10:09:59
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<tool-tip title="免责声明" :width="340" :content="content">
|
<tool-tip title="免责声明" :width="340" :content="content">
|
||||||
@ -20,7 +20,7 @@ import toolTip from '@/components/common/PopoverTip.vue'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { toolTip },
|
components: { toolTip },
|
||||||
setup() {
|
setup() {
|
||||||
const content = '本站为个人项目,素材资源均来源于网络,不提供任何版权保障,下载之作品仅供学习研究或欣赏目的而使用,请于24h内自行删除。'
|
const content = '本站为个人项目,所使用素材图片等均为网络收集而来,下载之作品仅供学习研究或欣赏目的而使用,无法提供商用授权哦。'
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* @Date: 2021-08-19 18:30:38
|
* @Date: 2021-08-19 18:30:38
|
||||||
* @Description: Vite配置文件
|
* @Description: Vite配置文件
|
||||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||||
* @LastEditTime: 2023-07-20 18:48:25
|
* @LastEditTime: 2023-08-01 10:46:59
|
||||||
*/
|
*/
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user