mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
Merge branch 'master' into fix_reset
This commit is contained in:
commit
8c0c290102
@ -66,6 +66,7 @@ module.exports = {
|
|||||||
'no-alert': isProduction ? 'error' : 'warn',
|
'no-alert': isProduction ? 'error' : 'warn',
|
||||||
'no-console': isProduction ? 'error' : 'warn',
|
'no-console': isProduction ? 'error' : 'warn',
|
||||||
'no-debugger': isProduction ? 'error' : 'warn',
|
'no-debugger': isProduction ? 'error' : 'warn',
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
17
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Bug反馈
|
||||||
|
about: 'Bug report'
|
||||||
|
title: "[Bug report]"
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**问题描述**
|
||||||
|
请尽量简洁、完整地描述你遇到的bug,至少包括以下部分(如有必要,可提供截图):
|
||||||
|
1. 问题触发的条件/操作流程
|
||||||
|
2. 期望表现与实际表现
|
||||||
|
|
||||||
|
**环境信息**
|
||||||
|
至少包含以下部分:
|
||||||
|
1. 系统环境(Mac or Windows)
|
||||||
|
2. 浏览器环境(如:Chrome v89.0.4389.114)
|
28
.github/workflows/deploy.yml
vendored
Normal file
28
.github/workflows/deploy.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Use Node.js v14.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '14.x'
|
||||||
|
|
||||||
|
- name: Install and Build
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
- name: Deploy to github pages
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.PPTIST }}
|
||||||
|
commit_message: deploy to github pages
|
||||||
|
publish_dir: ./dist
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
|
100
README.md
100
README.md
@ -1,11 +1,11 @@
|
|||||||
# 🎨 PPTist
|
# 🎨 PPTist
|
||||||
> 一个基于 Vue3.x + TypeScript 的在线演示文稿应用,还原了大部分PPT常用功能,支持 文字、图片、形状、线条、图表、表格 6种最常用的元素类型,每一种元素都拥有高度可编辑能力,同时支持丰富的快捷键和右键菜单,尽可能还原本地桌面应用的使用体验。
|
> 一个基于 Vue3.x + TypeScript 的在线演示文稿应用,还原了大部分PPT常用功能,支持 文字、图片、形状、线条、图表、表格 6种最常用的元素类型,每一种元素都拥有高度可编辑能力,同时支持丰富的快捷键和右键菜单,尽可能还原本地桌面应用的使用体验。
|
||||||
|
|
||||||
在线体验地址:https://pipipi-pikachu.github.io/PPTist/
|
在线体验地址:[https://pipipi-pikachu.github.io/PPTist/](https://pipipi-pikachu.github.io/PPTist/)
|
||||||
|
|
||||||
如果网络状态不佳,可以访问国内镜像:https://pptist.gitee.io/
|
如果网络状态不佳,可以访问国内镜像:[https://pptist.gitee.io/](https://pptist.gitee.io/)
|
||||||
|
|
||||||
Github仓库:https://github.com/pipipi-pikachu/PPTist
|
Github仓库:[https://github.com/pipipi-pikachu/PPTist](https://github.com/pipipi-pikachu/PPTist)
|
||||||
|
|
||||||
|
|
||||||
# 🚀 项目运行
|
# 🚀 项目运行
|
||||||
@ -17,21 +17,20 @@ npm run serve
|
|||||||
|
|
||||||
|
|
||||||
# 📚 功能列表
|
# 📚 功能列表
|
||||||
## 通用功能
|
### 通用功能
|
||||||
- 历史记录
|
- 历史记录(撤销、重做)
|
||||||
- 快捷键
|
- 快捷键
|
||||||
- 右键菜单
|
- 右键菜单
|
||||||
|
### 幻灯片页面编辑
|
||||||
## 幻灯片页面编辑
|
|
||||||
- 页面添加、删除
|
- 页面添加、删除
|
||||||
- 页面顺序调整
|
- 页面顺序调整
|
||||||
- 页面复制粘贴
|
- 页面复制粘贴
|
||||||
- 背景设置(纯色、渐变、图片)
|
- 背景设置(纯色、渐变、图片)
|
||||||
- 网格线
|
- 网格线
|
||||||
|
- 画布缩放
|
||||||
- 主题设置
|
- 主题设置
|
||||||
- 幻灯片备注
|
- 幻灯片备注
|
||||||
|
### 幻灯片元素编辑
|
||||||
## 幻灯片元素编辑
|
|
||||||
- 元素添加、删除
|
- 元素添加、删除
|
||||||
- 元素复制粘贴
|
- 元素复制粘贴
|
||||||
- 元素拖拽移动
|
- 元素拖拽移动
|
||||||
@ -44,11 +43,11 @@ npm run serve
|
|||||||
- 元素层级调整
|
- 元素层级调整
|
||||||
- 元素对齐到画布
|
- 元素对齐到画布
|
||||||
- 元素对齐到其他元素
|
- 元素对齐到其他元素
|
||||||
|
- 多元素均匀分布
|
||||||
- 拖拽添加图文
|
- 拖拽添加图文
|
||||||
- 粘贴外部图片
|
- 粘贴外部图片
|
||||||
- 元素坐标、尺寸和旋转角度设置
|
- 元素坐标、尺寸和旋转角度设置
|
||||||
|
#### 文字
|
||||||
### 文字
|
|
||||||
- 富文本编辑(颜色、高亮、字体、字号、加粗、斜体、下划线、删除线、角标、行内代码、引用、对齐方式、项目符号、清除格式)
|
- 富文本编辑(颜色、高亮、字体、字号、加粗、斜体、下划线、删除线、角标、行内代码、引用、对齐方式、项目符号、清除格式)
|
||||||
- 行高
|
- 行高
|
||||||
- 字间距
|
- 字间距
|
||||||
@ -56,7 +55,7 @@ npm run serve
|
|||||||
- 边框
|
- 边框
|
||||||
- 阴影
|
- 阴影
|
||||||
- 透明度
|
- 透明度
|
||||||
### 图片
|
#### 图片
|
||||||
- 裁剪(自定义、按形状、按纵横比)
|
- 裁剪(自定义、按形状、按纵横比)
|
||||||
- 滤镜
|
- 滤镜
|
||||||
- 翻转
|
- 翻转
|
||||||
@ -65,43 +64,37 @@ npm run serve
|
|||||||
- 替换图片
|
- 替换图片
|
||||||
- 重置图片
|
- 重置图片
|
||||||
- 设置为背景图
|
- 设置为背景图
|
||||||
### 形状
|
#### 形状
|
||||||
- 填充色
|
- 填充色
|
||||||
- 边框
|
- 边框
|
||||||
- 阴影
|
- 阴影
|
||||||
- 透明度
|
- 透明度
|
||||||
- 翻转
|
- 翻转
|
||||||
### 线条
|
#### 线条
|
||||||
- 颜色
|
- 颜色
|
||||||
- 宽度
|
- 宽度
|
||||||
- 样式
|
- 样式
|
||||||
- 端点样式
|
- 端点样式
|
||||||
### 图表(柱状图、折线图、饼图)
|
#### 图表(柱状图、折线图、饼图)
|
||||||
- 数据编辑
|
- 数据编辑
|
||||||
- 背景填充
|
- 背景填充
|
||||||
- 主题色
|
- 主题色
|
||||||
- 坐标系与坐标文字颜色
|
- 坐标系与坐标文字颜色
|
||||||
- 其他设置(柱状图转条形图、折线图转面积图、折线图转散点图、饼图转环形图、折线图开关平滑曲线)
|
- 其他设置(柱状图转条形图、折线图转面积图、折线图转散点图、饼图转环形图、折线图开关平滑曲线)
|
||||||
- 边框
|
- 边框
|
||||||
### 表格
|
#### 表格
|
||||||
- 行、列添加删除
|
- 行、列添加删除
|
||||||
- 行列数设置
|
- 行列数设置
|
||||||
- 主题设置(主题色、表头、汇总行、第一列、最后一列)
|
- 主题设置(主题色、表头、汇总行、第一列、最后一列)
|
||||||
- 合并单元格
|
- 合并单元格
|
||||||
- 单元格样式(填充色、文字颜色、加粗、斜体、下划线、删除线、对齐方式)
|
- 单元格样式(填充色、文字颜色、加粗、斜体、下划线、删除线、对齐方式)
|
||||||
- 边框
|
- 边框
|
||||||
## 幻灯片放映
|
### 幻灯片放映
|
||||||
- 翻页动画
|
- 翻页动画
|
||||||
- 元素入场动画
|
- 元素入场动画
|
||||||
- 全部幻灯片预览
|
- 全部幻灯片预览
|
||||||
- 画笔工具
|
- 画笔工具
|
||||||
|
|
||||||
# 📃 TODO
|
|
||||||
- [ ] 幻灯片模板
|
|
||||||
- [ ] 图表缩略图优化
|
|
||||||
- [ ] 公式元素
|
|
||||||
- [ ] 导出(PPT、PDF、图片、JSON)
|
|
||||||
- [ ] 导入(PPT)
|
|
||||||
|
|
||||||
# 💡 常见问题
|
# 💡 常见问题
|
||||||
**Q. 为什么xxx快捷键没有作用?**
|
**Q. 为什么xxx快捷键没有作用?**
|
||||||
@ -128,32 +121,55 @@ A. 由于本演示项目不依赖后端,插入本地图片实际引用的是Ba
|
|||||||
|
|
||||||
A. 设置预置主题的作用是使新添加的元素和页面应用主题样式,不会对已有的元素和页面生效(字体颜色除外),您可以使用“应用主题到全部”功能,将当前主题应用到当前全部页面中。
|
A. 设置预置主题的作用是使新添加的元素和页面应用主题样式,不会对已有的元素和页面生效(字体颜色除外),您可以使用“应用主题到全部”功能,将当前主题应用到当前全部页面中。
|
||||||
|
|
||||||
|
**Q. 设置在线字体不生效?**
|
||||||
|
|
||||||
# 🔧 项目依赖
|
A. 设置在线字体时会下载对应的字体文件,该文件较大,需要等待下载完成后才会应用新的字体。
|
||||||
|
|
||||||
`ant-design-vue` -- UI库
|
|
||||||
|
|
||||||
`lodash` -- 工具库
|
# 📁 项目目录结构
|
||||||
|
```
|
||||||
|
├── assets // 静态资源
|
||||||
|
│ ├── fonts // 在线字体文件
|
||||||
|
│ └── styles // 样式
|
||||||
|
│ ├── antd.scss // antd默认样式覆盖
|
||||||
|
│ ├── font.scss // 在线字体定义
|
||||||
|
│ ├── global.scss // 通用全局样式
|
||||||
|
│ ├── mixin.scss // scss全局混入
|
||||||
|
│ ├── variable.scss // scss全局变量
|
||||||
|
│ └── prosemirror.scss // ProseMirror 富文本默认样式
|
||||||
|
├── components // 与业务逻辑无关的通用组件
|
||||||
|
├── configs // 配置文件,如:画布尺寸、字体、动画配置、快捷键配置、预置形状、预置线条等数据。
|
||||||
|
├── hooks // 供多个组件(模块)使用的 hooks 方法
|
||||||
|
├── mocks // mocks 数据
|
||||||
|
├── plugins // 自定义的 Vue 插件
|
||||||
|
├── prosemirror // ProseMirror 富文本编辑器相关的文件
|
||||||
|
├── types // 类型定义文件
|
||||||
|
├── store // Vuex store,参考:https://vuex.vuejs.org/zh/guide/
|
||||||
|
├── utils // 通用的工具方法
|
||||||
|
└── views // 业务组件目录,分为 `编辑器` 和 `播放器` 两个部分。
|
||||||
|
├── components // 公用的业务组件
|
||||||
|
├── Editor // 编辑器模块
|
||||||
|
└── Screen // 播放器模块
|
||||||
|
```
|
||||||
|
|
||||||
`prosemirror` -- 富文本编辑框架,用于文本元素的富文本编辑
|
|
||||||
|
|
||||||
`chartist` -- svg图表库,用于图表元素
|
# 💿 数据
|
||||||
|
幻灯片的数据主要由 `slides` 和 `theme` 两部分组成。
|
||||||
|
> 换句话说,在实际的生产环境中,一般只需要存储这两项数据即可。
|
||||||
|
|
||||||
`tinycolor2` -- 颜色处理工具
|
- `slides` 表示幻灯片页面数据,包括每一页的ID、元素内容、备注、背景、动画、切页方式等信息
|
||||||
|
- `theme` 表示幻灯片主题数据,包括背景色、主题色、字体颜色、字体等信息
|
||||||
|
|
||||||
`dexie` -- indexedDB 包装器,用于记录历史操作
|
具体类型的定义可见:[https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts](https://github.com/pipipi-pikachu/PPTist/blob/master/src/types/slides.ts)
|
||||||
|
|
||||||
`mitt` -- 自定义事件发射/监听
|
|
||||||
|
|
||||||
`animate.css` -- CSS动画库
|
# 📃 TODO
|
||||||
|
- [ ] 幻灯片模板
|
||||||
|
- [ ] 图表缩略图优化
|
||||||
|
- [ ] 公式元素
|
||||||
|
- [ ] 导出、导入
|
||||||
|
|
||||||
`vuedraggable` -- 基于vue的拖拽插件,用于调整页面顺序等
|
> 作为一个在线幻灯片,导出、导入PPTX文件是非常重要的功能。但是经过本人一段时间的调研发现,该功能实现起来的复杂度远超过了预期。由于个人时间有限,暂时可能无法集中精力来做该功能,短时间内还是会更多优先去提升其他方面的使用体验。如果有做过相关内容的朋友,也欢迎给我提建议。
|
||||||
|
|
||||||
`crypto-js` -- 加密函数库,用于加解密剪贴板内容
|
|
||||||
|
|
||||||
`clipboard` -- 用于复制内容到剪贴板
|
|
||||||
|
|
||||||
`icon-park` -- 图标库
|
|
||||||
|
|
||||||
|
|
||||||
# 💻 贡献代码
|
# 💻 贡献代码
|
||||||
@ -169,12 +185,12 @@ A. 设置预置主题的作用是使新添加的元素和页面应用主题样
|
|||||||
- 对于较大的新功能,你需要先提交 Issues,例如 ‘添加 XXX 功能’,确认该功能有被添加的必要后,再开始工作;
|
- 对于较大的新功能,你需要先提交 Issues,例如 ‘添加 XXX 功能’,确认该功能有被添加的必要后,再开始工作;
|
||||||
- 其他如简单的体验或代码优化、文档修正等,只要修改合理都会被接受。
|
- 其他如简单的体验或代码优化、文档修正等,只要修改合理都会被接受。
|
||||||
|
|
||||||
### 最后,感谢每一位贡献者:
|
在此,感谢每一位贡献者。
|
||||||
- [lhyUnited](https://github.com/lhyUnited)
|
|
||||||
|
|
||||||
|
|
||||||
# 📄 开源协议
|
# 📄 开源协议
|
||||||
[MIT License](https://github.com/pipipi-pikachu/PPTist/blob/master/LICENSE)
|
[MIT License](https://github.com/pipipi-pikachu/PPTist/blob/master/LICENSE)
|
||||||
|
|
||||||
|
|
||||||
# 💣 友情提示
|
# 💣 友情提示
|
||||||
本项目不接受任何形式的私人咨询,有任何问题欢迎在 github 提交你的 Issues
|
本项目不接受任何形式的私人咨询,有任何问题 [欢迎在 github 提交你的 Issues](https://github.com/pipipi-pikachu/PPTist/issues)
|
1
dist/css/app.abb643bc.css
vendored
1
dist/css/app.abb643bc.css
vendored
File diff suppressed because one or more lines are too long
7
dist/css/chunk-vendors.9281d9df.css
vendored
7
dist/css/chunk-vendors.9281d9df.css
vendored
File diff suppressed because one or more lines are too long
BIN
dist/favicon.ico
vendored
BIN
dist/favicon.ico
vendored
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
BIN
dist/fonts/仓耳小丸子.676e187a.ttf
vendored
BIN
dist/fonts/仓耳小丸子.676e187a.ttf
vendored
Binary file not shown.
BIN
dist/fonts/优设标题黑.1726685c.ttf
vendored
BIN
dist/fonts/优设标题黑.1726685c.ttf
vendored
Binary file not shown.
BIN
dist/fonts/峰广明锐体.8bdb14f7.ttf
vendored
BIN
dist/fonts/峰广明锐体.8bdb14f7.ttf
vendored
Binary file not shown.
BIN
dist/fonts/摄图摩登小方体.de722238.ttf
vendored
BIN
dist/fonts/摄图摩登小方体.de722238.ttf
vendored
Binary file not shown.
BIN
dist/fonts/站酷快乐体.0aceab97.ttf
vendored
BIN
dist/fonts/站酷快乐体.0aceab97.ttf
vendored
Binary file not shown.
BIN
dist/fonts/站酷酷黑体.6b4f114c.ttf
vendored
BIN
dist/fonts/站酷酷黑体.6b4f114c.ttf
vendored
Binary file not shown.
BIN
dist/fonts/素材集市康康体.8db9d61f.ttf
vendored
BIN
dist/fonts/素材集市康康体.8db9d61f.ttf
vendored
Binary file not shown.
BIN
dist/fonts/联盟起艺卢帅正锐黑体.42cb84f9.ttf
vendored
BIN
dist/fonts/联盟起艺卢帅正锐黑体.42cb84f9.ttf
vendored
Binary file not shown.
BIN
dist/fonts/谦度手写楷体.7bfb15ee.ttf
vendored
BIN
dist/fonts/谦度手写楷体.7bfb15ee.ttf
vendored
Binary file not shown.
BIN
dist/fonts/途牛类圆体.abaea3c4.ttf
vendored
BIN
dist/fonts/途牛类圆体.abaea3c4.ttf
vendored
Binary file not shown.
BIN
dist/fonts/锐字真言体.1583afec.ttf
vendored
BIN
dist/fonts/锐字真言体.1583afec.ttf
vendored
Binary file not shown.
BIN
dist/fonts/问藏书房.59a94370.ttf
vendored
BIN
dist/fonts/问藏书房.59a94370.ttf
vendored
Binary file not shown.
1
dist/index.html
vendored
1
dist/index.html
vendored
@ -1 +0,0 @@
|
|||||||
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="renderer" content="webkit"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>PPTIST - 在线演示文稿</title><link href="css/app.abb643bc.css" rel="preload" as="style"><link href="css/chunk-vendors.9281d9df.css" rel="preload" as="style"><link href="js/app.42e95de6.js" rel="preload" as="script"><link href="js/chunk-vendors.cdb8e65d.js" rel="preload" as="script"><link href="css/chunk-vendors.9281d9df.css" rel="stylesheet"><link href="css/app.abb643bc.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but pptist doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>document.oncontextmenu = e => e.preventDefault()</script><script src="js/chunk-vendors.cdb8e65d.js"></script><script src="js/app.42e95de6.js"></script></body></html>
|
|
2
dist/js/app.42e95de6.js
vendored
2
dist/js/app.42e95de6.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/app.42e95de6.js.map
vendored
1
dist/js/app.42e95de6.js.map
vendored
File diff suppressed because one or more lines are too long
326
dist/js/chunk-vendors.cdb8e65d.js
vendored
326
dist/js/chunk-vendors.cdb8e65d.js
vendored
File diff suppressed because one or more lines are too long
1
dist/js/chunk-vendors.cdb8e65d.js.map
vendored
1
dist/js/chunk-vendors.cdb8e65d.js.map
vendored
File diff suppressed because one or more lines are too long
490
package-lock.json
generated
490
package-lock.json
generated
@ -6,8 +6,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design-vue/use": {
|
"@ant-design-vue/use": {
|
||||||
"version": "0.0.1-alpha.9",
|
"version": "0.0.1-alpha.9",
|
||||||
"resolved": "https://registry.npm.taobao.org/@ant-design-vue/use/download/@ant-design-vue/use-0.0.1-alpha.9.tgz",
|
"resolved": "https://registry.npmjs.org/@ant-design-vue/use/-/use-0.0.1-alpha.9.tgz",
|
||||||
"integrity": "sha1-t98mFQRpORODuhwt1LolAmelhBE=",
|
"integrity": "sha512-X+ESJt+e95sRwlSkpzETjc0opE5l34tCjMEm92JkoM4BVl6YxG9IgyX1dBy0W2jF74SSCOiCc7GdIlsPFQvE/g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async-validator": "^3.4.0",
|
"async-validator": "^3.4.0",
|
||||||
"lodash-es": "^4.17.15",
|
"lodash-es": "^4.17.15",
|
||||||
@ -17,21 +17,21 @@
|
|||||||
},
|
},
|
||||||
"@ant-design/colors": {
|
"@ant-design/colors": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-5.1.1.tgz",
|
||||||
"integrity": "sha1-gAshhrHifmZDLmfQPtlq8+IdiUA=",
|
"integrity": "sha512-Txy4KpHrp3q4XZdfgOBqLl+lkQIc3tEvHXOimRN1giX1AEC7mGtyrO9p8iRGJ3FLuVMGa2gNEzQyghVymLttKQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ctrl/tinycolor": "^3.3.1"
|
"@ctrl/tinycolor": "^3.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ant-design/icons-svg": {
|
"@ant-design/icons-svg": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@ant-design/icons-svg/download/@ant-design/icons-svg-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.1.0.tgz",
|
||||||
"integrity": "sha1-SAsCX0sg73/o9H1KSEbk/uhOoGw="
|
"integrity": "sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ=="
|
||||||
},
|
},
|
||||||
"@ant-design/icons-vue": {
|
"@ant-design/icons-vue": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@ant-design/icons-vue/download/@ant-design/icons-vue-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-6.0.1.tgz",
|
||||||
"integrity": "sha1-nYBMPHTSz6+XyxjlgtO5QAk09f0=",
|
"integrity": "sha512-HigIgEVV6bbcrz2A92/qDzi/aKWB5EC6b6E1mxMB6aQA7ksiKY+gi4U94TpqyEIIhR23uaDrjufJ+xCZQ+vx6Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ant-design/colors": "^5.0.0",
|
"@ant-design/colors": "^5.0.0",
|
||||||
"@ant-design/icons-svg": "^4.0.0",
|
"@ant-design/icons-svg": "^4.0.0",
|
||||||
@ -1412,8 +1412,8 @@
|
|||||||
},
|
},
|
||||||
"@ctrl/tinycolor": {
|
"@ctrl/tinycolor": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@ctrl/tinycolor/download/@ctrl/tinycolor-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
|
||||||
"integrity": "sha1-w8WuVDyJfKqcKmhjC+01W+X5mQ8="
|
"integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
|
||||||
},
|
},
|
||||||
"@hapi/address": {
|
"@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
@ -1912,12 +1912,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@simonwep/pickr": {
|
"@simonwep/pickr": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@simonwep/pickr/download/@simonwep/pickr-1.8.0.tgz?cache=0&sync_timestamp=1607168186154&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40simonwep%2Fpickr%2Fdownload%2F%40simonwep%2Fpickr-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.1.tgz",
|
||||||
"integrity": "sha1-rb/5pPfw5Z3smUZQjF5IG3q64Pg=",
|
"integrity": "sha512-3Q5+INWW0Py+/E9hgy0cyD0/0w/yGZbkxam6RzFVFDOEHgAqMVJR+x9znx58/ky/ZIvE/78FbH189yIC9h111A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js": "^3.8.0",
|
"core-js": "^3.12.1",
|
||||||
"nanopop": "^2.1.0"
|
"nanopop": "^2.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"core-js": {
|
||||||
|
"version": "3.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.12.1.tgz",
|
||||||
|
"integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@soda/friendly-errors-webpack-plugin": {
|
"@soda/friendly-errors-webpack-plugin": {
|
||||||
@ -2153,12 +2160,6 @@
|
|||||||
"integrity": "sha1-OkvSRRiw5sWUDaTiZZ7rLvCAaWM=",
|
"integrity": "sha1-OkvSRRiw5sWUDaTiZZ7rLvCAaWM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/eslint-visitor-keys": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/eslint-visitor-keys/download/@types/eslint-visitor-keys-1.0.0.tgz?cache=0&sync_timestamp=1613379039201&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Feslint-visitor-keys%2Fdownload%2F%40types%2Feslint-visitor-keys-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-HuMNeVRMqE1o1LPNsK9PIFZj3S0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/express": {
|
"@types/express": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.11",
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/express/download/@types/express-4.17.11.tgz?cache=0&sync_timestamp=1613378518678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fexpress%2Fdownload%2F%40types%2Fexpress-4.17.11.tgz",
|
"resolved": "https://registry.npm.taobao.org/@types/express/download/@types/express-4.17.11.tgz?cache=0&sync_timestamp=1613378518678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fexpress%2Fdownload%2F%40types%2Fexpress-4.17.11.tgz",
|
||||||
@ -2248,9 +2249,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
"version": "4.14.168",
|
"version": "4.14.169",
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/lodash/download/@types/lodash-4.14.168.tgz?cache=0&sync_timestamp=1613379222224&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Flodash%2Fdownload%2F%40types%2Flodash-4.14.168.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.169.tgz",
|
||||||
"integrity": "sha1-/iRjLnm3rePxMoka//hsql5c4Ag="
|
"integrity": "sha512-DvmZHoHTFJ8zhVYwCLWbQ7uAbYQEk52Ev2/ZiQ7Y7gQGeV9pjBqjnQpECMHfKS1rCYAhMI7LHVxwyZLZinJgdw=="
|
||||||
},
|
},
|
||||||
"@types/mdast": {
|
"@types/mdast": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
@ -2578,56 +2579,339 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "2.34.0",
|
"version": "4.23.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-2.34.0.tgz?cache=0&sync_timestamp=1616464424176&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Feslint-plugin%2Fdownload%2F%40typescript-eslint%2Feslint-plugin-2.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz",
|
||||||
"integrity": "sha1-b4zopGx96kpvHRcdK7j7rm2sK+k=",
|
"integrity": "sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@typescript-eslint/experimental-utils": "2.34.0",
|
"@typescript-eslint/experimental-utils": "4.23.0",
|
||||||
|
"@typescript-eslint/scope-manager": "4.23.0",
|
||||||
|
"debug": "^4.1.1",
|
||||||
"functional-red-black-tree": "^1.0.1",
|
"functional-red-black-tree": "^1.0.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
"regexpp": "^3.0.0",
|
"regexpp": "^3.0.0",
|
||||||
|
"semver": "^7.3.2",
|
||||||
"tsutils": "^3.17.1"
|
"tsutils": "^3.17.1"
|
||||||
}
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.stat": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"@typescript-eslint/experimental-utils": {
|
"@typescript-eslint/experimental-utils": {
|
||||||
"version": "2.34.0",
|
"version": "4.23.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@typescript-eslint/experimental-utils/download/@typescript-eslint/experimental-utils-2.34.0.tgz?cache=0&sync_timestamp=1616464293813&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40typescript-eslint%2Fexperimental-utils%2Fdownload%2F%40typescript-eslint%2Fexperimental-utils-2.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz",
|
||||||
"integrity": "sha1-01JLZEzbQO687KZ/jPPkzJyPmA8=",
|
"integrity": "sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/json-schema": "^7.0.3",
|
"@types/json-schema": "^7.0.3",
|
||||||
"@typescript-eslint/typescript-estree": "2.34.0",
|
"@typescript-eslint/scope-manager": "4.23.0",
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||||
"eslint-scope": "^5.0.0",
|
"eslint-scope": "^5.0.0",
|
||||||
"eslint-utils": "^2.0.0"
|
"eslint-utils": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@typescript-eslint/parser": {
|
|
||||||
"version": "2.34.0",
|
|
||||||
"resolved": "https://registry.npm.taobao.org/@typescript-eslint/parser/download/@typescript-eslint/parser-2.34.0.tgz",
|
|
||||||
"integrity": "sha1-UCUmMMoxloVCDpo5ygX+GFola8g=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/eslint-visitor-keys": "^1.0.0",
|
|
||||||
"@typescript-eslint/experimental-utils": "2.34.0",
|
|
||||||
"@typescript-eslint/typescript-estree": "2.34.0",
|
|
||||||
"eslint-visitor-keys": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@typescript-eslint/typescript-estree": {
|
"@typescript-eslint/typescript-estree": {
|
||||||
"version": "2.34.0",
|
"version": "4.23.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-2.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
|
||||||
"integrity": "sha1-FK62NTs57wcyzH8bgoUpSTfPN9U=",
|
"integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "4.23.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"eslint-visitor-keys": "^1.1.0",
|
"globby": "^11.0.1",
|
||||||
"glob": "^7.1.6",
|
|
||||||
"is-glob": "^4.0.1",
|
"is-glob": "^4.0.1",
|
||||||
"lodash": "^4.17.15",
|
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.2",
|
||||||
"tsutils": "^3.17.1"
|
"tsutils": "^3.17.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"array-union": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"braces": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"fill-range": "^7.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dir-glob": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-type": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fast-glob": {
|
||||||
|
"version": "3.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
|
||||||
|
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
|
"glob-parent": "^5.1.0",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"micromatch": "^4.0.2",
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fill-range": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globby": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-union": "^2.1.0",
|
||||||
|
"dir-glob": "^3.0.1",
|
||||||
|
"fast-glob": "^3.1.1",
|
||||||
|
"ignore": "^5.1.4",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"slash": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore": {
|
||||||
|
"version": "5.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||||
|
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"micromatch": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"braces": "^3.0.1",
|
||||||
|
"picomatch": "^2.2.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slash": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/parser": {
|
||||||
|
"version": "4.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.23.0.tgz",
|
||||||
|
"integrity": "sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/scope-manager": "4.23.0",
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"@typescript-eslint/typescript-estree": "4.23.0",
|
||||||
|
"debug": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/scope-manager": {
|
||||||
|
"version": "4.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz",
|
||||||
|
"integrity": "sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "4.23.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/types": {
|
||||||
|
"version": "4.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.23.0.tgz",
|
||||||
|
"integrity": "sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "4.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz",
|
||||||
|
"integrity": "sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "4.23.0",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"globby": "^11.0.1",
|
||||||
|
"is-glob": "^4.0.1",
|
||||||
|
"semver": "^7.3.2",
|
||||||
|
"tsutils": "^3.17.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.stat": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"array-union": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"braces": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"fill-range": "^7.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dir-glob": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-type": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fast-glob": {
|
||||||
|
"version": "3.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
|
||||||
|
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
|
"glob-parent": "^5.1.0",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"micromatch": "^4.0.2",
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fill-range": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globby": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-union": "^2.1.0",
|
||||||
|
"dir-glob": "^3.0.1",
|
||||||
|
"fast-glob": "^3.1.1",
|
||||||
|
"ignore": "^5.1.4",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"slash": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignore": {
|
||||||
|
"version": "5.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||||
|
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"micromatch": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"braces": "^3.0.1",
|
||||||
|
"picomatch": "^2.2.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slash": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "4.23.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz",
|
||||||
|
"integrity": "sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@typescript-eslint/types": "4.23.0",
|
||||||
|
"eslint-visitor-keys": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"eslint-visitor-keys": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": {
|
"@vue/babel-helper-vue-jsx-merge-props": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz?cache=0&sync_timestamp=1602851135129&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-jsx-merge-props%2Fdownload%2F%40vue%2Fbabel-helper-vue-jsx-merge-props-1.2.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz?cache=0&sync_timestamp=1602851135129&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fbabel-helper-vue-jsx-merge-props%2Fdownload%2F%40vue%2Fbabel-helper-vue-jsx-merge-props-1.2.1.tgz",
|
||||||
@ -3384,9 +3668,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vue/eslint-config-typescript": {
|
"@vue/eslint-config-typescript": {
|
||||||
"version": "5.1.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/@vue/eslint-config-typescript/download/@vue/eslint-config-typescript-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-7.0.0.tgz",
|
||||||
"integrity": "sha1-F+sa9k9j4jH8zspWA4Wb37T11OA=",
|
"integrity": "sha512-UxUlvpSrFOoF8aQ+zX1leYiEBEm7CZmXYn/ZEM1zwSadUzpamx56RB4+Htdjisv1mX2tOjBegNUqH3kz2OL+Aw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"vue-eslint-parser": "^7.0.0"
|
"vue-eslint-parser": "^7.0.0"
|
||||||
@ -3807,9 +4091,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ant-design-vue": {
|
"ant-design-vue": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npm.taobao.org/ant-design-vue/download/ant-design-vue-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.1.6.tgz",
|
||||||
"integrity": "sha1-IGXX5jGZwMWEkZRYr1e2oLWX9nc=",
|
"integrity": "sha512-qICxb6Y4f7QuSuh/jbLhZA9SkUBnP9xYfy/E6yD7+1fg04aAzmRK8oLv8ETuGTrROVdSVeic9v/NS2BXEuuARg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ant-design-vue/use": "^0.0.1-0",
|
"@ant-design-vue/use": "^0.0.1-0",
|
||||||
"@ant-design/icons-vue": "^6.0.0",
|
"@ant-design/icons-vue": "^6.0.0",
|
||||||
@ -3819,7 +4103,7 @@
|
|||||||
"async-validator": "^3.3.0",
|
"async-validator": "^3.3.0",
|
||||||
"dom-align": "^1.10.4",
|
"dom-align": "^1.10.4",
|
||||||
"dom-scroll-into-view": "^2.0.0",
|
"dom-scroll-into-view": "^2.0.0",
|
||||||
"is-mobile": "^2.2.1",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.15",
|
"lodash-es": "^4.17.15",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"omit.js": "^2.0.0",
|
"omit.js": "^2.0.0",
|
||||||
@ -3905,8 +4189,8 @@
|
|||||||
},
|
},
|
||||||
"array-tree-filter": {
|
"array-tree-filter": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
|
||||||
"integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA="
|
"integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
|
||||||
},
|
},
|
||||||
"array-union": {
|
"array-union": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -4031,9 +4315,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"async-validator": {
|
"async-validator": {
|
||||||
"version": "3.5.1",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-3.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
|
||||||
"integrity": "sha1-zWK5aIskZfSEIOJ620d2CrG1VZ8="
|
"integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
|
||||||
},
|
},
|
||||||
"asynckit": {
|
"asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@ -5660,8 +5944,8 @@
|
|||||||
},
|
},
|
||||||
"compute-scroll-into-view": {
|
"compute-scroll-into-view": {
|
||||||
"version": "1.0.17",
|
"version": "1.0.17",
|
||||||
"resolved": "https://registry.npm.taobao.org/compute-scroll-into-view/download/compute-scroll-into-view-1.0.17.tgz?cache=0&sync_timestamp=1614042424875&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcompute-scroll-into-view%2Fdownload%2Fcompute-scroll-into-view-1.0.17.tgz",
|
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz",
|
||||||
"integrity": "sha1-aojxis2dQunPS6pr7H4FImB6t6s="
|
"integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg=="
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
@ -6929,9 +7213,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-align": {
|
"dom-align": {
|
||||||
"version": "1.12.0",
|
"version": "1.12.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/dom-align/download/dom-align-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.1.tgz",
|
||||||
"integrity": "sha1-VvtxVt8LkQmYMDZNLUj4iWP1opw="
|
"integrity": "sha512-CdTD9EdA5WviP8oO3n+okOm0Xt7dSuWxRTLcJiW0memwUr3Tvz66JDDCh9cb50IZFHXvBmLoyX454uJU/EVg+g=="
|
||||||
},
|
},
|
||||||
"dom-converter": {
|
"dom-converter": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
@ -6944,8 +7228,8 @@
|
|||||||
},
|
},
|
||||||
"dom-scroll-into-view": {
|
"dom-scroll-into-view": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/dom-scroll-into-view/download/dom-scroll-into-view-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz",
|
||||||
"integrity": "sha1-DezIUigB/Y0/HGujVadNOCxfmJs="
|
"integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w=="
|
||||||
},
|
},
|
||||||
"dom-serializer": {
|
"dom-serializer": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
@ -9116,11 +9400,6 @@
|
|||||||
"integrity": "sha1-e15vfmZen7QfMAB+2eDUHpf7IUA=",
|
"integrity": "sha1-e15vfmZen7QfMAB+2eDUHpf7IUA=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"html-to-image": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.6.0.tgz",
|
|
||||||
"integrity": "sha512-omzkdNnZOacH7udio09I3eGkOrE8VcpzabQbLYmjojpi+FmtofpNY9lHV2fn2DaDO9G9p10O3E8SF5HHgFhSWg=="
|
|
||||||
},
|
|
||||||
"html-webpack-plugin": {
|
"html-webpack-plugin": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz?cache=0&sync_timestamp=1615296080987&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-webpack-plugin%2Fdownload%2Fhtml-webpack-plugin-3.2.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz?cache=0&sync_timestamp=1615296080987&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-webpack-plugin%2Fdownload%2Fhtml-webpack-plugin-3.2.0.tgz",
|
||||||
@ -9936,11 +10215,6 @@
|
|||||||
"integrity": "sha1-zDXJdYjaS9Saju3WvECC1E3LI6c=",
|
"integrity": "sha1-zDXJdYjaS9Saju3WvECC1E3LI6c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"is-mobile": {
|
|
||||||
"version": "2.2.2",
|
|
||||||
"resolved": "https://registry.npm.taobao.org/is-mobile/download/is-mobile-2.2.2.tgz",
|
|
||||||
"integrity": "sha1-9snF1Q7gElTOBec5vdg18e1OmVQ="
|
|
||||||
},
|
|
||||||
"is-negative-zero": {
|
"is-negative-zero": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.1.tgz?cache=0&sync_timestamp=1607123092746&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-negative-zero%2Fdownload%2Fis-negative-zero-2.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.1.tgz?cache=0&sync_timestamp=1607123092746&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-negative-zero%2Fdownload%2Fis-negative-zero-2.0.1.tgz",
|
||||||
@ -10011,8 +10285,8 @@
|
|||||||
},
|
},
|
||||||
"is-plain-object": {
|
"is-plain-object": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-3.0.1.tgz?cache=0&sync_timestamp=1599667313656&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-plain-object%2Fdownload%2Fis-plain-object-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz",
|
||||||
"integrity": "sha1-Zi2S0kwKpDAkB7DUXSHyJRyF+Fs="
|
"integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g=="
|
||||||
},
|
},
|
||||||
"is-regex": {
|
"is-regex": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
@ -12465,8 +12739,8 @@
|
|||||||
},
|
},
|
||||||
"lodash-es": {
|
"lodash-es": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npm.taobao.org/lodash-es/download/lodash-es-4.17.21.tgz?cache=0&sync_timestamp=1613836838613&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash-es%2Fdownload%2Flodash-es-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
"integrity": "sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4="
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
},
|
},
|
||||||
"lodash.camelcase": {
|
"lodash.camelcase": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
@ -13151,8 +13425,8 @@
|
|||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.29.1",
|
"version": "2.29.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz?cache=0&sync_timestamp=1601983557585&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmoment%2Fdownload%2Fmoment-2.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||||
"integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M="
|
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||||
},
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -13241,8 +13515,8 @@
|
|||||||
},
|
},
|
||||||
"nanopop": {
|
"nanopop": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/nanopop/download/nanopop-2.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnanopop%2Fdownload%2Fnanopop-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.1.0.tgz",
|
||||||
"integrity": "sha1-I0dlE87iQFiIr9LopLVAZrcLnmA="
|
"integrity": "sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw=="
|
||||||
},
|
},
|
||||||
"native-request": {
|
"native-request": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
@ -13653,8 +13927,8 @@
|
|||||||
},
|
},
|
||||||
"omit.js": {
|
"omit.js": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/omit.js/download/omit.js-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/omit.js/-/omit.js-2.0.2.tgz",
|
||||||
"integrity": "sha1-3ZuENvq5R6Xz/yFMslOGMeMT7C8="
|
"integrity": "sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg=="
|
||||||
},
|
},
|
||||||
"on-finished": {
|
"on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
@ -15591,8 +15865,8 @@
|
|||||||
},
|
},
|
||||||
"regexpp": {
|
"regexpp": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/regexpp/download/regexpp-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
|
||||||
"integrity": "sha1-IG0K0KVkjP+9uK5GQ489xRyfeOI=",
|
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"regexpu-core": {
|
"regexpu-core": {
|
||||||
@ -15789,8 +16063,8 @@
|
|||||||
},
|
},
|
||||||
"resize-observer-polyfill": {
|
"resize-observer-polyfill": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresize-observer-polyfill%2Fdownload%2Fresize-observer-polyfill-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||||
"integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ="
|
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.20.0",
|
"version": "1.20.0",
|
||||||
@ -16003,12 +16277,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.32.8",
|
"version": "1.32.13",
|
||||||
"resolved": "https://registry.npm.taobao.org/sass/download/sass-1.32.8.tgz?cache=0&sync_timestamp=1613687400541&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsass%2Fdownload%2Fsass-1.32.8.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.13.tgz",
|
||||||
"integrity": "sha1-8WqavY3FMK3Yg05QaHiigIwDe9w=",
|
"integrity": "sha512-dEgI9nShraqP7cXQH+lEXVf73WOPCse0QlFzSD8k+1TcOxCMwVXfQlr0jtoluZysQOyJGnfr21dLvYKDJq8HkA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": ">=2.0.0 <4.0.0"
|
"chokidar": ">=3.0.0 <4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass-loader": {
|
"sass-loader": {
|
||||||
@ -16060,8 +16334,8 @@
|
|||||||
},
|
},
|
||||||
"scroll-into-view-if-needed": {
|
"scroll-into-view-if-needed": {
|
||||||
"version": "2.2.28",
|
"version": "2.2.28",
|
||||||
"resolved": "https://registry.npm.taobao.org/scroll-into-view-if-needed/download/scroll-into-view-if-needed-2.2.28.tgz",
|
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz",
|
||||||
"integrity": "sha1-WhWy9YpSZCyIyOylhGROAXA9ZFo=",
|
"integrity": "sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"compute-scroll-into-view": "^1.0.17"
|
"compute-scroll-into-view": "^1.0.17"
|
||||||
}
|
}
|
||||||
@ -16304,8 +16578,8 @@
|
|||||||
},
|
},
|
||||||
"shallow-equal": {
|
"shallow-equal": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
|
||||||
"integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo="
|
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
|
||||||
},
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@ -18392,9 +18666,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.9.9",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npm.taobao.org/typescript/download/typescript-3.9.9.tgz?cache=0&sync_timestamp=1616916044038&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftypescript%2Fdownload%2Ftypescript-3.9.9.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
|
||||||
"integrity": "sha1-5pkFxUvAaB0FGL1NWHzG8tCxpnQ=",
|
"integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
@ -19004,8 +19278,8 @@
|
|||||||
},
|
},
|
||||||
"vue-types": {
|
"vue-types": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/vue-types/download/vue-types-3.0.2.tgz?cache=0&sync_timestamp=1612247108041&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-types%2Fdownload%2Fvue-types-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz",
|
||||||
"integrity": "sha1-7BbgXUEsA4Ji/B76TOuWR+f7YB0=",
|
"integrity": "sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-plain-object": "3.0.1"
|
"is-plain-object": "3.0.1"
|
||||||
}
|
}
|
||||||
@ -19059,8 +19333,8 @@
|
|||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz?cache=0&sync_timestamp=1586264004611&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwarning%2Fdownload%2Fwarning-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
"integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=",
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.0.0"
|
"loose-envify": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
13
package.json
13
package.json
@ -11,14 +11,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@icon-park/vue-next": "^1.2.6",
|
"@icon-park/vue-next": "^1.2.6",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"ant-design-vue": "^2.1.2",
|
"ant-design-vue": "^2.1.6",
|
||||||
"chartist": "^0.11.4",
|
"chartist": "^0.11.4",
|
||||||
"clipboard": "^2.0.6",
|
"clipboard": "^2.0.6",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
"dexie": "^3.0.3",
|
"dexie": "^3.0.3",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"html-to-image": "^1.6.0",
|
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"mitt": "^2.1.0",
|
"mitt": "^2.1.0",
|
||||||
"prosemirror-commands": "^1.1.7",
|
"prosemirror-commands": "^1.1.7",
|
||||||
@ -54,8 +53,8 @@
|
|||||||
"@types/prosemirror-schema-list": "^1.0.1",
|
"@types/prosemirror-schema-list": "^1.0.1",
|
||||||
"@types/resize-observer-browser": "^0.1.4",
|
"@types/resize-observer-browser": "^0.1.4",
|
||||||
"@types/tinycolor2": "^1.4.2",
|
"@types/tinycolor2": "^1.4.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||||
"@typescript-eslint/parser": "^2.33.0",
|
"@typescript-eslint/parser": "^4.23.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||||
@ -63,7 +62,7 @@
|
|||||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
"@vue/cli-service": "~4.5.0",
|
"@vue/cli-service": "~4.5.0",
|
||||||
"@vue/compiler-sfc": "^3.0.11",
|
"@vue/compiler-sfc": "^3.0.11",
|
||||||
"@vue/eslint-config-typescript": "^5.0.2",
|
"@vue/eslint-config-typescript": "^7.0.0",
|
||||||
"@vue/test-utils": "^2.0.0-0",
|
"@vue/test-utils": "^2.0.0-0",
|
||||||
"babel-plugin-import": "^1.13.3",
|
"babel-plugin-import": "^1.13.3",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
@ -71,12 +70,12 @@
|
|||||||
"husky": "^4.3.8",
|
"husky": "^4.3.8",
|
||||||
"less": "^3.12.2",
|
"less": "^3.12.2",
|
||||||
"less-loader": "^7.1.0",
|
"less-loader": "^7.1.0",
|
||||||
"sass": "^1.26.5",
|
"sass": "^1.32.13",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
"stylelint": "^13.8.0",
|
"stylelint": "^13.8.0",
|
||||||
"stylelint-config-standard": "^20.0.0",
|
"stylelint-config-standard": "^20.0.0",
|
||||||
"stylelint-webpack-plugin": "^2.1.1",
|
"stylelint-webpack-plugin": "^2.1.1",
|
||||||
"typescript": "~3.9.3",
|
"typescript": "^4.2.4",
|
||||||
"vue-jest": "^5.0.0-0"
|
"vue-jest": "^5.0.0-0"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
|
BIN
src/assets/fonts/字制区喜脉体.ttf
Normal file
BIN
src/assets/fonts/字制区喜脉体.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/assets/fonts/素材集市酷方体.ttf
Normal file
BIN
src/assets/fonts/素材集市酷方体.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/assets/fonts/阿里汉仪智能黑体.ttf
Normal file
BIN
src/assets/fonts/阿里汉仪智能黑体.ttf
Normal file
Binary file not shown.
@ -19,8 +19,8 @@
|
|||||||
src: url(../fonts/站酷快乐体.ttf);
|
src: url(../fonts/站酷快乐体.ttf);
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: '站酷酷黑体';
|
font-family: '字制区喜脉体';
|
||||||
src: url(../fonts/站酷酷黑体.ttf);
|
src: url(../fonts/字制区喜脉体.ttf);
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: '素材集市康康体';
|
font-family: '素材集市康康体';
|
||||||
@ -31,8 +31,8 @@
|
|||||||
src: url(../fonts/联盟起艺卢帅正锐黑体.ttf);
|
src: url(../fonts/联盟起艺卢帅正锐黑体.ttf);
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: '谦度手写楷体';
|
font-family: '素材集市酷方体';
|
||||||
src: url(../fonts/谦度手写楷体.ttf);
|
src: url(../fonts/素材集市酷方体.ttf);
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: '途牛类圆体';
|
font-family: '途牛类圆体';
|
||||||
@ -43,6 +43,6 @@
|
|||||||
src: url(../fonts/锐字真言体.ttf);
|
src: url(../fonts/锐字真言体.ttf);
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: '问藏书房';
|
font-family: '阿里汉仪智能黑体';
|
||||||
src: url(../fonts/问藏书房.ttf);
|
src: url(../fonts/阿里汉仪智能黑体.ttf);
|
||||||
}
|
}
|
@ -37,7 +37,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const color = computed(() => {
|
const color = computed(() => {
|
||||||
const hsla = tinycolor(props.value).toHsl()
|
const hsla = tinycolor(props.value).toHsl()
|
||||||
if (hsla.s === 0) hsla.h = props.hue
|
if (props.hue !== -1) hsla.h = props.hue
|
||||||
return hsla
|
return hsla
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -68,9 +68,9 @@ export default defineComponent({
|
|||||||
else if (left > containerWidth) h = 360
|
else if (left > containerWidth) h = 360
|
||||||
else {
|
else {
|
||||||
percent = left * 100 / containerWidth
|
percent = left * 100 / containerWidth
|
||||||
h = (360 * percent / 100)
|
h = 360 * percent / 100
|
||||||
}
|
}
|
||||||
if (color.value.h !== h) {
|
if (props.hue === -1 || color.value.h !== h) {
|
||||||
emit('colorChange', {
|
emit('colorChange', {
|
||||||
h,
|
h,
|
||||||
l: color.value.l,
|
l: color.value.l,
|
||||||
|
@ -39,7 +39,7 @@ export default defineComponent({
|
|||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const color = computed(() => {
|
const color = computed(() => {
|
||||||
const hsva = tinycolor(props.value).toHsv()
|
const hsva = tinycolor(props.value).toHsv()
|
||||||
if (hsva.s === 0) hsva.h = props.hue
|
if (props.hue !== -1) hsva.h = props.hue
|
||||||
return hsva
|
return hsva
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const hue = ref(0)
|
const hue = ref(-1)
|
||||||
const recentColors = ref<string[]>([])
|
const recentColors = ref<string[]>([])
|
||||||
|
|
||||||
const color = computed({
|
const color = computed({
|
||||||
@ -162,6 +162,7 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const selectPresetColor = (colorString: string) => {
|
const selectPresetColor = (colorString: string) => {
|
||||||
|
hue.value = tinycolor(colorString).toHsl().h
|
||||||
emit('update:modelValue', colorString)
|
emit('update:modelValue', colorString)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +194,10 @@ export default defineComponent({
|
|||||||
hue.value = value.h
|
hue.value = value.h
|
||||||
color.value = tinycolor(value).toRgb()
|
color.value = tinycolor(value).toRgb()
|
||||||
}
|
}
|
||||||
else color.value = value
|
else {
|
||||||
|
hue.value = tinycolor(value).toHsl().h
|
||||||
|
color.value = value
|
||||||
|
}
|
||||||
|
|
||||||
updateRecentColorsCache()
|
updateRecentColorsCache()
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
@mousedown="$event => handleMousedown($event)"
|
@mousedown="$event => handleMousedown($event)"
|
||||||
@mousemove="$event => handleMousemove($event)"
|
@mousemove="$event => handleMousemove($event)"
|
||||||
@mouseup="handleMouseup()"
|
@mouseup="handleMouseup()"
|
||||||
|
@touchstart="$event => handleMousedown($event)"
|
||||||
|
@touchmove="$event => handleMousemove($event)"
|
||||||
|
@touchend="handleMouseup(); mouseInCanvas = false"
|
||||||
@mouseleave="handleMouseup(); mouseInCanvas = false"
|
@mouseleave="handleMouseup(); mouseInCanvas = false"
|
||||||
@mouseenter="mouseInCanvas = true"
|
@mouseenter="mouseInCanvas = true"
|
||||||
></canvas>
|
></canvas>
|
||||||
@ -67,10 +70,11 @@ export default defineComponent({
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新鼠标位置坐标
|
// 更新鼠标位置坐标
|
||||||
const updateMousePosition = (e: MouseEvent) => {
|
const updateMousePosition = (x: number, y: number) => {
|
||||||
mouse.x = e.pageX
|
mouse.x = x
|
||||||
mouse.y = e.pageY
|
mouse.y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鼠标是否处在画布范围内:处在范围内才会显示画笔或橡皮
|
// 鼠标是否处在画布范围内:处在范围内才会显示画笔或橡皮
|
||||||
@ -145,13 +149,6 @@ export default defineComponent({
|
|||||||
ctx.restore()
|
ctx.restore()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备开始绘制/擦除墨迹(落笔)
|
|
||||||
const handleMousedown = (e: MouseEvent) => {
|
|
||||||
isMouseDown = true
|
|
||||||
lastPos = { x: e.offsetX, y: e.offsetY }
|
|
||||||
lastTime = new Date().getTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算鼠标两次移动之间的距离
|
// 计算鼠标两次移动之间的距离
|
||||||
const getDistance = (posX: number, posY: number) => {
|
const getDistance = (posX: number, posY: number) => {
|
||||||
const lastPosX = lastPos.x
|
const lastPosX = lastPos.x
|
||||||
@ -176,28 +173,50 @@ export default defineComponent({
|
|||||||
return lineWidth * 1 / 3 + lastLineWidth * 2 / 3
|
return lineWidth * 1 / 3 + lastLineWidth * 2 / 3
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始绘制/擦除墨迹(移动)
|
// 路径操作
|
||||||
const handleMousemove = (e: MouseEvent) => {
|
const handleMove = (x: number, y: number) => {
|
||||||
updateMousePosition(e)
|
|
||||||
|
|
||||||
if (!isMouseDown) return
|
|
||||||
|
|
||||||
const time = new Date().getTime()
|
const time = new Date().getTime()
|
||||||
|
|
||||||
if (props.model === 'pen') {
|
if (props.model === 'pen') {
|
||||||
const s = getDistance(e.offsetX, e.offsetY)
|
const s = getDistance(x, y)
|
||||||
const t = time - lastTime
|
const t = time - lastTime
|
||||||
const lineWidth = getLineWidth(s, t)
|
const lineWidth = getLineWidth(s, t)
|
||||||
|
|
||||||
draw(e.offsetX, e.offsetY, lineWidth)
|
draw(x, y, lineWidth)
|
||||||
lastLineWidth = lineWidth
|
lastLineWidth = lineWidth
|
||||||
}
|
}
|
||||||
else erase(e.offsetX, e.offsetY)
|
else erase(x, y)
|
||||||
|
|
||||||
lastPos = { x: e.offsetX, y: e.offsetY }
|
lastPos = {x, y}
|
||||||
lastTime = new Date().getTime()
|
lastTime = new Date().getTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理鼠标(触摸)事件
|
||||||
|
// 准备开始绘制/擦除墨迹(落笔)
|
||||||
|
const handleMousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
|
const x = e instanceof MouseEvent ? e.offsetX : e.changedTouches[0].pageX
|
||||||
|
const y = e instanceof MouseEvent ? e.offsetY : e.changedTouches[0].pageY
|
||||||
|
|
||||||
|
isMouseDown = true
|
||||||
|
lastPos = { x, y }
|
||||||
|
lastTime = new Date().getTime()
|
||||||
|
|
||||||
|
if (e instanceof TouchEvent) {
|
||||||
|
updateMousePosition(x, y)
|
||||||
|
mouseInCanvas.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始绘制/擦除墨迹(移动)
|
||||||
|
const handleMousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
|
const x = e instanceof MouseEvent ? e.offsetX : e.changedTouches[0].pageX
|
||||||
|
const y = e instanceof MouseEvent ? e.offsetY : e.changedTouches[0].pageY
|
||||||
|
|
||||||
|
updateMousePosition(x, y)
|
||||||
|
|
||||||
|
if (isMouseDown) handleMove(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
// 结束绘制/擦除墨迹(停笔)
|
// 结束绘制/擦除墨迹(停笔)
|
||||||
const handleMouseup = () => {
|
const handleMouseup = () => {
|
||||||
if (!isMouseDown) return
|
if (!isMouseDown) return
|
||||||
|
@ -35,11 +35,11 @@ export const WEB_FONTS = [
|
|||||||
{ label: '峰广明锐体', value: '峰广明锐体' },
|
{ label: '峰广明锐体', value: '峰广明锐体' },
|
||||||
{ label: '摄图摩登小方体', value: '摄图摩登小方体' },
|
{ label: '摄图摩登小方体', value: '摄图摩登小方体' },
|
||||||
{ label: '站酷快乐体', value: '站酷快乐体' },
|
{ label: '站酷快乐体', value: '站酷快乐体' },
|
||||||
{ label: '站酷酷黑体', value: '站酷酷黑体' },
|
{ label: '字制区喜脉体', value: '字制区喜脉体' },
|
||||||
{ label: '素材集市康康体', value: '素材集市康康体' },
|
{ label: '素材集市康康体', value: '素材集市康康体' },
|
||||||
{ label: '联盟起艺卢帅正锐黑体', value: '联盟起艺卢帅正锐黑体' },
|
{ label: '联盟起艺卢帅正锐黑体', value: '联盟起艺卢帅正锐黑体' },
|
||||||
{ label: '谦度手写楷体', value: '谦度手写楷体' },
|
{ label: '素材集市酷方体', value: '素材集市酷方体' },
|
||||||
{ label: '途牛类圆体', value: '途牛类圆体' },
|
{ label: '途牛类圆体', value: '途牛类圆体' },
|
||||||
{ label: '锐字真言体', value: '锐字真言体' },
|
{ label: '锐字真言体', value: '锐字真言体' },
|
||||||
{ label: '问藏书房', value: '问藏书房' },
|
{ label: '阿里汉仪智能黑体', value: '阿里汉仪智能黑体' },
|
||||||
]
|
]
|
@ -55,8 +55,8 @@ export const HOTKEY_DOC = [
|
|||||||
{ label: '放大画布', value: 'Ctrl + =' },
|
{ label: '放大画布', value: 'Ctrl + =' },
|
||||||
{ label: '缩小画布', value: 'Ctrl + -' },
|
{ label: '缩小画布', value: 'Ctrl + -' },
|
||||||
{ label: '缩放画布到合适大小', value: 'Ctrl + 0' },
|
{ label: '缩放画布到合适大小', value: 'Ctrl + 0' },
|
||||||
{ label: '编辑上一页', value: '↑ / ←' },
|
{ label: '编辑上一页', value: '↑ / ← / 鼠标上滚' },
|
||||||
{ label: '编辑下一页', value: '↓ / →' },
|
{ label: '编辑下一页', value: '↓ / → / 鼠标下滚' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -70,6 +70,7 @@ export const HOTKEY_DOC = [
|
|||||||
{ label: '置底层', value: 'Alt + B' },
|
{ label: '置底层', value: 'Alt + B' },
|
||||||
{ label: '锁定宽高比例', value: '按住 Ctrl 或 Shift' },
|
{ label: '锁定宽高比例', value: '按住 Ctrl 或 Shift' },
|
||||||
{ label: '创建水平 / 垂直线条', value: '按住 Ctrl 或 Shift' },
|
{ label: '创建水平 / 垂直线条', value: '按住 Ctrl 或 Shift' },
|
||||||
|
{ label: '切换焦点元素', value: 'Tab' },
|
||||||
{ label: '确认图片裁剪', value: 'Enter' },
|
{ label: '确认图片裁剪', value: 'Enter' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -63,6 +63,7 @@ export default () => {
|
|||||||
left: (VIEWPORT_SIZE - width) / 2,
|
left: (VIEWPORT_SIZE - width) / 2,
|
||||||
top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,
|
top: (VIEWPORT_SIZE * viewportRatio.value - height) / 2,
|
||||||
fixedRatio: true,
|
fixedRatio: true,
|
||||||
|
rotate: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -147,6 +148,7 @@ export default () => {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
content,
|
content,
|
||||||
|
rotate: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +170,7 @@ export default () => {
|
|||||||
path: data.path,
|
path: data.path,
|
||||||
fill: themeColor.value,
|
fill: themeColor.value,
|
||||||
fixedRatio: false,
|
fixedRatio: false,
|
||||||
|
rotate: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,29 @@
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { MutationTypes, useStore } from '@/store'
|
import { MutationTypes, useStore } from '@/store'
|
||||||
import { Slide } from '@/types/slides'
|
import { PPTElement, Slide } from '@/types/slides'
|
||||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
|
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||||
|
|
||||||
const { addHistorySnapshot } = useHistorySnapshot()
|
const { addHistorySnapshot } = useHistorySnapshot()
|
||||||
|
|
||||||
// 删除全部选中元素
|
// 删除全部选中元素
|
||||||
|
// 组合元素成员中,存在被选中可独立操作的元素时,优先删除该元素。否则默认删除所有被选中的元素
|
||||||
const deleteElement = () => {
|
const deleteElement = () => {
|
||||||
if (!activeElementIdList.value.length) return
|
if (!activeElementIdList.value.length) return
|
||||||
const newElementList = currentSlide.value.elements.filter(el => !activeElementIdList.value.includes(el.id))
|
|
||||||
|
let newElementList: PPTElement[] = []
|
||||||
|
if (activeGroupElementId.value) {
|
||||||
|
newElementList = currentSlide.value.elements.filter(el => el.id !== activeGroupElementId.value)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newElementList = currentSlide.value.elements.filter(el => !activeElementIdList.value.includes(el.id))
|
||||||
|
}
|
||||||
|
|
||||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||||
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
|
||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { computed, onMounted, onUnmounted } from 'vue'
|
import { computed, onMounted, onUnmounted } from 'vue'
|
||||||
import { MutationTypes, useStore } from '@/store'
|
import { MutationTypes, useStore } from '@/store'
|
||||||
import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
|
import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
|
||||||
import { PPTElement } from '@/types/slides'
|
import { PPTElement, Slide } from '@/types/slides'
|
||||||
import { KEYS } from '@/configs/hotkey'
|
import { KEYS } from '@/configs/hotkey'
|
||||||
|
|
||||||
import useSlideHandler from './useSlideHandler'
|
import useSlideHandler from './useSlideHandler'
|
||||||
@ -24,6 +24,7 @@ export default () => {
|
|||||||
const disableHotkeys = computed(() => store.state.disableHotkeys)
|
const disableHotkeys = computed(() => store.state.disableHotkeys)
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
const handleElement = computed<PPTElement>(() => store.getters.handleElement)
|
||||||
|
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||||
|
|
||||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||||
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
|
const thumbnailsFocus = computed(() => store.state.thumbnailsFocus)
|
||||||
@ -103,15 +104,31 @@ export default () => {
|
|||||||
createSlide()
|
createSlide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tabActiveElement = () => {
|
||||||
|
if (!currentSlide.value.elements.length) return
|
||||||
|
if (!handleElement.value) {
|
||||||
|
const firstElement = currentSlide.value.elements[0]
|
||||||
|
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [firstElement.id])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentIndex = currentSlide.value.elements.findIndex(el => el.id === handleElement.value.id)
|
||||||
|
const nextIndex = currentIndex >= currentSlide.value.elements.length - 1 ? 0 : currentIndex + 1
|
||||||
|
const nextElementId = currentSlide.value.elements[nextIndex].id
|
||||||
|
|
||||||
|
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [nextElementId])
|
||||||
|
}
|
||||||
|
|
||||||
const keydownListener = (e: KeyboardEvent) => {
|
const keydownListener = (e: KeyboardEvent) => {
|
||||||
const { ctrlKey, shiftKey, altKey, metaKey } = e
|
const { ctrlKey, shiftKey, altKey, metaKey } = e
|
||||||
|
const ctrlOrMetaKeyActive = ctrlKey || metaKey
|
||||||
|
|
||||||
const key = e.key.toUpperCase()
|
const key = e.key.toUpperCase()
|
||||||
|
|
||||||
if (ctrlKey && !ctrlKeyActive.value) store.commit(MutationTypes.SET_CTRL_KEY_STATE, true)
|
if (ctrlOrMetaKeyActive && !ctrlKeyActive.value) store.commit(MutationTypes.SET_CTRL_KEY_STATE, true)
|
||||||
if (shiftKey && !shiftKeyActive.value) store.commit(MutationTypes.SET_SHIFT_KEY_STATE, true)
|
if (shiftKey && !shiftKeyActive.value) store.commit(MutationTypes.SET_SHIFT_KEY_STATE, true)
|
||||||
|
|
||||||
if (ctrlKey && key === KEYS.F) {
|
if (ctrlOrMetaKeyActive && key === KEYS.F) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
enterScreening()
|
enterScreening()
|
||||||
store.commit(MutationTypes.SET_CTRL_KEY_STATE, false)
|
store.commit(MutationTypes.SET_CTRL_KEY_STATE, false)
|
||||||
@ -119,47 +136,47 @@ export default () => {
|
|||||||
|
|
||||||
if (!editorAreaFocus.value && !thumbnailsFocus.value) return
|
if (!editorAreaFocus.value && !thumbnailsFocus.value) return
|
||||||
|
|
||||||
if ((ctrlKey || metaKey) && key === KEYS.C) {
|
if (ctrlOrMetaKeyActive && key === KEYS.C) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
copy()
|
copy()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.X) {
|
if (ctrlOrMetaKeyActive && key === KEYS.X) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
cut()
|
cut()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.D) {
|
if (ctrlOrMetaKeyActive && key === KEYS.D) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
quickCopy()
|
quickCopy()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.Z) {
|
if (ctrlOrMetaKeyActive && key === KEYS.Z) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
undo()
|
undo()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.Y) {
|
if (ctrlOrMetaKeyActive && key === KEYS.Y) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
redo()
|
redo()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.A) {
|
if (ctrlOrMetaKeyActive && key === KEYS.A) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
selectAll()
|
selectAll()
|
||||||
}
|
}
|
||||||
if (ctrlKey && key === KEYS.L) {
|
if (ctrlOrMetaKeyActive && key === KEYS.L) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
lock()
|
lock()
|
||||||
}
|
}
|
||||||
if (!shiftKey && ctrlKey && key === KEYS.G) {
|
if (!shiftKey && ctrlOrMetaKeyActive && key === KEYS.G) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
combine()
|
combine()
|
||||||
}
|
}
|
||||||
if (shiftKey && ctrlKey && key === KEYS.G) {
|
if (shiftKey && ctrlOrMetaKeyActive && key === KEYS.G) {
|
||||||
if (disableHotkeys.value) return
|
if (disableHotkeys.value) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
uncombine()
|
uncombine()
|
||||||
@ -219,6 +236,11 @@ export default () => {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setCanvasPercentage(90)
|
setCanvasPercentage(90)
|
||||||
}
|
}
|
||||||
|
if (key === KEYS.TAB) {
|
||||||
|
if (disableHotkeys.value) return
|
||||||
|
e.preventDefault()
|
||||||
|
tabActiveElement()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyupListener = () => {
|
const keyupListener = () => {
|
||||||
|
@ -43,14 +43,12 @@ export default () => {
|
|||||||
* @param command 移动页面焦点命令:上移、下移
|
* @param command 移动页面焦点命令:上移、下移
|
||||||
*/
|
*/
|
||||||
const updateSlideIndex = (command: string) => {
|
const updateSlideIndex = (command: string) => {
|
||||||
let targetIndex = 0
|
|
||||||
if (command === KEYS.UP && slideIndex.value > 0) {
|
if (command === KEYS.UP && slideIndex.value > 0) {
|
||||||
targetIndex = slideIndex.value - 1
|
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
|
||||||
}
|
}
|
||||||
else if (command === KEYS.DOWN && slideIndex.value < slides.value.length - 1) {
|
else if (command === KEYS.DOWN && slideIndex.value < slides.value.length - 1) {
|
||||||
targetIndex = slideIndex.value + 1
|
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
|
||||||
}
|
}
|
||||||
store.commit(MutationTypes.UPDATE_SLIDE_INDEX, targetIndex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将当前页面数据加密后复制到剪贴板
|
// 将当前页面数据加密后复制到剪贴板
|
||||||
@ -82,6 +80,7 @@ export default () => {
|
|||||||
color: theme.value.backgroundColor,
|
color: theme.value.backgroundColor,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [])
|
||||||
store.commit(MutationTypes.ADD_SLIDE, emptySlide)
|
store.commit(MutationTypes.ADD_SLIDE, emptySlide)
|
||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
}
|
}
|
||||||
|
@ -23,19 +23,24 @@ export default () => {
|
|||||||
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
||||||
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
|
const newElementList: PPTElement[] = JSON.parse(JSON.stringify(currentSlide.value.elements))
|
||||||
|
|
||||||
|
// 将选中的元素按位置(从左到右)排序
|
||||||
copyOfActiveElementList.sort((elementA, elementB) => {
|
copyOfActiveElementList.sort((elementA, elementB) => {
|
||||||
const { minX: elAMinX } = getElementRange(elementA)
|
const { minX: elAMinX } = getElementRange(elementA)
|
||||||
const { minX: elBMinX } = getElementRange(elementB)
|
const { minX: elBMinX } = getElementRange(elementB)
|
||||||
return elAMinX - elBMinX
|
return elAMinX - elBMinX
|
||||||
})
|
})
|
||||||
|
|
||||||
let totaiWidth = 0
|
// 计算元素均匀分布所需要的间隔:
|
||||||
|
// (所选元素整体范围 - 所有所选元素宽度和) / (所选元素数 - 1)
|
||||||
|
let totalWidth = 0
|
||||||
for (const element of activeElementList.value) {
|
for (const element of activeElementList.value) {
|
||||||
const { minX: elMinX, maxX: elMaxX } = getElementRange(element)
|
const { minX: elMinX, maxX: elMaxX } = getElementRange(element)
|
||||||
totaiWidth += (elMaxX - elMinX)
|
totalWidth += (elMaxX - elMinX)
|
||||||
}
|
}
|
||||||
const span = ((maxX - minX) - totaiWidth) / (activeElementList.value.length - 1)
|
const span = ((maxX - minX) - totalWidth) / (activeElementList.value.length - 1)
|
||||||
|
|
||||||
|
// 将所选元素按位置顺序依次计算目标位置
|
||||||
|
// 注意pos并非元素目标left值,而是目标位置范围最小值(元素旋转后的left值 ≠ 范围最小值)
|
||||||
const sortedElementData: SortedElementData[] = []
|
const sortedElementData: SortedElementData[] = []
|
||||||
for (const element of copyOfActiveElementList) {
|
for (const element of copyOfActiveElementList) {
|
||||||
if (!sortedElementData.length) {
|
if (!sortedElementData.length) {
|
||||||
@ -52,6 +57,8 @@ export default () => {
|
|||||||
sortedElementData.push({ el: element, pos: lastItemPos + lastElementWidth + span })
|
sortedElementData.push({ el: element, pos: lastItemPos + lastElementWidth + span })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据目标位置计算元素最终目标left值
|
||||||
|
// 对于旋转后的元素,需要计算旋转前后left的偏移来做校正
|
||||||
for (const element of newElementList) {
|
for (const element of newElementList) {
|
||||||
if (!activeElementIdList.value.includes(element.id)) continue
|
if (!activeElementIdList.value.includes(element.id)) continue
|
||||||
|
|
||||||
@ -76,7 +83,7 @@ export default () => {
|
|||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 垂直均匀排列
|
// 垂直均匀排列(逻辑类似水平均匀排列方法)
|
||||||
const uniformVerticalDisplay = () => {
|
const uniformVerticalDisplay = () => {
|
||||||
const { minY, maxY } = getElementListRange(activeElementList.value)
|
const { minY, maxY } = getElementListRange(activeElementList.value)
|
||||||
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
const copyOfActiveElementList: PPTElement[] = JSON.parse(JSON.stringify(activeElementList.value))
|
||||||
@ -88,12 +95,12 @@ export default () => {
|
|||||||
return elAMinY - elBMinY
|
return elAMinY - elBMinY
|
||||||
})
|
})
|
||||||
|
|
||||||
let totaiHeight = 0
|
let totalHeight = 0
|
||||||
for (const element of activeElementList.value) {
|
for (const element of activeElementList.value) {
|
||||||
const { minY: elMinY, maxY: elMaxY } = getElementRange(element)
|
const { minY: elMinY, maxY: elMaxY } = getElementRange(element)
|
||||||
totaiHeight += (elMaxY - elMinY)
|
totalHeight += (elMaxY - elMinY)
|
||||||
}
|
}
|
||||||
const span = ((maxY - minY) - totaiHeight) / (activeElementList.value.length - 1)
|
const span = ((maxY - minY) - totalHeight) / (activeElementList.value.length - 1)
|
||||||
|
|
||||||
const sortedElementData: SortedElementData[] = []
|
const sortedElementData: SortedElementData[] = []
|
||||||
for (const element of copyOfActiveElementList) {
|
for (const element of copyOfActiveElementList) {
|
||||||
|
@ -13,9 +13,10 @@ export const slides: Slide[] = [
|
|||||||
height: 362.5,
|
height: 362.5,
|
||||||
viewBox: 200,
|
viewBox: 200,
|
||||||
path: 'M 0 0 L 0 200 L 200 200 Z',
|
path: 'M 0 0 L 0 200 L 200 200 Z',
|
||||||
fill: '#d14424',
|
fill: '#5b9bd5',
|
||||||
fixedRatio: false,
|
fixedRatio: false,
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
|
rotate: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'shape',
|
type: 'shape',
|
||||||
@ -26,12 +27,13 @@ export const slides: Slide[] = [
|
|||||||
height: 320,
|
height: 320,
|
||||||
viewBox: 200,
|
viewBox: 200,
|
||||||
path: 'M 0 0 L 0 200 L 200 200 Z',
|
path: 'M 0 0 L 0 200 L 200 200 Z',
|
||||||
fill: '#d14424',
|
fill: '#5b9bd5',
|
||||||
fixedRatio: false,
|
fixedRatio: false,
|
||||||
flip: {
|
flip: {
|
||||||
x: 180,
|
x: 180,
|
||||||
y: 0,
|
y: 0,
|
||||||
},
|
},
|
||||||
|
rotate: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@ -40,7 +42,9 @@ export const slides: Slide[] = [
|
|||||||
top: 65.25,
|
top: 65.25,
|
||||||
width: 585,
|
width: 585,
|
||||||
height: 188,
|
height: 188,
|
||||||
|
lineHeight: 1.2,
|
||||||
content: '<p style=\'\'><strong><span style=\'font-size: 112px\'>PPTIST</span></strong></p>',
|
content: '<p style=\'\'><strong><span style=\'font-size: 112px\'>PPTIST</span></strong></p>',
|
||||||
|
rotate: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@ -50,6 +54,7 @@ export const slides: Slide[] = [
|
|||||||
width: 585,
|
width: 585,
|
||||||
height: 56,
|
height: 56,
|
||||||
content: '<p style=\'\'><span style=\'font-size: 24px\'>基于 Vue 3.x + TypeScript 的在线演示文稿应用</span></p>',
|
content: '<p style=\'\'><span style=\'font-size: 24px\'>基于 Vue 3.x + TypeScript 的在线演示文稿应用</span></p>',
|
||||||
|
rotate: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: 'line',
|
||||||
@ -59,7 +64,7 @@ export const slides: Slide[] = [
|
|||||||
start: [0, 0],
|
start: [0, 0],
|
||||||
end: [549, 0],
|
end: [549, 0],
|
||||||
points: ['', ''],
|
points: ['', ''],
|
||||||
color: '#d14424',
|
color: '#5b9bd5',
|
||||||
style: 'solid',
|
style: 'solid',
|
||||||
width: 2,
|
width: 2,
|
||||||
},
|
},
|
8
src/mocks/theme.ts
Normal file
8
src/mocks/theme.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SlideTheme } from '@/types/slides'
|
||||||
|
|
||||||
|
export const theme: SlideTheme = {
|
||||||
|
themeColor: '#5b9bd5',
|
||||||
|
fontColor: '#333',
|
||||||
|
fontName: '微软雅黑',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
}
|
@ -69,6 +69,7 @@ import {
|
|||||||
Platte,
|
Platte,
|
||||||
UpOne,
|
UpOne,
|
||||||
DownOne,
|
DownOne,
|
||||||
|
Close,
|
||||||
CloseSmall,
|
CloseSmall,
|
||||||
Undo,
|
Undo,
|
||||||
Transform,
|
Transform,
|
||||||
@ -76,6 +77,9 @@ import {
|
|||||||
Theme,
|
Theme,
|
||||||
ArrowCircleLeft,
|
ArrowCircleLeft,
|
||||||
GraphicDesign,
|
GraphicDesign,
|
||||||
|
Logout,
|
||||||
|
Erase,
|
||||||
|
Clear,
|
||||||
} from '@icon-park/vue-next'
|
} from '@icon-park/vue-next'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -154,6 +158,7 @@ export default {
|
|||||||
app.component('IconRightTwo', RightTwo)
|
app.component('IconRightTwo', RightTwo)
|
||||||
app.component('IconPlus', Plus)
|
app.component('IconPlus', Plus)
|
||||||
app.component('IconMinus', Minus)
|
app.component('IconMinus', Minus)
|
||||||
|
app.component('IconClose', Close)
|
||||||
app.component('IconCloseSmall', CloseSmall)
|
app.component('IconCloseSmall', CloseSmall)
|
||||||
|
|
||||||
// 图表
|
// 图表
|
||||||
@ -171,6 +176,7 @@ export default {
|
|||||||
app.component('IconHelpcenter', Helpcenter)
|
app.component('IconHelpcenter', Helpcenter)
|
||||||
app.component('IconGithub', Github)
|
app.component('IconGithub', Github)
|
||||||
app.component('IconWrite', Write)
|
app.component('IconWrite', Write)
|
||||||
|
app.component('IconErase', Erase)
|
||||||
app.component('IconEffects', Effects)
|
app.component('IconEffects', Effects)
|
||||||
app.component('IconRotate', Rotate)
|
app.component('IconRotate', Rotate)
|
||||||
app.component('IconEdit', Edit)
|
app.component('IconEdit', Edit)
|
||||||
@ -179,5 +185,7 @@ export default {
|
|||||||
app.component('IconClick', Click)
|
app.component('IconClick', Click)
|
||||||
app.component('IconTheme', Theme)
|
app.component('IconTheme', Theme)
|
||||||
app.component('IconArrowCircleLeft', ArrowCircleLeft)
|
app.component('IconArrowCircleLeft', ArrowCircleLeft)
|
||||||
|
app.component('IconLogout', Logout)
|
||||||
|
app.component('IconClear', Clear)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,26 +23,38 @@ export const actions: ActionTree<State, State> = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async [ActionTypes.ADD_SNAPSHOT]({ state, commit }) {
|
async [ActionTypes.ADD_SNAPSHOT]({ state, commit }) {
|
||||||
|
|
||||||
|
// 获取当前indexeddb中全部快照的ID
|
||||||
const allKeys = await snapshotDB.snapshots.orderBy('id').keys()
|
const allKeys = await snapshotDB.snapshots.orderBy('id').keys()
|
||||||
|
|
||||||
let needDeleteKeys: IndexableTypeArray = []
|
let needDeleteKeys: IndexableTypeArray = []
|
||||||
|
|
||||||
|
// 记录需要删除的快照ID
|
||||||
|
// 若当前快照指针不处在最后一位,那么再添加快照时,应该将当前指针位置后面的快照全部删除,对应的实际情况是:
|
||||||
|
// 用户撤回多次后,再进行操作(添加快照),此时原先被撤销的快照都应该被删除
|
||||||
if (state.snapshotCursor >= 0 && state.snapshotCursor < allKeys.length - 1) {
|
if (state.snapshotCursor >= 0 && state.snapshotCursor < allKeys.length - 1) {
|
||||||
needDeleteKeys = allKeys.slice(state.snapshotCursor + 1)
|
needDeleteKeys = allKeys.slice(state.snapshotCursor + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加新快照
|
||||||
const snapshot = {
|
const snapshot = {
|
||||||
index: state.slideIndex,
|
index: state.slideIndex,
|
||||||
slides: state.slides,
|
slides: state.slides,
|
||||||
}
|
}
|
||||||
await snapshotDB.snapshots.add(snapshot)
|
await snapshotDB.snapshots.add(snapshot)
|
||||||
|
|
||||||
|
// 计算当前快照长度,用于设置快照指针的位置(此时指针应该处在最后一位,即:快照长度 - 1)
|
||||||
let snapshotLength = allKeys.length - needDeleteKeys.length + 1
|
let snapshotLength = allKeys.length - needDeleteKeys.length + 1
|
||||||
|
|
||||||
if (snapshotLength > 20) {
|
// 快照数量超过长度限制时,应该将头部多余的快照删除
|
||||||
|
const snapshotLengthLimit = 20
|
||||||
|
if (snapshotLength > snapshotLengthLimit) {
|
||||||
needDeleteKeys.push(allKeys[0])
|
needDeleteKeys.push(allKeys[0])
|
||||||
snapshotLength--
|
snapshotLength--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 快照数大于1时,需要保证撤回操作后维持页面焦点不变:也就是将倒数第二个快照对应的索引设置为当前页的索引
|
||||||
|
// https://github.com/pipipi-pikachu/PPTist/issues/27
|
||||||
if (snapshotLength >= 2) {
|
if (snapshotLength >= 2) {
|
||||||
snapshotDB.snapshots.update(allKeys[snapshotLength - 2] as number, { index: state.slideIndex })
|
snapshotDB.snapshots.update(allKeys[snapshotLength - 2] as number, { index: state.slideIndex })
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ export const enum MutationTypes {
|
|||||||
// editor
|
// editor
|
||||||
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
SET_ACTIVE_ELEMENT_ID_LIST = 'setActiveElementIdList',
|
||||||
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
SET_HANDLE_ELEMENT_ID = 'setHandleElementId',
|
||||||
|
SET_ACTIVE_GROUP_ELEMENT_ID = 'setActiveGroupElementId',
|
||||||
SET_CANVAS_PERCENTAGE = 'setCanvasPercentage',
|
SET_CANVAS_PERCENTAGE = 'setCanvasPercentage',
|
||||||
SET_CANVAS_SCALE = 'setCanvasScale',
|
SET_CANVAS_SCALE = 'setCanvasScale',
|
||||||
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
SET_THUMBNAILS_FOCUS = 'setThumbnailsFocus',
|
||||||
|
@ -32,6 +32,10 @@ export const mutations: MutationTree<State> = {
|
|||||||
state.handleElementId = handleElementId
|
state.handleElementId = handleElementId
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID](state, activeGroupElementId: string) {
|
||||||
|
state.activeGroupElementId = activeGroupElementId
|
||||||
|
},
|
||||||
|
|
||||||
[MutationTypes.SET_CANVAS_PERCENTAGE](state, percentage: number) {
|
[MutationTypes.SET_CANVAS_PERCENTAGE](state, percentage: number) {
|
||||||
state.canvasPercentage = percentage
|
state.canvasPercentage = percentage
|
||||||
},
|
},
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { Slide, SlideTheme } from '@/types/slides'
|
import { Slide, SlideTheme } from '@/types/slides'
|
||||||
import { CreatingElement } from '@/types/edit'
|
import { CreatingElement } from '@/types/edit'
|
||||||
import { ToolbarState } from '@/types/toolbar'
|
import { ToolbarState } from '@/types/toolbar'
|
||||||
import { slides } from '@/mocks/index'
|
import { slides } from '@/mocks/slides'
|
||||||
|
import { theme } from '@/mocks/theme'
|
||||||
import { SYS_FONTS } from '@/configs/font'
|
import { SYS_FONTS } from '@/configs/font'
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
activeElementIdList: string[];
|
activeElementIdList: string[];
|
||||||
handleElementId: string;
|
handleElementId: string;
|
||||||
|
activeGroupElementId: string;
|
||||||
canvasPercentage: number;
|
canvasPercentage: number;
|
||||||
canvasScale: number;
|
canvasScale: number;
|
||||||
thumbnailsFocus: boolean;
|
thumbnailsFocus: boolean;
|
||||||
@ -30,31 +32,27 @@ export interface State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const state: State = {
|
export const state: State = {
|
||||||
activeElementIdList: [],
|
activeElementIdList: [], // 被选中的元素ID集合,包含 handleElementId
|
||||||
handleElementId: '',
|
handleElementId: '', // 正在操作的元素ID
|
||||||
canvasPercentage: 90,
|
activeGroupElementId: '', // 组合元素成员中,被选中可独立操作的元素ID
|
||||||
canvasScale: 1,
|
canvasPercentage: 90, // 画布可视区域百分比
|
||||||
thumbnailsFocus: false,
|
canvasScale: 1, // 画布缩放比例(基于宽度1000px)
|
||||||
editorAreaFocus: false,
|
thumbnailsFocus: false, // 左侧导航缩略图区域聚焦
|
||||||
disableHotkeys: false,
|
editorAreaFocus: false, // 编辑区域聚焦
|
||||||
showGridLines: false,
|
disableHotkeys: false, // 禁用快捷键
|
||||||
creatingElement: null,
|
showGridLines: false, // 显示网格线
|
||||||
availableFonts: [],
|
creatingElement: null, // 正在插入的元素信息,需要绘制插入的元素需要(文字、形状、线条)
|
||||||
toolbarState: 'slideStyle',
|
availableFonts: [], // 当前环境可用字体
|
||||||
theme: {
|
toolbarState: 'slideStyle', // 右侧工具栏状态
|
||||||
themeColor: '#d14424',
|
viewportRatio: 0.5625, // 可是区域比例,默认16:9
|
||||||
fontColor: '#333',
|
theme: theme, // 主题样式
|
||||||
fontName: '微软雅黑',
|
slides: slides, // 幻灯片页面数据
|
||||||
backgroundColor: '#fff',
|
slideIndex: 0, // 当前页面索引
|
||||||
},
|
selectedSlidesIndex: [], // 当前被选中的页面索引集合
|
||||||
viewportRatio: 0.5625,
|
snapshotCursor: -1, // 历史快照指针
|
||||||
slides: slides,
|
snapshotLength: 0, // 历史快照长度
|
||||||
slideIndex: 0,
|
ctrlKeyState: false, // ctrl键按下状态
|
||||||
selectedSlidesIndex: [],
|
shiftKeyState: false, // shift键按下状态
|
||||||
snapshotCursor: -1,
|
screening: false, // 是否进入放映状态
|
||||||
snapshotLength: 0,
|
clipingImageElementId: '', // 当前正在裁剪的图片ID
|
||||||
ctrlKeyState: false,
|
|
||||||
shiftKeyState: false,
|
|
||||||
screening: false,
|
|
||||||
clipingImageElementId: '',
|
|
||||||
}
|
}
|
@ -35,7 +35,7 @@ interface PPTBaseElement {
|
|||||||
export interface PPTTextElement extends PPTBaseElement {
|
export interface PPTTextElement extends PPTBaseElement {
|
||||||
type: 'text';
|
type: 'text';
|
||||||
content: string;
|
content: string;
|
||||||
rotate?: number;
|
rotate: number;
|
||||||
outline?: PPTElementOutline;
|
outline?: PPTElementOutline;
|
||||||
fill?: string;
|
fill?: string;
|
||||||
lineHeight?: number;
|
lineHeight?: number;
|
||||||
@ -65,7 +65,7 @@ export interface PPTImageElement extends PPTBaseElement{
|
|||||||
type: 'image';
|
type: 'image';
|
||||||
fixedRatio: boolean;
|
fixedRatio: boolean;
|
||||||
src: string;
|
src: string;
|
||||||
rotate?: number;
|
rotate: number;
|
||||||
outline?: PPTElementOutline;
|
outline?: PPTElementOutline;
|
||||||
filters?: ImageElementFilters;
|
filters?: ImageElementFilters;
|
||||||
clip?: ImageElementClip;
|
clip?: ImageElementClip;
|
||||||
@ -85,7 +85,7 @@ export interface PPTShapeElement extends PPTBaseElement{
|
|||||||
fixedRatio: boolean;
|
fixedRatio: boolean;
|
||||||
fill: string;
|
fill: string;
|
||||||
gradient?: ShapeGradient;
|
gradient?: ShapeGradient;
|
||||||
rotate?: number;
|
rotate: number;
|
||||||
outline?: PPTElementOutline;
|
outline?: PPTElementOutline;
|
||||||
opacity?: number;
|
opacity?: number;
|
||||||
flip?: ImageOrShapeFlip;
|
flip?: ImageOrShapeFlip;
|
||||||
|
@ -30,16 +30,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 计算网格线的颜色,避免与背景的颜色太接近
|
// 计算网格线的颜色,避免与背景的颜色太接近
|
||||||
const gridColor = computed(() => {
|
const gridColor = computed(() => {
|
||||||
if (!background.value || background.value.type === 'image') return 'rgba(100, 100, 100, 0.5)'
|
const bgColor = background.value?.color || '#fff'
|
||||||
const color = background.value.color
|
const colorList = ['#000', '#fff']
|
||||||
const rgba = tinycolor(color).toRgb()
|
return tinycolor.mostReadable(bgColor, colorList, { includeFallbackColors: true }).setAlpha(.5).toRgbString()
|
||||||
const newRgba = {
|
|
||||||
r: rgba.r > 128 ? rgba.r - 128 : rgba.r + 127,
|
|
||||||
g: rgba.g > 128 ? rgba.g - 128 : rgba.g + 127,
|
|
||||||
b: rgba.b > 128 ? rgba.b - 128 : rgba.b + 127,
|
|
||||||
a: 0.5
|
|
||||||
}
|
|
||||||
return `rgba(${[newRgba.r, newRgba.g, newRgba.b, newRgba.a].join(',')})`
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const gridSize = 50
|
const gridSize = 50
|
||||||
@ -80,5 +73,7 @@ export default defineComponent({
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
z-index: 999;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -8,11 +8,11 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
|||||||
|
|
||||||
export default (
|
export default (
|
||||||
elementList: Ref<PPTElement[]>,
|
elementList: Ref<PPTElement[]>,
|
||||||
activeGroupElementId: Ref<string>,
|
|
||||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||||
) => {
|
) => {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
|
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||||
const canvasScale = computed(() => store.state.canvasScale)
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||||
|
|
||||||
|
@ -94,11 +94,11 @@ const getOppositePoint = (direction: string, points: ReturnType<typeof getRotate
|
|||||||
|
|
||||||
export default (
|
export default (
|
||||||
elementList: Ref<PPTElement[]>,
|
elementList: Ref<PPTElement[]>,
|
||||||
activeGroupElementId: Ref<string>,
|
|
||||||
alignmentLines: Ref<AlignmentLineProps[]>,
|
alignmentLines: Ref<AlignmentLineProps[]>,
|
||||||
) => {
|
) => {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
|
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||||
const canvasScale = computed(() => store.state.canvasScale)
|
const canvasScale = computed(() => store.state.canvasScale)
|
||||||
const viewportRatio = computed(() => store.state.viewportRatio)
|
const viewportRatio = computed(() => store.state.viewportRatio)
|
||||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||||
|
@ -5,21 +5,22 @@ import { PPTElement } from '@/types/slides'
|
|||||||
|
|
||||||
export default (
|
export default (
|
||||||
elementList: Ref<PPTElement[]>,
|
elementList: Ref<PPTElement[]>,
|
||||||
activeGroupElementId: Ref<string>,
|
|
||||||
moveElement: (e: MouseEvent, element: PPTElement) => void,
|
moveElement: (e: MouseEvent, element: PPTElement) => void,
|
||||||
) => {
|
) => {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
const handleElementId = computed(() => store.state.handleElementId)
|
const handleElementId = computed(() => store.state.handleElementId)
|
||||||
|
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||||
|
|
||||||
// 选中元素
|
// 选中元素
|
||||||
const selectElement = (e: MouseEvent, element: PPTElement, canMove = true) => {
|
// startMove 表示是否需要再选中操作后进入到开始移动的状态
|
||||||
|
const selectElement = (e: MouseEvent, element: PPTElement, startMove = true) => {
|
||||||
if (!editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
if (!editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, true)
|
||||||
|
|
||||||
// 如果目标元素当前未被选中,则将他设为选中状态
|
// 如果目标元素当前未被选中,则将他设为选中状态
|
||||||
// 此时如果按下Ctrl键或Shift键,则进入多选状态,将当前已选中的元素和目标元素一桶设置为选中状态,否则仅将目标元素设置为选中状态
|
// 此时如果按下Ctrl键或Shift键,则进入多选状态,将当前已选中的元素和目标元素一起设置为选中状态,否则仅将目标元素设置为选中状态
|
||||||
// 如果目标元素是分组成员,需要将该组合的其他元素一起设置为选中状态
|
// 如果目标元素是分组成员,需要将该组合的其他元素一起设置为选中状态
|
||||||
if (!activeElementIdList.value.includes(element.id)) {
|
if (!activeElementIdList.value.includes(element.id)) {
|
||||||
let newActiveIdList: string[] = []
|
let newActiveIdList: string[] = []
|
||||||
@ -78,13 +79,13 @@ export default (
|
|||||||
const currentPageY = e.pageY
|
const currentPageY = e.pageY
|
||||||
|
|
||||||
if (startPageX === currentPageX && startPageY === currentPageY) {
|
if (startPageX === currentPageX && startPageY === currentPageY) {
|
||||||
activeGroupElementId.value = element.id
|
store.commit(MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID, element.id)
|
||||||
;(e.target as HTMLElement).onmouseup = null
|
;(e.target as HTMLElement).onmouseup = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canMove) moveElement(e, element)
|
if (startMove) moveElement(e, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选中页面内的全部元素
|
// 选中页面内的全部元素
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div
|
<div
|
||||||
class="canvas"
|
class="canvas"
|
||||||
ref="canvasRef"
|
ref="canvasRef"
|
||||||
@mousewheel="$event => mousewheelScaleCanvas($event)"
|
@mousewheel="$event => handleMousewheelCanvas($event)"
|
||||||
@mousedown="$event => handleClickBlankArea($event)"
|
@mousedown="$event => handleClickBlankArea($event)"
|
||||||
v-contextmenu="contextmenus"
|
v-contextmenu="contextmenus"
|
||||||
v-click-outside="removeEditorAreaFocus"
|
v-click-outside="removeEditorAreaFocus"
|
||||||
@ -82,6 +82,7 @@ import { ContextmenuItem } from '@/components/Contextmenu/types'
|
|||||||
import { PPTElement, Slide } from '@/types/slides'
|
import { PPTElement, Slide } from '@/types/slides'
|
||||||
import { AlignmentLineProps } from '@/types/edit'
|
import { AlignmentLineProps } from '@/types/edit'
|
||||||
import { removeAllRanges } from '@/utils/selection'
|
import { removeAllRanges } from '@/utils/selection'
|
||||||
|
import { KEYS } from '@/configs/hotkey'
|
||||||
|
|
||||||
import useViewportSize from './hooks/useViewportSize'
|
import useViewportSize from './hooks/useViewportSize'
|
||||||
import useMouseSelection from './hooks/useMouseSelection'
|
import useMouseSelection from './hooks/useMouseSelection'
|
||||||
@ -98,6 +99,7 @@ import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
|
|||||||
import useSelectAllElement from '@/hooks/useSelectAllElement'
|
import useSelectAllElement from '@/hooks/useSelectAllElement'
|
||||||
import useScaleCanvas from '@/hooks/useScaleCanvas'
|
import useScaleCanvas from '@/hooks/useScaleCanvas'
|
||||||
import useScreening from '@/hooks/useScreening'
|
import useScreening from '@/hooks/useScreening'
|
||||||
|
import useSlideHandler from '@/hooks/useSlideHandler'
|
||||||
|
|
||||||
import EditableElement from './EditableElement.vue'
|
import EditableElement from './EditableElement.vue'
|
||||||
import MouseSelection from './MouseSelection.vue'
|
import MouseSelection from './MouseSelection.vue'
|
||||||
@ -123,6 +125,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
const activeElementIdList = computed(() => store.state.activeElementIdList)
|
||||||
const handleElementId = computed(() => store.state.handleElementId)
|
const handleElementId = computed(() => store.state.handleElementId)
|
||||||
|
const activeGroupElementId = computed(() => store.state.activeGroupElementId)
|
||||||
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
const editorAreaFocus = computed(() => store.state.editorAreaFocus)
|
||||||
const ctrlKeyState = computed(() => store.state.ctrlKeyState)
|
const ctrlKeyState = computed(() => store.state.ctrlKeyState)
|
||||||
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
const ctrlOrShiftKeyActive = computed<boolean>(() => store.getters.ctrlOrShiftKeyActive)
|
||||||
@ -130,8 +133,9 @@ export default defineComponent({
|
|||||||
const viewportRef = ref<HTMLElement>()
|
const viewportRef = ref<HTMLElement>()
|
||||||
const alignmentLines = ref<AlignmentLineProps[]>([])
|
const alignmentLines = ref<AlignmentLineProps[]>([])
|
||||||
|
|
||||||
const activeGroupElementId = ref('')
|
watch(handleElementId, () => {
|
||||||
watch(handleElementId, () => activeGroupElementId.value = '')
|
store.commit(MutationTypes.SET_ACTIVE_GROUP_ELEMENT_ID, '')
|
||||||
|
})
|
||||||
|
|
||||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||||
const elementList = ref<PPTElement[]>([])
|
const elementList = ref<PPTElement[]>([])
|
||||||
@ -148,16 +152,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef)
|
const { mouseSelectionState, updateMouseSelection } = useMouseSelection(elementList, viewportRef)
|
||||||
|
|
||||||
const { dragElement } = useDragElement(elementList, activeGroupElementId, alignmentLines)
|
const { dragElement } = useDragElement(elementList, alignmentLines)
|
||||||
const { dragLineElement } = useDragLineElement(elementList)
|
const { dragLineElement } = useDragLineElement(elementList)
|
||||||
const { selectElement } = useSelectElement(elementList, activeGroupElementId, dragElement)
|
const { selectElement } = useSelectElement(elementList, dragElement)
|
||||||
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, activeGroupElementId, alignmentLines)
|
const { scaleElement, scaleMultiElement } = useScaleElement(elementList, alignmentLines)
|
||||||
const { rotateElement } = useRotateElement(elementList, viewportRef)
|
const { rotateElement } = useRotateElement(elementList, viewportRef)
|
||||||
|
|
||||||
const { selectAllElement } = useSelectAllElement()
|
const { selectAllElement } = useSelectAllElement()
|
||||||
const { deleteAllElements } = useDeleteElement()
|
const { deleteAllElements } = useDeleteElement()
|
||||||
const { pasteElement } = useCopyAndPasteElement()
|
const { pasteElement } = useCopyAndPasteElement()
|
||||||
const { enterScreening } = useScreening()
|
const { enterScreening } = useScreening()
|
||||||
|
const { updateSlideIndex } = useSlideHandler()
|
||||||
|
|
||||||
// 点击画布的空白区域:清空焦点元素、设置画布焦点、清除文字选区
|
// 点击画布的空白区域:清空焦点元素、设置画布焦点、清除文字选区
|
||||||
const handleClickBlankArea = (e: MouseEvent) => {
|
const handleClickBlankArea = (e: MouseEvent) => {
|
||||||
@ -172,17 +177,25 @@ export default defineComponent({
|
|||||||
if (editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
if (editorAreaFocus.value) store.commit(MutationTypes.SET_EDITORAREA_FOCUS, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按住Ctrl键滚动鼠标缩放画布
|
// 滚动鼠标
|
||||||
const { scaleCanvas } = useScaleCanvas()
|
const { scaleCanvas } = useScaleCanvas()
|
||||||
const throttleScaleCanvas = throttle(scaleCanvas, 100, { leading: true, trailing: false })
|
const throttleScaleCanvas = throttle(scaleCanvas, 100, { leading: true, trailing: false })
|
||||||
|
const throttleUpdateSlideIndex = throttle(updateSlideIndex, 300, { leading: true, trailing: false })
|
||||||
|
|
||||||
const mousewheelScaleCanvas = (e: WheelEvent) => {
|
const handleMousewheelCanvas = (e: WheelEvent) => {
|
||||||
if (!ctrlKeyState.value) return
|
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
// 按住Ctrl键时:缩放画布
|
||||||
|
if (ctrlKeyState.value) {
|
||||||
if (e.deltaY > 0) throttleScaleCanvas('-')
|
if (e.deltaY > 0) throttleScaleCanvas('-')
|
||||||
else if (e.deltaY < 0) throttleScaleCanvas('+')
|
else if (e.deltaY < 0) throttleScaleCanvas('+')
|
||||||
}
|
}
|
||||||
|
// 上下翻页
|
||||||
|
else {
|
||||||
|
if (e.deltaY > 0) throttleUpdateSlideIndex(KEYS.DOWN)
|
||||||
|
else if (e.deltaY < 0) throttleUpdateSlideIndex(KEYS.UP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 开关网格线
|
// 开关网格线
|
||||||
const showGridLines = computed(() => store.state.showGridLines)
|
const showGridLines = computed(() => store.state.showGridLines)
|
||||||
@ -247,7 +260,7 @@ export default defineComponent({
|
|||||||
scaleElement,
|
scaleElement,
|
||||||
dragLineElement,
|
dragLineElement,
|
||||||
scaleMultiElement,
|
scaleMultiElement,
|
||||||
mousewheelScaleCanvas,
|
handleMousewheelCanvas,
|
||||||
contextmenus,
|
contextmenus,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -186,6 +186,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
.handler-item {
|
.handler-item {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&.disable {
|
&.disable {
|
||||||
@ -202,8 +203,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.viewport-size {
|
.viewport-size {
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
margin-top: -1px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,110 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="export-dialog">
|
<div class="export-dialog">
|
||||||
<div class="tabs">
|
<div class="preview">
|
||||||
<div
|
|
||||||
class="tab"
|
|
||||||
:class="{ 'active': tab.value === currentTab }"
|
|
||||||
v-for="tab in tabs"
|
|
||||||
:key="tab.value"
|
|
||||||
@click="currentTab = tab.value"
|
|
||||||
>{{tab.label}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content json" v-if="currentTab === 'json'">
|
|
||||||
<div class="json-preview">
|
|
||||||
<pre>{{slides}}</pre>
|
<pre>{{slides}}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="json-configs">
|
<div class="handle">
|
||||||
<Button class="btn" type="primary" @click="exportJSON()">导出 JSON 文件</Button>
|
<Button class="btn" type="primary" @click="exportJSON()">导出</Button>
|
||||||
<Button class="btn" @click="emit('close')">关闭</Button>
|
<Button class="btn" @click="emit('close')">关闭</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content image" v-if="currentTab === 'image'">
|
|
||||||
<div class="thumbnails-view">
|
|
||||||
<div class="thumbnails" ref="imageThumbnailsRef">
|
|
||||||
<ThumbnailSlide
|
|
||||||
class="thumbnail"
|
|
||||||
v-for="slide in slides"
|
|
||||||
:key="slide.id"
|
|
||||||
:slide="slide"
|
|
||||||
:size="1600"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="configs">
|
|
||||||
<Button class="btn" type="primary" @click="exportImage('png')">导出 PNG 图片</Button>
|
|
||||||
<Button class="btn" type="primary" @click="exportImage('jpeg')">导出 JPEG 图片</Button>
|
|
||||||
<Button class="btn" @click="emit('close')">关闭</Button>
|
|
||||||
</div>
|
|
||||||
<div class="spinning" v-if="spinning">
|
|
||||||
<Spin />
|
|
||||||
<div class="tip">正在导出,请稍等...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, ref } from 'vue'
|
import { computed, defineComponent } from 'vue'
|
||||||
import { useStore } from '@/store'
|
import { useStore } from '@/store'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import { toPng, toJpeg } from 'html-to-image'
|
|
||||||
|
|
||||||
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
|
|
||||||
import { message } from 'ant-design-vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'export-dialog',
|
name: 'export-dialog',
|
||||||
components: {
|
|
||||||
ThumbnailSlide,
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const slides = computed(() => store.state.slides)
|
const slides = computed(() => store.state.slides)
|
||||||
|
|
||||||
const tabs = ref([
|
|
||||||
{ label: 'JSON', value: 'json' },
|
|
||||||
{ label: '图片', value: 'image' },
|
|
||||||
])
|
|
||||||
|
|
||||||
const currentTab = ref('json')
|
|
||||||
const spinning = ref(false)
|
|
||||||
|
|
||||||
const exportJSON = () => {
|
const exportJSON = () => {
|
||||||
const blob = new Blob([JSON.stringify(slides.value)], { type: '' })
|
const blob = new Blob([JSON.stringify(slides.value)], { type: '' })
|
||||||
saveAs(blob, 'pptist_slides.json')
|
saveAs(blob, 'pptist_slides.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageThumbnailsRef = ref<HTMLElement>()
|
|
||||||
const exportImage = (type: string) => {
|
|
||||||
spinning.value = true
|
|
||||||
const toImage = type === 'png' ? toPng : toJpeg
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!imageThumbnailsRef.value) return
|
|
||||||
|
|
||||||
toImage(imageThumbnailsRef.value, {
|
|
||||||
quality: 0.95,
|
|
||||||
width: 1600,
|
|
||||||
}).then(dataUrl => {
|
|
||||||
spinning.value = false
|
|
||||||
saveAs(dataUrl, `pptist_slides.${type}`)
|
|
||||||
}).catch(() => {
|
|
||||||
spinning.value = false
|
|
||||||
message.error('导出图片失败')
|
|
||||||
})
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tabs,
|
|
||||||
currentTab,
|
|
||||||
spinning,
|
|
||||||
slides,
|
slides,
|
||||||
exportJSON,
|
exportJSON,
|
||||||
exportImage,
|
|
||||||
imageThumbnailsRef,
|
|
||||||
emit,
|
emit,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -114,40 +39,11 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.export-dialog {
|
.export-dialog {
|
||||||
height: 500px;
|
height: 500px;
|
||||||
}
|
|
||||||
.tabs {
|
|
||||||
height: 40px;
|
|
||||||
font-size: 12px;
|
|
||||||
display: flex;
|
|
||||||
margin: -24px -24px 20px -24px;
|
|
||||||
}
|
|
||||||
.tab {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: $lightGray;
|
|
||||||
border-bottom: 1px solid $borderColor;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: #fff;
|
|
||||||
border-bottom-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
& + .tab {
|
|
||||||
border-left: 1px solid $borderColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
height: calc(100% - 60px);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
.json-preview {
|
.preview {
|
||||||
width: 460px;
|
width: 460px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -160,7 +56,7 @@ export default defineComponent({
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.json-configs {
|
.handle {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
@ -168,52 +64,4 @@ export default defineComponent({
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnails-view {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.configs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 240px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinning {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
margin-top: 10px;
|
|
||||||
color: $themeColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -11,7 +11,7 @@
|
|||||||
<MenuItem @click="deleteSlide()">删除页面</MenuItem>
|
<MenuItem @click="deleteSlide()">删除页面</MenuItem>
|
||||||
<MenuItem @click="toggleGridLines()">{{ showGridLines ? '关闭网格线' : '打开网格线' }}</MenuItem>
|
<MenuItem @click="toggleGridLines()">{{ showGridLines ? '关闭网格线' : '打开网格线' }}</MenuItem>
|
||||||
<MenuItem @click="resetSlides()">重置幻灯片</MenuItem>
|
<MenuItem @click="resetSlides()">重置幻灯片</MenuItem>
|
||||||
<MenuItem @click="exportDialogVisible = true">导出为</MenuItem>
|
<MenuItem @click="exportDialogVisible = true">导出 JSON</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</template>
|
</template>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
@ -28,7 +28,6 @@
|
|||||||
<div class="menu-item"><IconHelpcenter /> <span class="text">帮助</span></div>
|
<div class="menu-item"><IconHelpcenter /> <span class="text">帮助</span></div>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuItem @click="openDoc()">开发文档</MenuItem>
|
|
||||||
<MenuItem @click="hotkeyDrawerVisible = true">快捷键</MenuItem>
|
<MenuItem @click="hotkeyDrawerVisible = true">快捷键</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</template>
|
</template>
|
||||||
@ -78,8 +77,6 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
|||||||
import HotkeyDoc from './HotkeyDoc.vue'
|
import HotkeyDoc from './HotkeyDoc.vue'
|
||||||
import ExportDialog from './ExportDialog.vue'
|
import ExportDialog from './ExportDialog.vue'
|
||||||
|
|
||||||
import { message } from 'ant-design-vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'editor-header',
|
name: 'editor-header',
|
||||||
components: {
|
components: {
|
||||||
@ -98,10 +95,6 @@ export default defineComponent({
|
|||||||
store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
|
store.commit(MutationTypes.SET_GRID_LINES_STATE, !showGridLines.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const openDoc = () => {
|
|
||||||
message.warning('作者努力编写中...')
|
|
||||||
}
|
|
||||||
|
|
||||||
const hotkeyDrawerVisible = ref(false)
|
const hotkeyDrawerVisible = ref(false)
|
||||||
const exportDialogVisible = ref(false)
|
const exportDialogVisible = ref(false)
|
||||||
|
|
||||||
@ -115,7 +108,6 @@ export default defineComponent({
|
|||||||
toggleGridLines,
|
toggleGridLines,
|
||||||
showGridLines,
|
showGridLines,
|
||||||
resetSlides,
|
resetSlides,
|
||||||
openDoc,
|
|
||||||
hotkeyDrawerVisible,
|
hotkeyDrawerVisible,
|
||||||
exportDialogVisible,
|
exportDialogVisible,
|
||||||
}
|
}
|
||||||
@ -142,7 +134,7 @@ export default defineComponent({
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
transition: background-color .2s;
|
transition: background-color .2s;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
v-click-outside="() => setThumbnailsFocus(false)"
|
v-click-outside="() => setThumbnailsFocus(false)"
|
||||||
v-contextmenu="contextmenusThumbnails"
|
v-contextmenu="contextmenusThumbnails"
|
||||||
>
|
>
|
||||||
<div class="add-slide" @click="createSlide()"><IconPlus /> 添加幻灯片</div>
|
<div class="add-slide" @click="createSlide()"><IconPlus class="icon" />添加幻灯片</div>
|
||||||
<Draggable
|
<Draggable
|
||||||
class="thumbnail-list"
|
class="thumbnail-list"
|
||||||
:modelValue="slides"
|
:modelValue="slides"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
'active': slideIndex === index,
|
'active': slideIndex === index,
|
||||||
'selected': selectedSlidesIndex.includes(index),
|
'selected': selectedSlidesIndex.includes(index),
|
||||||
}"
|
}"
|
||||||
@mousedown="handleClickSlideThumbnail(index)"
|
@mousedown="$event => handleClickSlideThumbnail($event, index)"
|
||||||
v-contextmenu="contextmenusThumbnailItem"
|
v-contextmenu="contextmenusThumbnailItem"
|
||||||
>
|
>
|
||||||
<div class="label">{{ fillDigit(index + 1, 2) }}</div>
|
<div class="label">{{ fillDigit(index + 1, 2) }}</div>
|
||||||
@ -77,9 +77,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 点击缩略图
|
// 点击缩略图
|
||||||
const handleClickSlideThumbnail = (index: number) => {
|
const handleClickSlideThumbnail = (e: MouseEvent, index: number) => {
|
||||||
const isMultiSelected = selectedSlidesIndex.value.length > 1
|
const isMultiSelected = selectedSlidesIndex.value.length > 1
|
||||||
|
|
||||||
|
if (isMultiSelected && selectedSlidesIndex.value.includes(index) && e.button !== 0) return
|
||||||
|
|
||||||
// 按住Ctrl键,点选幻灯片,再次点击已选中的页面则取消选中
|
// 按住Ctrl键,点选幻灯片,再次点击已选中的页面则取消选中
|
||||||
if (ctrlKeyState.value) {
|
if (ctrlKeyState.value) {
|
||||||
if (slideIndex.value === index) {
|
if (slideIndex.value === index) {
|
||||||
@ -255,6 +257,11 @@ export default defineComponent({
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-bottom: 1px solid $borderColor;
|
border-bottom: 1px solid $borderColor;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.thumbnail-list {
|
.thumbnail-list {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
|
@ -129,7 +129,7 @@ export default defineComponent({
|
|||||||
const themeColor = ref<string>('')
|
const themeColor = ref<string>('')
|
||||||
const gridColor = ref('')
|
const gridColor = ref('')
|
||||||
|
|
||||||
const lineSmooth = ref<boolean | Function>(true)
|
const lineSmooth = ref(true)
|
||||||
const showLine = ref(true)
|
const showLine = ref(true)
|
||||||
const showArea = ref(false)
|
const showArea = ref(false)
|
||||||
const horizontalBars = ref(false)
|
const horizontalBars = ref(false)
|
||||||
@ -148,7 +148,7 @@ export default defineComponent({
|
|||||||
donut: _donut,
|
donut: _donut,
|
||||||
} = handleElement.value.options
|
} = handleElement.value.options
|
||||||
|
|
||||||
if (_lineSmooth !== undefined) lineSmooth.value = _lineSmooth
|
if (_lineSmooth !== undefined) lineSmooth.value = _lineSmooth as boolean
|
||||||
if (_showLine !== undefined) showLine.value = _showLine
|
if (_showLine !== undefined) showLine.value = _showLine
|
||||||
if (_showArea !== undefined) showArea.value = _showArea
|
if (_showArea !== undefined) showArea.value = _showArea
|
||||||
if (_horizontalBars !== undefined) horizontalBars.value = _horizontalBars
|
if (_horizontalBars !== undefined) horizontalBars.value = _horizontalBars
|
||||||
|
@ -2,24 +2,24 @@
|
|||||||
<div class="multi-position-panel">
|
<div class="multi-position-panel">
|
||||||
<ButtonGroup class="row">
|
<ButtonGroup class="row">
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="左对齐">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="左对齐">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('left')"><IconAlignLeft /></Button>
|
<Button style="flex: 1;" @click="alignElement('left')"><IconAlignLeft /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="水平居中">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="水平居中">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('horizontal')"><IconAlignVertically /></Button>
|
<Button style="flex: 1;" @click="alignElement('horizontal')"><IconAlignVertically /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="右对齐">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="右对齐">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('right')"><IconAlignRight /></Button>
|
<Button style="flex: 1;" @click="alignElement('right')"><IconAlignRight /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<ButtonGroup class="row">
|
<ButtonGroup class="row">
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="上对齐">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="上对齐">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('top')"><IconAlignTop /></Button>
|
<Button style="flex: 1;" @click="alignElement('top')"><IconAlignTop /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="垂直居中">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="垂直居中">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('vertical')"><IconAlignHorizontally /></Button>
|
<Button style="flex: 1;" @click="alignElement('vertical')"><IconAlignHorizontally /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="下对齐">
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="下对齐">
|
||||||
<Button style="flex: 1;" @click="alignActiveElement('bottom')"><IconAlignBottom /></Button>
|
<Button style="flex: 1;" @click="alignElement('bottom')"><IconAlignBottom /></Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<ButtonGroup class="row" v-if="activeElementList.length > 2">
|
<ButtonGroup class="row" v-if="activeElementList.length > 2">
|
||||||
@ -40,8 +40,10 @@
|
|||||||
import { computed, defineComponent } from 'vue'
|
import { computed, defineComponent } from 'vue'
|
||||||
import { useStore } from '@/store'
|
import { useStore } from '@/store'
|
||||||
import { PPTElement } from '@/types/slides'
|
import { PPTElement } from '@/types/slides'
|
||||||
|
import { ElementAlignCommand } from '@/types/edit'
|
||||||
import useCombineElement from '@/hooks/useCombineElement'
|
import useCombineElement from '@/hooks/useCombineElement'
|
||||||
import useAlignActiveElement from '@/hooks/useAlignActiveElement'
|
import useAlignActiveElement from '@/hooks/useAlignActiveElement'
|
||||||
|
import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas'
|
||||||
import useUniformDisplayElement from '@/hooks/useUniformDisplayElement'
|
import useUniformDisplayElement from '@/hooks/useUniformDisplayElement'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -52,6 +54,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const { combineElements, uncombineElements } = useCombineElement()
|
const { combineElements, uncombineElements } = useCombineElement()
|
||||||
const { alignActiveElement } = useAlignActiveElement()
|
const { alignActiveElement } = useAlignActiveElement()
|
||||||
|
const { alignElementToCanvas } = useAlignElementToCanvas()
|
||||||
const { uniformHorizontalDisplay, uniformVerticalDisplay } = useUniformDisplayElement()
|
const { uniformHorizontalDisplay, uniformVerticalDisplay } = useUniformDisplayElement()
|
||||||
|
|
||||||
// 判断当前多选的几个元素是否可以组合
|
// 判断当前多选的几个元素是否可以组合
|
||||||
@ -63,14 +66,22 @@ export default defineComponent({
|
|||||||
return !inSameGroup
|
return !inSameGroup
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 多选元素对齐,需要先判断当前所选中的元素状态:
|
||||||
|
// 如果所选元素为一组组合元素,则将它对齐到画布;
|
||||||
|
// 如果所选元素不是组合元素或不止一组元素(即当前为可组合状态),则将这多个(多组)元素相互对齐。
|
||||||
|
const alignElement = (command: ElementAlignCommand) => {
|
||||||
|
if (canCombine.value) alignActiveElement(command)
|
||||||
|
else alignElementToCanvas(command)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeElementList,
|
activeElementList,
|
||||||
canCombine,
|
canCombine,
|
||||||
combineElements,
|
combineElements,
|
||||||
uncombineElements,
|
uncombineElements,
|
||||||
alignActiveElement,
|
|
||||||
uniformHorizontalDisplay,
|
uniformHorizontalDisplay,
|
||||||
uniformVerticalDisplay,
|
uniformVerticalDisplay,
|
||||||
|
alignElement,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -9,9 +9,15 @@
|
|||||||
</teleport>
|
</teleport>
|
||||||
|
|
||||||
<div class="tools">
|
<div class="tools">
|
||||||
<div class="btn" :class="{ 'active': writingBoardModel === 'pen' }" @click="changePen()">画笔</div>
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.3" title="画笔">
|
||||||
<div class="btn" :class="{ 'active': writingBoardModel === 'eraser' }" @click="changeEraser()">橡皮</div>
|
<div class="btn" :class="{ 'active': writingBoardModel === 'pen' }" @click="changePen()"><IconWrite class="icon" /></div>
|
||||||
<div class="btn" @click="clearCanvas()">清除墨迹</div>
|
</Tooltip>
|
||||||
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.3" title="橡皮擦">
|
||||||
|
<div class="btn" :class="{ 'active': writingBoardModel === 'eraser' }" @click="changeEraser()"><IconErase class="icon" /></div>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.3" title="清除墨迹">
|
||||||
|
<div class="btn" @click="clearCanvas()"><IconClear class="icon" /></div>
|
||||||
|
</Tooltip>
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div
|
<div
|
||||||
class="color"
|
class="color"
|
||||||
@ -22,7 +28,9 @@
|
|||||||
@click="changeColor(color)"
|
@click="changeColor(color)"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn" @click="closeWritingBoard()">退出画笔</div>
|
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.3" title="关闭画笔">
|
||||||
|
<div class="btn" @click="closeWritingBoard()"><IconClose class="icon" /></div>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -91,41 +99,49 @@ export default defineComponent({
|
|||||||
.tools {
|
.tools {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 5px;
|
||||||
left: 0;
|
left: 5px;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: #fff;
|
background-color: #eee;
|
||||||
|
border-radius: $borderRadius;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.btn {
|
.btn {
|
||||||
padding: 6px 10px;
|
padding: 5px 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover, &.active {
|
&:hover {
|
||||||
background-color: rgba($color: $themeColor, $alpha: .2);
|
color: $themeColor;
|
||||||
}
|
}
|
||||||
|
&.active {
|
||||||
|
background-color: rgba($color: $themeColor, $alpha: .5);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
.colors {
|
.colors {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
.color {
|
.color {
|
||||||
width: 15px;
|
width: 16px;
|
||||||
height: 15px;
|
height: 16px;
|
||||||
outline: 1px solid #ccc;
|
border-radius: $borderRadius;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.1);
|
transform: scale(1.15);
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
outline: 2px solid $themeColor;
|
transform: scale(1.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
& + .color {
|
& + .color {
|
||||||
margin-left: 5px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,15 +422,9 @@ export default defineComponent({
|
|||||||
right: 8px;
|
right: 8px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
color: #666;
|
color: #666;
|
||||||
border: 2px solid #acacac;
|
background-color: #eee;
|
||||||
background-color: rgba($color: #fff, $alpha: .6);
|
|
||||||
border-radius: $borderRadius;
|
border-radius: $borderRadius;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border: 2px solid #333;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -7,7 +7,6 @@
|
|||||||
width: elementInfo.width + 'px',
|
width: elementInfo.width + 'px',
|
||||||
height: elementInfo.height + 'px',
|
height: elementInfo.height + 'px',
|
||||||
}"
|
}"
|
||||||
@mousedown="$event => handleSelectElement($event)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="element-content"
|
class="element-content"
|
||||||
@ -15,6 +14,7 @@
|
|||||||
backgroundColor: elementInfo.fill,
|
backgroundColor: elementInfo.fill,
|
||||||
}"
|
}"
|
||||||
v-contextmenu="contextmenus"
|
v-contextmenu="contextmenus"
|
||||||
|
@mousedown="$event => handleSelectElement($event)"
|
||||||
>
|
>
|
||||||
<ElementOutline
|
<ElementOutline
|
||||||
:width="elementInfo.width"
|
:width="elementInfo.width"
|
||||||
@ -79,7 +79,6 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.editable-element-chart {
|
.editable-element-chart {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: move;
|
|
||||||
|
|
||||||
&.lock .element-content {
|
&.lock .element-content {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -90,5 +89,6 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
cursor: move;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
width: elementInfo.width + 'px',
|
width: elementInfo.width + 'px',
|
||||||
height: elementInfo.height + 'px',
|
height: elementInfo.height + 'px',
|
||||||
}"
|
}"
|
||||||
@mousedown="$event => handleSelectElement($event)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rotate-wrapper"
|
class="rotate-wrapper"
|
||||||
@ -28,11 +27,12 @@
|
|||||||
<div
|
<div
|
||||||
class="element-content"
|
class="element-content"
|
||||||
v-else
|
v-else
|
||||||
v-contextmenu="contextmenus"
|
|
||||||
:style="{
|
:style="{
|
||||||
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
|
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
|
||||||
transform: flipStyle,
|
transform: flipStyle,
|
||||||
}"
|
}"
|
||||||
|
v-contextmenu="contextmenus"
|
||||||
|
@mousedown="$event => handleSelectElement($event)"
|
||||||
>
|
>
|
||||||
<ImageOutline :elementInfo="elementInfo" />
|
<ImageOutline :elementInfo="elementInfo" />
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
width: elementInfo.width + 'px',
|
width: elementInfo.width + 'px',
|
||||||
height: elementInfo.height + 'px',
|
height: elementInfo.height + 'px',
|
||||||
}"
|
}"
|
||||||
@mousedown="$event => handleSelectElement($event)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rotate-wrapper"
|
class="rotate-wrapper"
|
||||||
@ -16,12 +15,13 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="element-content"
|
class="element-content"
|
||||||
v-contextmenu="contextmenus"
|
|
||||||
:style="{
|
:style="{
|
||||||
opacity: elementInfo.opacity,
|
opacity: elementInfo.opacity,
|
||||||
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
|
filter: shadowStyle ? `drop-shadow(${shadowStyle})` : '',
|
||||||
transform: flipStyle,
|
transform: flipStyle,
|
||||||
}"
|
}"
|
||||||
|
v-contextmenu="contextmenus"
|
||||||
|
@mousedown="$event => handleSelectElement($event)"
|
||||||
>
|
>
|
||||||
<SvgWrapper
|
<SvgWrapper
|
||||||
overflow="visible"
|
overflow="visible"
|
||||||
@ -118,7 +118,6 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.editable-element-shape {
|
.editable-element-shape {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: move;
|
|
||||||
|
|
||||||
&.lock .element-content {
|
&.lock .element-content {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -132,6 +131,7 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
|
@ -103,6 +103,8 @@ export default defineComponent({
|
|||||||
const realHeightCache = ref(-1)
|
const realHeightCache = ref(-1)
|
||||||
|
|
||||||
const scaleElementStateListener = (state: boolean) => {
|
const scaleElementStateListener = (state: boolean) => {
|
||||||
|
if (handleElementId.value !== props.elementInfo.id) return
|
||||||
|
|
||||||
isScaling.value = state
|
isScaling.value = state
|
||||||
|
|
||||||
if (state) editable.value = false
|
if (state) editable.value = false
|
||||||
@ -190,7 +192,6 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.editable-element-table {
|
.editable-element-table {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: move;
|
|
||||||
|
|
||||||
&.lock .element-content {
|
&.lock .element-content {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -201,6 +202,7 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: move;
|
||||||
}
|
}
|
||||||
.table-mask {
|
.table-mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
left: elementInfo.left + 'px',
|
left: elementInfo.left + 'px',
|
||||||
width: elementInfo.width + 'px',
|
width: elementInfo.width + 'px',
|
||||||
}"
|
}"
|
||||||
@mousedown="$event => handleSelectElement($event)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rotate-wrapper"
|
class="rotate-wrapper"
|
||||||
@ -24,6 +23,7 @@
|
|||||||
letterSpacing: (elementInfo.wordSpace || 0) + 'px',
|
letterSpacing: (elementInfo.wordSpace || 0) + 'px',
|
||||||
}"
|
}"
|
||||||
v-contextmenu="contextmenus"
|
v-contextmenu="contextmenus"
|
||||||
|
@mousedown="$event => handleSelectElement($event)"
|
||||||
>
|
>
|
||||||
<ElementOutline
|
<ElementOutline
|
||||||
:width="elementInfo.width"
|
:width="elementInfo.width"
|
||||||
@ -108,6 +108,8 @@ export default defineComponent({
|
|||||||
// 监听文本元素的尺寸变化,当高度变化时,更新高度到vuex
|
// 监听文本元素的尺寸变化,当高度变化时,更新高度到vuex
|
||||||
// 如果高度变化时正处在缩放操作中,则等待缩放操作结束后再更新
|
// 如果高度变化时正处在缩放操作中,则等待缩放操作结束后再更新
|
||||||
const scaleElementStateListener = (state: boolean) => {
|
const scaleElementStateListener = (state: boolean) => {
|
||||||
|
if (handleElementId.value !== props.elementInfo.id) return
|
||||||
|
|
||||||
isScaling.value = state
|
isScaling.value = state
|
||||||
|
|
||||||
if (!state && realHeightCache.value !== -1) {
|
if (!state && realHeightCache.value !== -1) {
|
||||||
@ -323,7 +325,6 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.editable-element-text {
|
.editable-element-text {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: move;
|
|
||||||
|
|
||||||
&.lock .element-content {
|
&.lock .element-content {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -338,6 +339,7 @@ export default defineComponent({
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user