+
+ ` +
+ '$' +
+ `{Object.entries(params[0].value).map(kv => ` +
+ '`' +
+ `
` +
+ '$' +
+ `{kv[0]}:` +
+ '$' +
+ `{kv[1]}
` +
+ '`' +
+ `).join('')}
+
+ ` +
+ '`;' +
+ `
+ },
+ }
+})
+`
+
+// 添加【轮播列表】样式
+const addStyleString =
+ `
+// 组件样式作用域标识
+const scoped = this.subTree.scopeId
+function loadStyleString(css){
+ let style = document.createElement('style')
+ style.type = 'text/css'
+ style.appendChild(document.createTextNode(css))
+ let head = document.getElementsByTagName('head')[0]
+ head.appendChild(style)
+}
+loadStyleString(` +
+ '`' +
+ `
+.dv-scroll-board[` +
+ '$' +
+ `{scoped}] {
+ position: relative;
+ overflow: hidden;
+}
+.dv-scroll-board[` +
+ '$' +
+ `{scoped}]::before {
+ content: '';
+ display: block;
+ position: absolute;
+ top: -20%;
+ left: -100%;
+ width: 550px;
+ height: 60px;
+ transform: rotate(-45deg);
+ background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0));
+ animation: cross 2s infinite;
+}
+@keyframes cross{
+ to{
+ top: 80%;
+ left: 100%;
+ transform: rotate(-45deg);
+ }
+}
+` +
+ '`' +
+ `)
+`
+
+// 修改地图原点大小
+const editMapPointString = `
+const chart = this.refs.vChartRef.chart
+// 定义地图原点大小 同理可自定义标签等等内容
+this.props.chartConfig.option.series[0].symbolSize = (val) => {
+ return Math.sqrt(val[2]) / 3;
+}
+this.setupState.vEchartsSetOption();
+let i = 0; // 当前轮播索引
+const len = 3; // 轮播部分提示
+(function showTips() {
+ const action = (type, dataIndex) => {
+ chart.dispatchAction({
+ type,
+ dataIndex,
+ seriesIndex: 0,
+ });
+ }
+ setInterval(() => {
+ action("downplay", i);
+ action("hideTip", i);
+ if (i === len) i = 0;
+ i++;
+ action("highlight", i);
+ action("showTip", i);
+ }, 2000);
+})()
+`
+
+export const templateList = [
+ {
+ description: '获取当前组件实例',
+ code: eTemplateString
+ },
+ {
+ description: '获取全局 echarts 实例',
+ code: echartsTemplateString
+ },
+ {
+ description: '获取组件图表集合',
+ code: componentsTemplateString
+ },
+ {
+ description: '获取 nodeModules 实例',
+ code: nodeModulesTemplateString
+ },
+ {
+ description: '获取远程 CDN 库',
+ code: importTemplateString
+ },
+ {
+ description: '设置文字组件点击事件',
+ code: addClickTemplateString
+ },
+ {
+ description: '修改图表 tooltip',
+ code: tooltipTemplateString
+ },
+ {
+ description: '添加【轮播列表】样式',
+ code: addStyleString
+ },
+ {
+ description: '修改【地图】圆点,新增提示自动轮播',
+ code: editMapPointString
+ }
+]
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.ts b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.ts
new file mode 100644
index 0000000..32daaf6
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.ts
@@ -0,0 +1,3 @@
+import ChartEventAdvancedHandle from './index.vue'
+
+export { ChartEventAdvancedHandle }
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.vue b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.vue
new file mode 100644
index 0000000..581fefc
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventAdvancedHandle/index.vue
@@ -0,0 +1,253 @@
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+ // {{ EventLifeName[eventName] }}
+
+ async {{ eventName }} (e, components, echarts, node_modules) {
+
+
+
+
+
},
+
+
+
+
+
+
+
+
+
+ 高级事件编辑器(配合源码使用)
+
+
+
+
+
+
+
+
+
+
+ 提示: {{ EventLifeTip[editTab] }}
+
+
+
+
+ async function
+ {{ eventName }}(e, components, echarts, node_modules) {
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ {{ error.errorFn || '暂无' }}
+
+
+ {{ error.name || '暂无' }}
+
+
+ {{ error.message || '暂无' }}
+
+
+
+
+
+
+
+
+
+
+ 触发对应生命周期事件时接收的参数
+
+
+ 图表组件实例
+
+ {{
+ prop
+ }}
+
+
+ 当前大屏内所有组件的集合id 图表组件中的配置id,可以获取其他图表组件进行控制
+
+
+
+ 以下是内置在代码环境中可用的包变量
+
+ {{ pkg }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 说明
+
+ 通过提供的参数可为图表增加定制化的tooltip、交互事件等等
+
+
+
+ 取消
+ 保存
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.ts b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.ts
new file mode 100644
index 0000000..d45f2f1
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.ts
@@ -0,0 +1,3 @@
+import ChartEventBaseHandle from './index.vue'
+
+export { ChartEventBaseHandle }
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.vue b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.vue
new file mode 100644
index 0000000..2defea3
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/ChartEventBaseHandle/index.vue
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+ // {{ EventTypeName[eventName] }}
+
+ async {{ eventName }} (mouseEvent) {
+
+
+
+
+
},
+
+
+
+
+
+
+
+
+
+ 基础事件编辑器
+
+
+
+
+
+
+
+
+
+ 提示: ECharts 组件会拦截鼠标事件
+
+
+
+
+ async function
+ {{ eventName }}(mouseEvent) {
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+ {{ error.errorFn || '暂无' }}
+
+
+ {{ error.name || '暂无' }}
+
+
+ {{ error.message || '暂无' }}
+
+
+
+
+
+
+
+
+
+
+ 鼠标事件对象
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 说明
+
+ 编写方式同正常 JavaScript 写法
+
+
+
+ 取消
+ 保存
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/components/index.scss b/src/views/chart/ContentConfigurations/components/ChartEvent/components/index.scss
new file mode 100644
index 0000000..8cd67cf
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/components/index.scss
@@ -0,0 +1,51 @@
+/* 外层也要使用 */
+.func-keyword {
+ color: #b478cf;
+}
+
+.func-annotate {
+ color: #70c0e8;
+}
+
+@include go('chart-data-monaco-editor') {
+ .func-keyNameWord {
+ color: #70c0e8;
+ }
+ .tab-tip {
+ font-size: 12px;
+ }
+ &.n-card.n-modal,
+ .n-card {
+ @extend .go-background-filter;
+ }
+}
+@include deep() {
+ .n-layout,
+ .n-layout-sider {
+ background-color: transparent;
+ }
+ .collapse-show-box {
+ .n-card__content {
+ padding-left: 20px;
+ padding-right: 10px;
+ }
+ }
+ .go-editor-area {
+ max-height: 530px;
+ }
+ .checkbox--hidden:checked {
+ & + label {
+ .n-icon {
+ transition: all 0.3s;
+ transform: rotate(180deg);
+ }
+ }
+ & ~ .go-editor-area {
+ display: none;
+ }
+ }
+ // 优化代码换行
+ .n-code > pre {
+ white-space: break-spaces;
+ }
+}
diff --git a/src/views/chart/ContentConfigurations/components/ChartEvent/index.vue b/src/views/chart/ContentConfigurations/components/ChartEvent/index.vue
new file mode 100644
index 0000000..05e5ce4
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartEvent/index.vue
@@ -0,0 +1,21 @@
+
+
+
+
+ 组件 id:
+ {{ targetData.id }}
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentConfigurations/components/ChartSetting/index.vue b/src/views/chart/ContentConfigurations/components/ChartSetting/index.vue
new file mode 100644
index 0000000..21c7d96
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/ChartSetting/index.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentConfigurations/components/hooks/useTargetData.hook.ts b/src/views/chart/ContentConfigurations/components/hooks/useTargetData.hook.ts
new file mode 100644
index 0000000..0fde624
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/components/hooks/useTargetData.hook.ts
@@ -0,0 +1,14 @@
+import { computed, Ref } from 'vue'
+import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+
+// 获取当前对象数据
+export const useTargetData = () => {
+ const chartEditStore = useChartEditStore()
+ const targetData: Ref
= computed(() => {
+ const list = chartEditStore.getComponentList
+ const targetIndex = chartEditStore.fetchTargetIndex()
+ return list[targetIndex]
+ })
+ return { targetData, chartEditStore }
+}
diff --git a/src/views/chart/ContentConfigurations/index.d.ts b/src/views/chart/ContentConfigurations/index.d.ts
new file mode 100644
index 0000000..59ca5bc
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/index.d.ts
@@ -0,0 +1,7 @@
+export enum TabsEnum {
+ PAGE_SETTING = 'pageSetting',
+ CHART_SETTING = 'chartSetting',
+ CHART_ANIMATION = 'chartAnimation',
+ CHART_DATA = 'chartData',
+ CHART_EVENT = 'chartEvent'
+}
diff --git a/src/views/chart/ContentConfigurations/index.ts b/src/views/chart/ContentConfigurations/index.ts
new file mode 100644
index 0000000..e708cd5
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/index.ts
@@ -0,0 +1,3 @@
+import ContentConfigurations from './index.vue'
+
+export { ContentConfigurations }
diff --git a/src/views/chart/ContentConfigurations/index.vue b/src/views/chart/ContentConfigurations/index.vue
new file mode 100644
index 0000000..110a3c2
--- /dev/null
+++ b/src/views/chart/ContentConfigurations/index.vue
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditAlignLine/index.ts b/src/views/chart/ContentEdit/components/EditAlignLine/index.ts
new file mode 100644
index 0000000..d07271c
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditAlignLine/index.ts
@@ -0,0 +1,3 @@
+import EditAlignLine from './index.vue'
+
+export { EditAlignLine }
diff --git a/src/views/chart/ContentEdit/components/EditAlignLine/index.vue b/src/views/chart/ContentEdit/components/EditAlignLine/index.vue
new file mode 100644
index 0000000..bfa3000
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditAlignLine/index.vue
@@ -0,0 +1,285 @@
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditBottom/index.ts b/src/views/chart/ContentEdit/components/EditBottom/index.ts
new file mode 100644
index 0000000..d987298
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditBottom/index.ts
@@ -0,0 +1,3 @@
+import EditBottom from './index.vue'
+
+export { EditBottom }
diff --git a/src/views/chart/ContentEdit/components/EditBottom/index.vue b/src/views/chart/ContentEdit/components/EditBottom/index.vue
new file mode 100644
index 0000000..2f21b65
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditBottom/index.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ lockScale ? '解锁' : '锁定' }}当前比例
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditDataSync/index.ts b/src/views/chart/ContentEdit/components/EditDataSync/index.ts
new file mode 100644
index 0000000..b012584
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditDataSync/index.ts
@@ -0,0 +1,3 @@
+import EditDataSync from './index.vue'
+
+export { EditDataSync }
diff --git a/src/views/chart/ContentEdit/components/EditDataSync/index.vue b/src/views/chart/ContentEdit/components/EditDataSync/index.vue
new file mode 100644
index 0000000..7a2a8f8
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditDataSync/index.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+ {{ statusDesc }}
+
+
+ {{saveInterval}}s 更新一次
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditGroup/index.ts b/src/views/chart/ContentEdit/components/EditGroup/index.ts
new file mode 100644
index 0000000..4fd9d52
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditGroup/index.ts
@@ -0,0 +1,3 @@
+import EditGroup from './index.vue'
+
+export { EditGroup }
diff --git a/src/views/chart/ContentEdit/components/EditGroup/index.vue b/src/views/chart/ContentEdit/components/EditGroup/index.vue
new file mode 100644
index 0000000..5d7f146
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditGroup/index.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditHistory/index.ts b/src/views/chart/ContentEdit/components/EditHistory/index.ts
new file mode 100644
index 0000000..36ca8b2
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditHistory/index.ts
@@ -0,0 +1,3 @@
+import EditHistory from './index.vue'
+
+export { EditHistory }
diff --git a/src/views/chart/ContentEdit/components/EditHistory/index.vue b/src/views/chart/ContentEdit/components/EditHistory/index.vue
new file mode 100644
index 0000000..a9c6c6a
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditHistory/index.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
+ 历史记录
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 最多只保留{{ editHistoryMax }}条记录
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditRange/index.ts b/src/views/chart/ContentEdit/components/EditRange/index.ts
new file mode 100644
index 0000000..eadec58
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditRange/index.ts
@@ -0,0 +1,3 @@
+import EditRange from './index.vue'
+
+export { EditRange }
diff --git a/src/views/chart/ContentEdit/components/EditRange/index.vue b/src/views/chart/ContentEdit/components/EditRange/index.vue
new file mode 100644
index 0000000..d9a7bcc
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditRange/index.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditRule/index.ts b/src/views/chart/ContentEdit/components/EditRule/index.ts
new file mode 100644
index 0000000..426c4ce
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditRule/index.ts
@@ -0,0 +1,3 @@
+import EditRule from './index.vue'
+
+export { EditRule }
diff --git a/src/views/chart/ContentEdit/components/EditRule/index.vue b/src/views/chart/ContentEdit/components/EditRule/index.vue
new file mode 100644
index 0000000..e200bee
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditRule/index.vue
@@ -0,0 +1,356 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditSelect/index.ts b/src/views/chart/ContentEdit/components/EditSelect/index.ts
new file mode 100644
index 0000000..88b3334
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditSelect/index.ts
@@ -0,0 +1,3 @@
+import EditSelect from './index.vue'
+
+export { EditSelect }
diff --git a/src/views/chart/ContentEdit/components/EditSelect/index.vue b/src/views/chart/ContentEdit/components/EditSelect/index.vue
new file mode 100644
index 0000000..90fc086
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditSelect/index.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditShapeBox/index.ts b/src/views/chart/ContentEdit/components/EditShapeBox/index.ts
new file mode 100644
index 0000000..8980e45
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditShapeBox/index.ts
@@ -0,0 +1,3 @@
+import EditShapeBox from './index.vue'
+
+export { EditShapeBox }
diff --git a/src/views/chart/ContentEdit/components/EditShapeBox/index.vue b/src/views/chart/ContentEdit/components/EditShapeBox/index.vue
new file mode 100644
index 0000000..b509b32
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditShapeBox/index.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditShortcutKey/ShortcutKeyModal.vue b/src/views/chart/ContentEdit/components/EditShortcutKey/ShortcutKeyModal.vue
new file mode 100644
index 0000000..c8ed76a
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditShortcutKey/ShortcutKeyModal.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+ 功能 |
+ Win 快捷键 |
+
+
+ Mac 快捷键
+
+
+
+
+ |
+
+
+
+
+ {{ item.label }} |
+ {{ item.win }} |
+ {{ item.mac }} |
+
+ {{ item.mac.substr(0, 1) }}
+ + {{ item.mac.substr(3) }}
+ |
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditShortcutKey/index.ts b/src/views/chart/ContentEdit/components/EditShortcutKey/index.ts
new file mode 100644
index 0000000..377edf8
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditShortcutKey/index.ts
@@ -0,0 +1,3 @@
+import EditShortcutKey from './index.vue'
+
+export { EditShortcutKey }
\ No newline at end of file
diff --git a/src/views/chart/ContentEdit/components/EditShortcutKey/index.vue b/src/views/chart/ContentEdit/components/EditShortcutKey/index.vue
new file mode 100644
index 0000000..1ffc816
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditShortcutKey/index.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+ 快捷键
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditTools/hooks/useFile.hooks.ts b/src/views/chart/ContentEdit/components/EditTools/hooks/useFile.hooks.ts
new file mode 100644
index 0000000..3acc824
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/hooks/useFile.hooks.ts
@@ -0,0 +1,68 @@
+import { ref, nextTick } from 'vue'
+import { UploadCustomRequestOptions } from 'naive-ui'
+import { FileTypeEnum } from '@/enums/fileTypeEnum'
+import { readFile, goDialog, JSONParse } from '@/utils'
+import { useSync } from '@/views/chart/hooks/useSync.hook'
+
+export const useFile = () => {
+ const importUploadFileListRef = ref()
+ const { updateComponent } = useSync()
+ // 上传-前置
+ //@ts-ignore
+ const importBeforeUpload = ({ file }) => {
+ importUploadFileListRef.value = []
+ const type = file.file.type
+ if (type !== FileTypeEnum.JSON && type !== FileTypeEnum.TXT) {
+ window['$message'].warning('仅支持上传 【JSON】 格式文件,请重新上传!')
+ return false
+ }
+ return true
+ }
+
+ // 上传-导入
+ const importCustomRequest = (options: UploadCustomRequestOptions) => {
+ const { file } = options
+ nextTick(() => {
+ if (file.file) {
+ readFile(file.file).then((fileData: any) => {
+ goDialog({
+ message: '请选择导入方式:',
+ positiveText: '新增(可撤回)',
+ negativeText: '覆盖(不可撤回)',
+ negativeButtonProps: { type: 'info', ghost: false },
+ // 新增
+ onPositiveCallback: async () => {
+ try {
+ fileData = JSONParse(fileData)
+ await updateComponent(fileData, false, true)
+ window['$message'].success('导入成功!')
+ } catch (error) {
+ console.log(error)
+ window['$message'].error('组件导入失败,请检查文件完整性!')
+ }
+ },
+ // 覆盖
+ onNegativeCallback: async () => {
+ try {
+ fileData = JSONParse(fileData)
+ await updateComponent(fileData, true, true)
+ window['$message'].success('导入成功!')
+ } catch (error) {
+ console.log(error)
+ window['$message'].error('组件导入失败,请检查文件完整性!')
+ }
+ }
+ })
+ })
+ } else {
+ window['$message'].error('导入失败,请检查数据或联系管理员!')
+ }
+ })
+ }
+
+ return {
+ importUploadFileListRef,
+ importBeforeUpload,
+ importCustomRequest
+ }
+}
diff --git a/src/views/chart/ContentEdit/components/EditTools/hooks/useSyncUpdate.hook.ts b/src/views/chart/ContentEdit/components/EditTools/hooks/useSyncUpdate.hook.ts
new file mode 100644
index 0000000..3a1633a
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/hooks/useSyncUpdate.hook.ts
@@ -0,0 +1,65 @@
+import { watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { useSync } from '@/views/chart/hooks/useSync.hook'
+import { ChartEnum } from '@/enums/pageEnum'
+import { SavePageEnum } from '@/enums/editPageEnum'
+import { editToJsonInterval } from '@/settings/designSetting'
+
+const { updateComponent, dataSyncUpdate } = useSync()
+const chartEditStore = useChartEditStore()
+
+// 侦听器更新
+const useSyncUpdateHandle = () => {
+ // 定义侦听器变量
+ let timer: any
+ const updateFn = (e: any) => updateComponent(e!.detail, true, false)
+ const syncData = async () => {
+ dataSyncUpdate && (await dataSyncUpdate())
+ dispatchEvent(new CustomEvent(SavePageEnum.CHART, { detail: chartEditStore.getStorageInfo }))
+ }
+
+ // 开启侦听
+ const use = () => {
+ // // 1、定时同步数据
+ // timer = setInterval(() => {
+ // // 窗口激活并且处于工作台
+ // document.hasFocus() && syncData()
+ // }, editToJsonInterval)
+ // // 1、定时同步数据
+ // timer = setInterval(() => {
+ // // 窗口激活并且处于工作台
+ // document.hasFocus() && syncData()
+ // }, editToJsonInterval)
+ // 2、失焦同步数据
+ addEventListener('blur', syncData)
+
+ // 【监听JSON代码 刷新工作台图表】
+ addEventListener(SavePageEnum.JSON, updateFn)
+ }
+
+ // 关闭侦听
+ const unUse = () => {
+ // clearInterval(timer)
+ // clearInterval(timer)
+ removeEventListener(SavePageEnum.JSON, updateFn)
+ removeEventListener('blur', syncData)
+ }
+
+ // 路由变更时处理
+ const watchHandler = (toName: any, fromName: any) => {
+ if (fromName == ChartEnum.CHART_HOME_NAME) {
+ unUse()
+ }
+ if (toName == ChartEnum.CHART_HOME_NAME) {
+ use()
+ }
+ }
+
+ return watchHandler
+}
+
+export const useSyncUpdate = () => {
+ const routerParamsInfo = useRoute()
+ watch(() => routerParamsInfo.name, useSyncUpdateHandle(), { immediate: true })
+}
\ No newline at end of file
diff --git a/src/views/chart/ContentEdit/components/EditTools/index.d.ts b/src/views/chart/ContentEdit/components/EditTools/index.d.ts
new file mode 100644
index 0000000..950436d
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/index.d.ts
@@ -0,0 +1,12 @@
+export enum TypeEnum {
+ BUTTON = 'button',
+ IMPORTUPLOAD = 'importUpload'
+}
+
+export type BtnListType = {
+ key: string
+ type: TypeEnum
+ name: string
+ icon: any
+ handle?: () => void
+}
diff --git a/src/views/chart/ContentEdit/components/EditTools/index.ts b/src/views/chart/ContentEdit/components/EditTools/index.ts
new file mode 100644
index 0000000..e4dcfcb
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/index.ts
@@ -0,0 +1,3 @@
+import EditTools from './index.vue'
+
+export { EditTools }
diff --git a/src/views/chart/ContentEdit/components/EditTools/index.vue b/src/views/chart/ContentEdit/components/EditTools/index.vue
new file mode 100644
index 0000000..79d2eb6
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/index.vue
@@ -0,0 +1,370 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentEdit/components/EditTools/utils/index.ts b/src/views/chart/ContentEdit/components/EditTools/utils/index.ts
new file mode 100644
index 0000000..39e7af1
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditTools/utils/index.ts
@@ -0,0 +1,41 @@
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { canvasCut, downloadTextFile, JSONStringify } from '@/utils'
+const chartEditStore = useChartEditStore()
+
+// 导出
+export const exportHandle = () => {
+ // 取消选中
+ chartEditStore.setTargetSelectChart(undefined)
+
+ // 导出数据
+ downloadTextFile(
+ JSONStringify(chartEditStore.getStorageInfo || []),
+ undefined,
+ 'json'
+ )
+
+ // 导出图片
+ const range = document.querySelector('.go-edit-range') as HTMLElement
+ const watermark = document.getElementById('go-edit-watermark')
+ // 隐藏边距线
+ if (!range || !watermark) {
+ window['$message'].error('导出失败!')
+ return
+ }
+
+ // 记录缩放比例
+ const scaleTemp = chartEditStore.getEditCanvas.scale
+ // 百分百展示页面
+ chartEditStore.setScale(1, true)
+ // 展示水印
+ watermark.style.display = 'block'
+
+ setTimeout(() => {
+ canvasCut(range, () => {
+ // 隐藏水印
+ if (watermark) watermark.style.display = 'none'
+ // 还原页面大小
+ chartEditStore.setScale(scaleTemp, true)
+ })
+ }, 600)
+}
diff --git a/src/views/chart/ContentEdit/components/EditWatermark/index.ts b/src/views/chart/ContentEdit/components/EditWatermark/index.ts
new file mode 100644
index 0000000..77882ab
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditWatermark/index.ts
@@ -0,0 +1,3 @@
+import EditWatermark from './index.vue'
+
+export { EditWatermark }
diff --git a/src/views/chart/ContentEdit/components/EditWatermark/index.vue b/src/views/chart/ContentEdit/components/EditWatermark/index.vue
new file mode 100644
index 0000000..88fe429
--- /dev/null
+++ b/src/views/chart/ContentEdit/components/EditWatermark/index.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/chart/ContentEdit/hooks/useDrag.hook.ts b/src/views/chart/ContentEdit/hooks/useDrag.hook.ts
new file mode 100644
index 0000000..3aae554
--- /dev/null
+++ b/src/views/chart/ContentEdit/hooks/useDrag.hook.ts
@@ -0,0 +1,382 @@
+import { toRaw } from 'vue'
+import { DragKeyEnum, MouseEventButton } from '@/enums/editPageEnum'
+import { createComponent } from '@/packages'
+import { ConfigType } from '@/packages/index.d'
+import { CreateComponentType, CreateComponentGroupType, PickCreateComponentType } from '@/packages/index.d'
+import { useContextMenu } from '@/views/chart/hooks/useContextMenu.hook'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
+import { loadingStart, loadingFinish, loadingError, setComponentPosition, JSONParse } from '@/utils'
+import { throttle, cloneDeep } from 'lodash'
+
+const chartEditStore = useChartEditStore()
+const { onClickOutSide } = useContextMenu()
+
+// * 拖拽到编辑区域里
+export const dragHandle = async (e: DragEvent) => {
+ e.preventDefault()
+
+ try {
+ loadingStart()
+
+ // 获取拖拽数据
+ const drayDataString = e!.dataTransfer!.getData(DragKeyEnum.DRAG_KEY)
+ if (!drayDataString) {
+ loadingFinish()
+ return
+ }
+
+ // 修改状态
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_CREATE, false)
+ const dropData: Exclude = JSONParse(drayDataString)
+
+ // 创建新图表组件
+ let newComponent: CreateComponentType = await createComponent(dropData)
+
+ setComponentPosition(newComponent, e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2)
+ chartEditStore.addComponentList(newComponent, false, true)
+ chartEditStore.setTargetSelectChart(newComponent.id)
+ loadingFinish()
+ } catch (error) {
+ loadingError()
+ window['$message'].warning(`图表正在研发中, 敬请期待...`)
+ }
+}
+
+// * 进入拖拽区域
+export const dragoverHandle = (e: DragEvent) => {
+ e.preventDefault()
+ e.stopPropagation()
+
+ if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'
+}
+
+// * 不拦截默认行为点击
+export const mousedownHandleUnStop = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
+ if (item) {
+ chartEditStore.setTargetSelectChart(item.id)
+ return
+ }
+ chartEditStore.setTargetSelectChart(undefined)
+}
+
+// * 框选
+export const mousedownBoxSelect = (e: MouseEvent, item?: CreateComponentType | CreateComponentGroupType) => {
+ if (e.which == 2) return
+ if (window.$KeyboardActive?.space) return
+
+ mousedownHandleUnStop(e)
+
+ // 记录点击初始位置
+ const startOffsetX = e.offsetX
+ const startOffsetY = e.offsetY
+ const startScreenX = e.screenX
+ const startScreenY = e.screenY
+
+ // 记录缩放
+ const scale = chartEditStore.getEditCanvas.scale
+
+ chartEditStore.setMousePosition(undefined, undefined, startOffsetX, startOffsetY)
+
+ // 移动框选
+ const mousemove = throttle((moveEvent: MouseEvent) => {
+ // 取消当前选中
+ chartEditStore.setTargetSelectChart()
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, true)
+
+ // 这里先把相对值算好,不然组件无法获取 startScreenX 和 startScreenY 的值
+ const currX = startOffsetX + moveEvent.screenX - startScreenX
+ const currY = startOffsetY + moveEvent.screenY - startScreenY
+ chartEditStore.setMousePosition(currX, currY)
+
+ // 计算框选的左上角和右下角
+ const selectAttr = {
+ // 左上角
+ x1: 0,
+ y1: 0,
+ // 右下角
+ x2: 0,
+ y2: 0
+ }
+ if (currX > startOffsetX && currY > startOffsetY) {
+ // 右下方向
+ selectAttr.x1 = startOffsetX
+ selectAttr.y1 = startOffsetY
+ selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
+ selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
+ } else if (currX > startOffsetX && currY < startOffsetY) {
+ // 右上方向
+ selectAttr.x1 = startOffsetX
+ selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
+ selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
+ selectAttr.y2 = startOffsetY
+ } else if (currX < startOffsetX && currY > startOffsetY) {
+ selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
+ selectAttr.y1 = startOffsetY
+ selectAttr.x2 = startOffsetX
+ selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
+ // 左下方向
+ } else {
+ // 左上方向
+ selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
+ selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
+ selectAttr.x2 = startOffsetX
+ selectAttr.y2 = startOffsetY
+ }
+
+ // 遍历组件
+ chartEditStore.getComponentList.forEach(item => {
+ if (!chartEditStore.getTargetChart.selectId.includes(item.id)) {
+ // 处理左上角
+ let isSelect = false
+ const { x, y, w, h } = item.attr
+ const targetAttr = {
+ // 左上角
+ x1: x,
+ y1: y,
+ // 右下角
+ x2: x + w,
+ y2: y + h
+ }
+ // 全包含则选中
+ if (
+ targetAttr.x1 - selectAttr.x1 >= 0 &&
+ targetAttr.y1 - selectAttr.y1 >= 0 &&
+ targetAttr.x2 - selectAttr.x2 <= 0 &&
+ targetAttr.y2 - selectAttr.y2 <= 0 &&
+ !item.status.lock &&
+ !item.status.hide
+ ) {
+ isSelect = true
+ chartEditStore.setTargetSelectChart(item.id, true)
+ }
+ }
+ })
+ }, 30)
+
+ // 鼠标抬起
+ const mouseup = () => {
+ // 鼠标抬起时,结束mousemove的节流函数,避免选框不消失问题
+ mousemove.cancel()
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_SELECT, false)
+ chartEditStore.setMousePosition(0, 0, 0, 0)
+ document.removeEventListener('mousemove', mousemove)
+ document.removeEventListener('mouseup', mouseup)
+ }
+ document.addEventListener('mousemove', mousemove)
+ document.addEventListener('mouseup', mouseup)
+}
+
+// * 鼠标事件
+export const useMouseHandle = () => {
+ // * Click 事件, 松开鼠标触发
+ const mouseClickHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
+ e.preventDefault()
+ e.stopPropagation()
+ if (item.status.lock) return
+ // 若此时按下了 CTRL, 表示多选
+ if (window.$KeyboardActive?.ctrl) {
+ // 若已选中,则去除
+ if (chartEditStore.targetChart.selectId.includes(item.id)) {
+ const exList = chartEditStore.targetChart.selectId.filter(e => e !== item.id)
+ chartEditStore.setTargetSelectChart(exList)
+ } else {
+ chartEditStore.setTargetSelectChart(item.id, true)
+ }
+ }
+ }
+
+ // * 按下事件(包含移动事件)
+ const mousedownHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
+ e.preventDefault()
+ e.stopPropagation()
+ if (item.status.lock) return
+ onClickOutSide()
+ // 按下左键 + CTRL
+ if (e.buttons === MouseEventButton.LEFT && window.$KeyboardActive?.ctrl) return
+
+ // 按下右键 + 选中多个 + 目标元素是多选子元素
+ const selectId = chartEditStore.getTargetChart.selectId
+ if (e.buttons === MouseEventButton.RIGHT && selectId.length > 1 && selectId.includes(item.id)) return
+
+ // 选中当前目标组件
+ chartEditStore.setTargetSelectChart(item.id)
+
+ // 按下右键
+ if (e.buttons === MouseEventButton.RIGHT) return
+
+ const scale = chartEditStore.getEditCanvas.scale
+ const canvasWidth = chartEditStore.getEditCanvasConfig.width
+ const canvasHeight = chartEditStore.getEditCanvasConfig.height
+
+ // 记录图表初始位置和大小
+ const targetMap = new Map()
+ chartEditStore.getTargetChart.selectId.forEach(id => {
+ const index = chartEditStore.fetchTargetIndex(id)
+ if (index !== -1) {
+ const { x, y, w, h } = toRaw(chartEditStore.getComponentList[index]).attr
+ targetMap.set(id, { x, y, w, h })
+ }
+ })
+
+ // 记录点击初始位置
+ const startX = e.screenX
+ const startY = e.screenY
+
+ // 记录历史位置
+ let prevComponentInstance: Array = []
+ chartEditStore.getTargetChart.selectId.forEach(id => {
+ if (!targetMap.has(id)) return
+
+ const index = chartEditStore.fetchTargetIndex(id)
+ // 拿到初始位置数据
+ prevComponentInstance.push(cloneDeep(chartEditStore.getComponentList[index]))
+ })
+
+ // 记录初始位置
+ chartEditStore.setMousePosition(undefined, undefined, startX, startY)
+
+ // 移动-计算偏移量
+ const mousemove = throttle((moveEvent: MouseEvent) => {
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
+ chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY)
+
+ // 当前偏移量,处理 scale 比例问题
+ let offsetX = (moveEvent.screenX - startX) / scale
+ let offsetY = (moveEvent.screenY - startY) / scale
+
+ chartEditStore.getTargetChart.selectId.forEach(id => {
+ if (!targetMap.has(id)) return
+
+ const index = chartEditStore.fetchTargetIndex(id)
+ // 拿到初始位置数据
+ const { x, y, w, h } = targetMap.get(id)
+ const componentInstance = chartEditStore.getComponentList[index]
+
+ let currX = Math.round(x + offsetX)
+ let currY = Math.round(y + offsetY)
+
+ // 要预留的距离
+ const distance = 50
+
+ // 基于左上角位置检测
+ currX = currX < -w + distance ? -w + distance : currX
+ currY = currY < -h + distance ? -h + distance : currY
+
+ // 基于右下角位置检测
+ currX = currX > canvasWidth - distance ? canvasWidth - distance : currX
+ currY = currY > canvasHeight - distance ? canvasHeight - distance : currY
+ if (componentInstance) {
+ componentInstance.attr = Object.assign(componentInstance.attr, {
+ x: currX,
+ y: currY
+ })
+ }
+ })
+ return
+ }, 20)
+
+ const mouseup = () => {
+ try {
+ chartEditStore.setMousePosition(0, 0, 0, 0)
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
+ // 加入历史栈
+ if (prevComponentInstance.length) {
+ chartEditStore.getTargetChart.selectId.forEach(id => {
+ if (!targetMap.has(id)) return
+ const index = chartEditStore.fetchTargetIndex(id)
+ const curComponentInstance = chartEditStore.getComponentList[index]
+ // 找到记录的所选组件
+ prevComponentInstance.forEach(preItem => {
+ if (preItem.id === id) {
+ preItem.attr = Object.assign(preItem.attr, {
+ offsetX: curComponentInstance.attr.x - preItem.attr.x,
+ offsetY: curComponentInstance.attr.y - preItem.attr.y
+ })
+ }
+ })
+ })
+ chartEditStore.moveComponentList(prevComponentInstance)
+ }
+ document.removeEventListener('mousemove', mousemove)
+ document.removeEventListener('mouseup', mouseup)
+ } catch (err) {
+ console.log(err)
+ }
+ }
+
+ document.addEventListener('mousemove', mousemove)
+ document.addEventListener('mouseup', mouseup)
+ }
+
+ // * 进入事件
+ const mouseenterHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
+ e.preventDefault()
+ e.stopPropagation()
+ if (!chartEditStore.getEditCanvas.isSelect) {
+ chartEditStore.setTargetHoverChart(item.id)
+ }
+ }
+
+ // * 移出事件
+ const mouseleaveHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
+ e.preventDefault()
+ e.stopPropagation()
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
+ chartEditStore.setTargetHoverChart(undefined)
+ }
+
+ return { mouseClickHandle, mousedownHandle, mouseenterHandle, mouseleaveHandle }
+}
+
+// * 移动锚点
+export const useMousePointHandle = (e: MouseEvent, point: string, attr: PickCreateComponentType<'attr'>) => {
+ e.stopPropagation()
+ e.preventDefault()
+
+ // 设置拖拽状态
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, true)
+ const scale = chartEditStore.getEditCanvas.scale
+
+ const itemAttrX = attr.x
+ const itemAttrY = attr.y
+ const itemAttrW = attr.w
+ const itemAttrH = attr.h
+
+ // 记录点击初始位置
+ const startX = e.screenX
+ const startY = e.screenY
+
+ // 记录初始位置
+ chartEditStore.setMousePosition(startX, startY)
+
+ const mousemove = throttle((moveEvent: MouseEvent) => {
+ chartEditStore.setMousePosition(moveEvent.screenX, moveEvent.screenY)
+
+ let currX = Math.round((moveEvent.screenX - startX) / scale)
+ let currY = Math.round((moveEvent.screenY - startY) / scale)
+
+ const isTop = /t/.test(point)
+ const isBottom = /b/.test(point)
+ const isLeft = /l/.test(point)
+ const isRight = /r/.test(point)
+
+ const newHeight = itemAttrH + (isTop ? -currY : isBottom ? currY : 0)
+ const newWidth = itemAttrW + (isLeft ? -currX : isRight ? currX : 0)
+
+ attr.h = newHeight > 0 ? newHeight : 0
+ attr.w = newWidth > 0 ? newWidth : 0
+ attr.x = itemAttrX + (isLeft ? currX : 0)
+ attr.y = itemAttrY + (isTop ? currY : 0)
+ }, 50)
+
+ const mouseup = () => {
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.IS_DRAG, false)
+ chartEditStore.setMousePosition(0, 0, 0, 0)
+ document.removeEventListener('mousemove', mousemove)
+ document.removeEventListener('mouseup', mouseup)
+ }
+
+ document.addEventListener('mousemove', mousemove)
+ document.addEventListener('mouseup', mouseup)
+}
diff --git a/src/views/chart/ContentEdit/hooks/useLayout.hook.ts b/src/views/chart/ContentEdit/hooks/useLayout.hook.ts
new file mode 100644
index 0000000..1da17d5
--- /dev/null
+++ b/src/views/chart/ContentEdit/hooks/useLayout.hook.ts
@@ -0,0 +1,29 @@
+import { onUnmounted, onMounted } from 'vue'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { EditCanvasTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
+
+const chartEditStore = useChartEditStore()
+
+// 布局处理
+export const useLayout = () => {
+ onMounted(() => {
+ // 设置 Dom 值(ref 不生效先用 document)
+ chartEditStore.setEditCanvas(
+ EditCanvasTypeEnum.EDIT_LAYOUT_DOM,
+ document.getElementById('go-chart-edit-layout')
+ )
+ chartEditStore.setEditCanvas(
+ EditCanvasTypeEnum.EDIT_CONTENT_DOM,
+ document.getElementById('go-chart-edit-content')
+ )
+
+ // 监听初始化
+ const removeScale = chartEditStore.listenerScale()
+
+ onUnmounted(() => {
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.EDIT_LAYOUT_DOM, null)
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.EDIT_CONTENT_DOM, null)
+ removeScale()
+ })
+ })
+}
\ No newline at end of file
diff --git a/src/views/chart/ContentEdit/hooks/useStyle.hook.ts b/src/views/chart/ContentEdit/hooks/useStyle.hook.ts
new file mode 100644
index 0000000..14507f7
--- /dev/null
+++ b/src/views/chart/ContentEdit/hooks/useStyle.hook.ts
@@ -0,0 +1,65 @@
+import { PickCreateComponentType } from '@/packages/index.d'
+
+type AttrType = PickCreateComponentType<'attr'>
+
+export const useComponentStyle = (attr: AttrType, index: number) => {
+ if(!attr) return {}
+ const componentStyle = {
+ zIndex: index + 1,
+ left: `${attr.x}px`,
+ top: `${attr.y}px`
+ }
+ return componentStyle
+}
+
+export const useSizeStyle = (attr: AttrType, scale?: number) => {
+ if(!attr) return {}
+ return {
+ width: `${scale ? scale * attr.w : attr.w}px`,
+ height: `${scale ? scale * attr.h : attr.h}px`
+ }
+}
+
+// 锚点位置
+export const usePointStyle = (
+ point: string,
+ index: number,
+ attr: PickCreateComponentType<'attr'>,
+ cursorResize: string[]
+) => {
+ const { w: width, h: height } = attr
+
+ const isTop = /t/.test(point)
+ const isBottom = /b/.test(point)
+ const isLeft = /l/.test(point)
+ const isRight = /r/.test(point)
+
+ let newLeft = 0
+ let newTop = 0
+
+ // 四个角的点
+ if (point.length === 2) {
+ newLeft = isLeft ? 0 : width
+ newTop = isTop ? 0 : height
+ } else {
+ // 上下两点的点,宽度居中
+ if (isTop || isBottom) {
+ newLeft = width / 2
+ newTop = isTop ? 0 : height
+ }
+
+ // 左右两边的点,高度居中
+ if (isLeft || isRight) {
+ newLeft = isLeft ? 0 : width
+ newTop = Math.floor(height / 2)
+ }
+ }
+
+ const style = {
+ left: `${newLeft}px`,
+ top: `${newTop}px`,
+ cursor: cursorResize[index] + '-resize'
+ }
+
+ return style
+}
diff --git a/src/views/chart/ContentEdit/index.ts b/src/views/chart/ContentEdit/index.ts
new file mode 100644
index 0000000..4a4766a
--- /dev/null
+++ b/src/views/chart/ContentEdit/index.ts
@@ -0,0 +1,3 @@
+import ContentEdit from './index.vue'
+
+export { ContentEdit }
diff --git a/src/views/chart/ContentEdit/index.vue b/src/views/chart/ContentEdit/index.vue
new file mode 100644
index 0000000..6f25ec9
--- /dev/null
+++ b/src/views/chart/ContentEdit/index.vue
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentHeader/headerLeftBtn/index.ts b/src/views/chart/ContentHeader/headerLeftBtn/index.ts
new file mode 100644
index 0000000..1a76146
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerLeftBtn/index.ts
@@ -0,0 +1,3 @@
+import HeaderLeftBtn from './index.vue'
+
+export { HeaderLeftBtn }
diff --git a/src/views/chart/ContentHeader/headerLeftBtn/index.vue b/src/views/chart/ContentHeader/headerLeftBtn/index.vue
new file mode 100644
index 0000000..e29a59a
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerLeftBtn/index.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
diff --git a/src/views/chart/ContentHeader/headerRightBtn/index.ts b/src/views/chart/ContentHeader/headerRightBtn/index.ts
new file mode 100644
index 0000000..d6b6deb
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerRightBtn/index.ts
@@ -0,0 +1,3 @@
+import HeaderRightBtn from './index.vue'
+
+export { HeaderRightBtn }
diff --git a/src/views/chart/ContentHeader/headerRightBtn/index.vue b/src/views/chart/ContentHeader/headerRightBtn/index.vue
new file mode 100644
index 0000000..9819bb2
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerRightBtn/index.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+ {{ item.title() }}
+
+
+
+
+
+
+
+
+ 发布管理
+
+
+
+
+
+
+
+
+
+ {{ previewPath() }}
+
+
+
+ 复制地址
+
+
+ {{ release ? '取消发布' : '发布大屏' }}
+
+
+
+
+
+
+
+ 关闭弹窗
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentHeader/headerTitle/index.ts b/src/views/chart/ContentHeader/headerTitle/index.ts
new file mode 100644
index 0000000..19b5dbc
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerTitle/index.ts
@@ -0,0 +1,3 @@
+import HeaderTitle from './index.vue'
+
+export { HeaderTitle }
diff --git a/src/views/chart/ContentHeader/headerTitle/index.vue b/src/views/chart/ContentHeader/headerTitle/index.vue
new file mode 100644
index 0000000..e1a710a
--- /dev/null
+++ b/src/views/chart/ContentHeader/headerTitle/index.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+ 工作空间 -
+
+ {{ comTitle }}
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentLayers/components/LayersGroupListItem/index.ts b/src/views/chart/ContentLayers/components/LayersGroupListItem/index.ts
new file mode 100644
index 0000000..2593932
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersGroupListItem/index.ts
@@ -0,0 +1,3 @@
+import LayersGroupListItem from './index.vue'
+
+export { LayersGroupListItem }
diff --git a/src/views/chart/ContentLayers/components/LayersGroupListItem/index.vue b/src/views/chart/ContentLayers/components/LayersGroupListItem/index.vue
new file mode 100644
index 0000000..ac9892e
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersGroupListItem/index.vue
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ componentGroupData.chartConfig.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentLayers/components/LayersListItem/index.ts b/src/views/chart/ContentLayers/components/LayersListItem/index.ts
new file mode 100644
index 0000000..f39abe9
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersListItem/index.ts
@@ -0,0 +1,3 @@
+import LayersListItem from './index.vue'
+
+export { LayersListItem }
diff --git a/src/views/chart/ContentLayers/components/LayersListItem/index.vue b/src/views/chart/ContentLayers/components/LayersListItem/index.vue
new file mode 100644
index 0000000..d77ed45
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersListItem/index.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+ {{ props.componentData.chartConfig.title }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentLayers/components/LayersStatus/index.ts b/src/views/chart/ContentLayers/components/LayersStatus/index.ts
new file mode 100644
index 0000000..220d5c2
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersStatus/index.ts
@@ -0,0 +1,3 @@
+import LayersStatus from './index.vue'
+
+export { LayersStatus }
diff --git a/src/views/chart/ContentLayers/components/LayersStatus/index.vue b/src/views/chart/ContentLayers/components/LayersStatus/index.vue
new file mode 100644
index 0000000..a43d8aa
--- /dev/null
+++ b/src/views/chart/ContentLayers/components/LayersStatus/index.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentLayers/enums.ts b/src/views/chart/ContentLayers/enums.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/views/chart/ContentLayers/index.ts b/src/views/chart/ContentLayers/index.ts
new file mode 100644
index 0000000..e2e64f5
--- /dev/null
+++ b/src/views/chart/ContentLayers/index.ts
@@ -0,0 +1,3 @@
+import ContentLayers from './index.vue'
+
+export { ContentLayers }
diff --git a/src/views/chart/ContentLayers/index.vue b/src/views/chart/ContentLayers/index.vue
new file mode 100644
index 0000000..4f5895d
--- /dev/null
+++ b/src/views/chart/ContentLayers/index.vue
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+ 暂无图层~
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/chart/ContentLoad/index.ts b/src/views/chart/ContentLoad/index.ts
new file mode 100644
index 0000000..7e41ed3
--- /dev/null
+++ b/src/views/chart/ContentLoad/index.ts
@@ -0,0 +1,3 @@
+import ContentLoad from './index.vue'
+
+export { ContentLoad }
diff --git a/src/views/chart/ContentLoad/index.vue b/src/views/chart/ContentLoad/index.vue
new file mode 100644
index 0000000..2b7f46c
--- /dev/null
+++ b/src/views/chart/ContentLoad/index.vue
@@ -0,0 +1,40 @@
+
+
+
+ 拼命加载中...
+
+
+
+
+
+
diff --git a/src/views/chart/hooks/useContextMenu.hook.d.ts b/src/views/chart/hooks/useContextMenu.hook.d.ts
new file mode 100644
index 0000000..ec1276c
--- /dev/null
+++ b/src/views/chart/hooks/useContextMenu.hook.d.ts
@@ -0,0 +1,11 @@
+import { MenuEnum } from '@/enums/editPageEnum'
+
+export interface MenuOptionsItemType {
+ type?: string
+ label?: string
+ key: MenuEnum | string
+ icon?: Function
+ fnHandle?: Function
+ disabled?: boolean
+ hidden?: boolean
+}
\ No newline at end of file
diff --git a/src/views/chart/hooks/useContextMenu.hook.ts b/src/views/chart/hooks/useContextMenu.hook.ts
new file mode 100644
index 0000000..e0aa782
--- /dev/null
+++ b/src/views/chart/hooks/useContextMenu.hook.ts
@@ -0,0 +1,277 @@
+import { ref, nextTick, toRaw } from 'vue'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
+import { renderIcon, loadingError } from '@/utils'
+import { icon } from '@/plugins'
+import { MenuOptionsItemType } from './useContextMenu.hook.d'
+import { MenuEnum } from '@/enums/editPageEnum'
+import cloneDeep from 'lodash/cloneDeep'
+
+const {
+ CopyIcon,
+ CutIcon,
+ ClipboardOutlineIcon,
+ TrashIcon,
+ ChevronDownIcon,
+ ChevronUpIcon,
+ LockOpenOutlineIcon,
+ LockClosedOutlineIcon,
+ EyeOutlineIcon,
+ EyeOffOutlineIcon
+} = icon.ionicons5
+const { UpToTopIcon, DownToBottomIcon, PaintBrushIcon, Carbon3DSoftwareIcon, Carbon3DCursorIcon } = icon.carbon
+
+const chartEditStore = useChartEditStore()
+
+/**
+ * 分割线
+ * @param {number} n > 2
+ * @returns
+ */
+export const divider = (n: number = 3) => {
+ return {
+ type: 'divider',
+ key: `d${n}`
+ }
+}
+
+// * 默认单组件选项
+export const defaultOptions: MenuOptionsItemType[] = [
+ {
+ label: '锁定',
+ key: MenuEnum.LOCK,
+ icon: renderIcon(LockClosedOutlineIcon),
+ fnHandle: chartEditStore.setLock
+ },
+ {
+ label: '解锁',
+ key: MenuEnum.UNLOCK,
+ icon: renderIcon(LockOpenOutlineIcon),
+ fnHandle: chartEditStore.setUnLock
+ },
+ {
+ label: '隐藏',
+ key: MenuEnum.HIDE,
+ icon: renderIcon(EyeOffOutlineIcon),
+ fnHandle: chartEditStore.setHide
+ },
+ {
+ label: '显示',
+ key: MenuEnum.SHOW,
+ icon: renderIcon(EyeOutlineIcon),
+ fnHandle: chartEditStore.setShow
+ },
+ {
+ type: 'divider',
+ key: 'd0'
+ },
+ {
+ label: '复制',
+ key: MenuEnum.COPY,
+ icon: renderIcon(CopyIcon),
+ fnHandle: chartEditStore.setCopy
+ },
+ {
+ label: '剪切',
+ key: MenuEnum.CUT,
+ icon: renderIcon(CutIcon),
+ fnHandle: chartEditStore.setCut
+ },
+ {
+ label: '粘贴',
+ key: MenuEnum.PARSE,
+ icon: renderIcon(ClipboardOutlineIcon),
+ fnHandle: chartEditStore.setParse
+ },
+ {
+ type: 'divider',
+ key: 'd1'
+ },
+ {
+ label: '置顶',
+ key: MenuEnum.TOP,
+ icon: renderIcon(UpToTopIcon),
+ fnHandle: chartEditStore.setTop
+ },
+ {
+ label: '置底',
+ key: MenuEnum.BOTTOM,
+ icon: renderIcon(DownToBottomIcon),
+ fnHandle: chartEditStore.setBottom
+ },
+ {
+ label: '上移',
+ key: MenuEnum.UP,
+ icon: renderIcon(ChevronUpIcon),
+ fnHandle: chartEditStore.setUp
+ },
+ {
+ label: '下移',
+ key: MenuEnum.DOWN,
+ icon: renderIcon(ChevronDownIcon),
+ fnHandle: chartEditStore.setDown
+ },
+ {
+ type: 'divider',
+ key: 'd2'
+ },
+ {
+ label: '清空剪贴板',
+ key: MenuEnum.CLEAR,
+ icon: renderIcon(PaintBrushIcon),
+ fnHandle: chartEditStore.setRecordChart
+ },
+ {
+ label: '删除',
+ key: MenuEnum.DELETE,
+ icon: renderIcon(TrashIcon),
+ fnHandle: chartEditStore.removeComponentList
+ }
+]
+
+// * 默认多选组件选项
+export const defaultMultiSelectOptions: MenuOptionsItemType[] = [
+ {
+ label: '创建分组',
+ key: MenuEnum.GROUP,
+ icon: renderIcon(Carbon3DSoftwareIcon),
+ fnHandle: chartEditStore.setGroup
+ },
+ {
+ label: '解除分组',
+ key: MenuEnum.UN_GROUP,
+ icon: renderIcon(Carbon3DCursorIcon),
+ fnHandle: chartEditStore.setUnGroup
+ }
+]
+
+// * 无数据传递拥有的选项
+const defaultNoItemKeys = [MenuEnum.PARSE, MenuEnum.CLEAR]
+
+/**
+ * * 挑选选项
+ * @param options
+ * @param pickList
+ * @returns
+ */
+const pickOption = (options: MenuOptionsItemType[], pickList?: MenuEnum[]) => {
+ if (!pickList) return options
+ const list: MenuOptionsItemType[] = []
+ pickList.forEach(e => {
+ list.push(...options.filter(op => op.key === e))
+ })
+ return list
+}
+
+/**
+ * * 去除选项
+ * @param options
+ * @param hideList
+ * @returns
+ */
+const hideOption = (options: MenuOptionsItemType[], hideList?: MenuEnum[]) => {
+ if (!hideList) return options
+ return options.filter((op: MenuOptionsItemType) => {
+ return hideList.findIndex((e: MenuEnum) => e !== op.key) !== -1
+ })
+}
+
+// * 右键内容
+const menuOptions = ref([])
+
+// * 右键处理
+const handleContextMenu = (
+ e: MouseEvent,
+ // 右键对象
+ targetInstance?: CreateComponentType | CreateComponentGroupType,
+ // 判断函数
+ optionsHandle?: Function,
+ // 隐藏选项列表
+ hideOptionsList?: MenuEnum[],
+ // 挑选选项列表
+ pickOptionsList?: MenuEnum[]
+) => {
+ e.stopPropagation()
+ e.preventDefault()
+
+ let target = e.target
+ while (target instanceof SVGElement) {
+ target = target.parentNode
+ }
+
+ chartEditStore.setTargetSelectChart(targetInstance && targetInstance.id)
+
+ // 隐藏旧列表
+ chartEditStore.setRightMenuShow(false)
+
+ // * 多选默认选项
+ if (chartEditStore.getTargetChart.selectId.length > 1) {
+ menuOptions.value = defaultMultiSelectOptions
+ } else {
+ // * 单选默认选项
+ menuOptions.value = defaultOptions
+ }
+
+ if (!targetInstance) {
+ menuOptions.value = pickOption(toRaw(menuOptions.value), defaultNoItemKeys)
+ }
+ if (hideOptionsList) {
+ menuOptions.value = hideOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], hideOptionsList)
+ }
+ if (pickOptionsList) {
+ menuOptions.value = pickOption([...defaultMultiSelectOptions, divider(), ...defaultOptions], pickOptionsList)
+ }
+ if (optionsHandle) {
+ // 自定义函数能够拿到当前选项和所有选项
+ menuOptions.value = optionsHandle(
+ cloneDeep(toRaw(menuOptions.value)),
+ [...defaultMultiSelectOptions, ...defaultOptions],
+ targetInstance
+ )
+ }
+ nextTick().then(() => {
+ chartEditStore.setMousePosition(e.clientX, e.clientY)
+ chartEditStore.setRightMenuShow(true)
+ })
+}
+
+/**
+ * * 右键hook
+ * @param menuConfig
+ * @returns
+ */
+export const useContextMenu = () => {
+ // 设置默认项
+ menuOptions.value = defaultOptions
+
+ // * 失焦
+ const onClickOutSide = () => {
+ chartEditStore.setRightMenuShow(false)
+ }
+
+ // * 事件处理
+ const handleMenuSelect = (key: string) => {
+ chartEditStore.setRightMenuShow(false)
+ const targetItem: MenuOptionsItemType[] = menuOptions.value.filter((e: MenuOptionsItemType) => e.key === key)
+
+ menuOptions.value.forEach((e: MenuOptionsItemType) => {
+ if (e.key === key) {
+ if (e.fnHandle) {
+ e.fnHandle()
+ return
+ }
+ if (!targetItem) loadingError()
+ }
+ })
+ }
+
+ return {
+ menuOptions,
+ defaultOptions,
+ defaultMultiSelectOptions,
+ handleContextMenu,
+ onClickOutSide,
+ handleMenuSelect,
+ mousePosition: chartEditStore.getMousePosition
+ }
+}
diff --git a/src/views/chart/hooks/useKeyboard.hook.ts b/src/views/chart/hooks/useKeyboard.hook.ts
new file mode 100644
index 0000000..9cef8c6
--- /dev/null
+++ b/src/views/chart/hooks/useKeyboard.hook.ts
@@ -0,0 +1,251 @@
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { useSync } from './useSync.hook'
+import { WinKeyboard, MacKeyboard, MenuEnum } from '@/enums/editPageEnum'
+import throttle from 'lodash/throttle'
+import debounce from 'lodash/debounce'
+import keymaster from 'keymaster'
+import { setKeyboardDressShow } from '@/utils'
+
+// Keymaster可以支持识别以下组合键: ⇧,shift,option,⌥,alt,ctrl,control,command,和⌘
+const chartEditStore = useChartEditStore()
+const useSyncIns = useSync()
+const winCtrlMerge = (e: string) => `${WinKeyboard.CTRL}+${e}`
+const winShiftMerge = (e: string) => `${WinKeyboard.SHIFT}+${e}`
+const winAltMerge = (e: string) => `${WinKeyboard.ALT}+${e}`
+
+export const winKeyboardValue = {
+ [MenuEnum.ARROW_UP]: winCtrlMerge('up'),
+ [MenuEnum.ARROW_RIGHT]: winCtrlMerge('right'),
+ [MenuEnum.ARROW_DOWN]: winCtrlMerge('down'),
+ [MenuEnum.ARROW_LEFT]: winCtrlMerge('left'),
+ [MenuEnum.COPY]: winCtrlMerge('c'),
+ [MenuEnum.CUT]: winCtrlMerge('x'),
+ [MenuEnum.PARSE]: winCtrlMerge('v'),
+ [MenuEnum.DELETE]: 'delete',
+ [MenuEnum.BACK]: winCtrlMerge('z'),
+ [MenuEnum.FORWORD]: winCtrlMerge(winShiftMerge('z')),
+ [MenuEnum.SAVE]: winCtrlMerge('s'),
+ [MenuEnum.GROUP]: winCtrlMerge('g'),
+ [MenuEnum.UN_GROUP]: winCtrlMerge(winShiftMerge('g')),
+ [MenuEnum.LOCK]: winCtrlMerge('l'),
+ [MenuEnum.UNLOCK]: winCtrlMerge(winShiftMerge('l')),
+ [MenuEnum.HIDE]: winCtrlMerge('h'),
+ [MenuEnum.SHOW]: winCtrlMerge(winShiftMerge('h'))
+}
+
+// 这个 Ctrl 后面还是换成了 ⌘
+const macCtrlMerge = (e: string) => `${MacKeyboard.CTRL}+${e}`
+const macShiftMerge = (e: string) => `${MacKeyboard.SHIFT}+${e}`
+const macAltMerge = (e: string) => `${MacKeyboard.ALT}+${e}`
+
+// 没有测试 macOS 系统,因为我没有😤👻
+export const macKeyboardValue = {
+ [MenuEnum.ARROW_UP]: macCtrlMerge('arrowup'),
+ [MenuEnum.ARROW_RIGHT]: macCtrlMerge('arrowright'),
+ [MenuEnum.ARROW_DOWN]: macCtrlMerge('arrowdown'),
+ [MenuEnum.ARROW_LEFT]: macCtrlMerge('arrowleft'),
+ [MenuEnum.COPY]: macCtrlMerge('c'),
+ [MenuEnum.CUT]: macCtrlMerge('x'),
+ [MenuEnum.PARSE]: macCtrlMerge('v'),
+ [MenuEnum.DELETE]: macCtrlMerge('backspace'),
+ [MenuEnum.BACK]: macCtrlMerge('z'),
+ [MenuEnum.FORWORD]: macCtrlMerge(macShiftMerge('z')),
+ [MenuEnum.SAVE]: macCtrlMerge('s'),
+ [MenuEnum.GROUP]: macCtrlMerge('g'),
+ [MenuEnum.UN_GROUP]: macCtrlMerge(macShiftMerge('g')),
+ [MenuEnum.LOCK]: macCtrlMerge('l'),
+ [MenuEnum.UNLOCK]: macCtrlMerge(macShiftMerge('l')),
+ [MenuEnum.HIDE]: macCtrlMerge('h'),
+ [MenuEnum.SHOW]: macCtrlMerge(macShiftMerge('h'))
+}
+
+// Win 快捷键列表
+const winKeyList: Array = [
+ winKeyboardValue.up,
+ winKeyboardValue.right,
+ winKeyboardValue.down,
+ winKeyboardValue.left,
+
+ winKeyboardValue.delete,
+ winKeyboardValue.copy,
+ winKeyboardValue.cut,
+ winKeyboardValue.parse,
+
+ winKeyboardValue.back,
+ winKeyboardValue.forward,
+
+ winKeyboardValue.save,
+ winKeyboardValue.group,
+ winKeyboardValue.unGroup,
+
+ winKeyboardValue.lock,
+ winKeyboardValue.unLock,
+
+ winKeyboardValue.hide,
+ winKeyboardValue.show
+]
+
+// Mac 快捷键列表
+const macKeyList: Array = [
+ macKeyboardValue.up,
+ macKeyboardValue.right,
+ macKeyboardValue.down,
+ macKeyboardValue.left,
+
+ macKeyboardValue.delete,
+ macKeyboardValue.copy,
+ macKeyboardValue.cut,
+ macKeyboardValue.parse,
+
+ macKeyboardValue.back,
+ macKeyboardValue.forward,
+
+ macKeyboardValue.save,
+ macKeyboardValue.group,
+ macKeyboardValue.unGroup,
+
+ macKeyboardValue.lock,
+ macKeyboardValue.unLock,
+
+ macKeyboardValue.hide,
+ macKeyboardValue.show
+]
+
+// 处理键盘记录
+const keyRecordHandle = () => {
+ // 默认赋值
+ window.$KeyboardActive = {
+ ctrl: false,
+ space: false
+ }
+
+ document.onkeydown = (e: KeyboardEvent) => {
+ const { keyCode } = e
+ if (keyCode == 32 && e.target == document.body) e.preventDefault()
+
+ if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
+ setKeyboardDressShow(e.keyCode)
+ switch (keyCode) {
+ case 17: window.$KeyboardActive.ctrl = true; break
+ case 32: window.$KeyboardActive.space = true; break
+ }
+ }
+ }
+
+ document.onkeyup = (e: KeyboardEvent) => {
+ const { keyCode } = e
+ if (keyCode == 32 && e.target == document.body) e.preventDefault()
+
+ if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
+ setKeyboardDressShow()
+ switch (keyCode) {
+ case 17: window.$KeyboardActive.ctrl = false; break
+ case 32: window.$KeyboardActive.space = false; break
+ }
+ }
+ }
+}
+
+// 初始化监听事件
+export const useAddKeyboard = () => {
+ const throttleTime = 50
+ const switchHandle = (keyboardValue: typeof winKeyboardValue, e: string) => {
+ switch (e) {
+ // ct+↑
+ case keyboardValue.up:
+ keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_UP); return false }, throttleTime))
+ break;
+ // ct+→
+ case keyboardValue.right:
+ keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_RIGHT); return false }, throttleTime))
+ break;
+ // ct+↓
+ case keyboardValue.down:
+ keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_DOWN); return false }, throttleTime))
+ break;
+ // ct+←
+ case keyboardValue.left:
+ keymaster(e, throttle(() => { chartEditStore.setMove(MenuEnum.ARROW_LEFT); return false }, throttleTime))
+ break;
+
+ // 删除 delete
+ case keyboardValue.delete:
+ keymaster(e, debounce(() => { chartEditStore.removeComponentList(); return false }, throttleTime))
+ break;
+ // 复制 ct+v
+ case keyboardValue.copy:
+ keymaster(e, debounce(() => { chartEditStore.setCopy(); return false }, throttleTime))
+ break;
+ // 剪切 ct+x
+ case keyboardValue.cut:
+ keymaster(e, debounce(() => { chartEditStore.setCut(); return false }, throttleTime))
+ break;
+ // 粘贴 ct+v
+ case keyboardValue.parse:
+ keymaster(e, throttle(() => { chartEditStore.setParse(); return false }, throttleTime))
+ break;
+
+ // 撤回 ct+z
+ case keyboardValue.back:
+ keymaster(e, throttle(() => { chartEditStore.setBack(); return false }, throttleTime))
+ break;
+ // 前进 ct+sh+z
+ case keyboardValue.forward:
+ keymaster(e, throttle(() => { chartEditStore.setForward(); return false }, throttleTime))
+ break;
+
+ // 创建分组 ct+g
+ case keyboardValue.group:
+ keymaster(e, throttle(() => { chartEditStore.setGroup(); return false }, throttleTime))
+ break;
+ // 解除分组 ct+sh+g
+ case keyboardValue.unGroup:
+ keymaster(e, throttle(() => { chartEditStore.setUnGroup(); return false }, throttleTime))
+ break;
+
+ // 锁定 ct+l
+ case keyboardValue.lock:
+ keymaster(e, throttle(() => { chartEditStore.setLock(); return false }, throttleTime))
+ break;
+ // 解除锁定 ct+sh+l
+ case keyboardValue.unLock:
+ keymaster(e, throttle(() => { chartEditStore.setUnLock(); return false }, throttleTime))
+ break;
+
+ // 隐藏 ct+h
+ case keyboardValue.hide:
+ keymaster(e, throttle(() => { chartEditStore.setHide(); return false }, throttleTime))
+ break;
+ // 解除隐藏 ct+sh+h
+ case keyboardValue.show:
+ keymaster(e, throttle(() => { chartEditStore.setShow(); return false }, throttleTime))
+ break;
+
+ // 保存 ct+s
+ case keyboardValue.save:
+ keymaster(e, throttle(() => { useSyncIns.dataSyncUpdate(); return false }, 200))
+ break;
+ }
+ }
+ winKeyList.forEach((key: string) => {
+ switchHandle(winKeyboardValue, key)
+ })
+ macKeyList.forEach((key: string) => {
+ switchHandle(macKeyboardValue, key)
+ })
+
+ keyRecordHandle()
+}
+
+// 卸载监听事件
+export const useRemoveKeyboard = () => {
+ document.onkeydown = () => {};
+ document.onkeyup = () => {};
+
+ winKeyList.forEach((key: string) => {
+ keymaster.unbind(key)
+ })
+ macKeyList.forEach((key: string) => {
+ keymaster.unbind(key)
+ })
+}
\ No newline at end of file
diff --git a/src/views/chart/hooks/useSync.hook.ts b/src/views/chart/hooks/useSync.hook.ts
new file mode 100644
index 0000000..ddb560d
--- /dev/null
+++ b/src/views/chart/hooks/useSync.hook.ts
@@ -0,0 +1,348 @@
+import { onUnmounted } from 'vue';
+import html2canvas from 'html2canvas'
+import { getUUID, httpErrorHandle, fetchRouteParamsLocation, base64toFile, JSONStringify, JSONParse } from '@/utils'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { EditCanvasTypeEnum, ChartEditStoreEnum, ProjectInfoEnum, ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
+import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
+import { StylesSetting } from '@/components/Pages/ChartItemSetting'
+import { useSystemStore } from '@/store/modules/systemStore/systemStore'
+import { useChartLayoutStore } from '@/store/modules/chartLayoutStore/chartLayoutStore'
+import { ChartLayoutStoreEnum } from '@/store/modules/chartLayoutStore/chartLayoutStore.d'
+import { fetchChartComponent, fetchConfigComponent, createComponent } from '@/packages/index'
+import { saveInterval } from '@/settings/designSetting'
+import throttle from 'lodash/throttle'
+// 接口状态
+import { ResultEnum } from '@/enums/httpEnum'
+// 接口
+import { saveProjectApi, fetchProjectApi, uploadFile, updateProjectApi } from '@/api/path'
+// 画布枚举
+import { SyncEnum } from '@/enums/editPageEnum'
+import { CreateComponentType, CreateComponentGroupType, ConfigType } from '@/packages/index.d'
+import { BaseEvent, EventLife } from '@/enums/eventEnum'
+import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
+import merge from 'lodash/merge'
+
+/**
+ * * 画布-版本升级对旧数据无法兼容的补丁
+ * @param object
+ */
+const canvasVersionUpdatePolyfill = (object: any) => {
+ return object
+}
+
+/**
+ * * 组件-版本升级对旧数据无法兼容的补丁
+ * @param newObject
+ * @param sources
+ */
+const componentVersionUpdatePolyfill = (newObject: any, sources: any) => {
+ try {
+ // 判断是否是组件
+ if (sources.id) {
+ // 处理事件补丁
+ const hasVnodeBeforeMount = 'vnodeBeforeMount' in sources.events
+ const hasVnodeMounted = 'vnodeMounted' in sources.events
+
+ if (hasVnodeBeforeMount) {
+ newObject.events.advancedEvents.vnodeBeforeMount = sources?.events.vnodeBeforeMount
+ }
+ if (hasVnodeMounted) {
+ newObject.events.advancedEvents.vnodeMounted = sources?.events.vnodeMounted
+ }
+ if (hasVnodeBeforeMount || hasVnodeMounted) {
+ sources.events = {
+ baseEvent: {
+ [BaseEvent.ON_CLICK]: undefined,
+ [BaseEvent.ON_DBL_CLICK]: undefined,
+ [BaseEvent.ON_MOUSE_ENTER]: undefined,
+ [BaseEvent.ON_MOUSE_LEAVE]: undefined
+ },
+ advancedEvents: {
+ [EventLife.VNODE_MOUNTED]: undefined,
+ [EventLife.VNODE_BEFORE_MOUNT]: undefined
+ }
+ }
+ }
+ return newObject
+ }
+ } catch (error) {
+ return newObject
+ }
+}
+
+/**
+ * * 合并处理
+ * @param newObject 新的模板数据
+ * @param sources 新拿到的数据
+ * @returns object
+ */
+const componentMerge = (newObject: any, sources: any, notComponent = false) => {
+ // 处理组件补丁
+ componentVersionUpdatePolyfill(newObject, sources)
+
+ // 非组件不处理
+ if (notComponent) return merge(newObject, sources)
+ // 组件排除 newObject
+ const option = sources.option
+ if (!option) return merge(newObject, sources)
+
+ // 为 undefined 的 sources 来源对象属性将被跳过详见 https://www.lodashjs.com/docs/lodash.merge
+ sources.option = undefined
+ if (option) {
+ return {
+ ...merge(newObject, sources),
+ option: option
+ }
+ }
+}
+
+// 请求处理
+export const useSync = () => {
+ const chartEditStore = useChartEditStore()
+ const chartHistoryStore = useChartHistoryStore()
+ const systemStore = useSystemStore()
+ const chartLayoutStore = useChartLayoutStore()
+ /**
+ * * 组件动态注册
+ * @param projectData 项目数据
+ * @param isReplace 是否替换数据
+ * @returns
+ */
+ const updateComponent = async (projectData: ChartEditStorage, isReplace = false, changeId = false) => {
+ if (isReplace) {
+ // 清除列表
+ chartEditStore.componentList = []
+ // 清除历史记录
+ chartHistoryStore.clearBackStack()
+ chartHistoryStore.clearForwardStack()
+ }
+ // 画布补丁处理
+ projectData.editCanvasConfig = canvasVersionUpdatePolyfill(projectData.editCanvasConfig)
+
+ // 列表组件注册
+ projectData.componentList.forEach(async (e: CreateComponentType | CreateComponentGroupType) => {
+ const intComponent = (target: CreateComponentType) => {
+ if (!window['$vue'].component(target.chartConfig.chartKey)) {
+ window['$vue'].component(target.chartConfig.chartKey, fetchChartComponent(target.chartConfig))
+ window['$vue'].component(target.chartConfig.conKey, fetchConfigComponent(target.chartConfig))
+ }
+ }
+
+ if (e.isGroup) {
+ (e as CreateComponentGroupType).groupList.forEach(groupItem => {
+ intComponent(groupItem)
+ })
+ } else {
+ intComponent(e as CreateComponentType)
+ }
+ })
+
+ // 创建函数-重新创建是为了处理类种方法消失的问题
+ const create = async (
+ _componentInstance: CreateComponentType,
+ callBack?: (componentInstance: CreateComponentType) => void
+ ) => {
+ // 补充 class 上的方法
+ let newComponent: CreateComponentType = await createComponent(_componentInstance.chartConfig)
+ if (callBack) {
+ if (changeId) {
+ callBack(componentMerge(newComponent, { ..._componentInstance, id: getUUID() }))
+ } else {
+ callBack(componentMerge(newComponent, _componentInstance))
+ }
+ } else {
+ if (changeId) {
+ chartEditStore.addComponentList(
+ componentMerge(newComponent, { ..._componentInstance, id: getUUID() }),
+ false,
+ true
+ )
+ } else {
+ chartEditStore.addComponentList(componentMerge(newComponent, _componentInstance), false, true)
+ }
+ }
+ }
+
+ // 数据赋值
+ for (const key in projectData) {
+ // 组件
+ if (key === ChartEditStoreEnum.COMPONENT_LIST) {
+ let loadIndex = 0
+ const listLength = projectData[key].length;
+ for (const comItem of projectData[key]) {
+ // 设置加载数量
+ let percentage = parseInt((parseFloat(`${++loadIndex / listLength}`) * 100).toString())
+ chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.PERCENTAGE, percentage)
+ // 判断类型
+ if (comItem.isGroup) {
+ // 创建分组
+ let groupClass = new PublicGroupConfigClass()
+ if (changeId) {
+ groupClass = componentMerge(groupClass, { ...comItem, id: getUUID() })
+ } else {
+ groupClass = componentMerge(groupClass, comItem)
+ }
+
+ // 异步注册子应用
+ const targetList: CreateComponentType[] = []
+ for (const groupItem of (comItem as CreateComponentGroupType).groupList) {
+ await create(groupItem, e => {
+ targetList.push(e)
+ })
+ }
+ groupClass.groupList = targetList
+
+ // 分组插入到列表
+ chartEditStore.addComponentList(groupClass, false, true)
+ } else {
+ await create(comItem as CreateComponentType)
+ }
+ }
+ } else {
+ // 非组件(顺便排除脏数据)
+ if (key !== 'editCanvasConfig' && key !== 'requestGlobalConfig') return
+ componentMerge(chartEditStore[key], projectData[key], true)
+ }
+ }
+
+ // 清除数量
+ chartLayoutStore.setItemUnHandle(ChartLayoutStoreEnum.PERCENTAGE, 0)
+ }
+
+ /**
+ * * 赋值全局数据
+ * @param projectData 项目数据
+ * @returns
+ */
+ const updateStoreInfo = (projectData: {
+ id: string,
+ name: string,
+ picUrl: string,
+ remark: string,
+ status: number
+ }) => {
+ const { id, name, remark, picUrl, status } = projectData
+ // ID
+ chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, id)
+ // 名称
+ chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_NAME, name)
+ // 描述
+ chartEditStore.setProjectInfo(ProjectInfoEnum.REMARKS, remark)
+ // 缩略图
+ chartEditStore.setProjectInfo(ProjectInfoEnum.THUMBNAIL, picUrl)
+ // 发布
+ chartEditStore.setProjectInfo(ProjectInfoEnum.RELEASE, status === 0)
+ }
+
+ // * 数据获取
+ const dataSyncFetch = async () => {
+ // FIX:重新执行dataSyncFetch需清空chartEditStore.componentList,否则会导致图层重复
+ // 切换语言等操作会导致重新执行 dataSyncFetch,此时pinia中并未清空chartEditStore.componentList,导致图层重复
+ chartEditStore.componentList = []
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
+ try {
+ const res = await fetchProjectApi({ id: fetchRouteParamsLocation() })
+ if (res && res.code === ResultEnum.SUCCESS) {
+ if (res.data) {
+ updateStoreInfo(res.data)
+ // 更新全局数据
+ if (res.data.content) {
+ await updateComponent(JSONParse(res.data.content))
+ }
+ return
+ }else {
+ chartEditStore.setProjectInfo(ProjectInfoEnum.PROJECT_ID, fetchRouteParamsLocation())
+ }
+ setTimeout(() => {
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
+ }, 1000)
+ return
+ }
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
+ } catch (error) {
+ console.log(error)
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
+ httpErrorHandle()
+ }
+ }
+
+ // * 数据保存
+ const dataSyncUpdate = throttle(async (updateImg = true) => {
+ if(!fetchRouteParamsLocation()) return
+
+ let projectId = chartEditStore.getProjectInfo[ProjectInfoEnum.PROJECT_ID];
+ if(projectId === null || projectId === ''){
+ window['$message'].error('数据初未始化成功,请刷新页面!')
+ return
+ }
+
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.START)
+
+ // 异常处理:缩略图上传失败不影响JSON的保存
+ try {
+ if (updateImg) {
+ // 获取缩略图片
+ const range = document.querySelector('.go-edit-range') as HTMLElement
+ // 生成图片
+ const canvasImage: HTMLCanvasElement = await html2canvas(range, {
+ backgroundColor: null,
+ allowTaint: true,
+ useCORS: true
+ })
+
+ // 上传预览图
+ let uploadParams = new FormData()
+ uploadParams.append('file',
+ base64toFile(canvasImage.toDataURL(),
+ `go-view/${fetchRouteParamsLocation()}_index_preview.png`)) // 名字使用 go-view 作为前缀
+ const uploadRes = await uploadFile(uploadParams)
+ // 保存预览图
+ if(uploadRes && uploadRes.code === ResultEnum.SUCCESS) {
+ await updateProjectApi({
+ id: fetchRouteParamsLocation(),
+ picUrl: uploadRes.data
+ })
+ }
+ }
+ } catch (e) {
+ console.log(e)
+ }
+
+ // 保存数据
+ const res = await saveProjectApi({
+ id: projectId,
+ content: JSONStringify(chartEditStore.getStorageInfo || {})
+ })
+
+ if (res && res.code === ResultEnum.SUCCESS) {
+ // 成功状态
+ setTimeout(() => {
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.SUCCESS)
+ }, 1000)
+ return
+ }
+ // 失败状态
+ chartEditStore.setEditCanvas(EditCanvasTypeEnum.SAVE_STATUS, SyncEnum.FAILURE)
+ }, 3000)
+
+ // * 定时处理
+ const intervalDataSyncUpdate = () => {
+ // 定时获取数据
+ const syncTiming = setInterval(() => {
+ dataSyncUpdate()
+ }, saveInterval * 1000)
+
+ // 销毁
+ onUnmounted(() => {
+ clearInterval(syncTiming)
+ })
+ }
+
+ return {
+ updateComponent,
+ updateStoreInfo,
+ dataSyncFetch,
+ dataSyncUpdate,
+ intervalDataSyncUpdate
+ }
+}
diff --git a/src/views/chart/index.vue b/src/views/chart/index.vue
new file mode 100644
index 0000000..89c60d9
--- /dev/null
+++ b/src/views/chart/index.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/edit/index.vue b/src/views/edit/index.vue
new file mode 100644
index 0000000..f59d497
--- /dev/null
+++ b/src/views/edit/index.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/exception/403.vue b/src/views/exception/403.vue
new file mode 100644
index 0000000..8f973b2
--- /dev/null
+++ b/src/views/exception/403.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
抱歉,你无权访问该页面
+
+
回到首页
+
+
+
+
+
+
diff --git a/src/views/exception/404.vue b/src/views/exception/404.vue
new file mode 100644
index 0000000..d6e0a82
--- /dev/null
+++ b/src/views/exception/404.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
抱歉,你访问的页面不存在
+
+
回到首页
+
+
+
+
+
+
diff --git a/src/views/exception/500.vue b/src/views/exception/500.vue
new file mode 100644
index 0000000..363bb58
--- /dev/null
+++ b/src/views/exception/500.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
抱歉,服务器出错了,建议您重新登录呢
+
+
重新登录
+
+
+
+
+
+
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..1105934
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,432 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ $t('login.form_auto')
+ }}
+
+
+
+
+ {{ $t('login.form_button') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/preview/components/PreviewRenderGroup/index.ts b/src/views/preview/components/PreviewRenderGroup/index.ts
new file mode 100644
index 0000000..5d5a652
--- /dev/null
+++ b/src/views/preview/components/PreviewRenderGroup/index.ts
@@ -0,0 +1,3 @@
+import PreviewRenderGroup from './index.vue'
+
+export { PreviewRenderGroup }
diff --git a/src/views/preview/components/PreviewRenderGroup/index.vue b/src/views/preview/components/PreviewRenderGroup/index.vue
new file mode 100644
index 0000000..e6e22d9
--- /dev/null
+++ b/src/views/preview/components/PreviewRenderGroup/index.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/preview/components/PreviewRenderList/index.ts b/src/views/preview/components/PreviewRenderList/index.ts
new file mode 100644
index 0000000..5dacecd
--- /dev/null
+++ b/src/views/preview/components/PreviewRenderList/index.ts
@@ -0,0 +1,3 @@
+import PreviewRenderList from './index.vue'
+
+export { PreviewRenderList }
diff --git a/src/views/preview/components/PreviewRenderList/index.vue b/src/views/preview/components/PreviewRenderList/index.vue
new file mode 100644
index 0000000..ee5ea39
--- /dev/null
+++ b/src/views/preview/components/PreviewRenderList/index.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
diff --git a/src/views/preview/hooks/useComInstall.hook.ts b/src/views/preview/hooks/useComInstall.hook.ts
new file mode 100644
index 0000000..a11e8bf
--- /dev/null
+++ b/src/views/preview/hooks/useComInstall.hook.ts
@@ -0,0 +1,36 @@
+import { ref } from 'vue'
+import { ChartEditStorageType } from '../index.d'
+import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
+import { fetchChartComponent } from '@/packages/index'
+
+export const useComInstall = (localStorageInfo: ChartEditStorageType) => {
+ const show = ref(false)
+
+ // 注册组件(一开始无法获取window['$vue'])
+ const intervalTiming = setInterval(() => {
+ if (window['$vue']?.component) {
+ clearInterval(intervalTiming)
+
+ const intComponent = (target: CreateComponentType) => {
+ if (!window['$vue'].component(target.chartConfig.chartKey)) {
+ window['$vue'].component(target.chartConfig.chartKey, fetchChartComponent(target.chartConfig))
+ }
+ }
+
+ localStorageInfo.componentList.forEach(async (e: CreateComponentType | CreateComponentGroupType) => {
+ if (e.isGroup) {
+ (e as CreateComponentGroupType).groupList.forEach(groupItem => {
+ intComponent(groupItem)
+ })
+ } else {
+ intComponent(e as CreateComponentType)
+ }
+ })
+ show.value = true
+ }
+ }, 200)
+
+ return {
+ show
+ }
+}
diff --git a/src/views/preview/hooks/useScale.hook.ts b/src/views/preview/hooks/useScale.hook.ts
new file mode 100644
index 0000000..202aaf0
--- /dev/null
+++ b/src/views/preview/hooks/useScale.hook.ts
@@ -0,0 +1,87 @@
+import { ref, onMounted, onUnmounted} from 'vue'
+import { usePreviewFitScale, usePreviewScrollYScale, usePreviewScrollXScale, usePreviewFullScale } from '@/hooks/index'
+import type { ChartEditStorageType } from '../index.d'
+import { PreviewScaleEnum } from '@/enums/styleEnum'
+
+export const useScale = (localStorageInfo: ChartEditStorageType) => {
+
+ const entityRef = ref()
+ const previewRef = ref()
+ const width = ref(localStorageInfo.editCanvasConfig.width)
+ const height = ref(localStorageInfo.editCanvasConfig.height)
+
+ // 屏幕适配
+ onMounted(() => {
+ switch (localStorageInfo.editCanvasConfig.previewScaleType) {
+ case PreviewScaleEnum.FIT: (() => {
+ const { calcRate, windowResize, unWindowResize } = usePreviewFitScale(
+ width.value as number,
+ height.value as number,
+ previewRef.value,
+ )
+ calcRate()
+ windowResize()
+ onUnmounted(() => {
+ unWindowResize()
+ })
+ })()
+ break;
+ case PreviewScaleEnum.SCROLL_Y: (() => {
+ const { calcRate, windowResize, unWindowResize } = usePreviewScrollYScale(
+ width.value as number,
+ height.value as number,
+ previewRef.value,
+ (scale) => {
+ const dom = entityRef.value
+ dom.style.width = `${width.value * scale.width}px`
+ dom.style.height = `${height.value * scale.height}px`
+ }
+ )
+ calcRate()
+ windowResize()
+ onUnmounted(() => {
+ unWindowResize()
+ })
+ })()
+
+ break;
+ case PreviewScaleEnum.SCROLL_X: (() => {
+ const { calcRate, windowResize, unWindowResize } = usePreviewScrollXScale(
+ width.value as number,
+ height.value as number,
+ previewRef.value,
+ (scale) => {
+ const dom = entityRef.value
+ dom.style.width = `${width.value * scale.width}px`
+ dom.style.height = `${height.value * scale.height}px`
+ }
+ )
+ calcRate()
+ windowResize()
+ onUnmounted(() => {
+ unWindowResize()
+ })
+ })()
+
+ break;
+ case PreviewScaleEnum.FULL: (() => {
+ const { calcRate, windowResize, unWindowResize } = usePreviewFullScale(
+ width.value as number,
+ height.value as number,
+ previewRef.value,
+ )
+ calcRate()
+ windowResize()
+ onUnmounted(() => {
+ unWindowResize()
+ })
+ })()
+ break;
+ }
+ })
+
+ return {
+ entityRef,
+ previewRef
+ }
+}
diff --git a/src/views/preview/hooks/useStore.hook.ts b/src/views/preview/hooks/useStore.hook.ts
new file mode 100644
index 0000000..06bed69
--- /dev/null
+++ b/src/views/preview/hooks/useStore.hook.ts
@@ -0,0 +1,9 @@
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { ChartEditStoreEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
+import type { ChartEditStorageType } from '../index.d'
+
+// store 相关
+export const useStore = (localStorageInfo: ChartEditStorageType) => {
+ const chartEditStore = useChartEditStore()
+ chartEditStore.requestGlobalConfig = localStorageInfo[ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]
+}
diff --git a/src/views/preview/index.d.ts b/src/views/preview/index.d.ts
new file mode 100644
index 0000000..0dfbe7c
--- /dev/null
+++ b/src/views/preview/index.d.ts
@@ -0,0 +1,6 @@
+import { ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
+
+export interface ChartEditStorageType extends ChartEditStorage {
+ id: string,
+ isRelease?: boolean
+}
\ No newline at end of file
diff --git a/src/views/preview/index.vue b/src/views/preview/index.vue
new file mode 100644
index 0000000..4e6bc66
--- /dev/null
+++ b/src/views/preview/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/src/views/preview/suspenseIndex.vue b/src/views/preview/suspenseIndex.vue
new file mode 100644
index 0000000..ec10e36
--- /dev/null
+++ b/src/views/preview/suspenseIndex.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
diff --git a/src/views/preview/utils/index.ts b/src/views/preview/utils/index.ts
new file mode 100644
index 0000000..f0f79cf
--- /dev/null
+++ b/src/views/preview/utils/index.ts
@@ -0,0 +1,2 @@
+export * from './style'
+export * from './storage'
\ No newline at end of file
diff --git a/src/views/preview/utils/storage.ts b/src/views/preview/utils/storage.ts
new file mode 100644
index 0000000..5db0609
--- /dev/null
+++ b/src/views/preview/utils/storage.ts
@@ -0,0 +1,38 @@
+import { getSessionStorage, fetchRouteParamsLocation, httpErrorHandle, JSONParse } from '@/utils'
+import { ResultEnum } from '@/enums/httpEnum'
+import { StorageEnum } from '@/enums/storageEnum'
+import { ChartEditStorage } from '@/store/modules/chartEditStore/chartEditStore.d'
+import { fetchProjectApi } from '@/api/path'
+
+export interface ChartEditStorageType extends ChartEditStorage {
+ id: string
+}
+
+// 根据路由 id 获取存储数据的信息
+export const getSessionStorageInfo = async () => {
+ const id = fetchRouteParamsLocation()
+ const storageList: ChartEditStorageType[] = getSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST)
+
+ // 是否本地预览
+ if (!storageList || storageList.findIndex(e => e.id === id.toString()) === -1) {
+ // 接口调用
+ const res = await fetchProjectApi({ id: id })
+ if (res && res.code === ResultEnum.SUCCESS) {
+ const { content, status } = res.data
+ if (status === 1) {
+ // 跳转未发布页
+ return { isRelease: false }
+ }
+ return { ...JSONParse(content), id }
+ } else {
+ httpErrorHandle()
+ }
+ } else {
+ // 本地读取
+ for (let i = 0; i < storageList.length; i++) {
+ if (id.toString() === storageList[i]['id']) {
+ return storageList[i]
+ }
+ }
+ }
+}
diff --git a/src/views/preview/utils/style.ts b/src/views/preview/utils/style.ts
new file mode 100644
index 0000000..6cd25cb
--- /dev/null
+++ b/src/views/preview/utils/style.ts
@@ -0,0 +1,46 @@
+import { PickCreateComponentType } from '@/packages/index.d'
+import { EditCanvasConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
+
+type AttrType = PickCreateComponentType<'attr'>
+type StatusType = PickCreateComponentType<'status'>
+
+// 设置位置
+export const getComponentAttrStyle = (attr: AttrType, index: number) => {
+ const componentStyle = {
+ zIndex: index + 1,
+ left: `${attr.x}px`,
+ top: `${attr.y}px`
+ }
+ return componentStyle
+}
+
+// 设置大小
+export const getSizeStyle = (attr: AttrType, scale?: number) => {
+ return {
+ width: `${scale ? scale * attr.w : attr.w}px`,
+ height: `${scale ? scale * attr.h : attr.h}px`
+ }
+}
+
+// 设置状态样式
+export const getStatusStyle = (attr: StatusType) => {
+ return {
+ display: attr.hide ? 'none' : 'block'
+ }
+}
+
+// 全局样式
+export const getEditCanvasConfigStyle = (canvas: EditCanvasConfigType) => {
+ // 背景
+ const computedBackground = canvas.selectColor
+ ? { background: canvas.background }
+ : {
+ background: `url(${canvas.backgroundImage}) center center / cover no-repeat !important`
+ }
+ return {
+ position: 'relative' as const,
+ width: canvas.width ? `${canvas.width || 100}px` : '100%',
+ height: canvas.height ? `${canvas.height}px` : '100%',
+ ...computedBackground
+ }
+}
diff --git a/src/views/preview/wrapper.vue b/src/views/preview/wrapper.vue
new file mode 100644
index 0000000..86abc6b
--- /dev/null
+++ b/src/views/preview/wrapper.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/src/views/project/index.vue b/src/views/project/index.vue
new file mode 100644
index 0000000..535899b
--- /dev/null
+++ b/src/views/project/index.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/project/items/components/ProjectItemsCard/index.ts b/src/views/project/items/components/ProjectItemsCard/index.ts
new file mode 100644
index 0000000..304ac60
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsCard/index.ts
@@ -0,0 +1,3 @@
+import ProjectItemsCard from './index.vue'
+
+export { ProjectItemsCard }
diff --git a/src/views/project/items/components/ProjectItemsCard/index.vue b/src/views/project/items/components/ProjectItemsCard/index.vue
new file mode 100644
index 0000000..bc79edc
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsCard/index.vue
@@ -0,0 +1,254 @@
+
+
+
+
+
+
+
diff --git a/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts b/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts
new file mode 100644
index 0000000..aad90d1
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsList/hooks/useData.hook.ts
@@ -0,0 +1,124 @@
+import { ref, reactive } from 'vue'
+import { formatDate, goDialog, httpErrorHandle } from '@/utils'
+import { DialogEnum } from '@/enums/pluginEnum'
+import { projectListApi, deleteProjectApi, changeProjectReleaseApi } from '@/api/path'
+import { Chartype, ChartList } from '../../../index.d'
+import { ResultEnum } from '@/enums/httpEnum'
+
+// 数据初始化
+export const useDataListInit = () => {
+ const loading = ref(true)
+
+ const paginat = reactive({
+ // 当前页数
+ page: 1,
+ // 每页值
+ limit: 12,
+ // 总数
+ count: 10
+ })
+
+ const list = ref([])
+
+ // 数据请求
+ const fetchList = async () => {
+ loading.value = true
+ const res = await projectListApi({
+ pageNo: paginat.page,
+ pageSize: paginat.limit
+ })
+ if (res && res.data) {
+ paginat.count = res.data.count
+ const projects = res.data.list
+ list.value = projects.map(e => {
+ const { id, name, status, createTime, picUrl, creator } = e
+ return {
+ id: id,
+ title: name,
+ createId: creator,
+ time: formatDate(new Date(createTime), 'YYY-mm-dd HH:MM:SS'),
+ image: picUrl,
+ release: status === 0
+ }
+ })
+ setTimeout(() => {
+ loading.value = false
+ }, 500)
+ return
+ }
+ httpErrorHandle()
+ }
+
+ // 修改页数
+ const changePage = (_page: number) => {
+ paginat.page = _page
+ fetchList()
+ }
+
+ // 修改大小
+ const changeSize = (_size: number) => {
+ paginat.limit = _size
+ fetchList()
+ }
+
+ // 删除处理
+ const deleteHandle = (cardData: Chartype) => {
+ goDialog({
+ type: DialogEnum.DELETE,
+ promise: true,
+ onPositiveCallback: () =>
+ new Promise(res => {
+ res(
+ deleteProjectApi({
+ id: cardData.id
+ })
+ )
+ }),
+ promiseResCallback: (res: any) => {
+ if (res.code === ResultEnum.SUCCESS) {
+ window['$message'].success(window['$t']('global.r_delete_success'))
+ fetchList()
+ return
+ }
+ httpErrorHandle()
+ }
+ })
+ }
+
+ // 发布处理
+ const releaseHandle = async (cardData: Chartype, index: number) => {
+ const { id, release } = cardData
+ const res = await changeProjectReleaseApi({
+ id: id,
+ // 反过来
+ status: !release ? 0 : 1
+ })
+ if (res && res.code === ResultEnum.SUCCESS) {
+ list.value = []
+ fetchList()
+ // 发布 -> 未发布
+ if (release) {
+ window['$message'].success(window['$t']('global.r_unpublish_success'))
+ return
+ }
+ // 未发布 -> 发布
+ window['$message'].success(window['$t']('global.r_publish_success'))
+ return
+ }
+ httpErrorHandle()
+ }
+
+ // 立即请求
+ fetchList()
+
+ return {
+ loading,
+ paginat,
+ list,
+ fetchList,
+ releaseHandle,
+ changeSize,
+ changePage,
+ deleteHandle
+ }
+}
diff --git a/src/views/project/items/components/ProjectItemsList/hooks/useModal.hook.ts b/src/views/project/items/components/ProjectItemsList/hooks/useModal.hook.ts
new file mode 100644
index 0000000..e28b1f9
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsList/hooks/useModal.hook.ts
@@ -0,0 +1,42 @@
+import { ref } from 'vue'
+import { ChartEnum } from '@/enums/pageEnum'
+import { fetchPathByName, routerTurnByPath, openNewWindow, previewPath } from '@/utils'
+import { Chartype } from '../../../index.d'
+export const useModalDataInit = () => {
+ const modalShow = ref(false)
+ const modalData = ref(null)
+
+ // 关闭 modal
+ const closeModal = () => {
+ modalShow.value = false
+ modalData.value = null
+ }
+
+ // 缩放处理
+ const resizeHandle = (cardData: Chartype) => {
+ if (!cardData) return
+ modalShow.value = true
+ modalData.value = cardData
+ }
+
+ // 编辑处理
+ const editHandle = (cardData: Chartype) => {
+ if (!cardData) return
+ const path = fetchPathByName(ChartEnum.CHART_HOME_NAME, 'href')
+ routerTurnByPath(path, [cardData.id], undefined, true)
+ }
+
+ // 预览处理
+ const previewHandle = (cardData: Chartype) => {
+ openNewWindow(previewPath(cardData.id))
+ }
+
+ return {
+ modalData,
+ modalShow,
+ closeModal,
+ resizeHandle,
+ editHandle,
+ previewHandle
+ }
+}
diff --git a/src/views/project/items/components/ProjectItemsList/index.ts b/src/views/project/items/components/ProjectItemsList/index.ts
new file mode 100644
index 0000000..f4b5290
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsList/index.ts
@@ -0,0 +1,3 @@
+import ProjectItemsList from './index.vue'
+
+export { ProjectItemsList }
diff --git a/src/views/project/items/components/ProjectItemsList/index.vue b/src/views/project/items/components/ProjectItemsList/index.vue
new file mode 100644
index 0000000..81aea4d
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsList/index.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/project/items/components/ProjectItemsModalCard/index.ts b/src/views/project/items/components/ProjectItemsModalCard/index.ts
new file mode 100644
index 0000000..d5b8a58
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsModalCard/index.ts
@@ -0,0 +1,3 @@
+import ProjectItemsModalCard from './index.vue'
+
+export { ProjectItemsModalCard }
diff --git a/src/views/project/items/components/ProjectItemsModalCard/index.vue b/src/views/project/items/components/ProjectItemsModalCard/index.vue
new file mode 100644
index 0000000..1916462
--- /dev/null
+++ b/src/views/project/items/components/ProjectItemsModalCard/index.vue
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+
+
+ {{ cardData?.title || cardData?.id || '未命名' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/project/items/index.d.ts b/src/views/project/items/index.d.ts
new file mode 100644
index 0000000..b0be038
--- /dev/null
+++ b/src/views/project/items/index.d.ts
@@ -0,0 +1,11 @@
+export type Chartype = {
+ id: number | string
+ title: string // 标题
+ label?: string // 标签
+ time: string, // 时间
+ image: string, // 预览图地址
+ createId: string, // 创建者
+ release: boolean // false 未发布 | true 已发布
+}
+
+export type ChartList = Chartype[]
\ No newline at end of file
diff --git a/src/views/project/items/index.vue b/src/views/project/items/index.vue
new file mode 100644
index 0000000..78b79c1
--- /dev/null
+++ b/src/views/project/items/index.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/src/views/project/layout/components/ProjectLayoutAsideFooter/index.ts b/src/views/project/layout/components/ProjectLayoutAsideFooter/index.ts
new file mode 100644
index 0000000..6032c13
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutAsideFooter/index.ts
@@ -0,0 +1,3 @@
+import ProjectLayoutAsideFooter from './index.vue'
+
+export { ProjectLayoutAsideFooter }
diff --git a/src/views/project/layout/components/ProjectLayoutAsideFooter/index.vue b/src/views/project/layout/components/ProjectLayoutAsideFooter/index.vue
new file mode 100644
index 0000000..731796c
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutAsideFooter/index.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
diff --git a/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.ts b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.ts
new file mode 100644
index 0000000..6d5e114
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.ts
@@ -0,0 +1,3 @@
+import CreateModal from './index.vue'
+
+export { CreateModal }
diff --git a/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue
new file mode 100644
index 0000000..2dcc5c0
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutCreate/components/CreateModal/index.vue
@@ -0,0 +1,138 @@
+
+
+
+
+
+ {{ $t('project.create_tip') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/project/layout/components/ProjectLayoutCreate/index.ts b/src/views/project/layout/components/ProjectLayoutCreate/index.ts
new file mode 100644
index 0000000..d732e52
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutCreate/index.ts
@@ -0,0 +1,3 @@
+import ProjectLayoutCreate from './index.vue'
+
+export { ProjectLayoutCreate }
diff --git a/src/views/project/layout/components/ProjectLayoutCreate/index.vue b/src/views/project/layout/components/ProjectLayoutCreate/index.vue
new file mode 100644
index 0000000..12f294f
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutCreate/index.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('project.create_btn') }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('project.create_btn') }}
+
+
+
+
+
+
diff --git a/src/views/project/layout/components/ProjectLayoutSider/index.ts b/src/views/project/layout/components/ProjectLayoutSider/index.ts
new file mode 100644
index 0000000..d870cce
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutSider/index.ts
@@ -0,0 +1,3 @@
+import ProjectLayoutSider from './index.vue'
+
+export { ProjectLayoutSider }
diff --git a/src/views/project/layout/components/ProjectLayoutSider/index.vue b/src/views/project/layout/components/ProjectLayoutSider/index.vue
new file mode 100644
index 0000000..c7b963e
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutSider/index.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/project/layout/components/ProjectLayoutSider/menu.ts b/src/views/project/layout/components/ProjectLayoutSider/menu.ts
new file mode 100644
index 0000000..c878f70
--- /dev/null
+++ b/src/views/project/layout/components/ProjectLayoutSider/menu.ts
@@ -0,0 +1,86 @@
+import { reactive, h } from 'vue'
+import { renderIcon } from '@/utils'
+import { RouterLink } from 'vue-router'
+import { PageEnum } from '@/enums/pageEnum'
+import { MenuOption, MenuGroupOption } from 'naive-ui'
+import { icon } from '@/plugins'
+
+const { GridIcon, TvOutlineIcon } = icon.ionicons5
+const { StoreIcon, ObjectStorageIcon, DevicesIcon } = icon.carbon
+export const renderMenuLabel = (option: MenuOption | MenuGroupOption) => {
+ return option.label
+}
+
+export const expandedKeys = () => ['all-project']
+
+export const menuOptionsInit = () => {
+ const t = window['$t']
+
+ return reactive([
+ {
+ key: 'divider-1',
+ type: 'divider',
+ },
+ {
+ label: () => h('span', null, { default: () => t('project.project') }),
+ key: 'all-project',
+ icon: renderIcon(DevicesIcon),
+ children: [
+ {
+ type: 'group',
+ label: () => h('span', null, { default: () => t('project.my') }),
+ key: 'my-project',
+ children: [
+ {
+ label: () =>
+ h(
+ RouterLink,
+ {
+ to: {
+ name: PageEnum.BASE_HOME_ITEMS_NAME,
+ },
+ },
+ { default: () => t('project.all_project') }
+ ),
+ key: PageEnum.BASE_HOME_ITEMS_NAME,
+ icon: renderIcon(TvOutlineIcon),
+ },
+ {
+ label: () =>
+ h(
+ RouterLink,
+ {
+ to: {
+ name: PageEnum.BASE_HOME_TEMPLATE_NAME,
+ },
+ },
+ { default: () => t('project.my_templete') }
+ ),
+ key: PageEnum.BASE_HOME_TEMPLATE_NAME,
+ icon: renderIcon(ObjectStorageIcon),
+ },
+ ],
+ },
+ ],
+ },
+
+ {
+ key: 'divider-2',
+ type: 'divider',
+ },
+ {
+ label: () =>
+ h(
+ RouterLink,
+ {
+ to: {
+ name: PageEnum.BASE_HOME_TEMPLATE_MARKET_NAME,
+ },
+ },
+ { default: () => t('project.template_market') }
+ ),
+ key: PageEnum.BASE_HOME_TEMPLATE_MARKET_NAME,
+ icon: renderIcon(StoreIcon),
+ },
+ ])
+}
diff --git a/src/views/project/mtTemplate/index.vue b/src/views/project/mtTemplate/index.vue
new file mode 100644
index 0000000..22ffd40
--- /dev/null
+++ b/src/views/project/mtTemplate/index.vue
@@ -0,0 +1,24 @@
+
+
+
+
+ 暂时还没有东西呢
+
+
+
+
+
+
+
diff --git a/src/views/project/templateMarket/index.vue b/src/views/project/templateMarket/index.vue
new file mode 100644
index 0000000..fffc9e1
--- /dev/null
+++ b/src/views/project/templateMarket/index.vue
@@ -0,0 +1,19 @@
+
+
+
+
+ 暂时还没有东西呢
+
+
+
+
+
+
+
diff --git a/src/views/redirect/UnPublish.vue b/src/views/redirect/UnPublish.vue
new file mode 100644
index 0000000..2429dd3
--- /dev/null
+++ b/src/views/redirect/UnPublish.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
当前项目暂未发布
+
+
+
+
+
diff --git a/src/views/redirect/index.vue b/src/views/redirect/index.vue
new file mode 100644
index 0000000..7ff0e23
--- /dev/null
+++ b/src/views/redirect/index.vue
@@ -0,0 +1,31 @@
+
+
+
+
+ 看看别的
+
+
+
+
+
+
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..07a4c65
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": true,
+ "jsx": "preserve",
+ "baseUrl": ".",
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "lib": ["es6", "ESNext", "dom"],
+ "types": ["vite/client"],
+ "paths": {
+ "@/*": ["src/*"],
+ "/#/*": ["types/*"]
+ },
+ "noImplicitAny": true, //不允许使用any
+ // "strictNullChecks": true, //不允许使用null
+ "noImplicitThis": true //不允许往this上面挂属性
+ },
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*"],
+ "exclude": ["node_modules", "dist", "**/*.js"]
+}
diff --git a/types/global.d.ts b/types/global.d.ts
new file mode 100644
index 0000000..aabfe76
--- /dev/null
+++ b/types/global.d.ts
@@ -0,0 +1,16 @@
+interface Window {
+ $loading: any
+ $message: any
+ $dialog: any
+ // 语言
+ $t: any
+ $vue: any
+ // 键盘按键记录
+ $KeyboardActive?: { [T: string]: boolean }
+ onKeySpacePressHold?: Function
+
+ // 编辑 JSON 的存储对象
+ opener: any
+}
+
+declare type Recordable = Record
diff --git a/types/shims-vue.d.ts b/types/shims-vue.d.ts
new file mode 100644
index 0000000..fbfc892
--- /dev/null
+++ b/types/shims-vue.d.ts
@@ -0,0 +1,8 @@
+declare module '*.vue' {
+ import { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
+
+declare module 'lodash/*'
+declare module 'dom-helpers'
\ No newline at end of file
diff --git a/types/vite-env.d.ts b/types/vite-env.d.ts
new file mode 100644
index 0000000..317bb4b
--- /dev/null
+++ b/types/vite-env.d.ts
@@ -0,0 +1,10 @@
+///
+
+interface ImportMetaEnv {
+ // 端口
+ VITE_DEV_PORT: string;
+ // 开发地址
+ VITE_DEV_PATH: string
+ // 生产地址
+ VITE_PRO_PATH: string
+}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..ad47cad
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,92 @@
+import { defineConfig, loadEnv } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import { resolve } from 'path'
+import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant'
+import viteCompression from 'vite-plugin-compression'
+import { axiosPre } from './src/settings/httpSetting'
+import { viteMockServe } from 'vite-plugin-mock'
+import monacoEditorPlugin from 'vite-plugin-monaco-editor'
+
+function pathResolve(dir: string) {
+ return resolve(process.cwd(), '.', dir)
+}
+
+export default ({ mode }) => defineConfig({
+ base: process.env.NODE_ENV === 'production' ? './' : '/',
+ // 路径重定向
+ resolve: {
+ alias: [
+ {
+ find: /\/#\//,
+ replacement: pathResolve('types')
+ },
+ {
+ find: '@',
+ replacement: pathResolve('src')
+ },
+ {
+ find: 'vue-i18n',
+ replacement: 'vue-i18n/dist/vue-i18n.cjs.js', //解决i8n警告
+ }
+ ],
+ dedupe: ['vue']
+ },
+ // 全局 css 注册
+ css: {
+ preprocessorOptions: {
+ scss: {
+ javascriptEnabled: true,
+ additionalData: `@import "src/styles/common/style.scss";`
+ }
+ }
+ },
+ // 开发服务器配置
+ server: {
+ host: true,
+ open: true,
+ port: 3000,
+ proxy: {
+ [axiosPre]: {
+ // @ts-ignore
+ target: loadEnv(mode, process.cwd()).VITE_DEV_PATH,
+ changeOrigin: true,
+ ws: true,
+ secure: true,
+ }
+ }
+ },
+ plugins: [
+ vue(),
+ monacoEditorPlugin({
+ languageWorkers: ['editorWorkerService', 'typescript', 'json', 'html']
+ }),
+ viteMockServe({
+ mockPath: '/src/api/mock',
+ // 开发打包开关
+ localEnabled: true,
+ // 生产打包开关
+ prodEnabled: true,
+ // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
+ supportTs: true,
+ // 监视文件更改
+ watchFiles: true
+ }),
+ // 压缩
+ viteCompression({
+ verbose: true,
+ disable: false,
+ threshold: 10240,
+ algorithm: 'gzip',
+ ext: '.gz'
+ })
+ ],
+ build: {
+ target: 'es2015',
+ outDir: OUTPUT_DIR,
+ // minify: 'terser', // 如果需要用terser混淆,可打开这两行
+ // terserOptions: terserOptions,
+ rollupOptions: rollupOptions,
+ brotliSize: brotliSize,
+ chunkSizeWarningLimit: chunkSizeWarningLimit
+ }
+})