mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
feat: add back-end
This commit is contained in:
parent
85275c32ff
commit
f6512b30b0
20
LICENSE
20
LICENSE
@ -19,3 +19,23 @@ 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.
|
||||
|
||||
------
|
||||
|
||||
中文许可证:
|
||||
|
||||
“迅排设计”(以下简称迅排)项目开源旨在促进技术社区交流与发展,本软件代码允许任何人士免费使用、研究、修改及发布、销售等行为,但必须保留本许可声明。
|
||||
|
||||
在可能的情况下,请在产品界面始终注明软件来源,并链接到此 Github 仓库,这种行为值得赞扬!但也并非是强制的。
|
||||
|
||||
一些行为或用途会直接损害作者的努力成果,特此声明:
|
||||
|
||||
❌ 您不得以原样形式倒卖或分发内容,原样形式是指未对内容进行任何创造性努力,并且其形式与我们网站上的内容完全相同。
|
||||
❌ 您不得以误导或欺骗的方式使用内容,或暗示你的产品获得了来自迅排的授意。
|
||||
❌ 您不得将迅排的任何内容用作商标、设计标记、商号或服务标记的一部分。
|
||||
|
||||
免责声明:
|
||||
|
||||
1)本许可证项下的软件代码是“按原样”提供,不作任何明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵犯版权、专利、商标或其他权利的保证。在任何情况下,版权持有人均不承担因使用或无法使用本软件而产生、引起的任何索赔、损害或其他责任,包括任何一般、特殊、间接、附带或结果性损害。
|
||||
|
||||
2)这是一个非官方翻译的开源许可证,在 MIT 协议下的版本只有原始英文版才有效。然而,我们认识到,这种非官方的翻译将帮助开发者们更好地理解迅排设计的开源理念。我们鼓励自由地在迅排开源基础上进行各种创造、作品衍生,并期待社区能够出现更精彩的产品。
|
78
README.md
78
README.md
@ -1,26 +1,37 @@
|
||||
**[在线体验网站](https://design.palxp.cn/)** | **[在线文档](https://xp.palxp.cn/)** | [常见问题](https://xp.palxp.cn/#/articles/1689323321667) | [性能压测](https://juejin.cn/post/7348288810722869300)
|
||||
<!--
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-08-11 16:17:52
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-14 18:54:40
|
||||
-->
|
||||
<h2>迅排设计 - Poster Design</h2>
|
||||
|
||||
---
|
||||
<p>
|
||||
<a href=""><img src="https://img.shields.io/github/stars/palxiao/poster-design?style=flat" alt="starts"></a>
|
||||
<a href="https://github.com/palxiao/poster-design?tab=MIT-1-ov-file"><img src="https://img.shields.io/github/license/palxiao/poster-design?style=flat" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## 迅排设计
|
||||
<p>
|
||||
<a href="https://trendshift.io/repositories/8728" target="_blank"><img src="https://trendshift.io/api/badge/repositories/8728" alt="palxiao%2Fposter-design | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
一款漂亮易用且功能强大的创意图片编辑器,对标稿定设计、创客贴、Canva 等商业产品。
|
||||
漂亮易用且功能强大的在线创意图片编辑器,对标稿定设计、创客贴、Canva 等产品,开源免费。
|
||||
|
||||
适用于多种场景:海报图片生成、电商分享图、文章长图、视频/公众号封面等,无需下载软件即可轻松实现云端编辑、迅速完成图文排版。
|
||||
适用于多种场景:海报图片生成、电商图文分享、制作文章长图、视频/公众号封面等,在线实现创意,迅速图文排版,设计就是如此简单!
|
||||
|
||||
[](https://design.palxp.cn/)
|
||||
|
||||
### 特点
|
||||
**[官方网站](https://design.palxp.cn/)** | **[在线文档](https://xp.palxp.cn/)** | [常见问题](https://xp.palxp.cn/#/articles/1689323321667) | [性能压测](https://juejin.cn/post/7348288810722869300)
|
||||
|
||||
- 丝滑的页面操作体验,丰富的交互细节,基础功能完善
|
||||
- 采用服务端生成图片,确保多端出图统一性,支持各种 HTML5 特性
|
||||
- 简易 AI 抠图工具,上传图片一键去除背景
|
||||
- 技术栈:Vue3 、Vite5 、Pinia 、ElementPlus
|
||||
- 图片生成:Puppeteer、Express
|
||||
- 丝滑的操作体验,丰富的交互细节,基础功能完善
|
||||
- 服务端生成图片,支持各种 HTML5 特性
|
||||
- 主要技术栈:Vue3 、Vite5 、Pinia 、ElementPlus、Puppeteer、Express
|
||||
|
||||
### 支持功能
|
||||
### 功能简介
|
||||
|
||||
- 导入 PSD 文件解析成模板、在线导出图片下载。
|
||||
- 简易 AI 抠图工具,上传图片一键去除背景。
|
||||
- 元素拖拽、组合、缩放、层级调整、对齐等操作。
|
||||
- 图片素材插入、替换、裁剪,图片容器等功能。
|
||||
- SVG 素材颜色、透明度编辑,文字花字组合。
|
||||
@ -30,36 +41,30 @@
|
||||
- 风格二维码编辑,支持单色、渐变、自定义 logo 等。
|
||||
- 颜色调色板,原生级取色器颜色吸管(Chrome)。
|
||||
|
||||
## 快速开始
|
||||
### 快速开始
|
||||
|
||||
```
|
||||
git clone https://github.com/palxiao/poster-design.git
|
||||
cd poster-design
|
||||
npm run prepared
|
||||
npm run dev
|
||||
cd screenshot
|
||||
npm run dev
|
||||
npm run server
|
||||
```
|
||||
|
||||

|
||||
输入网址 http://127.0.0.1:5173/ 访问站点,更多参阅[详细说明文档](https://xp.palxp.cn/#/articles/1689319644311)。
|
||||
|
||||
访问 http://127.0.0.1:5173/ 查看网页。点此查看[更多说明文档](https://xp.palxp.cn/#/articles/1689319644311)。
|
||||
### 服务端 & 图片生成
|
||||
|
||||
### 图片生成服务
|
||||
本仓库中所提供的后端代码仅为示例作用,目的在于帮助开发者更好地理解项目,实际生产则推荐根据自身需求进行开发。原项目中请求的远程 API 接口已不再适用,但 [接口 API 文档](https://xp.palxp.cn/apidoc/index.html) 仍具有一定参考性。
|
||||
|
||||
代码位于根目录 [/screenshot](https://github.com/palxiao/poster-design/tree/main/screenshot),接口API文档点此查看:[接口 API 文档](https://xp.palxp.cn/apidoc/screenshot.html)。
|
||||
|
||||
### 服务端
|
||||
|
||||
后端需要自己开发,目前本项目演示 Demo 中的后端接口参考:[接口 API 文档](https://xp.palxp.cn/apidoc/index.html)。
|
||||
关于部署等说明请前往项目中查看,后端项目代码位于根目录 [/service](https://github.com/palxiao/poster-design/tree/main/service) 下。
|
||||
|
||||
### 其它
|
||||
|
||||
一些问题修改与记录[点击这里查看](https://xp.palxp.cn/#/articles/1689319986889?id=%e8%bf%ad%e4%bb%a3%e8%ae%a1%e5%88%92),项目持续迭代中,还有很多不足,可以将你遇到的问题在 Issues 中提出,或者提交 Pull Request 帮助完善。
|
||||
项目持续迭代中,还有很多不足,可以将你遇到的问题在 Issues 中提出,或者提交 Pull Request 帮助完善。
|
||||
|
||||
### 交流群
|
||||
|
||||
关注公众号:品味前端,回复 “加群” 获取二维码,更新公告不错过。
|
||||
了解项目最新资讯、或技术交流,欢迎关注公众号《品味前端》;回复“加群”获取群号。
|
||||
|
||||
<img style="width: 380px;" src="https://xp.palxp.cn/images/2024-3-1-1709306365949.png" />
|
||||
|
||||
@ -68,26 +73,20 @@ npm run dev
|
||||
项目还使用或参考了一些优秀开源项目,包括但不限于:
|
||||
|
||||
- [moveable](https://github.com/daybrush/moveable): 提供了画布中选择、拖动缩放等能力
|
||||
- [html2canvas](https://github.com/niklasvh/html2canvas): 前端生图的一种快捷方案
|
||||
- [qr-code-styling](https://qr-code-styling.com/): 风格化二维码
|
||||
- [rembg](https://github.com/danielgatis/rembg): 图片抠图,使用 u2net 预训练模型
|
||||
- [html2canvas](https://github.com/niklasvh/html2canvas): 前端出图的简单方案
|
||||
- [qr-code-styling](https://qr-code-styling.com/): 生成风格化二维码
|
||||
- [rembg](https://github.com/danielgatis/rembg): 图片自动抠图,使用 u2net 预训练模型
|
||||
|
||||
### `Star`
|
||||
|
||||
开源不易,最后别忘了给本项目点个 **Star** ~
|
||||
|
||||
[](https://star-history.com/#palxiao/poster-design&Date)
|
||||
|
||||
### `Star`
|
||||
|
||||
感谢所有支持本项目的朋友 :heart:
|
||||
感谢所有喜欢和支持本项目的朋友 :heart:
|
||||
|
||||
[](https://github.com/palxiao/poster-design/stargazers)
|
||||
|
||||
### `Fork`
|
||||
|
||||
这些小伙伴都在使用迅排设计 :heart:
|
||||
|
||||
[](https://github.com/palxiao/poster-design/network/members)
|
||||
|
||||
### 友情赞助商
|
||||
|
||||
| Dooring低代码 | DrawOn桌案 |
|
||||
@ -102,5 +101,4 @@ npm run dev
|
||||
|
||||
### `LICENSE`
|
||||
|
||||
本项目完全免费,可在保留 [MIT 开源许可证](https://github.com/palxiao/poster-design/blob/main/LICENSE) 的前提下使用。
|
||||
|
||||
本项目遵循 MIT 开源协议,建议仔细阅读并保留 [开源许可证](https://github.com/palxiao/poster-design/blob/main/LICENSE)。
|
||||
|
41
package-lock.json
generated
41
package-lock.json
generated
@ -21,7 +21,7 @@
|
||||
"dayjs": "^1.10.7",
|
||||
"element-plus": "^2.6.3",
|
||||
"fontfaceobserver": "^2.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"html2canvas": "^1.0.0",
|
||||
"immer": "^10.0.4",
|
||||
"microdiff": "^1.4.0",
|
||||
"mitt": "^3.0.1",
|
||||
@ -1665,9 +1665,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
|
||||
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
@ -1914,11 +1914,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-1.1.1.tgz",
|
||||
"integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
"base64-arraybuffer": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/css-styled": {
|
||||
@ -2665,12 +2665,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.0.0.tgz",
|
||||
"integrity": "sha512-0d/f2Aj1Brn+EeNWkuRdtnT13qu1NdvxhBMvts3ssme7jgPU7dtuwnm1P6cXvXmnDdUUerH5XdhveWvuLfqkew==",
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
"css-line-break": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
@ -3845,14 +3844,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
@ -4017,14 +4008,6 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz",
|
||||
|
@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"author": "ShawnPhang",
|
||||
"scripts": {
|
||||
"prepared": "npm i && cd screenshot && npm i",
|
||||
"serve": "npm run dev & cd screenshot && npm run dev",
|
||||
"prepared": "npm i && cd service && npm i",
|
||||
"serve": "npm run dev & cd service && npm run dev",
|
||||
"dev": "cross-env NODE_ENV=development vite",
|
||||
"v-build": "cross-env NODE_ENV=production && vite build",
|
||||
"v-build-hard": "cross-env NODE_ENV=production vue-tsc --noEmit && vite build",
|
||||
@ -24,7 +24,7 @@
|
||||
"dayjs": "^1.10.7",
|
||||
"element-plus": "^2.6.3",
|
||||
"fontfaceobserver": "^2.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"html2canvas": "^1.0.0",
|
||||
"immer": "^10.0.4",
|
||||
"microdiff": "^1.4.0",
|
||||
"mitt": "^3.0.1",
|
||||
|
@ -1,14 +0,0 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2020-07-22 20:13:14
|
||||
* @Description: 接口名称
|
||||
* @LastEditors: ShawnPhang <site: m.palxp.cn>
|
||||
* @LastEditTime: 2023-07-27 17:51:53
|
||||
*/
|
||||
let path = '/api';
|
||||
|
||||
module.exports = {
|
||||
GETIMAGE: path + '/get_img',
|
||||
SCREENGHOT: path + '/screenshots',
|
||||
PRINTSCREEN: path + '/printscreen'
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2020-07-22 20:13:14
|
||||
* @Description: 路由
|
||||
* @LastEditors: ShawnPhang <site: m.palxp.cn>
|
||||
* @LastEditTime: 2023-07-27 17:51:36
|
||||
*/
|
||||
const rExpress = require('express');
|
||||
const screenshots = require('../service/screenshots.ts');
|
||||
const api = require('./api.ts');
|
||||
const rRouter = rExpress.Router();
|
||||
|
||||
rRouter.get(api.SCREENGHOT, screenshots.screenshots);
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
rRouter.get(api.PRINTSCREEN, screenshots.printscreen);
|
||||
rRouter.get(api.GETIMAGE, screenshots.getImg);
|
||||
}
|
||||
|
||||
module.exports = rRouter;
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2022-02-01 13:41:59
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <site: m.palxp.cn>
|
||||
* @LastEditTime: 2023-07-06 10:19:18
|
||||
*/
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const fs = require('fs')
|
||||
// const path = require('path')
|
||||
const router = require('./control/router.ts')
|
||||
const { filePath, servicePort } = require('./configs.ts')
|
||||
const handleTimeout = require('./utils/timeout.ts')
|
||||
|
||||
const port = process.env.PORT || servicePort
|
||||
const app = express()
|
||||
|
||||
// 创建目录
|
||||
const createFolder = (folder: string) => {
|
||||
try {
|
||||
fs.accessSync(folder)
|
||||
} catch (e) {
|
||||
fs.mkdirSync(folder)
|
||||
}
|
||||
}
|
||||
createFolder(filePath)
|
||||
|
||||
app.all('*', (req: any, res: any, next: any) => {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization,Content-Length,Content-Size');
|
||||
res.header('Access-Control-Allow-Methods', '*');
|
||||
res.header('Content-Type', 'application/json;charset=utf-8');
|
||||
next();
|
||||
});
|
||||
|
||||
app.use('/static', express.static('static'))
|
||||
// app.use('/cache', express.static('cache'))
|
||||
|
||||
app.use(handleTimeout)
|
||||
|
||||
app.use((req: any, res: any, next: any) => {
|
||||
console.log(req.path)
|
||||
next()
|
||||
})
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.use(router)
|
||||
|
||||
app.listen(port, () => console.log(`Screenshot Server start on port:${port}`))
|
2027
screenshot/yarn.lock
2027
screenshot/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,8 @@
|
||||
|
||||
## Node截图服务
|
||||
|
||||
目录结构比较简单,主要就实现了三个接口,其中 `api/screenshots` 即是项目中所使用到的图片生成接口,在真实生产项目中可以把该服务单独部署,于内网调用,这样利于做一些鉴权之类的处理。
|
||||
项目中所使用到的图片生成接口为:`api/screenshots`,在真实生产项目中可以把该服务单独部署,于内网调用,这样利于做一些鉴权之类的处理。
|
||||
|
||||
另外 `api/printscreen` 这个接口实现的是网页截图的 API,该接口可以传入一个 URL 对整个网页进行截图,可用于合成长图分享海报等场景,本项目中没有使用到此接口。
|
||||
注:另外的 `api/printscreen` 本项目中并未使用,这个接口的作用是实现普通网页截图,可以传入一个 URL 生成该网址的预览图片,用于合成长图分享海报等场景。
|
||||
|
||||
### 安装依赖
|
||||
|
||||
@ -15,9 +14,9 @@
|
||||
ERROR: Failed to set up Chromium xxx! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.
|
||||
```
|
||||
|
||||
不用慌,这是因为 puppeteer 会自动下载 Chromium,国内会受到网络波动的影响。
|
||||
不用慌,这是因为 puppeteer 会自动下载 Chromium,国内可能受到网络波动的影响而失败。
|
||||
|
||||
如果跳过的话需要手动安装,比较麻烦所以并不推荐。解决方法是**多尝试几次,或者更换国内的镜像源**即可。
|
||||
如果跳过的话需要手动安装,比较麻烦所以并不推荐,请**多尝试安装几次,或者更换国内的镜像源再安装**。
|
||||
|
||||
### 启动项目并热更新
|
||||
|
||||
@ -29,7 +28,11 @@ ERROR: Failed to set up Chromium xxx! Set "PUPPETEER_SKIP_DOWNLOAD" env variable
|
||||
|
||||
#### 打包部署步骤
|
||||
|
||||
> 服务器环境需求:Node.js 16.18.1(版本不同则可能出现错误)、PM2(进程守护)
|
||||
> 服务器环境需求:
|
||||
>
|
||||
> - Node.js 16.18.1(尽量保持生产版本相同,避免出现错误)
|
||||
>
|
||||
> - PM2(进程守护)
|
||||
|
||||
1. 本地执行 `npm run build` 打包
|
||||
2. 打包后项目根目录 `dist/` 文件夹上传服务器,并执行 `npm install` 安装依赖
|
6398
service/package-lock.json
generated
Normal file
6398
service/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,13 +17,17 @@
|
||||
"author": "ShawnPhang",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.3",
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"express": "^4.19.2",
|
||||
"image-size": "^1.1.1",
|
||||
"images": "^3.2.4",
|
||||
"multiparty": "^4.2.3",
|
||||
"puppeteer": "^10.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.18.87",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^16.18.105",
|
||||
"cross-env": "^7.0.3",
|
||||
"ts-loader": "^6.0.4",
|
||||
"ts-node": "^8.3.0",
|
@ -3,14 +3,14 @@
|
||||
* @Date: 2022-02-01 13:41:59
|
||||
* @Description: 配置文件
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-12-06 19:17:27
|
||||
* @LastEditTime: 2024-08-12 05:13:19
|
||||
*/
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
// 服务器常用修改项
|
||||
const serviceComfig = {
|
||||
port: 7001, // 端口号
|
||||
website: 'https://design.palxp.cn', // 编辑器项目的地址
|
||||
website: 'http://127.0.0.1:5173/', // 编辑器项目的地址
|
||||
filePath: '/cache/' // 生成图片保存的目录
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ exports.servicePort = serviceComfig.port
|
||||
/**
|
||||
* 前端绘制页地址
|
||||
*/
|
||||
exports.drawLink = isDev ? 'http://localhost:5173/draw' : serviceComfig.website + '/draw'
|
||||
exports.drawLink = isDev ? 'http://127.0.0.1:5173/draw' : serviceComfig.website + '/draw'
|
||||
|
||||
/**
|
||||
* 图片缓存目录位置,根据实际情况调整
|
21
service/src/control/api.ts
Normal file
21
service/src/control/api.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2020-07-22 20:13:14
|
||||
* @Description: 接口名称
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 13:39:59
|
||||
*/
|
||||
let path = '/api'
|
||||
|
||||
module.exports = {
|
||||
SCREENGHOT: path + '/screenshots',
|
||||
PRINTSCREEN: path + '/printscreen',
|
||||
// 后端示例
|
||||
UPLOAD: path + '/file/upload',
|
||||
USER_IMAGES: '/design/user/image',
|
||||
GET_TEMPLATE_LIST: '/design/list',
|
||||
GET_TEMPLATE: '/design/temp',
|
||||
GET_MATERIAL: '/design/material',
|
||||
GET_PHOTOS: '/design/imgs',
|
||||
UPDATE_TEMPLATE: '/design/edit',
|
||||
}
|
26
service/src/control/router.ts
Normal file
26
service/src/control/router.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2020-07-22 20:13:14
|
||||
* @Description: 路由
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 13:40:13
|
||||
*/
|
||||
const rExpress = require('express')
|
||||
const screenshots = require('../service/screenshots.ts')
|
||||
const fileService = require('../service/files.ts')
|
||||
const userService = require('../service/user.ts')
|
||||
const designService = require('../service/design.ts')
|
||||
const api = require('./api.ts')
|
||||
const rRouter = rExpress.Router()
|
||||
|
||||
rRouter.get(api.SCREENGHOT, screenshots.screenshots)
|
||||
rRouter.get(api.PRINTSCREEN, screenshots.printscreen)
|
||||
rRouter.post(api.UPLOAD, fileService.upload)
|
||||
rRouter.get(api.USER_IMAGES, userService.getUserImages)
|
||||
rRouter.get(api.GET_TEMPLATE_LIST, designService.getTemplates)
|
||||
rRouter.get(api.GET_TEMPLATE, designService.getDetail)
|
||||
rRouter.get(api.GET_MATERIAL, designService.getMaterial)
|
||||
rRouter.get(api.GET_PHOTOS, designService.getPhotos)
|
||||
rRouter.post(api.UPDATE_TEMPLATE, designService.saveTemplate)
|
||||
|
||||
module.exports = rRouter
|
75
service/src/main.ts
Normal file
75
service/src/main.ts
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2022-02-01 13:41:59
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 06:18:56
|
||||
*/
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const fs = require('fs')
|
||||
// const path = require('path')
|
||||
const router = require('./control/router.ts')
|
||||
const { filePath, servicePort } = require('./configs.ts')
|
||||
const handleTimeout = require('./utils/timeout.ts')
|
||||
|
||||
const port = process.env.PORT || servicePort
|
||||
const app = express()
|
||||
|
||||
// 创建目录
|
||||
const createFolder = (folder: string) => {
|
||||
try {
|
||||
fs.accessSync(folder)
|
||||
} catch (e) {
|
||||
fs.mkdirSync(folder)
|
||||
}
|
||||
}
|
||||
createFolder(filePath)
|
||||
|
||||
app.all('*', (req: any, res: any, next: any) => {
|
||||
res.header('Access-Control-Allow-Origin', '*')
|
||||
res.header('Access-Control-Allow-Headers', 'X-Access-Token,Content-Type,Authorization,Content-Length,Content-Size')
|
||||
res.header('Access-Control-Allow-Methods', '*')
|
||||
res.header('Content-Type', 'application/json;charset=utf-8')
|
||||
next()
|
||||
})
|
||||
|
||||
app.use('/static', setUploadContentType, express.static(process.cwd() + `/static/`))
|
||||
|
||||
app.use(handleTimeout)
|
||||
|
||||
app.use((req: any, res: any, next: any) => {
|
||||
console.log(req.path)
|
||||
next()
|
||||
})
|
||||
|
||||
app.use(bodyParser.urlencoded({ limit: '100mb', extended: true, parameterLimit: 100000 }))
|
||||
app.use(bodyParser.json({ limit: '100mb' }))
|
||||
app.use(router)
|
||||
|
||||
app.listen(port, () => console.log(`Screenshot Server start on port:${port}`))
|
||||
|
||||
const getContentType = function (path: any) {
|
||||
const extension = path.split('.').pop().toLowerCase()
|
||||
switch (extension) {
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
return 'image/jpeg'
|
||||
case 'png':
|
||||
return 'image/png'
|
||||
case 'gif':
|
||||
return 'image/gif'
|
||||
case 'svg':
|
||||
return 'image/svg+xml'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function setUploadContentType(req: any, res: any, next: any) {
|
||||
const contentType = getContentType(req.path)
|
||||
if (contentType) {
|
||||
res.setHeader('Content-Type', contentType)
|
||||
}
|
||||
next()
|
||||
}
|
8
service/src/mock/cates.json
Normal file
8
service/src/mock/cates.json
Normal file
@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "手机海报",
|
||||
"type": 1,
|
||||
"pid": null
|
||||
}
|
||||
]
|
12
service/src/mock/components/detail/1.json
Normal file
12
service/src/mock/components/detail/1.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1907,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96b6ad9c307b7e9568778.png",
|
||||
"data": "{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":-1,\"editable\":false,\"left\":40,\"top\":292,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":0,\"fontSize\":180,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#000000ff\",\"textAlign\":\"center\",\"text\":\"%E8%BE%93%E5%85%A5%E6%96%87%E5%AD%97\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"-1\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":721,\"height\":217,\"rotate\":0,\"transformData\":{\"a\":1,\"b\":0,\"c\":0,\"d\":1,\"tx\":0,\"ty\":0},\"textEffects\":[{\"stroke\":{\"enable\":true,\"type\":\"center\",\"color\":\"#8581f7ff\",\"width\":11.122105263157893},\"offset\":{\"x\":3.7082741393523917,\"y\":6.171604565055211,\"enable\":true}},{\"stroke\":{\"enable\":true,\"type\":\"center\",\"color\":\"#8581f7ff\",\"width\":11.520000000000001}},{\"filling\":{\"enable\":true,\"type\":0,\"color\":\"#ffffffff\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":0,\"stops\":[{\"color\":\"#ffffffff\",\"offset\":0},{\"color\":\"#000000ff\",\"offset\":1}]}}}]}",
|
||||
"created_time": "2023-11-29T11:07:49.000Z",
|
||||
"updated_time": "2023-11-29T11:13:04.000Z",
|
||||
"title": "",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
12
service/src/mock/components/detail/2.json
Normal file
12
service/src/mock/components/detail/2.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1897,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96b84d9c307b7e9569826.png",
|
||||
"data": "{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":-1,\"editable\":false,\"left\":46.00000000000002,\"top\":292,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":0,\"fontSize\":180,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#b8f5ffff\",\"textAlign\":\"center\",\"text\":\"%E8%BE%93%E5%85%A5%E6%96%87%E5%AD%97\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"-1\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":709,\"height\":217,\"rotate\":0,\"transformData\":{\"a\":1,\"b\":0,\"c\":0,\"d\":1,\"tx\":0,\"ty\":0},\"textEffects\":[{\"stroke\":{\"color\":\"#148ef5ff\",\"type\":\"outer\",\"width\":5.538461538461537,\"enable\":true},\"filling\":{\"enable\":true,\"type\":0,\"color\":\"#b8f5ffff\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":0,\"stops\":[{\"color\":\"#ffffffff\",\"offset\":0},{\"color\":\"#000000ff\",\"offset\":1}]}}}]}",
|
||||
"created_time": "2023-11-29T11:07:38.000Z",
|
||||
"updated_time": "2023-11-29T11:18:09.000Z",
|
||||
"title": "花字-输入文字",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
12
service/src/mock/components/detail/3.json
Normal file
12
service/src/mock/components/detail/3.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1893,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96ba4d9c307b7e956b11f.png",
|
||||
"data": "{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":-1,\"editable\":false,\"left\":40,\"top\":292,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":0,\"fontSize\":180,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#e5b187ff\",\"textAlign\":\"center\",\"text\":\"%E8%BE%93%E5%85%A5%E6%96%87%E5%AD%97\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"-1\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":721,\"height\":217,\"rotate\":0,\"transformData\":{\"a\":1,\"b\":0,\"c\":0,\"d\":1,\"tx\":0,\"ty\":0},\"textEffects\":[{\"stroke\":{\"enable\":true,\"type\":\"outer\",\"color\":\"#ffffffff\",\"width\":10.080000000000002},\"filling\":{\"enable\":true,\"type\":0,\"color\":\"#e5b187ff\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":0,\"stops\":[{\"color\":\"#ffffffff\",\"offset\":0},{\"color\":\"#000000ff\",\"offset\":1}]}},\"offset\":{\"x\":0.00045311068155588286,\"y\":0.0005595450922490192,\"enable\":true}},{\"filling\":{\"enable\":true,\"type\":2,\"color\":\"linear-gradient(90deg, #b6aff4ff 0%,#ffa6a9ff 98.83720930232558%)\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":90,\"stops\":[{\"color\":\"#b6aff4ff\",\"offset\":0},{\"color\":\"#ffa6a9ff\",\"offset\":0.9883720930232558}]}}}]}",
|
||||
"created_time": "2023-11-29T11:07:30.000Z",
|
||||
"updated_time": "2023-11-29T11:12:58.000Z",
|
||||
"title": "",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
12
service/src/mock/components/detail/4.json
Normal file
12
service/src/mock/components/detail/4.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1708,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96bbbd9c307b7e956c11f.png",
|
||||
"data": "[{\"name\":\"图片\",\"type\":\"w-image\",\"uuid\":\"b7757b96efa5\",\"width\":764.4985269919339,\"height\":345.4354257106468,\"left\":0,\"top\":0,\"zoom\":1,\"transform\":\" scale(1)\",\"radius\":0,\"opacity\":1,\"parent\":\"8004f90b6dc9\",\"imgUrl\":\"https://pic.imgdb.cn/item/66b96be4d9c307b7e956dd5d.png\",\"setting\":[],\"record\":{\"width\":0,\"height\":0,\"minWidth\":10,\"minHeight\":10,\"dir\":\"all\"},\"letterSpacing\":null,\"rotate\":0,\"imageTransform\":{\"a\":0.9567650714184636,\"b\":0,\"c\":0,\"d\":0.9567650714184635,\"tx\":0,\"ty\":0},\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":\"ed669ec12cad\",\"editable\":false,\"left\":85.44999999999999,\"top\":321.05,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":-3.0004813902799334,\"fontSize\":46.3,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#ffbe55ff\",\"textAlign\":\"left\",\"text\":\"Good thing recommendation\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"8004f90b6dc9\",\"record\":{\"width\":387,\"height\":111,\"minWidth\":46.3,\"minHeight\":55.559999999999995,\"dir\":\"horizontal\"},\"width\":387.16,\"height\":111,\"imgUrl\":\"\",\"rotate\":0,\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":\"bb59ff748689\",\"editable\":false,\"left\":25.058536726412704,\"top\":74.51670112876556,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":-3.4640083745899415,\"fontSize\":165,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#d86356ff\",\"textAlign\":\"center\",\"text\":\"好物推荐\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"8004f90b6dc9\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":703.1134861689588,\"height\":230.00000000000003,\"imgUrl\":\"\",\"rotate\":0,\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"组合\",\"type\":\"w-group\",\"uuid\":\"8004f90b6dc9\",\"width\":765,\"height\":432,\"left\":0,\"top\":0,\"transform\":\"\",\"opacity\":1,\"parent\":\"-1\",\"isContainer\":true,\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"none\"}}]",
|
||||
"created_time": "2023-10-16T01:51:00.000Z",
|
||||
"updated_time": "2023-10-16T11:16:16.000Z",
|
||||
"title": "穿搭品牌文字组合-好物推荐",
|
||||
"width": 763.5,
|
||||
"height": 436.41,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
12
service/src/mock/components/detail/5.json
Normal file
12
service/src/mock/components/detail/5.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1665,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96c65d9c307b7e95738de.png",
|
||||
"data": "[{\"name\":\"图片\",\"type\":\"w-image\",\"uuid\":\"7951dcdd7692\",\"width\":795,\"height\":501,\"left\":0,\"top\":0,\"zoom\":1,\"transform\":\" scale(1)\",\"radius\":0,\"opacity\":1,\"parent\":\"ab07c35d8793\",\"imgUrl\":\"https://pic.imgdb.cn/item/66b96c87d9c307b7e9575fcf.png\",\"setting\":[],\"record\":{\"width\":0,\"height\":0,\"minWidth\":10,\"minHeight\":10,\"dir\":\"all\"},\"letterSpacing\":null,\"rotate\":0,\"imageTransform\":{\"a\":1,\"b\":0,\"c\":0,\"d\":1,\"tx\":0,\"ty\":0},\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":\"250fd3b14808\",\"editable\":false,\"left\":64.48518998724226,\"top\":124.72493062188272,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":0,\"fontSize\":164,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#fa7f69ff\",\"textAlign\":\"center\",\"text\":\"今日探店\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"ab07c35d8793\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":675.563157252699,\"height\":198.00000000000003,\"imgUrl\":\"\",\"rotate\":0,\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":\"99118d63bc46\",\"editable\":false,\"left\":204.35,\"top\":321.93,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":24.10222222222222,\"fontSize\":45,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#9f5b40ff\",\"textAlign\":\"center\",\"text\":\"Today's shop\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"ab07c35d8793\",\"record\":{\"width\":476,\"height\":54,\"minWidth\":45,\"minHeight\":54,\"dir\":\"horizontal\"},\"width\":475.84,\"height\":54,\"imgUrl\":\"\",\"rotate\":0,\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"组合\",\"type\":\"w-group\",\"uuid\":\"ab07c35d8793\",\"width\":795,\"height\":501,\"left\":0,\"top\":0,\"transform\":\"\",\"opacity\":1,\"parent\":\"-1\",\"isContainer\":true,\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"none\"}}]",
|
||||
"created_time": "2023-10-16T01:49:31.000Z",
|
||||
"updated_time": "2023-10-16T11:24:01.000Z",
|
||||
"title": "穿搭品牌文字组合",
|
||||
"width": 794,
|
||||
"height": 500,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
12
service/src/mock/components/detail/6.json
Normal file
12
service/src/mock/components/detail/6.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": 1692,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96cc9d9c307b7e958455f.png",
|
||||
"data": "[{\"name\":\"图片\",\"type\":\"w-image\",\"uuid\":\"53f98d18aeae\",\"width\":767.4314928425358,\"height\":367.5040822916187,\"left\":0,\"top\":0,\"zoom\":1,\"transform\":\" scale(1)\",\"radius\":0,\"opacity\":1,\"parent\":\"e885329bd396\",\"imgUrl\":\"https://pic.imgdb.cn/item/66b96cddd9c307b7e9588873.png\",\"setting\":[],\"record\":{\"width\":0,\"height\":0,\"minWidth\":10,\"minHeight\":10,\"dir\":\"all\"},\"letterSpacing\":null,\"rotate\":0,\"imageTransform\":{\"a\":1.1525285606654676,\"b\":0,\"c\":0,\"d\":1.1525285606654676,\"tx\":0,\"ty\":0},\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"文本\",\"type\":\"w-text\",\"uuid\":\"092893910ceb\",\"editable\":false,\"left\":41.16266426491816,\"top\":91.58384458077711,\"transform\":\"\",\"lineHeight\":1.2,\"letterSpacing\":0,\"fontSize\":150,\"fontClass\":{\"alias\":\"站酷快乐体\",\"id\":543,\"value\":\"zcool-kuaile-regular\",\"url\":\"https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2\"},\"fontWeight\":400,\"fontStyle\":\"normal\",\"writingMode\":\"horizontal-tb\",\"textDecoration\":\"none\",\"color\":\"#057bccff\",\"textAlign\":\"center\",\"text\":\"今日上新\",\"opacity\":1,\"backgroundColor\":\"\",\"parent\":\"e885329bd396\",\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"horizontal\"},\"width\":698.1940988730267,\"height\":204,\"imgUrl\":\"\",\"rotate\":0,\"textEffects\":[{\"shadow\":{\"color\":\"#45ece4ff\",\"offsetX\":4.610655737704919,\"offsetY\":7.985889993913879,\"blur\":0,\"enable\":true},\"filling\":{\"enable\":true,\"type\":0,\"color\":\"#057bccff\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":0,\"stops\":[{\"color\":\"#ffffffff\",\"offset\":0},{\"color\":\"#000000ff\",\"offset\":1}]}}},{\"stroke\":{\"color\":\"#ffffffff\",\"type\":\"outer\",\"width\":2.0491803278688523,\"enable\":true},\"filling\":{\"enable\":true,\"type\":0,\"color\":\"#057bccff\",\"imageContent\":{\"repeat\":0,\"scaleX\":1,\"scaleY\":1,\"image\":null,\"width\":null,\"height\":null},\"gradient\":{\"byLine\":0,\"angle\":0,\"stops\":[{\"color\":\"#ffffffff\",\"offset\":0},{\"color\":\"#000000ff\",\"offset\":1}]}}}],\"filter\":{\"contrast\":0,\"sharpness\":0,\"hueRotate\":0,\"saturate\":0,\"brightness\":0,\"gaussianBlur\":0,\"temperature\":0,\"tint\":0}},{\"name\":\"组合\",\"type\":\"w-group\",\"uuid\":\"e885329bd396\",\"width\":766.4314928425358,\"height\":366.50408229161866,\"left\":0,\"top\":0,\"transform\":\"\",\"opacity\":1,\"parent\":\"-1\",\"isContainer\":true,\"setting\":[],\"record\":{\"width\":0,\"height\":0,\"minWidth\":0,\"minHeight\":0,\"dir\":\"none\"}}]",
|
||||
"created_time": "2023-10-16T01:50:26.000Z",
|
||||
"updated_time": "2023-10-16T11:19:39.000Z",
|
||||
"title": "穿搭品牌文字组合",
|
||||
"width": 766.43,
|
||||
"height": 366.5,
|
||||
"state": 1,
|
||||
"tag": null
|
||||
}
|
26
service/src/mock/components/list/comp.json
Normal file
26
service/src/mock/components/list/comp.json
Normal file
@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96bbbd9c307b7e956c11f.png",
|
||||
"title": "穿搭品牌文字组合",
|
||||
"width": 763.5,
|
||||
"height": 436.41,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96c65d9c307b7e95738de.png",
|
||||
"title": "穿搭品牌文字组合",
|
||||
"width": 794,
|
||||
"height": 500,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96cc9d9c307b7e958455f.png",
|
||||
"title": "穿搭品牌文字组合",
|
||||
"width": 766.43,
|
||||
"height": 366.5,
|
||||
"state": 1
|
||||
}
|
||||
]
|
26
service/src/mock/components/list/text.json
Normal file
26
service/src/mock/components/list/text.json
Normal file
@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96b6ad9c307b7e9568778.png",
|
||||
"title": "",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96b84d9c307b7e9569826.png",
|
||||
"title": "花字-输入文字",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"cover": "https://pic.imgdb.cn/item/66b96ba4d9c307b7e956b11f.png",
|
||||
"title": "",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"state": 1
|
||||
}
|
||||
]
|
41
service/src/mock/materials/mask.json
Normal file
41
service/src/mock/materials/mask.json
Normal file
@ -0,0 +1,41 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "爱心图片容器",
|
||||
"width": 1000,
|
||||
"height": 1000,
|
||||
"type": "mask",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96d96d9c307b7e95b20a9.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96d96d9c307b7e95b20a9.png",
|
||||
"created_time": "2023-08-20T21:46:49.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "扇形图片容器",
|
||||
"width": 1000,
|
||||
"height": 1000,
|
||||
"type": "mask",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96da6d9c307b7e95b5cb8.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96da6d9c307b7e95b5cb8.png",
|
||||
"created_time": "2023-08-20T21:46:52.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "星星图片容器",
|
||||
"width": 1000,
|
||||
"height": 1000,
|
||||
"type": "mask",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96db5d9c307b7e95b9c96.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96db5d9c307b7e95b9c96.png",
|
||||
"created_time": "2023-08-20T21:47:03.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
}
|
||||
]
|
422
service/src/mock/materials/photos/1.json
Normal file
422
service/src/mock/materials/photos/1.json
Normal file
@ -0,0 +1,422 @@
|
||||
[
|
||||
{
|
||||
"id": 392,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1669904021308-567d085a0ee7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1669904021308-567d085a0ee7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3943,
|
||||
"height": 5907,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "BnHJf5bx6zY",
|
||||
"author": "Kateryna Hliznitsova",
|
||||
"description": "一个人在一杯咖啡旁边的一张纸上写字",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 394,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1669686968068-ef4133a3e782?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1669686968068-ef4133a3e782?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6630,
|
||||
"height": 5304,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "KRUtalZrz04",
|
||||
"author": "Brock Wegner",
|
||||
"description": "桌上放着一台笔记本电脑",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 395,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1661274209157-118069b926f3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1661274209157-118069b926f3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5760,
|
||||
"height": 3840,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "BCeRwWOvenM",
|
||||
"author": "Getty Images",
|
||||
"description": "商务人士在办公室工作和头脑风暴",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 396,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1672287578699-618ea6dbcc9e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1672287578699-618ea6dbcc9e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2724,
|
||||
"height": 4086,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "P1nKvKqkXGk",
|
||||
"author": "Giulia Squillace",
|
||||
"description": "一个在建筑里雕刻雕塑的人",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 397,
|
||||
"thumb": "https://images.unsplash.com/photo-1587554801471-37976a256db0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1587554801471-37976a256db0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3684,
|
||||
"height": 5526,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "tqkDGqPW8Vo",
|
||||
"author": "Olga Serjantu",
|
||||
"description": "穿黄衬衫的女人坐在椅子上",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 398,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1674777843121-a205f3e0bc62?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1674777843121-a205f3e0bc62?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2473,
|
||||
"height": 3300,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "mMVFQwDAlPQ",
|
||||
"author": "Lia Bekyan",
|
||||
"description": "一个穿西装打领带的男人",
|
||||
"color": "#260c0c"
|
||||
},
|
||||
{
|
||||
"id": 399,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1677695598264-6d88f8ee31f0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1677695598264-6d88f8ee31f0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5000,
|
||||
"height": 3333,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "j1esUYunPdo",
|
||||
"author": "JSB Co.",
|
||||
"description": "剪刀放在机器上的一把剪刀",
|
||||
"color": "#c0c0c0"
|
||||
},
|
||||
{
|
||||
"id": 400,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1668383778611-a817740e1b6b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1668383778611-a817740e1b6b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6000,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "Mal1M5DQWdc",
|
||||
"author": "Michael Tucker",
|
||||
"description": "几个人坐在房间里的一张桌子旁",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 401,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1668383205037-8d3f75314a06?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1668383205037-8d3f75314a06?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTYzNTQwOTR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5472,
|
||||
"height": 3648,
|
||||
"created_time": "2023-10-04T01:29:13.000Z",
|
||||
"updated_time": "2023-10-04T01:29:13.000Z",
|
||||
"category": 26,
|
||||
"original": "FePq2NkJ6wU",
|
||||
"author": "Michael Tucker",
|
||||
"description": "一个男人和一个小女孩坐在一张桌子旁",
|
||||
"color": "#EFEFEF"
|
||||
},
|
||||
{
|
||||
"id": 492,
|
||||
"thumb": "https://images.unsplash.com/photo-1695408251539-31edab27e8e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695408251539-31edab27e8e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4000,
|
||||
"height": 6000,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "e2btSmpVyVM",
|
||||
"author": "Wesley Tingey",
|
||||
"description": "一名男子拿着照相机正在录像",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 493,
|
||||
"thumb": "https://images.unsplash.com/photo-1695395855294-92b404ec00e9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695395855294-92b404ec00e9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 8377,
|
||||
"height": 5755,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "W6Fh690Ntfk",
|
||||
"author": "aboodi vesakaran",
|
||||
"description": "一辆白色货车,上面有亚马逊prime的标志",
|
||||
"color": "#c0c0c0"
|
||||
},
|
||||
{
|
||||
"id": 494,
|
||||
"thumb": "https://images.unsplash.com/photo-1695624825386-ec67689eb983?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695624825386-ec67689eb983?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3847,
|
||||
"height": 6000,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "9IdFjHfP0lo",
|
||||
"author": "Declan Sun",
|
||||
"description": "走廊上有文字装饰的墙壁和海报",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 495,
|
||||
"thumb": "https://images.unsplash.com/photo-1695548053857-c070504389f0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695548053857-c070504389f0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4595,
|
||||
"height": 6893,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "VnrTSfWmP1s",
|
||||
"author": "Maxence Pira",
|
||||
"description": "一间摆满了桌椅的大房间",
|
||||
"color": "#260c0c"
|
||||
},
|
||||
{
|
||||
"id": 496,
|
||||
"thumb": "https://images.unsplash.com/photo-1694951558444-03b27ca33665?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694951558444-03b27ca33665?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3024,
|
||||
"height": 4032,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "XTkIub6UDnU",
|
||||
"author": "Yana Marudova",
|
||||
"description": "从Ludwig Erhard Haus电梯内部看,展示了建筑的未来主义内部,电梯本身装饰着木板。",
|
||||
"color": "#73260c"
|
||||
},
|
||||
{
|
||||
"id": 497,
|
||||
"thumb": "https://images.unsplash.com/photo-1695407773557-ea2dc7b3ed4a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695407773557-ea2dc7b3ed4a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6240,
|
||||
"height": 4160,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "zCX0mBy1-iU",
|
||||
"author": "Komarov Egor ",
|
||||
"description": "带有按钮的控制面板的特写",
|
||||
"color": "#0c2626"
|
||||
},
|
||||
{
|
||||
"id": 498,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1677508967195-a3951205ca70?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1677508967195-a3951205ca70?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6004,
|
||||
"height": 3935,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "seGYeyekwAU",
|
||||
"author": "Mina Rad",
|
||||
"description": "一个戴安全帽的女人拿着一张蓝图",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 499,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1677920190308-ea03b51a9d9b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1677920190308-ea03b51a9d9b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3597,
|
||||
"height": 5381,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "4NKaNzL1Iqg",
|
||||
"author": "Mina Rad",
|
||||
"description": "一男一女站在大楼前",
|
||||
"color": "#c0c0c0"
|
||||
},
|
||||
{
|
||||
"id": 500,
|
||||
"thumb": "https://images.unsplash.com/photo-1695029400320-f3fc8efa30b5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695029400320-f3fc8efa30b5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5984,
|
||||
"height": 3848,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "27Eot-Zulmw",
|
||||
"author": "Cai Fang",
|
||||
"description": "密集宿舍楼",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 501,
|
||||
"thumb": "https://images.unsplash.com/photo-1694881227503-ddc502d4b4cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694881227503-ddc502d4b4cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjczODl8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6227,
|
||||
"height": 4151,
|
||||
"created_time": "2023-10-04T21:49:57.000Z",
|
||||
"updated_time": "2023-10-04T21:49:57.000Z",
|
||||
"category": 26,
|
||||
"original": "E8JXH2PNahs",
|
||||
"author": "Tim Mossholder",
|
||||
"description": "播客主持人Dorian Djougoue。关注他:@dorian.djougoue",
|
||||
"color": "#c0c0c0"
|
||||
},
|
||||
{
|
||||
"id": 502,
|
||||
"thumb": "https://images.unsplash.com/photo-1694638275387-9971d6b19880?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694638275387-9971d6b19880?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4480,
|
||||
"height": 5600,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "cdiSpITPwvE",
|
||||
"author": "Ben Iwara",
|
||||
"description": "一个人站在红灯前",
|
||||
"color": "#8c0c0c"
|
||||
},
|
||||
{
|
||||
"id": 503,
|
||||
"thumb": "https://images.unsplash.com/photo-1694638278223-4c3907aa2354?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694638278223-4c3907aa2354?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6720,
|
||||
"height": 4480,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "V51__4DiYV4",
|
||||
"author": "Ben Iwara",
|
||||
"description": "一个女人正在对着镜子照自己",
|
||||
"color": "#c0590c"
|
||||
},
|
||||
{
|
||||
"id": 504,
|
||||
"thumb": "https://images.unsplash.com/photo-1694543668881-f5a1174bfca9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694543668881-f5a1174bfca9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4000,
|
||||
"height": 5000,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "qELWBcqOzdo",
|
||||
"author": "Sayan Majhi",
|
||||
"description": "苹果2023年发布会。",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 505,
|
||||
"thumb": "https://images.unsplash.com/photo-1694324217586-3b065a9eeee8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694324217586-3b065a9eeee8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2626,
|
||||
"height": 3283,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "0vJz_fyVcZ8",
|
||||
"author": "Vishwasa Navada K",
|
||||
"description": "班加罗尔国际机场休息室的工作舱",
|
||||
"color": "#594040"
|
||||
},
|
||||
{
|
||||
"id": 506,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1682702597511-df891e5e2219?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1682702597511-df891e5e2219?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6000,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "4_-k_FGlU8Y",
|
||||
"author": "Lala Azizli",
|
||||
"description": "手里拿着白牌的人",
|
||||
"color": "#8c8ca6"
|
||||
},
|
||||
{
|
||||
"id": 507,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1681319269837-98a23dfb24aa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1681319269837-98a23dfb24aa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3376,
|
||||
"height": 5071,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "k3ifGQUJGf8",
|
||||
"author": "Jason Hawke ",
|
||||
"description": "从钱包里伸出来的一美元钞票",
|
||||
"color": "#59408c"
|
||||
},
|
||||
{
|
||||
"id": 508,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1681305758171-f28f43aa0dc7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1681305758171-f28f43aa0dc7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4738,
|
||||
"height": 2961,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "a74eSALUep0",
|
||||
"author": "Jason Hawke ",
|
||||
"description": "皮沙发上放着一部手机",
|
||||
"color": "#594026"
|
||||
},
|
||||
{
|
||||
"id": 509,
|
||||
"thumb": "https://images.unsplash.com/photo-1694409496215-d116011d0d1b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694409496215-d116011d0d1b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5842,
|
||||
"height": 3895,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "kOdl-epUGUE",
|
||||
"author": "Michael Pointner",
|
||||
"description": "有桌子和椅子的房间",
|
||||
"color": "#260c0c"
|
||||
},
|
||||
{
|
||||
"id": 510,
|
||||
"thumb": "https://images.unsplash.com/photo-1694401460834-87b727378a63?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694401460834-87b727378a63?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5463,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "cDOXyyBeK8c",
|
||||
"author": "Declan Sun",
|
||||
"description": "张江科学馆的自动扶梯",
|
||||
"color": "#8ca6c0"
|
||||
},
|
||||
{
|
||||
"id": 511,
|
||||
"thumb": "https://images.unsplash.com/photo-1694401460698-8b7b0489b27a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694401460698-8b7b0489b27a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgyMjV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5455,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-04T22:03:53.000Z",
|
||||
"updated_time": "2023-10-04T22:03:53.000Z",
|
||||
"category": 26,
|
||||
"original": "pYLuh6fRdhw",
|
||||
"author": "Declan Sun",
|
||||
"description": "张江科学馆近景",
|
||||
"color": "#8cc0f3"
|
||||
},
|
||||
{
|
||||
"id": 512,
|
||||
"thumb": "https://images.unsplash.com/photo-1694399319378-efcfd00aa1e8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgzMjh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694399319378-efcfd00aa1e8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8YWV1NnJMLWo2ZXd8fHx8fDJ8fDE2OTY0MjgzMjh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2995,
|
||||
"height": 2995,
|
||||
"created_time": "2023-10-04T22:08:45.000Z",
|
||||
"updated_time": "2023-10-04T22:08:45.000Z",
|
||||
"category": 26,
|
||||
"original": "s0DKhyQftnk",
|
||||
"author": "Hillary Black",
|
||||
"description": "无题",
|
||||
"color": "#8c8c8c"
|
||||
}
|
||||
]
|
394
service/src/mock/materials/photos/2.json
Normal file
394
service/src/mock/materials/photos/2.json
Normal file
@ -0,0 +1,394 @@
|
||||
[
|
||||
{
|
||||
"id": 432,
|
||||
"thumb": "https://images.unsplash.com/photo-1674684417927-0008e103930f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1674684417927-0008e103930f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3077,
|
||||
"height": 2040,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "H28oH0s7gac",
|
||||
"author": "Megan Nixon",
|
||||
"description": "无题",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 433,
|
||||
"thumb": "https://images.unsplash.com/photo-1674684493970-a153e378af72?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1674684493970-a153e378af72?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3130,
|
||||
"height": 2075,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "OcfpHpQNiI8",
|
||||
"author": "Megan Nixon",
|
||||
"description": "太阳正落在海面上,海面上有岩石",
|
||||
"color": "#a6c0c0"
|
||||
},
|
||||
{
|
||||
"id": 434,
|
||||
"thumb": "https://images.unsplash.com/photo-1696258361221-9f9bc7b99c92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696258361221-9f9bc7b99c92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5807,
|
||||
"height": 3869,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "8Yjvz56y7QU",
|
||||
"author": "Samuele Giglio",
|
||||
"description": "一群棕榈树,背景是蓝天",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 435,
|
||||
"thumb": "https://images.unsplash.com/photo-1696258361311-0b25ee8af854?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696258361311-0b25ee8af854?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5807,
|
||||
"height": 3869,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "krA_f-jEobI",
|
||||
"author": "Samuele Giglio",
|
||||
"description": "以山为背景的城市景观",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 436,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1690164161389-1921e4981b69?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1690164161389-1921e4981b69?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3130,
|
||||
"height": 2075,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "N7GTHx2F8H0",
|
||||
"author": "Hans Isaacson",
|
||||
"description": "有很多树和岩石的海滩",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 437,
|
||||
"thumb": "https://images.unsplash.com/photo-1696259630326-9cf6be5e96aa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696259630326-9cf6be5e96aa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 1846,
|
||||
"height": 2785,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "dXSe4d9xbyQ",
|
||||
"author": "Richard Stachmann",
|
||||
"description": "柯达黄金200",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 438,
|
||||
"thumb": "https://images.unsplash.com/photo-1684183164497-f62ee4c78620?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1684183164497-f62ee4c78620?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2411,
|
||||
"height": 3616,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "0aWJqicnOLM",
|
||||
"author": "Chris Weiher",
|
||||
"description": "地中海的海浪冲击着意大利阿马尔菲海岸。水的颜色可以用青绿色来形容。",
|
||||
"color": "#a6a68c"
|
||||
},
|
||||
{
|
||||
"id": 439,
|
||||
"thumb": "https://images.unsplash.com/photo-1684183164552-df1258404d38?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1684183164552-df1258404d38?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3612,
|
||||
"height": 2408,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "2HwdhMvgYfE",
|
||||
"author": "Chris Weiher",
|
||||
"description": "意大利南部两棵丑陋的棕榈树之间的蓝色天空中的月亮。在西尔伯萨尔兹250D模拟胶片上拍摄。",
|
||||
"color": "#8ca6c0"
|
||||
},
|
||||
{
|
||||
"id": 440,
|
||||
"thumb": "https://images.unsplash.com/photo-1696268516413-56e2c7c37639?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696268516413-56e2c7c37639?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3167,
|
||||
"height": 4492,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "OMGAR5MSSM8",
|
||||
"author": "Robert Bye",
|
||||
"description": "一群人站在沙滩上",
|
||||
"color": "#c0d9f3"
|
||||
},
|
||||
{
|
||||
"id": 441,
|
||||
"thumb": "https://images.unsplash.com/photo-1696258361232-5cf43e06afa8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696258361232-5cf43e06afa8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MTgxODV8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5807,
|
||||
"height": 3869,
|
||||
"created_time": "2023-10-04T19:16:32.000Z",
|
||||
"updated_time": "2023-10-04T19:16:32.000Z",
|
||||
"category": 33,
|
||||
"original": "-pQUCnVLqFs",
|
||||
"author": "Samuele Giglio",
|
||||
"description": "灯光昏暗的房间里有几张木桌和椅子",
|
||||
"color": "#260c0c"
|
||||
},
|
||||
{
|
||||
"id": 632,
|
||||
"thumb": "https://images.unsplash.com/photo-1696268547236-09b9669f8a7e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696268547236-09b9669f8a7e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3167,
|
||||
"height": 4492,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "mxkqjQtYhlU",
|
||||
"author": "Robert Bye",
|
||||
"description": "在阳光明媚的日子里通往大海的楼梯",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 633,
|
||||
"thumb": "https://images.unsplash.com/photo-1696268615869-f6be40a7ebd8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696268615869-f6be40a7ebd8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3167,
|
||||
"height": 4492,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "u4RGxjShwnc",
|
||||
"author": "Robert Bye",
|
||||
"description": "一座石头建筑,前面有一座钟",
|
||||
"color": "#c0d9f3"
|
||||
},
|
||||
{
|
||||
"id": 634,
|
||||
"thumb": "https://images.unsplash.com/photo-1694816602214-72f2729e86e7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694816602214-72f2729e86e7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4881,
|
||||
"height": 3272,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "UNYHQM0ElwI",
|
||||
"author": "Ethan Hansen",
|
||||
"description": "搭载富士GW690II的Porta 800",
|
||||
"color": "#a65940"
|
||||
},
|
||||
{
|
||||
"id": 635,
|
||||
"thumb": "https://images.unsplash.com/photo-1681332192745-1f00ceed0b45?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1681332192745-1f00ceed0b45?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5444,
|
||||
"height": 3649,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "23XSW5hNFRU",
|
||||
"author": "Mykyta Kravenko",
|
||||
"description": "本地汽车隧道。尼康F(1968),尼克尔50mm(21世纪初)。高分辨率模拟扫描www.boutiquefilmlab.com cinstill 800钨",
|
||||
"color": "#0c2626"
|
||||
},
|
||||
{
|
||||
"id": 636,
|
||||
"thumb": "https://images.unsplash.com/photo-1695370530104-3417106f11e3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695370530104-3417106f11e3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2872,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "bidoZaK4ZIE",
|
||||
"author": "The Australian War Memorial",
|
||||
"description": "一名德国士兵从他的观察气球上跳下来身份证号:H13483摄影师:德意志帝国档案馆地点:未知一名德国士兵从他的观察气球上跳下来。当他们的气球被盟军飞机袭击时,德国观察员遵循了这个程序。https://www.flickr.com/photos/australian-war-memorial/21795002060/in/album-72157659120304398/",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 637,
|
||||
"thumb": "https://images.unsplash.com/photo-1695649424908-b98530375146?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695649424908-b98530375146?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3507,
|
||||
"height": 5108,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "sZM6zQObTFU",
|
||||
"author": "szm 4",
|
||||
"description": "一栋有很多窗户的建筑",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 638,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1690164680142-701cf794a832?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1690164680142-701cf794a832?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2075,
|
||||
"height": 3130,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "RZkg3a-RVSE",
|
||||
"author": "Hans Isaacson",
|
||||
"description": "拿着冲浪板走在沙滩上的人",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 639,
|
||||
"thumb": "https://images.unsplash.com/photo-1681625597273-a8888f25eddb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1681625597273-a8888f25eddb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MDN8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2645,
|
||||
"height": 3826,
|
||||
"created_time": "2023-10-05T00:24:59.000Z",
|
||||
"updated_time": "2023-10-05T00:24:59.000Z",
|
||||
"category": 33,
|
||||
"original": "vgShIkGBqFc",
|
||||
"author": "Howen",
|
||||
"description": "在街上骑自行车的人",
|
||||
"color": "#c0a68c"
|
||||
},
|
||||
{
|
||||
"id": 640,
|
||||
"thumb": "https://images.unsplash.com/photo-1693416789619-0dfb6485943d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1693416789619-0dfb6485943d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2333,
|
||||
"height": 3500,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "xNuTNri-6Hs",
|
||||
"author": "Markus Spiske",
|
||||
"description": "慕尼黑的地铁。徕卡M6 (1987), Summilux-M 1.4 35mm(1983)。高分辨率模拟扫描www.urbanfilmlab.com cinstill Xpro 800钨",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 641,
|
||||
"thumb": "https://images.unsplash.com/photo-1695404468642-12830a1d4c7d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695404468642-12830a1d4c7d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3637,
|
||||
"height": 2433,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "Dolz-BphJjQ",
|
||||
"author": "Chase Caldwell",
|
||||
"description": "一个女人站在海边的悬崖顶上",
|
||||
"color": "#8ca6c0"
|
||||
},
|
||||
{
|
||||
"id": 642,
|
||||
"thumb": "https://images.unsplash.com/photo-1692026801134-dc74fa1d9aa5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1692026801134-dc74fa1d9aa5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4313,
|
||||
"height": 6504,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "1HuDHbAnd78",
|
||||
"author": "Annie Spratt",
|
||||
"description": "一片被树木和山脉包围的水域",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 643,
|
||||
"thumb": "https://images.unsplash.com/photo-1691824103453-2b9c1d89504b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1691824103453-2b9c1d89504b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4492,
|
||||
"height": 6774,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "Ms-FanpBBU4",
|
||||
"author": "Annie Spratt",
|
||||
"description": "一条流经郁郁葱葱的山坡的河流",
|
||||
"color": "#c0d9f3"
|
||||
},
|
||||
{
|
||||
"id": 644,
|
||||
"thumb": "https://images.unsplash.com/photo-1695659650981-a0afd184d6ad?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695659650981-a0afd184d6ad?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 1889,
|
||||
"height": 2897,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "IJEw0v34dak",
|
||||
"author": "Valeria Vaganian",
|
||||
"description": "生日花",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 645,
|
||||
"thumb": "https://images.unsplash.com/photo-1695307965322-61077ed0bc22?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695307965322-61077ed0bc22?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3600,
|
||||
"height": 2400,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "aB-a8q-x5hM",
|
||||
"author": "Randy Laybourne",
|
||||
"description": "我们使用的越多,我们制造的垃圾就越多。回收这些垃圾的尝试似乎只是杯水车薪。",
|
||||
"color": "#d92626"
|
||||
},
|
||||
{
|
||||
"id": 646,
|
||||
"thumb": "https://images.unsplash.com/photo-1695676304344-06f3f16faf59?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695676304344-06f3f16faf59?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3510,
|
||||
"height": 5293,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "NZFzU0ILyC0",
|
||||
"author": "Caleb Woods",
|
||||
"description": "一辆顶着头盔的红色汽车",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 647,
|
||||
"thumb": "https://images.unsplash.com/photo-1696215123982-f6ced9faa34f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696215123982-f6ced9faa34f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 7719,
|
||||
"height": 11520,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "TerTY3G7GJI",
|
||||
"author": "Venti Views",
|
||||
"description": "使用尼康f100 35mm胶片拍摄",
|
||||
"color": "#c0c0c0"
|
||||
},
|
||||
{
|
||||
"id": 648,
|
||||
"thumb": "https://images.unsplash.com/photo-1694588579227-e5d9c9524dfa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694588579227-e5d9c9524dfa?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4722,
|
||||
"height": 3108,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "h-OwCCAMMVk",
|
||||
"author": "Nik",
|
||||
"description": "",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 649,
|
||||
"thumb": "https://images.unsplash.com/photo-1694588586438-703ef60dc56a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1694588586438-703ef60dc56a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8aG1lbnZRaFVteE18fHx8fDJ8fDE2OTY0MzY3MjR8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5689,
|
||||
"height": 3803,
|
||||
"created_time": "2023-10-05T00:25:25.000Z",
|
||||
"updated_time": "2023-10-05T00:25:25.000Z",
|
||||
"category": 33,
|
||||
"original": "zQgNc8IDtqY",
|
||||
"author": "Nik",
|
||||
"description": "",
|
||||
"color": "#404040"
|
||||
}
|
||||
]
|
422
service/src/mock/materials/photos/3.json
Normal file
422
service/src/mock/materials/photos/3.json
Normal file
@ -0,0 +1,422 @@
|
||||
[
|
||||
{
|
||||
"id": 482,
|
||||
"thumb": "https://images.unsplash.com/photo-1695763608950-d224f9189ef7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695763608950-d224f9189ef7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6336,
|
||||
"height": 9520,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "lc9uYwe54us",
|
||||
"author": "Karsten Winegeart",
|
||||
"description": "通往天堂的阶梯",
|
||||
"color": "#c0d9d9"
|
||||
},
|
||||
{
|
||||
"id": 483,
|
||||
"thumb": "https://images.unsplash.com/photo-1695763491781-748b1e3b2c3c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695763491781-748b1e3b2c3c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6264,
|
||||
"height": 9412,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "6hy-3Uc0jS0",
|
||||
"author": "Karsten Winegeart",
|
||||
"description": "教堂",
|
||||
"color": "#738ca6"
|
||||
},
|
||||
{
|
||||
"id": 484,
|
||||
"thumb": "https://images.unsplash.com/photo-1695760442128-6db7202ea8cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695760442128-6db7202ea8cc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4091,
|
||||
"height": 6136,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "baWtGQuyNVo",
|
||||
"author": "Karsten Winegeart",
|
||||
"description": "独自一人",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 485,
|
||||
"thumb": "https://images.unsplash.com/photo-1696171667963-ad7a0ab6ffac?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696171667963-ad7a0ab6ffac?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5629,
|
||||
"height": 7505,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "O_D4pTrPcBQ",
|
||||
"author": "Martin Katler",
|
||||
"description": "以山为背景的城市景观",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 486,
|
||||
"thumb": "https://images.unsplash.com/photo-1696259141244-650be1219522?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696259141244-650be1219522?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3648,
|
||||
"height": 5472,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "8IU8l_39XR0",
|
||||
"author": "eberhard grossgasteiger",
|
||||
"description": "一个湖边的小镇,背后是群山",
|
||||
"color": "#262626"
|
||||
},
|
||||
{
|
||||
"id": 487,
|
||||
"thumb": "https://images.unsplash.com/photo-1696346299667-808c1f233dbc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696346299667-808c1f233dbc?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 9240,
|
||||
"height": 13883,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "q-MldlOR9EE",
|
||||
"author": "Karsten Winegeart",
|
||||
"description": "安静...",
|
||||
"color": "#735940"
|
||||
},
|
||||
{
|
||||
"id": 488,
|
||||
"thumb": "https://images.unsplash.com/photo-1696371254452-e8fd8e0cd191?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696371254452-e8fd8e0cd191?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3308,
|
||||
"height": 4961,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "U96T__GBdUU",
|
||||
"author": "Mathias Reding",
|
||||
"description": "一座大建筑物,上面有一座钟楼",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 489,
|
||||
"thumb": "https://images.unsplash.com/photo-1695043722490-72207a74a7be?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695043722490-72207a74a7be?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3605,
|
||||
"height": 5634,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "ovfl4RfHoac",
|
||||
"author": "Jorgen Hendriksen",
|
||||
"description": "绿色的。",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 490,
|
||||
"thumb": "https://images.unsplash.com/photo-1695418416357-4b248028af92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695418416357-4b248028af92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4000,
|
||||
"height": 6000,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "5x3Cfw2h7sI",
|
||||
"author": "Anne Laure P",
|
||||
"description": "神社",
|
||||
"color": "#c0d9d9"
|
||||
},
|
||||
{
|
||||
"id": 491,
|
||||
"thumb": "https://images.unsplash.com/photo-1696085709531-81fba5dbcffd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696085709531-81fba5dbcffd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MjYxMzh8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5966,
|
||||
"height": 3356,
|
||||
"created_time": "2023-10-04T21:43:34.000Z",
|
||||
"updated_time": "2023-10-04T21:43:34.000Z",
|
||||
"category": 35,
|
||||
"original": "B34Vmj0ZgCA",
|
||||
"author": "Fahrul Razi",
|
||||
"description": "太阳落山,海面上露出一块岩石",
|
||||
"color": "#c0a673"
|
||||
},
|
||||
{
|
||||
"id": 670,
|
||||
"thumb": "https://images.unsplash.com/photo-1695883668752-3e6bdf0f3649?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695883668752-3e6bdf0f3649?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6001,
|
||||
"height": 3993,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "uzVUwf4ri8E",
|
||||
"author": "Zetong Li",
|
||||
"description": "太阳照耀着沙漠中的群山",
|
||||
"color": "#594026"
|
||||
},
|
||||
{
|
||||
"id": 671,
|
||||
"thumb": "https://images.unsplash.com/photo-1691788793928-2924fb185699?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1691788793928-2924fb185699?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 7727,
|
||||
"height": 5152,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "LiI5VQEWKqg",
|
||||
"author": "Alexey Iskhakov",
|
||||
"description": "一座山,背景是粉红色的天空",
|
||||
"color": "#c08c8c"
|
||||
},
|
||||
{
|
||||
"id": 672,
|
||||
"thumb": "https://images.unsplash.com/photo-1673881140563-6779096df45c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1673881140563-6779096df45c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6048,
|
||||
"height": 4024,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "iNknvUAC3BY",
|
||||
"author": "Tianhao Wang",
|
||||
"description": "雪中一个人站在一辆红色汽车的车顶上",
|
||||
"color": "#c0d9f3"
|
||||
},
|
||||
{
|
||||
"id": 673,
|
||||
"thumb": "https://images.unsplash.com/photo-1673881142553-673849892c3e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1673881142553-673849892c3e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6048,
|
||||
"height": 4024,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "0wmUgIDXFy4",
|
||||
"author": "Tianhao Wang",
|
||||
"description": "一个人站在布满星星的天空下被雪覆盖的路上",
|
||||
"color": "#262640"
|
||||
},
|
||||
{
|
||||
"id": 674,
|
||||
"thumb": "https://images.unsplash.com/photo-1695982207069-49678b07a4c9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695982207069-49678b07a4c9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6000,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "8qIx1JfP1GA",
|
||||
"author": "David Becker",
|
||||
"description": "一座红色的小房子坐落在郁郁葱葱的绿色山坡上",
|
||||
"color": "#404040"
|
||||
},
|
||||
{
|
||||
"id": 675,
|
||||
"thumb": "https://images.unsplash.com/photo-1696142990758-581061f2801d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696142990758-581061f2801d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3569,
|
||||
"height": 5353,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "Dn48lk8FyMk",
|
||||
"author": "Wenhao Ryan",
|
||||
"description": "夜晚的城市,摩天大楼灯火通明",
|
||||
"color": "#404059"
|
||||
},
|
||||
{
|
||||
"id": 676,
|
||||
"thumb": "https://images.unsplash.com/photo-1696317425062-6c7454c1808a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696317425062-6c7454c1808a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4000,
|
||||
"height": 6000,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "oHqcohDTka0",
|
||||
"author": "AXP Photography",
|
||||
"description": "瓦迪拉姆沙漠,约旦。",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 677,
|
||||
"thumb": "https://images.unsplash.com/photo-1696280787336-5abad24b7df8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1696280787336-5abad24b7df8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4770,
|
||||
"height": 2683,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "Z3LNnjtQtNU",
|
||||
"author": "Marek Piwnicki",
|
||||
"description": "“Birds"",
|
||||
"color": "#f3d98c"
|
||||
},
|
||||
{
|
||||
"id": 678,
|
||||
"thumb": "https://images.unsplash.com/photo-1692912364084-97b9ae31a8e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1692912364084-97b9ae31a8e1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6000,
|
||||
"height": 4000,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "IxqUT4zy89U",
|
||||
"author": "Ilia Bronskiy",
|
||||
"description": "一座山倒映在平静的湖水中",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 679,
|
||||
"thumb": "https://images.unsplash.com/photo-1691871095969-bae4e5ff8640?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1691871095969-bae4e5ff8640?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY4NjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5435,
|
||||
"height": 8153,
|
||||
"created_time": "2023-10-05T00:28:20.000Z",
|
||||
"updated_time": "2023-10-05T00:28:20.000Z",
|
||||
"category": 35,
|
||||
"original": "QgdIt34lXNA",
|
||||
"author": "Mauro Lima",
|
||||
"description": "站在一幢大楼前的人",
|
||||
"color": "#c08c73"
|
||||
},
|
||||
{
|
||||
"id": 680,
|
||||
"thumb": "https://images.unsplash.com/photo-1695918433515-2d6be66c02c1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695918433515-2d6be66c02c1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5801,
|
||||
"height": 3867,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "MoKOZql7cpE",
|
||||
"author": "Adam Davis",
|
||||
"description": "一个男人站在两块独木舟旁边的岩石上",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 681,
|
||||
"thumb": "https://plus.unsplash.com/premium_photo-1695930107980-efac202e0345?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://plus.unsplash.com/premium_photo-1695930107980-efac202e0345?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3543,
|
||||
"height": 5314,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "K1v6UqQOQnw",
|
||||
"author": "laura adai",
|
||||
"description": "去五岛度假",
|
||||
"color": "#f38c73"
|
||||
},
|
||||
{
|
||||
"id": 682,
|
||||
"thumb": "https://images.unsplash.com/photo-1681835108931-aea72262dd5c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1681835108931-aea72262dd5c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5202,
|
||||
"height": 3716,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "CMVHlKRLMGI",
|
||||
"author": "Stas Ostrikov",
|
||||
"description": "一个女孩在海上的波浪上游泳",
|
||||
"color": "#f3f3f3"
|
||||
},
|
||||
{
|
||||
"id": 683,
|
||||
"thumb": "https://images.unsplash.com/photo-1695153374208-1b8382bd6388?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1695153374208-1b8382bd6388?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5472,
|
||||
"height": 3648,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "GsnB-RKgWT8",
|
||||
"author": "Tim Oun",
|
||||
"description": "在Aiguille du Midi的登山运动员",
|
||||
"color": "#d9d9d9"
|
||||
},
|
||||
{
|
||||
"id": 684,
|
||||
"thumb": "https://images.unsplash.com/photo-1671616215399-1dd96cae9917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1671616215399-1dd96cae9917?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 5239,
|
||||
"height": 3889,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "wAnb_CyK-1Y",
|
||||
"author": "Vincenzo De Simone",
|
||||
"description": "几幢相邻的建筑",
|
||||
"color": "#f3d9c0"
|
||||
},
|
||||
{
|
||||
"id": 685,
|
||||
"thumb": "https://images.unsplash.com/photo-1675440941747-3edab9ae2b4a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1675440941747-3edab9ae2b4a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3690,
|
||||
"height": 4612,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "GkoQKCa8NF4",
|
||||
"author": "Jovan Vasiljevi",
|
||||
"description": "一个年轻人蹲着,小心翼翼地开枪;被华丽、郁郁葱葱的大自然包围|| Photo by: Jovan Vasiljevi;模特:Jovan Vasiljevi(自画像)",
|
||||
"color": "#26260c"
|
||||
},
|
||||
{
|
||||
"id": 686,
|
||||
"thumb": "https://images.unsplash.com/photo-1689457362806-af3a973a3c45?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1689457362806-af3a973a3c45?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 6240,
|
||||
"height": 4160,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "sn7aS4DD9Ro",
|
||||
"author": "Jovan Vasiljevi",
|
||||
"description": "阿马尔菲海岸:Jovan Vasiljevi",
|
||||
"color": "#26260c"
|
||||
},
|
||||
{
|
||||
"id": 687,
|
||||
"thumb": "https://images.unsplash.com/photo-1690070416537-fb5e0aab54c0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1690070416537-fb5e0aab54c0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 4160,
|
||||
"height": 5200,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "pzeFjX6HoWY",
|
||||
"author": "Jovan Vasiljevi",
|
||||
"description": "Jovan Vasiljevi拿着相机站在庞贝遗址(意大利)庞贝是意大利南部坎帕尼亚地区的一个巨大的考古遗址,靠近那不勒斯湾的海岸。庞贝曾经是一个繁荣而精致的罗马城市,在公元79年维苏威火山灾难性爆发后,庞贝被埋在几米厚的火山灰和浮石之下。保存完好的遗址以挖掘出来的街道和房屋废墟为特色,游客可以自由探索。",
|
||||
"color": "#735940"
|
||||
},
|
||||
{
|
||||
"id": 688,
|
||||
"thumb": "https://images.unsplash.com/photo-1670382393921-516cfd9f3119?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1670382393921-516cfd9f3119?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0MzY5MjZ8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 3707,
|
||||
"height": 5479,
|
||||
"created_time": "2023-10-05T00:28:46.000Z",
|
||||
"updated_time": "2023-10-05T00:28:46.000Z",
|
||||
"category": 35,
|
||||
"original": "bHiCWmbQL8E",
|
||||
"author": "Mauro Lima",
|
||||
"description": "一座城市的钟楼",
|
||||
"color": "#d9d9f3"
|
||||
},
|
||||
{
|
||||
"id": 689,
|
||||
"thumb": "https://images.unsplash.com/photo-1670469628385-21e0515dc946?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0ODE1OTB8&ixlib=rb-4.0.3&q=80&w=200",
|
||||
"url": "https://images.unsplash.com/photo-1670469628385-21e0515dc946?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMjA3fDB8MXx0b3BpY3x8RnpvM3p1T0hONnd8fHx8fDJ8fDE2OTY0ODE1OTB8&ixlib=rb-4.0.3&q=80&w=400",
|
||||
"width": 2695,
|
||||
"height": 4043,
|
||||
"created_time": "2023-10-05T12:53:07.000Z",
|
||||
"updated_time": "2023-10-05T12:53:07.000Z",
|
||||
"category": 35,
|
||||
"original": "Z4mZYFeTxLY",
|
||||
"author": "Mauro Lima",
|
||||
"description": "人们在等餐车",
|
||||
"color": "#260c0c"
|
||||
}
|
||||
]
|
41
service/src/mock/materials/png.json
Normal file
41
service/src/mock/materials/png.json
Normal file
@ -0,0 +1,41 @@
|
||||
[
|
||||
{
|
||||
"id": 886,
|
||||
"title": "卡通-计划便利贴元素",
|
||||
"width": 800,
|
||||
"height": 800,
|
||||
"type": "image",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96dddd9c307b7e95c2db6.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96dddd9c307b7e95c2db6.png",
|
||||
"created_time": "2023-08-20T21:46:13.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 885,
|
||||
"title": "卡通-计划便利贴元素",
|
||||
"width": 800,
|
||||
"height": 800,
|
||||
"type": "image",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96df2d9c307b7e95c8109.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96df2d9c307b7e95c8109.png",
|
||||
"created_time": "2023-08-20T21:46:12.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 882,
|
||||
"title": "卡通-计划便利贴元素",
|
||||
"width": 800,
|
||||
"height": 800,
|
||||
"type": "image",
|
||||
"model": "{}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96e05d9c307b7e95cc86f.png",
|
||||
"url": "https://pic.imgdb.cn/item/66b96e05d9c307b7e95cc86f.png",
|
||||
"created_time": "2023-08-20T21:46:07.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
}
|
||||
]
|
41
service/src/mock/materials/svg.json
Normal file
41
service/src/mock/materials/svg.json
Normal file
@ -0,0 +1,41 @@
|
||||
[
|
||||
{
|
||||
"id": 996,
|
||||
"title": "SVG-基础形状-多边形",
|
||||
"width": 747.9,
|
||||
"height": 747.9,
|
||||
"type": "svg",
|
||||
"model": "{\"colors\":[\"#B59683\"]}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b96ee7d9c307b7e9604257.png",
|
||||
"url": "<svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"图层 1\" viewBox=\"0 0 747.9 747.9\" preserveAspectRatio=\"none\"><path d=\"M747.8 373.9c0 30.9-60.2 53.5-67.8 82s32.7 79.2 17.8 105-78.6 15.7-99.9 37-10.8 84.7-37 99.9-75.5-25.7-105-17.8-51.1 67.8-82 67.8-53.5-60.2-82-67.8-79.2 32.7-105 17.8-15.7-78.6-37-99.9-84.7-10.8-99.9-37 25.7-75.5 17.8-105S0 404.8 0 373.9s60.2-53.5 67.8-82-32.7-79.2-17.8-105 78.6-15.7 99.9-37 10.8-84.7 37-99.9 75.5 25.7 105 17.8S343 0 373.9 0s53.5 60.2 82 67.8 79.2-32.7 105-17.8 15.7 78.6 37 99.9 84.7 10.8 99.9 37-25.7 75.5-17.8 105 67.8 51.1 67.8 82z\" fill=\"{{colors[0]}}\"/></svg>",
|
||||
"created_time": "2023-08-20T21:51:23.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 994,
|
||||
"title": "SVG-基础形状-三角形",
|
||||
"width": 771.2,
|
||||
"height": 682.2,
|
||||
"type": "svg",
|
||||
"model": "{\"colors\":[\"#F3CFD3\"]}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b97267d9c307b7e962f070.png",
|
||||
"url": "<svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"图层 1\" viewBox=\"0 0 771.2 682.2\" preserveAspectRatio=\"none\"><path d=\"M338.9 27L7.3 601.3c-20.7 35.9 5.2 80.9 46.8 80.9h663.1c41.5 0 67.5-45 46.7-80.9L432.3 27c-20.7-36-72.6-36-93.4 0z\" fill=\"{{colors[0]}}\"/></svg>",
|
||||
"created_time": "2023-08-20T21:51:21.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"id": 995,
|
||||
"title": "装饰图形圆形条",
|
||||
"width": 798.92,
|
||||
"height": 161,
|
||||
"type": "svg",
|
||||
"model": "{\"colors\":[\"#b8a8ffff\"]}",
|
||||
"thumb": "https://pic.imgdb.cn/item/66b9727dd9c307b7e96303ae.png",
|
||||
"url": "<svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"图层 1\" viewBox=\"0 0 1052.3 212.87\"><path d=\"M945.86 0H106.43a106.44 106.44 0 0 0 0 212.87h839.43a106.44 106.44 0 1 0 0-212.87z\" fill=\"{{colors[0]}}\"/></svg>",
|
||||
"created_time": "2023-08-20T21:51:21.000Z",
|
||||
"updated_time": "2023-09-15T11:42:14.000Z",
|
||||
"state": 1
|
||||
}
|
||||
]
|
4
service/src/mock/templates/list.json
Normal file
4
service/src/mock/templates/list.json
Normal file
@ -0,0 +1,4 @@
|
||||
[
|
||||
{ "id": 1, "cover": "https://pic.imgdb.cn/item/66b93ff9d9c307b7e92cbb2b.jpg", "title": "示例模板1", "width": 1242, "height": 2208, "state": 1 },
|
||||
{ "id": 2, "cover": "https://pic.imgdb.cn/item/66b93f95d9c307b7e92c86aa.webp", "title": "示例模板2", "width": 1242, "height": 2208, "state": 1 }
|
||||
]
|
1
service/src/mock/templates/poster1.json
Normal file
1
service/src/mock/templates/poster1.json
Normal file
File diff suppressed because one or more lines are too long
1
service/src/mock/templates/poster2.json
Normal file
1
service/src/mock/templates/poster2.json
Normal file
File diff suppressed because one or more lines are too long
111
service/src/service/design.ts
Normal file
111
service/src/service/design.ts
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-05-16 18:25:10
|
||||
* @Description: 示例代码,仅供参考
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 16:05:33
|
||||
*/
|
||||
import { Request, Response } from 'express'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const axios = require('../utils/http.ts')
|
||||
const multiparty = require('multiparty')
|
||||
const { filePath } = require('../configs.ts')
|
||||
const { checkCreateFolder, randomCode, send } = require('../utils/tools.ts')
|
||||
|
||||
const FileUrl = 'http://localhost:7001/static/'
|
||||
|
||||
module.exports = {
|
||||
// design/list 获取模板列表(虚拟)
|
||||
async getTemplates(req: any, res: Response) {
|
||||
/**
|
||||
* @api {get} /design/list 获取模板列表(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup design
|
||||
*/
|
||||
const { cate, type } = req.query
|
||||
const tempPath = type == 1 ? `../mock/components/list/${cate}.json` : '../mock/templates/list.json'
|
||||
try {
|
||||
const list = fs.readFileSync(path.resolve(__dirname, tempPath), 'utf8')
|
||||
send.success(res, { list: JSON.parse(list) })
|
||||
} catch (error) {}
|
||||
},
|
||||
// design/temp 获取模板(虚拟)
|
||||
async getDetail(req: any, res: Response) {
|
||||
/**
|
||||
* @api {get} /design/list 获取模板(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup design
|
||||
*/
|
||||
const { cate, type, id } = req.query
|
||||
const dPath = type == 1 ? `../mock/components/detail/${id}.json` : `../mock/templates/poster${id}.json`
|
||||
try {
|
||||
const detail = fs.readFileSync(path.resolve(__dirname, dPath), 'utf8')
|
||||
send.success(res, JSON.parse(detail))
|
||||
} catch (error) {}
|
||||
},
|
||||
// design/material 获取素材(虚拟)
|
||||
async getMaterial(req: any, res: any) {
|
||||
/**
|
||||
* @api {get} /design/material 获取素材(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup design
|
||||
*/
|
||||
const { cate } = req.query
|
||||
try {
|
||||
const detail = fs.readFileSync(path.resolve(__dirname, `../mock/materials/${cate}.json`), 'utf8')
|
||||
send.success(res, { list: JSON.parse(detail) })
|
||||
} catch (error) {}
|
||||
},
|
||||
// design/imgs 获取照片素材(虚拟)
|
||||
async getPhotos(req: any, res: any) {
|
||||
/**
|
||||
* @api {get} /design/imgs 获取照片素材(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup design
|
||||
*/
|
||||
const { cate } = req.query
|
||||
try {
|
||||
const detail = fs.readFileSync(path.resolve(__dirname, `../mock/materials/photos/${cate}.json`), 'utf8')
|
||||
send.success(res, { list: JSON.parse(detail) })
|
||||
} catch (error) {}
|
||||
},
|
||||
// design/edit 保存模板(虚拟)
|
||||
async saveTemplate(req: any, res: any) {
|
||||
/**
|
||||
* @api {post} /design/edit 保存模板(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup design
|
||||
*/
|
||||
let { id, title, data, width, height, type, cate, tag } = req.body
|
||||
try {
|
||||
const isAdd = !id // 是否新增模板
|
||||
id = id || randomCode(8)
|
||||
const savePath = path.resolve(__dirname, `../mock/templates/poster${id}.json`)
|
||||
const jsonData = {
|
||||
id,
|
||||
data,
|
||||
title,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
fs.writeFileSync(savePath, JSON.stringify(jsonData))
|
||||
// 生成封面
|
||||
const size = width > height ? 640 : 320
|
||||
const fetchScreenshotUrl = `http://localhost:7001/api/screenshots?tempid=${id}&tempType=${type}&width=${width}&height=${height}&type=cover&size=${size}&quality=75`
|
||||
await axios.get(fetchScreenshotUrl, { responseType: 'arraybuffer' })
|
||||
// 保存到其他地方可以设置 responseType: 'arraybuffer' 后操作buffer,这里只为了得到封面,发起请求就可以了
|
||||
if (isAdd) {
|
||||
const listVal = fs.readFileSync(path.resolve(__dirname, `../mock/templates/list.json`), 'utf8')
|
||||
const list = JSON.parse(listVal)
|
||||
list.unshift({ id, cover: FileUrl + `/${id}-cover.jpg`, title, width, height })
|
||||
fs.writeFileSync(path.resolve(__dirname, `../mock/templates/list.json`), JSON.stringify(list))
|
||||
}
|
||||
send.success(res, { id })
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export {}
|
60
service/src/service/files.ts
Normal file
60
service/src/service/files.ts
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-05-16 18:25:10
|
||||
* @Description: 文件操作示例代码,仅供参考
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 18:52:18
|
||||
*/
|
||||
import { Request, Response } from 'express'
|
||||
const multiparty = require('multiparty')
|
||||
const { filePath } = require('../configs.ts')
|
||||
const { checkCreateFolder, randomCode, copyFile, send } = require('../utils/tools.ts')
|
||||
|
||||
const FileUrl = 'http://localhost:7001/static/'
|
||||
|
||||
module.exports = {
|
||||
// api/file/upload 上传接口
|
||||
async upload(req: Request, res: Response) {
|
||||
/**
|
||||
* @api {post} /api/file/upload 上传接口
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup file
|
||||
*
|
||||
* @apiParam {File} file 二进制文件
|
||||
* @apiParam {String} folder 目标文件夹,空为根目录
|
||||
* @apiParam {String} name 文件名,默认随机
|
||||
*
|
||||
* @apiSuccess (__组__) {__类型__} __字段名__ __返回字段说明__
|
||||
*/
|
||||
const form = new multiparty.Form()
|
||||
form.parse(req, async function (err: any, fields: any, files: any) {
|
||||
if (err) {
|
||||
console.error('上传文件出错!')
|
||||
return
|
||||
}
|
||||
if (files) {
|
||||
const file = files.file ? files.file[0] : {}
|
||||
const { size, headers, originalFilename } = file
|
||||
const fileType = headers['content-type'].split('/')[1]
|
||||
const Suffix = originalFilename.split('.').pop() || fileType || 'png'
|
||||
const { folder = '', name = `${randomCode(12)}.${Suffix}` } = fields
|
||||
const folderPath = `${filePath}${folder ? `${folder}/` : ''}`
|
||||
checkCreateFolder(folderPath) // 检测对应目录是否存在
|
||||
const targetPath = `${folderPath}${name}`
|
||||
copyFile(file.path, targetPath)
|
||||
.then(() => {
|
||||
const url = `${FileUrl}${folder ? folder + '/' : ''}${name}`
|
||||
send.success(res, {
|
||||
key: `${folder}/${name}`,
|
||||
url,
|
||||
})
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.log('上传异常', err)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export {}
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2020-07-22 20:13:14
|
||||
* @Description:
|
||||
* @Description: 服务端截图
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 15:43:29
|
||||
* @LastEditTime: 2024-08-12 11:03:07
|
||||
*/
|
||||
const { saveScreenshot } = require('../utils/download-single.ts')
|
||||
const uuid = require('../utils/uuid.ts')
|
||||
@ -13,33 +13,6 @@ const { queueRun, queueList } = require('../utils/node-queue.ts')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = {
|
||||
async getImg(req: any, res: any) {
|
||||
/**
|
||||
* @api {get} api/get_img 获取图片
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup screenShot
|
||||
*
|
||||
* @apiParam {String|Number} id (必传) 截图id
|
||||
* @apiParam {String} type 可选, file源文件,cover封面图
|
||||
*/
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
let { id, type = 'file' } = req.query
|
||||
const path = filePath + `${id}-screenshot.png`
|
||||
const thumbPath = type === 'cover' ? filePath + `${id}-cover.jpg` : null
|
||||
|
||||
if (id) {
|
||||
try {
|
||||
fs.statSync(path)
|
||||
res.setHeader('Content-Type', 'image/jpg')
|
||||
type === 'file' ? res.sendFile(path) : res.sendFile(thumbPath)
|
||||
} catch (error) {
|
||||
res.json({ code: 500, msg: '请求图片不存在' })
|
||||
}
|
||||
} else {
|
||||
res.json({ code: 500, msg: '缺少参数,请检查' })
|
||||
}
|
||||
},
|
||||
async screenshots(req: any, res: any) {
|
||||
/**
|
||||
* @api {get} api/screenshots 截图
|
||||
@ -58,6 +31,7 @@ module.exports = {
|
||||
* @apiParam {String|Number} index 可选, 下载哪个画板
|
||||
*/
|
||||
let { id, tempid, tempType, width, height, screenshot_url, type = 'file', size, quality, index = 0 } = req.query
|
||||
id == 'undefined' && (id = null)
|
||||
const url = (screenshot_url || drawLink) + `${id ? '?id=' : '?tempid='}`
|
||||
id = id || tempid
|
||||
const path = filePath + `${id}-screenshot.png`
|
||||
@ -68,7 +42,7 @@ module.exports = {
|
||||
res.json({ code: 200, msg: '服务器表示顶不住啊,等等再来吧~' })
|
||||
return
|
||||
}
|
||||
const targetUrl = url + id + `${tempType?'&tempType='+tempType:''}` + `&index=${index}`
|
||||
const targetUrl = url + id + `${tempType ? '&tempType=' + tempType : ''}` + `&index=${index}`
|
||||
queueRun(saveScreenshot, targetUrl, { width, height, path, thumbPath, size, quality })
|
||||
.then(() => {
|
||||
res.setHeader('Content-Type', 'image/jpg')
|
28
service/src/service/user.ts
Normal file
28
service/src/service/user.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-05-16 18:25:10
|
||||
* @Description: 示例代码,仅供参考
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 06:25:23
|
||||
*/
|
||||
import { Request, Response } from 'express'
|
||||
const multiparty = require('multiparty')
|
||||
const { filePath } = require('../configs.ts')
|
||||
const { checkCreateFolder, filesReader, send } = require('../utils/tools.ts')
|
||||
|
||||
const FileUrl = 'http://localhost:7001/static/'
|
||||
|
||||
module.exports = {
|
||||
// design/user/image 获取用户上传列表(虚拟)
|
||||
async getUserImages(req: Request, res: Response) {
|
||||
/**
|
||||
* @api {post} /design/user/image 获取用户上传列表(虚拟)
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup user
|
||||
*/
|
||||
const list = await filesReader('user')
|
||||
send.success(res, { list })
|
||||
},
|
||||
}
|
||||
|
||||
export {}
|
78
service/src/utils/fs.ts
Normal file
78
service/src/utils/fs.ts
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-05-28 17:10:51
|
||||
* @Description: 文件操作相关方法
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 06:29:58
|
||||
*/
|
||||
import fs from 'fs'
|
||||
const path = require('path')
|
||||
const imageSize = require('image-size')
|
||||
const { filePath: StaticPath } = require('../configs.ts')
|
||||
const FileUrl = 'http://localhost:7001/static/'
|
||||
|
||||
module.exports = {
|
||||
copyFile(sourceFile: string, destinationFile: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const readStream = fs.createReadStream(sourceFile)
|
||||
const writeStream = fs.createWriteStream(destinationFile)
|
||||
|
||||
readStream.on('error', (err: any) => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
writeStream.on('error', (err: any) => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
writeStream.on('finish', () => {
|
||||
resolve()
|
||||
})
|
||||
|
||||
readStream.pipe(writeStream)
|
||||
})
|
||||
},
|
||||
// 读取目录
|
||||
filesReader(directoryPath: string) {
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
const files = fs.readdirSync(StaticPath + directoryPath)
|
||||
const filesArray: any = []
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(directoryPath, file)
|
||||
// const stats = fs.statSync(filePath);
|
||||
const { width, height } = imageSize(StaticPath + filePath)
|
||||
if (file !== '.DS_Store') {
|
||||
const fileInfo = {
|
||||
width,
|
||||
height,
|
||||
// filename: file,
|
||||
// link: FileUrl + directoryPath,
|
||||
url: `${FileUrl + directoryPath}/${file}`,
|
||||
// filepath: StaticPath + filePath
|
||||
// size: stats.size, // 文件大小
|
||||
// modified: stats.mtime // 最后修改时间
|
||||
}
|
||||
filesArray.push(fileInfo)
|
||||
}
|
||||
})
|
||||
// JSON.stringify(filesArray, null, 2)
|
||||
resolve(filesArray)
|
||||
} catch (err) {
|
||||
console.error('Error reading directory:', err)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 读取文件
|
||||
readFile(directoryPath: string) {
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
resolve(fs.readFileSync(StaticPath + directoryPath, 'utf8'))
|
||||
} catch (err) {
|
||||
console.error('Error reading file:', err)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export {}
|
19
service/src/utils/http.ts
Normal file
19
service/src/utils/http.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2022-01-25 17:02:02
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 13:59:34
|
||||
*/
|
||||
const axios = require('axios')
|
||||
|
||||
const httpRequest = axios.create({
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
})
|
||||
|
||||
httpRequest.interceptors.response.use((config: any) => {
|
||||
return config.data
|
||||
})
|
||||
|
||||
module.exports = httpRequest
|
84
service/src/utils/tools.ts
Normal file
84
service/src/utils/tools.ts
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2024-05-11 02:26:55
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 13:48:40
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const fsFunc = require('./fs.ts')
|
||||
|
||||
module.exports = {
|
||||
send: {
|
||||
success: (res: any, result: any, msg: string = 'ok') => {
|
||||
res.json({
|
||||
code: 200,
|
||||
msg,
|
||||
result: result || undefined,
|
||||
})
|
||||
},
|
||||
error: (res: any, msg: string = 'error') => {
|
||||
res.json({
|
||||
code: 400,
|
||||
msg,
|
||||
})
|
||||
},
|
||||
},
|
||||
isNumber: (value: any) => {
|
||||
return typeof value === 'number' && !isNaN(value)
|
||||
},
|
||||
buildTree: (data: any[]) => {},
|
||||
groupBy: (array: any[], property: any) => {},
|
||||
// 检测目录并创建目录(支持深层级)
|
||||
checkCreateFolder: (folder: string) => {
|
||||
try {
|
||||
const pathArr = splitPath(folder)
|
||||
let _path = ''
|
||||
for (let i = 0; i < pathArr.length; i++) {
|
||||
if (pathArr[i]) {
|
||||
_path += `/${pathArr[i]}`
|
||||
!fs.existsSync(_path) && fs.mkdirSync(_path)
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
// 检测文件
|
||||
checkCreateFile: (filePath: string) => {
|
||||
try {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
fs.writeFileSync(filePath, '')
|
||||
}
|
||||
} catch (e) {
|
||||
fs.writeFileSync(filePath, '')
|
||||
}
|
||||
},
|
||||
// 生成随机码
|
||||
randomCode: (length = 5) => {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
let result = ''
|
||||
for (let i = 0; i < length; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * chars.length)
|
||||
result += chars[randomIndex]
|
||||
}
|
||||
return result
|
||||
},
|
||||
// 取数组差集
|
||||
findDifference: (a: any, b: any) => {
|
||||
return a.concat(b).filter((v: any) => !a.includes(v) || !b.includes(v))
|
||||
},
|
||||
...fsFunc,
|
||||
}
|
||||
|
||||
/**
|
||||
* 将路径切割为数组
|
||||
* @param dirPath
|
||||
* @returns Array
|
||||
*/
|
||||
function splitPath(dirPath: string) {
|
||||
const normalizedPath = path.normalize(dirPath)
|
||||
const separator = path.sep
|
||||
return normalizedPath.split(separator)
|
||||
}
|
||||
|
||||
export {}
|
2190
service/yarn.lock
Normal file
2190
service/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,10 @@
|
||||
* @Date: 2021-08-27 14:42:15
|
||||
* @Description: 媒体相关接口
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-12-11 11:40:47
|
||||
* @LastEditTime: 2024-08-11 19:27:41
|
||||
*/
|
||||
import fetch from '@/utils/axios'
|
||||
import _config from '@/config'
|
||||
import { IGetTempListData } from './home'
|
||||
|
||||
// 获取素材分类:
|
||||
@ -130,3 +131,20 @@ type TAddMyPhotoParam = {
|
||||
|
||||
// 添加图片
|
||||
export const addMyPhoto = (params: TAddMyPhotoParam) => fetch<void>('design/user/add_image', params)
|
||||
|
||||
// 上传接口
|
||||
export const upload = ({ file, folder = 'user' }: any, cb: Function) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('folder', folder)
|
||||
const extra = {
|
||||
responseType: 'application/json',
|
||||
onUploadProgress: (progress: any) => {
|
||||
cb(Math.floor((progress.loaded / progress.total) * 100), 0)
|
||||
},
|
||||
onDownloadProgress: (progress: any) => {
|
||||
cb(100, Math.floor((progress.loaded / progress.total) * 100))
|
||||
},
|
||||
}
|
||||
return fetch(`${_config.SCREEN_URL}/api/file/upload`, formData, 'post', {}, extra)
|
||||
}
|
@ -8,11 +8,16 @@
|
||||
@height2: 54px;
|
||||
|
||||
@canvasBG: #f8f8f8;
|
||||
@pageBG: #f0f2f5;
|
||||
@canvasDeepBG: #000;
|
||||
|
||||
.page-design-bg-color {
|
||||
// background-color: #4b678c;
|
||||
// background-color: #4682b4;
|
||||
background-color: @canvasDeepBG;
|
||||
}
|
||||
.page-bg-color {
|
||||
background-color: @pageBG;
|
||||
}
|
||||
|
||||
#page-design-index {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -2,52 +2,28 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-09-30 15:52:59
|
||||
* @Description: 下载远程图片
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-02 11:50:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 17:01:59
|
||||
*/
|
||||
|
||||
type TCallBack = (progress: number, xhr: XMLHttpRequest) => void
|
||||
|
||||
export default (src: string, cb: TCallBack) => {
|
||||
export default (src: string, cb: TCallBack, fileName?: string) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
// const image = new Image()
|
||||
// // 解决跨域 Canvas 污染问题
|
||||
// image.setAttribute('crossOrigin', 'anonymous')
|
||||
// image.onload = function() {
|
||||
// const 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)
|
||||
// const url = canvas.toDataURL('image/jpg')
|
||||
|
||||
// const a = document.createElement('a')
|
||||
// const event = new MouseEvent('click')
|
||||
|
||||
// a.download = String(new Date().getTime())
|
||||
// a.href = url
|
||||
|
||||
// // 触发a的单击事件
|
||||
// a.dispatchEvent(event)
|
||||
// resolve()
|
||||
// }
|
||||
|
||||
fetchImageDataFromUrl(src, (progress: number, xhr: XMLHttpRequest) => {
|
||||
cb(progress, xhr)
|
||||
}).then((res) => {
|
||||
}).then((res: any) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = function (event) {
|
||||
const txt = event?.target?.result as string
|
||||
// image.src = txt
|
||||
const a = document.createElement('a')
|
||||
const mE = new MouseEvent('click')
|
||||
// TODO: 部分浏览器会丢失后缀,所以补上
|
||||
a.download = String(new Date().getTime()) + '.png'
|
||||
a.href = txt
|
||||
const suffix = res.type ? res.type.split('/')[1] : 'png'
|
||||
const randomName = String(new Date().getTime()) + `.${suffix || 'png'}`
|
||||
a.download = fileName || randomName
|
||||
a.href = event?.target?.result as string
|
||||
// 触发a的单击事件
|
||||
a.dispatchEvent(mE)
|
||||
resolve()
|
||||
resolve(res)
|
||||
}
|
||||
if (!res) {
|
||||
resolve()
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-01-08 09:43:37
|
||||
* @Description: 字体处理
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-10-13 01:30:33
|
||||
* @LastEditTime: 2024-08-12 10:33:36
|
||||
*/
|
||||
// import { isSupportFontFamily, blob2Base64 } from './utils'
|
||||
import { TGetFontItemData, getFonts } from '@/api/material'
|
||||
@ -11,7 +11,7 @@ import { TGetFontItemData, getFonts } from '@/api/material'
|
||||
const nowVersion = '2' // 当前字体文件版本更新,将刷新前端缓存
|
||||
|
||||
/** 字体item类型 */
|
||||
export type TFontItemData = { url: string } & Omit<TGetFontItemData, "woff">
|
||||
export type TFontItemData = { url: string } & Omit<TGetFontItemData, 'woff'>
|
||||
|
||||
const fontList: TFontItemData[] = []
|
||||
// const download: any = {}
|
||||
@ -27,11 +27,27 @@ export const useFontStore = {
|
||||
}
|
||||
|
||||
if (this.list.length === 0) {
|
||||
const res = await getFonts({ pageSize: 400 })
|
||||
// TODO: 模拟
|
||||
const res = {
|
||||
list: [
|
||||
{
|
||||
id: 543,
|
||||
alias: '站酷快乐体',
|
||||
preview: '',
|
||||
ttf: null,
|
||||
woff: 'https://lib.baomitu.com/fonts/zcool-kuaile/zcool-kuaile-regular.woff2',
|
||||
value: 'zcool-kuaile-regular',
|
||||
font_family: '',
|
||||
size: 0,
|
||||
lang: 'zh',
|
||||
woff_size: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
this.list.unshift(
|
||||
...res.list.map((x) => {
|
||||
const { id, alias, oid, value, preview, woff, lang } = x
|
||||
return { id, oid, value, preview, alias, url: woff, lang }
|
||||
const { id, alias, value, preview, woff, lang } = x
|
||||
return { id, oid: 0, value, preview, alias, url: woff, lang }
|
||||
}),
|
||||
)
|
||||
localStorage.setItem('FONTS', JSON.stringify(this.list))
|
||||
|
@ -6,13 +6,14 @@
|
||||
* @Date: 2024-03-03 19:00:00
|
||||
-->
|
||||
<template>
|
||||
<el-dialog v-model="state.show" title="AI 智能抠图" align-center width="650" @close="handleClose">
|
||||
<el-dialog v-model="state.show" title="AI 抠图(模拟演示)" align-center width="650" @close="handleClose">
|
||||
<uploader v-if="!state.rawImage" :hold="true" :drag="true" :multiple="true" class="uploader" @load="handleUploaderLoad">
|
||||
<div class="uploader__box">
|
||||
<upload-filled style="width: 64px; height: 64px" />
|
||||
<div class="el-upload__text">在此拖入或选择<em>上传图片</em></div>
|
||||
<!-- <div class="el-upload__text">在此拖入或选择<em>上传图片</em></div> -->
|
||||
<div class="el-upload__text">自动抠图目前依赖后端服务,需自行部署</div>
|
||||
</div>
|
||||
<div class="el-upload__tip">服务器带宽小,为了更好的体验,请上传 2M 内的图片</div>
|
||||
<div class="el-upload__tip el-upload__text"><em>体验前端效果演示以及修补编辑器,随便上传一张图片即可触发</em></div>
|
||||
</uploader>
|
||||
<el-progress v-if="!state.cutImage && state.progressText" :percentage="state.progress">
|
||||
<el-button text>
|
||||
@ -104,7 +105,8 @@ defineExpose({
|
||||
const handleUploaderLoad = (file: File) => {
|
||||
selectImageFile(state as TImageCutoutState, raw, file, (result, name) => {
|
||||
fileName = name
|
||||
const resultImage = URL.createObjectURL(result)
|
||||
// TODO: 模拟演示
|
||||
const resultImage = 'https://pic.imgdb.cn/item/6522253ec458853aefb0b013.webp' // URL.createObjectURL(result)
|
||||
state.rawImage && (state.cutImage = resultImage)
|
||||
requestAnimationFrame(run)
|
||||
})
|
||||
|
@ -2,51 +2,47 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-03 19:00:00
|
||||
* @Description: 裁剪组件公共方法
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @Date: 2024-03-03 19:00:00
|
||||
*/
|
||||
|
||||
import Qiniu from '@/common/methods/QiNiu'
|
||||
import { TCommonUploadCb, TUploadErrorResult } from "@/api/ai"
|
||||
import { TImageCutoutState } from "./index.vue"
|
||||
import api from "@/api"
|
||||
import { TCommonUploadCb, TUploadErrorResult } from '@/api/ai'
|
||||
import { TImageCutoutState } from './index.vue'
|
||||
import api from '@/api'
|
||||
import { getImage } from '@/common/methods/getImgDetail'
|
||||
import _config from '@/config'
|
||||
import { Ref } from 'vue'
|
||||
|
||||
/** 选择图片 */
|
||||
export const selectImageFile = async (
|
||||
state: TImageCutoutState,
|
||||
raw: Ref<HTMLElement | null>,
|
||||
file: File,
|
||||
successCb?: (result: MediaSource, fileName: string) => void,
|
||||
uploadCb?: TCommonUploadCb,
|
||||
) => {
|
||||
if (file.size > 1024 * 1024 * 2) {
|
||||
alert('上传图片超出限制')
|
||||
return false
|
||||
}
|
||||
export const selectImageFile = async (state: TImageCutoutState, raw: Ref<HTMLElement | null>, file: File, successCb?: (result: MediaSource, fileName: string) => void, uploadCb?: TCommonUploadCb) => {
|
||||
// if (file.size > 1024 * 1024 * 2) {
|
||||
// alert('上传图片超出限制')
|
||||
// return false
|
||||
// }
|
||||
if (!raw.value) return
|
||||
// 显示选择的图片
|
||||
raw.value.addEventListener('load', () => {
|
||||
state.offsetWidth = (raw.value as HTMLElement).offsetWidth
|
||||
})
|
||||
state.rawImage = URL.createObjectURL(file)
|
||||
// TODO: 模拟演示
|
||||
state.rawImage = 'https://pic.imgdb.cn/item/65222530c458853aefb0adeb.webp' // URL.createObjectURL(file)
|
||||
|
||||
// 返回抠图结果
|
||||
const result = await api.ai.upload(file, (up: number, dp: number) => {
|
||||
uploadCb && uploadCb(up, dp)
|
||||
if (dp) {
|
||||
state.progressText = dp === 100 ? '' : '导入中..'
|
||||
state.progress = dp
|
||||
} else {
|
||||
state.progressText = up < 100 ? '上传中..' : '正在处理,请稍候..'
|
||||
state.progress = up < 100 ? up : 0
|
||||
}
|
||||
})
|
||||
if (typeof result == 'object' && (result as TUploadErrorResult).type !== 'application/json') {
|
||||
successCb && successCb(result as MediaSource, file.name)
|
||||
} else alert('服务器繁忙,请稍等下重新尝试~')
|
||||
// const result = await api.ai.upload(file, (up: number, dp: number) => {
|
||||
// uploadCb && uploadCb(up, dp)
|
||||
// if (dp) {
|
||||
// state.progressText = dp === 100 ? '' : '导入中..'
|
||||
// state.progress = dp
|
||||
// } else {
|
||||
// state.progressText = up < 100 ? '上传中..' : '正在处理,请稍候..'
|
||||
// state.progress = up < 100 ? up : 0
|
||||
// }
|
||||
// })
|
||||
// if (typeof result == 'object' && (result as TUploadErrorResult).type !== 'application/json') {
|
||||
// successCb && successCb(result as MediaSource, file.name)
|
||||
// } else alert('服务器繁忙,请稍等下重新尝试~')
|
||||
successCb('', file.name)
|
||||
}
|
||||
|
||||
export async function uploadCutPhotoToCloud(cutImage: string) {
|
||||
@ -61,7 +57,7 @@ export async function uploadCutPhotoToCloud(cutImage: string) {
|
||||
const url = _config.IMG_URL + result.key
|
||||
await api.material.addMyPhoto({ width, height, url })
|
||||
return url
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(`upload cut file error: msg: ${e}`)
|
||||
return ''
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-04 11:46:39
|
||||
* @Description: 原版movable插件
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-06 14:56:35
|
||||
* @LastEditTime: 2024-08-12 09:24:51
|
||||
-->
|
||||
<template>
|
||||
<div id="empty" class="moveable__remove-item zk-moveable-style"></div>
|
||||
@ -345,10 +345,6 @@ onMounted(() => {
|
||||
// })
|
||||
|
||||
holdPosition = null // important
|
||||
setTimeout(() => {
|
||||
historyStore.pushHistory()
|
||||
// store.dispatch("pushHistory")
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
// .on('keyUp', (e) => {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-01 11:12:17
|
||||
* @Description: 前端出图 - 用于封面
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>, Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @Date: 2024-03-04 18:50:00
|
||||
-->
|
||||
<template>
|
||||
@ -13,8 +13,9 @@
|
||||
import html2canvas from 'html2canvas'
|
||||
import Qiniu from '@/common/methods/QiNiu'
|
||||
// import { useSetupMapGetters } from '@/common/hooks/mapGetters'
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useCanvasStore, useWidgetStore } from '@/store';
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useCanvasStore, useWidgetStore } from '@/store'
|
||||
import FontFaceObserver from 'fontfaceobserver'
|
||||
|
||||
// const { dZoom } = useSetupMapGetters(['dZoom'])
|
||||
|
||||
@ -22,15 +23,14 @@ const canvasStore = useCanvasStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
const { dZoom } = storeToRefs(canvasStore)
|
||||
|
||||
|
||||
// props: ['modelValue'],
|
||||
// props: ['modelValue'],
|
||||
// emits: ['update:modelValue'],
|
||||
|
||||
async function createCover(cb: any) {
|
||||
const nowZoom = dZoom.value
|
||||
// 取消选中元素
|
||||
widgetStore.selectWidget({
|
||||
uuid: '-1'
|
||||
uuid: '-1',
|
||||
})
|
||||
// store.dispatch('selectWidget', {
|
||||
// uuid: '-1',
|
||||
@ -66,8 +66,46 @@ async function createCover(cb: any) {
|
||||
}, 10)
|
||||
}
|
||||
|
||||
async function createPoster() {
|
||||
await checkFonts() // 等待字体加载完成
|
||||
const fonts = document.fonts
|
||||
const opts = {
|
||||
backgroundColor: null, // 关闭背景以支持透明图片生成
|
||||
useCORS: true,
|
||||
scale: 100 / dZoom.value, // * window.devicePixelRatio
|
||||
onclone: (document: any) => fonts.forEach((font) => document.fonts.add(font)),
|
||||
}
|
||||
// const style = document.createElement('style')
|
||||
// document.head.appendChild(style)
|
||||
// style.sheet?.insertRule('body > img { display: initial; }')
|
||||
return new Promise((resolve) => {
|
||||
const clonePage = document.getElementById('page-design-canvas')?.cloneNode(true) as HTMLElement
|
||||
if (!clonePage) return
|
||||
clonePage.setAttribute('id', 'clone-page')
|
||||
document.body.appendChild(clonePage)
|
||||
html2canvas(clonePage, opts).then((canvas) => {
|
||||
canvas.toBlob(async (blob) => resolve({ blob }), `image/png`)
|
||||
clonePage.remove()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 检查字体是否加载完成
|
||||
async function checkFonts() {
|
||||
const widgets = widgetStore.getWidgets()
|
||||
const fontLoaders: Promise<void>[] = []
|
||||
widgets.forEach((item: any) => {
|
||||
if (item.fontClass && item.fontClass.value) {
|
||||
const loader = new FontFaceObserver(item.fontClass.value)
|
||||
fontLoaders.push(loader.load(null, 120000)) // 延长超时让检测不会丢失字体
|
||||
}
|
||||
})
|
||||
await Promise.all(fontLoaders)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
createCover
|
||||
createCover,
|
||||
createPoster,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -3,13 +3,13 @@
|
||||
* @Date: 2024-03-17 16:10:21
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-03 12:25:15
|
||||
* @LastEditTime: 2024-08-11 18:42:09
|
||||
-->
|
||||
<template>
|
||||
<div v-if="percent" v-show="!hide" class="mask">
|
||||
<div class="content">
|
||||
<div class="tool">
|
||||
<div v-show="percent < 100" class="backstage" @click="close"><iconSell width="18" /> <span style="margin-left: 0.4rem">后台下载</span></div>
|
||||
<div v-show="percent < 100" class="backstage" @click="close"><span style="margin-left: 0.4rem">后台下载</span></div>
|
||||
<iconClose v-show="percent >= 100" class="backstage" @click="cancel" width="20" />
|
||||
</div>
|
||||
<div class="text">{{ text }}</div>
|
||||
@ -26,8 +26,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch, ref } from 'vue'
|
||||
import { ElProgress } from 'element-plus'
|
||||
import { Close as iconClose, Sell as iconSell } from '@element-plus/icons-vue'
|
||||
import toolTip from '@/components/common/PopoverTip.vue'
|
||||
import { Close as iconClose } from '@element-plus/icons-vue'
|
||||
// import toolTip from '@/components/common/PopoverTip.vue'
|
||||
|
||||
type TProps = {
|
||||
percent: number
|
||||
|
@ -16,7 +16,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, nextTick, withDefaults } from 'vue'
|
||||
import { ElUpload, UploadRequestOptions } from 'element-plus'
|
||||
import Qiniu from '@/common/methods/QiNiu'
|
||||
// import Qiniu from '@/common/methods/QiNiu'
|
||||
import api from '@/api'
|
||||
import { getImage } from '@/common/methods/getImgDetail'
|
||||
import _config from '@/config'
|
||||
import useNotification from '@/common/methods/notification'
|
||||
@ -32,11 +33,11 @@ export type TUploadDoneData = {
|
||||
url: string
|
||||
}
|
||||
|
||||
type TQiNiuUploadReturn = { hash: string, key: string }
|
||||
type TQiNiuUploadReturn = { hash: string; key: string }
|
||||
|
||||
type TProps = {
|
||||
modelValue?: TModelData
|
||||
options?: { bucket: string, prePath: string }
|
||||
options?: { bucket: string; prePath: string }
|
||||
hold?: boolean
|
||||
}
|
||||
|
||||
@ -49,7 +50,7 @@ type TEmits = {
|
||||
const props = withDefaults(defineProps<TProps>(), {
|
||||
modelValue: () => ({}),
|
||||
options: () => ({ bucket: 'xp-design', prePath: 'user' }),
|
||||
hold: false
|
||||
hold: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<TEmits>()
|
||||
@ -63,15 +64,15 @@ let count: number = 0 // 当前上传总数
|
||||
|
||||
let tempSimpleRes: TQiNiuUploadReturn | null // 单个文件上传时返回
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
setTimeout(() => {
|
||||
// 加载七牛上传插件
|
||||
const link_element = document.createElement('script')
|
||||
link_element.setAttribute('src', _config.QINIUYUN_PLUGIN)
|
||||
document.head.appendChild(link_element)
|
||||
}, 1000)
|
||||
})
|
||||
// onMounted(async () => {
|
||||
// await nextTick()
|
||||
// setTimeout(() => {
|
||||
// // 加载七牛上传插件
|
||||
// const link_element = document.createElement('script')
|
||||
// link_element.setAttribute('src', _config.QINIUYUN_PLUGIN)
|
||||
// document.head.appendChild(link_element)
|
||||
// }, 1000)
|
||||
// })
|
||||
|
||||
const upload = async ({ file }: UploadRequestOptions) => {
|
||||
if (props.hold) {
|
||||
@ -93,10 +94,9 @@ const uploadQueue = async () => {
|
||||
if (file) {
|
||||
if (file.size <= 1024 * 1024) {
|
||||
tempSimpleRes = await qiNiuUpload(file) // 队列有文件,执行上传
|
||||
console.log("tempSimpleRes", tempSimpleRes)
|
||||
const { width, height } = await getImage(file)
|
||||
useNotification('上传成功', '公共测试账户,上传请注意保护隐私哦!', { position: 'bottom-left' })
|
||||
emit('done', { width, height, url: _config.IMG_URL + tempSimpleRes?.key }) // 单个文件进行响应
|
||||
useNotification('上传成功', '', { position: 'bottom-left' })
|
||||
emit('done', { width, height, url: tempSimpleRes?.url }) // 单个文件进行响应
|
||||
} else useNotification('爱护小水管', '请上传小于 1M 的图片哦!', { type: 'error', position: 'bottom-left' })
|
||||
uploading = false
|
||||
handleRemove() // 移除已上传文件
|
||||
@ -120,9 +120,12 @@ const qiNiuUpload = async (file: File): Promise<null | TQiNiuUploadReturn> => {
|
||||
emit('load', file)
|
||||
resolve(null)
|
||||
} else {
|
||||
const result = await Qiniu.upload(file, props.options, (res: Type.Object) => {
|
||||
updatePercent(res.total.percent)
|
||||
const result = await api.material.upload({ file }, (up: any, dp: any) => {
|
||||
console.log(up, dp)
|
||||
})
|
||||
// const result = await Qiniu.upload(file, props.options, (res: Type.Object) => {
|
||||
// updatePercent(res.total.percent)
|
||||
// })
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
|
@ -158,8 +158,7 @@ function changeValue() {
|
||||
function finish(key: keyof TPageState, value: string | number) {
|
||||
pageStore.updatePageData({
|
||||
key: key,
|
||||
value: value,
|
||||
pushHistory: true,
|
||||
value: value
|
||||
})
|
||||
}
|
||||
async function uploadImgDone(img: TUploadDoneData) {
|
||||
@ -174,8 +173,7 @@ async function deleteBg() {
|
||||
_localTempBG = null
|
||||
pageStore.updatePageData({
|
||||
key: 'backgroundImage',
|
||||
value: '',
|
||||
pushHistory: true,
|
||||
value: ''
|
||||
})
|
||||
await nextTick()
|
||||
state.mode = state.modes[1]
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-03-07 17:25:19
|
||||
* @Description: 图层组件
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2023-11-24 11:39:02
|
||||
* @LastEditTime: 2024-08-12 09:25:15
|
||||
-->
|
||||
<template>
|
||||
<ul class="widget-list">
|
||||
@ -141,8 +141,7 @@ export default defineComponent({
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: item.uuid,
|
||||
key: 'lock',
|
||||
value: typeof item.lock === 'undefined' ? true : !item.lock,
|
||||
pushHistory: false,
|
||||
value: typeof item.lock === 'undefined' ? true : !item.lock
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: item.uuid,
|
||||
|
@ -69,7 +69,6 @@ function alignAction(item: TIconItemSelectData) {
|
||||
group,
|
||||
})
|
||||
});
|
||||
historyStore.pushHistory()
|
||||
})
|
||||
}
|
||||
function layerChange(newLayer: TdWidgetData[]) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-27 15:16:07
|
||||
* @Description: 背景图
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-09 22:29:51
|
||||
* @LastEditTime: 2024-08-12 09:49:35
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -100,7 +100,7 @@ const load = async (init: boolean = false) => {
|
||||
pageOptions.page = 1
|
||||
}
|
||||
|
||||
await api.material.getImagesList({ cate: 16, page: pageOptions.page }).then(({ list }) => {
|
||||
await api.material.getImagesList({ cate: 3, page: pageOptions.page }).then(({ list }) => {
|
||||
if (list.length > 0) {
|
||||
state.bgList.push(...list)
|
||||
} else {
|
||||
@ -120,8 +120,7 @@ function setBGcolor(color: string) {
|
||||
})
|
||||
pageStore.updatePageData({
|
||||
key: 'backgroundColor',
|
||||
value: color,
|
||||
pushHistory: true
|
||||
value: color
|
||||
})
|
||||
widgetStore.selectWidget({
|
||||
uuid: '-1'
|
||||
@ -139,8 +138,7 @@ async function selectItem(item: TGetImageListResult) {
|
||||
})
|
||||
pageStore.updatePageData({
|
||||
key: 'backgroundImage',
|
||||
value: item.url,
|
||||
pushHistory: true,
|
||||
value: item.url
|
||||
})
|
||||
widgetStore.selectWidget({
|
||||
uuid: '-1'
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-27 15:16:07
|
||||
* @Description: 素材列表,主要用于文字组合列表
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-09 22:30:10
|
||||
* @LastEditTime: 2024-08-14 18:49:06
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -18,13 +18,7 @@
|
||||
<classHeader v-show="!state.currentCategory" :types="state.types" @select="selectTypes">
|
||||
<template v-slot="{ index }">
|
||||
<div class="list-wrap">
|
||||
<div
|
||||
v-for="(item, i) in state.showList[index]" :key="i + 'sl'"
|
||||
draggable="false"
|
||||
@mousedown="dragStart($event, item)" @mousemove="mousemove"
|
||||
@mouseup="mouseup" @click.stop="selectItem(item)"
|
||||
@dragstart="dragStart($event, item)"
|
||||
>
|
||||
<div v-for="(item, i) in state.showList[index]" :key="i + 'sl'" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)">
|
||||
<el-image class="list__img-thumb" :src="item.cover" fit="contain" lazy loading="lazy"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
@ -34,13 +28,7 @@
|
||||
<ul v-if="state.currentCategory" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
|
||||
<classHeader :is-back="true" @back="back">{{ state.currentCategory.name }}</classHeader>
|
||||
<el-space fill wrap :fillRatio="30" direction="horizontal" class="list">
|
||||
<div
|
||||
v-for="(item, i) in state.list" :key="i + 'i'"
|
||||
class="list__item" draggable="false"
|
||||
@mousedown="dragStart($event, item)" @mousemove="mousemove"
|
||||
@mouseup="mouseup" @click.stop="selectItem(item)"
|
||||
@dragstart="dragStart($event, item)"
|
||||
>
|
||||
<div v-for="(item, i) in state.list" :key="i + 'i'" class="list__item" draggable="false" @mousedown="dragStart($event, item)" @mousemove="mousemove" @mouseup="mouseup" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)">
|
||||
<!-- <edit-model :isComp="true" @action="action($event, item, i)"> -->
|
||||
<el-image class="list__img" :src="item.cover" fit="contain" lazy loading="lazy" />
|
||||
<!-- </edit-model> -->
|
||||
@ -95,13 +83,15 @@ const pageOptions = { type: 1, page: 0, pageSize: 20 }
|
||||
|
||||
onMounted(async () => {
|
||||
if (state.types.length <= 0) {
|
||||
const types = await api.material.getKinds({ type: 3 })
|
||||
state.types = types
|
||||
for (const iterator of types) {
|
||||
// const types = await api.material.getKinds({ type: 3 })
|
||||
state.types = [
|
||||
{ cate: 'text', name: '高级特效文字' },
|
||||
{ cate: 'comp', name: '示例组合模板' },
|
||||
]
|
||||
for (const iterator of state.types) {
|
||||
const { list } = await api.home.getCompList({
|
||||
cate: iterator.id,
|
||||
type: 1,
|
||||
pageSize: 3,
|
||||
cate: iterator.cate,
|
||||
})
|
||||
state.showList.push(list)
|
||||
}
|
||||
@ -202,7 +192,7 @@ const selectItem = async (item: TGetCompListResult) => {
|
||||
}
|
||||
// store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择
|
||||
|
||||
|
||||
tempDetail = tempDetail || (await getCompDetail({ id: item.id, type: 1 }))
|
||||
// let group = JSON.parse(tempDetail.data)
|
||||
const group: any = await getComponentsData(tempDetail.data)
|
||||
@ -234,10 +224,11 @@ function getCompDetail(params: TGetTempDetail): Promise<TTempDetail> {
|
||||
return new Promise((resolve) => {
|
||||
if (compsCache[params.id]) {
|
||||
resolve(compsCache[params.id])
|
||||
} else api.home.getTempDetail(params).then((res: any) => {
|
||||
resolve(res)
|
||||
compsCache[params.id] = res // 缓存请求的组件数据
|
||||
})
|
||||
} else
|
||||
api.home.getTempDetail(params).then((res: any) => {
|
||||
resolve(res)
|
||||
compsCache[params.id] = res // 缓存请求的组件数据
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-27 15:16:07
|
||||
* @Description: 素材列表
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-02-29 16:49:59
|
||||
* @LastEditTime: 2024-08-14 18:48:34
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -62,7 +62,7 @@ type TState = {
|
||||
sub: []
|
||||
list: TGetListData[]
|
||||
currentType: Number
|
||||
currentCheck:number
|
||||
currentCheck: number
|
||||
colors: string[]
|
||||
currentCategory: TCurrentCategory | null
|
||||
types: []
|
||||
@ -83,7 +83,6 @@ const props = defineProps<TProps>()
|
||||
|
||||
const colors = ['#f8704b', '#5b89ff', '#2cc4cc', '#a8ba73', '#f8704b']
|
||||
|
||||
|
||||
const controlStore = useControlStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
|
||||
@ -105,12 +104,15 @@ const pageOptions = { page: 0, pageSize: 20 }
|
||||
|
||||
onMounted(async () => {
|
||||
if (state.types.length <= 0) {
|
||||
const types = await api.material.getKinds({ type: 2 })
|
||||
state.types = types
|
||||
for (const iterator of types) {
|
||||
// const types = await api.material.getKinds({ type: 2 })
|
||||
state.types = [
|
||||
{ cate: 'png', name: '贴纸,图片类型' },
|
||||
{ cate: 'svg', name: 'SVG矢量元素,可编辑' },
|
||||
{ cate: 'mask', name: '容器Mask,图形遮罩' },
|
||||
]
|
||||
for (const iterator of state.types) {
|
||||
const { list } = await api.material.getList({
|
||||
cate: iterator.id,
|
||||
pageSize: 3,
|
||||
cate: iterator.cate,
|
||||
})
|
||||
state.showList.push(list)
|
||||
}
|
||||
@ -182,7 +184,6 @@ defineExpose({
|
||||
mousemove,
|
||||
})
|
||||
|
||||
|
||||
// computed: {
|
||||
// ...mapGetters(['dPage']),
|
||||
// }
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-02-11 18:48:23
|
||||
* @Description: 照片图库 Form:Unsplash无版权图片
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-03-19 10:04:39
|
||||
* @LastEditTime: 2024-08-14 18:50:09
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -42,12 +42,12 @@ type TProps = {
|
||||
}
|
||||
|
||||
type TState = {
|
||||
recommendImgList: TGetImageListResult[],
|
||||
recommendImgList: TGetImageListResult[]
|
||||
loadDone: boolean
|
||||
page: number
|
||||
currentCategory: TCurrentCategory | null,
|
||||
types: [],
|
||||
showList: TGetImageListResult[][],
|
||||
currentCategory: TCurrentCategory | null
|
||||
types: []
|
||||
showList: TGetImageListResult[][]
|
||||
}
|
||||
|
||||
type TCurrentCategory = {
|
||||
@ -57,7 +57,6 @@ type TCurrentCategory = {
|
||||
|
||||
const props = defineProps<TProps>()
|
||||
|
||||
|
||||
const controlStore = useControlStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
|
||||
@ -74,9 +73,12 @@ let loading = false
|
||||
|
||||
onMounted(async () => {
|
||||
if (state.types.length <= 0) {
|
||||
const types = await api.material.getKinds({ type: 4 })
|
||||
state.types = types
|
||||
for (const iterator of types) {
|
||||
// const types = await api.material.getKinds({ type: 4 })
|
||||
state.types = [
|
||||
{ id: 1, name: '照片列表,自适应布局' },
|
||||
{ id: 2, name: '照片列表,自适应布局' },
|
||||
]
|
||||
for (const iterator of state.types) {
|
||||
const { list } = await api.material.getImagesList({ cate: iterator.id, pageSize: 2 })
|
||||
state.showList.push(list)
|
||||
}
|
||||
@ -85,7 +87,7 @@ onMounted(async () => {
|
||||
|
||||
const selectImg = async (index: number, list: TGetImageListResult[]) => {
|
||||
const item = list ? list[index] : state.recommendImgList[index]
|
||||
|
||||
|
||||
// store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择
|
||||
|
||||
|
@ -8,10 +8,13 @@
|
||||
<template>
|
||||
<div class="wrap">
|
||||
<search-header v-model="state.searchKeyword" @change="cateChange" />
|
||||
|
||||
<el-divider v-show="state.title" style="margin-top: 1.7rem" content-position="left">
|
||||
<span style="font-weight: bold">{{ state.title }}</span>
|
||||
</el-divider>
|
||||
|
||||
<el-button class="upload-psd" plain type="primary" @click="openPSD">导入 PSD 创建模板</el-button>
|
||||
|
||||
<ul ref="listRef" v-infinite-scroll="load" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
|
||||
<img-water-fall :listData="state.list" @select="selectItem" />
|
||||
<div v-show="state.loading" class="loading"><i class="el-icon-loading"></i> 拼命加载中</div>
|
||||
@ -64,7 +67,7 @@ const state = reactive<TState>({
|
||||
loading: false,
|
||||
loadDone: false,
|
||||
list: [],
|
||||
title: '推荐模板',
|
||||
title: '示例模板',
|
||||
searchKeyword: '',
|
||||
})
|
||||
|
||||
@ -122,7 +125,7 @@ let hideReplacePrompt: any = localStorage.getItem('hide_replace_prompt')
|
||||
async function selectItem(item: IGetTempListData) {
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
if (!hideReplacePrompt && dHistoryParams.value.length > 0) {
|
||||
const doNotPrompt = await useConfirm('添加到作品', '模板内容将替换页面内容', 'warning', {confirmButtonText: '知道了',cancelButtonText: '不再提示'})
|
||||
const doNotPrompt = await useConfirm('添加到作品', '模板内容将替换页面内容', 'warning', { confirmButtonText: '知道了', cancelButtonText: '不再提示' })
|
||||
if (!doNotPrompt) {
|
||||
localStorage.setItem('hide_replace_prompt', '1')
|
||||
hideReplacePrompt = true
|
||||
@ -139,9 +142,15 @@ async function selectItem(item: IGetTempListData) {
|
||||
} else {
|
||||
result = JSON.parse(item.data)
|
||||
}
|
||||
const { page, widgets } = result
|
||||
pageStore.setDPage(page)
|
||||
widgetStore.setTemplate(widgets)
|
||||
if (Array.isArray(result)) {
|
||||
const { global, layers } = result[0]
|
||||
pageStore.setDPage(global)
|
||||
widgetStore.setTemplate(layers)
|
||||
} else {
|
||||
const { page, widgets } = result
|
||||
pageStore.setDPage(page)
|
||||
widgetStore.setTemplate(widgets)
|
||||
}
|
||||
setTimeout(() => {
|
||||
forceStore.setZoomScreenChange()
|
||||
}, 300)
|
||||
@ -155,6 +164,10 @@ function setTempId(tempId: number | string) {
|
||||
router.push({ path: '/home', query: { tempid: tempId, id }, replace: true })
|
||||
}
|
||||
|
||||
const openPSD = () => {
|
||||
window.open(router.resolve('/psd').href, '_blank')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
load,
|
||||
cateChange,
|
||||
@ -211,4 +224,9 @@ defineExpose({
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.upload-psd {
|
||||
margin: 0 1rem;
|
||||
width: calc(100% - 2rem);
|
||||
}
|
||||
</style>
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2022-02-13 22:18:35
|
||||
* @Description: 我的
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-03 21:00:26
|
||||
* @LastEditTime: 2024-08-12 09:32:00
|
||||
-->
|
||||
<template>
|
||||
<div class="wrap">
|
||||
@ -15,14 +15,9 @@
|
||||
<uploader v-model="state.percent" class="upload" @done="uploadDone">
|
||||
<el-button class="upload-btn" plain><i class="iconfont icon-upload" /> 上传图片</el-button>
|
||||
</uploader>
|
||||
<el-button class="upload-btn upload-psd" plain type="primary" @click="openPSD">导入 PSD</el-button>
|
||||
<el-button disabled class="upload-btn upload-psd" plain type="primary" @click="openPSD">导入 PSD</el-button>
|
||||
<div style="margin: 1rem; height: 100vh">
|
||||
<photo-list
|
||||
ref="imgListRef"
|
||||
:edit="state.editOptions.photo" :isDone="state.isDone"
|
||||
:listData="state.imgList"
|
||||
@load="load" @drag="dragStart" @select="selectImg"
|
||||
/>
|
||||
<photo-list ref="imgListRef" :edit="state.editOptions.photo" :isDone="state.isDone" :listData="state.imgList" @load="load" @drag="dragStart" @select="selectImg" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="state.tabActiveName === 'design'" class="wrap">
|
||||
@ -60,20 +55,19 @@ type TProps = {
|
||||
}
|
||||
|
||||
type TState = {
|
||||
prePath: string,
|
||||
percent: { num: number }, // 当前上传进度
|
||||
imgList: IGetTempListData[],
|
||||
designList: IGetTempListData[],
|
||||
isDone: boolean,
|
||||
editOptions: Record<string, any>,
|
||||
tabActiveName: string,
|
||||
prePath: string
|
||||
percent: { num: number } // 当前上传进度
|
||||
imgList: IGetTempListData[]
|
||||
designList: IGetTempListData[]
|
||||
isDone: boolean
|
||||
editOptions: Record<string, any>
|
||||
tabActiveName: string
|
||||
}
|
||||
|
||||
const props = defineProps<TProps>()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
const controlStore = useControlStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
|
||||
@ -107,7 +101,6 @@ const load = (init?: boolean) => {
|
||||
loading = true
|
||||
page += 1
|
||||
api.material.getMyPhoto({ page }).then(({ list }) => {
|
||||
|
||||
if (list.length <= 0) {
|
||||
state.isDone = true
|
||||
} else {
|
||||
@ -166,7 +159,7 @@ onMounted(() => {
|
||||
|
||||
const selectImg = async (index: number) => {
|
||||
const item = state.imgList[index]
|
||||
|
||||
|
||||
// store.commit('setShowMoveable', false) // 清理掉上一次的选择
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择
|
||||
|
||||
@ -189,7 +182,6 @@ type controlImgParam = {
|
||||
}
|
||||
|
||||
const deleteImg = async ({ i, item }: controlImgParam) => {
|
||||
|
||||
// store.commit('setShowMoveable', false) // 清理掉上一次的选择框
|
||||
controlStore.setShowMoveable(false) // 清理掉上一次的选择框
|
||||
|
||||
@ -208,9 +200,9 @@ const deleteWorks = async ({ i, item }: controlImgParam) => {
|
||||
if (isPass) {
|
||||
await api.material.deleteMyWorks({ id: item.id })
|
||||
setTimeout(() => {
|
||||
router.push({ path: '/home', query: { }, replace: true })
|
||||
router.push({ path: '/home', query: {}, replace: true })
|
||||
loadDesign(true)
|
||||
}, 300);
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +218,7 @@ state.editOptions = {
|
||||
name: '删除',
|
||||
fn: deleteWorks,
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
const dragStart = (index: number) => {
|
||||
@ -234,10 +226,15 @@ const dragStart = (index: number) => {
|
||||
widgetStore.setSelectItem({ data: { value: item }, type: 'image' })
|
||||
// store.commit('selectItem', { data: { value: item }, type: 'image' })
|
||||
}
|
||||
const uploadDone = async (res: TUploadDoneData) => {
|
||||
await api.material.addMyPhoto(res)
|
||||
const uploadDone = async (res: any) => {
|
||||
// await api.material.addMyPhoto(res)
|
||||
// state.imgList = []
|
||||
// load(true)
|
||||
const newList = [res, ...state.imgList]
|
||||
state.imgList = []
|
||||
load(true)
|
||||
setTimeout(() => {
|
||||
state.imgList = newList // 模拟加载
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const tabChange = (tabName: TabPaneName) => {
|
||||
|
@ -102,7 +102,7 @@ watch(
|
||||
return
|
||||
}
|
||||
let list = newList.filter((v: IGetTempListData) => !oldList.includes(v)) // difference
|
||||
list = JSON.parse(JSON.stringify(list))
|
||||
list = JSON.parse(JSON.stringify(list))
|
||||
const marginRight = 6 // 间距
|
||||
const limitWidth = (await getFatherWidth()) - marginRight
|
||||
const standardHeight = 280 // 高度阈值
|
||||
|
@ -65,13 +65,14 @@ const state = reactive<TState>({
|
||||
})
|
||||
|
||||
if (props.type != 'none') {
|
||||
api.home.getCategories({ type: 1 }).then((list: any) => {
|
||||
list.unshift({ id: 0, name: '全部' })
|
||||
state.materialCates = list
|
||||
const { cate } = route.query
|
||||
cate && (state.currentIndex = cate as string)
|
||||
cate && action('change', state.materialCates[Number(cate)], Number(cate))
|
||||
})
|
||||
state.materialCates = [{ id: 0, name: '示例模板' }]
|
||||
// api.home.getCategories({ type: 1 }).then((list: any) => {
|
||||
// list.unshift({ id: 0, name: '全部' })
|
||||
// state.materialCates = list
|
||||
// const { cate } = route.query
|
||||
// cate && (state.currentIndex = cate as string)
|
||||
// cate && action('change', state.materialCates[Number(cate)], Number(cate))
|
||||
// })
|
||||
}
|
||||
|
||||
watch(
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-09 14:00:23
|
||||
* @Description: 图片容器
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||
* @LastEditTime: 2023-06-29 17:53:39
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:48:42
|
||||
-->
|
||||
<template>
|
||||
<el-card class="box-card" shadow="hover" :body-style="{ padding: state.effectSelect ? '20px' : 0 }">
|
||||
@ -85,8 +85,7 @@ onMounted(async () => {
|
||||
|
||||
async function getList() {
|
||||
const res = await api.material.getList({
|
||||
cate: 8,
|
||||
pageSize: 29
|
||||
cate: 'mask',
|
||||
})
|
||||
state.list = res.list.map(({ thumb, url }) => {
|
||||
return { thumb, url }
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-02 09:41:41
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 17:19:15
|
||||
* @LastEditTime: 2024-08-12 09:25:33
|
||||
-->
|
||||
<template>
|
||||
<div
|
||||
@ -203,8 +203,7 @@ function keyChange(uuid: string, key: keyof TParamsData, value: number) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid,
|
||||
key,
|
||||
value,
|
||||
pushHistory: false,
|
||||
value
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid,
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-09 11:21:37
|
||||
* @Description: 组合设置
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||
* @LastEditTime: 2023-06-29 17:57:24
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:25:37
|
||||
-->
|
||||
<template>
|
||||
<div id="w-group-style">
|
||||
@ -142,8 +142,7 @@ function finish(key: string, value: string | number | number[]) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: value as TUpdateWidgetPayload['value'],
|
||||
pushHistory: true,
|
||||
value: value as TUpdateWidgetPayload['value']
|
||||
})
|
||||
// store.dispatch("updateWidgetData", {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
|
@ -249,8 +249,7 @@ function setTransform(attrName: string, value: string | number) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: props.params.uuid,
|
||||
key: 'transform',
|
||||
value: setValue,
|
||||
pushHistory: false,
|
||||
value: setValue
|
||||
})
|
||||
// store.dispatch("updateWidgetData", {
|
||||
// uuid: props.params.uuid,
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2021-08-09 11:41:53
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-03-22 16:14:48
|
||||
* @LastEditTime: 2024-08-12 09:25:47
|
||||
-->
|
||||
<template>
|
||||
<div id="w-image-style">
|
||||
@ -37,16 +37,8 @@
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item v-if="state.innerElement.isNinePatch" title="点九图设置" name="3">
|
||||
<number-slider
|
||||
v-model="state.innerElement.sliceData.ratio"
|
||||
:step="0.01" label="比率" :maxValue="10"
|
||||
@finish="(value) => finishSliceData('ratio', value)"
|
||||
/>
|
||||
<number-slider
|
||||
v-model="state.innerElement.sliceData.left"
|
||||
:step="0.5" label="大小"
|
||||
@finish="(value) => finishSliceData('left', value)"
|
||||
/>
|
||||
<number-slider v-model="state.innerElement.sliceData.ratio" :step="0.01" label="比率" :maxValue="10" @finish="(value) => finishSliceData('ratio', value)" />
|
||||
<number-slider v-model="state.innerElement.sliceData.left" :step="0.5" label="大小" @finish="(value) => finishSliceData('left', value)" />
|
||||
</el-collapse-item>
|
||||
<br />
|
||||
<icon-item-select class="style-item" label="" :data="layerIconList" @finish="layerAction" />
|
||||
@ -55,11 +47,7 @@
|
||||
</el-collapse>
|
||||
<!-- <CropImage ref="crop" @done="cropDone" /> -->
|
||||
<inner-tool-bar v-show="state.innerElement.cropEdit" :style="toolBarStyle">
|
||||
<number-slider
|
||||
v-model="state.innerElement.zoom"
|
||||
class="inner-bar" label="缩放" labelWidth="40px"
|
||||
:step="0.01" :minValue="1" :maxValue="3"
|
||||
/>
|
||||
<number-slider v-model="state.innerElement.zoom" class="inner-bar" label="缩放" labelWidth="40px" :step="0.01" :minValue="1" :maxValue="3" />
|
||||
<i style="padding: 0 8px; cursor: pointer" class="icon sd-queren" @click="imgCrop(false)" />
|
||||
</inner-tool-bar>
|
||||
<picBox ref="picBoxRef" @select="selectDone" />
|
||||
@ -134,7 +122,6 @@ const state = reactive<TState>({
|
||||
const picBoxRef = ref<typeof picBox | null>(null)
|
||||
const imageCutoutRef = ref<typeof imageCutout | null>(null)
|
||||
|
||||
|
||||
const widgetStore = useWidgetStore()
|
||||
const forceStore = useForceStore()
|
||||
const canvasStore = useCanvasStore()
|
||||
@ -145,10 +132,9 @@ const controlStore = useControlStore()
|
||||
const { dMoving } = storeToRefs(controlStore)
|
||||
const { dActiveElement, dWidgets } = storeToRefs(widgetStore)
|
||||
|
||||
|
||||
let lastUuid: string | undefined = undefined
|
||||
let tag: boolean
|
||||
let toolBarStyle: { left: string, top: string } | null = null
|
||||
let toolBarStyle: { left: string; top: string } | null = null
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
imgCrop(false)
|
||||
@ -166,7 +152,7 @@ watch(
|
||||
}
|
||||
lastUuid = newValue.uuid
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -175,7 +161,7 @@ watch(
|
||||
changeValue()
|
||||
cropHandle()
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
function created() {
|
||||
@ -201,15 +187,12 @@ function changeValue() {
|
||||
}
|
||||
for (let key in state.innerElement) {
|
||||
if (state.ingoreKeys.indexOf(key) !== -1) {
|
||||
(dActiveElement.value as Record<string, any>)[key] = state.innerElement[(key as keyof TImageSetting)]
|
||||
} else if (
|
||||
key !== 'cropEdit' && key !== 'record' &&
|
||||
state.innerElement[(key as keyof TImageSetting)] !== (dActiveElement.value as Record<string, any>)[key]
|
||||
) {
|
||||
;(dActiveElement.value as Record<string, any>)[key] = state.innerElement[key as keyof TImageSetting]
|
||||
} else if (key !== 'cropEdit' && key !== 'record' && state.innerElement[key as keyof TImageSetting] !== (dActiveElement.value as Record<string, any>)[key]) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
key: (key as TUpdateWidgetPayload['key']),
|
||||
value: (state.innerElement[(key as keyof TImageSetting)] as TUpdateWidgetPayload['value']),
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: state.innerElement[key as keyof TImageSetting] as TUpdateWidgetPayload['value'],
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
@ -229,51 +212,37 @@ function finishSliceData(key: string, value: number | number[]) {
|
||||
uuid: dActiveElement.value.uuid,
|
||||
key: 'sliceData',
|
||||
value: data,
|
||||
pushHistory: true,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key: 'sliceData',
|
||||
// value: data,
|
||||
// pushHistory: true,
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
function finish(key: string = "", value: string | number | (string | number)[] | null = "") {
|
||||
function finish(key: string = '', value: string | number | (string | number)[] | null = '') {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
key: (key as TUpdateWidgetPayload['key']),
|
||||
value: value as TUpdateWidgetPayload['value'],
|
||||
pushHistory: true,
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: value as TUpdateWidgetPayload['value']
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key: key,
|
||||
// value: value,
|
||||
// pushHistory: true,
|
||||
// })
|
||||
}
|
||||
|
||||
function layerAction(item: TIconItemSelectData) {
|
||||
if (item.key === 'zIndex') {
|
||||
widgetStore.updateLayerIndex({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
value: (item.value as TupdateLayerIndexData['value']),
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
value: item.value as TupdateLayerIndexData['value'],
|
||||
})
|
||||
// store.dispatch("updateLayerIndex", {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// value: item.value,
|
||||
// })
|
||||
} else {
|
||||
finish(item.key || "", item.value === dActiveElement.value?.flip ? null : item.value)
|
||||
finish(item.key || '', item.value === dActiveElement.value?.flip ? null : item.value)
|
||||
}
|
||||
}
|
||||
|
||||
async function alignAction(item: TIconItemSelectData) {
|
||||
widgetStore.updateAlign({
|
||||
align: (item.value as TUpdateAlignData['align']),
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
align: item.value as TUpdateAlignData['align'],
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
})
|
||||
// store.dispatch("updateAlign", {
|
||||
// align: item.value,
|
||||
@ -295,7 +264,6 @@ function openCropper() {
|
||||
// this.innerElement.height = height.toFixed(0)
|
||||
// }
|
||||
|
||||
|
||||
async function changeContainer(setting: any) {
|
||||
state.innerElement.mask = setting.svgUrl
|
||||
// const index = this.dWidgets.findIndex((x) => x.uuid == this.innerElement.uuid)
|
||||
@ -318,18 +286,17 @@ async function changeContainer(setting: any) {
|
||||
// this.$store.commit('setShowMoveable', true)
|
||||
// }
|
||||
|
||||
|
||||
async function selectDone(img: TGetImageListResult) {
|
||||
state.innerElement.imgUrl = img.url
|
||||
const loadImg = await getImage(img.url)
|
||||
state.innerElement.width = loadImg.width * canvasStore.dZoom / 100
|
||||
state.innerElement.height = loadImg.height * canvasStore.dZoom / 100
|
||||
state.innerElement.width = (loadImg.width * canvasStore.dZoom) / 100
|
||||
state.innerElement.height = (loadImg.height * canvasStore.dZoom) / 100
|
||||
// this.imgCrop(true)
|
||||
}
|
||||
|
||||
function imgCrop(val: boolean) {
|
||||
// TODO: 画布内图像裁剪
|
||||
const el = document.getElementById(state.innerElement.uuid || "")
|
||||
const el = document.getElementById(state.innerElement.uuid || '')
|
||||
if (!el) return
|
||||
const { left, top } = el.getBoundingClientRect()
|
||||
toolBarStyle = { left: left + 'px', top: top + 'px' }
|
||||
@ -337,7 +304,6 @@ function imgCrop(val: boolean) {
|
||||
controlStore.setShowRotatable(!val)
|
||||
}
|
||||
|
||||
|
||||
function cropHandle() {
|
||||
controlStore.setCropUuid(state.innerElement.cropEdit ? state.innerElement.uuid : '-1')
|
||||
// store.commit('setCropUuid', state.innerElement.cropEdit ? state.innerElement.uuid : -1)
|
||||
@ -352,7 +318,7 @@ function openPicBox() {
|
||||
|
||||
// 打开抠图
|
||||
function openImageCutout() {
|
||||
fetch(state.innerElement.imgUrl || "")
|
||||
fetch(state.innerElement.imgUrl || '')
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const file = new File([blob], `image_${Math.random()}.jpg`, { type: 'image/jpeg' })
|
||||
@ -371,7 +337,6 @@ async function cutImageDone(url: string) {
|
||||
state.innerElement.imgUrl = url
|
||||
}, 300)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-09 11:41:53
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <site: book.palxp.com>
|
||||
* @LastEditTime: 2023-06-29 17:53:23
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:26:04
|
||||
-->
|
||||
<template>
|
||||
<div id="w-image-style">
|
||||
@ -80,12 +80,12 @@ import { TUpdateAlignData } from '@/store/design/widget/actions/align'
|
||||
|
||||
type TState = {
|
||||
activeNames: string[]
|
||||
innerElement: TWQrcodeSetting,
|
||||
tag: boolean,
|
||||
ingoreKeys: string[],
|
||||
layerIconList: TIconItemSelectData[],
|
||||
alignIconList: TIconItemSelectData[],
|
||||
localization: QrCodeLocalizationData,
|
||||
innerElement: TWQrcodeSetting
|
||||
tag: boolean
|
||||
ingoreKeys: string[]
|
||||
layerIconList: TIconItemSelectData[]
|
||||
alignIconList: TIconItemSelectData[]
|
||||
localization: QrCodeLocalizationData
|
||||
}
|
||||
|
||||
const state = reactive<TState>({
|
||||
@ -98,12 +98,10 @@ const state = reactive<TState>({
|
||||
localization,
|
||||
})
|
||||
|
||||
|
||||
const controlStore = useControlStore()
|
||||
const widgetStore = useWidgetStore()
|
||||
const forceStore = useForceStore()
|
||||
|
||||
|
||||
// const {
|
||||
// dActiveElement, dWidgets
|
||||
// } = useSetupMapGetters(['dActiveElement', 'dWidgets'])
|
||||
@ -121,7 +119,7 @@ watch(
|
||||
if (Number(newValue.uuid) == -1) {
|
||||
state.innerElement.cropEdit = false
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: lastUuid ?? "",
|
||||
uuid: lastUuid ?? '',
|
||||
key: 'cropEdit',
|
||||
value: false,
|
||||
})
|
||||
@ -134,7 +132,7 @@ watch(
|
||||
lastUuid = newValue.uuid
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -142,7 +140,7 @@ watch(
|
||||
(newValue, oldValue) => {
|
||||
changeValue()
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
function created() {
|
||||
@ -168,13 +166,10 @@ function changeValue() {
|
||||
for (let key in state.innerElement) {
|
||||
const itemKey = key as keyof TWQrcodeSetting
|
||||
if (state.ingoreKeys.indexOf(key) !== -1) {
|
||||
(dActiveElement.value as Record<string, any>)[itemKey] = state.innerElement[itemKey]
|
||||
} else if (
|
||||
key !== 'setting' && key !== 'record' &&
|
||||
state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]
|
||||
) {
|
||||
;(dActiveElement.value as Record<string, any>)[itemKey] = state.innerElement[itemKey]
|
||||
} else if (key !== 'setting' && key !== 'record' && state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: state.innerElement[itemKey] as TUpdateWidgetPayload['value'],
|
||||
})
|
||||
@ -192,20 +187,13 @@ function finish(key: string, value: number | number[] | string) {
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: value,
|
||||
pushHistory: true,
|
||||
})
|
||||
// store.dispatch("updateWidgetData", {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key: key,
|
||||
// value: value,
|
||||
// pushHistory: true,
|
||||
// })
|
||||
}
|
||||
|
||||
function layerAction(item: TIconItemSelectData) {
|
||||
console.log(item)
|
||||
widgetStore.updateLayerIndex({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
value: item.value as number,
|
||||
})
|
||||
// store.dispatch("updateLayerIndex", {
|
||||
@ -217,7 +205,7 @@ function layerAction(item: TIconItemSelectData) {
|
||||
async function alignAction(item: TIconItemSelectData) {
|
||||
widgetStore.updateAlign({
|
||||
align: item.value as TUpdateAlignData['align'],
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
})
|
||||
// store.dispatch("updateAlign", {
|
||||
// align: item.value,
|
||||
@ -237,7 +225,7 @@ async function uploadImgDone(img: TUploadDoneData) {
|
||||
// this.innerElement.width = img.width
|
||||
// this.innerElement.height = img.height * (this.innerElement.width / img.width)
|
||||
state.innerElement.url = img.url
|
||||
|
||||
|
||||
// store.commit('setShowMoveable', true)
|
||||
controlStore.setShowMoveable(true)
|
||||
}
|
||||
|
@ -21,11 +21,11 @@
|
||||
// svg
|
||||
// const NAME = 'w-svg'
|
||||
|
||||
import { useCanvasStore, useForceStore, useWidgetStore } from '@/store';
|
||||
import { useCanvasStore, useForceStore, useWidgetStore } from '@/store'
|
||||
import { TWSvgSetting } from './wSvgSetting'
|
||||
import { CSSProperties, computed, nextTick, onBeforeMount, onMounted, onUpdated, reactive, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { TUpdateWidgetPayload } from '@/store/design/widget/actions/widget';
|
||||
import { CSSProperties, computed, nextTick, onBeforeMount, onMounted, onUpdated, reactive, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { TUpdateWidgetPayload } from '@/store/design/widget/actions/widget'
|
||||
// import { useSetupMapGetters } from '@/common/hooks/mapGetters';
|
||||
|
||||
type TProps = {
|
||||
@ -37,12 +37,12 @@ type TProps = {
|
||||
}
|
||||
|
||||
type TState = {
|
||||
position: CSSProperties['position'], // 'absolute'relative
|
||||
editBoxStyle: CSSProperties,
|
||||
editBoxs: Record<string, any>,
|
||||
editingKey: string,
|
||||
cropWidgetXY: Record<string, any>, // 裁剪框移动作用
|
||||
attrRecord: Record<string, any>, // 记录可更改的属性
|
||||
position: CSSProperties['position'] // 'absolute'relative
|
||||
editBoxStyle: CSSProperties
|
||||
editBoxs: Record<string, any>
|
||||
editingKey: string
|
||||
cropWidgetXY: Record<string, any> // 裁剪框移动作用
|
||||
attrRecord: Record<string, any> // 记录可更改的属性
|
||||
svgImg: Record<string, any> | null
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ const state = reactive<TState>({
|
||||
editingKey: '',
|
||||
cropWidgetXY: {}, // 裁剪框移动作用
|
||||
attrRecord: {}, // 记录可更改的属性
|
||||
svgImg: null
|
||||
svgImg: null,
|
||||
})
|
||||
|
||||
const widgetStore = useWidgetStore()
|
||||
@ -88,7 +88,7 @@ watch(
|
||||
() => {
|
||||
attrsChange()
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -96,7 +96,7 @@ watch(
|
||||
async () => {
|
||||
await nextTick()
|
||||
updateRecord()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -106,7 +106,7 @@ watch(
|
||||
state.svgImg.attr({
|
||||
'xlink:href': props.params.imgUrl,
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -118,7 +118,7 @@ watch(
|
||||
} else {
|
||||
el?.removeEventListener('mousedown', touchstart, false)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
onUpdated(() => {
|
||||
@ -195,16 +195,14 @@ function loadSvg() {
|
||||
// console.log(this.params)
|
||||
const Snap = (window as any).Snap
|
||||
return new Promise<void>((resolve) => {
|
||||
Snap.load(
|
||||
props.params.svgUrl,
|
||||
function (svg: Record<string, any>) {
|
||||
let svg2 = Snap(svg.node)
|
||||
// let item = svg2.select('circle')
|
||||
// item.attr({
|
||||
// fill: 'rgb(255, 0, 0)',
|
||||
// })
|
||||
// console.log(item.attr('fill'))
|
||||
|
||||
// Snap.load(
|
||||
// props.params.svgUrl,
|
||||
// function (svg: Record<string, any>) {
|
||||
// 链接加载方法
|
||||
// },
|
||||
// )
|
||||
const svg = Snap.parse(props.params.svgUrl)
|
||||
let svg2 = Snap(svg.node)
|
||||
let items = svg2.node.childNodes
|
||||
svg2.node.removeAttribute('width')
|
||||
svg2.node.removeAttribute('height')
|
||||
@ -250,24 +248,12 @@ function loadSvg() {
|
||||
}
|
||||
// console.log(element.attributes, element.getAttribute('fill'), _this.params.colors)
|
||||
}
|
||||
|
||||
// _this.viewBox = svg2.node.viewBox.baseVal
|
||||
// _this.svgImg = img
|
||||
|
||||
// img.attr({
|
||||
// width: '100%',
|
||||
// height: '100%',
|
||||
// transform: '',
|
||||
// 'xlink:href': _this.params.imgUrl || '',
|
||||
// })
|
||||
|
||||
if (widgetRef.value) {
|
||||
// svg.node.classList.add('svg__box')
|
||||
widgetRef.value.appendChild(svg.node)
|
||||
}
|
||||
resolve()
|
||||
},
|
||||
document.getElementById(props.params.uuid),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -323,14 +309,7 @@ function changeFinish(key: string, value: number) {
|
||||
uuid: props.params.uuid,
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: value,
|
||||
pushHistory: true,
|
||||
})
|
||||
// store.dispatch("updateWidgetData", {
|
||||
// uuid: props.params.uuid,
|
||||
// key: key,
|
||||
// value: value,
|
||||
// pushHistory: true,
|
||||
// })
|
||||
}
|
||||
|
||||
function move(payload: Record<string, any>) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: ShawnPhang
|
||||
* @Date: 2021-08-09 11:41:53
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang
|
||||
* @LastEditTime: 2022-04-15 11:08:36
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:26:17
|
||||
-->
|
||||
<template>
|
||||
<div id="w-image-style">
|
||||
@ -83,7 +83,7 @@ watch(
|
||||
() => {
|
||||
change()
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
@ -91,7 +91,7 @@ watch(
|
||||
() => {
|
||||
changeValue()
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
function created() {
|
||||
@ -118,13 +118,10 @@ function changeValue() {
|
||||
for (let key in state.innerElement) {
|
||||
const itemKey = key as keyof TWSvgSetting
|
||||
if (state.ingoreKeys.indexOf(itemKey) !== -1) {
|
||||
(dActiveElement.value as Record<string, any>)[key] = state.innerElement[itemKey]
|
||||
} else if (
|
||||
itemKey !== 'setting' && itemKey !== 'record' &&
|
||||
state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]
|
||||
) {
|
||||
;(dActiveElement.value as Record<string, any>)[key] = state.innerElement[itemKey]
|
||||
} else if (itemKey !== 'setting' && itemKey !== 'record' && state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || "",
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: state.innerElement[itemKey] as TUpdateWidgetPayload['value'],
|
||||
})
|
||||
@ -146,14 +143,7 @@ function finish(key: string, value: any) {
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: value,
|
||||
pushHistory: true,
|
||||
})
|
||||
// store.dispatch("updateWidgetData", {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key: key,
|
||||
// value: value,
|
||||
// pushHistory: true,
|
||||
// })
|
||||
}
|
||||
|
||||
function layerAction(item: TIconItemSelectData) {
|
||||
|
@ -45,13 +45,7 @@
|
||||
v-html="params.text"
|
||||
></div>
|
||||
</template>
|
||||
<div
|
||||
ref="editWrap" :style="{ fontFamily: `'${params.fontClass.value}'` }"
|
||||
class="edit-text" spellcheck="false"
|
||||
:contenteditable="state.editable ? 'plaintext-only' : false"
|
||||
@input="writingText($event)"
|
||||
@blur="writeDone($event)"
|
||||
v-html="params.text"></div>
|
||||
<div ref="editWrap" :style="{ fontFamily: `'${params.fontClass.value}'` }" class="edit-text" spellcheck="false" :contenteditable="state.editable ? 'plaintext-only' : false" @input="writingText($event)" @blur="writeDone($event)" v-html="params.text"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -147,14 +141,7 @@ watch(
|
||||
uuid: String(props.params.uuid),
|
||||
key: 'editable',
|
||||
value,
|
||||
pushHistory: false,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: props.params.uuid,
|
||||
// key: 'editable',
|
||||
// value,
|
||||
// pushHistory: false,
|
||||
// })
|
||||
},
|
||||
)
|
||||
|
||||
@ -171,20 +158,13 @@ function updateRecord() {
|
||||
}
|
||||
|
||||
function updateText(e?: Event) {
|
||||
const value = e && e.target ? (e.target as HTMLElement).innerHTML : props.params.text//.replace(/\n/g, '<br/>')
|
||||
const value = e && e.target ? (e.target as HTMLElement).innerHTML : props.params.text //.replace(/\n/g, '<br/>')
|
||||
if (value !== props.params.text) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: String(props.params.uuid),
|
||||
key: 'text',
|
||||
value,
|
||||
pushHistory: false,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: props.params.uuid,
|
||||
// key: 'text',
|
||||
// value,
|
||||
// pushHistory: false,
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,24 +177,13 @@ function writingText(e?: Event) {
|
||||
uuid: String(props.params.uuid),
|
||||
key: 'height',
|
||||
value: el.offsetHeight,
|
||||
pushHistory: false,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: props.params.uuid,
|
||||
// key: 'height',
|
||||
// value: el.offsetHeight,
|
||||
// pushHistory: false,
|
||||
// })
|
||||
forceStore.setUpdateRect()
|
||||
// store.commit('updateRect')
|
||||
}
|
||||
|
||||
function writeDone(e: Event) {
|
||||
state.editable = false
|
||||
setTimeout(() => {
|
||||
historyStore.pushHistory("文字修改")
|
||||
// store.dispatch('pushHistory', '文字修改')
|
||||
}, 100)
|
||||
updateText(e)
|
||||
}
|
||||
|
||||
@ -231,9 +200,9 @@ function dblclickText(_: MouseEvent) {
|
||||
range.select()
|
||||
} else {
|
||||
const range = document.createRange()
|
||||
range.selectNodeContents(el);
|
||||
window.getSelection()?.removeAllRanges();
|
||||
window.getSelection()?.addRange(range);
|
||||
range.selectNodeContents(el)
|
||||
window.getSelection()?.removeAllRanges()
|
||||
window.getSelection()?.addRange(range)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
@ -64,25 +64,25 @@ import valueSelect from '../../settings/valueSelect.vue'
|
||||
import effectWrap from '../../settings/EffectSelect/TextWrap.vue'
|
||||
import { useFontStore } from '@/common/methods/fonts'
|
||||
import usePageFontsFilter from './pageFontsFilter'
|
||||
import { wTextSetting ,TwTextData } from './wTextSetting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useControlStore, useForceStore, useWidgetStore } from '@/store';
|
||||
import { TUpdateWidgetPayload } from '@/store/design/widget/actions/widget';
|
||||
import { TUpdateAlignData } from '@/store/design/widget/actions/align';
|
||||
import { wTextSetting, TwTextData } from './wTextSetting'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useControlStore, useForceStore, useWidgetStore } from '@/store'
|
||||
import { TUpdateWidgetPayload } from '@/store/design/widget/actions/widget'
|
||||
import { TUpdateAlignData } from '@/store/design/widget/actions/align'
|
||||
|
||||
type TState = {
|
||||
activeNames: string[],
|
||||
innerElement: TwTextData,
|
||||
tag: boolean,
|
||||
ingoreKeys: string[],
|
||||
fontSizeList: number[],
|
||||
fontClassList: Record<string, any>, // 不能设空字体系统默认字体,因为截图服务的默认字体无法保证一致
|
||||
lineHeightList: number[],
|
||||
letterSpacingList: number[],
|
||||
layerIconList: TIconItemSelectData[],
|
||||
styleIconList1: TStyleIconData[],
|
||||
styleIconList2: TStyleIconData2[],
|
||||
alignIconList: TIconItemSelectData[],
|
||||
activeNames: string[]
|
||||
innerElement: TwTextData
|
||||
tag: boolean
|
||||
ingoreKeys: string[]
|
||||
fontSizeList: number[]
|
||||
fontClassList: Record<string, any> // 不能设空字体系统默认字体,因为截图服务的默认字体无法保证一致
|
||||
lineHeightList: number[]
|
||||
letterSpacingList: number[]
|
||||
layerIconList: TIconItemSelectData[]
|
||||
styleIconList1: TStyleIconData[]
|
||||
styleIconList2: TStyleIconData2[]
|
||||
alignIconList: TIconItemSelectData[]
|
||||
}
|
||||
|
||||
const widgetStore = useWidgetStore()
|
||||
@ -108,13 +108,21 @@ const { dMoving } = storeToRefs(useControlStore())
|
||||
|
||||
// const isDraw = computed(() => route.name === 'Draw')
|
||||
|
||||
watch(() => dActiveElement.value, () => {
|
||||
change()
|
||||
}, { deep: true })
|
||||
watch(
|
||||
() => dActiveElement.value,
|
||||
() => {
|
||||
change()
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
watch(() => state.innerElement, () => {
|
||||
changeValue()
|
||||
}, { deep: true })
|
||||
watch(
|
||||
() => state.innerElement,
|
||||
() => {
|
||||
changeValue()
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
let timer: boolean | null = null
|
||||
|
||||
@ -150,24 +158,13 @@ function changeValue() {
|
||||
for (let key in state.innerElement) {
|
||||
const itemKey = key as keyof TwTextData
|
||||
if (state.ingoreKeys.indexOf(itemKey) !== -1) {
|
||||
(dActiveElement.value as Record<string, any>)[itemKey] = state.innerElement[itemKey]
|
||||
} else if (
|
||||
key !== 'setting' && key !== 'record' &&
|
||||
state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]
|
||||
) {
|
||||
// const pushHistory = !['textEffects', 'transformData', 'fontClass'].includes(key)
|
||||
;(dActiveElement.value as Record<string, any>)[itemKey] = state.innerElement[itemKey]
|
||||
} else if (key !== 'setting' && key !== 'record' && state.innerElement[itemKey] !== (dActiveElement.value as Record<string, any>)[itemKey]) {
|
||||
widgetStore.updateWidgetData({
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value: state.innerElement[itemKey],
|
||||
pushHistory: false,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key,
|
||||
// value: state.innerElement[itemKey],
|
||||
// pushHistory: false,
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,14 +195,7 @@ function finish(key: string, value: number | Record<string, any> | string) {
|
||||
uuid: dActiveElement.value?.uuid || '',
|
||||
key: key as TUpdateWidgetPayload['key'],
|
||||
value,
|
||||
pushHistory: false,
|
||||
})
|
||||
// store.dispatch('updateWidgetData', {
|
||||
// uuid: dActiveElement.value.uuid,
|
||||
// key,
|
||||
// value,
|
||||
// pushHistory: false,
|
||||
// })
|
||||
setTimeout(() => {
|
||||
key === 'fontClass' && (state.fontClassList['当前页面'] = usePageFontsFilter())
|
||||
}, 300)
|
||||
@ -223,8 +213,8 @@ function layerAction(item: TIconItemSelectData) {
|
||||
}
|
||||
|
||||
async function textStyleAction(item: TIconItemSelectData) {
|
||||
let value = item.key === 'textAlign' ? item.value : (item.value as number[])[item.select ? 1 : 0];
|
||||
(state.innerElement as Record<string, any>)[item.key || ""] = value
|
||||
let value = item.key === 'textAlign' ? item.value : (item.value as number[])[item.select ? 1 : 0]
|
||||
;(state.innerElement as Record<string, any>)[item.key || ''] = value
|
||||
// TODO: 对竖版文字的特殊处理
|
||||
item.key === 'writingMode' && relationChange()
|
||||
await nextTick()
|
||||
@ -291,7 +281,7 @@ defineExpose({
|
||||
textStyleAction,
|
||||
finish,
|
||||
layerAction,
|
||||
alignAction
|
||||
alignAction,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-04-05 07:31:45
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-22 20:47:43
|
||||
* @LastEditTime: 2024-08-12 05:30:15
|
||||
*/
|
||||
// const prefix = import.meta.env
|
||||
const prefix = process.env
|
||||
@ -16,10 +16,9 @@ export default {
|
||||
BASE_URL: isDev ? '/' : './',
|
||||
VERSION: version,
|
||||
APP_NAME: '迅排设计',
|
||||
COPYRIGHT: 'ShawnPhang - Palxp.cn',
|
||||
// API_URL: isDev ? 'http://localhost:9998' : '${API}',
|
||||
API_URL: 'https://palxp.cn:8887', // 服务端地址
|
||||
SCREEN_URL: isDev ? 'http://localhost:7001' : '#{SCREEN_URL}', // 截图服务地址
|
||||
COPYRIGHT: 'ShawnPhang - Design.pPalxp.cn',
|
||||
API_URL: isDev ? 'http://localhost:7001' : '', // 后端地址
|
||||
SCREEN_URL: isDev ? 'http://localhost:7001' : '', // 截图服务地址
|
||||
IMG_URL: 'https://store.palxp.cn/', // 七牛云资源地址
|
||||
// ICONFONT_URL: '//at.alicdn.com/t/font_3223711_74mlzj4jdue.css',
|
||||
ICONFONT_URL: '//at.alicdn.com/t/font_2717063_ypy8vprc3b.css?display=swap',
|
||||
|
@ -3,10 +3,10 @@
|
||||
* @Date: 2024-05-19 05:14:10
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-05-19 05:15:09
|
||||
* @LastEditTime: 2024-08-12 15:52:36
|
||||
*/
|
||||
export default {
|
||||
logout: '退出登录',
|
||||
save: '保存',
|
||||
download: '下载作品',
|
||||
download: '下载模版',
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-04-05 06:23:23
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-05-06 11:59:28
|
||||
* @LastEditTime: 2024-08-12 09:27:06
|
||||
*/
|
||||
export type TScreeData = {
|
||||
/** 记录编辑界面的宽度 */
|
||||
@ -51,7 +51,7 @@ export type TStoreAction = {
|
||||
updatePageData<T extends keyof TPageState>(data: {
|
||||
key: T
|
||||
value: TPageState[T]
|
||||
pushHistory?: boolean
|
||||
// pushHistory?: boolean
|
||||
}): void
|
||||
getDPage(data: TPageState): () => TPageState
|
||||
/** 设置dPage */
|
||||
|
@ -4,7 +4,7 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description: 画布全局配置
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-05-06 12:05:02
|
||||
* @LastEditTime: 2024-08-12 09:27:22
|
||||
*/
|
||||
|
||||
import { Store, defineStore } from 'pinia'
|
||||
@ -61,9 +61,9 @@ const CanvasStore = defineStore<"canvasStore", TCanvasState, {}, TStoreAction>("
|
||||
// this.dPage.tag = tag === 0 ? 0.01 : 0
|
||||
},
|
||||
/** 更新 Page 字段 */
|
||||
updatePageData({ key, value, pushHistory }) {
|
||||
updatePageData({ key, value }) {
|
||||
const data = this.dPage
|
||||
if (data[key] !== value || pushHistory) {
|
||||
if (data[key] !== value) {
|
||||
data[key] = value
|
||||
}
|
||||
},
|
||||
|
@ -3,8 +3,8 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-18 21:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:27:45
|
||||
*/
|
||||
|
||||
import { useHistoryStore } from "@/store";
|
||||
@ -92,20 +92,18 @@ const ControlStore = defineStore<"controlStore", TControlState, {}, TControlAct
|
||||
},
|
||||
/** 组件调整结束 */
|
||||
stopDResize() {
|
||||
if (this.dResizeing) {
|
||||
const historyStore = useHistoryStore()
|
||||
historyStore.pushHistory('stopDResize')
|
||||
// store.dispatch('pushHistory', 'stopDResize')
|
||||
}
|
||||
// if (this.dResizeing) {
|
||||
// // store.dispatch('pushHistory', 'stopDResize')
|
||||
// }
|
||||
this.dResizeing = false
|
||||
},
|
||||
/** 组件移动结束 */
|
||||
stopDMove() {
|
||||
if (this.dMoving) {
|
||||
const historyStore = useHistoryStore()
|
||||
historyStore.pushHistory("stopDMove")
|
||||
// store.dispatch('pushHistory', 'stopDMove')
|
||||
}
|
||||
// if (this.dMoving) {
|
||||
// const historyStore = useHistoryStore()
|
||||
// historyStore.pushHistory("stopDMove")
|
||||
// // store.dispatch('pushHistory', 'stopDMove')
|
||||
// }
|
||||
this.dMoving = false
|
||||
},
|
||||
setCropUuid(uuid: string) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-28 14:00:00
|
||||
* @Description:
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-28 14:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:28:15
|
||||
*/
|
||||
|
||||
import { customAlphabet } from 'nanoid/non-secure'
|
||||
@ -78,10 +78,6 @@ export function realCombined(store: TGroupStore) {
|
||||
group.height = Number(bottom - top)
|
||||
widgetStore.dActiveElement = group
|
||||
widgetStore.dSelectWidgets = []
|
||||
|
||||
historyStore.pushHistory('realCombined')
|
||||
// store.dispatch('pushHistory', 'realCombined')
|
||||
// store.dispatch('reChangeCanvas')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,14 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-18 18:17:13
|
||||
* @LastEditTime: 2024-08-12 09:29:10
|
||||
*/
|
||||
|
||||
import { useCanvasStore, useWidgetStore } from "@/store"
|
||||
import { THistoryStore } from ".."
|
||||
|
||||
/** push操作历史记录 */
|
||||
/** push操作历史记录(历史记录功能已重构,该方法不再使用) */
|
||||
export function pushHistory(store: THistoryStore, msg: string = "") {
|
||||
console.error('历史记录功能已重构,该方法即将移除:pushHistory');
|
||||
|
||||
// const pageStore = useCanvasStore()
|
||||
// const widgetStore = useWidgetStore()
|
||||
// console.log('history压栈', '来源: ' + msg)
|
||||
|
@ -3,11 +3,11 @@
|
||||
* @Date: 2024-03-18 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-18 15:41:25
|
||||
* @LastEditTime: 2024-08-12 09:28:41
|
||||
*/
|
||||
|
||||
import { Store, defineStore } from 'pinia'
|
||||
import { pushHistory, pushColorToHistory } from './actions/pushHistory'
|
||||
import { pushColorToHistory } from './actions/pushHistory'
|
||||
import handleHistory from './actions/handleHistory'
|
||||
import { useCanvasStore, useWidgetStore } from '@/store'
|
||||
|
||||
@ -36,7 +36,6 @@ type THistoryState = {
|
||||
}
|
||||
|
||||
type THistoryAction = {
|
||||
pushHistory: (msg?: string) => void
|
||||
/** 写入历史记录 */
|
||||
changeHistory: (patches: any) => void
|
||||
/**
|
||||
@ -67,9 +66,6 @@ const HistoryStore = defineStore<'historyStore', THistoryState, {}, THistoryActi
|
||||
}),
|
||||
|
||||
actions: {
|
||||
pushHistory(msg) {
|
||||
pushHistory(this, msg)
|
||||
},
|
||||
changeHistory({ patches, inversePatches }) {
|
||||
const pointer = ++this.dHistoryParams.stackPointer
|
||||
// 如若之前撤销过,当新增记录时,后面的记录就清空了
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-28 14:00:00
|
||||
* @Description:
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-28 14:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:29:27
|
||||
*/
|
||||
|
||||
import { useCanvasStore, useHistoryStore } from "@/store"
|
||||
@ -82,8 +82,6 @@ export function updateAlign(store: TWidgetStore, { align, uuid, group }: TUpdate
|
||||
target.left = left
|
||||
target.top = top
|
||||
|
||||
historyStore.pushHistory("updateAlign")
|
||||
// store.dispatch('pushHistory', 'updateAlign')
|
||||
canvasStore.reChangeCanvas()
|
||||
// store.dispatch('reChangeCanvas')
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @Author: Jeremy Yu
|
||||
* @Date: 2024-03-28 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: Jeremy Yu <https://github.com/JeremyYu-cn>
|
||||
* @LastEditTime: 2024-03-28 14:00:00
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-08-12 09:29:31
|
||||
*/
|
||||
|
||||
import { useCanvasStore, useHistoryStore } from "@/store"
|
||||
@ -29,8 +29,6 @@ export function addGroup(store: TWidgetStore, group: TdWidgetData[]) {
|
||||
const len = store.dWidgets.length
|
||||
store.dActiveElement = store.dWidgets[len - 1]
|
||||
|
||||
historyStore.pushHistory("addGroup")
|
||||
// store.dispatch('pushHistory', 'addGroup')
|
||||
canvasStore.reChangeCanvas()
|
||||
// store.dispatch('reChangeCanvas')
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
* @Date: 2024-03-28 21:00:00
|
||||
* @Description:
|
||||
* @LastEditors: ShawnPhang <https://m.palxp.cn>
|
||||
* @LastEditTime: 2024-04-16 01:03:05
|
||||
* @LastEditTime: 2024-08-12 09:29:35
|
||||
*/
|
||||
|
||||
|
||||
@ -23,6 +23,5 @@ export function setTemplate(store: TWidgetStore, allWidgets: TdWidgetData[]) {
|
||||
store.dWidgets.push(item)
|
||||
})
|
||||
widgetStore.updateDWidgets()
|
||||
// historyStore.pushHistory("setTemplate")
|
||||
canvasStore.reChangeCanvas()
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user