chartEditStore.ts 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. import { toRaw } from 'vue'
  2. import { defineStore } from 'pinia'
  3. import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
  4. import { PublicGroupConfigClass } from '@/packages/public/publicConfig'
  5. import debounce from 'lodash/debounce'
  6. import cloneDeep from 'lodash/cloneDeep'
  7. import { defaultTheme, globalThemeJson } from '@/settings/chartThemes/index'
  8. import { requestInterval, previewScaleType, requestIntervalUnit } from '@/settings/designSetting'
  9. // 记录记录
  10. import { useChartHistoryStore } from '@/store/modules/chartHistoryStore/chartHistoryStore'
  11. // 全局设置
  12. import { useSettingStore } from '@/store/modules/settingStore/settingStore'
  13. import {
  14. HistoryActionTypeEnum,
  15. HistoryItemType,
  16. HistoryTargetTypeEnum
  17. } from '@/store/modules/chartHistoryStore/chartHistoryStore.d'
  18. import { MenuEnum } from '@/enums/editPageEnum'
  19. import { getUUID, loadingStart, loadingFinish, loadingError, isString, isArray } from '@/utils'
  20. import {
  21. ChartEditStoreEnum,
  22. ChartEditStorage,
  23. ChartEditStoreType,
  24. EditCanvasType,
  25. MousePositionType,
  26. TargetChartType,
  27. RecordChartType,
  28. RequestGlobalConfigType,
  29. EditCanvasConfigType
  30. } from './chartEditStore.d'
  31. const chartHistoryStore = useChartHistoryStore()
  32. const settingStore = useSettingStore()
  33. // 编辑区域内容
  34. export const useChartEditStore = defineStore({
  35. id: 'useChartEditStore',
  36. state: (): ChartEditStoreType => ({
  37. // 画布属性
  38. editCanvas: {
  39. // 编辑区域 Dom
  40. editLayoutDom: null,
  41. editContentDom: null,
  42. // 偏移量
  43. offset: 20,
  44. // 系统控制缩放
  45. scale: 1,
  46. // 用户控制的缩放
  47. userScale: 1,
  48. // 锁定缩放
  49. lockScale: false,
  50. // 初始化
  51. isCreate: false,
  52. // 拖拽中
  53. isDrag: false,
  54. // 框选中
  55. isSelect: false
  56. },
  57. // 右键菜单
  58. rightMenuShow: false,
  59. // 鼠标定位
  60. mousePosition: {
  61. startX: 0,
  62. startY: 0,
  63. x: 0,
  64. y: 0
  65. },
  66. // 目标图表
  67. targetChart: {
  68. hoverId: undefined,
  69. selectId: []
  70. },
  71. // 记录临时数据(复制等)
  72. recordChart: undefined,
  73. // -----------------------
  74. // 画布属性(需存储给后端)
  75. editCanvasConfig: {
  76. // 默认宽度
  77. width: 1920,
  78. // 默认高度
  79. height: 1080,
  80. // 启用滤镜
  81. filterShow: false,
  82. // 色相
  83. hueRotate: 0,
  84. // 饱和度
  85. saturate: 1,
  86. // 对比度
  87. contrast: 1,
  88. // 亮度
  89. brightness: 1,
  90. // 透明度
  91. opacity: 1,
  92. // 变换(暂不更改)
  93. rotateZ: 0,
  94. rotateX: 0,
  95. rotateY: 0,
  96. skewX: 0,
  97. skewY: 0,
  98. // 默认背景色
  99. background: undefined,
  100. backgroundImage: undefined,
  101. // 是否使用纯颜色
  102. selectColor: true,
  103. // chart 主题色
  104. chartThemeColor: defaultTheme || 'dark',
  105. // 全局配置
  106. chartThemeSetting: globalThemeJson,
  107. // 预览方式
  108. previewScaleType: previewScaleType
  109. },
  110. // 数据请求处理(需存储给后端)
  111. requestGlobalConfig: {
  112. requestOriginUrl: '',
  113. requestInterval: requestInterval,
  114. requestIntervalUnit: requestIntervalUnit,
  115. requestParams: {
  116. Body: {
  117. 'form-data': {},
  118. 'x-www-form-urlencoded': {},
  119. json: '',
  120. xml: ''
  121. },
  122. Header: {},
  123. Params: {}
  124. }
  125. },
  126. // 图表数组(需存储给后端)
  127. componentList: []
  128. }),
  129. getters: {
  130. getMousePosition(): MousePositionType {
  131. return this.mousePosition
  132. },
  133. getRightMenuShow(): boolean {
  134. return this.rightMenuShow
  135. },
  136. getEditCanvas(): EditCanvasType {
  137. return this.editCanvas
  138. },
  139. getEditCanvasConfig(): EditCanvasConfigType {
  140. return this.editCanvasConfig
  141. },
  142. getTargetChart(): TargetChartType {
  143. return this.targetChart
  144. },
  145. getRecordChart(): RecordChartType | undefined {
  146. return this.recordChart
  147. },
  148. getRequestGlobalConfig(): RequestGlobalConfigType {
  149. return this.requestGlobalConfig
  150. },
  151. getComponentList(): Array<CreateComponentType | CreateComponentGroupType> {
  152. return this.componentList
  153. },
  154. // 获取需要存储的数据项
  155. getStorageInfo(): ChartEditStorage {
  156. return {
  157. [ChartEditStoreEnum.EDIT_CANVAS_CONFIG]: this.getEditCanvasConfig,
  158. [ChartEditStoreEnum.COMPONENT_LIST]: this.getComponentList,
  159. [ChartEditStoreEnum.REQUEST_GLOBAL_CONFIG]: this.getRequestGlobalConfig
  160. }
  161. }
  162. },
  163. actions: {
  164. // * 设置 editCanvas 数据项
  165. setEditCanvas<T extends keyof EditCanvasType, K extends EditCanvasType[T]>(key: T, value: K) {
  166. this.editCanvas[key] = value
  167. },
  168. // * 设置 editCanvasConfig(需保存后端) 数据项
  169. setEditCanvasConfig<T extends keyof EditCanvasConfigType, K extends EditCanvasConfigType[T]>(key: T, value: K) {
  170. this.editCanvasConfig[key] = value
  171. },
  172. // * 设置右键菜单
  173. setRightMenuShow(value: boolean) {
  174. this.rightMenuShow = value
  175. },
  176. // * 设置目标数据 hover
  177. setTargetHoverChart(hoverId?: TargetChartType['hoverId']) {
  178. this.targetChart.hoverId = hoverId
  179. },
  180. // * 设置目标数据 select
  181. setTargetSelectChart(selectId?: string | string[], push: boolean = false) {
  182. // 重复选中
  183. if (this.targetChart.selectId.find((e: string) => e === selectId)) return
  184. // 无 id 清空
  185. if (!selectId) {
  186. this.targetChart.selectId = []
  187. return
  188. }
  189. // 多选
  190. if (push) {
  191. // 字符串
  192. if (isString(selectId)) {
  193. this.targetChart.selectId.push(selectId)
  194. return
  195. }
  196. // 数组
  197. if (isArray(selectId)) {
  198. this.targetChart.selectId.push(...selectId)
  199. return
  200. }
  201. } else {
  202. // 字符串
  203. if (isString(selectId)) {
  204. this.targetChart.selectId = [selectId]
  205. return
  206. }
  207. // 数组
  208. if (isArray(selectId)) {
  209. this.targetChart.selectId = selectId
  210. return
  211. }
  212. }
  213. },
  214. // * 设置记录数据
  215. setRecordChart(item: RecordChartType | undefined) {
  216. this.recordChart = cloneDeep(item)
  217. },
  218. // * 设置鼠标位置
  219. setMousePosition(x?: number, y?: number, startX?: number, startY?: number): void {
  220. if (x) this.mousePosition.x = x
  221. if (y) this.mousePosition.y = y
  222. if (startX) this.mousePosition.startX = startX
  223. if (startY) this.mousePosition.startY = startY
  224. },
  225. // * 找到目标 id 数据的下标位置,id可为父级或子集数组(无则返回-1)
  226. fetchTargetIndex(id?: string): number {
  227. const targetId = id || (this.getTargetChart.selectId.length && this.getTargetChart.selectId[0]) || undefined
  228. if (!targetId) {
  229. loadingFinish()
  230. return -1
  231. }
  232. const targetIndex = this.componentList.findIndex(e => e.id === targetId)
  233. // 当前
  234. if (targetIndex !== -1) {
  235. return targetIndex
  236. } else {
  237. const length = this.getComponentList.length
  238. for (let i = 0; i < length; i++) {
  239. if (this.getComponentList[i].isGroup) {
  240. for (const cItem of (this.getComponentList[i] as CreateComponentGroupType).groupList) {
  241. if (cItem.id === targetId) {
  242. return i
  243. }
  244. }
  245. }
  246. }
  247. }
  248. return -1
  249. },
  250. // * 统一格式化处理入参 id
  251. idPreFormat(id?: string | string[]) {
  252. const idArr = []
  253. if (!id) {
  254. idArr.push(...this.getTargetChart.selectId)
  255. return idArr
  256. }
  257. if (isString(id)) idArr.push(id)
  258. if (isArray(id)) idArr.push(...id)
  259. return idArr
  260. },
  261. /**
  262. * * 新增组件列表
  263. * @param componentInstance 新图表实例
  264. * @param isHead 是否头部插入
  265. * @param isHistory 是否进行记录
  266. * @returns
  267. */
  268. addComponentList(
  269. componentInstance:
  270. | CreateComponentType
  271. | CreateComponentGroupType
  272. | Array<CreateComponentType | CreateComponentGroupType>,
  273. isHead = false,
  274. isHistory = false
  275. ): void {
  276. if (componentInstance instanceof Array) {
  277. componentInstance.forEach(item => {
  278. this.addComponentList(item, isHead, isHistory)
  279. })
  280. return
  281. }
  282. if (isHistory) {
  283. chartHistoryStore.createAddHistory([componentInstance])
  284. }
  285. if (isHead) {
  286. this.componentList.unshift(componentInstance)
  287. return
  288. }
  289. this.componentList.push(componentInstance)
  290. },
  291. // * 删除组件
  292. removeComponentList(id?: string | string[], isHistory = true): void {
  293. try {
  294. const idArr = this.idPreFormat(id)
  295. const history: Array<CreateComponentType | CreateComponentGroupType> = []
  296. // 遍历所有对象
  297. if (!idArr.length) return
  298. loadingStart()
  299. idArr.forEach(ids => {
  300. const index = this.fetchTargetIndex(ids)
  301. if (index !== -1) {
  302. history.push(this.getComponentList[index])
  303. this.componentList.splice(index, 1)
  304. }
  305. })
  306. isHistory && chartHistoryStore.createDeleteHistory(history)
  307. loadingFinish()
  308. return
  309. } catch (value) {
  310. loadingError()
  311. }
  312. },
  313. // * 重置组件位置
  314. resetComponentPosition(item: CreateComponentType | CreateComponentGroupType, isForward: boolean): void {
  315. const index = this.fetchTargetIndex(item.id)
  316. if (index > -1) {
  317. const componentInstance = this.getComponentList[index]
  318. if (isForward) {
  319. componentInstance.attr = Object.assign(componentInstance.attr, {
  320. x: item.attr.x + item.attr.offsetX,
  321. y: item.attr.y + item.attr.offsetY
  322. })
  323. } else {
  324. componentInstance.attr = Object.assign(componentInstance.attr, {
  325. x: item.attr.x,
  326. y: item.attr.y
  327. })
  328. }
  329. }
  330. },
  331. // * 移动组件
  332. moveComponentList(item: Array<CreateComponentType | CreateComponentGroupType>) {
  333. chartHistoryStore.createMoveHistory(item)
  334. },
  335. // * 更新组件列表某一项的值
  336. updateComponentList(index: number, newData: CreateComponentType | CreateComponentGroupType) {
  337. if (index < 1 && index > this.getComponentList.length) return
  338. this.componentList[index] = newData
  339. },
  340. // * 设置页面样式属性
  341. setPageStyle<T extends keyof CSSStyleDeclaration>(key: T, value: any): void {
  342. const dom = this.getEditCanvas.editContentDom
  343. if (dom) {
  344. dom.style[key] = value
  345. }
  346. },
  347. // * 移动组件列表层级位置到两端
  348. setBothEnds(isEnd = false, isHistory = true): void {
  349. try {
  350. // 暂不支持多选
  351. if (this.getTargetChart.selectId.length > 1) return
  352. loadingStart()
  353. const length = this.getComponentList.length
  354. if (length < 2) {
  355. loadingFinish()
  356. return
  357. }
  358. const index = this.fetchTargetIndex()
  359. const targetData = this.getComponentList[index]
  360. if (index !== -1) {
  361. // 置底排除最底层, 置顶排除最顶层
  362. if ((isEnd && index === 0) || (!isEnd && index === length - 1)) {
  363. loadingFinish()
  364. return
  365. }
  366. // 记录原有位置
  367. const setIndex = (componentInstance: CreateComponentType | CreateComponentGroupType, i: number) => {
  368. const temp = cloneDeep(componentInstance)
  369. temp.attr.zIndex = i
  370. return temp
  371. }
  372. // 历史记录
  373. if (isHistory) {
  374. chartHistoryStore.createLayerHistory(
  375. [setIndex(targetData, index)],
  376. isEnd ? HistoryActionTypeEnum.BOTTOM : HistoryActionTypeEnum.TOP
  377. )
  378. }
  379. // 插入两端
  380. this.addComponentList(targetData, isEnd)
  381. this.getComponentList.splice(isEnd ? index + 1 : index, 1)
  382. loadingFinish()
  383. return
  384. }
  385. } catch (value) {
  386. loadingError()
  387. }
  388. },
  389. // * 置顶
  390. setTop(isHistory = true): void {
  391. this.setBothEnds(false, isHistory)
  392. },
  393. // * 置底
  394. setBottom(isHistory = true): void {
  395. this.setBothEnds(true, isHistory)
  396. },
  397. // * 上移/下移互换图表位置
  398. wrap(isDown = false, isHistory = true) {
  399. try {
  400. // 暂不支持多选
  401. if (this.getTargetChart.selectId.length > 1) return
  402. loadingStart()
  403. const length = this.getComponentList.length
  404. if (length < 2) {
  405. loadingFinish()
  406. return
  407. }
  408. const index: number = this.fetchTargetIndex()
  409. if (index !== -1) {
  410. // 下移排除最底层, 上移排除最顶层
  411. if ((isDown && index === 0) || (!isDown && index === length - 1)) {
  412. loadingFinish()
  413. return
  414. }
  415. // 互换位置
  416. const swapIndex = isDown ? index - 1 : index + 1
  417. const targetItem = this.getComponentList[index]
  418. const swapItem = this.getComponentList[swapIndex]
  419. // 历史记录
  420. if (isHistory) {
  421. chartHistoryStore.createLayerHistory(
  422. [targetItem],
  423. isDown ? HistoryActionTypeEnum.DOWN : HistoryActionTypeEnum.UP
  424. )
  425. }
  426. this.updateComponentList(index, swapItem)
  427. this.updateComponentList(swapIndex, targetItem)
  428. loadingFinish()
  429. return
  430. }
  431. } catch (value) {
  432. loadingError()
  433. }
  434. },
  435. // * 图层上移
  436. setUp(isHistory = true) {
  437. this.wrap(false, isHistory)
  438. },
  439. // * 图层下移
  440. setDown(isHistory = true) {
  441. this.wrap(true, isHistory)
  442. },
  443. // * 复制
  444. setCopy(isCut = false) {
  445. try {
  446. // 暂不支持多选
  447. if (this.getTargetChart.selectId.length > 1) return
  448. // 处理弹窗普通复制的场景
  449. if (document.getElementsByClassName('n-modal-body-wrapper').length) return
  450. loadingStart()
  451. const index: number = this.fetchTargetIndex()
  452. if (index !== -1) {
  453. const copyData: RecordChartType = {
  454. charts: this.getComponentList[index],
  455. type: isCut ? HistoryActionTypeEnum.CUT : HistoryActionTypeEnum.COPY
  456. }
  457. this.setRecordChart(copyData)
  458. window['$message'].success(isCut ? '剪切图表成功' : '复制图表成功!')
  459. loadingFinish()
  460. }
  461. } catch (value) {
  462. loadingError()
  463. }
  464. },
  465. // * 剪切
  466. setCut() {
  467. this.setCopy(true)
  468. },
  469. // * 粘贴
  470. setParse() {
  471. try {
  472. loadingStart()
  473. const recordCharts = this.getRecordChart
  474. if (recordCharts === undefined) {
  475. loadingFinish()
  476. return
  477. }
  478. const parseHandle = (e: CreateComponentType | CreateComponentGroupType) => {
  479. e = cloneDeep(e)
  480. // 生成新 id
  481. e.id = getUUID()
  482. e.attr.x = this.getMousePosition.x + 30
  483. e.attr.y = this.getMousePosition.y + 30
  484. return e
  485. }
  486. const isCut = recordCharts.type === HistoryActionTypeEnum.CUT
  487. // 多项
  488. if (Array.isArray(recordCharts.charts)) {
  489. recordCharts.charts.forEach((e: CreateComponentType) => {
  490. this.addComponentList(parseHandle(e), undefined, true)
  491. // 剪切需删除原数据
  492. if (isCut) {
  493. this.setTargetSelectChart(e.id)
  494. this.removeComponentList(undefined, true)
  495. }
  496. })
  497. if (isCut) this.setRecordChart(undefined)
  498. loadingFinish()
  499. return
  500. }
  501. // 单项
  502. this.addComponentList(parseHandle(recordCharts.charts), undefined, true)
  503. if (isCut) {
  504. this.setTargetSelectChart(recordCharts.charts.id)
  505. this.removeComponentList()
  506. this.setRecordChart(undefined)
  507. }
  508. loadingFinish()
  509. } catch (value) {
  510. loadingError()
  511. }
  512. },
  513. // * 撤回/前进 目标处理
  514. setBackAndSetForwardHandle(HistoryItem: HistoryItemType, isForward = false) {
  515. // 处理画布
  516. if (HistoryItem.targetType === HistoryTargetTypeEnum.CANVAS) {
  517. this.editCanvas = HistoryItem.historyData[0] as EditCanvasType
  518. return
  519. }
  520. let historyData = HistoryItem.historyData as Array<CreateComponentType | CreateComponentGroupType>
  521. if (isArray(historyData)) {
  522. // 选中目标元素,支持多个
  523. historyData.forEach((item: CreateComponentType | CreateComponentGroupType) => {
  524. this.setTargetSelectChart(item.id, true)
  525. })
  526. }
  527. // 处理新增类型
  528. const isAdd = HistoryItem.actionType === HistoryActionTypeEnum.ADD
  529. const isDel = HistoryItem.actionType === HistoryActionTypeEnum.DELETE
  530. if (isAdd || isDel) {
  531. if ((isAdd && isForward) || (isDel && !isForward)) {
  532. historyData.forEach(item => {
  533. this.addComponentList(item)
  534. })
  535. return
  536. }
  537. historyData.forEach(item => {
  538. this.removeComponentList(item.id, false)
  539. })
  540. return
  541. }
  542. // 处理移动
  543. const isMove = HistoryItem.actionType === HistoryActionTypeEnum.MOVE
  544. if (isMove) {
  545. historyData.forEach(item => {
  546. this.resetComponentPosition(item, isForward)
  547. })
  548. return
  549. }
  550. // 处理层级
  551. const isTop = HistoryItem.actionType === HistoryActionTypeEnum.TOP
  552. const isBottom = HistoryItem.actionType === HistoryActionTypeEnum.BOTTOM
  553. if (isTop || isBottom) {
  554. if (!isForward) {
  555. // 插入到原有位置
  556. if (isTop) this.getComponentList.pop()
  557. if (isBottom) this.getComponentList.shift()
  558. this.getComponentList.splice(historyData[0].attr.zIndex, 0, historyData[0])
  559. return
  560. }
  561. if (isTop) this.setTop(false)
  562. if (isBottom) this.setBottom(false)
  563. }
  564. const isUp = HistoryItem.actionType === HistoryActionTypeEnum.UP
  565. const isDown = HistoryItem.actionType === HistoryActionTypeEnum.DOWN
  566. if (isUp || isDown) {
  567. if ((isUp && isForward) || (isDown && !isForward)) {
  568. this.setUp(false)
  569. return
  570. }
  571. this.setDown(false)
  572. return
  573. }
  574. // 处理分组
  575. const isGroup = HistoryItem.actionType === HistoryActionTypeEnum.GROUP
  576. const isUnGroup = HistoryItem.actionType === HistoryActionTypeEnum.UN_GROUP
  577. if (isGroup || isUnGroup) {
  578. if ((isGroup && isForward) || (isUnGroup && !isForward)) {
  579. const ids: string[] = []
  580. if (historyData.length > 1) {
  581. historyData.forEach(item => {
  582. ids.push(item.id)
  583. })
  584. } else {
  585. const group = historyData[0] as CreateComponentGroupType
  586. group.groupList.forEach(item => {
  587. ids.push(item.id)
  588. })
  589. }
  590. this.setGroup(ids, false)
  591. return
  592. }
  593. // 都需使用子组件的id去解组
  594. if (historyData.length > 1) {
  595. this.setUnGroup([(historyData[0] as CreateComponentType).id], undefined, false)
  596. } else {
  597. this.setUnGroup([(historyData[0] as CreateComponentGroupType).groupList[0].id], undefined, false)
  598. }
  599. return
  600. }
  601. switch (HistoryItem.actionType) {
  602. // 锁定处理
  603. case HistoryActionTypeEnum.LOCK:
  604. case HistoryActionTypeEnum.UNLOCK:
  605. if (!isForward) {
  606. // 恢复原来状态
  607. if (HistoryItem.actionType === HistoryActionTypeEnum.LOCK) historyData[0].status.lock = false
  608. if (HistoryItem.actionType === HistoryActionTypeEnum.UNLOCK) historyData[0].status.lock = true
  609. return
  610. }
  611. this.setLock(!historyData[0].status.lock, false)
  612. break
  613. // 隐藏处理
  614. case HistoryActionTypeEnum.HIDE:
  615. case HistoryActionTypeEnum.SHOW:
  616. if (!isForward) {
  617. // 恢复原来状态
  618. if (HistoryItem.actionType === HistoryActionTypeEnum.HIDE) historyData[0].status.hide = false
  619. if (HistoryItem.actionType === HistoryActionTypeEnum.SHOW) historyData[0].status.hide = true
  620. return
  621. }
  622. this.setHide(!historyData[0].status.hide, false)
  623. break
  624. }
  625. },
  626. // * 撤回
  627. setBack() {
  628. try {
  629. loadingStart()
  630. const targetData = chartHistoryStore.backAction()
  631. if (!targetData) {
  632. loadingFinish()
  633. return
  634. }
  635. this.setBackAndSetForwardHandle(targetData)
  636. loadingFinish()
  637. } catch (value) {
  638. loadingError()
  639. }
  640. },
  641. // * 前进
  642. setForward() {
  643. try {
  644. loadingStart()
  645. const targetData = chartHistoryStore.forwardAction()
  646. if (!targetData) {
  647. loadingFinish()
  648. return
  649. }
  650. this.setBackAndSetForwardHandle(targetData, true)
  651. loadingFinish()
  652. } catch (value) {
  653. loadingError()
  654. }
  655. },
  656. // * 移动位置
  657. setMove(keyboardValue: MenuEnum) {
  658. const index = this.fetchTargetIndex()
  659. if (index === -1) return
  660. const attr = this.getComponentList[index].attr
  661. const distance = settingStore.getChartMoveDistance
  662. switch (keyboardValue) {
  663. case MenuEnum.ARROW_UP:
  664. attr.y -= distance
  665. break
  666. case MenuEnum.ARROW_RIGHT:
  667. attr.x += distance
  668. break
  669. case MenuEnum.ARROW_DOWN:
  670. attr.y += distance
  671. break
  672. case MenuEnum.ARROW_LEFT:
  673. attr.x -= distance
  674. break
  675. }
  676. },
  677. // * 创建分组
  678. setGroup(id?: string | string[], isHistory = true) {
  679. try {
  680. const selectIds = this.idPreFormat(id) || this.getTargetChart.selectId
  681. if (selectIds.length < 2) return
  682. loadingStart()
  683. const groupClass = new PublicGroupConfigClass()
  684. // 记录整体坐标
  685. const groupAttr = {
  686. l: this.getEditCanvasConfig.width,
  687. t: this.getEditCanvasConfig.height,
  688. r: 0,
  689. b: 0
  690. }
  691. const targetList: CreateComponentType[] = []
  692. const historyList: CreateComponentType[] = []
  693. // 若目标中有数组则先解组
  694. const newSelectIds: string[] = []
  695. selectIds.forEach((id: string) => {
  696. const targetIndex = this.fetchTargetIndex(id)
  697. if (targetIndex !== -1 && this.getComponentList[targetIndex].isGroup) {
  698. this.setUnGroup(
  699. [id],
  700. (e: CreateComponentType[]) => {
  701. e.forEach(e => {
  702. this.addComponentList(e)
  703. newSelectIds.push(e.id)
  704. })
  705. },
  706. false
  707. )
  708. } else if (targetIndex !== -1) {
  709. newSelectIds.push(id)
  710. }
  711. })
  712. newSelectIds.forEach((id: string) => {
  713. // 获取目标数据并从 list 中移除 (成组后不可再次成组, 断言处理)
  714. const item = this.componentList.splice(this.fetchTargetIndex(id), 1)[0] as CreateComponentType
  715. const { x, y, w, h } = item.attr
  716. const { l, t, r, b } = groupAttr
  717. // 左
  718. groupAttr.l = l > x ? x : l
  719. // 上
  720. groupAttr.t = t > y ? y : t
  721. // 宽
  722. groupAttr.r = r < x + w ? x + w : r
  723. // 高
  724. groupAttr.b = b < y + h ? y + h : b
  725. targetList.push(item)
  726. historyList.push(toRaw(item))
  727. })
  728. // 修改原数据之前,先记录
  729. if (isHistory) chartHistoryStore.createGroupHistory(historyList)
  730. // 设置子组件的位置
  731. targetList.forEach((item: CreateComponentType) => {
  732. item.attr.x = item.attr.x - groupAttr.l
  733. item.attr.y = item.attr.y - groupAttr.t
  734. groupClass.groupList.push(item)
  735. })
  736. // 设置 group 属性
  737. groupClass.attr.x = groupAttr.l
  738. groupClass.attr.y = groupAttr.t
  739. groupClass.attr.w = groupAttr.r - groupAttr.l
  740. groupClass.attr.h = groupAttr.b - groupAttr.t
  741. this.addComponentList(groupClass)
  742. this.setTargetSelectChart(groupClass.id)
  743. loadingFinish()
  744. } catch (error) {
  745. console.log(error)
  746. window['$message'].error('创建分组失败,请联系管理员!')
  747. loadingFinish()
  748. }
  749. },
  750. // * 解除分组
  751. setUnGroup(ids?: string[], callBack?: (e: CreateComponentType[]) => void, isHistory = true) {
  752. try {
  753. const selectGroupIdArr = ids || this.getTargetChart.selectId
  754. if (selectGroupIdArr.length !== 1) return
  755. loadingStart()
  756. // 解组
  757. const unGroup = (targetIndex: number) => {
  758. const targetGroup = this.getComponentList[targetIndex] as CreateComponentGroupType
  759. if (!targetGroup.isGroup) return
  760. // 记录数据
  761. if (isHistory) chartHistoryStore.createUnGroupHistory(cloneDeep([targetGroup]))
  762. // 分离组件并还原位置属性
  763. targetGroup.groupList.forEach(item => {
  764. item.attr.x = item.attr.x + targetGroup.attr.x
  765. item.attr.y = item.attr.y + targetGroup.attr.y
  766. if (!callBack) {
  767. this.addComponentList(item)
  768. }
  769. })
  770. this.setTargetSelectChart(targetGroup.id)
  771. // 删除分组
  772. this.removeComponentList(targetGroup.id, false)
  773. if (callBack) {
  774. callBack(targetGroup.groupList)
  775. }
  776. }
  777. const targetIndex = this.fetchTargetIndex(selectGroupIdArr[0])
  778. // 判断目标是否为分组父级
  779. if (targetIndex !== -1) {
  780. unGroup(targetIndex)
  781. }
  782. loadingFinish()
  783. } catch (error) {
  784. console.log(error)
  785. window['$message'].error('解除分组失败,请联系管理员!')
  786. loadingFinish()
  787. }
  788. },
  789. // * 锁定
  790. setLock(status: boolean = true, isHistory: boolean = true) {
  791. try {
  792. // 暂不支持多选
  793. if (this.getTargetChart.selectId.length > 1) return
  794. loadingStart()
  795. const index: number = this.fetchTargetIndex()
  796. if (index !== -1) {
  797. // 更新状态
  798. const targetItem = this.getComponentList[index]
  799. targetItem.status.lock = status
  800. // 历史记录
  801. if (isHistory) {
  802. chartHistoryStore.createLockHistory(
  803. [targetItem],
  804. status ? HistoryActionTypeEnum.LOCK : HistoryActionTypeEnum.UNLOCK
  805. )
  806. }
  807. this.updateComponentList(index, targetItem)
  808. loadingFinish()
  809. return
  810. }
  811. } catch (value) {
  812. loadingError()
  813. }
  814. },
  815. // * 解除锁定
  816. setUnLock(isHistory: boolean = true) {
  817. this.setLock(false, isHistory)
  818. },
  819. // * 隐藏
  820. setHide(status: boolean = true, isHistory: boolean = true) {
  821. try {
  822. // 暂不支持多选
  823. if (this.getTargetChart.selectId.length > 1) return
  824. loadingStart()
  825. const index: number = this.fetchTargetIndex()
  826. if (index !== -1) {
  827. // 更新状态
  828. const targetItem = this.getComponentList[index]
  829. targetItem.status.hide = status
  830. // 历史记录
  831. if (isHistory) {
  832. chartHistoryStore.createHideHistory(
  833. [targetItem],
  834. status ? HistoryActionTypeEnum.HIDE : HistoryActionTypeEnum.SHOW
  835. )
  836. }
  837. this.updateComponentList(index, targetItem)
  838. loadingFinish()
  839. // 取消选择隐藏
  840. if (status) {
  841. const chartEditStore = useChartEditStore()
  842. chartEditStore.setTargetSelectChart(undefined)
  843. }
  844. return
  845. }
  846. } catch (value) {
  847. loadingError()
  848. }
  849. },
  850. // * 显示
  851. setShow(isHistory: boolean = true) {
  852. this.setHide(false, isHistory)
  853. },
  854. // ----------------
  855. // * 设置页面大小
  856. setPageSize(scale: number): void {
  857. this.setPageStyle('height', `${this.editCanvasConfig.height * scale}px`)
  858. this.setPageStyle('width', `${this.editCanvasConfig.width * scale}px`)
  859. },
  860. // * 计算缩放
  861. computedScale() {
  862. if (this.getEditCanvas.editLayoutDom) {
  863. // 现有展示区域
  864. const width = this.getEditCanvas.editLayoutDom.clientWidth - this.getEditCanvas.offset * 2 - 5
  865. const height = this.getEditCanvas.editLayoutDom.clientHeight - this.getEditCanvas.offset * 4
  866. // 用户设定大小
  867. const editCanvasWidth = this.editCanvasConfig.width
  868. const editCanvasHeight = this.editCanvasConfig.height
  869. // 需保持的比例
  870. const baseProportion = parseFloat((editCanvasWidth / editCanvasHeight).toFixed(5))
  871. const currentRate = parseFloat((width / height).toFixed(5))
  872. if (currentRate > baseProportion) {
  873. // 表示更宽
  874. const scaleWidth = parseFloat(((height * baseProportion) / editCanvasWidth).toFixed(5))
  875. this.setScale(scaleWidth > 1 ? 1 : scaleWidth)
  876. } else {
  877. // 表示更高
  878. const scaleHeight = parseFloat((width / baseProportion / editCanvasHeight).toFixed(5))
  879. this.setScale(scaleHeight > 1 ? 1 : scaleHeight)
  880. }
  881. } else {
  882. window['$message'].warning('请先创建画布,再进行缩放')
  883. }
  884. },
  885. // * 监听缩放
  886. listenerScale(): Function {
  887. const resize = debounce(this.computedScale, 200)
  888. // 默认执行一次
  889. resize()
  890. // 开始监听
  891. window.addEventListener('resize', resize)
  892. // 销毁函数
  893. const remove = () => {
  894. window.removeEventListener('resize', resize)
  895. }
  896. return remove
  897. },
  898. /**
  899. * * 设置缩放
  900. * @param scale 0~1 number 缩放比例;
  901. * @param force boolean 强制缩放
  902. */
  903. setScale(scale: number, force = false): void {
  904. if (!this.getEditCanvas.lockScale || force) {
  905. this.setPageSize(scale)
  906. this.getEditCanvas.userScale = scale
  907. this.getEditCanvas.scale = scale
  908. }
  909. }
  910. }
  911. })