decorate.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <template>
  2. <DiyEditor
  3. v-if="formData && !formLoading"
  4. v-model="currentFormData!.property"
  5. :title="templateItems[selectedTemplateItem].name"
  6. :libs="libs"
  7. :show-page-config="selectedTemplateItem !== 0"
  8. :show-tab-bar="selectedTemplateItem === 0"
  9. :show-navigation-bar="selectedTemplateItem !== 0"
  10. :preview-url="previewUrl"
  11. @save="submitForm"
  12. @reset="handleEditorReset"
  13. >
  14. <template #toolBarLeft>
  15. <el-radio-group
  16. v-model="selectedTemplateItem"
  17. class="h-full!"
  18. @change="handleTemplateItemChange"
  19. >
  20. <el-tooltip v-for="(item, index) in templateItems" :key="index" :content="item.name">
  21. <el-radio-button :label="index">
  22. <Icon :icon="item.icon" :size="24" />
  23. </el-radio-button>
  24. </el-tooltip>
  25. </el-radio-group>
  26. </template>
  27. </DiyEditor>
  28. </template>
  29. <script setup lang="ts">
  30. // TODO @疯狂:要不要建个 decorate 目录,然后挪进去,改成 index.vue,这样可以更明确看到是个独立界面哈,更好找
  31. import * as DiyTemplateApi from '@/api/mall/promotion/diy/template'
  32. import * as DiyPageApi from '@/api/mall/promotion/diy/page'
  33. import { useTagsViewStore } from '@/store/modules/tagsView'
  34. import { DiyComponentLibrary, PAGE_LIBS } from '@/components/DiyEditor/util' // 商城的 DIY 组件,在 DiyEditor 目录下
  35. import { toNumber } from 'lodash-es'
  36. /** 装修模板表单 */
  37. defineOptions({ name: 'DiyTemplateDecorate' })
  38. // 左上角工具栏操作按钮
  39. const selectedTemplateItem = ref(0)
  40. const templateItems = reactive([
  41. { name: '基础设置', icon: 'ep:iphone' },
  42. { name: '首页', icon: 'ep:home-filled' },
  43. { name: '我的', icon: 'ep:user-filled' }
  44. ])
  45. const message = useMessage() // 消息弹窗
  46. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  47. const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>()
  48. const formRef = ref() // 表单 Ref
  49. // 当前编辑的属性
  50. const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>()
  51. // 商城 H5 预览地址
  52. const previewUrl = ref('')
  53. // 获取详情
  54. const getPageDetail = async (id: any) => {
  55. formLoading.value = true
  56. try {
  57. formData.value = await DiyTemplateApi.getDiyTemplateProperty(id)
  58. currentFormData.value = formData.value
  59. // 拼接手机预览链接
  60. const domain = import.meta.env.VITE_MALL_H5_DOMAIN
  61. previewUrl.value = `${domain}/#/pages/index/index?templateId=${formData.value.id}`
  62. } finally {
  63. formLoading.value = false
  64. }
  65. }
  66. // 模板组件库
  67. const templateLibs = [] as DiyComponentLibrary[]
  68. // 当前组件库
  69. const libs = ref<DiyComponentLibrary[]>(templateLibs)
  70. // 模板选项切换
  71. const handleTemplateItemChange = () => {
  72. // 编辑模板
  73. if (selectedTemplateItem.value === 0) {
  74. libs.value = templateLibs
  75. currentFormData.value = formData.value
  76. return
  77. }
  78. // 编辑页面
  79. libs.value = PAGE_LIBS
  80. currentFormData.value = formData.value!.pages.find(
  81. (page: DiyPageApi.DiyPageVO) => page.name === templateItems[selectedTemplateItem.value].name
  82. )
  83. }
  84. // 提交表单
  85. const submitForm = async () => {
  86. // 校验表单
  87. if (!formRef) return
  88. // 提交请求
  89. formLoading.value = true
  90. try {
  91. if (selectedTemplateItem.value === 0) {
  92. // 提交模板属性
  93. await DiyTemplateApi.updateDiyTemplateProperty(unref(formData)!)
  94. } else {
  95. // 提交页面属性
  96. await DiyPageApi.updateDiyPageProperty(unref(currentFormData)!)
  97. }
  98. message.success('保存成功')
  99. } finally {
  100. formLoading.value = false
  101. }
  102. }
  103. // 重置表单
  104. const resetForm = () => {
  105. formData.value = {
  106. id: undefined,
  107. name: '',
  108. used: false,
  109. usedTime: undefined,
  110. remark: '',
  111. previewPicUrls: [],
  112. property: '',
  113. pages: []
  114. } as DiyTemplateApi.DiyTemplatePropertyVO
  115. formRef.value?.resetFields()
  116. }
  117. // 重置时记录当前编辑的页面
  118. const handleEditorReset = () => storePageIndex()
  119. //#region 无感刷新
  120. // 记录标识
  121. const DIY_PAGE_INDEX_KEY = 'diy_page_index'
  122. // 1. 记录
  123. const storePageIndex = () =>
  124. sessionStorage.setItem(DIY_PAGE_INDEX_KEY, `${selectedTemplateItem.value}`)
  125. // 2. 恢复
  126. const recoverPageIndex = () => {
  127. // 恢复重置前的页面,默认是第一个页面
  128. const pageIndex = toNumber(sessionStorage.getItem(DIY_PAGE_INDEX_KEY)) || 0
  129. // 移除标记
  130. sessionStorage.removeItem(DIY_PAGE_INDEX_KEY)
  131. // 切换页面
  132. if (pageIndex !== selectedTemplateItem.value) {
  133. selectedTemplateItem.value = pageIndex
  134. handleTemplateItemChange()
  135. }
  136. }
  137. //#endregion
  138. /** 初始化 **/
  139. const { currentRoute } = useRouter() // 路由
  140. const { delView } = useTagsViewStore() // 视图操作
  141. onMounted(async () => {
  142. resetForm()
  143. if (!currentRoute.value.params.id) {
  144. message.warning('参数错误,页面编号不能为空!')
  145. delView(unref(currentRoute))
  146. return
  147. }
  148. // 查询详情
  149. await getPageDetail(currentRoute.value.params.id)
  150. // 恢复重置前的页面
  151. recoverPageIndex()
  152. })
  153. </script>