|
|
@@ -1,495 +1,144 @@
|
|
|
<template>
|
|
|
<a-config-provider :locale="zhCN">
|
|
|
<div class="miniprogram-editor">
|
|
|
- <div class="editor-toolbar">
|
|
|
- <a-space>
|
|
|
- <a-dropdown>
|
|
|
- <a-button>
|
|
|
- 加载
|
|
|
- <DownOutlined />
|
|
|
- </a-button>
|
|
|
- <template #overlay>
|
|
|
- <a-menu v-if="historyList.length">
|
|
|
- <a-menu-item @click="onSelectDefault">
|
|
|
- 选择默认配置
|
|
|
- <a-badge v-if="currentConfig?.activeHistoryId === 0" count="激活" />
|
|
|
- </a-menu-item>
|
|
|
- <a-menu-item
|
|
|
- v-for="(item, index) in historyList"
|
|
|
- :key="index"
|
|
|
- @click="onSelectHistory(item.id!)"
|
|
|
- >
|
|
|
- {{ item.name }}
|
|
|
- <a-badge v-if="item.id === currentConfig?.activeHistoryId" count="激活" />
|
|
|
- </a-menu-item>
|
|
|
- </a-menu>
|
|
|
- <a-menu v-else>
|
|
|
- <a-menu-item disabled>暂无历史版本</a-menu-item>
|
|
|
- </a-menu>
|
|
|
- </template>
|
|
|
- </a-dropdown>
|
|
|
- <a-dropdown-button type="primary" @click="saveEditorJson">
|
|
|
- 保存
|
|
|
- <template #overlay>
|
|
|
- <a-menu>
|
|
|
- <a-menu-item @click="openSaveAsModal">另存为历史版本</a-menu-item>
|
|
|
- </a-menu>
|
|
|
- </template>
|
|
|
- </a-dropdown-button>
|
|
|
-
|
|
|
- <div>
|
|
|
- <InfoCircleFilled />
|
|
|
- 当前显示配置:
|
|
|
- <span>{{ currentShowConfigName }}</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <a-button v-if="currentConfig" @click="setActiveHistory">
|
|
|
- {{ currentConfig.activeHistoryId === currentHistoryId ? '已经是激活版本' : '设置为激活版本' }}
|
|
|
- </a-button>
|
|
|
- <a-button v-if="currentConfig && currentHistoryId !== 0" danger @click="deleteHistory">删除历史版本</a-button>
|
|
|
- </a-space>
|
|
|
- <a-button @click="exportToJsonFile">
|
|
|
- 导出为JSON文件
|
|
|
- <DownloadOutlined />
|
|
|
- </a-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 另存为历史版本弹框 -->
|
|
|
- <a-modal
|
|
|
- v-model:open="saveAsModalVisible"
|
|
|
- title="另存为历史版本"
|
|
|
- ok-text="保存"
|
|
|
- cancel-text="取消"
|
|
|
- :confirm-loading="saveAsLoading"
|
|
|
- @ok="confirmSaveAs"
|
|
|
- >
|
|
|
- <a-form layout="vertical" class="save-as-form">
|
|
|
- <a-form-item label="版本名称">
|
|
|
- <a-input
|
|
|
- v-model:value="saveAsVersionName"
|
|
|
- placeholder="请输入版本名称"
|
|
|
- allow-clear
|
|
|
- />
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-modal>
|
|
|
-
|
|
|
- <!-- 添加页面弹框 -->
|
|
|
- <a-modal
|
|
|
- v-model:open="addPageModalVisible"
|
|
|
- title="添加页面"
|
|
|
- ok-text="添加"
|
|
|
- cancel-text="取消"
|
|
|
- :confirm-loading="addPageLoading"
|
|
|
- @ok="confirmAddPage"
|
|
|
- >
|
|
|
- <a-form layout="vertical" class="add-page-form">
|
|
|
- <a-form-item label="key(页面唯一标识)" required>
|
|
|
- <a-input
|
|
|
- v-model:value="addPageKey"
|
|
|
- placeholder="如 home、list_1"
|
|
|
- allow-clear
|
|
|
- />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="title(页面标题)" required>
|
|
|
- <a-input
|
|
|
- v-model:value="addPageTitle"
|
|
|
- placeholder="如 首页、列表页"
|
|
|
- allow-clear
|
|
|
- />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item v-if="addPageTemplate" label="模板">
|
|
|
- <span>{{ addPageTemplate }}</span>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-modal>
|
|
|
+ <EditorToolbar
|
|
|
+ :history-list="historyList"
|
|
|
+ :current-config="currentConfig"
|
|
|
+ :current-history-id="currentHistoryId"
|
|
|
+ :current-show-config-name="currentShowConfigName"
|
|
|
+ v-model:save-as-modal-visible="saveAsModalVisible"
|
|
|
+ v-model:save-as-version-name="saveAsVersionName"
|
|
|
+ :save-as-loading="saveAsLoading"
|
|
|
+ @select-default="onSelectDefault"
|
|
|
+ @select-history="onSelectHistory"
|
|
|
+ @save="saveEditorJson"
|
|
|
+ @open-save-as="openSaveAsModal"
|
|
|
+ @confirm-save-as="confirmSaveAs"
|
|
|
+ @set-active="setActiveHistory"
|
|
|
+ @delete-history="deleteHistory"
|
|
|
+ @export="exportToJsonFile"
|
|
|
+ />
|
|
|
+
|
|
|
+ <AddPageModal
|
|
|
+ :open="addPageModalVisible"
|
|
|
+ :model-key="addPageKey"
|
|
|
+ :model-title="addPageTitle"
|
|
|
+ :template="addPageTemplate"
|
|
|
+ :loading="addPageLoading"
|
|
|
+ @update:open="setAddPageModalVisible"
|
|
|
+ @update:model-key="setAddPageKey"
|
|
|
+ @update:model-title="setAddPageTitle"
|
|
|
+ @ok="onConfirmAddPage"
|
|
|
+ />
|
|
|
|
|
|
<div class="editor-body">
|
|
|
- <!-- 左一:页面列表 -->
|
|
|
- <div class="panel panel-pages">
|
|
|
- <div class="panel-title panel-title-with-action">
|
|
|
- <span>页面列表</span>
|
|
|
- <a-dropdown size="small">
|
|
|
- <PlusOutlined />
|
|
|
- <template #overlay>
|
|
|
- <a-menu @click="onAddPageMenuClick">
|
|
|
- <a-menu-item key="Home">Home</a-menu-item>
|
|
|
- <a-menu-item key="CommonList">CommonList</a-menu-item>
|
|
|
- <a-menu-item key="Details">Details</a-menu-item>
|
|
|
- </a-menu>
|
|
|
- </template>
|
|
|
- </a-dropdown>
|
|
|
- </div>
|
|
|
- <a-list
|
|
|
- :data-source="currentEditorJson?.page ?? []"
|
|
|
- size="small"
|
|
|
- class="page-list"
|
|
|
- >
|
|
|
- <template #renderItem="{ item }">
|
|
|
- <a-list-item
|
|
|
- :class="{ 'page-item-active': selectedPage?.name === item.name }"
|
|
|
- class="page-list-item"
|
|
|
- @click="selectedPage = item"
|
|
|
- >
|
|
|
- <a-list-item-meta>
|
|
|
- <template #title>{{ item.title || item.name }}</template>
|
|
|
- <template #description>{{ item.name }} · {{ item.content?.type }}</template>
|
|
|
- </a-list-item-meta>
|
|
|
- <a-button
|
|
|
- type="text"
|
|
|
- danger
|
|
|
- size="small"
|
|
|
- class="page-item-delete"
|
|
|
- @click.stop="confirmDeletePage(item)"
|
|
|
- >
|
|
|
- <DeleteOutlined />
|
|
|
- </a-button>
|
|
|
- </a-list-item>
|
|
|
- </template>
|
|
|
- </a-list>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 左二:属性编辑器 -->
|
|
|
- <div class="panel panel-props">
|
|
|
- <div class="panel-title panel-title-with-action">
|
|
|
- 属性编辑
|
|
|
- <a-button type="primary" size="small" @click="($refs.previewRef as any)?.refresh()">刷新</a-button>
|
|
|
- </div>
|
|
|
- <div v-if="!selectedPage" class="panel-empty">请选择页面</div>
|
|
|
- <PropsEditorTree
|
|
|
- v-else
|
|
|
- :page="selectedPage"
|
|
|
- v-model:testDetailId="testDetailId"
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 中间:预览 -->
|
|
|
- <div class="panel panel-preview">
|
|
|
- <div class="panel-title">小程序预览</div>
|
|
|
- <div class="preview-wrap">
|
|
|
- <EditorPreview
|
|
|
- ref="previewRef"
|
|
|
- :editor-json="currentEditorJson"
|
|
|
- :selected-page="selectedPage"
|
|
|
- :test-detail-id="testDetailId"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <PageListPanel
|
|
|
+ :page-list="pageList"
|
|
|
+ :selected-page="selectedPage"
|
|
|
+ @update:selected-page="setSelectedPage"
|
|
|
+ @move-up="movePageUp"
|
|
|
+ @move-down="movePageDown"
|
|
|
+ @duplicate="duplicatePage"
|
|
|
+ @delete="confirmDeletePage"
|
|
|
+ @add-page="onAddPageMenuClick"
|
|
|
+ />
|
|
|
+
|
|
|
+ <PropsPanel
|
|
|
+ :selected-page="selectedPage"
|
|
|
+ v-model:test-detail-id="testDetailId"
|
|
|
+ @refresh="previewPanelRef?.refresh()"
|
|
|
+ />
|
|
|
+
|
|
|
+ <PreviewPanel
|
|
|
+ ref="previewPanelRef"
|
|
|
+ :editor-json="currentEditorJson"
|
|
|
+ :selected-page="selectedPage"
|
|
|
+ :test-detail-id="testDetailId"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</a-config-provider>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { computed, onMounted, provide, ref } from 'vue';
|
|
|
-import { ObjectUtils } from '@imengyu/imengyu-utils';
|
|
|
-import { DownOutlined, DownloadOutlined, InfoCircleFilled, PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
|
|
-import { message, Modal } from 'ant-design-vue';
|
|
|
-import type { IHomeCommonCategoryDefine, IHomeCommonCategoryDetailDefine, IHomeCommonCategoryListDefine, IHomeCommonCategoryHomeDefine } from '../CommonCategoryDefine';
|
|
|
-import DefaultEditorJson from '../DefaultCategory.json';
|
|
|
-import PropsEditorTree from './subpart/PropsEditorTree.vue';
|
|
|
-import EditorPreview from './subpart/EditorPreview.vue';
|
|
|
+import { onMounted, provide, ref } from 'vue';
|
|
|
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
|
|
-import CommonCategoryApi, { type ICommonCategoryConfigItem } from '../api/CommonCategoryApi';
|
|
|
-
|
|
|
-/** 历史版本列表项(接口返回的 items 元素) */
|
|
|
-interface IHistoryListItem {
|
|
|
- id?: number;
|
|
|
- data?: IHomeCommonCategoryDefine;
|
|
|
- createTime?: string;
|
|
|
- [key: string]: any;
|
|
|
+import EditorToolbar from './subpart/EditorToolbar.vue';
|
|
|
+import AddPageModal from './subpart/AddPageModal.vue';
|
|
|
+import PageListPanel from './subpart/PageListPanel.vue';
|
|
|
+import PropsPanel from './subpart/PropsPanel.vue';
|
|
|
+import PreviewPanel from './subpart/PreviewPanel.vue';
|
|
|
+import { useEditorConfig } from './composables/useEditorConfig';
|
|
|
+import { usePageList } from './composables/usePageList';
|
|
|
+
|
|
|
+const {
|
|
|
+ currentEditorJson,
|
|
|
+ selectedPage,
|
|
|
+ historyList,
|
|
|
+ currentConfig,
|
|
|
+ currentHistoryId,
|
|
|
+ currentShowConfigName,
|
|
|
+ saveAsModalVisible,
|
|
|
+ saveAsVersionName,
|
|
|
+ saveAsLoading,
|
|
|
+ onSelectDefault,
|
|
|
+ onSelectHistory,
|
|
|
+ saveEditorJson,
|
|
|
+ openSaveAsModal,
|
|
|
+ confirmSaveAs,
|
|
|
+ setActiveHistory,
|
|
|
+ deleteHistory,
|
|
|
+ exportToJsonFile,
|
|
|
+ init,
|
|
|
+} = useEditorConfig();
|
|
|
+
|
|
|
+const testDetailId = ref(0);
|
|
|
+
|
|
|
+const {
|
|
|
+ pageList,
|
|
|
+ movePageUp,
|
|
|
+ movePageDown,
|
|
|
+ duplicatePage,
|
|
|
+ confirmDeletePage,
|
|
|
+ addPageModalVisible,
|
|
|
+ addPageTemplate,
|
|
|
+ addPageKey,
|
|
|
+ addPageTitle,
|
|
|
+ addPageLoading,
|
|
|
+ onAddPageMenuClick,
|
|
|
+ confirmAddPage,
|
|
|
+} = usePageList(currentEditorJson, selectedPage);
|
|
|
+
|
|
|
+const previewPanelRef = ref<InstanceType<typeof PreviewPanel> | null>(null);
|
|
|
+
|
|
|
+function setSelectedPage(page: (typeof selectedPage.value) | null) {
|
|
|
+ selectedPage.value = page;
|
|
|
+}
|
|
|
+function setAddPageModalVisible(v: boolean) {
|
|
|
+ addPageModalVisible.value = v;
|
|
|
+}
|
|
|
+function setAddPageKey(v: string) {
|
|
|
+ addPageKey.value = v;
|
|
|
+}
|
|
|
+function setAddPageTitle(v: string) {
|
|
|
+ addPageTitle.value = v;
|
|
|
}
|
|
|
|
|
|
-const currentEditorJson = ref<IHomeCommonCategoryDefine>(DefaultEditorJson as IHomeCommonCategoryDefine);
|
|
|
-const selectedPage = ref<(IHomeCommonCategoryDefine['page'][0]) | null>(null);
|
|
|
-const pageList = computed(() => currentEditorJson.value.page || []);
|
|
|
-const historyList = ref<IHistoryListItem[]>([]);
|
|
|
-const currentConfig = ref<ICommonCategoryConfigItem>();
|
|
|
-const currentHistoryId = ref<number>(0);
|
|
|
-const currentShowConfigName = computed(() => {
|
|
|
- if (currentHistoryId.value === 0)
|
|
|
- return '默认配置';
|
|
|
- else
|
|
|
- return historyList.value.find(item => item.id === currentHistoryId.value)?.name ?? '未知';
|
|
|
-});
|
|
|
-
|
|
|
-const testDetailId = ref<number>(0);
|
|
|
-
|
|
|
-const saveAsModalVisible = ref(false);
|
|
|
-const saveAsVersionName = ref('');
|
|
|
-const saveAsLoading = ref(false);
|
|
|
-
|
|
|
-const addPageModalVisible = ref(false);
|
|
|
-const addPageTemplate = ref<'Home' | 'CommonList' | 'Details' | null>(null);
|
|
|
-const addPageKey = ref('');
|
|
|
-const addPageTitle = ref('');
|
|
|
-const addPageLoading = ref(false);
|
|
|
-
|
|
|
provide('pageList', pageList);
|
|
|
+provide('editorPreviewMark', true);
|
|
|
|
|
|
-/** 生成新页面唯一 name */
|
|
|
-function getUniquePageName(prefix: string): string {
|
|
|
- const pages = currentEditorJson.value?.page ?? [];
|
|
|
- const names = new Set(pages.map(p => p.name));
|
|
|
- let name = prefix;
|
|
|
- let n = 1;
|
|
|
- while (names.has(name)) {
|
|
|
- name = `${prefix}_${n}`;
|
|
|
- n++;
|
|
|
- }
|
|
|
- return name;
|
|
|
-}
|
|
|
-
|
|
|
-/** Home 模板 */
|
|
|
-function createHomePageTemplate(): IHomeCommonCategoryHomeDefine {
|
|
|
- return {
|
|
|
- type: 'Home',
|
|
|
- props: {
|
|
|
- title: '首页',
|
|
|
- subTitle: '',
|
|
|
- homeBanner: '',
|
|
|
- homeButtons: [],
|
|
|
- categorys: [],
|
|
|
- },
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-/** CommonList 模板 */
|
|
|
-function createCommonListPageTemplate(): IHomeCommonCategoryListDefine {
|
|
|
- return {
|
|
|
- type: 'CommonList',
|
|
|
- props: {
|
|
|
- showTab: true,
|
|
|
- showSearch: true,
|
|
|
- showTotal: true,
|
|
|
- tabs: [],
|
|
|
- },
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-/** Details 模板 */
|
|
|
-function createDetailPageTemplate(): IHomeCommonCategoryDetailDefine {
|
|
|
- return {
|
|
|
- type: 'Details',
|
|
|
- props: {
|
|
|
- showHead: true,
|
|
|
- introBlockDescs: [],
|
|
|
- introBlocks: [],
|
|
|
- tabs: [],
|
|
|
- },
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-function onAddPageMenuClick(e: { key: string }) {
|
|
|
- const template = e.key as 'Home' | 'CommonList' | 'Details';
|
|
|
- addPageTemplate.value = template;
|
|
|
- const prefixMap = { Home: 'home', CommonList: 'list', Details: 'detail' } as const;
|
|
|
- const titleMap = { Home: '首页', CommonList: '列表页', Details: '详情页' } as const;
|
|
|
- addPageKey.value = getUniquePageName(prefixMap[template] ?? 'page');
|
|
|
- addPageTitle.value = titleMap[template] ?? '页面';
|
|
|
- addPageModalVisible.value = true;
|
|
|
-}
|
|
|
-
|
|
|
-function confirmAddPage(): Promise<void> | void {
|
|
|
- const key = addPageKey.value?.trim();
|
|
|
- const title = addPageTitle.value?.trim();
|
|
|
- if (!key) {
|
|
|
- message.warning('请输入 key');
|
|
|
- return Promise.reject();
|
|
|
- }
|
|
|
- if (!title) {
|
|
|
- message.warning('请输入 title');
|
|
|
- return Promise.reject();
|
|
|
- }
|
|
|
- const pages = currentEditorJson.value?.page ?? [];
|
|
|
- const exists = pages.some(p => p.name === key);
|
|
|
- if (exists) {
|
|
|
- message.warning(`key「${key}」已存在,请使用其他 key`);
|
|
|
- return Promise.reject();
|
|
|
- }
|
|
|
- const template = addPageTemplate.value;
|
|
|
- if (!template) return Promise.reject();
|
|
|
- addPageLoading.value = true;
|
|
|
- let content: IHomeCommonCategoryHomeDefine | IHomeCommonCategoryListDefine | IHomeCommonCategoryDetailDefine;
|
|
|
- switch (template) {
|
|
|
- case 'Home':
|
|
|
- content = createHomePageTemplate();
|
|
|
- break;
|
|
|
- case 'CommonList':
|
|
|
- content = createCommonListPageTemplate();
|
|
|
- break;
|
|
|
- case 'Details':
|
|
|
- content = createDetailPageTemplate();
|
|
|
- break;
|
|
|
- default:
|
|
|
- message.warning(`不支持的模板:${template}`);
|
|
|
- return Promise.reject();
|
|
|
- }
|
|
|
- currentEditorJson.value = {
|
|
|
- ...currentEditorJson.value,
|
|
|
- page: [...pages, { name: key, title, content }],
|
|
|
- };
|
|
|
- const added = currentEditorJson.value.page[currentEditorJson.value.page.length - 1];
|
|
|
- selectedPage.value = added;
|
|
|
- addPageModalVisible.value = false;
|
|
|
- addPageLoading.value = false;
|
|
|
- message.success(`已添加页面 ${title} (${key})`);
|
|
|
-}
|
|
|
-
|
|
|
-function confirmDeletePage(page: IHomeCommonCategoryDefine['page'][0]) {
|
|
|
- Modal.confirm({
|
|
|
- title: '确认删除',
|
|
|
- content: `确定要删除页面「${page.title || page.name}」吗?删除后不可恢复。`,
|
|
|
- okText: '删除',
|
|
|
- okType: 'danger',
|
|
|
- cancelText: '取消',
|
|
|
- onOk() {
|
|
|
- const pages = currentEditorJson.value?.page ?? [];
|
|
|
- const index = pages.findIndex(p => p.name === page.name);
|
|
|
- if (index === -1) return;
|
|
|
- const next = pages.filter(p => p.name !== page.name);
|
|
|
- currentEditorJson.value = { ...currentEditorJson.value, page: next };
|
|
|
- if (selectedPage.value?.name === page.name)
|
|
|
- selectedPage.value = next[0] ?? null;
|
|
|
- message.success('已删除页面');
|
|
|
- },
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-async function loadEditorJson(selectDefault = false) {
|
|
|
- try {
|
|
|
- //加载基础配置
|
|
|
- currentConfig.value = await CommonCategoryApi.getConfigWithoutCache();
|
|
|
- if (!currentConfig.value)
|
|
|
- throw new Error('加载基础配置失败');
|
|
|
- if (selectDefault)
|
|
|
- currentHistoryId.value = currentConfig.value.activeHistoryId;
|
|
|
- //根据activeHistoryId选择当前激活的历史版本
|
|
|
- if (currentHistoryId.value > 0) {
|
|
|
- const activeHistory = historyList.value.find(item => item.id === currentHistoryId.value);
|
|
|
- if (activeHistory)
|
|
|
- currentEditorJson.value = ObjectUtils.clone(activeHistory.data!) as IHomeCommonCategoryDefine;
|
|
|
- else
|
|
|
- throw new Error('当前激活的历史版本不存在');
|
|
|
- } else {
|
|
|
- currentEditorJson.value = ObjectUtils.clone(currentConfig.value.data) as IHomeCommonCategoryDefine;
|
|
|
- }
|
|
|
- message.success('加载分类成功');
|
|
|
- } catch (error) {
|
|
|
- Modal.error({
|
|
|
- title: '加载分类失败',
|
|
|
- content: '' + error,
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-async function loadEditorJsonHistorys() {
|
|
|
- try {
|
|
|
- const res = await CommonCategoryApi.getConfigHistoryList(1, 10);
|
|
|
- const items = res?.items ?? [];
|
|
|
- historyList.value = Array.isArray(items) ? items : [];
|
|
|
- } catch (error) {
|
|
|
- historyList.value = [];
|
|
|
- Modal.error({
|
|
|
- title: '加载历史版本列表失败',
|
|
|
- content: '' + error,
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function onSelectDefault() {
|
|
|
- currentHistoryId.value = 0;
|
|
|
- loadEditorJson(true);
|
|
|
-}
|
|
|
-function onSelectHistory(id: number) {
|
|
|
- currentHistoryId.value = id;
|
|
|
- loadEditorJson(false);
|
|
|
-}
|
|
|
-
|
|
|
-/** 默认保存:根据 currentHistoryId 保存到默认配置或指定历史版本 */
|
|
|
-async function saveEditorJson() {
|
|
|
- try {
|
|
|
- const saveToHistoryId = currentHistoryId.value === 0 ? undefined : currentHistoryId.value;
|
|
|
- await CommonCategoryApi.editConfig(
|
|
|
- currentEditorJson.value,
|
|
|
- undefined,
|
|
|
- saveToHistoryId
|
|
|
- );
|
|
|
- message.success('保存成功');
|
|
|
- } catch (error) {
|
|
|
- Modal.error({
|
|
|
- title: '保存失败',
|
|
|
- content: '' + error,
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function openSaveAsModal() {
|
|
|
- saveAsVersionName.value = '';
|
|
|
- saveAsModalVisible.value = true;
|
|
|
-}
|
|
|
-
|
|
|
-async function confirmSaveAs() {
|
|
|
- const name = saveAsVersionName.value?.trim();
|
|
|
- if (!name) {
|
|
|
- message.warning('请输入版本名称');
|
|
|
- return;
|
|
|
- }
|
|
|
- saveAsLoading.value = true;
|
|
|
- try {
|
|
|
- await CommonCategoryApi.editConfig(
|
|
|
- currentEditorJson.value,
|
|
|
- name,
|
|
|
- 0
|
|
|
- );
|
|
|
- message.success('已另存为历史版本');
|
|
|
- saveAsModalVisible.value = false;
|
|
|
- await loadEditorJsonHistorys();
|
|
|
- } catch (error) {
|
|
|
- Modal.error({
|
|
|
- title: '另存为失败',
|
|
|
- content: '' + error,
|
|
|
- });
|
|
|
- } finally {
|
|
|
- saveAsLoading.value = false;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-async function setActiveHistory() {
|
|
|
- await CommonCategoryApi.setActiveConfigHistory(currentHistoryId.value);
|
|
|
- message.success('设置为激活版本成功');
|
|
|
-}
|
|
|
-async function deleteHistory() {
|
|
|
- Modal.confirm({
|
|
|
- title: '删除历史版本',
|
|
|
- content: '确定要删除该历史版本吗?',
|
|
|
- onOk: async () => {
|
|
|
- await CommonCategoryApi.deleteConfigHistory(currentHistoryId.value);
|
|
|
- message.success('删除历史版本成功');
|
|
|
- await loadEditorJsonHistorys();
|
|
|
- await loadEditorJson(true);
|
|
|
- },
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-function exportToJsonFile() {
|
|
|
- const json = JSON.stringify(currentEditorJson.value);
|
|
|
- const blob = new Blob([json], { type: 'application/json' });
|
|
|
- const url = URL.createObjectURL(blob);
|
|
|
- const a = document.createElement('a');
|
|
|
- a.href = url;
|
|
|
- a.download = 'editor.json';
|
|
|
- a.click();
|
|
|
+function onConfirmAddPage() {
|
|
|
+ return confirmAddPage();
|
|
|
}
|
|
|
|
|
|
onMounted(async () => {
|
|
|
- await loadEditorJsonHistorys();
|
|
|
- await loadEditorJson(true);
|
|
|
- window.addEventListener('beforeunload', function(e) {
|
|
|
- const message = '你还有未保存的内容,确定要离开吗?';
|
|
|
- e.returnValue = message;
|
|
|
- return message;
|
|
|
+ await init();
|
|
|
+ window.addEventListener('beforeunload', (e) => {
|
|
|
+ const msg = '你还有未保存的内容,确定要离开吗?';
|
|
|
+ e.returnValue = msg;
|
|
|
+ return msg;
|
|
|
});
|
|
|
-})
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
@@ -499,14 +148,6 @@ onMounted(async () => {
|
|
|
flex-direction: column;
|
|
|
background: #f5f5f5;
|
|
|
}
|
|
|
-.editor-toolbar {
|
|
|
- padding: 8px 16px;
|
|
|
- background: #fff;
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
.editor-body {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
@@ -523,73 +164,4 @@ onMounted(async () => {
|
|
|
.panel:last-of-type {
|
|
|
border-right: none;
|
|
|
}
|
|
|
-.panel-title {
|
|
|
- padding: 8px 12px;
|
|
|
- font-weight: 600;
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.panel-title-with-action {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
-.panel-pages {
|
|
|
- width: 220px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.panel-props {
|
|
|
- width: 720px;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.panel-preview {
|
|
|
- flex: 1;
|
|
|
- min-width: 0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 16px;
|
|
|
- overflow: auto;
|
|
|
-}
|
|
|
-.panel-empty {
|
|
|
- padding: 16px;
|
|
|
- color: #999;
|
|
|
- font-size: 12px;
|
|
|
-}
|
|
|
-.page-list {
|
|
|
- flex: 1;
|
|
|
- overflow: auto;
|
|
|
-}
|
|
|
-.page-list :deep(.ant-list-item) {
|
|
|
- cursor: pointer;
|
|
|
- padding: 8px 12px;
|
|
|
-}
|
|
|
-.page-list-item :deep(.ant-list-item-meta) {
|
|
|
- flex: 1;
|
|
|
- min-width: 0;
|
|
|
-}
|
|
|
-.page-list-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
-}
|
|
|
-.page-item-delete {
|
|
|
- flex-shrink: 0;
|
|
|
- padding: 0 4px;
|
|
|
-}
|
|
|
-.page-item-active {
|
|
|
- background: #e6f7ff;
|
|
|
-}
|
|
|
-.preview-wrap {
|
|
|
- width: 100%;
|
|
|
- max-width: 450px;
|
|
|
- aspect-ratio: 9 / 16;
|
|
|
- overflow: auto;
|
|
|
- background: #fff;
|
|
|
- border-radius: 8px;
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
- margin: 0 auto;
|
|
|
-}
|
|
|
</style>
|