Просмотр исходного кода

📚 修改编辑器发布功能,增加文档

快乐的梦鱼 8 часов назад
Родитель
Сommit
eb544cd31e

+ 9 - 1
src/pages/article/data/api/CommonCategoryApi.ts

@@ -62,14 +62,22 @@ export class CommonCategoryApi extends UpdateServerRequestModule<DataModel> {
    * @param json 配置数据
    * @param saveToHistoryId 保存到历史版本id:为0时创建新历史版本;为空不保存到历史版本;为其他值时保存到指定ID历史版本
    * @param name 历史版本名称:为空时使用默认名称
+   * @param autoSelectNewToActive 自动选择新创建的历史版本为活动版本:为true时自动选择新创建的历史版本为活动版本;为false时不自动选择;为空时不自动选择
    * @returns 
    */
-  async editConfig(isDev: boolean, json: ICommonCategoryConfigHistoryItem['data'], name?: string, saveToHistoryId?: number) {
+  async editConfig(
+    isDev: boolean, 
+    json: ICommonCategoryConfigHistoryItem['data'], 
+    name?: string, 
+    saveToHistoryId?: number,
+    autoSelectNewToActive?: boolean,
+  ) {
     return (await this.post(`/app-configuration-edit/${CommonCategoryConfig.getAppConfigId(isDev)}?saveToHistoryId=${saveToHistoryId ?? ''}`, '编辑配置', {
       id: CommonCategoryConfig.getAppConfigId(isDev),
       name,
       data: json,
       accessKey: CommonCategoryConfig.getAccessKey(isDev),
+      autoSelectNewToActive: autoSelectNewToActive ?? false,
     })).data;
   }
   /**

+ 13 - 0
src/pages/article/data/editor/MiniProgramEditor.vue

@@ -10,6 +10,7 @@
         v-model:save-as-modal-visible="saveAsModalVisible"
         v-model:save-as-version-name="saveAsVersionName"
         :save-as-loading="saveAsLoading"
+        @help="helpModalVisible=true"
         @select-default="onSelectDefault"
         @select-history="onSelectHistory"
         @save="saveEditorJson"
@@ -18,6 +19,7 @@
         @set-active="setActiveHistory"
         @delete-history="deleteHistory"
         @export="exportToJsonFile"
+        @sync-to-production="syncToProduction"
       />
 
       <AddPageModal
@@ -32,6 +34,14 @@
         @ok="onConfirmAddPage"
       />
 
+      <a-modal
+        v-model:open="helpModalVisible"
+        title="编辑器使用帮助"
+        width="800px"
+      >
+        <HelpView />
+      </a-modal>
+
       <div class="editor-body">
         <PageListPanel
           :page-list="pageList"
@@ -71,11 +81,13 @@ import PropsPanel from './subpart/PropsPanel.vue';
 import PreviewPanel from './subpart/PreviewPanel.vue';
 import { useEditorConfig } from './composables/useEditorConfig';
 import { usePageList } from './composables/usePageList';
+import HelpView from './subpart/HelpView.vue';
 
 const {
   currentEditorJson,
   selectedPage,
   historyList,
+  helpModalVisible,
   currentConfig,
   currentHistoryId,
   currentShowConfigName,
@@ -86,6 +98,7 @@ const {
   onSelectDefault,
   onSelectHistory,
   saveEditorJson,
+  syncToProduction,
   openSaveAsModal,
   confirmSaveAs,
   setActiveHistory,

+ 28 - 2
src/pages/article/data/editor/composables/useEditorConfig.ts

@@ -1,6 +1,6 @@
 import { computed, ref, watch } from 'vue';
 import { message, Modal } from 'ant-design-vue';
-import { ObjectUtils } from '@imengyu/imengyu-utils';
+import { DateUtils, ObjectUtils } from '@imengyu/imengyu-utils';
 import type { IHomeCommonCategoryDefine } from '../../CommonCategoryDefine';
 import DefaultEditorJson from '../../DefaultCategory.json';
 import CommonCategoryApi, { type ICommonCategoryConfigItem } from '../../api/CommonCategoryApi';
@@ -33,6 +33,9 @@ export function useEditorConfig() {
   const saveAsVersionName = ref('');
   const saveAsLoading = ref(false);
 
+  // 帮助弹窗
+  const helpModalVisible = ref(false);
+
   async function loadEditorJson(selectDefault = false) {
     try {
       currentConfig.value = await CommonCategoryApi.getConfigWithoutCache(isDev.value);
@@ -134,7 +137,7 @@ export function useEditorConfig() {
   function deleteHistory() {
     Modal.confirm({
       title: '删除历史版本',
-      content: '确定要删除该历史版本吗?',
+      content: '确定要删除该历史版本吗?注意:此操作将会删除该历史版本,无法恢复。',
       onOk: async () => {
         await CommonCategoryApi.deleteConfigHistory(isDev.value, currentHistoryId.value);
         message.success('删除历史版本成功');
@@ -154,6 +157,27 @@ export function useEditorConfig() {
     a.click();
   }
 
+  async function syncToProduction() {
+    if (!isDev.value) {
+      message.warning('当前是正式版,无需同步至正式版');
+      return;
+    }
+    Modal.confirm({
+      title: '同步至正式版',
+      content: '确定要同步至正式版吗?注意:此操作将会在正式版创建一个同步后的版本并设置为激活版本。',
+      onOk: async () => {
+        await CommonCategoryApi.editConfig(
+          false, currentEditorJson.value, 
+          `同步正式版-${DateUtils.formatDate(new Date(), 'YYYY-MM-DD HM')}`, 
+          0,
+          true
+        );
+        message.success('同步至正式版成功');
+        await loadEditorJsonHistorys();
+      },
+    });
+  }
+
   async function init() {
     await loadEditorJsonHistorys();
     await loadEditorJson(true);
@@ -168,6 +192,7 @@ export function useEditorConfig() {
     currentEditorJson,
     selectedPage,
     historyList,
+    helpModalVisible,
     currentConfig,
     currentHistoryId,
     currentShowConfigName,
@@ -179,6 +204,7 @@ export function useEditorConfig() {
     loadEditorJsonHistorys,
     onSelectDefault,
     onSelectHistory,
+    syncToProduction,
     saveEditorJson,
     openSaveAsModal,
     confirmSaveAs,

BIN
src/pages/article/data/editor/images/Help1.jpg


BIN
src/pages/article/data/editor/images/Help2.jpg


BIN
src/pages/article/data/editor/images/Help3.jpg


BIN
src/pages/article/data/editor/images/Help4.jpg


BIN
src/pages/article/data/editor/images/Help5.jpg


BIN
src/pages/article/data/editor/images/Help61.jpg


BIN
src/pages/article/data/editor/images/Help62.jpg


BIN
src/pages/article/data/editor/images/Help63.jpg


+ 22 - 10
src/pages/article/data/editor/subpart/EditorToolbar.vue

@@ -3,9 +3,10 @@
     <a-space>
       <span class="toolbar-label">环境:</span>
       <a-select
-        v-model:value="isDevValue"
+        :value="isDevValue"
         style="width: 100px"
         :options="envOptions"
+        @update:value="emit('update:isDev', $event == 'true' ? true : false)"
       />
       <a-dropdown>
         <a-button>
@@ -15,7 +16,7 @@
         <template #overlay>
           <a-menu v-if="historyList.length">
             <a-menu-item @click="emit('select-default')">
-              选择默认配置
+              默认版本
               <a-badge v-if="currentConfig?.activeHistoryId === 0" count="激活" />
             </a-menu-item>
             <a-menu-item
@@ -32,18 +33,19 @@
           </a-menu>
         </template>
       </a-dropdown>
-      <a-dropdown-button type="primary" @click="emit('save')">
+      <a-dropdown-button type="primary" :icon="h(DownOutlined)" @click="emit('save')">
         保存
         <template #overlay>
           <a-menu>
             <a-menu-item @click="emit('open-save-as')">另存为历史版本</a-menu-item>
+            <a-menu-item v-if="isDev" @click="emit('sync-to-production')">同步至正式版</a-menu-item>
           </a-menu>
         </template>
       </a-dropdown-button>
 
       <div>
         <InfoCircleFilled />
-        当前显示配置
+        当前激活版本
         <span>{{ currentShowConfigName }}</span>
       </div>
 
@@ -51,13 +53,21 @@
         {{ currentConfig.activeHistoryId === currentHistoryId ? '已经是激活版本' : '设置为激活版本' }}
       </a-button>
       <a-button v-if="currentConfig && currentHistoryId !== 0" danger @click="emit('delete-history')">
+        <DeleteOutlined />
         删除历史版本
       </a-button>
     </a-space>
-    <a-button @click="emit('export')">
-      导出为JSON文件
-      <DownloadOutlined />
-    </a-button>
+
+    <a-space>
+      <a-button type="primary" @click="emit('help')">
+        帮助
+        <QuestionCircleOutlined />
+      </a-button>
+      <a-button @click="emit('export')">
+        导出为JSON文件
+        <DownloadOutlined />
+      </a-button>
+    </a-space>
 
     <a-modal
       :open="saveAsModalVisible"
@@ -83,8 +93,8 @@
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue';
-import { DownOutlined, DownloadOutlined, InfoCircleFilled } from '@ant-design/icons-vue';
+import { computed, h } from 'vue';
+import { DownOutlined, DownloadOutlined, InfoCircleFilled, DeleteOutlined, QuestionCircleOutlined } from '@ant-design/icons-vue';
 import type { IHistoryListItem } from '../composables/useEditorConfig';
 import type { ICommonCategoryConfigItem } from '../../api/CommonCategoryApi';
 
@@ -105,9 +115,11 @@ const emit = defineEmits<{
   (e: 'save'): void;
   (e: 'open-save-as'): void;
   (e: 'confirm-save-as'): void;
+  (e: 'sync-to-production'): void;
   (e: 'set-active'): void;
   (e: 'delete-history'): void;
   (e: 'export'): void;
+  (e: 'help'): void;
   (e: 'update:isDev', v: boolean): void;
   (e: 'update:saveAsModalVisible', v: boolean): void;
   (e: 'update:saveAsVersionName', v: string): void;

+ 245 - 0
src/pages/article/data/editor/subpart/HelpView.vue

@@ -0,0 +1,245 @@
+<template>
+  <div class="help-view">
+    <p class="help-intro">
+      欢迎使用闽南文化小程序配套专题编辑器!本编辑器用于编辑闽南文化小程序配套专题的内容,
+      可实现闽南文化小程序的界面栏目动态编辑和配置。
+    </p>
+
+    <a-collapse v-model:activeKey="activeKeys" class="help-collapse" :bordered="false">
+
+      <a-collapse-panel key="basic" header="基础界面">
+        <img src="../images/Help1.jpg" alt="基础界面" />
+        <p>基础界面包括:</p>
+        <ul>
+          <li><strong>顶部工具栏</strong>:用于管理配置版本(开发版/正式版)、加载/保存、历史版本、导出及帮助。</li>
+          <li><strong>左侧页面列表</strong>:选择要编辑的页面,可添加、删除、克隆、上移下移页面。</li>
+          <li><strong>中间属性编辑区</strong>:编辑当前选中页面的属性和内容配置。</li>
+          <li><strong>右侧预览区</strong>:实时预览小程序显示效果,支持点击刷新。</li>
+        </ul>
+      </a-collapse-panel>
+
+      <a-collapse-panel key="toolbar" header="顶部工具栏(版本管理 / 加载 / 保存 / 历史版本 / 导出 / 帮助)">
+        <img src="../images/Help2.jpg" class="full" alt="版本管理工具栏" />
+        <ul>
+          <li><strong>环境切换</strong>:选择「开发版」或「正式版」。开发版用于调试(显示在体验版小程序),正式版为线上配置。</li>
+          <li><strong>加载</strong>:下拉选择「默认版本」或历史版本进行加载。「激活」表示当前小程序使用的版本。</li>
+          <li>
+            <strong>保存</strong>:保存当前编辑内容到当前选中的版本。保存将立即生效。如果当前保存的是激活的版本,则将立即更新小程序显示。
+            <b style="color: #f5222d;">注意:请记得随时保存,防止浏览器关闭或者页面切换导致可能的数据丢失。</b>
+          </li>
+          <li><strong>另存为历史版本</strong>:将当前配置另存为新历史版本,需填写版本名称。</li>
+          <li><strong>同步至正式版</strong>(开发版下可用):将当前配置同步到正式版并设为激活。</li>
+          <li><strong>设置为激活版本</strong>:将当前加载的版本设为小程序实际使用的配置。</li>
+          <li><strong>删除历史版本</strong>:删除当前加载的历史版本(无法恢复)。</li>
+          <li><strong>导出为 JSON 文件</strong>:将当前配置导出为本地 JSON 文件备份。</li>
+          <li><strong>帮助</strong>:打开本帮助文档。</li>
+        </ul>
+        <div class="sub-section">
+          <div class="sub-section-title">版本管理</div>
+          <p>
+            环境分为开发版和正式版,<b>建议在开发版进行调试,确认无误后再同步至正式版,以免影响线上使用。</b>
+          </p>
+          <p>
+            版本管理用于记录历史版本,方便回退和对比。在加载按钮下拉选择「默认版本」或历史版本进行加载。
+            <br />「激活」表示当前小程序使用的版本。
+            <br />点击保存按钮会保存当前配置到当前选中的版本;点击另存为历史版本按钮会保存当前配置到新历史版本,需填写版本名称。
+            <br />点击「同步至正式版」按钮可以将开发版当前配置同步到正式版,会创建一个新版本记录并自动设为激活。
+            点击「设置为激活版本」按钮将当前加载的版本设为小程序实际使用的配置。
+          </p>
+        </div>
+      </a-collapse-panel>
+
+      <a-collapse-panel key="page-list" header="左侧页面列表">
+        <div class="sub-section">
+          <img src="../images/Help3.jpg" alt="页面列表" />
+        </div>
+        <p>点击页面可选中进行编辑。列表项右侧操作按钮:</p>
+        <ul>
+          <li><strong>上移 / 下移</strong>:调整页面在配置中的顺序。</li>
+          <li><strong>克隆</strong>:复制当前页面为新页面(自动生成新 key)。</li>
+          <li><strong>删除</strong>:删除该页面(需确认)。</li>
+        </ul>
+        <p>点击「+」可添加新页面,支持三种模板:</p>
+        <ul>
+          <li><strong>Home</strong>:首页模板,含 Banner、按钮、栏目、底部 Tab 等。</li>
+          <li><strong>CommonList</strong>:通用列表页模板,支持 Tab、搜索、筛选等。</li>
+          <li><strong>Details</strong>:详情页模板,支持简介、图片、视频、音频、列表等 Tab。</li>
+        </ul>
+        <p>添加时需填写 <strong>key</strong>(唯一标识,如 home、list_1)和 <strong>title</strong>(页面标题)。</p>
+      </a-collapse-panel>
+
+      <a-collapse-panel key="props-editor" header="中间属性编辑区">
+        <p>该区域用于编辑页面属性,包括页面标题、页面数据、栏目排版等。</p>
+        <p>根据选中页面类型显示对应编辑器,有以下几种页面类型:</p>
+        <div class="sub-section">
+          <div class="sub-section-title">Home 首页</div>
+          <img src="../images/Help61.jpg" alt="Home 首页" />
+          <ul>
+            <li><strong>首页标题 / 副标题</strong>:顶部展示文案。</li>
+            <li><strong>Banner 图</strong>:首页头部横幅图 URL,支持上传。</li>
+            <li><strong>首页按钮 (homeButtons)</strong>:可配置多个按钮(标题、图标、跳转链接、样式、尺寸)。</li>
+            <li><strong>首页栏目 (categorys)</strong>:嵌套栏目结构,可配置栏目标题、类型、数据、跳转等。</li>
+            <li><strong>首页 Tab 控制 (tabs)</strong>:底部 Tab 栏,可配置:标签标题、类型(首页/内嵌列表/用户页)、图标、选中图标、可见性、凸起样式;当类型为「内嵌列表页」时需选择内置页面及头部图片等。</li>
+          </ul>
+        </div>
+        <div class="sub-section">
+          <div class="sub-section-title">CommonList 列表页</div>
+          <img src="../images/Help62.jpg" alt="CommonList 列表页" />
+          <ul>
+            <li><strong>显示 Tab / 搜索 / 总数</strong>:是否显示对应 UI。</li>
+            <li><strong>列表项类型 / 详情页</strong>:列表展示样式和详情跳转地址。</li>
+            <li><strong>子页面 (tabs)</strong>:列表内 Tab,类型包括:通用列表、跳转页面、子栏目。可上移下移、复制、删除;列表类型可配置数据接口、下拉筛选、前缀子栏目等。</li>
+          </ul>
+        </div>
+        <div class="sub-section">
+          <div class="sub-section-title">Details 详情页</div>
+          <img src="../images/Help63.jpg" alt="Details 详情页" />
+          <ul>
+            <li>配置详情页头部、简介块及 Tab(简介、图片、视频、音频、列表等)。</li>
+          </ul>
+        </div>
+        <a-alert icon message="编辑时可使用 刷新 按钮同步预览区显示。" type="info" />
+      </a-collapse-panel>
+
+      <a-collapse-panel key="preview" header="右侧预览区">
+        <p>模拟小程序 9:16 比例的显示效果。修改配置后点击「刷新」可更新预览。详情页编辑时可输入测试详情 ID 进行预览。</p>
+      
+        <a-alert message="左侧预览区域仅为测试显示,切勿点击跳转,可能会导致跳转后未保存而丢失数据。" type="warning" />
+      </a-collapse-panel>
+
+      <a-collapse-panel key="link-path" header="跳转路径配置">
+        <div class="sub-section">
+          <img src="../images/Help4.jpg" alt="跳转路径配置" />
+        </div>
+        <p>按钮链接、详情页、更多页等使用「跳转路径编辑器」时,可设置:</p>
+        <ul>
+          <li><strong>动态列表页面 / 动态详情页面</strong>:选择本配置中的页面。</li>
+          <li><strong>程序内置页面</strong>:选择小程序内置路由。</li>
+          <li><strong>自定义输入</strong>:手动输入完整路径和参数。</li>
+        </ul>
+      </a-collapse-panel>
+
+      <a-collapse-panel key="data-source" header="数据源配置">
+        <div class="sub-section">
+          <img src="../images/Help5.jpg" alt="数据源配置" />
+        </div>
+        <p>数据源配置用于配置栏目、列表、Tab 等的数据来源,在「动态数据」或「数据接口」编辑器中设置。支持以下五种类型:</p>
+
+        <div class="sub-section">
+          <div class="sub-section-title">commonContent - 通用内容</div>
+          <p>通过模型和栏目 ID 拉取后台通用内容列表。</p>
+          <ul>
+            <li><strong>modelId</strong>:模型 ID,必填。</li>
+            <li><strong>mainBodyColumnId</strong>:栏目 ID,支持单个或多个(数组)。</li>
+            <li><strong>typeId</strong>:分类类型 ID,可选。</li>
+            <li><strong>otherParams</strong>:其他请求参数。</li>
+          </ul>
+        </div>
+
+        <div class="sub-section">
+          <div class="sub-section-title">serializedApi - 预制接口</div>
+          <p>使用程序内已封装的序列化接口,通过 <strong>name</strong> 指定接口名称。可选配置 mainBodyColumnId、otherParams。</p>
+        </div>
+
+        <div class="sub-section">
+          <div class="sub-section-title">detailContent - 详情内容</div>
+          <p>拉取单条详情内容,用于详情类展示。</p>
+          <ul>
+            <li><strong>id</strong>:内容 ID。</li>
+            <li><strong>modelId</strong>:模型 ID。</li>
+            <li><strong>otherParams</strong>:其他参数。</li>
+          </ul>
+        </div>
+
+        <div class="sub-section">
+          <div class="sub-section-title">request - 自定义请求</div>
+          <p>通过 HTTP 请求直接访问指定接口。</p>
+          <ul>
+            <li><strong>method</strong>:请求方法(GET、POST、PUT、DELETE 等)。</li>
+            <li><strong>url</strong>:请求地址。</li>
+            <li><strong>querys</strong>:URL 查询参数。</li>
+            <li><strong>otherParams</strong>:请求体或其他参数。</li>
+          </ul>
+        </div>
+
+        <div class="sub-section">
+          <div class="sub-section-title">parentKey - 父级数据</div>
+          <p>在详情页嵌套栏目中,从父级数据对象的指定 <strong>key</strong> 取值。适用于子栏目复用父级返回的某一字段数据。</p>
+        </div>
+
+        <p>配置「下拉选择定义」后,下拉筛选条件会作为参数一并传入数据源;「数据处理显示」可对返回数据进行转换后再展示。</p>
+      </a-collapse-panel>
+    </a-collapse>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+
+const activeKeys = ref<string[]>(['']);
+</script>
+
+<style lang="scss" scoped>
+.help-view {
+  padding: 20px;
+  font-size: 14px;
+  line-height: 1.6;
+
+  .help-intro {
+    margin: 0 0 16px;
+  }
+
+  .sub-section {
+    margin-top: 16px;
+    padding-top: 12px;
+    border-top: 1px dashed #eee;
+
+    &:first-child {
+      margin-top: 0;
+      padding-top: 0;
+      border-top: none;
+    }
+
+    img:not(.full) {
+      margin-bottom: 12px;
+      max-width: 200px;
+      margin: 14px auto;
+    }
+  }
+  .sub-section-title {
+    font-weight: 600;
+    font-size: 15px;
+    color: #333;
+    margin-bottom: 8px;
+
+    &::before {
+      content: '';
+      display: inline-block;
+      width: 10px;
+      height: 10px;
+      border-radius: 50%;
+      background-color: #00aeff;  
+      vertical-align: baseline;
+      margin-right: 8px;
+    }
+  }
+
+  p {
+    margin: 0 0 12px;
+  }
+  ul {
+    margin: 0 0 12px;
+    padding-left: 20px;
+  }
+  li {
+    margin-bottom: 6px;
+  }
+  img {
+    max-width: 100%;
+    height: auto;
+    display: block;
+    margin-bottom: 12px;
+    border-radius: 4px;
+  }
+}
+</style>