Explorar el Código

酒店二维码生成 以及绑定房间号功能

徐滕 hace 1 semana
padre
commit
03bf2029e2
Se han modificado 100 ficheros con 11991 adiciones y 9997 borrados
  1. 112 0
      forge-admin-ui/src/api/hotel.js
  2. 543 0
      forge-admin-ui/src/views/hotel/qrcode.vue
  3. 158 0
      forge-admin-ui/src/views/hotel/room.vue
  4. 66 0
      forge-admin-ui/src/views/hotel/roomType.vue
  5. 3 0
      forge-h5-ui/package.json
  6. 9776 0
      forge-h5-ui/pnpm-lock.yaml
  7. 31 0
      forge-h5-ui/src/api/index.js
  8. 14 0
      forge-h5-ui/src/pages.json
  9. 473 0
      forge-h5-ui/src/pages/hotel/qr-scanner.vue
  10. 792 0
      forge-h5-ui/src/pages/hotel/scan-bind.vue
  11. 20 1
      forge-h5-ui/src/pages/index/index.vue
  12. 3 0
      forge-h5-ui/vite.config.js
  13. 0 97
      forge-server/db/backup/V1.0.10__dedupe_lowcode_app_menu.sql
  14. 0 148
      forge-server/db/backup/V1.0.11__reparent_lowcode_menus.sql
  15. 0 58
      forge-server/db/backup/V1.0.12__add_file_storage_type_dict.sql
  16. 0 85
      forge-server/db/backup/V1.0.13__add_common_business_dicts.sql
  17. 0 98
      forge-server/db/backup/V1.0.14__add_flow_business_dicts.sql
  18. 0 56
      forge-server/db/backup/V1.0.15__add_data_module_dicts.sql
  19. 0 50
      forge-server/db/backup/V1.0.16__add_ai_lowcode_dicts.sql
  20. 0 101
      forge-server/db/backup/V1.0.17__add_system_module_dicts.sql
  21. 0 120
      forge-server/db/backup/V1.0.18__add_flow_approval_action_control.sql
  22. 0 146
      forge-server/db/backup/V1.0.19__unify_lowcode_app_codegen_menus.sql
  23. 0 64
      forge-server/db/backup/V1.0.1__add_dashboard_version_and_record_audit.sql
  24. 0 147
      forge-server/db/backup/V1.0.20__add_lowcode_system_generator_agent.sql
  25. 0 27
      forge-server/db/backup/V1.0.21__tune_lowcode_agent_domain_reuse.sql
  26. 0 27
      forge-server/db/backup/V1.0.22__tune_lowcode_agent_single_domain_prefix.sql
  27. 0 81
      forge-server/db/backup/V1.0.23__add_common_crud_async_export.sql
  28. 0 164
      forge-server/db/backup/V1.0.24__add_excel_import_config_fields.sql
  29. 0 110
      forge-server/db/backup/V1.0.25__split_excel_import_export_config.sql
  30. 0 125
      forge-server/db/backup/V1.0.26__add_business_app_platform_tables.sql
  31. 0 142
      forge-server/db/backup/V1.0.27__add_business_app_platform_dicts_menus.sql
  32. 0 122
      forge-server/db/backup/V1.0.28__seed_crm_business_suite.sql
  33. 0 183
      forge-server/db/backup/V1.0.29__fix_business_app_center_menu_routes.sql
  34. 0 83
      forge-server/db/backup/V1.0.2__add_ai_prompt_template_library.sql
  35. 0 14
      forge-server/db/backup/V1.0.30__fix_app_center_dynamic_route_components.sql
  36. 0 116
      forge-server/db/backup/V1.0.31__normalize_app_center_menu_directory.sql
  37. 0 89
      forge-server/db/backup/V1.0.32__seed_crm_customer_runtime_link.sql
  38. 0 144
      forge-server/db/backup/V1.0.33__seed_crm_other_models.sql
  39. 0 135
      forge-server/db/backup/V1.0.34__normalize_lowcode_developer_menus.sql
  40. 0 127
      forge-server/db/backup/V1.0.35__normalize_crm_lowcode_model_schema.sql
  41. 0 213
      forge-server/db/backup/V1.0.36__add_crm_runtime_tables.sql
  42. 0 55
      forge-server/db/backup/V1.0.37__seed_crm_runtime_crud_configs.sql
  43. 0 43
      forge-server/db/backup/V1.0.38__normalize_crm_business_object_runtime.sql
  44. 0 15
      forge-server/db/backup/V1.0.39__fix_crm_runtime_config_status.sql
  45. 0 20
      forge-server/db/backup/V1.0.3__add_custom_query_scheme.sql
  46. 0 208
      forge-server/db/backup/V1.0.40__add_business_object_designer.sql
  47. 0 219
      forge-server/db/backup/V1.0.41__add_business_object_designer_menu_permissions.sql
  48. 0 26
      forge-server/db/backup/V1.0.42__fix_crm_business_relation_field_direction.sql
  49. 0 390
      forge-server/db/backup/V1.0.43__align_crm_follow_record_table_with_model.sql
  50. 0 95
      forge-server/db/backup/V1.0.44__add_crm_contact_customer_reference_relation.sql
  51. 0 16
      forge-server/db/backup/V1.0.45__add_business_object_design_version_designer_snapshot.sql
  52. 0 175
      forge-server/db/backup/V1.0.46__add_business_trigger_and_message_channel.sql
  53. 0 164
      forge-server/db/backup/V1.0.47__add_business_document_flow_closure.sql
  54. 0 30
      forge-server/db/backup/V1.0.48__add_sys_role_type.sql
  55. 0 29
      forge-server/db/backup/V1.0.49__add_business_flow_callback_permission.sql
  56. 0 285
      forge-server/db/backup/V1.0.4__add_visual_lowcode_crud_builder.sql
  57. 0 28
      forge-server/db/backup/V1.0.50__add_business_stats_and_action_permissions.sql
  58. 0 225
      forge-server/db/backup/V1.0.51__seed_crm_opportunity_document_flow.sql
  59. 0 277
      forge-server/db/backup/V1.0.52__seed_leave_document_flow_demo.sql
  60. 0 15
      forge-server/db/backup/V1.0.53__align_flow_template_logic_delete_column.sql
  61. 0 30
      forge-server/db/backup/V1.0.54__patch_opportunity_flow_dept_manager_mapping.sql
  62. 0 41
      forge-server/db/backup/V1.0.55__add_user_tenant_membership.sql
  63. 0 376
      forge-server/db/backup/V1.0.56__harden_tenant_isolation_boundaries.sql
  64. 0 300
      forge-server/db/backup/V1.0.57__add_flow_form_runtime_entry.sql
  65. 0 36
      forge-server/db/backup/V1.0.58__remove_standalone_flow_entry_menus.sql
  66. 0 467
      forge-server/db/backup/V1.0.59__normalize_pc_menu_modules.sql
  67. 0 2
      forge-server/db/backup/V1.0.5__add_sys_org_code.sql
  68. 0 44
      forge-server/db/backup/V1.0.60__add_workbench_home_menu.sql
  69. 0 216
      forge-server/db/backup/V1.0.61__restore_app_center_menu_permissions.sql
  70. 0 17
      forge-server/db/backup/V1.0.62__add_client_captcha_override.sql
  71. 0 25
      forge-server/db/backup/V1.0.63__allow_string_sys_org_type.sql
  72. 0 60
      forge-server/db/backup/V1.0.64__fix_org_datascope_and_role_visibility.sql
  73. 0 97
      forge-server/db/backup/V1.0.65__harden_user_type_permission_boundaries.sql
  74. 0 15
      forge-server/db/backup/V1.0.66__allow_normal_user_org_user_role_management.sql
  75. 0 40
      forge-server/db/backup/V1.0.67__harden_sensitive_data_and_upload_controls.sql
  76. 0 18
      forge-server/db/backup/V1.0.68__add_formula_config_to_gen_table_column.sql
  77. 0 203
      forge-server/db/backup/V1.0.69__add_formula_observability_and_function_market.sql
  78. 0 2
      forge-server/db/backup/V1.0.6__add_sys_org_code_parent.sql
  79. 0 168
      forge-server/db/backup/V1.0.70__consolidate_app_codegen_mode.sql
  80. 0 304
      forge-server/db/backup/V1.0.71__restore_app_center_runtime_route_permissions.sql
  81. 0 21
      forge-server/db/backup/V1.0.72__require_file_storage_allowed_types.sql
  82. 0 28
      forge-server/db/backup/V1.0.73__add_flow_model_designer_type.sql
  83. 0 175
      forge-server/db/backup/V1.0.74__add_flow_task_overdue_reminder.sql
  84. 0 530
      forge-server/db/backup/V1.0.75__add_lowcode_runtime_datasource_fields.sql
  85. 0 17
      forge-server/db/backup/V1.0.76__add_business_datasource_routing_config.sql
  86. 0 175
      forge-server/db/backup/V1.0.77__add_business_datasource_debug_menu.sql
  87. 0 15
      forge-server/db/backup/V1.0.78__add_lowcode_app_page_summary_index.sql
  88. 0 65
      forge-server/db/backup/V1.0.79__optimize_lowcode_runtime_document_queries.sql
  89. 0 341
      forge-server/db/backup/V1.0.7__add_lowcode_business_domain.sql
  90. 0 37
      forge-server/db/backup/V1.0.80__add_business_suite_hierarchy.sql
  91. 0 211
      forge-server/db/backup/V1.0.81__add_sample_purchase_order_flow_test.sql
  92. 0 100
      forge-server/db/backup/V1.0.82__seed_sample_purchase_order_flow_binding.sql
  93. 0 79
      forge-server/db/backup/V1.0.83__seed_sample_purchase_order_app_center_entry.sql
  94. 0 19
      forge-server/db/backup/V1.0.84__extend_sample_purchase_order_form_asset_fields.sql
  95. 0 15
      forge-server/db/backup/V1.0.85__fix_sample_purchase_order_designer_route.sql
  96. 0 112
      forge-server/db/backup/V1.0.86__add_code_rule_generator.sql
  97. 0 71
      forge-server/db/backup/V1.0.87__add_business_action_execution_log.sql
  98. 0 109
      forge-server/db/backup/V1.0.88__add_business_quantity_ledger.sql
  99. 0 28
      forge-server/db/backup/V1.0.89__add_business_quantity_query_permission.sql
  100. 0 0
      forge-server/db/backup/V1.0.8__fix_lowcode_domain_workspace_route.sql

+ 112 - 0
forge-admin-ui/src/api/hotel.js

@@ -0,0 +1,112 @@
+import { request } from '@/utils'
+
+// ==================== 二维码管理 ====================
+
+/** 分页查询二维码 */
+export function getQrCodePage(params) {
+  return request.get('/hotel/qrcode/page', { params })
+}
+
+/** 查询二维码详情 */
+export function getQrCodeDetail(id) {
+  return request.get(`/hotel/qrcode/${id}`)
+}
+
+/** 批量生成二维码 */
+export function batchGenerateQrCode(data) {
+  return request.post('/hotel/qrcode/batch-generate', data)
+}
+
+/** 绑定房间 */
+export function bindQrCode(id, data) {
+  return request.post(`/hotel/qrcode/${id}/bind`, data)
+}
+
+/** 重新绑定房间 */
+export function rebindQrCode(id, data) {
+  return request.post(`/hotel/qrcode/${id}/rebind`, data)
+}
+
+/** 解绑房间 */
+export function unbindQrCode(id) {
+  return request.post(`/hotel/qrcode/${id}/unbind`)
+}
+
+/** 更新二维码状态 */
+export function updateQrCodeStatus(id, status) {
+  return request.put(`/hotel/qrcode/${id}/status`, null, { params: { status } })
+}
+
+/** 查询绑定日志 */
+export function getQrCodeBindLogs(id) {
+  return request.get(`/hotel/qrcode/${id}/bind-logs`)
+}
+
+/** 批量删除二维码 */
+export function batchRemoveQrCode(ids) {
+  return request.post('/hotel/qrcode/batch-remove', ids)
+}
+
+/** 批量下载二维码ZIP(返回blob) */
+export function batchDownloadQrCode(ids) {
+  return request.post('/hotel/qrcode/batch-download', ids, { responseType: 'blob' })
+}
+
+// ==================== 房间管理 ====================
+
+/** 分页查询房间 */
+export function getRoomPage(params) {
+  return request.get('/hotel/room/page', { params })
+}
+
+/** 查询全部房间(下拉用) */
+export function getRoomListAll() {
+  return request.get('/hotel/room/list-all')
+}
+
+/** 查询房间详情 */
+export function getRoomDetail(id) {
+  return request.get(`/hotel/room/${id}`)
+}
+
+/** 新增房间 */
+export function createRoom(data) {
+  return request.post('/hotel/room', data)
+}
+
+/** 修改房间 */
+export function updateRoom(data) {
+  return request.put('/hotel/room', data)
+}
+
+/** 删除房间 */
+export function deleteRoom(id) {
+  return request.post(`/hotel/room/remove/${id}`)
+}
+
+// ==================== 房型管理 ====================
+
+/** 查询房型列表 */
+export function getRoomTypeList() {
+  return request.get('/hotel/room-type/list')
+}
+
+/** 查询房型详情 */
+export function getRoomTypeDetail(id) {
+  return request.get(`/hotel/room-type/${id}`)
+}
+
+/** 新增房型 */
+export function createRoomType(data) {
+  return request.post('/hotel/room-type', data)
+}
+
+/** 修改房型 */
+export function updateRoomType(data) {
+  return request.put('/hotel/room-type', data)
+}
+
+/** 删除房型 */
+export function deleteRoomType(id) {
+  return request.post(`/hotel/room-type/remove/${id}`)
+}

+ 543 - 0
forge-admin-ui/src/views/hotel/qrcode.vue

@@ -0,0 +1,543 @@
+<template>
+  <div class="hotel-qrcode-page">
+    <AiCrudPage
+      ref="crudRef"
+      :api-config="{
+        list: 'get@/hotel/qrcode/page',
+      }"
+      :search-schema="searchSchema"
+      :columns="tableColumns"
+      row-key="id"
+      :hide-add="true"
+      :hide-batch-delete="true"
+      :show-export="false"
+      :show-import="false"
+      :hide-selection="false"
+      @selection-change="handleSelectionChange"
+      @load-list-success="handleLoadSuccess"
+    >
+      <!-- 工具栏:批量操作按钮 -->
+      <template #toolbar-start>
+        <NButton type="primary" size="small" @click="showBatchGenerate = true">
+          <template #icon>
+            <NIcon><Add /></NIcon>
+          </template>
+          批量生成
+        </NButton>
+        <NButton type="error" size="small" :disabled="selectedIds.length === 0" @click="handleBatchRemove">
+          <template #icon>
+            <NIcon><TrashOutline /></NIcon>
+          </template>
+          批量删除{{ selectedIds.length > 0 ? ` (${selectedIds.length})` : '' }}
+        </NButton>
+        <NButton type="success" size="small" :disabled="selectedIds.length === 0" @click="handleBatchDownload">
+          <template #icon>
+            <NIcon><DownloadOutline /></NIcon>
+          </template>
+          批量下载ZIP{{ selectedIds.length > 0 ? ` (${selectedIds.length})` : '' }}
+        </NButton>
+      </template>
+    </AiCrudPage>
+
+    <!-- 批量生成弹窗 -->
+    <NModal v-model:show="showBatchGenerate" preset="dialog" title="批量生成二维码" positive-text="生成" negative-text="取消" @positive-click="handleBatchGenerate">
+      <NForm>
+        <NFormItem label="生成数量">
+          <NSelect v-model:value="batchCount" :options="batchCountOptions" />
+        </NFormItem>
+      </NForm>
+    </NModal>
+
+    <!-- 绑定/重绑弹窗 -->
+    <NModal v-model:show="showBindModal" preset="dialog" :title="bindAction === 'bind' ? '绑定房间' : '重新绑定房间'" positive-text="确定" negative-text="取消" @positive-click="handleBindConfirm">
+      <NForm>
+        <NFormItem label="选择房间">
+          <NSelect
+            v-model:value="bindRoomId"
+            filterable
+            placeholder="请选择房间"
+            :options="roomOptions"
+          />
+        </NFormItem>
+        <NFormItem label="备注">
+          <NInput v-model:value="bindRemark" type="textarea" placeholder="可选" />
+        </NFormItem>
+      </NForm>
+    </NModal>
+
+    <!-- 绑定日志弹窗 -->
+    <NModal v-model:show="showBindLog" preset="card" title="绑定日志" style="width: 700px;">
+      <NDataTable :columns="bindLogColumns" :data="bindLogData" :loading="bindLogLoading" size="small" />
+    </NModal>
+
+    <!-- 二维码预览弹窗 -->
+    <NModal v-model:show="showQrPreview" preset="card" title="二维码详情" style="width: 480px;">
+      <div class="qr-preview-container">
+        <div class="qr-image-wrapper">
+          <NImage :src="previewQrSrc" width="280" height="280" object-fit="contain" />
+        </div>
+        <div class="qr-url-section">
+          <div class="qr-url-label">二维码链接:</div>
+          <div class="qr-url-row">
+            <NInput :value="previewQrUrl" readonly size="small" />
+            <NButton text type="primary" @click="handleCopyUrl" class="copy-btn">
+              <template #icon>
+                <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
+                  <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
+                  <path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
+                </svg>
+              </template>
+              复制
+            </NButton>
+          </div>
+        </div>
+        <div class="qr-download-section">
+          <NButton type="primary" @click="handleDownloadQr">
+            <template #icon>
+              <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2">
+                <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/>
+                <polyline points="7 10 12 15 17 10"/>
+                <line x1="12" y1="15" x2="12" y2="3"/>
+              </svg>
+            </template>
+            下载二维码
+          </NButton>
+        </div>
+      </div>
+    </NModal>
+  </div>
+</template>
+
+<script setup>
+import { computed, h, ref } from 'vue'
+import { Add, TrashOutline, DownloadOutline } from '@vicons/ionicons5'
+import { NButton, NDataTable, NForm, NFormItem, NIcon, NImage, NInput, NModal, NSelect, NTag } from 'naive-ui'
+import { AiCrudPage } from '@/components/ai-form'
+import DictTag from '@/components/DictTag.vue'
+import { useDict } from '@/composables/useDict'
+import {
+  batchDownloadQrCode,
+  batchGenerateQrCode,
+  batchRemoveQrCode,
+  bindQrCode,
+  getQrCodeBindLogs,
+  getRoomListAll,
+  rebindQrCode,
+  unbindQrCode,
+  updateQrCodeStatus,
+} from '@/api/hotel'
+
+defineOptions({ name: 'HotelQrCode' })
+
+const crudRef = ref(null)
+const { dict } = useDict('sys_normal_disable')
+
+// ==================== 搜索配置 ====================
+const statusOptions = computed(() => dict.value.sys_normal_disable || [])
+const boundOptions = [
+  { label: '已绑定', value: true },
+  { label: '未绑定', value: false },
+]
+
+const searchSchema = computed(() => [
+  /*{
+    field: 'shortCode',
+    label: '短码',
+    type: 'input',
+    props: { placeholder: '请输入短码' },
+  },*/
+  {
+    field: 'batchNo',
+    label: '批次号',
+    type: 'input',
+    props: { placeholder: '请输入批次号' },
+  },
+  {
+    field: 'status',
+    label: '状态',
+    type: 'select',
+    props: { placeholder: '请选择状态', options: statusOptions.value },
+  },
+  {
+    field: 'bound',
+    label: '绑定状态',
+    type: 'select',
+    props: { placeholder: '请选择绑定状态', options: boundOptions },
+  },
+])
+
+// ==================== 表格列配置 ====================
+const tableColumns = computed(() => [
+  {
+    prop: 'qrCodeImage',
+    label: '二维码',
+    width: 80,
+    render: row => row.qrCodeImage
+      ? h(NImage, { src: `data:image/png;base64,${row.qrCodeImage}`, width: 48, height: 48, previewDisabled: true, style: 'cursor: pointer;', onClick: () => handlePreviewQr(row) })
+      : '-',
+  },
+  { prop: 'batchNo', label: '批次号', width: 160 },
+  {
+    prop: 'status',
+    label: '状态',
+    width: 80,
+    render: row => h(DictTag, { dictType: 'sys_normal_disable', value: row.status, size: 'small' }),
+  },
+  {
+    prop: 'bound',
+    label: '绑定状态',
+    width: 90,
+    render: row => h(NTag, { type: row.bound ? 'info' : 'default', size: 'small' }, { default: () => row.bound ? '已绑定' : '未绑定' }),
+  },
+  { prop: 'roomNo', label: '房间号', width: 100 },
+  { prop: 'bindUserName', label: '绑定人', width: 100 },
+  { prop: 'bindTime', label: '绑定时间', width: 172 },
+  { prop: 'unbindUserName', label: '解绑人', width: 100 },
+  { prop: 'unbindTime', label: '解绑时间', width: 172 },
+  { prop: 'createTime', label: '创建时间', width: 172 },
+  {
+    prop: 'action',
+    label: '操作',
+    width: 280,
+    fixed: 'right',
+    render(row) {
+      const buttons = []
+      // 绑定/重绑
+      if (!row.bound) {
+        buttons.push(h(NButton, { text: true, type: 'primary', size: 'small', onClick: () => handleBind(row) }, { default: () => '绑定' }))
+      } else {
+        buttons.push(h(NButton, { text: true, type: 'primary', size: 'small', onClick: () => handleRebind(row) }, { default: () => '重绑' }))
+      }
+      // 解绑
+      if (row.bound) {
+        buttons.push(h(NButton, { text: true, type: 'warning', size: 'small', onClick: () => handleUnbind(row) }, { default: () => '解绑' }))
+      }
+      // 启用/禁用
+      buttons.push(h(NButton, { text: true, type: row.status === '0' ? 'warning' : 'success', size: 'small', onClick: () => handleToggleStatus(row) }, { default: () => row.status === '0' ? '禁用' : '启用' }))
+      // 日志
+      buttons.push(h(NButton, { text: true, type: 'info', size: 'small', onClick: () => handleViewLogs(row) }, { default: () => '日志' }))
+      // 下载
+      buttons.push(h(NButton, { text: true, type: 'primary', size: 'small', onClick: () => handleSingleDownload(row) }, { default: () => '下载' }))
+      return h('div', { class: 'table-action-column' }, buttons.map((btn, i) => [
+        i > 0 ? h('span', { class: 'table-action-divider' }, ' | ') : null,
+        btn,
+      ]).flat())
+    },
+  },
+])
+
+// ==================== 数据加载回调 ====================
+function handleLoadSuccess() {
+  // 列表加载成功后的回调(可用于额外处理)
+}
+
+// ==================== 选中管理 ====================
+const selectedIds = ref([])
+
+function handleSelectionChange(rows) {
+  selectedIds.value = (rows || []).map(r => r.id)
+}
+
+// ==================== 批量生成 ====================
+const showBatchGenerate = ref(false)
+const batchCount = ref(10)
+const batchCountOptions = [
+  { label: '10个', value: 10 },
+  { label: '50个', value: 50 },
+  { label: '100个', value: 100 },
+  { label: '200个', value: 200 },
+]
+
+async function handleBatchGenerate() {
+  try {
+    const res = await batchGenerateQrCode({ count: batchCount.value })
+    if (res.code === 200) {
+      window.$message.success(`成功生成 ${res.data.length} 个二维码`)
+      crudRef.value?.handleRefresh()
+    }
+  } catch {
+    window.$message.error('生成失败')
+  }
+}
+
+// ==================== 绑定/重绑 ====================
+const showBindModal = ref(false)
+const bindAction = ref('bind')
+const bindQrId = ref(null)
+const bindRoomId = ref(null)
+const bindRemark = ref('')
+const roomOptions = ref([])
+
+async function loadRoomOptions() {
+  const res = await getRoomListAll()
+  if (res.code === 200) {
+    roomOptions.value = (res.data || []).map(r => ({
+      label: `${r.roomNo}${r.roomTypeName ? ` (${r.roomTypeName})` : ''}`,
+      value: r.id,
+    }))
+  }
+}
+
+function handleBind(row) {
+  bindAction.value = 'bind'
+  bindQrId.value = row.id
+  bindRoomId.value = null
+  bindRemark.value = ''
+  loadRoomOptions()
+  showBindModal.value = true
+}
+
+function handleRebind(row) {
+  bindAction.value = 'rebind'
+  bindQrId.value = row.id
+  bindRoomId.value = row.roomId
+  bindRemark.value = ''
+  loadRoomOptions()
+  showBindModal.value = true
+}
+
+async function handleBindConfirm() {
+  if (!bindRoomId.value) {
+    window.$message.warning('请选择房间')
+    return false
+  }
+  try {
+    const fn = bindAction.value === 'bind' ? bindQrCode : rebindQrCode
+    const res = await fn(bindQrId.value, { roomId: bindRoomId.value, remark: bindRemark.value })
+    if (res.code === 200) {
+      window.$message.success('操作成功')
+      crudRef.value?.handleRefresh()
+    }
+  } catch {
+    window.$message.error('操作失败')
+  }
+}
+
+function handleUnbind(row) {
+  window.$dialog.warning({
+    title: '确认解绑',
+    content: `确定要解绑二维码 ${row.shortCode} 与房间 ${row.roomNo} 的关联吗?`,
+    positiveText: '确定',
+    negativeText: '取消',
+    onPositiveClick: async () => {
+      try {
+        const res = await unbindQrCode(row.id)
+        if (res.code === 200) {
+          window.$message.success('解绑成功')
+          crudRef.value?.handleRefresh()
+        }
+      } catch {
+        window.$message.error('解绑失败')
+      }
+    },
+  })
+}
+
+async function handleToggleStatus(row) {
+  const newStatus = row.status === '0' ? '1' : '0'
+  try {
+    const res = await updateQrCodeStatus(row.id, newStatus)
+    if (res.code === 200) {
+      window.$message.success(newStatus === '0' ? '已启用' : '已禁用')
+      crudRef.value?.handleRefresh()
+    }
+  } catch {
+    window.$message.error('操作失败')
+  }
+}
+
+// ==================== 绑定日志 ====================
+const showBindLog = ref(false)
+const bindLogData = ref([])
+const bindLogLoading = ref(false)
+const bindLogColumns = [
+  { title: '操作类型', key: 'actionType', width: 80 },
+  { title: '房间号', key: 'roomNo', width: 100 },
+  { title: '操作人', key: 'operatorName', width: 120 },
+  { title: '操作时间', key: 'operateTime', width: 172 },
+  { title: '备注', key: 'remark' },
+]
+
+async function handleViewLogs(row) {
+  showBindLog.value = true
+  bindLogLoading.value = true
+  try {
+    const res = await getQrCodeBindLogs(row.id)
+    if (res.code === 200) {
+      bindLogData.value = res.data || []
+    }
+  } finally {
+    bindLogLoading.value = false
+  }
+}
+
+// ==================== 二维码预览 ====================
+const previewQrSrc = ref('')
+const previewQrUrl = ref('')
+const showQrPreview = ref(false)
+function handlePreviewQr(row) {
+  if (row.qrCodeImage) {
+    previewQrSrc.value = `data:image/png;base64,${row.qrCodeImage}`
+    previewQrUrl.value = row.qrCodeUrl || ''
+    showQrPreview.value = true
+  }
+}
+
+async function handleCopyUrl() {
+  if (!previewQrUrl.value) {
+    window.$message.warning('链接为空')
+    return
+  }
+  try {
+    await navigator.clipboard.writeText(previewQrUrl.value)
+    window.$message.success('链接已复制')
+  } catch {
+    const textarea = document.createElement('textarea')
+    textarea.value = previewQrUrl.value
+    textarea.style.position = 'fixed'
+    textarea.style.opacity = '0'
+    document.body.appendChild(textarea)
+    textarea.select()
+    document.execCommand('copy')
+    document.body.removeChild(textarea)
+    window.$message.success('链接已复制')
+  }
+}
+
+function handleDownloadQr() {
+  if (!previewQrSrc.value) {
+    window.$message.warning('二维码图片不存在')
+    return
+  }
+  const link = document.createElement('a')
+  link.href = previewQrSrc.value
+  link.download = `qrcode_${Date.now()}.png`
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+  window.$message.success('下载成功')
+}
+
+// ==================== 批量删除 ====================
+async function handleBatchRemove() {
+  if (selectedIds.value.length === 0) {
+    window.$message.warning('请先选择要删除的二维码')
+    return
+  }
+  window.$dialog.warning({
+    title: '确认批量删除',
+    content: `确定要删除选中的 ${selectedIds.value.length} 个二维码吗?已绑定房间的二维码无法删除。`,
+    positiveText: '确定',
+    negativeText: '取消',
+    onPositiveClick: async () => {
+      try {
+        const res = await batchRemoveQrCode(selectedIds.value)
+        if (res.code === 200) {
+          window.$message.success('批量删除成功')
+          selectedIds.value = []
+          crudRef.value?.handleRefresh()
+        }
+      } catch (e) {
+        window.$message.error(e?.message || '批量删除失败')
+      }
+    },
+  })
+}
+
+// ==================== 批量下载ZIP ====================
+async function handleBatchDownload() {
+  if (selectedIds.value.length === 0) {
+    window.$message.warning('请先选择要下载的二维码')
+    return
+  }
+  try {
+    const res = await batchDownloadQrCode(selectedIds.value)
+    const blob = new Blob([res], { type: 'application/zip' })
+    const url = window.URL.createObjectURL(blob)
+    const link = document.createElement('a')
+    link.href = url
+    link.download = `qrcodes_${Date.now()}.zip`
+    document.body.appendChild(link)
+    link.click()
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    window.$message.success('批量下载成功')
+  } catch {
+    window.$message.error('批量下载失败')
+  }
+}
+
+// ==================== 单条下载 ====================
+async function handleSingleDownload(row) {
+  try {
+    const res = await batchDownloadQrCode([row.id])
+    const blob = new Blob([res], { type: 'application/zip' })
+    const url = window.URL.createObjectURL(blob)
+    const link = document.createElement('a')
+    link.href = url
+    link.download = `${row.shortCode}.png`
+    document.body.appendChild(link)
+    link.click()
+    document.body.removeChild(link)
+    window.URL.revokeObjectURL(url)
+    window.$message.success('下载成功')
+  } catch {
+    window.$message.error('下载失败')
+  }
+}
+</script>
+
+<style scoped>
+.hotel-qrcode-page {
+  height: 100%;
+}
+
+.qr-preview-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 20px;
+  padding: 10px 0;
+}
+
+.qr-image-wrapper {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 20px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.qr-url-section {
+  width: 100%;
+  background: #f5f7fa;
+  border-radius: 6px;
+  padding: 12px 16px;
+}
+
+.qr-url-label {
+  font-size: 13px;
+  color: #666;
+  margin-bottom: 8px;
+}
+
+.qr-url-row {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.qr-url-row :deep(.n-input) {
+  flex: 1;
+}
+
+.copy-btn {
+  flex-shrink: 0;
+}
+
+.qr-download-section {
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 158 - 0
forge-admin-ui/src/views/hotel/room.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="hotel-room-page">
+    <AiCrudPage
+      ref="crudRef"
+      api="/hotel/room"
+      :api-config="{
+        list: 'get@/hotel/room/page',
+        detail: 'get@/hotel/room/:id',
+        add: 'post@/hotel/room',
+        update: 'put@/hotel/room',
+        delete: 'post@/hotel/room/remove/:id',
+      }"
+      :load-detail-on-edit="true"
+      :search-schema="searchSchema"
+      :columns="tableColumns"
+      :edit-schema="editSchema"
+      row-key="id"
+      add-button-text="新增房间"
+    />
+  </div>
+</template>
+
+<script setup>
+import { computed, h, ref } from 'vue'
+import { NTag } from 'naive-ui'
+import { AiCrudPage } from '@/components/ai-form'
+import { getRoomTypeList } from '@/api/hotel'
+
+defineOptions({ name: 'HotelRoom' })
+
+const crudRef = ref(null)
+
+// 房间状态选项
+const roomStatusOptions = [
+  { label: '空闲', value: 'VACANT' },
+  { label: '入住', value: 'OCCUPIED' },
+  { label: '打扫中', value: 'CLEANING' },
+  { label: '维护中', value: 'MAINTENANCE' },
+]
+
+// 房型选项(异步加载)
+const roomTypeOptions = ref([])
+async function loadRoomTypes() {
+  try {
+    const res = await getRoomTypeList()
+    if (res.code === 200) {
+      roomTypeOptions.value = (res.data || []).map(t => ({
+        label: t.typeName,
+        value: t.id,
+      }))
+    }
+  } catch {
+    // ignore
+  }
+}
+loadRoomTypes()
+
+// 状态标签颜色映射
+const statusColorMap = {
+  VACANT: 'success',
+  OCCUPIED: 'error',
+  CLEANING: 'warning',
+  MAINTENANCE: 'info',
+}
+const statusLabelMap = {
+  VACANT: '空闲',
+  OCCUPIED: '入住',
+  CLEANING: '打扫中',
+  MAINTENANCE: '维护中',
+}
+
+// 搜索表单配置
+const searchSchema = [
+  {
+    field: 'roomNo',
+    label: '房间号',
+    type: 'input',
+    props: { placeholder: '请输入房间号' },
+  },
+  {
+    field: 'status',
+    label: '状态',
+    type: 'select',
+    props: { placeholder: '请选择状态', options: roomStatusOptions },
+  },
+  {
+    field: 'roomTypeId',
+    label: '房型',
+    type: 'select',
+    props: { placeholder: '请选择房型', options: roomTypeOptions },
+  },
+]
+
+// 表格列配置
+const tableColumns = computed(() => [
+  { prop: 'roomNo', label: '房间号', width: 120 },
+  { prop: 'roomTypeName', label: '房型', width: 140 },
+  { prop: 'floorNo', label: '楼层', width: 80 },
+  {
+    prop: 'status',
+    label: '状态',
+    width: 100,
+    render: row => h(NTag, { type: statusColorMap[row.status] || 'default', size: 'small' }, { default: () => statusLabelMap[row.status] || row.status }),
+  },
+  { prop: 'sortOrder', label: '排序', width: 80 },
+  { prop: 'remark', label: '备注', minWidth: 200 },
+  { prop: 'createTime', label: '创建时间', width: 172 },
+])
+
+// 编辑表单配置
+const editSchema = computed(() => [
+  {
+    field: 'roomNo',
+    label: '房间号',
+    type: 'input',
+    rules: [{ required: true, message: '请输入房间号', trigger: 'blur' }],
+    props: { placeholder: '请输入房间号' },
+  },
+  {
+    field: 'roomTypeId',
+    label: '房型',
+    type: 'select',
+    props: { placeholder: '请选择房型', options: roomTypeOptions.value },
+  },
+  {
+    field: 'floorNo',
+    label: '楼层',
+    type: 'input',
+    props: { placeholder: '请输入楼层' },
+  },
+  {
+    field: 'status',
+    label: '状态',
+    type: 'select',
+    defaultValue: 'VACANT',
+    props: { placeholder: '请选择状态', options: roomStatusOptions },
+  },
+  {
+    field: 'sortOrder',
+    label: '排序',
+    type: 'input',
+    props: { placeholder: '排序号', type: 'number' },
+  },
+  {
+    field: 'remark',
+    label: '备注',
+    type: 'textarea',
+    span: 2,
+    props: { placeholder: '请输入备注', rows: 3 },
+  },
+])
+</script>
+
+<style scoped>
+.hotel-room-page {
+  height: 100%;
+}
+</style>

+ 66 - 0
forge-admin-ui/src/views/hotel/roomType.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="hotel-room-type-page">
+    <AiCrudPage
+      ref="crudRef"
+      api="/hotel/room-type"
+      :api-config="{
+        list: 'get@/hotel/room-type/list',
+        detail: 'get@/hotel/room-type/:id',
+        add: 'post@/hotel/room-type',
+        update: 'put@/hotel/room-type',
+        delete: 'post@/hotel/room-type/remove/:id',
+      }"
+      :load-detail-on-edit="true"
+      :columns="tableColumns"
+      :edit-schema="editSchema"
+      row-key="id"
+      add-button-text="新增房型"
+      :show-search="false"
+    />
+  </div>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { AiCrudPage } from '@/components/ai-form'
+
+defineOptions({ name: 'HotelRoomType' })
+
+// 表格列配置
+const tableColumns = computed(() => [
+  { prop: 'typeName', label: '房型名称', width: 200 },
+  { prop: 'description', label: '描述', minWidth: 300 },
+  { prop: 'sortOrder', label: '排序', width: 80 },
+  { prop: 'createTime', label: '创建时间', width: 172 },
+])
+
+// 编辑表单配置
+const editSchema = [
+  {
+    field: 'typeName',
+    label: '房型名称',
+    type: 'input',
+    rules: [{ required: true, message: '请输入房型名称', trigger: 'blur' }],
+    props: { placeholder: '请输入房型名称' },
+  },
+  {
+    field: 'description',
+    label: '描述',
+    type: 'textarea',
+    span: 2,
+    props: { placeholder: '请输入房型描述', rows: 3 },
+  },
+  {
+    field: 'sortOrder',
+    label: '排序',
+    type: 'input',
+    props: { placeholder: '排序号', type: 'number' },
+  },
+]
+</script>
+
+<style scoped>
+.hotel-room-type-page {
+  height: 100%;
+}
+</style>

+ 3 - 0
forge-h5-ui/package.json

@@ -58,6 +58,8 @@
     "clipboard": "^2.0.11",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.20",
+    "html5-qrcode": "^2.3.8",
+    "jsbn": "^1.1.0",
     "jsencrypt-ext": "^2.1.2",
     "pinia": "2.0.36",
     "pinia-plugin-persistedstate": "3.2.0",
@@ -77,6 +79,7 @@
     "@unocss/preset-mini": "^66.6.8",
     "@unocss/preset-rem-to-px": "^66.6.8",
     "@unocss/preset-uno": "^66.6.8",
+    "@vitejs/plugin-basic-ssl": "^1.2.0",
     "@vue/runtime-core": "^3.4.21",
     "glob": "^11.0.3",
     "sass": "^1.93.2",

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 9776 - 0
forge-h5-ui/pnpm-lock.yaml


+ 31 - 0
forge-h5-ui/src/api/index.js

@@ -238,4 +238,35 @@ export default {
     method: 'post',
     params: { tenantId },
   }),
+
+  // ==================== 酒店扫码绑定 ====================
+  /** 扫码查询(已登录时自动携带 Token,未登录时走白名单免登录) */
+  hotelScan: params => request({
+    url: '/hotel/open/scan',
+    method: 'get',
+    params,
+    skipAuthRefresh: true, // 扫码接口失败时不自动跳转登录,由页面自行处理
+  }),
+  /** 查询全部房间(用于绑定选择) */
+  hotelRoomListAll: () => request({
+    url: '/hotel/room/list-all',
+    method: 'get',
+  }),
+  /** 二维码绑定房间 */
+  hotelQrBind: (id, data) => request({
+    url: `/hotel/qrcode/${id}/bind`,
+    method: 'post',
+    data,
+  }),
+  /** 二维码重新绑定房间 */
+  hotelQrRebind: (id, data) => request({
+    url: `/hotel/qrcode/${id}/rebind`,
+    method: 'post',
+    data,
+  }),
+  /** 二维码解绑房间 */
+  hotelQrUnbind: id => request({
+    url: `/hotel/qrcode/${id}/unbind`,
+    method: 'post',
+  }),
 }

+ 14 - 0
forge-h5-ui/src/pages.json

@@ -63,6 +63,20 @@
 				"navigationBarTitleText": "应用功能",
 				"navigationStyle": "custom"
 			}
+		},
+		{
+			"path": "pages/hotel/scan-bind",
+			"style": {
+				"navigationBarTitleText": "扫码绑定",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/hotel/qr-scanner",
+			"style": {
+				"navigationBarTitleText": "扫描二维码",
+				"navigationStyle": "custom"
+			}
 		}
 	],
 	"tabBar": {

+ 473 - 0
forge-h5-ui/src/pages/hotel/qr-scanner.vue

@@ -0,0 +1,473 @@
+<template>
+  <view class="qr-scanner-page">
+    <!-- 顶部导航 -->
+    <view class="qr-scanner-nav">
+      <view class="qr-scanner-nav-back" @click="goBack">
+        <text class="qr-scanner-nav-back-icon">&larr;</text>
+      </view>
+      <text class="qr-scanner-nav-title">扫描二维码</text>
+      <view class="qr-scanner-nav-placeholder" />
+    </view>
+
+    <!-- 相机区域 -->
+    <view class="qr-scanner-viewfinder">
+      <view id="qr-reader" class="qr-scanner-reader" />
+
+      <!-- 扫描框覆盖层 -->
+      <view class="qr-scanner-overlay">
+        <view class="qr-scanner-corner qr-scanner-corner--tl" />
+        <view class="qr-scanner-corner qr-scanner-corner--tr" />
+        <view class="qr-scanner-corner qr-scanner-corner--bl" />
+        <view class="qr-scanner-corner qr-scanner-corner--br" />
+        <view class="qr-scanner-line" />
+      </view>
+
+      <!-- 相机未授权时的提示 -->
+      <view v-if="cameraError" class="qr-scanner-camera-error">
+        <view class="qr-scanner-camera-error-icon">
+          <AiIcon icon="/static/icons/ai-icon/alert-triangle.svg" color="#f59e0b" size="lg" />
+        </view>
+        <text class="qr-scanner-camera-error-title">无法访问摄像头</text>
+        <text class="qr-scanner-camera-error-desc">{{ cameraErrorMsg }}</text>
+        <view class="qr-scanner-camera-error-actions">
+          <AiButton size="sm" @click="startScanner">重试</AiButton>
+        </view>
+      </view>
+    </view>
+
+    <!-- 底部提示 -->
+    <view class="qr-scanner-footer">
+      <text class="qr-scanner-footer-text">将二维码放入框内,即可自动扫描</text>
+      <view class="qr-scanner-footer-actions">
+        <view class="qr-scanner-footer-btn" @click="handleAlbum">
+          <AiIcon icon="/static/icons/ai-icon/image.svg" color="#ffffff" size="sm" />
+          <text class="qr-scanner-footer-btn-text">从相册选择</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { onMounted, onBeforeUnmount, ref } from 'vue'
+import AiIcon from '@/components/AiIcon.vue'
+import AiButton from '@/components/AiButton.vue'
+import { Html5Qrcode, Html5QrcodeScanType } from 'html5-qrcode'
+import { toast } from '@/utils/notify'
+
+const cameraError = ref(false)
+const cameraErrorMsg = ref('')
+let html5QrCode = null
+let isDestroyed = false
+
+onMounted(() => {
+  startScanner()
+})
+
+onBeforeUnmount(() => {
+  stopScanner()
+})
+
+async function startScanner() {
+  cameraError.value = false
+  cameraErrorMsg.value = ''
+
+  try {
+    if (html5QrCode) {
+      try {
+        await html5QrCode.stop()
+      } catch (e) {
+        // ignore
+      }
+      html5QrCode.clear()
+      html5QrCode = null
+    }
+
+    html5QrCode = new Html5Qrcode('qr-reader', { verbose: false })
+
+    const config = {
+      fps: 15,
+      qrbox: (viewfinderWidth, viewfinderHeight) => {
+        const minEdge = Math.min(viewfinderWidth, viewfinderHeight)
+        const size = Math.floor(minEdge * 0.7)
+        return { width: size, height: size }
+      },
+      aspectRatio: 1.0,
+    }
+
+    // 优先使用后置摄像头
+    const cameras = await Html5Qrcode.getCameras()
+    if (!cameras || cameras.length === 0) {
+      throw new Error('未检测到摄像头设备')
+    }
+
+    let cameraId = cameras[0].id
+    // 查找后置摄像头
+    const backCamera = cameras.find(c =>
+      /back|rear|environment/i.test(c.label)
+    )
+    if (backCamera) {
+      cameraId = backCamera.id
+    }
+
+    await html5QrCode.start(
+      cameraId,
+      config,
+      onScanSuccess,
+      () => { /* onScanFailure - ignore */ }
+    )
+  } catch (err) {
+    console.error('Camera error:', err)
+    cameraError.value = true
+
+    if (err.name === 'NotAllowedError' || err.message?.includes('Permission')) {
+      cameraErrorMsg.value = '请在浏览器设置中允许访问摄像头'
+    } else if (err.name === 'NotFoundError' || err.message?.includes('未检测')) {
+      cameraErrorMsg.value = '未检测到摄像头设备,请确认设备已连接'
+    } else if (err.name === 'NotReadableError') {
+      cameraErrorMsg.value = '摄像头被占用,请关闭其他应用后重试'
+    } else if (err.message?.includes('HTTPS') || err.message?.includes('secure')) {
+      cameraErrorMsg.value = '摄像头功能需要 HTTPS 或 localhost 环境'
+    } else {
+      cameraErrorMsg.value = err.message || '摄像头启动失败'
+    }
+  }
+}
+
+async function stopScanner() {
+  isDestroyed = true
+  if (html5QrCode) {
+    try {
+      if (html5QrCode.isScanning) {
+        await html5QrCode.stop()
+      }
+    } catch (e) {
+      // ignore
+    }
+    try {
+      html5QrCode.clear()
+    } catch (e) {
+      // ignore
+    }
+    html5QrCode = null
+  }
+}
+
+function onScanSuccess(decodedText) {
+  // 扫码成功,震动反馈
+  uni.vibrateShort()
+
+  const params = parseQrUrl(decodedText)
+  if (params) {
+    stopScanner()
+    uni.redirectTo({
+      url: `/pages/hotel/scan-bind?c=${params.c}&t=${params.t}&s=${params.s}`,
+    })
+  } else {
+    toast('无法识别该二维码,请扫描酒店房间二维码', { type: 'warning' })
+  }
+}
+
+function parseQrUrl(url) {
+  try {
+    const matchC = url.match(/[?&]c=([^&]+)/)
+    const matchT = url.match(/[?&]t=([^&]+)/)
+    const matchS = url.match(/[?&]s=([^&]+)/)
+    if (matchC && matchS) {
+      return {
+        c: matchC[1],
+        t: matchT ? matchT[1] : '1',
+        s: matchS[1],
+      }
+    }
+  } catch (e) {
+    // ignore
+  }
+  return null
+}
+
+function goBack() {
+  uni.navigateBack({ delta: 1 })
+}
+
+async function handleAlbum() {
+  if (!html5QrCode) return
+
+  try {
+    // 暂停实时扫描
+    if (html5QrCode.isScanning) {
+      await html5QrCode.pause(/* shouldPauseResume */true)
+    }
+
+    // 使用 html5-qrcode 的文件扫描功能
+    const input = document.createElement('input')
+    input.type = 'file'
+    input.accept = 'image/*'
+    input.capture = 'environment'
+    input.style.display = 'none'
+
+    input.onchange = async (e) => {
+      const file = e.target.files?.[0]
+      if (!file) {
+        resumeScanner()
+        return
+      }
+
+      try {
+        const result = await html5QrCode.scanFileV2(file, {
+          formatsSupported: Object.values(Html5QrcodeScanType),
+        })
+        onScanSuccess(result)
+      } catch (err) {
+        toast('未能从图片中识别二维码', { type: 'warning' })
+        resumeScanner()
+      } finally {
+        input.remove()
+      }
+    }
+
+    input.oncancel = () => {
+      resumeScanner()
+      input.remove()
+    }
+
+    document.body.appendChild(input)
+    input.click()
+  } catch (err) {
+    console.error('Album scan error:', err)
+    toast('打开相册失败', { type: 'error' })
+    resumeScanner()
+  }
+}
+
+async function resumeScanner() {
+  if (html5QrCode && !isDestroyed) {
+    try {
+      await html5QrCode.resume()
+    } catch (e) {
+      // ignore
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.qr-scanner-page {
+  position: relative;
+  min-height: 100vh;
+  background: #000;
+  display: flex;
+  flex-direction: column;
+}
+
+// Nav
+.qr-scanner-nav {
+  position: relative;
+  z-index: 20;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 24rpx;
+  padding-top: env(safe-area-inset-top, 44px);
+  height: calc(88rpx + env(safe-area-inset-top, 44px));
+  background: rgba(0, 0, 0, 0.6);
+}
+
+.qr-scanner-nav-back {
+  width: 72rpx;
+  height: 72rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.qr-scanner-nav-back-icon {
+  color: #fff;
+  font-size: 40rpx;
+}
+
+.qr-scanner-nav-title {
+  color: #fff;
+  font-size: 32rpx;
+  font-weight: 700;
+}
+
+.qr-scanner-nav-placeholder {
+  width: 72rpx;
+}
+
+// Viewfinder
+.qr-scanner-viewfinder {
+  flex: 1;
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+}
+
+.qr-scanner-reader {
+  width: 100%;
+  max-width: 600rpx;
+  aspect-ratio: 1;
+
+  :deep(video) {
+    width: 100% !important;
+    height: 100% !important;
+    object-fit: cover;
+    border-radius: 24rpx;
+  }
+
+  :deep(#qr-reader-dashboard) {
+    display: none !important;
+  }
+
+  :deep(#qr-reader-status-container) {
+    display: none !important;
+  }
+}
+
+// Overlay with corners
+.qr-scanner-overlay {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 70%;
+  aspect-ratio: 1;
+  pointer-events: none;
+}
+
+.qr-scanner-corner {
+  position: absolute;
+  width: 48rpx;
+  height: 48rpx;
+  border-color: #2563eb;
+  border-style: solid;
+  border-width: 0;
+
+  &--tl {
+    top: 0;
+    left: 0;
+    border-top-width: 6rpx;
+    border-left-width: 6rpx;
+    border-top-left-radius: 16rpx;
+  }
+
+  &--tr {
+    top: 0;
+    right: 0;
+    border-top-width: 6rpx;
+    border-right-width: 6rpx;
+    border-top-right-radius: 16rpx;
+  }
+
+  &--bl {
+    bottom: 0;
+    left: 0;
+    border-bottom-width: 6rpx;
+    border-left-width: 6rpx;
+    border-bottom-left-radius: 16rpx;
+  }
+
+  &--br {
+    bottom: 0;
+    right: 0;
+    border-bottom-width: 6rpx;
+    border-right-width: 6rpx;
+    border-bottom-right-radius: 16rpx;
+  }
+}
+
+.qr-scanner-line {
+  position: absolute;
+  left: 5%;
+  right: 5%;
+  height: 4rpx;
+  background: linear-gradient(90deg, transparent, #2563eb, transparent);
+  animation: scanLine 2.5s ease-in-out infinite;
+}
+
+@keyframes scanLine {
+  0%, 100% { top: 5%; }
+  50% { top: 95%; }
+}
+
+// Camera error
+.qr-scanner-camera-error {
+  position: absolute;
+  inset: 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  gap: 16rpx;
+  background: rgba(0, 0, 0, 0.85);
+  padding: 40rpx;
+}
+
+.qr-scanner-camera-error-icon {
+  margin-bottom: 8rpx;
+}
+
+.qr-scanner-camera-error-title {
+  color: #fff;
+  font-size: 32rpx;
+  font-weight: 700;
+}
+
+.qr-scanner-camera-error-desc {
+  color: #94a3b8;
+  font-size: 26rpx;
+  text-align: center;
+  margin-bottom: 16rpx;
+}
+
+.qr-scanner-camera-error-actions {
+  margin-top: 8rpx;
+}
+
+// Footer
+.qr-scanner-footer {
+  position: relative;
+  z-index: 20;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 24rpx;
+  padding: 40rpx 0;
+  padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
+  background: rgba(0, 0, 0, 0.6);
+}
+
+.qr-scanner-footer-text {
+  color: rgba(255, 255, 255, 0.7);
+  font-size: 26rpx;
+  font-weight: 500;
+}
+
+.qr-scanner-footer-actions {
+  display: flex;
+  gap: 32rpx;
+}
+
+.qr-scanner-footer-btn {
+  display: flex;
+  align-items: center;
+  gap: 8rpx;
+  padding: 16rpx 32rpx;
+  border-radius: 40rpx;
+  background: rgba(255, 255, 255, 0.15);
+  border: 1rpx solid rgba(255, 255, 255, 0.2);
+
+  &:active {
+    background: rgba(255, 255, 255, 0.25);
+  }
+}
+
+.qr-scanner-footer-btn-text {
+  color: #fff;
+  font-size: 26rpx;
+  font-weight: 600;
+}
+</style>

+ 792 - 0
forge-h5-ui/src/pages/hotel/scan-bind.vue

@@ -0,0 +1,792 @@
+<template>
+  <view class="scan-bind-page">
+    <!-- 加载中 -->
+    <view v-if="loading" class="scan-bind-loading">
+      <view class="scan-bind-spinner" />
+      <text class="scan-bind-loading-text">正在识别二维码...</text>
+    </view>
+
+    <!-- 无参数 - 显示扫码入口 -->
+    <view v-else-if="!hasParams" class="scan-bind-content">
+      <view class="scan-bind-header">
+        <view class="scan-bind-header-icon">
+          <AiIcon icon="/static/icons/ai-icon/smartphone.svg" color="#2563eb" size="lg" />
+        </view>
+        <text class="scan-bind-header-title">扫码绑定房间</text>
+        <text class="scan-bind-header-desc">请扫描房间二维码进行绑定操作</text>
+      </view>
+
+      <view class="scan-bind-scan-area">
+        <view class="scan-bind-scan-btn" @click="handleCameraScan">
+          <AiIcon icon="/static/icons/ai-icon/camera.svg" color="#ffffff" size="lg" />
+          <text class="scan-bind-scan-btn-text">扫描二维码</text>
+        </view>
+        <text class="scan-bind-scan-hint">将二维码放入框内,即可自动扫描</text>
+      </view>
+    </view>
+
+    <!-- 错误状态 -->
+    <AiResult
+      v-else-if="errorMsg"
+      type="error"
+      :title="errorTitle"
+      :description="errorMsg"
+      primary-text="重新加载"
+      @primary="loadScanInfo"
+    />
+
+    <!-- 未绑定 - 选择房间绑定 -->
+    <view v-else-if="scanData && !scanData.bound" class="scan-bind-content">
+      <view class="scan-bind-header">
+        <view class="scan-bind-header-icon">
+          <AiIcon icon="/static/icons/ai-icon/smartphone.svg" color="#2563eb" size="lg" />
+        </view>
+        <text class="scan-bind-header-title">扫码绑定房间</text>
+        <text class="scan-bind-header-desc">请为当前二维码选择要绑定的房间</text>
+      </view>
+
+      <view class="scan-bind-info-card">
+        <view class="scan-bind-info-row">
+          <text class="scan-bind-info-label">二维码编号</text>
+          <text class="scan-bind-info-value">{{ scanData.shortCode }}</text>
+        </view>
+        <view class="scan-bind-info-row">
+          <text class="scan-bind-info-label">状态</text>
+          <text class="scan-bind-info-value" :class="scanData.status === 'ACTIVE' ? 'status-active' : 'status-disabled'">
+            {{ scanData.status === 'ACTIVE' ? '启用中' : '已禁用' }}
+          </text>
+        </view>
+      </view>
+
+      <!-- 房间选择 -->
+      <view class="scan-bind-room-section">
+        <text class="scan-bind-room-title">选择房间</text>
+
+        <view v-if="roomLoading" class="scan-bind-room-loading">
+          <text>加载房间列表...</text>
+        </view>
+
+        <view v-else-if="!roomList.length" class="scan-bind-room-empty">
+          <AiIcon icon="/static/icons/ai-icon/inbox.svg" color="#94a3b8" size="md" />
+          <text>暂无可用房间</text>
+        </view>
+
+        <scroll-view v-else class="scan-bind-room-list" scroll-y :show-scrollbar="false">
+          <view
+            v-for="room in filteredRooms"
+            :key="room.id"
+            class="scan-bind-room-item"
+            :class="{ 'scan-bind-room-item--active': selectedRoomId === room.id }"
+            @click="selectRoom(room)"
+          >
+            <view class="scan-bind-room-item-left">
+              <view class="scan-bind-room-item-icon" :class="roomStatusClass(room.status)">
+                <text class="scan-bind-room-item-icon-text">{{ room.roomNo }}</text>
+              </view>
+              <view class="scan-bind-room-item-info">
+                <text class="scan-bind-room-item-name">{{ room.roomNo }}号房间</text>
+                <text class="scan-bind-room-item-type">{{ room.roomTypeName || '未设置房型' }}</text>
+              </view>
+            </view>
+            <view v-if="selectedRoomId === room.id" class="scan-bind-room-item-check">
+              <AiIcon icon="/static/icons/ai-icon/check-circle.svg" color="#2563eb" size="sm" />
+            </view>
+          </view>
+        </scroll-view>
+      </view>
+
+      <!-- 底部操作栏 -->
+      <view class="scan-bind-footer">
+        <AiButton block :loading="bindLoading" :disabled="!selectedRoomId" @click="handleBind">
+          确认绑定
+        </AiButton>
+      </view>
+    </view>
+
+    <!-- 已绑定 - 展示绑定信息 -->
+    <view v-else-if="scanData && scanData.bound" class="scan-bind-content">
+      <view class="scan-bind-header">
+        <view class="scan-bind-header-icon scan-bind-header-icon--success">
+          <AiIcon icon="/static/icons/ai-icon/check-circle.svg" color="#10b981" size="lg" />
+        </view>
+        <text class="scan-bind-header-title">已绑定房间</text>
+        <text class="scan-bind-header-desc">当前二维码已绑定以下房间</text>
+      </view>
+
+      <view class="scan-bind-bound-card">
+        <view class="scan-bind-bound-room-no">
+          <text>{{ scanData.room.roomNo }}</text>
+        </view>
+        <view class="scan-bind-bound-detail">
+          <view class="scan-bind-bound-row" v-if="scanData.room.roomTypeName">
+            <text class="scan-bind-bound-label">房型</text>
+            <text class="scan-bind-bound-value">{{ scanData.room.roomTypeName }}</text>
+          </view>
+          <view class="scan-bind-bound-row" v-if="scanData.bindInfo?.operatorName">
+            <text class="scan-bind-bound-label">绑定人</text>
+            <text class="scan-bind-bound-value">{{ scanData.bindInfo.operatorName }}</text>
+          </view>
+          <view class="scan-bind-bound-row" v-if="scanData.bindInfo?.bindTime">
+            <text class="scan-bind-bound-label">绑定时间</text>
+            <text class="scan-bind-bound-value">{{ scanData.bindInfo.bindTime }}</text>
+          </view>
+        </view>
+      </view>
+
+      <view class="scan-bind-actions">
+        <AiButton variant="error" block @click="handleUnbind">
+          解绑房间
+        </AiButton>
+      </view>
+    </view>
+
+    <!-- 绑定成功弹窗 -->
+    <view v-if="showSuccess" class="scan-bind-success-mask" @click.self="closeSuccess">
+      <view class="scan-bind-success-dialog">
+        <view class="scan-bind-success-icon">
+          <AiIcon icon="/static/icons/ai-icon/check-circle.svg" color="#10b981" size="xl" />
+        </view>
+        <text class="scan-bind-success-title">绑定成功</text>
+        <text class="scan-bind-success-desc">二维码已成功绑定到 {{ successRoomNo }} 号房间</text>
+        <AiButton block @click="goToScanPage">完成</AiButton>
+      </view>
+    </view>
+
+    <!-- 解绑确认弹窗 -->
+    <view v-if="showUnbindConfirm" class="scan-bind-success-mask" @click.self="cancelUnbind">
+      <view class="scan-bind-success-dialog">
+        <view class="scan-bind-success-icon scan-bind-success-icon--warning">
+          <AiIcon icon="/static/icons/ai-icon/alert-triangle.svg" color="#f59e0b" size="xl" />
+        </view>
+        <text class="scan-bind-success-title">确认解绑</text>
+        <text class="scan-bind-success-desc">确定要解除二维码与 {{ currentBoundRoomNo }} 号房间的绑定吗?</text>
+        <view class="scan-bind-confirm-actions">
+          <AiButton variant="secondary" block @click="cancelUnbind">取消</AiButton>
+          <AiButton variant="error" :loading="unbindLoading" block @click="confirmUnbind">确认解绑</AiButton>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { computed, onMounted, ref } from 'vue'
+import AiIcon from '@/components/AiIcon.vue'
+import AiButton from '@/components/AiButton.vue'
+import AiResult from '@/components/AiResult.vue'
+import api from '@/api'
+import { useAuthStore } from '@/store'
+import { ensureLogin } from '@/utils/auth-guard'
+import { toast } from '@/utils/notify'
+
+const authStore = useAuthStore()
+
+// 页面状态
+const loading = ref(true)
+const errorMsg = ref('')
+const errorTitle = ref('二维码识别失败')
+const scanData = ref(null)
+
+// 房间相关
+const roomLoading = ref(false)
+const roomList = ref([])
+const selectedRoomId = ref(null)
+const bindLoading = ref(false)
+const showSuccess = ref(false)
+const successRoomNo = ref('')
+
+// 解绑相关
+const showUnbindConfirm = ref(false)
+const unbindLoading = ref(false)
+const currentBoundRoomNo = ref('')
+
+// 过滤已占用的房间(只展示空闲房间)
+const filteredRooms = computed(() => {
+  return roomList.value.filter(r => r.status === 'VACANT' || r.id === selectedRoomId.value)
+})
+
+// URL 参数
+let shortCode = ''
+let tenantId = ''
+let sign = ''
+const hasParams = ref(false)
+
+onMounted(async () => {
+  const pages = getCurrentPages()
+  const currentPage = pages[pages.length - 1]
+  const options = currentPage?.$page?.options || currentPage?.options || {}
+
+  shortCode = options.c || options.shortCode || ''
+  tenantId = options.t || options.tenantId || ''
+  sign = options.s || options.sign || ''
+
+  if (!shortCode || !sign) {
+    hasParams.value = false
+    loading.value = false
+    return
+  }
+
+  hasParams.value = true
+  await loadScanInfo()
+})
+
+async function loadScanInfo() {
+  loading.value = true
+  errorMsg.value = ''
+  scanData.value = null
+
+  try {
+    const res = await api.hotelScan({ shortCode, sign })
+    scanData.value = res?.data || res
+    loading.value = false
+
+    // 如果未绑定,加载房间列表
+    if (!scanData.value.bound) {
+      await loadRoomList()
+    }
+  } catch (err) {
+    loading.value = false
+    // 如果是认证错误(401/未提供登录凭证),直接跳转到主页
+    const errorCode = err?.code
+    if (errorCode === 401 || errorCode === '-8' || errorCode === 11007 || errorCode === 11008) {
+      // 认证错误,跳转到主页
+      uni.switchTab({ url: '/pages/index/index' })
+      return
+    }
+    errorTitle.value = '二维码识别失败'
+    errorMsg.value = err?.message || '无法识别该二维码,请检查二维码是否有效'
+  }
+}
+
+async function loadRoomList() {
+  roomLoading.value = true
+  try {
+    // 需要先登录才能获取房间列表
+    const loggedIn = await ensureLogin({ redirect: getCurrentPageUrl(), loadUser: false })
+    if (!loggedIn) {
+      return
+    }
+    const res = await api.hotelRoomListAll()
+    roomList.value = res?.data || res || []
+  } catch (err) {
+    roomList.value = []
+    console.error('加载房间列表失败:', err)
+  } finally {
+    roomLoading.value = false
+  }
+}
+
+function selectRoom(room) {
+  selectedRoomId.value = room.id
+}
+
+async function handleBind() {
+  if (!selectedRoomId.value) {
+    toast('请先选择房间', { type: 'info' })
+    return
+  }
+
+  const loggedIn = await ensureLogin({ redirect: getCurrentPageUrl(), loadUser: false })
+  if (!loggedIn) return
+
+  bindLoading.value = true
+  try {
+    await api.hotelQrBind(scanData.value.qrCodeId, {
+      roomId: selectedRoomId.value,
+      remark: 'H5扫码绑定',
+    })
+
+    const selectedRoom = roomList.value.find(r => r.id === selectedRoomId.value)
+    successRoomNo.value = selectedRoom?.roomNo || ''
+    showSuccess.value = true
+
+    // 更新本地状态
+    scanData.value.bound = true
+    scanData.value.room = {
+      roomId: selectedRoom?.id,
+      roomNo: selectedRoom?.roomNo,
+      roomTypeName: selectedRoom?.roomTypeName,
+    }
+    scanData.value.bindInfo = {
+      operatorName: authStore.userInfo?.nickName || authStore.userInfo?.userName || '',
+      bindTime: formatNow(),
+    }
+  } catch (err) {
+    toast(err?.message || '绑定失败,请重试', { type: 'error' })
+  } finally {
+    bindLoading.value = false
+  }
+}
+
+function handleUnbind() {
+  if (!scanData.value?.bound || !scanData.value?.room?.roomNo) {
+    toast('当前二维码未绑定房间', { type: 'info' })
+    return
+  }
+  currentBoundRoomNo.value = scanData.value.room.roomNo
+  showUnbindConfirm.value = true
+}
+
+async function confirmUnbind() {
+  const loggedIn = await ensureLogin({ redirect: getCurrentPageUrl(), loadUser: false })
+  if (!loggedIn) return
+
+  unbindLoading.value = true
+  try {
+    await api.hotelQrUnbind(scanData.value.qrCodeId)
+    toast('解绑成功', { type: 'success' })
+    // 关闭弹窗并跳转到扫码主界面(无参数状态)
+    cancelUnbind()
+    uni.redirectTo({ url: '/pages/hotel/scan-bind' })
+  } catch (err) {
+    toast(err?.message || '解绑失败,请重试', { type: 'error' })
+  } finally {
+    unbindLoading.value = false
+  }
+}
+
+function cancelUnbind() {
+  showUnbindConfirm.value = false
+  currentBoundRoomNo.value = ''
+}
+
+function goToScanPage() {
+  // 关闭成功弹窗并跳转到扫码主界面(无参数状态)
+  showSuccess.value = false
+  uni.redirectTo({ url: '/pages/hotel/scan-bind' })
+}
+
+function closeSuccess() {
+  showSuccess.value = false
+}
+
+function roomStatusClass(status) {
+  if (status === 'VACANT') return 'room-status--vacant'
+  if (status === 'OCCUPIED') return 'room-status--occupied'
+  return 'room-status--unknown'
+}
+
+function getCurrentPageUrl() {
+  const params = []
+  if (shortCode) params.push(`c=${shortCode}`)
+  if (tenantId) params.push(`t=${tenantId}`)
+  if (sign) params.push(`s=${sign}`)
+  return `/pages/hotel/scan-bind?${params.join('&')}`
+}
+
+function formatNow() {
+  const d = new Date()
+  const pad = n => String(n).padStart(2, '0')
+  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
+}
+
+// 相机扫码 — 跳转到浏览器扫码页面
+function handleCameraScan() {
+  uni.navigateTo({ url: '/pages/hotel/qr-scanner' })
+}
+
+function parseQrUrl(url) {
+  try {
+    const match = url.match(/[?&]c=([^&]+)/)
+    const matchT = url.match(/[?&]t=([^&]+)/)
+    const matchS = url.match(/[?&]s=([^&]+)/)
+    if (match && matchS) {
+      return {
+        c: match[1],
+        t: matchT ? matchT[1] : '1',
+        s: matchS[1],
+      }
+    }
+  } catch (e) {
+    // ignore
+  }
+  return null
+}
+</script>
+
+<style lang="scss" scoped>
+.scan-bind-page {
+  position: relative;
+  min-height: 100vh;
+  background: #f8fafc;
+  padding-bottom: env(safe-area-inset-bottom);
+}
+
+// Loading
+.scan-bind-loading {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  min-height: 70vh;
+  gap: 24rpx;
+}
+
+.scan-bind-spinner {
+  width: 64rpx;
+  height: 64rpx;
+  border: 6rpx solid #e2e8f0;
+  border-top-color: #2563eb;
+  border-radius: 50%;
+  animation: spin 0.8s linear infinite;
+}
+
+@keyframes spin {
+  to { transform: rotate(360deg); }
+}
+
+.scan-bind-loading-text {
+  color: #64748b;
+  font-size: 28rpx;
+  font-weight: 600;
+}
+
+// Content
+.scan-bind-content {
+  padding: 32rpx 28rpx 200rpx;
+}
+
+// Header
+.scan-bind-header {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 40rpx 0 32rpx;
+}
+
+.scan-bind-header-icon {
+  width: 120rpx;
+  height: 120rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 36rpx;
+  background: rgba(219, 234, 254, 0.6);
+  border: 1rpx solid rgba(255, 255, 255, 0.8);
+  margin-bottom: 20rpx;
+}
+
+.scan-bind-header-icon--success {
+  background: rgba(209, 250, 229, 0.6);
+}
+
+.scan-bind-header-title {
+  display: block;
+  color: #1e293b;
+  font-size: 36rpx;
+  font-weight: 900;
+}
+
+.scan-bind-header-desc {
+  display: block;
+  margin-top: 8rpx;
+  color: #64748b;
+  font-size: 26rpx;
+  font-weight: 500;
+}
+
+// Scan area (no params)
+.scan-bind-scan-area {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 32rpx;
+  margin-top: 40rpx;
+}
+
+.scan-bind-scan-btn {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  gap: 16rpx;
+  width: 280rpx;
+  height: 280rpx;
+  border-radius: 50%;
+  background: linear-gradient(135deg, #2563eb, #7c3aed);
+  box-shadow: 0 12rpx 40rpx rgba(37, 99, 235, 0.35);
+  transition: transform 0.2s;
+
+  &:active {
+    transform: scale(0.95);
+  }
+}
+
+.scan-bind-scan-btn-text {
+  color: #ffffff;
+  font-size: 28rpx;
+  font-weight: 700;
+}
+
+.scan-bind-scan-hint {
+  color: #94a3b8;
+  font-size: 24rpx;
+  font-weight: 500;
+}
+
+// Info card
+.scan-bind-info-card {
+  background: #fff;
+  border-radius: 24rpx;
+  padding: 28rpx 32rpx;
+  margin-bottom: 28rpx;
+  box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
+}
+
+.scan-bind-info-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12rpx 0;
+
+  & + & {
+    border-top: 1rpx solid #f1f5f9;
+  }
+}
+
+.scan-bind-info-label {
+  color: #64748b;
+  font-size: 26rpx;
+  font-weight: 500;
+}
+
+.scan-bind-info-value {
+  color: #1e293b;
+  font-size: 28rpx;
+  font-weight: 700;
+}
+
+.status-active {
+  color: #10b981;
+}
+
+.status-disabled {
+  color: #ef4444;
+}
+
+// Room selection
+.scan-bind-room-section {
+  background: #fff;
+  border-radius: 24rpx;
+  padding: 28rpx 32rpx;
+  box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
+}
+
+.scan-bind-room-title {
+  display: block;
+  color: #1e293b;
+  font-size: 30rpx;
+  font-weight: 800;
+  margin-bottom: 20rpx;
+}
+
+.scan-bind-room-loading,
+.scan-bind-room-empty {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 12rpx;
+  padding: 48rpx 0;
+  color: #94a3b8;
+  font-size: 26rpx;
+}
+
+.scan-bind-room-list {
+  max-height: 600rpx;
+}
+
+.scan-bind-room-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 20rpx 16rpx;
+  border-radius: 16rpx;
+  margin-bottom: 8rpx;
+  transition: background 0.2s;
+
+  &:active {
+    background: #f8fafc;
+  }
+
+  &--active {
+    background: rgba(219, 234, 254, 0.4);
+    border: 1rpx solid rgba(37, 99, 235, 0.2);
+  }
+}
+
+.scan-bind-room-item-left {
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
+}
+
+.scan-bind-room-item-icon {
+  width: 80rpx;
+  height: 80rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 20rpx;
+}
+
+.room-status--vacant {
+  background: rgba(209, 250, 229, 0.6);
+}
+
+.room-status--occupied {
+  background: rgba(254, 226, 226, 0.6);
+}
+
+.room-status--unknown {
+  background: rgba(241, 245, 249, 0.8);
+}
+
+.scan-bind-room-item-icon-text {
+  color: #1e293b;
+  font-size: 28rpx;
+  font-weight: 800;
+}
+
+.scan-bind-room-item-info {
+  display: flex;
+  flex-direction: column;
+  gap: 4rpx;
+}
+
+.scan-bind-room-item-name {
+  color: #1e293b;
+  font-size: 28rpx;
+  font-weight: 700;
+}
+
+.scan-bind-room-item-type {
+  color: #94a3b8;
+  font-size: 24rpx;
+  font-weight: 500;
+}
+
+.scan-bind-room-item-check {
+  flex-shrink: 0;
+}
+
+// Footer
+.scan-bind-footer {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 24rpx 32rpx;
+  padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
+  background: #fff;
+  box-shadow: 0 -4rpx 16rpx rgba(15, 23, 42, 0.06);
+  z-index: 10;
+}
+
+// Bound card
+.scan-bind-bound-card {
+  background: #fff;
+  border-radius: 24rpx;
+  overflow: hidden;
+  box-shadow: 0 4rpx 16rpx rgba(15, 23, 42, 0.04);
+  margin-bottom: 32rpx;
+}
+
+.scan-bind-bound-room-no {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 40rpx;
+  background: linear-gradient(135deg, #dbeafe, #c7d2fe);
+
+  text {
+    color: #1e293b;
+    font-size: 64rpx;
+    font-weight: 950;
+  }
+}
+
+.scan-bind-bound-detail {
+  padding: 24rpx 32rpx;
+}
+
+.scan-bind-bound-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 16rpx 0;
+
+  & + & {
+    border-top: 1rpx solid #f1f5f9;
+  }
+}
+
+.scan-bind-bound-label {
+  color: #64748b;
+  font-size: 26rpx;
+  font-weight: 500;
+}
+
+.scan-bind-bound-value {
+  color: #1e293b;
+  font-size: 28rpx;
+  font-weight: 700;
+}
+
+.scan-bind-actions {
+  padding: 0 32rpx;
+}
+
+// Success dialog
+.scan-bind-success-mask {
+  position: fixed;
+  inset: 0;
+  z-index: 999;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(0, 0, 0, 0.5);
+}
+
+.scan-bind-success-dialog {
+  width: 580rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 56rpx 40rpx 40rpx;
+  background: #fff;
+  border-radius: 32rpx;
+  gap: 16rpx;
+}
+
+.scan-bind-success-icon {
+  margin-bottom: 8rpx;
+}
+
+.scan-bind-success-title {
+  color: #1e293b;
+  font-size: 36rpx;
+  font-weight: 900;
+}
+
+.scan-bind-success-desc {
+  color: #64748b;
+  font-size: 26rpx;
+  font-weight: 500;
+  margin-bottom: 24rpx;
+}
+
+.scan-bind-success-icon--warning {
+  background: rgba(253, 230, 138, 0.6);
+}
+
+.scan-bind-confirm-actions {
+  width: 100%;
+  display: flex;
+  gap: 16rpx;
+  padding-top: 8rpx;
+
+  .ai-button {
+    flex: 1;
+  }
+}
+</style>

+ 20 - 1
forge-h5-ui/src/pages/index/index.vue

@@ -242,6 +242,14 @@ const componentDemoItem = {
   bgClass: 'bg-blue',
 }
 
+const scanBindItem = {
+  key: 'scan-bind',
+  label: '扫码绑定',
+  icon: '/static/icons/ai-icon/smartphone.svg',
+  color: '#10b981',
+  bgClass: 'bg-emerald',
+}
+
 const moreMenuItem = {
   key: 'more',
   label: '更多',
@@ -260,10 +268,15 @@ const menuToneList = [
   { icon: '/static/icons/ai-icon/briefcase.svg', color: '#0f766e', bgClass: 'bg-teal' },
 ]
 
+const SCAN_BIND_PERM = 'hotel:qrcode:scan'
+
 const menuItems = computed(() => {
   const backendItems = flattenMenus(authStore.menus)
   const sourceItems = backendItems.length ? backendItems : fallbackMenuItems
-  return [componentDemoItem, ...sourceItems].slice(0, 7).concat(moreMenuItem)
+  const perms = authStore.permissions || []
+  const hasScanBind = perms.includes('*:*:*') || perms.includes(SCAN_BIND_PERM)
+  const prefix = hasScanBind ? [scanBindItem] : []
+  return [...prefix, componentDemoItem, ...sourceItems].slice(0, 7).concat(moreMenuItem)
 })
 
 const menuGroups = computed(() => buildMenuGroups(authStore.menus))
@@ -395,6 +408,8 @@ function isRegisteredH5Route(path) {
     'pages/mine/index',
     'pages/demo/loading/index',
     'pages/app-entry',
+    'pages/hotel/scan-bind',
+    'pages/hotel/qr-scanner',
   ].includes(normalized)
 }
 
@@ -474,6 +489,10 @@ function handleShortcut(item) {
     uni.navigateTo({ url: '/pages/demo/loading/index' })
     return
   }
+  if (item.key === 'scan-bind') {
+    uni.navigateTo({ url: '/pages/hotel/scan-bind' })
+    return
+  }
   if (item.fromBackend) {
     openBackendMenu(item)
     return

+ 3 - 0
forge-h5-ui/vite.config.js

@@ -3,6 +3,7 @@ const require = createRequire(import.meta.url)
 const uniPlugin = require('@dcloudio/vite-plugin-uni')
 
 import { defineConfig, loadEnv } from 'vite'
+import basicSsl from '@vitejs/plugin-basic-ssl'
 import Unocss from 'unocss/vite'
 import AutoImport from 'unplugin-auto-import/vite'
 import Components from 'unplugin-vue-components/vite'
@@ -22,6 +23,7 @@ export default defineConfig(({ mode }) => {
     base: VITE_PUBLIC_PATH || '/',
     plugins: [
       uni(),
+      basicSsl(),
       Unocss(),
       AutoImport({
         imports: ['vue'],
@@ -54,6 +56,7 @@ export default defineConfig(({ mode }) => {
       port: VITE_HTTP_PORT || 3009,
       open: false,
       host: '0.0.0.0',
+      https: true,
       proxy: {
         // Flowable 流程服务代理:待办、审批、流程历史等接口默认走独立 flow-server。
         [`${requestPrefix}/api/flow`]: {

+ 0 - 97
forge-server/db/backup/V1.0.10__dedupe_lowcode_app_menu.sql

@@ -1,99 +0,0 @@
-
-SET @ai_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND path = '/ai'
-  LIMIT 1
-);
-
-SET @lowcode_app_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:domain:list'
-  LIMIT 1
-);
-
-SET @legacy_lowcode_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:list'
-  LIMIT 1
-);
-
-SET @workspace_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:domain:workspace'
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET resource_name = '低代码应用',
-    parent_id = COALESCE(@ai_root_id, parent_id),
-    sort = 12,
-    path = '/ai/lowcode-apps',
-    component = 'ai/lowcode-apps',
-    menu_status = 1,
-    visible = 1,
-    icon = 'ionicons5:ConstructOutline',
-    redirect = NULL,
-    remark = '低代码应用与业务领域管理',
-    update_by = 1,
-    update_time = NOW()
-WHERE @lowcode_app_menu_id IS NOT NULL
-  AND id = @lowcode_app_menu_id;
-
-UPDATE sys_resource
-SET parent_id = @lowcode_app_menu_id,
-    update_by = 1,
-    update_time = NOW()
-WHERE @lowcode_app_menu_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 3
-  AND perms IN ('ai:lowcode:publish', 'ai:lowcode:rollback', 'ai:lowcode:deploy-ddl');
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT rr.tenant_id, rr.role_id, @lowcode_app_menu_id, NOW()
-FROM sys_role_resource rr
-WHERE @lowcode_app_menu_id IS NOT NULL
-  AND @legacy_lowcode_menu_id IS NOT NULL
-  AND rr.resource_id = @legacy_lowcode_menu_id
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @lowcode_app_menu_id
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT rr.tenant_id, rr.role_id, @lowcode_app_menu_id, NOW()
-FROM sys_role_resource rr
-WHERE @lowcode_app_menu_id IS NOT NULL
-  AND @workspace_menu_id IS NOT NULL
-  AND rr.resource_id = @workspace_menu_id
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @lowcode_app_menu_id
-  );
-
-DELETE FROM sys_role_resource
-WHERE (@legacy_lowcode_menu_id IS NOT NULL AND resource_id = @legacy_lowcode_menu_id)
-   OR (@workspace_menu_id IS NOT NULL AND resource_id = @workspace_menu_id);
-
-DELETE FROM sys_resource
-WHERE (@legacy_lowcode_menu_id IS NOT NULL AND id = @legacy_lowcode_menu_id)
-   OR (@workspace_menu_id IS NOT NULL AND id = @workspace_menu_id);

+ 0 - 148
forge-server/db/backup/V1.0.11__reparent_lowcode_menus.sql

@@ -1,153 +0,0 @@
-
-SET @lowcode_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND (path = '/generator' OR resource_name = 'AI代码生成' OR resource_name = 'AI低代码')
-  ORDER BY CASE
-             WHEN path = '/generator' THEN 0
-             WHEN resource_name = 'AI低代码' THEN 1
-             ELSE 2
-           END
-  LIMIT 1
-);
-
-SET @app_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:domain:list'
-  LIMIT 1
-);
-
-SET @model_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:model:list'
-  LIMIT 1
-);
-
-SET @builder_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:edit'
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET resource_name = 'AI低代码',
-    menu_status = 1,
-    visible = 1,
-    always_show = 1,
-    remark = 'AI低代码目录',
-    update_by = 1,
-    update_time = NOW()
-WHERE @lowcode_root_id IS NOT NULL
-  AND id = @lowcode_root_id;
-
-UPDATE sys_resource
-SET resource_name = '模型设计',
-    parent_id = @lowcode_root_id,
-    sort = 1,
-    path = '/ai/lowcode-models',
-    component = 'ai/lowcode-models',
-    menu_status = 1,
-    visible = 1,
-    icon = 'ionicons5:GitBranchOutline',
-    redirect = NULL,
-    remark = '低代码数据模型设计',
-    update_by = 1,
-    update_time = NOW()
-WHERE @lowcode_root_id IS NOT NULL
-  AND @model_menu_id IS NOT NULL
-  AND id = @model_menu_id;
-
-UPDATE sys_resource
-SET resource_name = '应用开发',
-    parent_id = @lowcode_root_id,
-    sort = 2,
-    path = '/ai/lowcode-apps',
-    component = 'ai/lowcode-apps',
-    menu_status = 1,
-    visible = 1,
-    icon = 'ionicons5:ConstructOutline',
-    redirect = NULL,
-    remark = '低代码应用开发与业务领域管理',
-    update_by = 1,
-    update_time = NOW()
-WHERE @lowcode_root_id IS NOT NULL
-  AND @app_menu_id IS NOT NULL
-  AND id = @app_menu_id;
-
-UPDATE sys_resource
-SET resource_name = '应用搭建器',
-    parent_id = @app_menu_id,
-    sort = 99,
-    path = '/ai/lowcode-builder',
-    component = 'ai/lowcode-builder',
-    menu_status = 0,
-    visible = 0,
-    redirect = NULL,
-    remark = '低代码应用搭建器隐藏入口',
-    update_by = 1,
-    update_time = NOW()
-WHERE @app_menu_id IS NOT NULL
-  AND @builder_menu_id IS NOT NULL
-  AND id = @builder_menu_id;
-
-UPDATE sys_resource
-SET parent_id = @app_menu_id,
-    update_by = 1,
-    update_time = NOW()
-WHERE @app_menu_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 3
-  AND perms IN (
-    'ai:lowcode:domain:add',
-    'ai:lowcode:domain:edit',
-    'ai:lowcode:domain:status',
-    'ai:lowcode:domain:move',
-    'ai:lowcode:publish',
-    'ai:lowcode:rollback',
-    'ai:lowcode:deploy-ddl'
-  );
-
-UPDATE sys_resource
-SET parent_id = @model_menu_id,
-    update_by = 1,
-    update_time = NOW()
-WHERE @model_menu_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 3
-  AND perms IN (
-    'ai:lowcode:model:add',
-    'ai:lowcode:model:edit',
-    'ai:lowcode:model:status'
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, @lowcode_root_id, NOW()
-FROM sys_role_resource rr
-JOIN sys_resource r ON r.id = rr.resource_id
-WHERE @lowcode_root_id IS NOT NULL
-  AND rr.tenant_id = 1
-  AND r.tenant_id = 1
-  AND r.perms LIKE 'ai:lowcode:%'
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @lowcode_root_id
-  );

+ 0 - 58
forge-server/db/backup/V1.0.12__add_file_storage_type_dict.sql

@@ -1,60 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT 1, '文件存储类型', 'sys_file_storage_type', 1, '文件存储配置的存储类型选项', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type
-  WHERE tenant_id = 1
-    AND dict_type = 'sys_file_storage_type'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 1, '本地存储', 'local', 'sys_file_storage_type', NULL, 'default', 'Y', 1, '本地磁盘文件存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'local'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 2, 'RustFS存储', 'rustfs', 'sys_file_storage_type', NULL, 'success', 'N', 1, 'RustFS 对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'rustfs'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 3, 'MinIO', 'minio', 'sys_file_storage_type', NULL, 'info', 'N', 1, 'MinIO 对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'minio'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 4, '阿里云OSS', 'aliyun', 'sys_file_storage_type', NULL, 'warning', 'N', 1, '阿里云 OSS 对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'aliyun'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 5, '腾讯云COS', 'tencent', 'sys_file_storage_type', NULL, 'success', 'N', 1, '腾讯云 COS 对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'tencent'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 6, '七牛云', 'qiniu', 'sys_file_storage_type', NULL, 'error', 'N', 1, '七牛云对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 'qiniu'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT 1, 7, 'AWS S3', 's3', 'sys_file_storage_type', NULL, 'primary', 'N', 1, 'AWS S3 对象存储', NOW(), NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data
-  WHERE tenant_id = 1 AND dict_type = 'sys_file_storage_type' AND dict_value = 's3'
-);

+ 0 - 85
forge-server/db/backup/V1.0.13__add_common_business_dicts.sql

@@ -1,87 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '通用正常禁用' dict_name, 'sys_normal_disable' dict_type, 1 dict_status, '通用正常/禁用状态' remark
-  UNION ALL SELECT 1, '通用启用禁用', 'sys_enable_disable', 1, '通用启用/禁用状态'
-  UNION ALL SELECT 1, '通用是否', 'sys_yes_no', 1, '通用是否选项'
-  UNION ALL SELECT 1, '用户类型', 'sys_user_type', 1, '系统用户类型'
-  UNION ALL SELECT 1, '用户状态', 'sys_user_status', 1, '系统用户状态'
-  UNION ALL SELECT 1, '用户性别', 'sys_user_sex', 1, '系统用户性别'
-  UNION ALL SELECT 1, '角色数据范围', 'sys_role_data_scope', 1, '角色数据权限范围'
-  UNION ALL SELECT 1, '岗位类型', 'sys_post_type', 1, '系统岗位类型'
-  UNION ALL SELECT 1, '公告类型', 'sys_notice_type', 1, '通知公告类型'
-  UNION ALL SELECT 1, '公告发布状态', 'sys_notice_status', 1, '通知公告发布状态'
-  UNION ALL SELECT 1, '消息类型', 'sys_message_type', 1, '消息中心消息类型'
-  UNION ALL SELECT 1, '消息渠道', 'sys_message_channel', 1, '消息中心发送渠道'
-  UNION ALL SELECT 1, '消息发送范围', 'sys_message_send_scope', 1, '消息中心发送范围'
-  UNION ALL SELECT 1, '消息发送状态', 'sys_message_send_status', 1, '消息中心发送状态'
-  UNION ALL SELECT 1, '消息阅读状态', 'sys_message_read_status', 1, '消息中心阅读状态'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '正常' dict_label, '1' dict_value, 'sys_normal_disable' dict_type, 'success' list_class, 'Y' is_default, '正常状态' remark
-  UNION ALL SELECT 1, 2, '禁用', '0', 'sys_normal_disable', 'error', 'N', '禁用状态'
-  UNION ALL SELECT 1, 1, '启用', '1', 'sys_enable_disable', 'success', 'Y', '启用状态'
-  UNION ALL SELECT 1, 2, '禁用', '0', 'sys_enable_disable', 'error', 'N', '禁用状态'
-  UNION ALL SELECT 1, 1, '是', '1', 'sys_yes_no', 'success', 'N', '是'
-  UNION ALL SELECT 1, 2, '否', '0', 'sys_yes_no', 'default', 'Y', '否'
-  UNION ALL SELECT 1, 1, '系统管理员', '0', 'sys_user_type', 'warning', 'N', '系统管理员'
-  UNION ALL SELECT 1, 2, '租户管理员', '1', 'sys_user_type', 'info', 'Y', '租户管理员'
-  UNION ALL SELECT 1, 3, '普通用户', '2', 'sys_user_type', 'default', 'N', '普通用户'
-  UNION ALL SELECT 1, 1, '禁用', '0', 'sys_user_status', 'error', 'N', '用户禁用'
-  UNION ALL SELECT 1, 2, '正常', '1', 'sys_user_status', 'success', 'Y', '用户正常'
-  UNION ALL SELECT 1, 3, '锁定', '2', 'sys_user_status', 'warning', 'N', '用户锁定'
-  UNION ALL SELECT 1, 1, '未知', '0', 'sys_user_sex', 'default', 'Y', '性别未知'
-  UNION ALL SELECT 1, 2, '男', '1', 'sys_user_sex', 'info', 'N', '男'
-  UNION ALL SELECT 1, 3, '女', '2', 'sys_user_sex', 'error', 'N', '女'
-  UNION ALL SELECT 1, 1, '全部数据', '1', 'sys_role_data_scope', 'success', 'N', '全部数据权限'
-  UNION ALL SELECT 1, 2, '本租户数据', '2', 'sys_role_data_scope', 'info', 'Y', '本租户数据'
-  UNION ALL SELECT 1, 3, '本组织数据', '3', 'sys_role_data_scope', 'warning', 'N', '本组织数据'
-  UNION ALL SELECT 1, 4, '本组织及子组织', '4', 'sys_role_data_scope', 'warning', 'N', '本组织及子组织'
-  UNION ALL SELECT 1, 5, '个人数据', '5', 'sys_role_data_scope', 'default', 'N', '个人数据'
-  UNION ALL SELECT 1, 7, '本行政区划数据', '7', 'sys_role_data_scope', 'primary', 'N', '本行政区划数据'
-  UNION ALL SELECT 1, 1, '管理岗', '1', 'sys_post_type', 'success', 'N', '管理岗位'
-  UNION ALL SELECT 1, 2, '技术岗', '2', 'sys_post_type', 'info', 'N', '技术岗位'
-  UNION ALL SELECT 1, 3, '业务岗', '3', 'sys_post_type', 'warning', 'N', '业务岗位'
-  UNION ALL SELECT 1, 4, '其他', '4', 'sys_post_type', 'default', 'Y', '其他岗位'
-  UNION ALL SELECT 1, 1, '通知公告', 'NOTICE', 'sys_notice_type', 'info', 'Y', '普通通知公告'
-  UNION ALL SELECT 1, 2, '系统公告', 'ANNOUNCEMENT', 'sys_notice_type', 'warning', 'N', '系统级公告'
-  UNION ALL SELECT 1, 3, '新闻动态', 'NEWS', 'sys_notice_type', 'success', 'N', '新闻动态'
-  UNION ALL SELECT 1, 1, '草稿', '0', 'sys_notice_status', 'default', 'Y', '草稿状态'
-  UNION ALL SELECT 1, 2, '已发布', '1', 'sys_notice_status', 'success', 'N', '已发布状态'
-  UNION ALL SELECT 1, 3, '已撤回', '2', 'sys_notice_status', 'warning', 'N', '已撤回状态'
-  UNION ALL SELECT 1, 1, '系统消息', 'SYSTEM', 'sys_message_type', 'info', 'Y', '系统消息'
-  UNION ALL SELECT 1, 2, '短信', 'SMS', 'sys_message_type', 'warning', 'N', '短信消息'
-  UNION ALL SELECT 1, 3, '邮件', 'EMAIL', 'sys_message_type', 'success', 'N', '邮件消息'
-  UNION ALL SELECT 1, 4, '自定义', 'CUSTOM', 'sys_message_type', 'default', 'N', '自定义消息'
-  UNION ALL SELECT 1, 1, '站内信', 'WEB', 'sys_message_channel', 'default', 'Y', '站内信渠道'
-  UNION ALL SELECT 1, 2, '短信', 'SMS', 'sys_message_channel', 'warning', 'N', '短信渠道'
-  UNION ALL SELECT 1, 3, '邮件', 'EMAIL', 'sys_message_channel', 'success', 'N', '邮件渠道'
-  UNION ALL SELECT 1, 4, '推送', 'PUSH', 'sys_message_channel', 'info', 'N', '推送渠道'
-  UNION ALL SELECT 1, 1, '指定人员', 'USERS', 'sys_message_send_scope', 'info', 'Y', '发送给指定人员'
-  UNION ALL SELECT 1, 2, '指定组织', 'ORG', 'sys_message_send_scope', 'warning', 'N', '发送给指定组织'
-  UNION ALL SELECT 1, 3, '全员', 'ALL', 'sys_message_send_scope', 'success', 'N', '发送给全员'
-  UNION ALL SELECT 1, 1, '草稿', '0', 'sys_message_send_status', 'default', 'Y', '草稿'
-  UNION ALL SELECT 1, 2, '已发送', '1', 'sys_message_send_status', 'success', 'N', '已发送'
-  UNION ALL SELECT 1, 3, '发送失败', '2', 'sys_message_send_status', 'error', 'N', '发送失败'
-  UNION ALL SELECT 1, 1, '未读', '0', 'sys_message_read_status', 'error', 'Y', '未读'
-  UNION ALL SELECT 1, 2, '已读', '1', 'sys_message_read_status', 'success', 'N', '已读'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 98
forge-server/db/backup/V1.0.14__add_flow_business_dicts.sql

@@ -1,100 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '流程表单类型' dict_name, 'flow_form_type' dict_type, 1 dict_status, '流程表单管理使用的表单类型' remark
-  UNION ALL SELECT 1, '流程定义表单类型', 'flow_process_form_type', 1, '流程模型和模板使用的表单类型'
-  UNION ALL SELECT 1, '流程模型状态', 'flow_model_status', 1, '流程模型生命周期状态'
-  UNION ALL SELECT 1, 'SPEL 模板分类', 'flow_spel_category', 1, '审批人 SPEL 模板分类'
-  UNION ALL SELECT 1, '流程版本标记', 'flow_version_tag', 1, '流程模型版本标记'
-  UNION ALL SELECT 1, '流程待办状态', 'flow_todo_status', 1, '我的待办任务状态'
-  UNION ALL SELECT 1, '流程已办状态', 'flow_done_status', 1, '我的已办审批结果'
-  UNION ALL SELECT 1, '我发起的流程状态', 'flow_started_status', 1, '我发起的流程状态'
-  UNION ALL SELECT 1, '流程实例状态', 'flow_instance_status', 1, '流程监控实例状态'
-  UNION ALL SELECT 1, '流程错误日志状态', 'flow_error_log_status', 1, '流程监控错误日志处理状态'
-  UNION ALL SELECT 1, '流程阅读状态', 'flow_read_status', 1, '流程抄送阅读状态'
-  UNION ALL SELECT 1, '流程优先级', 'flow_priority', 1, '流程任务优先级'
-  UNION ALL SELECT 1, '流程条件规则类型', 'flow_rule_type', 1, '流程条件规则业务类型'
-  UNION ALL SELECT 1, '流程条件运算符', 'flow_rule_operator', 1, '流程条件规则运算符'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '动态表单' dict_label, 'dynamic' dict_value, 'flow_form_type' dict_type, 'info' list_class, 'Y' is_default, '动态表单' remark
-  UNION ALL SELECT 1, 2, '外置表单', 'external', 'flow_form_type', 'warning', 'N', '外置表单'
-  UNION ALL SELECT 1, 3, '内置表单', 'builtin', 'flow_form_type', 'success', 'N', '内置表单'
-  UNION ALL SELECT 1, 1, '动态表单', 'dynamic', 'flow_process_form_type', 'info', 'Y', '动态表单'
-  UNION ALL SELECT 1, 2, '外置表单', 'external', 'flow_process_form_type', 'warning', 'N', '外置表单'
-  UNION ALL SELECT 1, 3, '无表单', 'none', 'flow_process_form_type', 'default', 'N', '无表单'
-  UNION ALL SELECT 1, 1, '设计中', '0', 'flow_model_status', 'info', 'Y', '设计中'
-  UNION ALL SELECT 1, 2, '已部署', '1', 'flow_model_status', 'success', 'N', '已部署'
-  UNION ALL SELECT 1, 3, '已挂起', '2', 'flow_model_status', 'warning', 'N', '已挂起'
-  UNION ALL SELECT 1, 4, '已禁用', '3', 'flow_model_status', 'error', 'N', '已禁用'
-  UNION ALL SELECT 1, 1, '通用', 'general', 'flow_spel_category', 'default', 'Y', '通用'
-  UNION ALL SELECT 1, 2, '部门', 'dept', 'flow_spel_category', 'info', 'N', '部门'
-  UNION ALL SELECT 1, 3, '角色', 'role', 'flow_spel_category', 'success', 'N', '角色'
-  UNION ALL SELECT 1, 4, '行政区划', 'region', 'flow_spel_category', 'warning', 'N', '行政区划'
-  UNION ALL SELECT 1, 5, '自定义', 'custom', 'flow_spel_category', 'default', 'N', '自定义'
-  UNION ALL SELECT 1, 1, '草稿', 'draft', 'flow_version_tag', 'default', 'Y', '草稿版本'
-  UNION ALL SELECT 1, 2, '测试', 'test', 'flow_version_tag', 'info', 'N', '测试版本'
-  UNION ALL SELECT 1, 3, '正式发布', 'release', 'flow_version_tag', 'success', 'N', '正式发布版本'
-  UNION ALL SELECT 1, 4, '已废弃', 'deprecated', 'flow_version_tag', 'warning', 'N', '已废弃版本'
-  UNION ALL SELECT 1, 1, '待办', '0', 'flow_todo_status', 'warning', 'Y', '待办'
-  UNION ALL SELECT 1, 2, '已签收', '1', 'flow_todo_status', 'info', 'N', '已签收'
-  UNION ALL SELECT 1, 1, '已通过', '2', 'flow_done_status', 'success', 'Y', '已通过'
-  UNION ALL SELECT 1, 2, '已驳回', '3', 'flow_done_status', 'error', 'N', '已驳回'
-  UNION ALL SELECT 1, 3, '已转办', '4', 'flow_done_status', 'warning', 'N', '已转办'
-  UNION ALL SELECT 1, 4, '已委派', '5', 'flow_done_status', 'info', 'N', '已委派'
-  UNION ALL SELECT 1, 5, '已撤回', '6', 'flow_done_status', 'default', 'N', '已撤回'
-  UNION ALL SELECT 1, 1, '审批中', '0', 'flow_started_status', 'warning', 'Y', '审批中'
-  UNION ALL SELECT 1, 2, '已签收', '1', 'flow_started_status', 'info', 'N', '已签收'
-  UNION ALL SELECT 1, 3, '已通过', '2', 'flow_started_status', 'success', 'N', '已通过'
-  UNION ALL SELECT 1, 4, '已驳回', '3', 'flow_started_status', 'error', 'N', '已驳回'
-  UNION ALL SELECT 1, 5, '已转办', '4', 'flow_started_status', 'warning', 'N', '已转办'
-  UNION ALL SELECT 1, 6, '已委派', '5', 'flow_started_status', 'info', 'N', '已委派'
-  UNION ALL SELECT 1, 7, '已撤回', '6', 'flow_started_status', 'default', 'N', '已撤回'
-  UNION ALL SELECT 1, 1, '运行中', 'running', 'flow_instance_status', 'success', 'Y', '运行中'
-  UNION ALL SELECT 1, 2, '已挂起', 'suspended', 'flow_instance_status', 'warning', 'N', '已挂起'
-  UNION ALL SELECT 1, 3, '已通过', 'approved', 'flow_instance_status', 'success', 'N', '已通过'
-  UNION ALL SELECT 1, 4, '已驳回', 'rejected', 'flow_instance_status', 'error', 'N', '已驳回'
-  UNION ALL SELECT 1, 5, '已取消', 'canceled', 'flow_instance_status', 'default', 'N', '已取消'
-  UNION ALL SELECT 1, 6, '已终止', 'terminated', 'flow_instance_status', 'error', 'N', '已终止'
-  UNION ALL SELECT 1, 1, '未处理', '0', 'flow_error_log_status', 'error', 'Y', '未处理'
-  UNION ALL SELECT 1, 2, '已重试', '1', 'flow_error_log_status', 'success', 'N', '已重试'
-  UNION ALL SELECT 1, 3, '已解决', '2', 'flow_error_log_status', 'default', 'N', '已解决'
-  UNION ALL SELECT 1, 4, '重试失败', '3', 'flow_error_log_status', 'warning', 'N', '重试失败'
-  UNION ALL SELECT 1, 1, '未读', '0', 'flow_read_status', 'error', 'Y', '未读'
-  UNION ALL SELECT 1, 2, '已读', '1', 'flow_read_status', 'success', 'N', '已读'
-  UNION ALL SELECT 1, 1, '低', '0', 'flow_priority', 'default', 'N', '低优先级'
-  UNION ALL SELECT 1, 2, '普通', '1', 'flow_priority', 'default', 'Y', '普通优先级'
-  UNION ALL SELECT 1, 3, '高', '2', 'flow_priority', 'warning', 'N', '高优先级'
-  UNION ALL SELECT 1, 4, '紧急', '3', 'flow_priority', 'error', 'N', '紧急优先级'
-  UNION ALL SELECT 1, 1, '处理条件', 'approval', 'flow_rule_type', 'info', 'Y', '处理条件'
-  UNION ALL SELECT 1, 2, '流转条件', 'flow', 'flow_rule_type', 'success', 'N', '流转条件'
-  UNION ALL SELECT 1, 3, '通知条件', 'notify', 'flow_rule_type', 'warning', 'N', '通知条件'
-  UNION ALL SELECT 1, 1, '等于', 'eq', 'flow_rule_operator', 'default', 'Y', '等于'
-  UNION ALL SELECT 1, 2, '不等于', 'ne', 'flow_rule_operator', 'default', 'N', '不等于'
-  UNION ALL SELECT 1, 3, '大于', 'gt', 'flow_rule_operator', 'default', 'N', '大于'
-  UNION ALL SELECT 1, 4, '大于等于', 'ge', 'flow_rule_operator', 'default', 'N', '大于等于'
-  UNION ALL SELECT 1, 5, '小于', 'lt', 'flow_rule_operator', 'default', 'N', '小于'
-  UNION ALL SELECT 1, 6, '小于等于', 'le', 'flow_rule_operator', 'default', 'N', '小于等于'
-  UNION ALL SELECT 1, 7, '包含', 'contains', 'flow_rule_operator', 'default', 'N', '包含'
-  UNION ALL SELECT 1, 8, '为空', 'empty', 'flow_rule_operator', 'default', 'N', '为空'
-  UNION ALL SELECT 1, 9, '不为空', 'notEmpty', 'flow_rule_operator', 'default', 'N', '不为空'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 56
forge-server/db/backup/V1.0.15__add_data_module_dicts.sql

@@ -1,58 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '数据库类型' dict_name, 'data_db_type' dict_type, 1 dict_status, '数据连接支持的数据库类型' remark
-  UNION ALL SELECT 1, '维度来源类型', 'data_dimension_source_type', 1, '维度值录入方式'
-  UNION ALL SELECT 1, '数据集类型', 'data_dataset_type', 1, '数据集建模方式'
-  UNION ALL SELECT 1, '数据集发布状态', 'data_dataset_publish_status', 1, '数据集生命周期发布状态'
-  UNION ALL SELECT 1, '数据集访问模式', 'data_dataset_access_mode', 1, '数据集访问权限范围'
-  UNION ALL SELECT 1, '授权主体类型', 'data_acl_subject_type', 1, '数据集授权主体类型'
-  UNION ALL SELECT 1, '访问级别', 'data_acl_access_level', 1, '数据集授权访问级别'
-  UNION ALL SELECT 1, '字段角色', 'data_field_role', 1, '数据集字段角色类型'
-  UNION ALL SELECT 1, '敏感级别', 'data_field_sensitive_level', 1, '数据集字段敏感级别'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, 'MySQL' dict_label, 'MYSQL' dict_value, 'data_db_type' dict_type, 'success' list_class, 'Y' is_default, 'MySQL数据库' remark
-  UNION ALL SELECT 1, 2, 'Oracle', 'ORACLE', 'data_db_type', 'default', 'N', 'Oracle数据库'
-  UNION ALL SELECT 1, 3, 'PostgreSQL', 'POSTGRESQL', 'data_db_type', 'info', 'N', 'PostgreSQL数据库'
-  UNION ALL SELECT 1, 4, 'SQLServer', 'SQLSERVER', 'data_db_type', 'warning', 'N', 'SQLServer数据库'
-  UNION ALL SELECT 1, 1, '手动维护', 'MANUAL' dict_value, 'data_dimension_source_type' dict_type, 'info' list_class, 'Y' is_default, '手动维护维度值' remark
-  UNION ALL SELECT 1, 2, 'SQL同步', 'SQL', 'data_dimension_source_type', 'warning', 'N', '从数据源同步维度值'
-  UNION ALL SELECT 1, 1, '单表数据集', 'TABLE' dict_value, 'data_dataset_type' dict_type, 'info' list_class, 'Y' is_default, '单表数据集' remark
-  UNION ALL SELECT 1, 2, 'SQL数据集', 'SQL', 'data_dataset_type', 'warning', 'N', 'SQL数据集'
-  UNION ALL SELECT 1, 1, '未发布', '0' dict_value, 'data_dataset_publish_status' dict_type, 'default' list_class, 'Y' is_default, '草稿状态' remark
-  UNION ALL SELECT 1, 2, '已发布', '1', 'data_dataset_publish_status', 'success', 'N', '已发布状态'
-  UNION ALL SELECT 1, 3, '已下架', '2', 'data_dataset_publish_status', 'warning', 'N', '已下架状态'
-  UNION ALL SELECT 1, 1, '公开', 'PUBLIC' dict_value, 'data_dataset_access_mode' dict_type, 'success' list_class, 'Y' is_default, '公开访问' remark
-  UNION ALL SELECT 1, 2, '私有', 'PRIVATE', 'data_dataset_access_mode', 'warning', 'N', '私有访问'
-  UNION ALL SELECT 1, 1, '角色', 'ROLE' dict_value, 'data_acl_subject_type' dict_type, 'info' list_class, 'Y' is_default, '角色授权' remark
-  UNION ALL SELECT 1, 2, '用户', 'USER', 'data_acl_subject_type', 'success', 'N', '用户授权'
-  UNION ALL SELECT 1, 3, '组织', 'ORG', 'data_acl_subject_type', 'warning', 'N', '组织授权'
-  UNION ALL SELECT 1, 1, '查看', 'VIEW' dict_value, 'data_acl_access_level' dict_type, 'info' list_class, 'Y' is_default, '查看权限' remark
-  UNION ALL SELECT 1, 2, '查询', 'QUERY', 'data_acl_access_level', 'success', 'N', '查询权限'
-  UNION ALL SELECT 1, 3, '管理', 'MANAGE', 'data_acl_access_level', 'warning', 'N', '管理权限'
-  UNION ALL SELECT 1, 1, '维度', 'DIMENSION' dict_value, 'data_field_role' dict_type, 'info' list_class, 'Y' is_default, '维度字段' remark
-  UNION ALL SELECT 1, 2, '指标', 'MEASURE', 'data_field_role', 'success', 'N', '指标字段'
-  UNION ALL SELECT 1, 1, '不脱敏', 'NONE' dict_value, 'data_field_sensitive_level' dict_type, 'default' list_class, 'Y' is_default, '不脱敏' remark
-  UNION ALL SELECT 1, 2, '脱敏展示', 'MASK', 'data_field_sensitive_level', 'warning', 'N', '脱敏展示'
-  UNION ALL SELECT 1, 3, '隐藏字段', 'HIDDEN', 'data_field_sensitive_level', 'error', 'N', '隐藏字段'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 50
forge-server/db/backup/V1.0.16__add_ai_lowcode_dicts.sql

@@ -1,52 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '提示词适用场景' dict_name, 'ai_prompt_usage_scene' dict_type, 1 dict_status, 'AI提示词模板适用场景' remark
-  UNION ALL SELECT 1, '提示词状态', 'ai_prompt_status', 1, 'AI提示词模板状态'
-  UNION ALL SELECT 1, '提示词是否推荐', 'ai_prompt_recommended', 1, 'AI提示词模板推荐标记'
-  UNION ALL SELECT 1, '大屏生成状态', 'ai_dashboard_generate_status', 1, 'AI大屏生成记录状态'
-  UNION ALL SELECT 1, '低代码应用发布状态', 'lowcode_app_publish_status', 1, '低代码应用发布生命周期状态'
-  UNION ALL SELECT 1, '低代码模型状态', 'lowcode_model_status', 1, '低代码数据模型状态'
-  UNION ALL SELECT 1, 'AI上下文类型', 'ai_context_type', 1, 'AI上下文配置类型'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, 'AI大屏生成' dict_label, 'dashboard_generate' dict_value, 'ai_prompt_usage_scene' dict_type, 'success' list_class, 'Y' is_default, 'AI大屏生成场景' remark
-  UNION ALL SELECT 1, 2, '通用对话', 'chat', 'ai_prompt_usage_scene', 'info', 'N', '通用对话场景'
-  UNION ALL SELECT 1, 3, '代码生成', 'code_generate', 'ai_prompt_usage_scene', 'warning', 'N', '代码生成场景'
-  UNION ALL SELECT 1, 4, '流程编排', 'flow_design', 'ai_prompt_usage_scene', 'primary', 'N', '流程编排场景'
-  UNION ALL SELECT 1, 1, '启用', '0', 'ai_prompt_status', 'success', 'Y', '启用状态' remark
-  UNION ALL SELECT 1, 2, '停用', '1', 'ai_prompt_status', 'error', 'N', '停用状态'
-  UNION ALL SELECT 1, 1, '推荐', '1', 'ai_prompt_recommended', 'success', 'N', '推荐模板' remark
-  UNION ALL SELECT 1, 2, '普通', '0', 'ai_prompt_recommended', 'default', 'Y', '普通模板'
-  UNION ALL SELECT 1, 1, '成功', 'success', 'ai_dashboard_generate_status', 'success', 'Y', '生成成功' remark
-  UNION ALL SELECT 1, 2, '失败', 'failed', 'ai_dashboard_generate_status', 'error', 'N', '生成失败'
-  UNION ALL SELECT 1, 3, '解析失败', 'parse_failed', 'ai_dashboard_generate_status', 'warning', 'N', '解析失败'
-  UNION ALL SELECT 1, 4, '已停止', 'stopped', 'ai_dashboard_generate_status', 'default', 'N', '已停止'
-  UNION ALL SELECT 1, 1, '草稿', 'DRAFT', 'lowcode_app_publish_status', 'default', 'Y', '草稿状态' remark
-  UNION ALL SELECT 1, 2, '已发布', 'PUBLISHED', 'lowcode_app_publish_status', 'success', 'N', '已发布状态'
-  UNION ALL SELECT 1, 3, '已停用', 'STOPPED', 'lowcode_app_publish_status', 'warning', 'N', '已停用状态'
-  UNION ALL SELECT 1, 1, '启用', 'ENABLED', 'lowcode_model_status', 'success', 'Y', '启用状态' remark
-  UNION ALL SELECT 1, 2, '停用', 'DISABLED', 'lowcode_model_status', 'warning', 'N', '停用状态'
-  UNION ALL SELECT 1, 1, 'SPEC', 'SPEC', 'ai_context_type', 'info', 'Y', 'SPEC类型' remark
-  UNION ALL SELECT 1, 2, 'SAMPLE', 'SAMPLE', 'ai_context_type', 'success', 'N', 'SAMPLE类型'
-  UNION ALL SELECT 1, 3, 'RULE', 'RULE', 'ai_context_type', 'warning', 'N', 'RULE类型'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 101
forge-server/db/backup/V1.0.17__add_system_module_dicts.sql

@@ -1,103 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '登录类型' dict_name, 'sys_login_type' dict_type, 1 dict_status, '登录行为类型' remark
-  UNION ALL SELECT 1, '客户端类型', 'sys_client_type', 1, '登录客户端类型'
-  UNION ALL SELECT 1, '通用成功失败', 'sys_common_status', 1, '通用成功/失败状态'
-  UNION ALL SELECT 1, '操作类型', 'sys_operation_type', 1, '操作日志类型'
-  UNION ALL SELECT 1, '任务状态', 'sys_job_status', 1, '定时任务运行状态'
-  UNION ALL SELECT 1, '任务执行模式', 'sys_job_run_mode', 1, '定时任务执行模式'
-  UNION ALL SELECT 1, '请求方法', 'sys_req_method', 1, 'HTTP请求方法'
-  UNION ALL SELECT 1, '资源类型', 'sys_resource_type', 1, '菜单资源类型'
-  UNION ALL SELECT 1, '显示状态', 'sys_show_hide', 1, '菜单显示/隐藏'
-  UNION ALL SELECT 1, '链接打开方式', 'sys_link_open_target', 1, '链接打开目标'
-  UNION ALL SELECT 1, '参数内置类型', 'sys_config_type', 1, '系统参数是否内置'
-  UNION ALL SELECT 1, '文件分组类型', 'sys_file_group_type', 1, '文件分组类型'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  -- sys_login_type: 登录类型
-  SELECT 1 tenant_id, 1 dict_sort, '登录' dict_label, 'LOGIN' dict_value, 'sys_login_type' dict_type, 'success' list_class, 'Y' is_default, '用户登录' remark
-  UNION ALL SELECT 1, 2, '登出', 'LOGOUT', 'sys_login_type', 'default', 'N', '用户登出'
-  UNION ALL SELECT 1, 3, '注册', 'REGISTER', 'sys_login_type', 'info', 'N', '用户注册'
-  UNION ALL SELECT 1, 4, '被踢下线', 'KICKOUT', 'sys_login_type', 'error', 'N', '被踢下线'
-  UNION ALL SELECT 1, 5, '被顶下线', 'REPLACED', 'sys_login_type', 'warning', 'N', '被顶下线'
-  
-  -- sys_client_type: 客户端类型
-  UNION ALL SELECT 1, 1, '桌面端', 'pc', 'sys_client_type', 'info', 'Y', 'PC桌面端'
-  UNION ALL SELECT 1, 2, '移动APP', 'app', 'sys_client_type', 'success', 'N', '移动应用'
-  UNION ALL SELECT 1, 3, '网页H5', 'h5', 'sys_client_type', 'warning', 'N', 'H5网页'
-  UNION ALL SELECT 1, 4, '微信', 'wechat', 'sys_client_type', 'error', 'N', '微信客户端'
-  
-  -- sys_common_status: 通用成功失败
-  UNION ALL SELECT 1, 1, '成功', '1', 'sys_common_status', 'success', 'Y', '成功状态'
-  UNION ALL SELECT 1, 2, '失败', '0', 'sys_common_status', 'error', 'N', '失败状态'
-  
-  -- sys_operation_type: 操作类型
-  UNION ALL SELECT 1, 1, '查询', 'QUERY', 'sys_operation_type', 'info', 'Y', '查询操作'
-  UNION ALL SELECT 1, 2, '新增', 'INSERT', 'sys_operation_type', 'success', 'N', '新增操作'
-  UNION ALL SELECT 1, 3, '更新', 'UPDATE', 'sys_operation_type', 'warning', 'N', '更新操作'
-  UNION ALL SELECT 1, 4, '删除', 'DELETE', 'sys_operation_type', 'error', 'N', '删除操作'
-  UNION ALL SELECT 1, 5, '导入', 'IMPORT', 'sys_operation_type', 'info', 'N', '导入操作'
-  UNION ALL SELECT 1, 6, '导出', 'EXPORT', 'sys_operation_type', 'success', 'N', '导出操作'
-  UNION ALL SELECT 1, 7, '其他', 'OTHER', 'sys_operation_type', 'default', 'N', '其他操作'
-  
-  -- sys_job_status: 任务状态
-  UNION ALL SELECT 1, 1, '停止', '0', 'sys_job_status', 'default', 'Y', '任务停止'
-  UNION ALL SELECT 1, 2, '运行中', '1', 'sys_job_status', 'success', 'N', '任务运行'
-  
-  -- sys_job_run_mode: 任务执行模式
-  UNION ALL SELECT 1, 1, 'Bean模式(本地调用)', 'BEAN', 'sys_job_run_mode', 'info', 'Y', 'Bean模式'
-  UNION ALL SELECT 1, 2, 'Handler模式(扩展调用)', 'HANDLER', 'sys_job_run_mode', 'success', 'N', 'Handler模式'
-  
-  -- sys_req_method: 请求方法
-  UNION ALL SELECT 1, 1, 'GET', 'GET', 'sys_req_method', 'info', 'Y', 'GET请求'
-  UNION ALL SELECT 1, 2, 'POST', 'POST', 'sys_req_method', 'success', 'N', 'POST请求'
-  UNION ALL SELECT 1, 3, 'PUT', 'PUT', 'sys_req_method', 'warning', 'N', 'PUT请求'
-  UNION ALL SELECT 1, 4, 'DELETE', 'DELETE', 'sys_req_method', 'error', 'N', 'DELETE请求'
-  UNION ALL SELECT 1, 5, 'ALL', 'ALL', 'sys_req_method', 'default', 'N', '所有方法'
-  
-  -- sys_resource_type: 资源类型
-  UNION ALL SELECT 1, 1, '目录', '1', 'sys_resource_type', 'info', 'Y', '目录类型'
-  UNION ALL SELECT 1, 2, '菜单', '2', 'sys_resource_type', 'success', 'N', '菜单类型'
-  UNION ALL SELECT 1, 3, '按钮', '3', 'sys_resource_type', 'warning', 'N', '按钮类型'
-  UNION ALL SELECT 1, 4, 'API接口', '4', 'sys_resource_type', 'error', 'N', 'API接口类型'
-  
-  -- sys_show_hide: 显示状态
-  UNION ALL SELECT 1, 1, '显示', '1', 'sys_show_hide', 'success', 'Y', '显示状态'
-  UNION ALL SELECT 1, 2, '隐藏', '0', 'sys_show_hide', 'default', 'N', '隐藏状态'
-  
-  -- sys_link_open_target: 链接打开方式
-  UNION ALL SELECT 1, 1, '当前页', '_self', 'sys_link_open_target', 'info', 'Y', '当前页面打开'
-  UNION ALL SELECT 1, 2, '新窗口', '_blank', 'sys_link_open_target', 'success', 'N', '新窗口打开'
-  
-  -- sys_config_type: 参数内置类型(Y/N)
-  UNION ALL SELECT 1, 1, '是', 'Y', 'sys_config_type', 'success', 'N', '系统内置参数'
-  UNION ALL SELECT 1, 2, '否', 'N', 'sys_config_type', 'default', 'Y', '非内置参数'
-  
-  -- sys_file_group_type: 文件分组类型
-  UNION ALL SELECT 1, 1, '默认', 'default', 'sys_file_group_type', 'default', 'Y', '默认分组'
-  UNION ALL SELECT 1, 2, '文档', 'document', 'sys_file_group_type', 'info', 'N', '文档分组'
-  UNION ALL SELECT 1, 3, '图片', 'image', 'sys_file_group_type', 'success', 'N', '图片分组'
-  UNION ALL SELECT 1, 4, '视频', 'video', 'sys_file_group_type', 'warning', 'N', '视频分组'
-  UNION ALL SELECT 1, 5, '音频', 'audio', 'sys_file_group_type', 'info', 'N', '音频分组'
-  UNION ALL SELECT 1, 6, '压缩包', 'archive', 'sys_file_group_type', 'default', 'N', '压缩包分组'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 120
forge-server/db/backup/V1.0.18__add_flow_approval_action_control.sql

@@ -1,121 +0,0 @@
-
-SET @node_config_table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-);
-
-SET @flow_task_table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_task'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'allow_approve'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN allow_approve tinyint DEFAULT 1 COMMENT ''允许通过'' AFTER timeout_action',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'allow_return'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN allow_return tinyint DEFAULT 0 COMMENT ''允许退回上一审批节点'' AFTER allow_counter_sign',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'allow_terminate'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN allow_terminate tinyint DEFAULT 0 COMMENT ''允许终结流程'' AFTER allow_return',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'require_signature'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN require_signature tinyint DEFAULT 0 COMMENT ''办理时需要签名'' AFTER allow_terminate',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'require_comment'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN require_comment tinyint DEFAULT 1 COMMENT ''办理时需要审批意见'' AFTER require_signature',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_task'
-    AND column_name = 'signature'
-);
-SET @ddl := IF(@flow_task_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_task ADD COLUMN signature text COMMENT ''审批签名'' AFTER comment',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, 'N', 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 8 dict_sort, '已退回' dict_label, '7' dict_value, 'flow_todo_status' dict_type, 'warning' list_class, '审批任务已退回上一节点' remark
-  UNION ALL SELECT 1, 9, '已终结', '8', 'flow_todo_status', 'error', '审批人终结流程'
-  UNION ALL SELECT 1, 6, '已退回', '7', 'flow_done_status', 'warning', '审批任务已退回上一节点'
-  UNION ALL SELECT 1, 7, '已终结', '8', 'flow_done_status', 'error', '审批人终结流程'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);

+ 0 - 146
forge-server/db/backup/V1.0.19__unify_lowcode_app_codegen_menus.sql

@@ -1,148 +0,0 @@
-
-SET @app_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:domain:list'
-  LIMIT 1
-);
-
-SET @model_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:model:list'
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET resource_name = '应用开发',
-    path = '/ai/lowcode-apps',
-    component = 'ai/lowcode-apps',
-    menu_status = 1,
-    visible = 1,
-    remark = '低代码应用设计、AI创建、发布运行和代码输出主入口',
-    update_by = 1,
-    update_time = NOW()
-WHERE @app_menu_id IS NOT NULL
-  AND id = @app_menu_id;
-
-UPDATE sys_resource
-SET resource_name = '模型设计',
-    path = '/ai/lowcode-models',
-    component = 'ai/lowcode-models',
-    menu_status = 1,
-    visible = 1,
-    remark = '低代码数据模型资产设计入口',
-    update_by = 1,
-    update_time = NOW()
-WHERE @model_menu_id IS NOT NULL
-  AND id = @model_menu_id;
-
-UPDATE sys_resource
-SET menu_status = 0,
-    visible = 0,
-    remark = CONCAT(COALESCE(remark, ''), ';统一低代码代码生成后隐藏旧入口'),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND (
-    path IN ('/generator/table', '/generator/template', '/ai/crud-config', '/ai/crud-generator', '/ai/page-template')
-    OR component IN ('generator/table', 'generator/template', 'ai/crud-config', 'ai/crud-generator', 'ai/page-template')
-    OR perms IN ('ai:crud-config:list', 'ai:crud-gen:list', 'ai:crud-generator:use', 'ai:page-template:list')
-  );
-
-UPDATE sys_resource
-SET menu_status = 1,
-    visible = 1,
-    remark = COALESCE(remark, '代码生成数据源管理'),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND (path = '/generator/datasource' OR component = 'generator/datasource');
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, 'AI创建应用', @app_menu_id, 3, 11, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:ai-generate', NULL,
-       NULL, NULL, 0, 0, NULL, 'AI生成低代码模型和应用草稿按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @app_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:ai-generate'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '代码预览', @app_menu_id, 3, 12, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:code-preview', NULL,
-       NULL, NULL, 0, 0, NULL, '低代码应用代码预览按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @app_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:code-preview'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '下载代码', @app_menu_id, 3, 13, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:code-download', NULL,
-       NULL, NULL, 0, 0, NULL, '低代码应用代码下载按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @app_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:code-download'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '导入数据源表', @model_menu_id, 3, 11, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:model:import-table', NULL,
-       NULL, NULL, 0, 0, NULL, '从数据源表导入低代码模型按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @model_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:model:import-table'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, 'AI生成模型', @model_menu_id, 3, 12, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:model:ai-generate', NULL,
-       NULL, NULL, 0, 0, NULL, 'AI生成低代码模型草稿按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @model_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:model:ai-generate'
-  );

+ 0 - 64
forge-server/db/backup/V1.0.1__add_dashboard_version_and_record_audit.sql

@@ -1,65 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_report_project_version` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `project_id` bigint NOT NULL COMMENT '大屏项目ID',
-  `project_name` varchar(100) NOT NULL COMMENT '大屏项目名称',
-  `version_no` int NOT NULL COMMENT '版本号',
-  `version_name` varchar(32) NOT NULL COMMENT '版本名称',
-  `operation_type` varchar(20) NOT NULL DEFAULT 'publish' COMMENT '操作类型:publish发布 rollback回退',
-  `source_version_id` bigint DEFAULT NULL COMMENT '回退来源版本ID',
-  `publisher_id` bigint DEFAULT NULL COMMENT '发布人ID',
-  `publisher_name` varchar(100) DEFAULT NULL COMMENT '发布人名称',
-  `publish_time` datetime DEFAULT NULL COMMENT '发布时间',
-  `publish_url` varchar(500) DEFAULT NULL COMMENT '发布地址',
-  `index_img` varchar(500) DEFAULT NULL COMMENT '封面图文件ID',
-  `canvas_width` int DEFAULT NULL COMMENT '画布宽度',
-  `canvas_height` int DEFAULT NULL COMMENT '画布高度',
-  `background_color` varchar(20) DEFAULT NULL COMMENT '背景颜色',
-  `component_data` longtext COMMENT '组件配置JSON',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建者',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新者',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_report_project_version_no` (`tenant_id`, `project_id`, `version_no`),
-  KEY `idx_report_project_version_project` (`tenant_id`, `project_id`, `create_time`),
-  KEY `idx_report_project_version_publisher` (`tenant_id`, `publisher_id`, `publish_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='大屏项目发布版本表';
-
-SET @ai_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND path = '/ai'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '大屏生成记录', @ai_root_id, 2, 4, '/ai/dashboard-generate-record', 'ai/dashboard-generate-record', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:dashboard-record:list', 'ionicons5:ReceiptOutline',
-       NULL, NULL, 1, 0, NULL, 'AI大屏生成记录稽核', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @ai_root_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 2
-      AND perms = 'ai:dashboard-record:list'
-  );
-
-SET @dashboard_record_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:dashboard-record:list'
-  LIMIT 1
-);

+ 0 - 147
forge-server/db/backup/V1.0.20__add_lowcode_system_generator_agent.sql

@@ -1,149 +0,0 @@
-
-INSERT INTO ai_agent (tenant_id, agent_name, agent_code, description, system_prompt, provider_id, model_name,
-                      temperature, max_tokens, extra_config, status, create_by, create_time, update_by, update_time,
-                      del_flag, create_dept)
-SELECT 1,
-       '低代码业务系统生成 Agent',
-       'lowcode_system_generator',
-       '根据用户业务需求自动划分业务领域、生成数据模型和低代码应用草稿',
-       '你是 Forge 低代码业务系统生成 Agent。用户只输入完整业务需求,你需要自动完成业务领域划分、数据模型设计、应用页面规划和页面模板选择。你必须只输出一个合法 JSON 对象,不输出 Markdown、解释、注释或额外前后缀。输出内容必须遵守已注入的低代码协议上下文。AI 结果只能作为草稿建议,不能自动保存、不能执行 DDL、不能发布应用,必须等待用户确认。',
-       NULL,
-       NULL,
-       0.30,
-       6000,
-       JSON_OBJECT('scene', 'lowcode-system-generator', 'saveMode', 'confirm-before-save'),
-       '0',
-       1,
-       NOW(),
-       1,
-       NOW(),
-       '0',
-       1
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_agent
-    WHERE agent_code = 'lowcode_system_generator'
-);
-
-INSERT INTO ai_context_config (tenant_id, agent_code, config_name, config_content, config_type, sort, status,
-                               create_by, create_time, create_dept, update_by, update_time)
-SELECT 1,
-       'lowcode_system_generator',
-       '低代码业务系统生成规则',
-       '## 生成目标
-- 从用户需求自动识别业务边界,划分业务领域。
-- 为每个核心业务对象生成 LowcodeModelSchema 数据模型草稿。
-- 为每个可交付业务页面生成 LowcodeAppDraftDTO 应用草稿。
-- 页面模板由 Agent 自动选择,用户不需要提前选择模板。
-- 生成过程必须能被前端展示为清晰步骤和决策摘要。
-
-## 安全与保存规则
-- 不允许自动保存模型、业务领域或应用。
-- 不允许执行 DDL。
-- 不允许发布应用。
-- 不允许生成真实密钥、数据库密码、Token、AK/SK。
-- 必须在 generationNotes 中说明 AI 结果需要用户确认后保存。
-
-## 领域规划规则
-- 如果需求命中已有业务领域语义,应优先复用已有领域编码。
-- 如果无法判断已有领域,返回新的领域草稿。
-- 新领域 domainCode 使用小写字母开头,仅含小写字母、数字、下划线。
-- 新领域 tablePrefix 默认 biz_{domainCode}_,configKeyPrefix 默认 {domainCode}_。
-
-## 模板选择规则
-- 标准列表、查询、编辑、详情场景使用 simple-crud。
-- 部门、组织、分类、类目、目录、父子层级、树形管理场景使用 tree-crud,并补充 parentId 和 treeConfig。
-- 明细、子项、订单行等主子表场景可以使用 master-detail-crud;如果首期无法完整表达,拆成多个 simple-crud 应用,并在 decisions 中说明。
-
-## 字段规则
-- 不要生成 id、tenant_id、create_by、create_time、create_dept、update_by、update_time、del_flag 等审计字段。
-- 字段名使用 lowerCamel,数据库列名使用 lower_snake。
-- dataType 只能使用 varchar、char、text、longtext、int、bigint、decimal、date、datetime、time、tinyint。
-- componentType 只能使用 input、textarea、select、radio、checkbox、switch、date、datetime、time、number、upload、imageUpload、fileUpload、cascader、treeSelect、dictSelect、orgTreeSelect、userSelect、regionTreeSelect。
-- 手机号、身份证、邮箱、银行卡、人名、地址等敏感字段必须设置 sensitiveType。',
-       'RULE',
-       10,
-       '0',
-       1,
-       NOW(),
-       1,
-       1,
-       NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_context_config
-    WHERE tenant_id = 1
-      AND agent_code = 'lowcode_system_generator'
-      AND config_name = '低代码业务系统生成规则'
-);
-
-INSERT INTO ai_context_config (tenant_id, agent_code, config_name, config_content, config_type, sort, status,
-                               create_by, create_time, create_dept, update_by, update_time)
-SELECT 1,
-       'lowcode_system_generator',
-       '低代码 Agent 输出协议',
-       '## 输出 JSON 根字段
-必须输出一个兼容 LowcodeAiAppGenerateResult 的 JSON 对象,字段如下:
-- requirementSummary:需求摘要。
-- domainSuggestion:主领域建议名称。
-- steps:生成步骤数组,用于前端展示过程。
-- decisions:决策摘要数组,用于解释领域、模型、模板和保存策略。
-- domains:业务领域草稿数组。
-- models:数据模型草稿数组。
-- apps:应用草稿数组。
-- modelDraft、appDraft、modelSchema、pageSchema:兼容字段,取第一个模型和第一个应用。
-- generationNotes:面向用户的注意事项。
-- fallback:false。
-
-## steps 元素
-字段:orderNo、stepKey、title、status、message、summary。
-stepKey 固定使用 analyzing、domain-planning、model-generating、page-generating、validating。
-status 使用 completed。
-
-## decisions 元素
-字段:decisionType、title、target、value、reason、meta。
-decisionType 可使用 domain、model、template、save。
-reason 只写可审计的摘要依据,不输出不可控的内部推理链。
-
-## domains 元素
-字段:existingDomainId、domainCode、domainName、domainDesc、icon、sort、status、menuParentId、tablePrefix、configKeyPrefix、defaultAppType、defaultLayoutType、defaultTableMode、domainSchema、objectCodes。
-existingDomainId 不确定时置空。
-status 使用 ENABLED,defaultAppType 使用 SINGLE,defaultLayoutType 使用 simple-crud,defaultTableMode 使用 CREATE。
-
-## models 元素
-字段:id、domainId、modelCode、modelName、modelDesc、status、tenantEnabled、masterData、modelSchema、syncDdl、confirmSyncDdl。
-id 置空,domainId 不确定时置空,status 使用 ENABLED,tenantEnabled=true,masterData=false,syncDdl=false,confirmSyncDdl=false。
-
-## modelSchema
-字段:schemaVersion、domain、object、appType、tableMode、tableName、businessName、treeConfig、fields、relations、indexes、policies、children。
-schemaVersion=2,tableMode=CREATE。
-domain 包含 id、code、name;id 不确定时置空。
-object 包含 code、name、description。
-fields 至少包含 4 个业务字段。
-
-## apps 元素
-字段:id、configKey、appName、domainId、domainCode、domainName、objectCode、objectName、menuName、menuParentId、menuSort、modelSchema、pageSchema。
-id 置空,domainId 不确定时置空。
-configKey 使用领域 configKeyPrefix + objectCode。
-
-## pageSchema
-字段:layoutType、primaryModelCode、modelRefs、zones。
-zones 至少包含 search、table、edit、detail。
-每个 zone 字段:zoneKey、componentKey、enabled、fieldRefs、props。',
-       'SPEC',
-       20,
-       '0',
-       1,
-       NOW(),
-       1,
-       1,
-       NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_context_config
-    WHERE tenant_id = 1
-      AND agent_code = 'lowcode_system_generator'
-      AND config_name = '低代码 Agent 输出协议'
-);

+ 0 - 27
forge-server/db/backup/V1.0.21__tune_lowcode_agent_domain_reuse.sql

@@ -1,28 +0,0 @@
-
-INSERT INTO ai_context_config (tenant_id, agent_code, config_name, config_content, config_type, sort, status,
-                               create_by, create_time, create_dept, update_by, update_time)
-SELECT 1,
-       'lowcode_system_generator',
-       '低代码已有领域复用规则',
-       '## 已有业务领域复用规则
-- 当用户指定目标业务领域时,必须优先在该已有领域中生成模型和应用。
-- 输出 domains[0].existingDomainId 必须等于用户指定的 domainId。
-- 输出 domains[0].domainCode、domainName 必须与用户指定领域保持一致。
-- 除非用户需求明确要求跨领域拆分,否则不要新建业务领域。
-- 模型 modelSchema.domain 和应用 domainCode/domainName 需要与目标领域一致。',
-       'RULE',
-       15,
-       '0',
-       1,
-       NOW(),
-       1,
-       1,
-       NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_context_config
-    WHERE tenant_id = 1
-      AND agent_code = 'lowcode_system_generator'
-      AND config_name = '低代码已有领域复用规则'
-);

+ 0 - 27
forge-server/db/backup/V1.0.22__tune_lowcode_agent_single_domain_prefix.sql

@@ -1,28 +0,0 @@
-
-INSERT INTO ai_context_config (tenant_id, agent_code, config_name, config_content, config_type, sort, status,
-                               create_by, create_time, create_dept, update_by, update_time)
-SELECT 1,
-       'lowcode_system_generator',
-       '低代码单领域和命名规则',
-       '## 单领域和命名规则
-- 当用户描述中出现“一个业务领域”“同一个业务领域”“不要分开”“不要拆分”等表达时,必须只输出一个业务领域。
-- 单领域场景下,多个业务对象可以生成多个模型和应用,但 domains 数组只能有一个元素,所有 modelSchema.domain 和 app.domainCode 必须一致。
-- 当用户指定表名前缀时,例如“表名以 tf_f_ 开头”,所有 modelSchema.tableName 必须使用该前缀。
-- 商品基本信息和商品分类管理属于同一商品管理业务能力时,不要拆分成供应链和运营管理两个领域。
-- 如果当前领域已有数据模型上下文,优先复用已有模型生成应用页面;只有已有模型不能覆盖需求时才补充新模型。',
-       'RULE',
-       16,
-       '0',
-       1,
-       NOW(),
-       1,
-       1,
-       NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_context_config
-    WHERE tenant_id = 1
-      AND agent_code = 'lowcode_system_generator'
-      AND config_name = '低代码单领域和命名规则'
-);

+ 0 - 81
forge-server/db/backup/V1.0.23__add_common_crud_async_export.sql

@@ -1,81 +0,0 @@
-CREATE TABLE IF NOT EXISTS `ai_crud_export_task`
-(
-    `id`             bigint       NOT NULL COMMENT '任务ID',
-    `tenant_id`      bigint       NOT NULL DEFAULT 1 COMMENT '租户编号',
-    `config_key`     varchar(64)  NOT NULL COMMENT 'CRUD配置键',
-    `export_name`    varchar(128)          DEFAULT NULL COMMENT '导出名称',
-    `file_name`      varchar(255)          DEFAULT NULL COMMENT '导出文件名',
-    `file_id`        varchar(64)           DEFAULT NULL COMMENT '文件中心ID',
-    `file_size`      bigint                DEFAULT NULL COMMENT '文件大小(字节)',
-    `status`         varchar(20)  NOT NULL DEFAULT 'PENDING' COMMENT '任务状态:PENDING/RUNNING/SUCCESS/FAILED',
-    `total_count`    bigint       NOT NULL DEFAULT 0 COMMENT '总数据量',
-    `exported_count` bigint       NOT NULL DEFAULT 0 COMMENT '已导出数据量',
-    `progress`       int          NOT NULL DEFAULT 0 COMMENT '导出进度百分比',
-    `query_params`   json                  DEFAULT NULL COMMENT '导出查询参数快照',
-    `error_message`  varchar(1000)         DEFAULT NULL COMMENT '失败原因',
-    `finish_time`    datetime              DEFAULT NULL COMMENT '完成时间',
-    `expire_time`    datetime              DEFAULT NULL COMMENT '文件过期时间',
-    `create_by`      bigint                DEFAULT NULL COMMENT '创建者',
-    `create_time`    datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept`    bigint                DEFAULT NULL COMMENT '创建组织ID',
-    `update_by`      bigint                DEFAULT NULL COMMENT '更新者',
-    `update_time`    datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    PRIMARY KEY (`id`),
-    KEY `idx_ai_crud_export_task_user` (`tenant_id`, `create_by`, `config_key`, `create_time`),
-    KEY `idx_ai_crud_export_task_status` (`tenant_id`, `status`, `expire_time`),
-    KEY `idx_ai_crud_export_task_file` (`file_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='通用CRUD异步导出任务表';
-
-INSERT INTO sys_config (tenant_id, config_name, config_key, config_value, config_type, config_desc, sort,
-                        create_by, create_time, update_by, update_time, create_dept)
-SELECT 1,
-       '通用导出异步阈值',
-       'sys.export.async.threshold',
-       '5000',
-       'Y',
-       '通用CRUD导出数据量超过该阈值时自动转为异步导出',
-       30,
-       1,
-       NOW(),
-       1,
-       NOW(),
-       1
-WHERE NOT EXISTS (
-    SELECT 1 FROM sys_config WHERE tenant_id = 1 AND config_key = 'sys.export.async.threshold'
-);
-
-INSERT INTO sys_config (tenant_id, config_name, config_key, config_value, config_type, config_desc, sort,
-                        create_by, create_time, update_by, update_time, create_dept)
-SELECT 1,
-       '通用导出批量大小',
-       'sys.export.batch.size',
-       '1000',
-       'Y',
-       '通用CRUD异步导出每批分页查询和写入Excel的行数',
-       31,
-       1,
-       NOW(),
-       1,
-       NOW(),
-       1
-WHERE NOT EXISTS (
-    SELECT 1 FROM sys_config WHERE tenant_id = 1 AND config_key = 'sys.export.batch.size'
-);
-
-INSERT INTO sys_config (tenant_id, config_name, config_key, config_value, config_type, config_desc, sort,
-                        create_by, create_time, update_by, update_time, create_dept)
-SELECT 1,
-       '通用导出文件保留小时',
-       'sys.export.file.keepHours',
-       '24',
-       'Y',
-       '通用CRUD异步导出文件在任务中的默认保留小时数',
-       32,
-       1,
-       NOW(),
-       1,
-       NOW(),
-       1
-WHERE NOT EXISTS (
-    SELECT 1 FROM sys_config WHERE tenant_id = 1 AND config_key = 'sys.export.file.keepHours'
-);

+ 0 - 164
forge-server/db/backup/V1.0.24__add_excel_import_config_fields.sql

@@ -1,164 +0,0 @@
-SET @table_exists = (
-    SELECT COUNT(*)
-    FROM information_schema.TABLES
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'sys_excel_export_config'
-);
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_export_config'
-              AND COLUMN_NAME = 'include_sample'
-        ) = 0,
-        'ALTER TABLE sys_excel_export_config ADD COLUMN include_sample TINYINT(1) DEFAULT 0 COMMENT ''是否包含示例数据(用于模板)'' AFTER status',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_export_config'
-              AND COLUMN_NAME = 'allow_import'
-        ) = 0,
-        'ALTER TABLE sys_excel_export_config ADD COLUMN allow_import TINYINT(1) DEFAULT 1 COMMENT ''是否允许导入'' AFTER include_sample',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'UPDATE sys_excel_export_config SET include_sample = COALESCE(include_sample, 0), allow_import = COALESCE(allow_import, 1)'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (
-    SELECT COUNT(*)
-    FROM information_schema.TABLES
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'sys_excel_column_config'
-);
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_column_config'
-              AND COLUMN_NAME = 'importable'
-        ) = 0,
-        'ALTER TABLE sys_excel_column_config ADD COLUMN importable TINYINT(1) DEFAULT 1 COMMENT ''是否可导入(1-是,0-否)'' AFTER dict_type',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_column_config'
-              AND COLUMN_NAME = 'required'
-        ) = 0,
-        'ALTER TABLE sys_excel_column_config ADD COLUMN required TINYINT(1) DEFAULT 0 COMMENT ''是否必填(1-是,0-否)'' AFTER importable',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_column_config'
-              AND COLUMN_NAME = 'example_value'
-        ) = 0,
-        'ALTER TABLE sys_excel_column_config ADD COLUMN example_value VARCHAR(255) DEFAULT NULL COMMENT ''示例值(用于模板)'' AFTER required',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_column_config'
-              AND COLUMN_NAME = 'validation_rule'
-        ) = 0,
-        'ALTER TABLE sys_excel_column_config ADD COLUMN validation_rule VARCHAR(255) DEFAULT NULL COMMENT ''校验规则(正则表达式)'' AFTER example_value',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_column_config'
-              AND COLUMN_NAME = 'validation_message'
-        ) = 0,
-        'ALTER TABLE sys_excel_column_config ADD COLUMN validation_message VARCHAR(255) DEFAULT NULL COMMENT ''校验失败提示信息'' AFTER validation_rule',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'UPDATE sys_excel_column_config SET importable = COALESCE(importable, export), required = COALESCE(required, 0)'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 110
forge-server/db/backup/V1.0.25__split_excel_import_export_config.sql

@@ -1,111 +0,0 @@
-
-SET @table_exists = (
-    SELECT COUNT(1)
-    FROM information_schema.TABLES
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'sys_excel_export_config'
-);
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(1)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'sys_excel_export_config'
-              AND COLUMN_NAME = 'config_type'
-        ) = 0,
-        'ALTER TABLE sys_excel_export_config ADD COLUMN config_type VARCHAR(16) NOT NULL DEFAULT ''BOTH'' COMMENT ''配置类型:EXPORT导出 IMPORT导入 BOTH导入导出'' AFTER config_key',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'UPDATE sys_excel_export_config
-        SET config_type = CASE
-            WHEN COALESCE(allow_import, 1) = 0 THEN ''EXPORT''
-            WHEN (data_source_bean IS NULL OR data_source_bean = '''' OR query_method IS NULL OR query_method = '''') THEN ''IMPORT''
-            ELSE ''BOTH''
-        END
-      WHERE config_type IS NULL
-         OR config_type = ''''
-         OR (config_type = ''BOTH'' AND (
-                COALESCE(allow_import, 1) = 0
-                OR data_source_bean IS NULL OR data_source_bean = ''''
-                OR query_method IS NULL OR query_method = ''''
-            ))'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'UPDATE sys_excel_export_config
-        SET allow_import = CASE WHEN config_type = ''EXPORT'' THEN 0 ELSE 1 END'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE sys_excel_export_config MODIFY COLUMN data_source_bean VARCHAR(100) DEFAULT NULL COMMENT ''数据源Bean名称(如:userService,导入-only可为空)'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE sys_excel_export_config MODIFY COLUMN query_method VARCHAR(100) DEFAULT NULL COMMENT ''数据查询方法名(如:list、page,导入-only可为空)'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-    SELECT 1 tenant_id, 'Excel配置类型' dict_name, 'sys_excel_config_type' dict_type, 1 dict_status, 'Excel导入导出配置类型' remark
-) seed
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM sys_dict_type t
-    WHERE t.tenant_id = seed.tenant_id
-      AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-    SELECT 1 tenant_id, 1 dict_sort, '仅导出' dict_label, 'EXPORT' dict_value, 'sys_excel_config_type' dict_type, 'info' list_class, 'N' is_default, '仅用于导出' remark
-    UNION ALL SELECT 1, 2, '仅导入', 'IMPORT', 'sys_excel_config_type', 'warning', 'N', '仅用于导入'
-    UNION ALL SELECT 1, 3, '导入导出', 'BOTH', 'sys_excel_config_type', 'success', 'Y', '同时用于导入和导出'
-) seed
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM sys_dict_data d
-    WHERE d.tenant_id = seed.tenant_id
-      AND d.dict_type = seed.dict_type
-      AND d.dict_value = seed.dict_value
-);
-
-UPDATE sys_resource
-SET resource_name = 'Excel导入导出配置',
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND path = '/system/excel-export-config'
-  AND resource_name = 'Excel导出配置';

+ 0 - 125
forge-server/db/backup/V1.0.26__add_business_app_platform_tables.sql

@@ -1,126 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_business_suite` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `suite_code` varchar(48) NOT NULL COMMENT '业务套件编码',
-  `suite_name` varchar(128) NOT NULL COMMENT '业务套件名称',
-  `icon` varchar(128) DEFAULT NULL COMMENT '套件图标',
-  `description` varchar(500) DEFAULT NULL COMMENT '业务说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `options` json DEFAULT NULL COMMENT '扩展配置',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_suite_code` (`tenant_id`, `suite_code`),
-  KEY `idx_ai_business_suite_status` (`tenant_id`, `status`, `sort_order`),
-  KEY `idx_ai_business_suite_update` (`tenant_id`, `update_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-业务套件表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_object` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `suite_code` varchar(48) NOT NULL COMMENT '所属业务套件编码',
-  `object_code` varchar(48) NOT NULL COMMENT '业务对象编码',
-  `object_name` varchar(128) NOT NULL COMMENT '业务对象名称',
-  `object_type` varchar(32) NOT NULL COMMENT '对象类型:MASTER/DETAIL/LOOKUP/TRANSACTION',
-  `model_id` bigint DEFAULT NULL COMMENT '关联低代码模型ID',
-  `model_code` varchar(48) DEFAULT NULL COMMENT '关联低代码模型编码',
-  `display_field` varchar(64) DEFAULT NULL COMMENT '默认展示字段',
-  `icon` varchar(128) DEFAULT NULL COMMENT '对象图标',
-  `description` varchar(500) DEFAULT NULL COMMENT '业务说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `options` json DEFAULT NULL COMMENT '扩展配置',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_object_code` (`tenant_id`, `suite_code`, `object_code`),
-  KEY `idx_ai_business_object_suite` (`tenant_id`, `suite_code`, `status`, `sort_order`),
-  KEY `idx_ai_business_object_model` (`tenant_id`, `model_id`),
-  KEY `idx_ai_business_object_update` (`tenant_id`, `update_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-业务对象表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_object_relation` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `suite_code` varchar(48) NOT NULL COMMENT '所属业务套件编码',
-  `source_object_code` varchar(48) NOT NULL COMMENT '来源业务对象编码',
-  `target_object_code` varchar(48) NOT NULL COMMENT '目标业务对象编码',
-  `relation_type` varchar(32) NOT NULL COMMENT '关系类型:REFERENCE/DETAIL/CHILD_LIST/MANY_TO_MANY',
-  `relation_name` varchar(128) NOT NULL COMMENT '关系名称',
-  `source_field_code` varchar(64) DEFAULT NULL COMMENT '来源对象字段编码',
-  `target_field_code` varchar(64) DEFAULT NULL COMMENT '目标对象字段编码',
-  `relation_config` json DEFAULT NULL COMMENT '关系配置',
-  `description` varchar(500) DEFAULT NULL COMMENT '关系说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_relation_scope` (`tenant_id`, `suite_code`, `source_object_code`, `target_object_code`, `relation_type`, `relation_name`),
-  KEY `idx_ai_business_relation_source` (`tenant_id`, `suite_code`, `source_object_code`, `status`),
-  KEY `idx_ai_business_relation_target` (`tenant_id`, `suite_code`, `target_object_code`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-业务对象关系表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_app` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `app_code` varchar(64) NOT NULL COMMENT '应用入口编码',
-  `app_name` varchar(128) NOT NULL COMMENT '应用入口名称',
-  `app_type` varchar(32) NOT NULL COMMENT '应用类型:BUSINESS/EMBEDDED/MOBILE/INTEGRATION',
-  `suite_code` varchar(48) NOT NULL COMMENT '所属业务套件编码',
-  `object_code` varchar(48) DEFAULT NULL COMMENT '关联业务对象编码',
-  `entry_mode` varchar(32) NOT NULL COMMENT '入口模式:RUNTIME/ROUTE/IFRAME/EXTERNAL/H5/API',
-  `entry_url` varchar(512) DEFAULT NULL COMMENT '入口地址',
-  `config_key` varchar(128) DEFAULT NULL COMMENT '关联低代码运行配置键',
-  `icon` varchar(128) DEFAULT NULL COMMENT '应用图标',
-  `description` varchar(500) DEFAULT NULL COMMENT '业务说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `options` json DEFAULT NULL COMMENT '扩展配置',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_app_code` (`tenant_id`, `app_code`),
-  KEY `idx_ai_business_app_suite` (`tenant_id`, `suite_code`, `app_type`, `status`, `sort_order`),
-  KEY `idx_ai_business_app_object` (`tenant_id`, `suite_code`, `object_code`, `status`),
-  KEY `idx_ai_business_app_config_key` (`tenant_id`, `config_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-应用入口表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_binding` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `target_type` varchar(32) NOT NULL COMMENT '挂接目标类型:SUITE/OBJECT/APP',
-  `target_id` bigint DEFAULT NULL COMMENT '挂接目标ID',
-  `target_code` varchar(128) NOT NULL COMMENT '挂接目标编码',
-  `binding_type` varchar(32) NOT NULL COMMENT '能力类型:FLOW/APPROVAL/REPORT/PERMISSION/MESSAGE/TRIGGER/IMPORT/EXPORT/MOBILE/INTEGRATION',
-  `binding_key` varchar(128) NOT NULL COMMENT '能力业务键',
-  `binding_name` varchar(128) NOT NULL COMMENT '挂接名称',
-  `binding_config` json DEFAULT NULL COMMENT '挂接配置',
-  `description` varchar(500) DEFAULT NULL COMMENT '挂接说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_binding_target` (`tenant_id`, `target_type`, `target_code`, `binding_type`, `binding_key`),
-  KEY `idx_ai_business_binding_target_id` (`tenant_id`, `target_type`, `target_id`, `binding_type`),
-  KEY `idx_ai_business_binding_type` (`tenant_id`, `binding_type`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-能力挂接表';

+ 0 - 142
forge-server/db/backup/V1.0.27__add_business_app_platform_dicts_menus.sql

@@ -1,143 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, '业务套件' dict_name, 'ai_business_suite' dict_type, 1 dict_status, '企业应用装配平台业务套件' remark
-  UNION ALL SELECT 1, '业务对象类型', 'ai_business_object_type', 1, '业务对象/实体类型'
-  UNION ALL SELECT 1, '业务对象关系类型', 'ai_business_relation_type', 1, '业务对象之间的引用、明细和关联列表关系'
-  UNION ALL SELECT 1, '业务应用类型', 'ai_business_app_type', 1, '应用入口和渠道类型'
-  UNION ALL SELECT 1, '业务应用入口模式', 'ai_business_app_entry_mode', 1, '应用入口打开方式'
-  UNION ALL SELECT 1, '业务能力挂接类型', 'ai_business_binding_type', 1, '对象和应用可接入的引擎能力'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default,
-                           dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class,
-       seed.is_default, 1, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, 'CRM' dict_label, 'CRM' dict_value, 'ai_business_suite' dict_type, 'success' list_class, 'Y' is_default, '客户关系管理业务套件' remark
-  UNION ALL SELECT 1, 2, '合同', 'CONTRACT', 'ai_business_suite', 'info', 'N', '合同管理业务套件'
-  UNION ALL SELECT 1, 3, '项目', 'PROJECT', 'ai_business_suite', 'primary', 'N', '项目管理业务套件'
-  UNION ALL SELECT 1, 4, '采购', 'PURCHASE', 'ai_business_suite', 'warning', 'N', '采购管理业务套件'
-  UNION ALL SELECT 1, 5, '服务', 'SERVICE', 'ai_business_suite', 'default', 'N', '服务工单业务套件'
-  UNION ALL SELECT 1, 1, '主数据对象', 'MASTER', 'ai_business_object_type', 'success', 'Y', '客户、线索等主数据对象'
-  UNION ALL SELECT 1, 2, '明细对象', 'DETAIL', 'ai_business_object_type', 'info', 'N', '合同明细、跟进记录等明细对象'
-  UNION ALL SELECT 1, 3, '查找对象', 'LOOKUP', 'ai_business_object_type', 'default', 'N', '字典式或引用型对象'
-  UNION ALL SELECT 1, 4, '业务单据', 'TRANSACTION', 'ai_business_object_type', 'warning', 'N', '商机、合同、回款等业务单据'
-  UNION ALL SELECT 1, 1, '引用关系', 'REFERENCE', 'ai_business_relation_type', 'info', 'Y', '对象通过业务字段引用另一个对象'
-  UNION ALL SELECT 1, 2, '明细关系', 'DETAIL', 'ai_business_relation_type', 'success', 'N', '明细对象依附主对象'
-  UNION ALL SELECT 1, 3, '关联列表', 'CHILD_LIST', 'ai_business_relation_type', 'primary', 'N', '详情页展示下级或关联对象列表'
-  UNION ALL SELECT 1, 4, '多对多关系', 'MANY_TO_MANY', 'ai_business_relation_type', 'warning', 'N', '通过中间关系表达多对多关联'
-  UNION ALL SELECT 1, 1, '业务应用', 'BUSINESS', 'ai_business_app_type', 'success', 'Y', '客户管理、合同管理等标准业务入口'
-  UNION ALL SELECT 1, 2, '嵌入应用', 'EMBEDDED', 'ai_business_app_type', 'info', 'N', '大屏、BI、外部页面等嵌入入口'
-  UNION ALL SELECT 1, 3, '移动应用', 'MOBILE', 'ai_business_app_type', 'primary', 'N', 'H5、移动审批和移动业务入口'
-  UNION ALL SELECT 1, 4, '集成应用', 'INTEGRATION', 'ai_business_app_type', 'warning', 'N', '开放接口、Webhook、第三方平台连接'
-  UNION ALL SELECT 1, 1, '运行态页面', 'RUNTIME', 'ai_business_app_entry_mode', 'success', 'Y', '打开动态CRUD运行页'
-  UNION ALL SELECT 1, 2, '内部路由', 'ROUTE', 'ai_business_app_entry_mode', 'info', 'N', '打开平台内部路由'
-  UNION ALL SELECT 1, 3, '内嵌页面', 'IFRAME', 'ai_business_app_entry_mode', 'primary', 'N', '通过iframe内嵌访问'
-  UNION ALL SELECT 1, 4, '外部打开', 'EXTERNAL', 'ai_business_app_entry_mode', 'warning', 'N', '新窗口打开外部地址'
-  UNION ALL SELECT 1, 5, 'H5入口', 'H5', 'ai_business_app_entry_mode', 'default', 'N', '移动H5入口'
-  UNION ALL SELECT 1, 6, '接口入口', 'API', 'ai_business_app_entry_mode', 'info', 'N', '进入接口或集成配置'
-  UNION ALL SELECT 1, 1, '流程', 'FLOW', 'ai_business_binding_type', 'info', 'N', '流程能力'
-  UNION ALL SELECT 1, 2, '审批', 'APPROVAL', 'ai_business_binding_type', 'success', 'N', '审批能力'
-  UNION ALL SELECT 1, 3, '报表', 'REPORT', 'ai_business_binding_type', 'primary', 'N', '报表和看板能力'
-  UNION ALL SELECT 1, 4, '权限', 'PERMISSION', 'ai_business_binding_type', 'warning', 'N', '对象级权限能力'
-  UNION ALL SELECT 1, 5, '消息', 'MESSAGE', 'ai_business_binding_type', 'info', 'N', '站内信、邮件、短信等消息能力'
-  UNION ALL SELECT 1, 6, '触发器', 'TRIGGER', 'ai_business_binding_type', 'error', 'N', '轻量对象自动化能力'
-  UNION ALL SELECT 1, 7, '导入', 'IMPORT', 'ai_business_binding_type', 'default', 'N', '对象级导入能力'
-  UNION ALL SELECT 1, 8, '导出', 'EXPORT', 'ai_business_binding_type', 'default', 'N', '对象级导出能力'
-  UNION ALL SELECT 1, 9, '移动', 'MOBILE', 'ai_business_binding_type', 'primary', 'N', '移动端入口能力'
-  UNION ALL SELECT 1, 10, '集成', 'INTEGRATION', 'ai_business_binding_type', 'warning', 'N', '第三方平台和开放接口能力'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '应用中心', 0, 2, 6, '/app-center', 'app-center/index', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessApp:list', 'ionicons5:GridOutline',
-       NULL, NULL, 1, 0, NULL, '企业应用装配平台主入口', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-);
-
-SET @app_center_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @app_center_menu_id, seed.resource_type, seed.sort, seed.path,
-       seed.component, 0, 0, NULL, '_self', 0, seed.menu_status, seed.visible, seed.perms, seed.icon,
-       NULL, NULL, seed.keep_alive, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '业务套件详情' resource_name, 2 resource_type, 1 sort, '/app-center/suite/:suiteCode' path, 'app-center/suite-detail' component, 0 menu_status, 0 visible, 'ai:businessSuite:list' perms, 'ionicons5:AlbumsOutline' icon, 0 keep_alive, '业务套件详情隐藏路由' remark
-  UNION ALL SELECT 1, '业务对象详情', 2, 2, '/app-center/object/:objectCode', 'app-center/object-detail', 0, 0, 'ai:businessObject:list', 'ionicons5:CubeOutline', 0, '业务对象详情隐藏路由'
-  UNION ALL SELECT 1, '引擎中心', 2, 3, '/app-center/engines', 'app-center/engine-center', 1, 1, 'ai:businessEngine:list', 'ionicons5:HardwareChipOutline', 1, '流程、审批、报表、权限和消息引擎统一入口'
-  UNION ALL SELECT 1, '移动端中心', 2, 4, '/app-center/mobile', 'app-center/mobile-center', 1, 1, 'ai:businessMobile:list', 'ionicons5:PhonePortraitOutline', 1, '移动H5和移动业务入口'
-  UNION ALL SELECT 1, '集成中心', 2, 5, '/app-center/integration', 'app-center/integration-center', 1, 1, 'ai:businessIntegration:list', 'ionicons5:GitNetworkOutline', 1, '开放接口、Webhook和第三方平台连接入口'
-) seed
-WHERE @app_center_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.resource_type = seed.resource_type
-      AND r.perms = seed.perms
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @app_center_menu_id, 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '查看业务套件' resource_name, 11 sort, 'ai:businessSuite:list' perms, '查询业务套件按钮权限' remark
-  UNION ALL SELECT 1, '维护业务套件', 12, 'ai:businessSuite:edit', '新增或编辑业务套件按钮权限'
-  UNION ALL SELECT 1, '查看业务对象', 21, 'ai:businessObject:list', '查询业务对象按钮权限'
-  UNION ALL SELECT 1, '新增业务对象', 22, 'ai:businessObject:add', '新增业务对象按钮权限'
-  UNION ALL SELECT 1, '编辑业务对象', 23, 'ai:businessObject:edit', '编辑业务对象按钮权限'
-  UNION ALL SELECT 1, '删除业务对象', 24, 'ai:businessObject:delete', '删除业务对象按钮权限'
-  UNION ALL SELECT 1, '配置对象关系', 25, 'ai:businessObject:relation', '配置业务对象关系按钮权限'
-  UNION ALL SELECT 1, '配置接入能力', 31, 'ai:businessBinding:config', '配置对象或应用能力挂接按钮权限'
-  UNION ALL SELECT 1, '新增应用入口', 41, 'ai:businessApp:add', '新增应用入口按钮权限'
-  UNION ALL SELECT 1, '编辑应用入口', 42, 'ai:businessApp:edit', '编辑应用入口按钮权限'
-  UNION ALL SELECT 1, '删除应用入口', 43, 'ai:businessApp:delete', '删除应用入口按钮权限'
-  UNION ALL SELECT 1, '启停应用入口', 44, 'ai:businessApp:status', '启停应用入口按钮权限'
-  UNION ALL SELECT 1, '打开应用入口', 45, 'ai:businessApp:open', '打开应用入口按钮权限'
-) seed
-WHERE @app_center_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.resource_type = 3
-      AND r.perms = seed.perms
-  );

+ 0 - 122
forge-server/db/backup/V1.0.28__seed_crm_business_suite.sql

@@ -1,123 +0,0 @@
-
-INSERT INTO ai_business_suite (id, tenant_id, suite_code, suite_name, icon, description, status, sort_order, options,
-                               create_by, create_time, create_dept, update_by, update_time)
-SELECT 1910000000000000001, 1, 'CRM', 'CRM', 'ionicons5:PeopleOutline',
-       '围绕客户、联系人、线索、商机、合同、回款和销售任务组织的客户关系管理业务套件',
-       1, 1, '{"sample":true,"stage":"phase1"}', 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_suite
-  WHERE tenant_id = 1
-    AND suite_code = 'CRM'
-);
-
-INSERT INTO ai_business_object (id, tenant_id, suite_code, object_code, object_name, object_type, model_id, model_code,
-                                display_field, icon, description, status, sort_order, options, create_by, create_time,
-                                create_dept, update_by, update_time)
-SELECT seed.id, 1, 'CRM', seed.object_code, seed.object_name, seed.object_type, NULL, seed.model_code,
-       seed.display_field, seed.icon, seed.description, 1, seed.sort_order, seed.options,
-       1, NOW(), 1, 1, NOW()
-FROM (
-  SELECT 1910000000000000101 id, 'CUSTOMER' object_code, '客户' object_name, 'MASTER' object_type, 'crm_customer' model_code, 'customerName' display_field, 'ionicons5:BusinessOutline' icon, '管理客户基本信息、客户分级、所属区域和客户生命周期' description, 1 sort_order, '{"sample":true,"capabilityGroup":"customer"}' options
-  UNION ALL SELECT 1910000000000000102, 'CONTACT', '联系人', 'DETAIL', 'crm_contact', 'contactName', 'ionicons5:PersonOutline', '管理客户联系人、角色、联系方式和主要联系人标记', 2, '{"sample":true,"capabilityGroup":"customer"}'
-  UNION ALL SELECT 1910000000000000103, 'LEAD', '线索', 'MASTER', 'crm_lead', 'leadName', 'ionicons5:SparklesOutline', '管理销售线索、来源、跟进状态和转化进度', 3, '{"sample":true,"capabilityGroup":"sales"}'
-  UNION ALL SELECT 1910000000000000104, 'OPPORTUNITY', '商机', 'TRANSACTION', 'crm_opportunity', 'opportunityName', 'ionicons5:TrendingUpOutline', '管理商机阶段、预计金额、赢单概率和推进动作', 4, '{"sample":true,"capabilityGroup":"sales"}'
-  UNION ALL SELECT 1910000000000000105, 'CONTRACT', '合同', 'TRANSACTION', 'crm_contract', 'contractName', 'ionicons5:DocumentTextOutline', '管理合同信息、合同审批、归档和履约状态', 5, '{"sample":true,"capabilityGroup":"contract"}'
-  UNION ALL SELECT 1910000000000000106, 'CONTRACT_ITEM', '合同明细', 'DETAIL', 'crm_contract_item', 'itemName', 'ionicons5:ListOutline', '管理合同商品、服务、数量、单价和金额明细', 6, '{"sample":true,"capabilityGroup":"contract"}'
-  UNION ALL SELECT 1910000000000000107, 'PAYMENT', '回款', 'TRANSACTION', 'crm_payment', 'paymentNo', 'ionicons5:WalletOutline', '管理回款计划、回款记录和逾期提醒', 7, '{"sample":true,"capabilityGroup":"finance"}'
-  UNION ALL SELECT 1910000000000000108, 'FOLLOW_RECORD', '跟进记录', 'DETAIL', 'crm_follow_record', 'subject', 'ionicons5:ChatbubblesOutline', '管理客户拜访、电话、会议和商机推进记录', 8, '{"sample":true,"capabilityGroup":"activity"}'
-  UNION ALL SELECT 1910000000000000109, 'SALES_TASK', '销售任务', 'TRANSACTION', 'crm_sales_task', 'taskName', 'ionicons5:CheckboxOutline', '管理销售计划、待办任务和任务完成情况', 9, '{"sample":true,"capabilityGroup":"sales"}'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_object o
-  WHERE o.tenant_id = 1
-    AND o.suite_code = 'CRM'
-    AND o.object_code = seed.object_code
-);
-
-INSERT INTO ai_business_object_relation (id, tenant_id, suite_code, source_object_code, target_object_code,
-                                         relation_type, relation_name, source_field_code, target_field_code,
-                                         relation_config, description, status, sort_order, create_by, create_time,
-                                         create_dept, update_by, update_time)
-SELECT seed.id, 1, 'CRM', seed.source_object_code, seed.target_object_code, seed.relation_type, seed.relation_name,
-       seed.source_field_code, seed.target_field_code, seed.relation_config, seed.description, 1, seed.sort_order,
-       1, NOW(), 1, 1, NOW()
-FROM (
-  SELECT 1910000000000000201 id, 'CUSTOMER' source_object_code, 'CONTACT' target_object_code, 'CHILD_LIST' relation_type, '客户联系人' relation_name, 'customerId' source_field_code, 'id' target_field_code, '{"detailTab":"联系人","businessText":"客户详情中展示联系人列表"}' relation_config, '客户详情中展示联系人列表' description, 1 sort_order
-  UNION ALL SELECT 1910000000000000202, 'CUSTOMER', 'OPPORTUNITY', 'CHILD_LIST', '客户商机', 'customerId', 'id', '{"detailTab":"商机","businessText":"客户详情中展示相关商机"}', '客户详情中展示相关商机', 2
-  UNION ALL SELECT 1910000000000000203, 'OPPORTUNITY', 'CONTRACT', 'REFERENCE', '商机关联合同', 'id', 'opportunityId', '{"businessText":"合同可关联来源商机"}', '合同可关联来源商机', 3
-  UNION ALL SELECT 1910000000000000204, 'CONTRACT', 'CONTRACT_ITEM', 'DETAIL', '合同明细', 'id', 'contractId', '{"detailTab":"合同明细","summaryField":"amount"}', '合同明细依附合同并支持金额汇总', 4
-  UNION ALL SELECT 1910000000000000205, 'CONTRACT', 'PAYMENT', 'CHILD_LIST', '合同回款', 'id', 'contractId', '{"detailTab":"回款","businessText":"合同详情中展示回款计划或记录"}', '合同详情中展示回款计划或回款记录', 5
-  UNION ALL SELECT 1910000000000000206, 'CUSTOMER', 'FOLLOW_RECORD', 'CHILD_LIST', '客户跟进记录', 'customerId', 'id', '{"detailTab":"跟进记录","businessText":"客户详情中展示拜访、电话、会议记录"}', '客户详情中展示拜访、电话、会议记录', 6
-  UNION ALL SELECT 1910000000000000207, 'OPPORTUNITY', 'FOLLOW_RECORD', 'CHILD_LIST', '商机跟进记录', 'opportunityId', 'id', '{"detailTab":"跟进记录","businessText":"商机详情中展示推进记录"}', '商机详情中展示推进记录', 7
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_object_relation r
-  WHERE r.tenant_id = 1
-    AND r.suite_code = 'CRM'
-    AND r.source_object_code = seed.source_object_code
-    AND r.target_object_code = seed.target_object_code
-    AND r.relation_type = seed.relation_type
-    AND r.relation_name = seed.relation_name
-);
-
-INSERT INTO ai_business_binding (id, tenant_id, target_type, target_id, target_code, binding_type, binding_key,
-                                 binding_name, binding_config, description, status, sort_order, create_by,
-                                 create_time, create_dept, update_by, update_time)
-SELECT seed.id, 1, 'OBJECT', seed.target_id, seed.target_code, seed.binding_type, seed.binding_key,
-       seed.binding_name, seed.binding_config, seed.description, 1, seed.sort_order, 1, NOW(), 1, 1, NOW()
-FROM (
-  SELECT 1910000000000000401 id, 1910000000000000101 target_id, 'CUSTOMER' target_code, 'IMPORT' binding_type, 'import_customer' binding_key, '导入客户' binding_name, '{"template":"customer_import"}' binding_config, '客户对象导入能力' description, 1 sort_order
-  UNION ALL SELECT 1910000000000000402, 1910000000000000102, 'CONTACT', 'IMPORT', 'import_contact', '导入联系人', '{"template":"contact_import"}', '联系人对象导入能力', 2
-  UNION ALL SELECT 1910000000000000403, 1910000000000000105, 'CONTRACT', 'IMPORT', 'import_contract', '导入合同', '{"template":"contract_import"}', '合同对象导入能力', 3
-  UNION ALL SELECT 1910000000000000404, 1910000000000000101, 'CUSTOMER', 'EXPORT', 'export_customer', '导出客户', '{"template":"customer_export"}', '客户对象导出能力', 4
-  UNION ALL SELECT 1910000000000000405, 1910000000000000102, 'CONTACT', 'EXPORT', 'export_contact', '导出联系人', '{"template":"contact_export"}', '联系人对象导出能力', 5
-  UNION ALL SELECT 1910000000000000406, 1910000000000000105, 'CONTRACT', 'EXPORT', 'export_contract', '导出合同', '{"template":"contract_export"}', '合同对象导出能力', 6
-  UNION ALL SELECT 1910000000000000407, 1910000000000000101, 'CUSTOMER', 'REPORT', 'customer_report', '客户报表', '{"reportType":"CUSTOMER_GROWTH"}', '客户增长和客户结构分析报表', 7
-  UNION ALL SELECT 1910000000000000408, 1910000000000000104, 'OPPORTUNITY', 'REPORT', 'sales_funnel_report', '销售漏斗', '{"reportType":"SALES_FUNNEL"}', '商机阶段和销售漏斗分析报表', 8
-  UNION ALL SELECT 1910000000000000409, 1910000000000000107, 'PAYMENT', 'REPORT', 'payment_report', '回款报表', '{"reportType":"PAYMENT_ANALYSIS"}', '回款计划、回款记录和逾期分析报表', 9
-  UNION ALL SELECT 1910000000000000410, 1910000000000000105, 'CONTRACT', 'TRIGGER', 'contract_amount_summary', '合同金额汇总', '{"action":"SUM_DETAIL_AMOUNT"}', '根据合同明细汇总合同金额', 10
-  UNION ALL SELECT 1910000000000000411, 1910000000000000104, 'OPPORTUNITY', 'TRIGGER', 'opportunity_stage_reminder', '商机阶段提醒', '{"action":"STAGE_CHANGE_MESSAGE"}', '商机阶段变化后生成提醒', 11
-  UNION ALL SELECT 1910000000000000412, 1910000000000000107, 'PAYMENT', 'TRIGGER', 'payment_overdue_reminder', '回款逾期提醒', '{"action":"OVERDUE_TODO"}', '回款逾期后生成待办提醒', 12
-  UNION ALL SELECT 1910000000000000413, 1910000000000000105, 'CONTRACT', 'APPROVAL', 'contract_approval', '合同审批', '{"flowKey":"crm_contract_approval"}', '合同提交后进入审批流程', 13
-  UNION ALL SELECT 1910000000000000414, 1910000000000000104, 'OPPORTUNITY', 'MESSAGE', 'opportunity_follow_reminder', '商机跟进提醒', '{"messageType":"FOLLOW_REMINDER"}', '商机长期未跟进时提醒销售人员', 14
-  UNION ALL SELECT 1910000000000000415, 1910000000000000107, 'PAYMENT', 'MESSAGE', 'payment_overdue_message', '回款逾期通知', '{"messageType":"OVERDUE_PAYMENT"}', '回款逾期后发送消息通知', 15
-  UNION ALL SELECT 1910000000000000416, 1910000000000000101, 'CUSTOMER', 'PERMISSION', 'customer_permission', '客户对象权限', '{"scope":"OWNER_DEPT_REGION"}', '客户按负责人、部门和区域进行数据可见控制', 16
-  UNION ALL SELECT 1910000000000000417, 1910000000000000105, 'CONTRACT', 'PERMISSION', 'contract_permission', '合同对象权限', '{"scope":"OWNER_DEPT"}', '合同按负责人和部门进行数据可见控制', 17
-  UNION ALL SELECT 1910000000000000418, 1910000000000000107, 'PAYMENT', 'PERMISSION', 'payment_permission', '回款对象权限', '{"scope":"CONTRACT_SCOPE"}', '回款继承合同范围的数据可见控制', 18
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_binding b
-  WHERE b.tenant_id = 1
-    AND b.target_type = 'OBJECT'
-    AND b.target_code = seed.target_code
-    AND b.binding_type = seed.binding_type
-    AND b.binding_key = seed.binding_key
-);
-
-INSERT INTO ai_business_app (id, tenant_id, app_code, app_name, app_type, suite_code, object_code, entry_mode,
-                             entry_url, config_key, icon, description, status, sort_order, options, create_by,
-                             create_time, create_dept, update_by, update_time)
-SELECT seed.id, 1, seed.app_code, seed.app_name, 'BUSINESS', 'CRM', seed.object_code, 'RUNTIME',
-       seed.entry_url, seed.config_key, seed.icon, seed.description, 1, seed.sort_order,
-       '{"sample":true,"entryGroup":"crm-standard"}', 1, NOW(), 1, 1, NOW()
-FROM (
-  SELECT 1910000000000000301 id, 'CRM_CUSTOMER_MANAGE' app_code, '客户管理' app_name, 'CUSTOMER' object_code, '/ai/crud-page/crm_customer' entry_url, 'crm_customer' config_key, 'ionicons5:BusinessOutline' icon, '客户标准后台业务入口' description, 1 sort_order
-  UNION ALL SELECT 1910000000000000302, 'CRM_CONTACT_MANAGE', '联系人管理', 'CONTACT', '/ai/crud-page/crm_contact', 'crm_contact', 'ionicons5:PersonOutline', '联系人标准后台业务入口', 2
-  UNION ALL SELECT 1910000000000000303, 'CRM_LEAD_MANAGE', '线索管理', 'LEAD', '/ai/crud-page/crm_lead', 'crm_lead', 'ionicons5:SparklesOutline', '线索标准后台业务入口', 3
-  UNION ALL SELECT 1910000000000000304, 'CRM_OPPORTUNITY_MANAGE', '商机管理', 'OPPORTUNITY', '/ai/crud-page/crm_opportunity', 'crm_opportunity', 'ionicons5:TrendingUpOutline', '商机标准后台业务入口', 4
-  UNION ALL SELECT 1910000000000000305, 'CRM_CONTRACT_MANAGE', '合同管理', 'CONTRACT', '/ai/crud-page/crm_contract', 'crm_contract', 'ionicons5:DocumentTextOutline', '合同标准后台业务入口', 5
-  UNION ALL SELECT 1910000000000000306, 'CRM_PAYMENT_MANAGE', '回款管理', 'PAYMENT', '/ai/crud-page/crm_payment', 'crm_payment', 'ionicons5:WalletOutline', '回款标准后台业务入口', 6
-  UNION ALL SELECT 1910000000000000307, 'CRM_FOLLOW_RECORD_MANAGE', '跟进记录', 'FOLLOW_RECORD', '/ai/crud-page/crm_follow_record', 'crm_follow_record', 'ionicons5:ChatbubblesOutline', '跟进记录标准后台业务入口', 7
-  UNION ALL SELECT 1910000000000000308, 'CRM_SALES_TASK_MANAGE', '销售任务', 'SALES_TASK', '/ai/crud-page/crm_sales_task', 'crm_sales_task', 'ionicons5:CheckboxOutline', '销售任务标准后台业务入口', 8
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_app a
-  WHERE a.tenant_id = 1
-    AND a.app_code = seed.app_code
-);

+ 0 - 183
forge-server/db/backup/V1.0.29__fix_business_app_center_menu_routes.sql

@@ -1,186 +0,0 @@
-
-SET @business_app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '应用中心', 0, 1, 6, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, NULL, 'ionicons5:GridOutline',
-       NULL, NULL, 0, 1, NULL, '企业应用装配平台目录', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-);
-
-SET @business_app_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '应用总览', @business_app_root_id, 2, 1, '/app-center', 'app-center/index', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessApp:list', 'ionicons5:GridOutline',
-       NULL, NULL, 1, 0, NULL, '企业应用装配平台主入口', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @business_app_root_id IS NOT NULL
-  AND @business_app_overview_id IS NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 2
-      AND perms = 'ai:businessApp:list'
-  );
-
-SET @business_app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET resource_name = '应用总览',
-    parent_id = @business_app_root_id,
-    sort = 1,
-    path = '/app-center',
-    component = 'app-center/index',
-    menu_status = 1,
-    visible = 1,
-    icon = 'ionicons5:GridOutline',
-    keep_alive = 1,
-    always_show = 0,
-    redirect = NULL,
-    remark = '企业应用装配平台主入口',
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_root_id IS NOT NULL
-  AND @business_app_overview_id IS NOT NULL
-  AND id = @business_app_overview_id;
-
-UPDATE sys_resource
-SET parent_id = @business_app_root_id,
-    menu_status = 1,
-    visible = 1,
-    path = CASE perms
-             WHEN 'ai:businessEngine:list' THEN '/app-center/engines'
-             WHEN 'ai:businessMobile:list' THEN '/app-center/mobile'
-             WHEN 'ai:businessIntegration:list' THEN '/app-center/integration'
-             ELSE path
-           END,
-    component = CASE perms
-                  WHEN 'ai:businessEngine:list' THEN 'app-center/engines'
-                  WHEN 'ai:businessMobile:list' THEN 'app-center/mobile'
-                  WHEN 'ai:businessIntegration:list' THEN 'app-center/integration'
-                  ELSE component
-                END,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_root_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND perms IN (
-    'ai:businessEngine:list',
-    'ai:businessMobile:list',
-    'ai:businessIntegration:list'
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_app_overview_id,
-    menu_status = 0,
-    visible = 0,
-    path = CASE perms
-             WHEN 'ai:businessSuite:list' THEN '/app-center/suite/:suiteCode'
-             WHEN 'ai:businessObject:list' THEN '/app-center/object/:objectCode'
-             ELSE path
-           END,
-    component = CASE perms
-                  WHEN 'ai:businessSuite:list' THEN 'app-center/suite/[suiteCode]'
-                  WHEN 'ai:businessObject:list' THEN 'app-center/object/[objectCode]'
-                  ELSE component
-                END,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_overview_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND perms IN (
-    'ai:businessSuite:list',
-    'ai:businessObject:list'
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_app_overview_id,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_overview_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 3
-  AND perms IN (
-    'ai:businessSuite:list',
-    'ai:businessSuite:edit',
-    'ai:businessObject:list',
-    'ai:businessObject:add',
-    'ai:businessObject:edit',
-    'ai:businessObject:delete',
-    'ai:businessObject:relation',
-    'ai:businessBinding:config',
-    'ai:businessApp:add',
-    'ai:businessApp:edit',
-    'ai:businessApp:delete',
-    'ai:businessApp:status',
-    'ai:businessApp:open'
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, @business_app_root_id, NOW()
-FROM sys_role_resource rr
-WHERE @business_app_root_id IS NOT NULL
-  AND @business_app_overview_id IS NOT NULL
-  AND rr.resource_id = @business_app_overview_id
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @business_app_root_id
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, @business_app_overview_id, NOW()
-FROM sys_role_resource rr
-WHERE @business_app_root_id IS NOT NULL
-  AND @business_app_overview_id IS NOT NULL
-  AND rr.resource_id = @business_app_root_id
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @business_app_overview_id
-  );

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 83
forge-server/db/backup/V1.0.2__add_ai_prompt_template_library.sql


+ 0 - 14
forge-server/db/backup/V1.0.30__fix_app_center_dynamic_route_components.sql

@@ -1,16 +0,0 @@
-UPDATE sys_resource
-SET component = CASE perms
-                  WHEN 'ai:businessSuite:list' THEN 'app-center/suite.[suiteCode]'
-                  WHEN 'ai:businessObject:list' THEN 'app-center/object.[objectCode]'
-                  ELSE component
-                END,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND perms IN (
-    'ai:businessSuite:list',
-    'ai:businessObject:list'
-  );

+ 0 - 116
forge-server/db/backup/V1.0.31__normalize_app_center_menu_directory.sql

@@ -1,117 +0,0 @@
-SET @business_app_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @business_app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  ORDER BY CASE WHEN parent_id = @business_app_root_id THEN 0 ELSE 1 END, id
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET path = NULL,
-    component = NULL,
-    perms = NULL,
-    menu_status = 1,
-    visible = 1,
-    always_show = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_root_id IS NOT NULL
-  AND id = @business_app_root_id
-  AND tenant_id = 1
-  AND resource_type = 1;
-
-UPDATE sys_resource
-SET resource_name = '应用总览',
-    parent_id = @business_app_root_id,
-    sort = 1,
-    path = '/app-center',
-    component = 'app-center/index',
-    menu_status = 1,
-    visible = 1,
-    icon = 'ionicons5:GridOutline',
-    keep_alive = 1,
-    always_show = 0,
-    redirect = NULL,
-    remark = '企业应用装配平台主入口',
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_root_id IS NOT NULL
-  AND @business_app_overview_id IS NOT NULL
-  AND id = @business_app_overview_id
-  AND tenant_id = 1;
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @business_app_root_id, 2, seed.sort, seed.path, seed.component, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, seed.icon,
-       NULL, NULL, 1, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '引擎中心' resource_name, 3 sort, '/app-center/engines' path, 'app-center/engines' component, 'ai:businessEngine:list' perms, 'ionicons5:HardwareChipOutline' icon, '流程、审批、报表、权限和消息引擎统一入口' remark
-  UNION ALL SELECT 1, '移动端中心', 4, '/app-center/mobile', 'app-center/mobile', 'ai:businessMobile:list', 'ionicons5:PhonePortraitOutline', '移动H5和移动业务入口'
-  UNION ALL SELECT 1, '集成中心', 5, '/app-center/integration', 'app-center/integration', 'ai:businessIntegration:list', 'ionicons5:GitNetworkOutline', '开放接口、Webhook和第三方平台连接入口'
-) seed
-WHERE @business_app_root_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.resource_type = 2
-      AND r.perms = seed.perms
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_app_root_id,
-    menu_status = 1,
-    visible = 1,
-    path = CASE perms
-             WHEN 'ai:businessEngine:list' THEN '/app-center/engines'
-             WHEN 'ai:businessMobile:list' THEN '/app-center/mobile'
-             WHEN 'ai:businessIntegration:list' THEN '/app-center/integration'
-             ELSE path
-           END,
-    component = CASE perms
-                  WHEN 'ai:businessEngine:list' THEN 'app-center/engines'
-                  WHEN 'ai:businessMobile:list' THEN 'app-center/mobile'
-                  WHEN 'ai:businessIntegration:list' THEN 'app-center/integration'
-                  ELSE component
-                END,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_root_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND perms IN (
-    'ai:businessEngine:list',
-    'ai:businessMobile:list',
-    'ai:businessIntegration:list'
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_app_overview_id,
-    menu_status = 0,
-    visible = 0,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_overview_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND perms IN (
-    'ai:businessSuite:list',
-    'ai:businessObject:list'
-  );

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 89
forge-server/db/backup/V1.0.32__seed_crm_customer_runtime_link.sql


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 144
forge-server/db/backup/V1.0.33__seed_crm_other_models.sql


+ 0 - 135
forge-server/db/backup/V1.0.34__normalize_lowcode_developer_menus.sql

@@ -1,137 +0,0 @@
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '开发者工具', 0, 1, 88, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, NULL, 'ionicons5:CodeSlashOutline',
-       NULL, NULL, 0, 1, NULL, '低代码、模型设计、数据源和代码输出等开发者入口', 1, NOW(),
-       1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-);
-
-SET @developer_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-  ORDER BY id
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET parent_id = @developer_root_id,
-    sort = CASE perms
-             WHEN 'ai:lowcode:domain:list' THEN 1
-             WHEN 'ai:lowcode:model:list' THEN 2
-             WHEN 'ai:datasource:list' THEN 3
-             WHEN 'gen:datasource:list' THEN 3
-             ELSE sort
-           END,
-    menu_status = 1,
-    visible = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE @developer_root_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND (
-    perms IN ('ai:lowcode:domain:list', 'ai:lowcode:model:list', 'ai:datasource:list', 'gen:datasource:list')
-    OR path IN ('/ai/lowcode-apps', '/ai/lowcode-models', '/generator/datasource')
-    OR component IN ('ai/lowcode-apps', 'ai/lowcode-models', 'generator/datasource')
-  );
-
-UPDATE sys_resource
-SET menu_status = 0,
-    visible = 0,
-    remark = CONCAT(COALESCE(remark, ''), ';已收敛到开发者工具或隐藏普通菜单入口'),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND (
-    path IN ('/ai/crud-config', '/ai/crud-generator', '/ai/page-template', '/generator/table', '/generator/template')
-    OR component IN ('ai/crud-config', 'ai/crud-generator', 'ai/page-template', 'generator/table', 'generator/template')
-    OR perms IN ('ai:crud-config:list', 'ai:crud-gen:list', 'ai:crud-generator:use', 'ai:page-template:list')
-  );
-
-UPDATE sys_resource
-SET parent_id = COALESCE(
-      CASE
-        WHEN perms IN (
-          'ai:lowcode:domain:add',
-          'ai:lowcode:domain:edit',
-          'ai:lowcode:domain:status',
-          'ai:lowcode:domain:move',
-          'ai:lowcode:publish',
-          'ai:lowcode:rollback',
-          'ai:lowcode:deploy-ddl',
-          'ai:lowcode:ai-generate',
-          'ai:lowcode:code-preview',
-          'ai:lowcode:code-download'
-        ) THEN (
-          SELECT id
-          FROM (
-            SELECT id
-            FROM sys_resource
-            WHERE tenant_id = 1
-              AND resource_type = 2
-              AND perms = 'ai:lowcode:domain:list'
-            LIMIT 1
-          ) app_menu
-        )
-        WHEN perms IN (
-          'ai:lowcode:model:add',
-          'ai:lowcode:model:edit',
-          'ai:lowcode:model:status',
-          'ai:lowcode:model:import-table',
-          'ai:lowcode:model:ai-generate'
-        ) THEN (
-          SELECT id
-          FROM (
-            SELECT id
-            FROM sys_resource
-            WHERE tenant_id = 1
-              AND resource_type = 2
-              AND perms = 'ai:lowcode:model:list'
-            LIMIT 1
-          ) model_menu
-        )
-        ELSE parent_id
-      END,
-      parent_id
-    ),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 3
-  AND perms LIKE 'ai:lowcode:%';
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, @developer_root_id, NOW()
-FROM sys_role_resource rr
-JOIN sys_resource r ON r.id = rr.resource_id
-WHERE @developer_root_id IS NOT NULL
-  AND r.tenant_id = 1
-  AND (
-    r.perms LIKE 'ai:lowcode:%'
-    OR r.perms IN ('ai:datasource:list', 'gen:datasource:list')
-    OR r.path IN ('/ai/lowcode-apps', '/ai/lowcode-models', '/generator/datasource')
-  )
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = @developer_root_id
-  );

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 127
forge-server/db/backup/V1.0.35__normalize_crm_lowcode_model_schema.sql


+ 0 - 213
forge-server/db/backup/V1.0.36__add_crm_runtime_tables.sql

@@ -1,222 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `crm_customer` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `customer_name` varchar(200) NOT NULL COMMENT '客户名称',
-    `customer_code` varchar(100) DEFAULT NULL COMMENT '客户编码',
-    `customer_type` varchar(50) DEFAULT 'ENTERPRISE' COMMENT '客户类型:ENTERPRISE-企业,PERSONAL-个人',
-    `industry` varchar(100) DEFAULT NULL COMMENT '所属行业',
-    `region_code` varchar(20) DEFAULT NULL COMMENT '区域编码',
-    `address` varchar(500) DEFAULT NULL COMMENT '详细地址',
-    `contact_name` varchar(100) DEFAULT NULL COMMENT '联系人',
-    `contact_phone` varchar(50) DEFAULT NULL COMMENT '联系电话',
-    `contact_email` varchar(200) DEFAULT NULL COMMENT '联系邮箱',
-    `source` varchar(50) DEFAULT NULL COMMENT '客户来源',
-    `level` varchar(20) DEFAULT 'NORMAL' COMMENT '客户等级:VIP-重要,NORMAL-普通,POTENTIAL-潜在',
-    `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-停用,1-启用',
-    `owner_id` bigint DEFAULT NULL COMMENT '负责人ID',
-    `owner_name` varchar(100) DEFAULT NULL COMMENT '负责人名称',
-    `dept_id` bigint DEFAULT NULL COMMENT '部门ID',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_customer_tenant_id` (`tenant_id`),
-    KEY `idx_crm_customer_status` (`tenant_id`, `status`),
-    KEY `idx_crm_customer_owner` (`tenant_id`, `owner_id`),
-    KEY `idx_crm_customer_create_time` (`tenant_id`, `create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM客户表';
-
-CREATE TABLE IF NOT EXISTS `crm_contact` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `customer_id` bigint NOT NULL COMMENT '客户ID',
-    `contact_name` varchar(100) NOT NULL COMMENT '联系人姓名',
-    `gender` tinyint DEFAULT NULL COMMENT '性别:0-女,1-男',
-    `position` varchar(100) DEFAULT NULL COMMENT '职位',
-    `phone` varchar(50) DEFAULT NULL COMMENT '手机号码',
-    `telephone` varchar(50) DEFAULT NULL COMMENT '固定电话',
-    `email` varchar(200) DEFAULT NULL COMMENT '邮箱',
-    `wechat` varchar(100) DEFAULT NULL COMMENT '微信号',
-    `is_primary` tinyint NOT NULL DEFAULT '0' COMMENT '是否主联系人:0-否,1-是',
-    `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-停用,1-启用',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_contact_tenant_id` (`tenant_id`),
-    KEY `idx_crm_contact_customer` (`tenant_id`, `customer_id`),
-    KEY `idx_crm_contact_status` (`tenant_id`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM联系人表';
-
-CREATE TABLE IF NOT EXISTS `crm_opportunity` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `customer_id` bigint NOT NULL COMMENT '客户ID',
-    `opportunity_name` varchar(200) NOT NULL COMMENT '商机名称',
-    `opportunity_code` varchar(100) DEFAULT NULL COMMENT '商机编码',
-    `stage` varchar(50) DEFAULT 'INITIAL' COMMENT '商机阶段:INITIAL-初步接触,FOLLOWING-跟进中,NEGOTIATION-商务谈判,CLOSED_WON-赢单,CLOSED_LOST-丢单',
-    `amount_cent` bigint DEFAULT '0' COMMENT '预计金额(分)',
-    `probability` int DEFAULT '0' COMMENT '赢单概率(0-100)',
-    `expected_close_date` date DEFAULT NULL COMMENT '预计成交日期',
-    `actual_close_date` date DEFAULT NULL COMMENT '实际成交日期',
-    `source` varchar(50) DEFAULT NULL COMMENT '商机来源',
-    `owner_id` bigint DEFAULT NULL COMMENT '负责人ID',
-    `owner_name` varchar(100) DEFAULT NULL COMMENT '负责人名称',
-    `dept_id` bigint DEFAULT NULL COMMENT '部门ID',
-    `contact_id` bigint DEFAULT NULL COMMENT '联系人ID',
-    `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-停用,1-启用',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_opportunity_tenant_id` (`tenant_id`),
-    KEY `idx_crm_opportunity_customer` (`tenant_id`, `customer_id`),
-    KEY `idx_crm_opportunity_stage` (`tenant_id`, `stage`),
-    KEY `idx_crm_opportunity_owner` (`tenant_id`, `owner_id`),
-    KEY `idx_crm_opportunity_status` (`tenant_id`, `status`),
-    KEY `idx_crm_opportunity_create_time` (`tenant_id`, `create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM商机表';
-
-CREATE TABLE IF NOT EXISTS `crm_contract` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `customer_id` bigint NOT NULL COMMENT '客户ID',
-    `opportunity_id` bigint DEFAULT NULL COMMENT '商机ID',
-    `contract_name` varchar(200) NOT NULL COMMENT '合同名称',
-    `contract_code` varchar(100) DEFAULT NULL COMMENT '合同编码',
-    `contract_type` varchar(50) DEFAULT 'SALES' COMMENT '合同类型:SALES-销售,SERVICE-服务,FRAMEWORK-框架',
-    `amount_cent` bigint NOT NULL DEFAULT '0' COMMENT '合同金额(分)',
-    `sign_date` date DEFAULT NULL COMMENT '签约日期',
-    `start_date` date DEFAULT NULL COMMENT '开始日期',
-    `end_date` date DEFAULT NULL COMMENT '结束日期',
-    `status` varchar(50) DEFAULT 'DRAFT' COMMENT '合同状态:DRAFT-草稿,PENDING_APPROVAL-待审批,APPROVED-已审批,EXECUTING-执行中,COMPLETED-已完成,TERMINATED-已终止',
-    `approval_status` varchar(50) DEFAULT NULL COMMENT '审批状态',
-    `approval_id` bigint DEFAULT NULL COMMENT '审批流程ID',
-    `owner_id` bigint DEFAULT NULL COMMENT '负责人ID',
-    `owner_name` varchar(100) DEFAULT NULL COMMENT '负责人名称',
-    `dept_id` bigint DEFAULT NULL COMMENT '部门ID',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_contract_tenant_id` (`tenant_id`),
-    KEY `idx_crm_contract_customer` (`tenant_id`, `customer_id`),
-    KEY `idx_crm_contract_opportunity` (`tenant_id`, `opportunity_id`),
-    KEY `idx_crm_contract_status` (`tenant_id`, `status`),
-    KEY `idx_crm_contract_owner` (`tenant_id`, `owner_id`),
-    KEY `idx_crm_contract_create_time` (`tenant_id`, `create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM合同表';
-
-CREATE TABLE IF NOT EXISTS `crm_contract_item` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `contract_id` bigint NOT NULL COMMENT '合同ID',
-    `product_name` varchar(200) NOT NULL COMMENT '产品名称',
-    `product_code` varchar(100) DEFAULT NULL COMMENT '产品编码',
-    `product_spec` varchar(200) DEFAULT NULL COMMENT '产品规格',
-    `unit` varchar(20) DEFAULT NULL COMMENT '单位',
-    `quantity` decimal(18,4) DEFAULT '0' COMMENT '数量',
-    `unit_price_cent` bigint DEFAULT '0' COMMENT '单价(分)',
-    `amount_cent` bigint DEFAULT '0' COMMENT '金额(分)',
-    `sort_order` int DEFAULT '0' COMMENT '排序',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_contract_item_tenant_id` (`tenant_id`),
-    KEY `idx_crm_contract_item_contract` (`tenant_id`, `contract_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM合同明细表';
-
-CREATE TABLE IF NOT EXISTS `crm_payment` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `contract_id` bigint NOT NULL COMMENT '合同ID',
-    `customer_id` bigint NOT NULL COMMENT '客户ID',
-    `payment_code` varchar(100) DEFAULT NULL COMMENT '回款编码',
-    `amount_cent` bigint NOT NULL DEFAULT '0' COMMENT '回款金额(分)',
-    `payment_date` date NOT NULL COMMENT '回款日期',
-    `payment_method` varchar(50) DEFAULT 'BANK_TRANSFER' COMMENT '回款方式:BANK_TRANSFER-银行转账,CASH-现金,CHECK-支票,OTHER-其他',
-    `payment_status` varchar(50) DEFAULT 'PENDING' COMMENT '回款状态:PENDING-待确认,CONFIRMED-已确认,REJECTED-已驳回',
-    `receiver_id` bigint DEFAULT NULL COMMENT '收款人ID',
-    `receiver_name` varchar(100) DEFAULT NULL COMMENT '收款人名称',
-    `invoice_no` varchar(100) DEFAULT NULL COMMENT '发票号',
-    `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_payment_tenant_id` (`tenant_id`),
-    KEY `idx_crm_payment_contract` (`tenant_id`, `contract_id`),
-    KEY `idx_crm_payment_customer` (`tenant_id`, `customer_id`),
-    KEY `idx_crm_payment_status` (`tenant_id`, `payment_status`),
-    KEY `idx_crm_payment_date` (`tenant_id`, `payment_date`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM回款表';
-
-CREATE TABLE IF NOT EXISTS `crm_follow_record` (
-    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-    `customer_id` bigint NOT NULL COMMENT '客户ID',
-    `opportunity_id` bigint DEFAULT NULL COMMENT '商机ID',
-    `contact_id` bigint DEFAULT NULL COMMENT '联系人ID',
-    `follow_type` varchar(50) DEFAULT 'VISIT' COMMENT '跟进方式:VISIT-拜访,PHONE-电话,EMAIL-邮件,WECHAT-微信,OTHER-其他',
-    `follow_content` text NOT NULL COMMENT '跟进内容',
-    `follow_time` datetime NOT NULL COMMENT '跟进时间',
-    `next_follow_time` datetime DEFAULT NULL COMMENT '下次跟进时间',
-    `next_follow_content` varchar(500) DEFAULT NULL COMMENT '下次跟进内容',
-    `follow_user_id` bigint DEFAULT NULL COMMENT '跟进人ID',
-    `follow_user_name` varchar(100) DEFAULT NULL COMMENT '跟进人名称',
-    `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-停用,1-启用',
-    `options` text DEFAULT NULL COMMENT '扩展配置JSON',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    `del_flag` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常,1-删除',
-    PRIMARY KEY (`id`),
-    KEY `idx_crm_follow_record_tenant_id` (`tenant_id`),
-    KEY `idx_crm_follow_record_customer` (`tenant_id`, `customer_id`),
-    KEY `idx_crm_follow_record_opportunity` (`tenant_id`, `opportunity_id`),
-    KEY `idx_crm_follow_record_contact` (`tenant_id`, `contact_id`),
-    KEY `idx_crm_follow_record_time` (`tenant_id`, `follow_time`),
-    KEY `idx_crm_follow_record_user` (`tenant_id`, `follow_user_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CRM跟进记录表';

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 55
forge-server/db/backup/V1.0.37__seed_crm_runtime_crud_configs.sql


+ 0 - 43
forge-server/db/backup/V1.0.38__normalize_crm_business_object_runtime.sql

@@ -1,51 +0,0 @@
-
-UPDATE `ai_business_object` 
-SET `model_code` = 'crm_customer', `update_time` = NOW()
-WHERE `tenant_id` = 1 
-  AND `suite_code` = 'CRM' 
-  AND `object_code` = 'customer' 
-  AND (`model_code` IS NULL OR `model_code` = '');
-
-UPDATE `ai_business_object` 
-SET `model_code` = 'crm_contact', `update_time` = NOW()
-WHERE `tenant_id` = 1 
-  AND `suite_code` = 'CRM' 
-  AND `object_code` = 'contact' 
-  AND (`model_code` IS NULL OR `model_code` = '');
-
-UPDATE `ai_business_object` 
-SET `model_code` = 'crm_opportunity', `update_time` = NOW()
-WHERE `tenant_id` = 1 
-  AND `suite_code` = 'CRM' 
-  AND `object_code` = 'opportunity' 
-  AND (`model_code` IS NULL OR `model_code` = '');
-
-UPDATE `ai_business_object` 
-SET `model_code` = 'crm_contract', `update_time` = NOW()
-WHERE `tenant_id` = 1 
-  AND `suite_code` = 'CRM' 
-  AND `object_code` = 'contract' 
-  AND (`model_code` IS NULL OR `model_code` = '');
-
-UPDATE `ai_business_object` 
-SET `model_code` = 'crm_payment', `update_time` = NOW()
-WHERE `tenant_id` = 1 
-  AND `suite_code` = 'CRM' 
-  AND `object_code` = 'payment' 
-  AND (`model_code` IS NULL OR `model_code` = '');
-
-UPDATE `ai_business_app` a
-INNER JOIN `ai_crud_config` c ON c.`tenant_id` = a.`tenant_id` AND c.`object_code` = a.`object_code` AND c.`domain_code` = a.`suite_code`
-SET a.`config_key` = c.`config_key`, a.`update_time` = NOW()
-WHERE a.`tenant_id` = 1 
-  AND a.`suite_code` = 'CRM' 
-  AND a.`entry_mode` = 'RUNTIME'
-  AND (a.`config_key` IS NULL OR a.`config_key` = '');

+ 0 - 15
forge-server/db/backup/V1.0.39__fix_crm_runtime_config_status.sql

@@ -1,17 +0,0 @@
-
-UPDATE ai_crud_config
-SET status = '0',
-    publish_status = 'PUBLISHED',
-    options = JSON_SET(
-      COALESCE(NULLIF(options, ''), '{}'),
-      '$.importEnabled', true,
-      '$.exportEnabled', true,
-      '$.detailEnabled', true,
-      '$.showImport', true,
-      '$.showExport', true
-    ),
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND config_key IN ('crm_customer', 'crm_contact', 'crm_opportunity', 'crm_contract', 'crm_payment');

+ 0 - 20
forge-server/db/backup/V1.0.3__add_custom_query_scheme.sql

@@ -1,20 +0,0 @@
-CREATE TABLE IF NOT EXISTS `ai_custom_query_scheme` (
-  `id` bigint NOT NULL COMMENT '主键',
-  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户编号',
-  `config_key` varchar(64) NOT NULL COMMENT 'CRUD配置键',
-  `scheme_name` varchar(128) NOT NULL COMMENT '查询方案名称',
-  `conditions_json` json DEFAULT NULL COMMENT '查询条件JSON',
-  `columns_json` json DEFAULT NULL COMMENT '展示字段JSON',
-  `sort_json` json DEFAULT NULL COMMENT '排序配置JSON',
-  `display_json` json DEFAULT NULL COMMENT '展示方式配置JSON',
-  `is_default` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认方案(1是 0否)',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  PRIMARY KEY (`id`),
-  KEY `idx_tenant_config_user` (`tenant_id`, `config_key`, `create_by`),
-  KEY `idx_tenant_config_default` (`tenant_id`, `config_key`, `create_by`, `is_default`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI自定义查询方案表';

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 208
forge-server/db/backup/V1.0.40__add_business_object_designer.sql


+ 0 - 219
forge-server/db/backup/V1.0.41__add_business_object_designer_menu_permissions.sql

@@ -1,220 +0,0 @@
-
-SET @business_app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '业务对象设计器', @business_app_overview_id, 2, 6, '/app-center/object/:objectCode/designer',
-       'app-center/object-designer.[objectCode]', 0,
-       0, NULL, '_self', 0, 0, 0, 'ai:businessObject:design', 'ionicons5:BuildOutline',
-       NULL, NULL, 0, 0, NULL, '业务对象设计器隐藏路由', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @business_app_overview_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 2
-      AND perms = 'ai:businessObject:design'
-      AND path = '/app-center/object/:objectCode/designer'
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_app_overview_id,
-    resource_name = '业务对象设计器',
-    path = '/app-center/object/:objectCode/designer',
-    component = 'app-center/object-designer.[objectCode]',
-    menu_status = 0,
-    visible = 0,
-    icon = 'ionicons5:BuildOutline',
-    remark = '业务对象设计器隐藏路由',
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_app_overview_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND perms = 'ai:businessObject:design';
-
-SET @business_object_designer_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessObject:design'
-    AND path = '/app-center/object/:objectCode/designer'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @business_object_permission_parent_id := COALESCE(@business_object_designer_id, @business_app_overview_id);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @business_object_permission_parent_id, 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '设计业务对象' resource_name, 26 sort, 'ai:businessObject:design' perms, '进入和保存业务对象设计器' remark
-  UNION ALL SELECT 1, '维护业务字段', 27, 'ai:businessObject:field', '新增、编辑、删除和排序业务字段'
-  UNION ALL SELECT 1, '维护对象布局', 28, 'ai:businessObject:layout', '维护表单、列表和详情布局'
-  UNION ALL SELECT 1, '配置对象操作', 29, 'ai:businessObject:action', '配置工具栏、行和详情自定义操作'
-  UNION ALL SELECT 1, '发布业务对象', 30, 'ai:businessObject:publish', '执行发布检查并发布业务对象'
-  UNION ALL SELECT 1, '高级对象配置', 31, 'ai:businessObject:advanced', '查看模型、表名、Schema、DDL和开发者入口'
-) seed
-WHERE @business_object_permission_parent_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.resource_type = 3
-      AND r.perms = seed.perms
-  );
-
-UPDATE sys_resource
-SET parent_id = @business_object_permission_parent_id,
-    sort = CASE perms
-             WHEN 'ai:businessObject:relation' THEN 25
-             WHEN 'ai:businessObject:design' THEN 26
-             WHEN 'ai:businessObject:field' THEN 27
-             WHEN 'ai:businessObject:layout' THEN 28
-             WHEN 'ai:businessObject:action' THEN 29
-             WHEN 'ai:businessObject:publish' THEN 30
-             WHEN 'ai:businessObject:advanced' THEN 31
-             ELSE sort
-           END,
-    resource_name = CASE perms
-                      WHEN 'ai:businessObject:relation' THEN '配置对象关系'
-                      WHEN 'ai:businessObject:design' THEN '设计业务对象'
-                      WHEN 'ai:businessObject:field' THEN '维护业务字段'
-                      WHEN 'ai:businessObject:layout' THEN '维护对象布局'
-                      WHEN 'ai:businessObject:action' THEN '配置对象操作'
-                      WHEN 'ai:businessObject:publish' THEN '发布业务对象'
-                      WHEN 'ai:businessObject:advanced' THEN '高级对象配置'
-                      ELSE resource_name
-                    END,
-    menu_status = 1,
-    visible = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE @business_object_permission_parent_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 3
-  AND perms IN (
-    'ai:businessObject:relation',
-    'ai:businessObject:design',
-    'ai:businessObject:field',
-    'ai:businessObject:layout',
-    'ai:businessObject:action',
-    'ai:businessObject:publish',
-    'ai:businessObject:advanced'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '开发者工具', 0, 1, 88, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, NULL, 'ionicons5:CodeSlashOutline',
-       NULL, NULL, 0, 1, NULL, '低代码、模型设计、数据源和代码输出等开发者入口', 1, NOW(),
-       1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-);
-
-SET @developer_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-  ORDER BY id
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET parent_id = @developer_root_id,
-    menu_status = 1,
-    visible = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE @developer_root_id IS NOT NULL
-  AND tenant_id = 1
-  AND resource_type = 2
-  AND (
-    perms IN ('ai:lowcode:domain:list', 'ai:lowcode:model:list', 'ai:datasource:list', 'gen:datasource:list')
-    OR path IN ('/ai/lowcode-apps', '/ai/lowcode-models', '/generator/datasource')
-    OR component IN ('ai/lowcode-apps', 'ai/lowcode-models', 'generator/datasource')
-  );
-
-UPDATE sys_resource
-SET menu_status = 0,
-    visible = 0,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND (
-    path IN ('/ai/crud-config', '/ai/crud-generator', '/ai/page-template', '/generator/table', '/generator/template')
-    OR component IN ('ai/crud-config', 'ai/crud-generator', 'ai/page-template', 'generator/table', 'generator/template')
-    OR perms IN ('ai:crud-config:list', 'ai:crud-gen:list', 'ai:crud-generator:use', 'ai:page-template:list')
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, target.id, NOW()
-FROM sys_role_resource rr
-JOIN sys_resource src ON src.id = rr.resource_id
-JOIN sys_resource target ON target.tenant_id = 1
-WHERE src.tenant_id = 1
-  AND src.perms IN ('ai:businessObject:list', 'ai:businessObject:add', 'ai:businessObject:edit', 'ai:businessObject:relation')
-  AND target.perms IN (
-    'ai:businessObject:design',
-    'ai:businessObject:field',
-    'ai:businessObject:layout',
-    'ai:businessObject:relation',
-    'ai:businessObject:action',
-    'ai:businessObject:publish'
-  )
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = target.id
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, target.id, NOW()
-FROM sys_role_resource rr
-JOIN sys_resource src ON src.id = rr.resource_id
-JOIN sys_resource target ON target.tenant_id = 1
-WHERE src.tenant_id = 1
-  AND (
-    src.perms LIKE 'ai:lowcode:%'
-    OR src.perms IN ('ai:crud-config:list', 'ai:crud-gen:list', 'ai:crud-generator:use', 'ai:page-template:list', 'ai:datasource:list', 'gen:datasource:list')
-    OR src.path IN ('/ai/lowcode-apps', '/ai/lowcode-models', '/generator/datasource')
-  )
-  AND target.perms = 'ai:businessObject:advanced'
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 26
forge-server/db/backup/V1.0.42__fix_crm_business_relation_field_direction.sql

@@ -1,28 +0,0 @@
-
-UPDATE ai_business_object_relation
-SET source_field_code = 'id',
-    target_field_code = 'customerId',
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND suite_code = 'CRM'
-  AND source_object_code = 'CUSTOMER'
-  AND target_object_code IN ('CONTACT', 'OPPORTUNITY', 'FOLLOW_RECORD')
-  AND relation_type = 'CHILD_LIST'
-  AND source_field_code = 'customerId'
-  AND target_field_code = 'id';
-
-UPDATE ai_business_object_relation
-SET source_field_code = 'id',
-    target_field_code = 'opportunityId',
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND suite_code = 'CRM'
-  AND source_object_code = 'OPPORTUNITY'
-  AND target_object_code = 'FOLLOW_RECORD'
-  AND relation_type = 'CHILD_LIST'
-  AND source_field_code = 'opportunityId'
-  AND target_field_code = 'id';

+ 0 - 390
forge-server/db/backup/V1.0.43__align_crm_follow_record_table_with_model.sql

@@ -1,393 +0,0 @@
-
-SET @table_exists = (
-    SELECT COUNT(*)
-    FROM information_schema.TABLES
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'crm_follow_record'
-);
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'crm_follow_record'
-              AND COLUMN_NAME = 'subject'
-        ) = 0,
-        'ALTER TABLE crm_follow_record ADD COLUMN `subject` VARCHAR(256) NOT NULL DEFAULT '''' COMMENT ''主题'' AFTER `tenant_id`',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'crm_follow_record'
-              AND COLUMN_NAME = 'type'
-        ) = 0,
-        'ALTER TABLE crm_follow_record ADD COLUMN `type` VARCHAR(32) DEFAULT NULL COMMENT ''跟进方式'' AFTER `opportunity_id`',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'crm_follow_record'
-              AND COLUMN_NAME = 'content'
-        ) = 0,
-        'ALTER TABLE crm_follow_record ADD COLUMN `content` TEXT DEFAULT NULL COMMENT ''跟进内容'' AFTER `type`',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        (
-            SELECT COUNT(*)
-            FROM information_schema.COLUMNS
-            WHERE TABLE_SCHEMA = DATABASE()
-              AND TABLE_NAME = 'crm_follow_record'
-              AND COLUMN_NAME = 'assignee_id'
-        ) = 0,
-        'ALTER TABLE crm_follow_record ADD COLUMN `assignee_id` BIGINT DEFAULT NULL COMMENT ''负责人'' AFTER `follow_time`',
-        'SELECT 1'
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @has_follow_type = (
-    SELECT COUNT(*)
-    FROM information_schema.COLUMNS
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'crm_follow_record'
-      AND COLUMN_NAME = 'follow_type'
-);
-
-SET @has_follow_content = (
-    SELECT COUNT(*)
-    FROM information_schema.COLUMNS
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'crm_follow_record'
-      AND COLUMN_NAME = 'follow_content'
-);
-
-SET @has_follow_user_id = (
-    SELECT COUNT(*)
-    FROM information_schema.COLUMNS
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'crm_follow_record'
-      AND COLUMN_NAME = 'follow_user_id'
-);
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_type > 0,
-    'UPDATE crm_follow_record SET `type` = COALESCE(`type`, follow_type) WHERE `type` IS NULL AND follow_type IS NOT NULL',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_content > 0,
-    'UPDATE crm_follow_record SET `content` = COALESCE(`content`, follow_content) WHERE `content` IS NULL AND follow_content IS NOT NULL',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_user_id > 0,
-    'UPDATE crm_follow_record SET assignee_id = COALESCE(assignee_id, follow_user_id) WHERE assignee_id IS NULL AND follow_user_id IS NOT NULL',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    IF(
-        @has_follow_content > 0,
-        'UPDATE crm_follow_record SET subject = LEFT(COALESCE(NULLIF(subject, ''''), NULLIF(content, ''''), NULLIF(follow_content, ''''), ''跟进记录''), 256) WHERE subject IS NULL OR subject = ''''',
-        'UPDATE crm_follow_record SET subject = LEFT(COALESCE(NULLIF(subject, ''''), NULLIF(content, ''''), ''跟进记录''), 256) WHERE subject IS NULL OR subject = '''''
-    )
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `subject` VARCHAR(256) NOT NULL DEFAULT '''' COMMENT ''主题'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `customer_id` BIGINT DEFAULT NULL COMMENT ''关联客户'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `opportunity_id` BIGINT DEFAULT NULL COMMENT ''关联商机'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `type` VARCHAR(32) DEFAULT NULL COMMENT ''跟进方式'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `content` TEXT DEFAULT NULL COMMENT ''跟进内容'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `follow_time` DATETIME DEFAULT NULL COMMENT ''跟进时间'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `assignee_id` BIGINT DEFAULT NULL COMMENT ''负责人'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 0,
-    'SELECT 1',
-    'ALTER TABLE crm_follow_record MODIFY COLUMN `del_flag` CHAR(1) NOT NULL DEFAULT ''0'' COMMENT ''删除标志'''
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.STATISTICS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND INDEX_NAME = 'idx_crm_follow_record_contact'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP INDEX idx_crm_follow_record_contact',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.STATISTICS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND INDEX_NAME = 'idx_crm_follow_record_user'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP INDEX idx_crm_follow_record_user',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.STATISTICS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND INDEX_NAME = 'idx_crm_follow_record_assignee'
-    ) = 0,
-    'ALTER TABLE crm_follow_record ADD INDEX idx_crm_follow_record_assignee (`tenant_id`, `assignee_id`)',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'contact_id'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `contact_id`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_type > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `follow_type`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_content > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `follow_content`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'next_follow_time'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `next_follow_time`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'next_follow_content'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `next_follow_content`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1 AND @has_follow_user_id > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `follow_user_id`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'follow_user_name'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `follow_user_name`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'status'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `status`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql = IF(
-    @table_exists = 1
-    AND (
-        SELECT COUNT(*)
-        FROM information_schema.COLUMNS
-        WHERE TABLE_SCHEMA = DATABASE()
-          AND TABLE_NAME = 'crm_follow_record'
-          AND COLUMN_NAME = 'options'
-    ) > 0,
-    'ALTER TABLE crm_follow_record DROP COLUMN `options`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 95
forge-server/db/backup/V1.0.44__add_crm_contact_customer_reference_relation.sql

@@ -1,97 +0,0 @@
-
-UPDATE ai_business_object_relation
-SET relation_config = JSON_SET(
-        COALESCE(relation_config, JSON_OBJECT()),
-        '$.displayField', 'contactName',
-        '$.detailTabTitle', COALESCE(
-            JSON_UNQUOTE(JSON_EXTRACT(relation_config, '$.detailTabTitle')),
-            JSON_UNQUOTE(JSON_EXTRACT(relation_config, '$.detailTab')),
-            '联系人'
-        )
-    ),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND suite_code = 'CRM'
-  AND source_object_code = 'CUSTOMER'
-  AND target_object_code = 'CONTACT'
-  AND relation_type = 'CHILD_LIST';
-
-INSERT INTO ai_business_object_relation (
-    id,
-    tenant_id,
-    suite_code,
-    source_object_code,
-    target_object_code,
-    relation_type,
-    relation_name,
-    source_field_code,
-    target_field_code,
-    relation_config,
-    description,
-    status,
-    sort_order,
-    create_by,
-    create_time,
-    create_dept,
-    update_by,
-    update_time
-)
-SELECT
-    1910000000000000210,
-    1,
-    'CRM',
-    'CONTACT',
-    'CUSTOMER',
-    'REFERENCE',
-    '联系人属于客户',
-    'customerId',
-    'id',
-    JSON_OBJECT(
-        'displayField', 'customerName',
-        'businessText', '联系人列表通过客户名称回显所属客户',
-        'showInDetail', false,
-        'inlineCreateEnabled', false,
-        'inlineEditEnabled', false
-    ),
-    '联系人通过 customerId 归属客户,运行态列表回显客户名称',
-    1,
-    10,
-    1,
-    NOW(),
-    1,
-    1,
-    NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM ai_business_object_relation
-    WHERE tenant_id = 1
-      AND suite_code = 'CRM'
-      AND source_object_code = 'CONTACT'
-      AND target_object_code = 'CUSTOMER'
-      AND relation_type = 'REFERENCE'
-      AND relation_name = '联系人属于客户'
-)
-AND NOT EXISTS (
-    SELECT 1
-    FROM ai_business_object_relation
-    WHERE tenant_id = 1
-      AND id = 1910000000000000210
-);
-
-UPDATE ai_business_object_relation
-SET source_field_code = 'customerId',
-    target_field_code = 'id',
-    relation_config = JSON_SET(
-        COALESCE(relation_config, JSON_OBJECT()),
-        '$.displayField', 'customerName'
-    ),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND suite_code = 'CRM'
-  AND source_object_code = 'CONTACT'
-  AND target_object_code = 'CUSTOMER'
-  AND relation_type = 'REFERENCE';

+ 0 - 16
forge-server/db/backup/V1.0.45__add_business_object_design_version_designer_snapshot.sql

@@ -1,16 +0,0 @@
-SET @column_exists := (
-    SELECT COUNT(1)
-    FROM information_schema.COLUMNS
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'ai_business_object_design_version'
-      AND COLUMN_NAME = 'designer_options_snapshot'
-);
-
-SET @sql := IF(
-    @column_exists = 0,
-    'ALTER TABLE `ai_business_object_design_version` ADD COLUMN `designer_options_snapshot` json DEFAULT NULL COMMENT ''表单优先设计器扩展快照'' AFTER `relation_snapshot`',
-    'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 175
forge-server/db/backup/V1.0.46__add_business_trigger_and_message_channel.sql

@@ -1,182 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_business_trigger` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `suite_code` varchar(48) NOT NULL COMMENT '所属业务套件编码',
-  `object_code` varchar(48) NOT NULL COMMENT '所属业务对象编码',
-  `trigger_name` varchar(128) NOT NULL COMMENT '触发器名称',
-  `trigger_desc` varchar(500) DEFAULT NULL COMMENT '触发器说明',
-  `trigger_type` varchar(32) NOT NULL DEFAULT 'EVENT' COMMENT '触发器类型:EVENT事件触发/SCHEDULE定时触发/MANUAL手动触发',
-  `event_type` varchar(64) DEFAULT NULL COMMENT '事件类型:RECORD_CREATED/RECORD_UPDATED/RECORD_DELETED/STATUS_CHANGED/FIELD_CHANGED',
-  `event_condition` json DEFAULT NULL COMMENT '事件条件表达式JSON',
-  `action_type` varchar(32) NOT NULL COMMENT '动作类型:START_FLOW/SEND_MESSAGE/CREATE_RECORD/UPDATE_FIELD/WEBHOOK',
-  `action_config` json NOT NULL COMMENT '动作配置JSON',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `execute_count` bigint NOT NULL DEFAULT 0 COMMENT '累计执行次数',
-  `last_execute_time` datetime DEFAULT NULL COMMENT '最近执行时间',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  KEY `idx_ai_business_trigger_object` (`tenant_id`, `suite_code`, `object_code`, `status`),
-  KEY `idx_ai_business_trigger_event` (`tenant_id`, `object_code`, `event_type`, `status`),
-  KEY `idx_ai_business_trigger_type` (`tenant_id`, `trigger_type`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-触发器规则表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_trigger_log` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `trigger_id` bigint NOT NULL COMMENT '触发器ID',
-  `trigger_name` varchar(128) DEFAULT NULL COMMENT '触发器名称',
-  `suite_code` varchar(48) NOT NULL COMMENT '业务套件编码',
-  `object_code` varchar(48) NOT NULL COMMENT '业务对象编码',
-  `record_id` varchar(64) DEFAULT NULL COMMENT '触发记录ID',
-  `event_type` varchar(64) NOT NULL COMMENT '触发事件类型',
-  `event_data` json DEFAULT NULL COMMENT '事件数据快照',
-  `action_type` varchar(32) NOT NULL COMMENT '执行动作类型',
-  `action_result` json DEFAULT NULL COMMENT '执行结果',
-  `execute_status` varchar(32) NOT NULL DEFAULT 'PENDING' COMMENT '执行状态:PENDING/SUCCESS/FAILED/SKIPPED',
-  `error_message` varchar(2000) DEFAULT NULL COMMENT '错误信息',
-  `execute_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '执行时间',
-  `duration_ms` bigint DEFAULT NULL COMMENT '执行耗时(毫秒)',
-  `retry_count` int NOT NULL DEFAULT 0 COMMENT '重试次数',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  PRIMARY KEY (`id`),
-  KEY `idx_ai_trigger_log_trigger` (`tenant_id`, `trigger_id`, `execute_status`),
-  KEY `idx_ai_trigger_log_object` (`tenant_id`, `object_code`, `execute_time`),
-  KEY `idx_ai_trigger_log_record` (`tenant_id`, `object_code`, `record_id`),
-  KEY `idx_ai_trigger_log_time` (`tenant_id`, `execute_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-触发器执行日志表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_message_channel` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `channel_code` varchar(64) NOT NULL COMMENT '通道编码',
-  `channel_name` varchar(128) NOT NULL COMMENT '通道名称',
-  `channel_type` varchar(32) NOT NULL COMMENT '通道类型:WECHAT_WORK/FEISHU/DINGTALK/WEBHOOK/INTERNAL',
-  `channel_config_ref` varchar(256) DEFAULT NULL COMMENT '通道配置安全引用(不存明文密钥)',
-  `webhook_url` varchar(512) DEFAULT NULL COMMENT 'Webhook地址(仅WEBHOOK类型)',
-  `description` varchar(500) DEFAULT NULL COMMENT '通道说明',
-  `status` int NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `options` json DEFAULT NULL COMMENT '扩展配置',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_message_channel_code` (`tenant_id`, `channel_code`),
-  KEY `idx_ai_message_channel_type` (`tenant_id`, `channel_type`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-消息推送通道表';
-
-INSERT INTO ai_business_message_channel (id, tenant_id, channel_code, channel_name, channel_type, channel_config_ref,
-                                          description, status, sort_order, create_by, create_time, create_dept,
-                                          update_by, update_time)
-SELECT 1910000000000001001, 1, 'internal_websocket', '站内信(WebSocket)', 'INTERNAL', NULL,
-       '系统内置站内信通道,通过WebSocket实时推送', 1, 0, 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM ai_business_message_channel
-  WHERE tenant_id = 1 AND channel_code = 'internal_websocket'
-);
-
-INSERT INTO ai_business_message_channel (id, tenant_id, channel_code, channel_name, channel_type, channel_config_ref,
-                                          description, status, sort_order, create_by, create_time, create_dept,
-                                          update_by, update_time)
-SELECT 1910000000000001002, 1, 'wechat_work', '企业微信', 'WECHAT_WORK', NULL,
-       '企业微信消息推送通道(待实现)', 0, 1, 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM ai_business_message_channel
-  WHERE tenant_id = 1 AND channel_code = 'wechat_work'
-);
-
-INSERT INTO ai_business_message_channel (id, tenant_id, channel_code, channel_name, channel_type, channel_config_ref,
-                                          description, status, sort_order, create_by, create_time, create_dept,
-                                          update_by, update_time)
-SELECT 1910000000000001003, 1, 'feishu', '飞书', 'FEISHU', NULL,
-       '飞书消息推送通道(待实现)', 0, 2, 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM ai_business_message_channel
-  WHERE tenant_id = 1 AND channel_code = 'feishu'
-);
-
-INSERT INTO ai_business_message_channel (id, tenant_id, channel_code, channel_name, channel_type, channel_config_ref,
-                                          description, status, sort_order, create_by, create_time, create_dept,
-                                          update_by, update_time)
-SELECT 1910000000000001004, 1, 'dingtalk', '钉钉', 'DINGTALK', NULL,
-       '钉钉消息推送通道(待实现)', 0, 3, 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1 FROM ai_business_message_channel
-  WHERE tenant_id = 1 AND channel_code = 'dingtalk'
-);
-
-SET @app_center_menu_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND resource_type = 2 AND perms = 'ai:businessApp:list'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '触发器管理', COALESCE(@app_center_menu_id, 0), 3, 20, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessTrigger:list', NULL,
-       NULL, NULL, 0, 0, NULL, '业务触发器列表权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource WHERE tenant_id = 1 AND resource_type = 3 AND perms = 'ai:businessTrigger:list'
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '新增触发器', COALESCE(@app_center_menu_id, 0), 3, 21, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessTrigger:add', NULL,
-       NULL, NULL, 0, 0, NULL, '新增业务触发器按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource WHERE tenant_id = 1 AND resource_type = 3 AND perms = 'ai:businessTrigger:add'
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '编辑触发器', COALESCE(@app_center_menu_id, 0), 3, 22, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessTrigger:edit', NULL,
-       NULL, NULL, 0, 0, NULL, '编辑业务触发器按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource WHERE tenant_id = 1 AND resource_type = 3 AND perms = 'ai:businessTrigger:edit'
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '删除触发器', COALESCE(@app_center_menu_id, 0), 3, 23, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessTrigger:delete', NULL,
-       NULL, NULL, 0, 0, NULL, '删除业务触发器按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource WHERE tenant_id = 1 AND resource_type = 3 AND perms = 'ai:businessTrigger:delete'
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '流程发起', COALESCE(@app_center_menu_id, 0), 3, 24, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessFlow:start', NULL,
-       NULL, NULL, 0, 0, NULL, '从业务记录发起流程权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource WHERE tenant_id = 1 AND resource_type = 3 AND perms = 'ai:businessFlow:start'
-);

+ 0 - 164
forge-server/db/backup/V1.0.47__add_business_document_flow_closure.sql

@@ -1,165 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_business_document_config` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `object_id` bigint DEFAULT NULL COMMENT '业务对象ID',
-  `suite_code` varchar(48) NOT NULL COMMENT '业务套件编码',
-  `object_code` varchar(48) NOT NULL COMMENT '业务对象编码',
-  `config_key` varchar(128) DEFAULT NULL COMMENT '动态CRUD运行配置键',
-  `document_name` varchar(128) NOT NULL COMMENT '单据名称',
-  `document_no_rule` varchar(256) DEFAULT NULL COMMENT '单据编号规则',
-  `document_enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否启用单据模式',
-  `status_field` varchar(64) DEFAULT NULL COMMENT '单据状态字段',
-  `starter_field` varchar(64) DEFAULT NULL COMMENT '发起人字段',
-  `owner_field` varchar(64) DEFAULT NULL COMMENT '负责人字段',
-  `default_flow_key` varchar(128) DEFAULT NULL COMMENT '默认流程模型Key',
-  `status_mapping` json DEFAULT NULL COMMENT '单据状态映射JSON',
-  `options` json DEFAULT NULL COMMENT '扩展配置JSON',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_document_object_code` (`tenant_id`, `object_code`),
-  UNIQUE KEY `uk_ai_business_document_object_id` (`tenant_id`, `object_id`),
-  KEY `idx_ai_business_document_suite` (`tenant_id`, `suite_code`),
-  KEY `idx_ai_business_document_config` (`tenant_id`, `config_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-业务单据配置表';
-
-CREATE TABLE IF NOT EXISTS `ai_business_flow_instance_link` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `object_code` varchar(48) NOT NULL COMMENT '业务对象编码',
-  `record_id` bigint NOT NULL COMMENT '业务记录ID',
-  `business_key` varchar(160) NOT NULL COMMENT '流程业务Key,格式 objectCode:recordId',
-  `flow_model_key` varchar(128) NOT NULL COMMENT '流程模型Key',
-  `process_instance_id` varchar(128) NOT NULL COMMENT '流程实例ID',
-  `flow_status` varchar(32) NOT NULL DEFAULT 'STARTED' COMMENT '流程状态:STARTED/RUNNING/APPROVED/REJECTED/CANCELED/ENDED',
-  `start_user_id` bigint DEFAULT NULL COMMENT '流程发起人ID',
-  `start_time` datetime DEFAULT NULL COMMENT '流程发起时间',
-  `end_time` datetime DEFAULT NULL COMMENT '流程结束时间',
-  `result` varchar(32) DEFAULT NULL COMMENT '流程结果',
-  `variables_snapshot` json DEFAULT NULL COMMENT '流程变量快照',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_flow_process` (`tenant_id`, `process_instance_id`),
-  UNIQUE KEY `uk_ai_business_flow_business_process` (`tenant_id`, `business_key`, `process_instance_id`),
-  KEY `idx_ai_business_flow_business_key` (`tenant_id`, `business_key`, `flow_status`),
-  KEY `idx_ai_business_flow_record` (`tenant_id`, `object_code`, `record_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-单据流程实例关联表';
-
-SET @sql := (
-  SELECT IF(COUNT(*) = 0,
-    'ALTER TABLE ai_business_trigger ADD COLUMN scenario_type varchar(64) DEFAULT NULL COMMENT ''业务场景模板类型'' AFTER trigger_type',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_trigger'
-    AND column_name = 'scenario_type'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql := (
-  SELECT IF(COUNT(*) = 0,
-    'ALTER TABLE ai_business_trigger ADD COLUMN blocking_mode varchar(32) NOT NULL DEFAULT ''ASYNC'' COMMENT ''阻断模式:ASYNC异步/SYNC_BLOCK同步阻断'' AFTER scenario_type',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_trigger'
-    AND column_name = 'blocking_mode'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql := (
-  SELECT IF(COUNT(*) = 0,
-    'ALTER TABLE ai_business_trigger ADD COLUMN developer_mode tinyint(1) NOT NULL DEFAULT 0 COMMENT ''是否开发者高级模式'' AFTER blocking_mode',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_trigger'
-    AND column_name = 'developer_mode'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql := (
-  SELECT IF(COUNT(*) = 0,
-    'ALTER TABLE ai_business_trigger_log ADD COLUMN todo_code varchar(64) DEFAULT NULL COMMENT ''TODO状态编码'' AFTER error_message',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_trigger_log'
-    AND column_name = 'todo_code'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @sql := (
-  SELECT IF(COUNT(*) = 0,
-    'ALTER TABLE ai_business_trigger_log ADD COLUMN correlation_id varchar(128) DEFAULT NULL COMMENT ''关联流程/消息/外部动作ID'' AFTER todo_code',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_trigger_log'
-    AND column_name = 'correlation_id'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE sys_resource
-SET menu_status = 0,
-    visible = 0,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 2
-  AND perms IN ('ai:businessMobile:list', 'ai:businessIntegration:list');
-
-SET @app_center_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, seed.resource_name, COALESCE(@app_center_menu_id, 0), 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT '配置单据' resource_name, 25 sort, 'ai:businessDocument:config' perms, '配置业务对象单据模式权限' remark
-  UNION ALL SELECT '查看单据运行态', 26, 'ai:businessDocument:view', '查看业务单据运行态权限'
-  UNION ALL SELECT '配置业务流程', 27, 'ai:businessFlow:config', '配置业务对象流程绑定权限'
-  UNION ALL SELECT '查看业务流程', 28, 'ai:businessFlow:view', '查看业务记录流程状态权限'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.resource_type = 3
-    AND r.perms = seed.perms
-);

+ 0 - 30
forge-server/db/backup/V1.0.48__add_sys_role_type.sql

@@ -1,36 +0,0 @@
-
-SET @col_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_role' AND COLUMN_NAME = 'role_type');
-SET @sql = IF(@col_exists = 0,
-  'ALTER TABLE sys_role ADD COLUMN role_type INT DEFAULT 1 COMMENT ''角色类型(1-管理角色,2-业务角色,3-审批角色,4-数据角色)'' AFTER role_key',
-  'SELECT ''Column role_type already exists''');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '角色类型' dict_name, 'sys_role_type' dict_type, 1 dict_status, '用于区分不同类型的角色以控制业务' remark
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_type WHERE dict_type = 'sys_role_type'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '管理角色' dict_label, '1' dict_value, 'sys_role_type' dict_type, 'info' list_class, 'Y' is_default, '用于系统管理的角色' remark
-  UNION ALL SELECT 1, 2, '业务角色', '2', 'sys_role_type', 'success', 'N', '用于业务操作的角色'
-  UNION ALL SELECT 1, 3, '审批角色', '3', 'sys_role_type', 'warning', 'N', '用于审批流程的角色'
-  UNION ALL SELECT 1, 4, '数据角色', '4', 'sys_role_type', 'default', 'N', '用于数据权限控制的角色'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data WHERE dict_type = 'sys_role_type' AND dict_value = seed.dict_value
-);

+ 0 - 29
forge-server/db/backup/V1.0.49__add_business_flow_callback_permission.sql

@@ -1,30 +0,0 @@
-
-SET @app_center_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, seed.resource_name, COALESCE(@app_center_menu_id, 0), 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT '流程回调' resource_name, 29 sort, 'ai:businessFlow:callback' perms, '处理业务流程回调权限' remark
-  UNION ALL SELECT '审批兼容发起', 30, 'ai:businessApproval:start', '旧业务审批入口兼容转发权限'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.resource_type = 3
-    AND r.perms = seed.perms
-);

+ 0 - 285
forge-server/db/backup/V1.0.4__add_visual_lowcode_crud_builder.sql

@@ -1,287 +0,0 @@
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'app_name'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN app_name varchar(128) DEFAULT NULL COMMENT ''低代码应用名称'' AFTER table_comment',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'build_mode'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN build_mode varchar(16) NOT NULL DEFAULT ''AI'' COMMENT ''构建模式:AI智能生成 LOWCODE可视化低代码 CODEGEN代码生成'' AFTER mode',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'publish_status'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN publish_status varchar(16) NOT NULL DEFAULT ''DRAFT'' COMMENT ''发布状态:DRAFT草稿 PUBLISHED已发布 STOPPED已停用'' AFTER status',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'model_schema'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN model_schema json DEFAULT NULL COMMENT ''可视化数据模型协议'' AFTER layout_type',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'page_schema'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN page_schema json DEFAULT NULL COMMENT ''可视化页面搭建协议'' AFTER model_schema',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'draft_version'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN draft_version int NOT NULL DEFAULT 0 COMMENT ''草稿版本号'' AFTER page_schema',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'published_version'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN published_version int NOT NULL DEFAULT 0 COMMENT ''已发布版本号'' AFTER draft_version',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'publish_time'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN publish_time datetime DEFAULT NULL COMMENT ''发布时间'' AFTER published_version',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'publish_by'
-);
-SET @ddl := IF(@column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN publish_by bigint DEFAULT NULL COMMENT ''发布人'' AFTER publish_time',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.statistics
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND index_name = 'idx_ai_crud_publish_status'
-);
-SET @ddl := IF(@index_exists = 0,
-  'ALTER TABLE ai_crud_config ADD INDEX idx_ai_crud_publish_status (tenant_id, publish_status, update_time)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE ai_crud_config
-SET app_name = COALESCE(NULLIF(menu_name, ''), NULLIF(table_comment, ''), config_key)
-WHERE app_name IS NULL;
-
-UPDATE ai_crud_config
-SET publish_status = 'PUBLISHED',
-    published_version = CASE WHEN published_version = 0 THEN 1 ELSE published_version END
-WHERE publish_status = 'DRAFT'
-  AND mode = 'CONFIG';
-
-CREATE TABLE IF NOT EXISTS `ai_crud_config_version` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `config_id` bigint NOT NULL COMMENT 'CRUD配置ID',
-  `config_key` varchar(64) NOT NULL COMMENT 'CRUD配置键',
-  `version_no` int NOT NULL COMMENT '版本号',
-  `version_type` varchar(20) NOT NULL DEFAULT 'publish' COMMENT '版本类型:publish发布 rollback回滚',
-  `model_schema` json DEFAULT NULL COMMENT '可视化数据模型协议',
-  `page_schema` json DEFAULT NULL COMMENT '可视化页面搭建协议',
-  `search_schema` json DEFAULT NULL COMMENT '搜索表单Schema JSON',
-  `columns_schema` json DEFAULT NULL COMMENT '表格列Schema JSON',
-  `edit_schema` json DEFAULT NULL COMMENT '编辑表单Schema JSON',
-  `api_config` json DEFAULT NULL COMMENT 'API配置JSON',
-  `options` json DEFAULT NULL COMMENT 'AiCrudPage运行时配置',
-  `publish_snapshot` longtext COMMENT '发布快照JSON',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建者',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新者',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_crud_version_no` (`tenant_id`, `config_id`, `version_no`),
-  KEY `idx_ai_crud_version_config` (`tenant_id`, `config_id`, `create_time`),
-  KEY `idx_ai_crud_version_key` (`tenant_id`, `config_key`, `version_no`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI CRUD低代码发布版本表';
-
-SET @ai_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 1
-    AND path = '/ai'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '低代码应用', @ai_root_id, 2, 13, '/ai/lowcode-apps', 'ai/lowcode-apps', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:list', 'ionicons5:ConstructOutline',
-       NULL, NULL, 1, 0, NULL, 'AI低代码应用管理', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @ai_root_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 2
-      AND perms = 'ai:lowcode:list'
-  );
-
-SET @lowcode_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:lowcode:list'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '低代码搭建器', @ai_root_id, 2, 14, '/ai/lowcode-builder', 'ai/lowcode-builder', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:edit', 'ionicons5:BuildOutline',
-       NULL, NULL, 1, 0, NULL, 'AI低代码可视化搭建器', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @ai_root_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 2
-      AND perms = 'ai:lowcode:edit'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '发布低代码应用', @lowcode_menu_id, 3, 1, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:publish', NULL,
-       NULL, NULL, 0, 0, NULL, '发布低代码应用按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @lowcode_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:publish'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '回滚低代码应用', @lowcode_menu_id, 3, 2, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:rollback', NULL,
-       NULL, NULL, 0, 0, NULL, '回滚低代码应用按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @lowcode_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:rollback'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '在线建表发布', @lowcode_menu_id, 3, 3, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:lowcode:deploy-ddl', NULL,
-       NULL, NULL, 0, 0, NULL, '低代码在线建表发布按钮权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @lowcode_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND resource_type = 3
-      AND perms = 'ai:lowcode:deploy-ddl'
-  );

+ 0 - 28
forge-server/db/backup/V1.0.50__add_business_stats_and_action_permissions.sql

@@ -1,29 +0,0 @@
-
-SET @app_center_menu_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND resource_type = 2 AND perms = 'ai:businessApp:list'
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, seed.resource_name, COALESCE(@app_center_menu_id, 0), 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT '保存单据' resource_name, 31 sort, 'ai:businessDocument:save' perms, '保存业务单据权限' remark
-  UNION ALL SELECT '提交单据', 32, 'ai:businessDocument:submit', '提交业务单据权限'
-  UNION ALL SELECT '撤回单据', 33, 'ai:businessDocument:withdraw', '撤回业务单据权限'
-  UNION ALL SELECT '执行触发器', 34, 'ai:businessTrigger:execute', '执行业务触发器权限'
-  UNION ALL SELECT '查看业务报表', 35, 'ai:businessStats:view', '查看业务对象报表权限'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.resource_type = 3
-    AND r.perms = seed.perms
-);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 225
forge-server/db/backup/V1.0.51__seed_crm_opportunity_document_flow.sql


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 277
forge-server/db/backup/V1.0.52__seed_leave_document_flow_demo.sql


+ 0 - 15
forge-server/db/backup/V1.0.53__align_flow_template_logic_delete_column.sql

@@ -1,17 +0,0 @@
-
-SET @add_flow_template_del_flag := (
-  SELECT IF(
-    COUNT(*) = 0,
-    'ALTER TABLE sys_flow_template ADD COLUMN del_flag tinyint NOT NULL DEFAULT 0 COMMENT ''删除标志:0正常 1删除'' AFTER update_time',
-    'SELECT 1'
-  )
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_template'
-    AND column_name = 'del_flag'
-);
-PREPARE stmt FROM @add_flow_template_del_flag;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 30
forge-server/db/backup/V1.0.54__patch_opportunity_flow_dept_manager_mapping.sql

@@ -1,32 +0,0 @@
-
-UPDATE ai_business_binding
-SET binding_config = JSON_ARRAY_APPEND(
-    CAST(binding_config AS JSON),
-    '$.variableMapping',
-    JSON_OBJECT('formField', 'createBy', 'flowVariable', 'deptManager', 'label', '部门经理')
-  ),
-  update_by = 1,
-  update_time = NOW()
-WHERE tenant_id = 1
-  AND target_type = 'OBJECT'
-  AND target_code = 'OPPORTUNITY'
-  AND binding_type = 'FLOW'
-  AND binding_key = 'leave_multi'
-  AND JSON_VALID(binding_config)
-  AND JSON_SEARCH(CAST(binding_config AS JSON), 'one', 'deptManager', NULL, '$.variableMapping[*].flowVariable') IS NULL;
-
-UPDATE ai_business_trigger
-SET action_config = JSON_ARRAY_APPEND(
-    CAST(action_config AS JSON),
-    '$.variableMapping',
-    JSON_OBJECT('formField', 'createBy', 'flowVariable', 'deptManager', 'label', '部门经理')
-  ),
-  update_by = 1,
-  update_time = NOW()
-WHERE tenant_id = 1
-  AND object_code = 'OPPORTUNITY'
-  AND action_type = 'START_FLOW'
-  AND JSON_VALID(action_config)
-  AND JSON_SEARCH(CAST(action_config AS JSON), 'one', 'deptManager', NULL, '$.variableMapping[*].flowVariable') IS NULL;

+ 0 - 41
forge-server/db/backup/V1.0.55__add_user_tenant_membership.sql

@@ -1,41 +0,0 @@
-CREATE TABLE IF NOT EXISTS sys_user_tenant
-(
-    id           bigint      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-    tenant_id    bigint      NOT NULL COMMENT '租户ID',
-    user_id      bigint      NOT NULL COMMENT '用户ID',
-    member_type  tinyint     NOT NULL DEFAULT 2 COMMENT '成员类型(1-租户管理员,2-普通成员)',
-    is_default   tinyint     NOT NULL DEFAULT 0 COMMENT '是否默认租户(0-否,1-是)',
-    status       tinyint     NOT NULL DEFAULT 1 COMMENT '状态(0-禁用,1-正常)',
-    create_by    bigint               DEFAULT NULL COMMENT '创建者',
-    create_time  datetime    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    create_dept  bigint               DEFAULT NULL COMMENT '创建部门',
-    update_by    bigint               DEFAULT NULL COMMENT '更新者',
-    update_time  datetime    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    PRIMARY KEY (id),
-    UNIQUE KEY uk_user_tenant (tenant_id, user_id),
-    KEY idx_user_tenant_user (user_id, status),
-    KEY idx_user_tenant_default (user_id, is_default)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户-租户成员关系表';
-
-UPDATE sys_user
-SET tenant_id = 1
-WHERE tenant_id IS NULL
-   OR tenant_id = 0;
-
-INSERT INTO sys_user_tenant (tenant_id, user_id, member_type, is_default, status, create_by, create_time, update_by, update_time)
-SELECT u.tenant_id,
-       u.id,
-       CASE WHEN u.user_type = 1 THEN 1 ELSE 2 END,
-       1,
-       1,
-       u.create_by,
-       COALESCE(u.create_time, NOW()),
-       u.update_by,
-       COALESCE(u.update_time, NOW())
-FROM sys_user u
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM sys_user_tenant sut
-    WHERE sut.tenant_id = u.tenant_id
-      AND sut.user_id = u.id
-);

+ 0 - 376
forge-server/db/backup/V1.0.56__harden_tenant_isolation_boundaries.sql

@@ -1,384 +0,0 @@
-
-UPDATE sys_user SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_role SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_role_resource SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_role_data_scope SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_user_role SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_user_org SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_user_post SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_org SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_post SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_resource SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-DELETE legacy
-FROM sys_dict_data legacy
-JOIN sys_dict_data keeper ON keeper.tenant_id = 1
-    AND keeper.dict_type = legacy.dict_type
-    AND keeper.dict_value = legacy.dict_value
-WHERE (legacy.tenant_id IS NULL OR legacy.tenant_id = 0)
-  AND legacy.dict_code <> keeper.dict_code;
-
-DELETE legacy
-FROM sys_dict_type legacy
-JOIN sys_dict_type keeper ON keeper.tenant_id = 1
-    AND keeper.dict_type = legacy.dict_type
-WHERE (legacy.tenant_id IS NULL OR legacy.tenant_id = 0)
-  AND legacy.dict_id <> keeper.dict_id;
-
-UPDATE sys_dict_type SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_dict_data SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_config SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_data_scope_config SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_notice SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_message SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_message_template SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_message_receiver SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_message_send_record SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_login_log SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_operation_log SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_user_social SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_flow_form SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_flow_model_version SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-UPDATE sys_flow_spel_template SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_group');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_group' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_file_group ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_file_group SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_group' AND INDEX_NAME = 'idx_sys_file_group_tenant');
-SET @sql = IF(@table_exists > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_file_group ADD INDEX idx_sys_file_group_tenant (tenant_id, deleted, status)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_metadata');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_metadata' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_file_metadata ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_file_metadata SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_file_metadata' AND INDEX_NAME = 'idx_sys_file_metadata_tenant');
-SET @sql = IF(@table_exists > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_file_metadata ADD INDEX idx_sys_file_metadata_tenant (tenant_id, status, upload_time)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_org');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_org' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_notice_org ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_notice_org no
-JOIN sys_notice n ON n.notice_id = no.notice_id
-SET no.tenant_id = n.tenant_id
-WHERE n.tenant_id IS NOT NULL AND n.tenant_id <> 0;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_org' AND INDEX_NAME = 'idx_sys_notice_org_tenant');
-SET @sql = IF(@table_exists > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_notice_org ADD INDEX idx_sys_notice_org_tenant (tenant_id, notice_id, org_id)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_read_record');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_read_record' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_notice_read_record ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_notice_read_record rr
-JOIN sys_notice n ON n.notice_id = rr.notice_id
-SET rr.tenant_id = n.tenant_id
-WHERE n.tenant_id IS NOT NULL AND n.tenant_id <> 0;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_notice_read_record' AND INDEX_NAME = 'idx_sys_notice_read_tenant');
-SET @sql = IF(@table_exists > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_notice_read_record ADD INDEX idx_sys_notice_read_tenant (tenant_id, notice_id, user_id)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_model ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_model SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_business ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_business SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_category');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_category' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_category ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_category SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_cc');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_cc' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_cc ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_cc SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_comment');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_comment' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_comment ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_comment SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_condition_item');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_condition_item' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_condition_item ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_condition_item SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_condition_rule');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_condition_rule' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_condition_rule ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_condition_rule SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_error_log');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_error_log' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_error_log ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_error_log SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_node_config');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_node_config' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_node_config ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_node_config SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_approval_level');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_approval_level' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_approval_level ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_approval_level SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_statistics');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_statistics' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_statistics ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_statistics SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_task');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_task' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_task ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_task SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_template');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_template' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_template ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-UPDATE sys_flow_template SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0;
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_node_operation');
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_node_operation' AND COLUMN_NAME = 'tenant_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_node_operation ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 COMMENT ''租户ID'' AFTER id',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @sql = IF(@table_exists > 0, 'UPDATE sys_flow_node_operation SET tenant_id = 1 WHERE tenant_id IS NULL OR tenant_id = 0', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model' AND INDEX_NAME = 'idx_sys_flow_model_tenant');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_model ADD INDEX idx_sys_flow_model_tenant (tenant_id, status, create_time)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_task' AND INDEX_NAME = 'idx_sys_flow_task_tenant');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_task') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_task ADD INDEX idx_sys_flow_task_tenant (tenant_id, status, create_time)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business' AND INDEX_NAME = 'idx_sys_flow_business_tenant');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_business ADD INDEX idx_sys_flow_business_tenant (tenant_id, status, create_time)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_comment' AND INDEX_NAME = 'idx_sys_flow_comment_tenant');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_comment') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_comment ADD INDEX idx_sys_flow_comment_tenant (tenant_id, process_instance_id, create_time)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model_version' AND INDEX_NAME = 'idx_sys_flow_model_version_tenant');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model_version') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_model_version ADD INDEX idx_sys_flow_model_version_tenant (tenant_id, model_id, version)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model' AND INDEX_NAME = 'model_key');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_model DROP INDEX model_key', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model' AND INDEX_NAME = 'uk_flow_model_tenant_key');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_model') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_model ADD UNIQUE KEY uk_flow_model_tenant_key (tenant_id, model_key)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business' AND INDEX_NAME = 'uk_business_key');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_business DROP INDEX uk_business_key', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business' AND INDEX_NAME = 'uk_flow_business_tenant_key');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_business') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_business ADD UNIQUE KEY uk_flow_business_tenant_key (tenant_id, business_key)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_category' AND INDEX_NAME = 'category_code');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_category DROP INDEX category_code', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_category' AND INDEX_NAME = 'uk_flow_category_tenant_code');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_category') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_category ADD UNIQUE KEY uk_flow_category_tenant_code (tenant_id, category_code)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND INDEX_NAME = 'form_key');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_form DROP INDEX form_key', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND INDEX_NAME = 'uk_flow_form_tenant_key');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_form ADD UNIQUE KEY uk_flow_form_tenant_key (tenant_id, form_key)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_template' AND INDEX_NAME = 'template_key');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_template DROP INDEX template_key', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_template' AND INDEX_NAME = 'uk_flow_template_tenant_key');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_template') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_template ADD UNIQUE KEY uk_flow_template_tenant_key (tenant_id, template_key)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_statistics' AND INDEX_NAME = 'uk_process_date');
-SET @sql = IF(@index_exists > 0, 'ALTER TABLE sys_flow_statistics DROP INDEX uk_process_date', 'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_statistics' AND INDEX_NAME = 'uk_flow_statistics_tenant_date');
-SET @sql = IF((SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_statistics') > 0 AND @index_exists = 0,
-              'ALTER TABLE sys_flow_statistics ADD UNIQUE KEY uk_flow_statistics_tenant_date (tenant_id, process_def_key, stat_date)',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 300
forge-server/db/backup/V1.0.57__add_flow_form_runtime_entry.sql

@@ -1,301 +0,0 @@
-
-SET @table_exists = (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form');
-
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND COLUMN_NAME = 'form_category');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_form ADD COLUMN form_category varchar(64) DEFAULT NULL COMMENT ''表单分类'' AFTER form_name',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND COLUMN_NAME = 'field_registry');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_form ADD COLUMN field_registry json DEFAULT NULL COMMENT ''字段目录快照'' AFTER form_schema',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND COLUMN_NAME = 'default_data_mode');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_form ADD COLUMN default_data_mode varchar(32) NOT NULL DEFAULT ''PROCESS_ONLY'' COMMENT ''默认数据模式'' AFTER form_config',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND COLUMN_NAME = 'publish_status');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_form ADD COLUMN publish_status tinyint NOT NULL DEFAULT 0 COMMENT ''发布状态:0草稿 1已发布'' AFTER status',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sys_flow_form' AND COLUMN_NAME = 'current_version_id');
-SET @sql = IF(@table_exists > 0 AND @column_exists = 0,
-              'ALTER TABLE sys_flow_form ADD COLUMN current_version_id bigint DEFAULT NULL COMMENT ''当前发布版本ID'' AFTER publish_status',
-              'SELECT 1');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-CREATE TABLE IF NOT EXISTS `sys_flow_form_version` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `form_id` bigint NOT NULL COMMENT '流程表单ID',
-  `form_key` varchar(128) NOT NULL COMMENT '表单Key',
-  `form_name` varchar(128) NOT NULL COMMENT '表单名称',
-  `form_category` varchar(64) DEFAULT NULL COMMENT '表单分类',
-  `form_type` varchar(32) NOT NULL DEFAULT 'dynamic' COMMENT '表单类型',
-  `version` int NOT NULL COMMENT '版本号',
-  `form_schema` longtext COMMENT '表单Schema快照',
-  `field_registry` json DEFAULT NULL COMMENT '字段目录快照',
-  `form_config` json DEFAULT NULL COMMENT '表单配置快照',
-  `default_data_mode` varchar(32) NOT NULL DEFAULT 'PROCESS_ONLY' COMMENT '默认数据模式',
-  `publish_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间',
-  `publish_by` bigint DEFAULT NULL COMMENT '发布人ID',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_flow_form_version` (`tenant_id`, `form_id`, `version`),
-  KEY `idx_flow_form_version_key` (`tenant_id`, `form_key`, `version`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程表单发布版本表';
-
-CREATE TABLE IF NOT EXISTS `sys_flow_entry` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `entry_code` varchar(128) NOT NULL COMMENT '入口编码',
-  `entry_name` varchar(128) NOT NULL COMMENT '入口名称',
-  `entry_desc` varchar(500) DEFAULT NULL COMMENT '入口说明',
-  `model_key` varchar(128) NOT NULL COMMENT '流程模型Key',
-  `form_key` varchar(128) NOT NULL COMMENT '表单Key',
-  `form_version_id` bigint NOT NULL COMMENT '表单版本ID',
-  `data_mode` varchar(32) NOT NULL DEFAULT 'PROCESS_ONLY' COMMENT '数据模式',
-  `object_code` varchar(64) DEFAULT NULL COMMENT '业务对象编码',
-  `config_key` varchar(128) DEFAULT NULL COMMENT '动态CRUD配置Key',
-  `visible_scope` json DEFAULT NULL COMMENT '可见范围配置',
-  `title_template` varchar(256) DEFAULT NULL COMMENT '流程标题模板',
-  `business_key_template` varchar(256) DEFAULT NULL COMMENT '业务Key模板',
-  `submit_strategy` json DEFAULT NULL COMMENT '提交策略配置',
-  `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:0禁用 1启用',
-  `sort` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志:0正常 1删除',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_flow_entry_code` (`tenant_id`, `entry_code`),
-  KEY `idx_flow_entry_model` (`tenant_id`, `model_key`, `status`),
-  KEY `idx_flow_entry_form` (`tenant_id`, `form_key`, `form_version_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程应用入口表';
-
-CREATE TABLE IF NOT EXISTS `sys_flow_entry_field_mapping` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `entry_id` bigint NOT NULL COMMENT '流程入口ID',
-  `form_field` varchar(128) NOT NULL COMMENT '表单字段',
-  `target_type` varchar(32) NOT NULL DEFAULT 'FLOW_VARIABLE' COMMENT '目标类型:FLOW_VARIABLE/BUSINESS_FIELD',
-  `target_field` varchar(128) DEFAULT NULL COMMENT '目标字段',
-  `flow_variable` varchar(128) DEFAULT NULL COMMENT '流程变量名',
-  `required` tinyint NOT NULL DEFAULT 0 COMMENT '是否必填映射',
-  `mapping_config` json DEFAULT NULL COMMENT '映射扩展配置',
-  `sort` int NOT NULL DEFAULT 0 COMMENT '排序',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志:0正常 1删除',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_flow_entry_mapping` (`tenant_id`, `entry_id`, `form_field`, `target_type`, `target_field`),
-  KEY `idx_flow_entry_mapping_entry` (`tenant_id`, `entry_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程入口字段映射表';
-
-CREATE TABLE IF NOT EXISTS `sys_flow_form_instance` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `entry_id` bigint DEFAULT NULL COMMENT '流程入口ID',
-  `entry_code` varchar(128) NOT NULL COMMENT '入口编码',
-  `business_key` varchar(256) NOT NULL COMMENT '流程业务Key',
-  `process_instance_id` varchar(128) DEFAULT NULL COMMENT '流程实例ID',
-  `model_key` varchar(128) NOT NULL COMMENT '流程模型Key',
-  `form_key` varchar(128) NOT NULL COMMENT '表单Key',
-  `form_version_id` bigint NOT NULL COMMENT '表单版本ID',
-  `form_version` int NOT NULL COMMENT '表单版本号',
-  `schema_snapshot` longtext COMMENT '表单Schema快照',
-  `field_registry` json DEFAULT NULL COMMENT '字段目录快照',
-  `form_data` json DEFAULT NULL COMMENT '表单填报数据',
-  `data_mode` varchar(32) NOT NULL DEFAULT 'PROCESS_ONLY' COMMENT '数据模式',
-  `object_code` varchar(64) DEFAULT NULL COMMENT '业务对象编码',
-  `record_id` bigint DEFAULT NULL COMMENT '业务记录ID',
-  `title` varchar(256) DEFAULT NULL COMMENT '流程标题',
-  `start_user_id` bigint DEFAULT NULL COMMENT '发起人ID',
-  `start_user_name` varchar(100) DEFAULT NULL COMMENT '发起人姓名',
-  `start_dept_id` bigint DEFAULT NULL COMMENT '发起部门ID',
-  `start_dept_name` varchar(128) DEFAULT NULL COMMENT '发起部门名称',
-  `status` varchar(32) NOT NULL DEFAULT 'RUNNING' COMMENT '状态:DRAFT/RUNNING/APPROVED/REJECTED/CANCELED/TERMINATED',
-  `submit_time` datetime DEFAULT NULL COMMENT '提交时间',
-  `end_time` datetime DEFAULT NULL COMMENT '结束时间',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志:0正常 1删除',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_flow_form_instance_business` (`tenant_id`, `business_key`),
-  KEY `idx_flow_form_instance_process` (`tenant_id`, `process_instance_id`),
-  KEY `idx_flow_form_instance_entry` (`tenant_id`, `entry_code`, `status`, `create_time`),
-  KEY `idx_flow_form_instance_record` (`tenant_id`, `object_code`, `record_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程表单填报实例表';
-
-CREATE TABLE IF NOT EXISTS `sys_flow_fill_batch` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `entry_id` bigint NOT NULL COMMENT '流程入口ID',
-  `entry_code` varchar(128) NOT NULL COMMENT '入口编码',
-  `batch_name` varchar(128) NOT NULL COMMENT '批次名称',
-  `period_key` varchar(64) DEFAULT NULL COMMENT '周期标识',
-  `target_scope` json DEFAULT NULL COMMENT '目标组织范围',
-  `owner_rule` json DEFAULT NULL COMMENT '负责人规则',
-  `deadline_time` datetime DEFAULT NULL COMMENT '截止时间',
-  `allow_resubmit` tinyint NOT NULL DEFAULT 1 COMMENT '驳回后是否允许重新提交',
-  `status` varchar(32) NOT NULL DEFAULT 'DRAFT' COMMENT '批次状态:DRAFT/PUBLISHED/CLOSED',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志:0正常 1删除',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  KEY `idx_flow_fill_batch_entry` (`tenant_id`, `entry_code`, `status`, `deadline_time`),
-  KEY `idx_flow_fill_batch_period` (`tenant_id`, `period_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程组织批量填报批次表';
-
-CREATE TABLE IF NOT EXISTS `sys_flow_fill_batch_item` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `batch_id` bigint NOT NULL COMMENT '批次ID',
-  `entry_code` varchar(128) NOT NULL COMMENT '入口编码',
-  `org_id` bigint NOT NULL COMMENT '组织ID',
-  `org_name` varchar(128) DEFAULT NULL COMMENT '组织名称',
-  `owner_user_id` bigint DEFAULT NULL COMMENT '负责人用户ID',
-  `owner_user_name` varchar(100) DEFAULT NULL COMMENT '负责人姓名',
-  `form_instance_id` bigint DEFAULT NULL COMMENT '表单实例ID',
-  `object_code` varchar(64) DEFAULT NULL COMMENT '业务对象编码',
-  `record_id` bigint DEFAULT NULL COMMENT '业务记录ID',
-  `process_instance_id` varchar(128) DEFAULT NULL COMMENT '流程实例ID',
-  `submit_status` varchar(32) NOT NULL DEFAULT 'PENDING' COMMENT '填报状态:PENDING/SUBMITTED/RETURNED/OVERDUE',
-  `flow_status` varchar(32) DEFAULT NULL COMMENT '流程状态',
-  `deadline_time` datetime DEFAULT NULL COMMENT '截止时间',
-  `submit_time` datetime DEFAULT NULL COMMENT '提交时间',
-  `deleted` tinyint NOT NULL DEFAULT 0 COMMENT '删除标志:0正常 1删除',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_flow_fill_batch_org` (`tenant_id`, `batch_id`, `org_id`),
-  KEY `idx_flow_fill_item_owner` (`tenant_id`, `owner_user_id`, `submit_status`),
-  KEY `idx_flow_fill_item_process` (`tenant_id`, `process_instance_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程组织批量填报明细表';
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, 1, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, '流程数据模式' dict_name, 'sys_flow_data_mode' dict_type, '流程入口数据保存模式' remark
-  UNION ALL SELECT 1, '流程入口状态', 'sys_flow_entry_status', '流程入口启停状态'
-  UNION ALL SELECT 1, '组织填报批次状态', 'sys_flow_batch_status', '组织批量填报批次状态'
-  UNION ALL SELECT 1, '组织填报状态', 'sys_flow_fill_status', '组织批量填报明细状态'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default,
-                           dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class,
-       seed.is_default, 1, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '仅流程快照' dict_label, 'PROCESS_ONLY' dict_value, 'sys_flow_data_mode' dict_type, 'info' list_class, 'Y' is_default, '只保存流程变量和表单实例快照' remark
-  UNION ALL SELECT 1, 2, '业务对象落表', 'BUSINESS_OBJECT', 'sys_flow_data_mode', 'success', 'N', '写入业务对象实际数据表后发起流程'
-  UNION ALL SELECT 1, 3, '混合模式', 'HYBRID', 'sys_flow_data_mode', 'warning', 'N', '同时保存业务记录和流程表单快照'
-  UNION ALL SELECT 1, 1, '启用', '1', 'sys_flow_entry_status', 'success', 'Y', '入口启用'
-  UNION ALL SELECT 1, 2, '禁用', '0', 'sys_flow_entry_status', 'default', 'N', '入口禁用'
-  UNION ALL SELECT 1, 1, '草稿', 'DRAFT', 'sys_flow_batch_status', 'default', 'Y', '批次配置草稿'
-  UNION ALL SELECT 1, 2, '已发布', 'PUBLISHED', 'sys_flow_batch_status', 'success', 'N', '批次已发布并生成填报明细'
-  UNION ALL SELECT 1, 3, '已关闭', 'CLOSED', 'sys_flow_batch_status', 'default', 'N', '批次已关闭'
-  UNION ALL SELECT 1, 1, '待填报', 'PENDING', 'sys_flow_fill_status', 'default', 'Y', '待组织负责人填报'
-  UNION ALL SELECT 1, 2, '已提交', 'SUBMITTED', 'sys_flow_fill_status', 'info', 'N', '负责人已提交'
-  UNION ALL SELECT 1, 3, '审核中', 'RUNNING', 'sys_flow_fill_status', 'warning', 'N', '流程审核中'
-  UNION ALL SELECT 1, 4, '已通过', 'APPROVED', 'sys_flow_fill_status', 'success', 'N', '审核通过'
-  UNION ALL SELECT 1, 5, '已驳回', 'REJECTED', 'sys_flow_fill_status', 'error', 'N', '审核驳回,可重新提交'
-  UNION ALL SELECT 1, 6, '已逾期', 'OVERDUE', 'sys_flow_fill_status', 'error', 'N', '超过截止时间未提交'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);
-
-SET @flow_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND (perms = 'flow:model:list' OR path = '/flow/model' OR path = '/flow')
-  ORDER BY CASE WHEN path = '/flow' THEN 0 ELSE 1 END, id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, COALESCE(@flow_menu_id, 0), 2, seed.sort, seed.path, seed.component, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, seed.icon,
-       NULL, NULL, 1, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '流程入口' resource_name, 31 sort, '/flow/entry' path, 'flow/entry' component, 'flow:entry:list' perms, 'ionicons5:EnterOutline' icon, '流程表单运行入口管理' remark
-  UNION ALL SELECT 1, '组织填报批次', 32, '/flow/fill-batch', 'flow/fillBatch', 'flow:fillBatch:list', 'ionicons5:ClipboardOutline', '组织批量填报任务管理'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource r
-  WHERE r.tenant_id = seed.tenant_id
-    AND r.resource_type = 2
-    AND r.perms = seed.perms
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, seed.resource_name, COALESCE(@flow_menu_id, 0), 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT '发布流程表单版本' resource_name, 41 sort, 'flow:form:publish' perms, '发布流程表单不可变版本' remark
-  UNION ALL SELECT '维护流程入口', 42, 'flow:entry:edit', '新增或编辑流程入口'
-  UNION ALL SELECT '打开流程入口', 43, 'flow:entry:open', '按入口填报并发起流程'
-  UNION ALL SELECT '查看流程表单实例', 44, 'flow:runtime:instance', '查看流程表单实例快照'
-  UNION ALL SELECT '维护填报批次', 45, 'flow:fillBatch:edit', '新增或编辑组织填报批次'
-  UNION ALL SELECT '发布填报批次', 46, 'flow:fillBatch:publish', '发布批次并生成组织填报项'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.resource_type = 3
-    AND r.perms = seed.perms
-);

+ 0 - 36
forge-server/db/backup/V1.0.58__remove_standalone_flow_entry_menus.sql

@@ -1,37 +0,0 @@
-
-DELETE FROM sys_role_resource
-WHERE resource_id IN (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND (
-      (resource_type = 2 AND (perms IN ('flow:entry:list', 'flow:fillBatch:list') OR path IN ('/flow/entry', '/flow/fill-batch')))
-      OR (resource_type = 3 AND perms IN ('flow:fillBatch:edit', 'flow:fillBatch:publish'))
-    )
-);
-
-DELETE FROM sys_resource
-WHERE tenant_id = 1
-  AND (
-    (resource_type = 2 AND (perms IN ('flow:entry:list', 'flow:fillBatch:list') OR path IN ('/flow/entry', '/flow/fill-batch')))
-    OR (resource_type = 3 AND perms IN ('flow:fillBatch:edit', 'flow:fillBatch:publish'))
-  );
-
-UPDATE sys_resource
-SET resource_name = '维护模型入口配置',
-    remark = '在流程模型内新增或编辑入口配置',
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 3
-  AND perms = 'flow:entry:edit';
-
-UPDATE sys_resource
-SET resource_name = '打开模型入口',
-    remark = '按模型入口填报并发起流程',
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 3
-  AND perms = 'flow:entry:open';

+ 0 - 467
forge-server/db/backup/V1.0.59__normalize_pc_menu_modules.sql

@@ -1,484 +0,0 @@
-
-UPDATE sys_resource
-SET resource_name = '工作台',
-    parent_id = 0,
-    sort = 1,
-    path = '/workbench',
-    icon = 'ionicons5:HomeOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 43;
-
-UPDATE sys_resource
-SET resource_name = '应用中心',
-    parent_id = 0,
-    sort = 2,
-    path = '/app-center',
-    icon = 'ionicons5:GridOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9194;
-
-UPDATE sys_resource
-SET resource_name = '流程中心',
-    parent_id = 0,
-    sort = 3,
-    path = '/flow',
-    icon = 'ionicons5:GitNetworkOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 79;
-
-UPDATE sys_resource
-SET resource_name = '数据与报表',
-    parent_id = 0,
-    sort = 4,
-    path = '/data-report',
-    icon = 'ionicons5:StatsChartOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9100;
-
-UPDATE sys_resource
-SET resource_name = 'AI能力',
-    parent_id = 0,
-    sort = 5,
-    path = '/ai',
-    icon = 'ionicons5:SparklesOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9067;
-
-UPDATE sys_resource
-SET resource_name = '平台管理',
-    parent_id = 0,
-    sort = 6,
-    path = '/platform',
-    icon = 'ionicons5:SettingsOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 1;
-
-UPDATE sys_resource
-SET resource_name = '旧低代码配置',
-    sort = 900,
-    visible = 0,
-    menu_status = 0,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 39;
-
-UPDATE sys_resource
-SET resource_name = '个人中心(已归档)',
-    sort = 910,
-    visible = 0,
-    menu_status = 0,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9045;
-
-UPDATE sys_resource
-SET resource_name = '报表管理(已归档)',
-    sort = 920,
-    visible = 0,
-    menu_status = 0,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9096;
-
-UPDATE sys_resource
-SET resource_name = '开发者工具(已归档)',
-    sort = 930,
-    visible = 0,
-    menu_status = 0,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9218;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 80;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 81;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 82;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 83;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 10, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 30;
-
-UPDATE sys_resource
-SET parent_id = 43, sort = 90, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 900;
-
-UPDATE sys_resource
-SET resource_name = '应用总览',
-    parent_id = 9194,
-    sort = 1,
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9217;
-
-UPDATE sys_resource
-SET resource_name = '应用数据源',
-    parent_id = 9194,
-    sort = 2,
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 40;
-
-UPDATE sys_resource
-SET parent_id = 9194, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9197;
-
-UPDATE sys_resource
-SET parent_id = 9194, sort = 4, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9198;
-
-UPDATE sys_resource
-SET parent_id = 9194, sort = 5, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9199;
-
-UPDATE sys_resource
-SET parent_id = 9217, sort = 1, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9195;
-
-UPDATE sys_resource
-SET parent_id = 9217, sort = 2, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9196;
-
-UPDATE sys_resource
-SET parent_id = 9217, sort = 6, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9221;
-
-UPDATE sys_resource
-SET visible = 0,
-    menu_status = 0,
-    sort = 900,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND client_code = 'pc'
-  AND id IN (
-      41, 9080, 9081, 9085, 9088,
-      9174, 9180, 9169,
-      9184, 9185, 9186, 9187, 9193,
-      9220, 9229, 9230, 9244, 9270
-  );
-
-UPDATE sys_resource
-SET visible = 0,
-    menu_status = 0,
-    sort = 910,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND client_code = 'pc'
-  AND id IN (9239, 9243);
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 85;
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 86;
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9094;
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9046;
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 90, visible = 0, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 101;
-
-UPDATE sys_resource
-SET parent_id = 79, sort = 91, visible = 0, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9095;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9101;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9102;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9136;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9147;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9162;
-
-UPDATE sys_resource
-SET parent_id = 9100, sort = 10, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9113;
-
-UPDATE sys_resource
-SET parent_id = 9067, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9068;
-
-UPDATE sys_resource
-SET parent_id = 9067, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9160;
-
-UPDATE sys_resource
-SET parent_id = 9067, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9077;
-
-UPDATE sys_resource
-SET parent_id = 9067, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9167;
-
-UPDATE sys_resource
-SET parent_id = 9067, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9163;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 2;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 14;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 17;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 24;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 6, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 26;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 7, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9051;
-
-UPDATE sys_resource
-SET parent_id = 1, sort = 8, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 31;
-
-UPDATE sys_resource
-SET resource_name = '基础配置',
-    parent_id = 1,
-    sort = 50,
-    path = '/platform/config',
-    icon = 'ionicons5:OptionsOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 44;
-
-UPDATE sys_resource
-SET resource_name = '消息中心',
-    parent_id = 1,
-    sort = 60,
-    path = '/platform/message',
-    icon = 'ionicons5:ChatboxEllipsesOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 48;
-
-UPDATE sys_resource
-SET resource_name = '运维监控',
-    parent_id = 1,
-    sort = 70,
-    path = '/platform/monitor',
-    icon = 'ionicons5:PulseOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 54;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 27;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 2, visible = 0, menu_status = 0, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 28;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 29;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 77;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9091;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 6, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9047;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 20, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 45;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 21, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 46;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 22, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9097;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 23, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 47;
-
-UPDATE sys_resource
-SET parent_id = 44, sort = 24, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 68;
-
-UPDATE sys_resource
-SET resource_name = '模板配置', parent_id = 48, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 49;
-
-UPDATE sys_resource
-SET parent_id = 48, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 50;
-
-UPDATE sys_resource
-SET parent_id = 48, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9048;
-
-UPDATE sys_resource
-SET parent_id = 48, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9050;
-
-UPDATE sys_resource
-SET parent_id = 48, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 9049;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 1, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 78;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 2, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 58;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 3, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 67;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 4, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 56;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 5, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 57;
-
-UPDATE sys_resource
-SET parent_id = 54, sort = 6, visible = 1, menu_status = 1, update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 55;
-
-UPDATE sys_resource
-SET visible = 0,
-    menu_status = 0,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND id = 53;
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 43, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (30, 80, 81, 82, 83, 900, 901, 902);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 9194, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (40, 9197, 9198, 9199, 9217, 9239, 9243);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 79, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (85, 86, 101, 9046, 9094, 9095);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 9100, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (9101, 9102, 9113, 9136, 9147, 9162);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 9067, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (9068, 9077, 9160, 9163, 9167);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 1, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (
-    2, 9, 14, 17, 24, 26, 31, 44, 45, 46, 47, 48, 49, 50, 54, 55, 56, 57,
-    58, 67, 68, 77, 9047, 9048, 9049, 9050, 9051, 9091, 9097
-);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 44, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (27, 28, 29, 45, 46, 47, 68, 77, 9047, 9091, 9097);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 48, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (49, 50, 9048, 9049, 9050);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 54, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (55, 56, 57, 58, 67, 78);
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 900, NOW()
-FROM sys_role_resource rr
-WHERE rr.resource_id IN (901, 902);

+ 0 - 2
forge-server/db/backup/V1.0.5__add_sys_org_code.sql

@@ -1,2 +0,0 @@
-ALTER TABLE sys_org ADD org_code varchar(100) NULL COMMENT '组织编码';
-ALTER TABLE sys_org CHANGE org_code org_code varchar(100) NULL COMMENT '组织编码' AFTER tenant_id;

+ 0 - 44
forge-server/db/backup/V1.0.60__add_workbench_home_menu.sql

@@ -1,46 +0,0 @@
-
-INSERT INTO sys_resource (
-    tenant_id, resource_name, parent_id, resource_type, sort, path, component,
-    is_external, sso_enabled, open_target, is_public, menu_status, visible,
-    perms, icon, keep_alive, always_show, client_code, create_by, create_time,
-    update_by, update_time
-)
-SELECT
-    1, '首页', 43, 2, 0, '/home', 'home/index',
-    0, 0, '_self', 0, 1, 1,
-    NULL, 'ionicons5:HomeOutline', 0, 0, 'pc', NULL, NOW(),
-    NULL, NOW()
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1 AND client_code = 'pc' AND path = '/home'
-);
-
-UPDATE sys_resource
-SET resource_name = '首页',
-    parent_id = 43,
-    resource_type = 2,
-    sort = 0,
-    component = 'home/index',
-    icon = 'ionicons5:HomeOutline',
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE tenant_id = 1 AND client_code = 'pc' AND path = '/home';
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, 43, NOW()
-FROM sys_role_resource rr
-INNER JOIN sys_resource owned ON owned.id = rr.resource_id
-WHERE owned.client_code = 'pc';
-
-INSERT IGNORE INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, home.id, NOW()
-FROM sys_role_resource rr
-INNER JOIN sys_resource owned ON owned.id = rr.resource_id
-INNER JOIN sys_resource home ON home.tenant_id = 1
-    AND home.client_code = 'pc'
-    AND home.path = '/home'
-WHERE owned.client_code = 'pc';

+ 0 - 216
forge-server/db/backup/V1.0.61__restore_app_center_menu_permissions.sql

@@ -1,222 +0,0 @@
-
-SET @app_center_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-    AND component = 'app-center/index'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_datasource_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/generator/datasource'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_engine_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/engines'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_mobile_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/mobile'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_integration_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/integration'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_suite_detail_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/suite/:suiteCode'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_object_detail_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/object/:objectCode'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_object_designer_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/object/:objectCode/designer'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @admin_role_id := (
-  SELECT id
-  FROM sys_role
-  WHERE tenant_id = 1
-    AND role_key = 'admin'
-  ORDER BY id
-  LIMIT 1
-);
-
-UPDATE sys_resource
-SET parent_id = 0,
-    resource_type = 1,
-    resource_name = '应用中心',
-    path = '/app-center',
-    component = NULL,
-    sort = 2,
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE id = @app_center_root_id;
-
-UPDATE sys_resource
-SET parent_id = @app_center_root_id,
-    resource_type = 2,
-    resource_name = '应用总览',
-    path = '/app-center',
-    component = 'app-center/index',
-    sort = 1,
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE @app_center_root_id IS NOT NULL
-  AND id = @app_overview_id;
-
-UPDATE sys_resource
-SET parent_id = @app_center_root_id,
-    sort = CASE id
-             WHEN @app_datasource_id THEN 2
-             WHEN @app_engine_id THEN 3
-             WHEN @app_mobile_id THEN 4
-             WHEN @app_integration_id THEN 5
-             ELSE sort
-           END,
-    visible = 1,
-    menu_status = 1,
-    update_time = NOW()
-WHERE @app_center_root_id IS NOT NULL
-  AND id IN (@app_datasource_id, @app_engine_id, @app_mobile_id, @app_integration_id);
-
-UPDATE sys_resource
-SET parent_id = @app_overview_id,
-    visible = 0,
-    menu_status = 1,
-    update_time = NOW()
-WHERE @app_overview_id IS NOT NULL
-  AND id IN (@app_suite_detail_id, @app_object_detail_id, @app_object_designer_id);
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT 1, @admin_role_id, target.id, NOW()
-FROM sys_resource target
-WHERE @admin_role_id IS NOT NULL
-  AND target.id IN (
-    @app_center_root_id,
-    @app_overview_id,
-    @app_datasource_id,
-    @app_engine_id,
-    @app_mobile_id,
-    @app_integration_id,
-    @app_suite_detail_id,
-    @app_object_detail_id,
-    @app_object_designer_id
-  )
-  AND target.id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = 1
-      AND exists_rr.role_id = @admin_role_id
-      AND exists_rr.resource_id = target.id
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT source.tenant_id, source.role_id, target.id, NOW()
-FROM (
-  SELECT rr.tenant_id, rr.role_id
-  FROM sys_role_resource rr
-  INNER JOIN sys_resource owned ON owned.id = rr.resource_id
-  WHERE owned.tenant_id = 1
-    AND owned.client_code = 'pc'
-    AND (
-      owned.id IN (
-        @app_center_root_id,
-        @app_overview_id,
-        @app_datasource_id,
-        @app_engine_id,
-        @app_mobile_id,
-        @app_integration_id,
-        @app_suite_detail_id,
-        @app_object_detail_id,
-        @app_object_designer_id
-      )
-      OR owned.path LIKE '/app-center%'
-      OR owned.perms LIKE 'ai:business%'
-    )
-) source
-INNER JOIN sys_resource target ON target.id IN (@app_center_root_id, @app_overview_id)
-WHERE target.id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = source.tenant_id
-      AND exists_rr.role_id = source.role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 17
forge-server/db/backup/V1.0.62__add_client_captcha_override.sql

@@ -1,18 +0,0 @@
-
-SET @column_exists = (
-  SELECT COUNT(1)
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_client'
-    AND COLUMN_NAME = 'captcha_type'
-);
-
-SET @sql = IF(
-  @column_exists = 0,
-  'ALTER TABLE `sys_client` ADD COLUMN `captcha_type` varchar(32) DEFAULT NULL COMMENT ''验证码覆盖类型:graphical/slider/sms,空表示继承全局登录配置'' AFTER `auth_types`',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 25
forge-server/db/backup/V1.0.63__allow_string_sys_org_type.sql

@@ -1,26 +0,0 @@
-
-SET @table_exists = (
-  SELECT COUNT(1)
-  FROM information_schema.TABLES
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_org'
-);
-
-SET @column_is_string = (
-  SELECT COUNT(1)
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_org'
-    AND COLUMN_NAME = 'org_type'
-    AND DATA_TYPE IN ('char', 'varchar')
-);
-
-SET @sql = IF(
-  @table_exists > 0 AND @column_is_string = 0,
-  'ALTER TABLE `sys_org` MODIFY COLUMN `org_type` varchar(64) DEFAULT ''1'' COMMENT ''组织类型(sys_org_type 字典值)''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 60
forge-server/db/backup/V1.0.64__fix_org_datascope_and_role_visibility.sql

@@ -1,63 +0,0 @@
-
-UPDATE sys_data_scope_config
-SET user_id_column = '<sql>id IN (SELECT org_id FROM sys_user_org WHERE user_id = #{userId} AND tenant_id = #{tenantId})</sql>',
-    table_alias = '',
-    update_time = NOW()
-WHERE mapper_method IN (
-    'com.mdframe.forge.plugin.system.mapper.SysOrgMapper.selectOrgPage',
-    'com.mdframe.forge.plugin.system.mapper.SysOrgMapper.selectOrgList'
-);
-
-UPDATE sys_data_scope_config
-SET user_id_column = '<sql>o.id IN (SELECT org_id FROM sys_user_org WHERE user_id = #{userId} AND tenant_id = #{tenantId})</sql>',
-    table_alias = 'o',
-    update_time = NOW()
-WHERE mapper_method = 'com.mdframe.forge.plugin.system.mapper.SysOrgMapper.selectOrgLazyTree';
-
-INSERT INTO sys_data_scope_config (
-    tenant_id,
-    resource_code,
-    resource_name,
-    mapper_method,
-    table_alias,
-    user_id_column,
-    org_id_column,
-    tenant_id_column,
-    region_code_column,
-    user_region_column,
-    user_table_alias,
-    enabled,
-    remark,
-    create_by,
-    create_time,
-    update_by,
-    update_time,
-    create_dept
-)
-SELECT
-    1,
-    'system:org:children',
-    '组织子节点查询',
-    'com.mdframe.forge.plugin.system.mapper.SysOrgMapper.selectOrgChildrenByParentId',
-    'o',
-    '<sql>o.id IN (SELECT org_id FROM sys_user_org WHERE user_id = #{userId} AND tenant_id = #{tenantId})</sql>',
-    'id',
-    'tenant_id',
-    'region_code',
-    NULL,
-    NULL,
-    1,
-    '组织懒加载子节点数据权限配置',
-    NULL,
-    NOW(),
-    NULL,
-    NOW(),
-    NULL
-WHERE NOT EXISTS (
-    SELECT 1
-    FROM sys_data_scope_config
-    WHERE mapper_method = 'com.mdframe.forge.plugin.system.mapper.SysOrgMapper.selectOrgChildrenByParentId'
-);

+ 0 - 97
forge-server/db/backup/V1.0.65__harden_user_type_permission_boundaries.sql

@@ -1,100 +0,0 @@
-
-SET @col_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_resource'
-    AND COLUMN_NAME = 'min_user_type'
-);
-SET @sql = IF(@col_exists = 0,
-  'ALTER TABLE sys_resource ADD COLUMN min_user_type INT NOT NULL DEFAULT 2 COMMENT ''最低可访问用户类型(0-系统管理员,1-租户管理员,2-普通用户)'' AFTER client_code',
-  'SELECT ''Column min_user_type already exists''');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE sys_resource
-SET min_user_type = 2
-WHERE min_user_type IS NULL;
-
-UPDATE sys_resource
-SET min_user_type = 1
-WHERE resource_name IN ('系统管理', '用户管理', '角色管理', '组织管理', '岗位管理')
-   OR path IN ('/system/user', '/system/role', '/system/org', '/system/post')
-   OR component IN ('system/user', 'system/role', 'system/org', 'system/post')
-   OR perms LIKE 'system:user:%'
-   OR perms LIKE 'system:role:%'
-   OR perms LIKE 'system:org:%'
-   OR perms LIKE 'system:post:%'
-   OR api_url = '/system/user'
-   OR api_url LIKE '/system/user/%'
-   OR api_url = '/system/role'
-   OR api_url LIKE '/system/role/%'
-   OR api_url = '/system/org'
-   OR api_url LIKE '/system/org/%'
-   OR api_url = '/system/post'
-   OR api_url LIKE '/system/post/%';
-
-UPDATE sys_resource
-SET min_user_type = 0
-WHERE resource_name IN (
-        '数据权限配置', '客户端配置', '系统参数配置', '系统配置', '菜单管理',
-        '资源管理', '租户管理', '字典管理', '字典类型', '字典数据',
-        '缓存管理', '系统监控', '在线用户', '操作日志', '登录日志',
-        '文件存储配置', 'Excel导出配置', 'Excel列配置'
-      )
-   OR path IN (
-        '/system/dataScopeConfig', '/system/client', '/system/config',
-        '/system/menu', '/system/resource', '/system/tenant',
-        '/system/dictType', '/system/dictData', '/system/cache',
-        '/system/monitor', '/system/online', '/system/operation-log',
-        '/system/login-log', '/system/fileStorageConfig',
-        '/system/excelExportConfig', '/system/excelColumnConfig'
-      )
-   OR component IN (
-        'system/dataScopeConfig', 'system/client', 'system/config',
-        'system/menu', 'system/tenant', 'system/dictType',
-        'system/dictData', 'system/cache', 'system/monitor',
-        'system/online', 'system/operation-log', 'system/login-log',
-        'system/fileStorageConfig', 'system/excelExportConfig',
-        'system/excelColumnConfig'
-      )
-   OR perms LIKE 'system:dataScopeConfig:%'
-   OR perms LIKE 'system:client:%'
-   OR perms LIKE 'system:config:%'
-   OR perms LIKE 'system:resource:%'
-   OR perms LIKE 'system:menu:%'
-   OR perms LIKE 'system:tenant:%'
-   OR perms LIKE 'system:dict:%'
-   OR perms LIKE 'system:cache:%'
-   OR perms LIKE 'system:monitor:%'
-   OR perms LIKE 'system:online:%'
-   OR perms LIKE 'system:operationLog:%'
-   OR perms LIKE 'system:loginLog:%'
-   OR api_url = '/system/dataScopeConfig'
-   OR api_url LIKE '/system/dataScopeConfig/%'
-   OR api_url = '/datascope'
-   OR api_url LIKE '/datascope/%'
-   OR api_url = '/system/client'
-   OR api_url LIKE '/system/client/%'
-   OR api_url = '/system/config'
-   OR api_url LIKE '/system/config/%'
-   OR api_url = '/system/resource'
-   OR api_url LIKE '/system/resource/%'
-   OR api_url = '/system/tenant'
-   OR api_url LIKE '/system/tenant/%'
-   OR api_url = '/system/dict'
-   OR api_url LIKE '/system/dict/%'
-   OR api_url = '/system/cache'
-   OR api_url LIKE '/system/cache/%'
-   OR api_url = '/system/monitor'
-   OR api_url LIKE '/system/monitor/%'
-   OR api_url = '/system/online'
-   OR api_url LIKE '/system/online/%'
-   OR api_url = '/system/operation-log'
-   OR api_url LIKE '/system/operation-log/%'
-   OR api_url = '/system/login-log'
-   OR api_url LIKE '/system/login-log/%';

+ 0 - 15
forge-server/db/backup/V1.0.66__allow_normal_user_org_user_role_management.sql

@@ -1,17 +0,0 @@
-
-UPDATE sys_resource
-SET min_user_type = 2
-WHERE resource_name IN ('系统管理', '组织管理', '用户管理', '角色管理')
-   OR path IN ('/system/org', '/system/user', '/system/role')
-   OR component IN ('system/org', 'system/user', 'system/role')
-   OR perms LIKE 'system:org:%'
-   OR perms LIKE 'system:user:%'
-   OR perms LIKE 'system:role:%'
-   OR api_url = '/system/org'
-   OR api_url LIKE '/system/org/%'
-   OR api_url = '/system/user'
-   OR api_url LIKE '/system/user/%'
-   OR api_url = '/system/role'
-   OR api_url LIKE '/system/role/%';

+ 0 - 40
forge-server/db/backup/V1.0.67__harden_sensitive_data_and_upload_controls.sql

@@ -1,44 +0,0 @@
-
-SET @col_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_user'
-    AND COLUMN_NAME = 'force_password_change'
-);
-SET @sql = IF(@col_exists = 0,
-  'ALTER TABLE sys_user ADD COLUMN force_password_change TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否必须修改密码'' AFTER login_count',
-  'SELECT ''Column force_password_change already exists''');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE sys_user
-SET force_password_change = 1,
-    update_time = CURRENT_TIMESTAMP
-WHERE user_status = 1
-  AND force_password_change = 0;
-
-UPDATE sys_config
-SET config_value = '',
-    config_type = 'N',
-    config_desc = CASE
-      WHEN config_desc LIKE '%已因安全加固停用%' THEN config_desc
-      ELSE CONCAT(
-        COALESCE(NULLIF(config_desc, ''), '用户初始密码配置'),
-        ';已因安全加固停用,新增/重置用户必须首次登录修改密码'
-      )
-    END,
-    update_time = CURRENT_TIMESTAMP
-WHERE config_key = 'sys.user.initPassword';
-
-UPDATE sys_file_storage_config
-SET allowed_types = 'jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,txt,csv,zip,rar,mp4,mp3',
-    update_time = CURRENT_TIMESTAMP
-WHERE allowed_types IS NULL
-   OR TRIM(allowed_types) = ''
-   OR LOWER(CONCAT(',', REPLACE(allowed_types, ' ', ''), ',')) REGEXP ',(svg|html|htm|js|mjs|ts|vue|jsp|jspx|php|asp|aspx|sh|bash|bat|cmd|ps1|exe|dll|jar|war|ear|sql|md),';

+ 0 - 18
forge-server/db/backup/V1.0.68__add_formula_config_to_gen_table_column.sql

@@ -1,21 +0,0 @@
-
-SET @column_exists = (
-    SELECT COUNT(*)
-    FROM information_schema.COLUMNS
-    WHERE TABLE_SCHEMA = DATABASE()
-      AND TABLE_NAME = 'gen_table_column'
-      AND COLUMN_NAME = 'formula_config'
-);
-
-SET @sql = IF(
-    @column_exists = 0,
-    'ALTER TABLE gen_table_column ADD COLUMN formula_config TEXT NULL COMMENT ''公式配置JSON {type,expression,mode,dependsOn,aggregate,condition}'' AFTER validate_rule',
-    'SELECT 1'
-);
-
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 203
forge-server/db/backup/V1.0.69__add_formula_observability_and_function_market.sql

@@ -1,206 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_formula_execution_log` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `trace_id` varchar(64) DEFAULT NULL COMMENT '公式执行链路ID',
-  `object_code` varchar(64) NOT NULL COMMENT '业务对象编码',
-  `record_id` varchar(64) DEFAULT NULL COMMENT '业务记录ID',
-  `field_code` varchar(64) NOT NULL COMMENT '公式字段编码',
-  `formula_type` varchar(32) DEFAULT NULL COMMENT '公式类型:CALC/AGGREGATE/CONDITIONAL/LOOKUP',
-  `formula_mode` varchar(32) DEFAULT NULL COMMENT '计算模式:STORED/VIRTUAL',
-  `expression` text DEFAULT NULL COMMENT '表达式或配置摘要',
-  `input_snapshot` json DEFAULT NULL COMMENT '输入快照,脱敏后存储',
-  `output_value` text DEFAULT NULL COMMENT '输出值摘要,脱敏后存储',
-  `success` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否执行成功:1成功 0失败',
-  `error_message` text DEFAULT NULL COMMENT '错误信息',
-  `elapsed_ms` bigint DEFAULT NULL COMMENT '执行耗时(毫秒)',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  KEY `idx_ai_formula_log_trace` (`tenant_id`, `trace_id`),
-  KEY `idx_ai_formula_log_record` (`tenant_id`, `object_code`, `record_id`, `create_time`),
-  KEY `idx_ai_formula_log_field` (`tenant_id`, `field_code`, `create_time`),
-  KEY `idx_ai_formula_log_success` (`tenant_id`, `success`, `create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-公式执行日志表';
-
-CREATE TABLE IF NOT EXISTS `ai_formula_function` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `function_code` varchar(64) NOT NULL COMMENT '函数编码',
-  `display_name` varchar(128) NOT NULL COMMENT '展示名称',
-  `category` varchar(64) NOT NULL COMMENT '函数分类',
-  `description` varchar(500) DEFAULT NULL COMMENT '函数说明',
-  `source_type` varchar(32) NOT NULL DEFAULT 'BUILTIN' COMMENT '来源类型:BUILTIN/SYSTEM/TENANT/MARKET',
-  `argument_schema` json DEFAULT NULL COMMENT '参数Schema',
-  `return_type` varchar(32) DEFAULT NULL COMMENT '返回类型',
-  `example` text DEFAULT NULL COMMENT '示例',
-  `status` varchar(32) NOT NULL DEFAULT 'ENABLED' COMMENT '状态:ENABLED/DISABLED',
-  `current_version` varchar(32) DEFAULT NULL COMMENT '当前版本',
-  `latest_version` varchar(32) DEFAULT NULL COMMENT '最新版本',
-  `builtin` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否内置函数',
-  `sort_order` int NOT NULL DEFAULT 0 COMMENT '排序号',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_formula_function_code` (`tenant_id`, `function_code`),
-  KEY `idx_ai_formula_function_query` (`tenant_id`, `category`, `source_type`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-公式函数注册表';
-
-CREATE TABLE IF NOT EXISTS `ai_formula_function_version` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `function_code` varchar(64) NOT NULL COMMENT '函数编码',
-  `version` varchar(32) NOT NULL COMMENT '函数版本',
-  `implementation_type` varchar(32) NOT NULL DEFAULT 'JAVA_BEAN' COMMENT '实现类型',
-  `bean_name` varchar(128) DEFAULT NULL COMMENT 'Spring Bean名称',
-  `method_name` varchar(128) DEFAULT NULL COMMENT '方法名称',
-  `argument_schema` json DEFAULT NULL COMMENT '参数Schema',
-  `return_type` varchar(32) DEFAULT NULL COMMENT '返回类型',
-  `example` text DEFAULT NULL COMMENT '示例',
-  `release_note` varchar(500) DEFAULT NULL COMMENT '版本说明',
-  `status` varchar(32) NOT NULL DEFAULT 'ENABLED' COMMENT '状态:ENABLED/DISABLED/DEPRECATED',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_formula_function_version` (`tenant_id`, `function_code`, `version`),
-  KEY `idx_ai_formula_function_version_code` (`tenant_id`, `function_code`, `status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-公式函数版本表';
-
-CREATE TABLE IF NOT EXISTS `ai_formula_function_install` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `function_code` varchar(64) NOT NULL COMMENT '函数编码',
-  `installed_version` varchar(32) NOT NULL COMMENT '已安装版本',
-  `install_status` varchar(32) NOT NULL DEFAULT 'INSTALLED' COMMENT '安装状态:INSTALLED/UNINSTALLED',
-  `enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
-  `source_type` varchar(32) NOT NULL DEFAULT 'BUILTIN' COMMENT '来源类型:BUILTIN/SYSTEM/TENANT/MARKET',
-  `installed_by` bigint DEFAULT NULL COMMENT '安装人',
-  `installed_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '安装时间',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_formula_function_install` (`tenant_id`, `function_code`),
-  KEY `idx_ai_formula_function_install_status` (`tenant_id`, `install_status`, `enabled`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-公式函数安装表';
-
-INSERT INTO `ai_formula_function` (
-  id, tenant_id, function_code, display_name, category, description, source_type,
-  argument_schema, return_type, example, status, current_version, latest_version,
-  builtin, sort_order, create_by, create_time, create_dept, update_by, update_time
-)
-SELECT seed.id, 1, seed.function_code, seed.display_name, seed.category, seed.description, 'BUILTIN',
-       seed.argument_schema, seed.return_type, seed.example, 'ENABLED', '1.0.0', '1.0.0',
-       1, seed.sort_order, NULL, NOW(), NULL, NULL, NOW()
-FROM (
-  SELECT 690001001 AS id, 'math.abs' AS function_code, '绝对值' AS display_name, 'Math' AS category, '返回数字绝对值' AS description, JSON_ARRAY(JSON_OBJECT('name','value','type','NUMBER','required',true)) AS argument_schema, 'NUMBER' AS return_type, 'math.abs(-5) => 5' AS example, 10 AS sort_order
-  UNION ALL SELECT 690001002, 'math.round', '四舍五入', 'Math', '返回最接近的整数', JSON_ARRAY(JSON_OBJECT('name','value','type','NUMBER','required',true)), 'NUMBER', 'math.round(3.6) => 4', 20
-  UNION ALL SELECT 690001010, 'math.floor', '向下取整', 'Math', '返回不大于入参的最大整数', JSON_ARRAY(JSON_OBJECT('name','value','type','NUMBER','required',true)), 'NUMBER', 'math.floor(3.9) => 3', 25
-  UNION ALL SELECT 690001011, 'math.ceil', '向上取整', 'Math', '返回不小于入参的最小整数', JSON_ARRAY(JSON_OBJECT('name','value','type','NUMBER','required',true)), 'NUMBER', 'math.ceil(3.1) => 4', 26
-  UNION ALL SELECT 690001003, 'math.max', '最大值', 'Math', '返回两个数字中的最大值', JSON_ARRAY(JSON_OBJECT('name','left','type','NUMBER','required',true), JSON_OBJECT('name','right','type','NUMBER','required',true)), 'NUMBER', 'math.max(3, 7) => 7', 30
-  UNION ALL SELECT 690001004, 'math.min', '最小值', 'Math', '返回两个数字中的最小值', JSON_ARRAY(JSON_OBJECT('name','left','type','NUMBER','required',true), JSON_OBJECT('name','right','type','NUMBER','required',true)), 'NUMBER', 'math.min(3, 7) => 3', 40
-  UNION ALL SELECT 690001012, 'math.pow', '幂运算', 'Math', '返回 left 的 right 次方', JSON_ARRAY(JSON_OBJECT('name','left','type','NUMBER','required',true), JSON_OBJECT('name','right','type','NUMBER','required',true)), 'NUMBER', 'math.pow(2, 3) => 8', 50
-  UNION ALL SELECT 690001013, 'math.sqrt', '平方根', 'Math', '返回数字平方根', JSON_ARRAY(JSON_OBJECT('name','value','type','NUMBER','required',true)), 'NUMBER', 'math.sqrt(16) => 4', 60
-  UNION ALL SELECT 690001005, 'string.length', '字符串长度', 'String', '返回字符串长度', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true)), 'NUMBER', 'string.length(''hello'') => 5', 110
-  UNION ALL SELECT 690001006, 'string.contains', '包含判断', 'String', '判断字符串是否包含子串', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true), JSON_OBJECT('name','keyword','type','STRING','required',true)), 'BOOLEAN', 'string.contains(''hello'',''ll'') => true', 120
-  UNION ALL SELECT 690001007, 'string.startsWith', '前缀判断', 'String', '判断字符串前缀', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true), JSON_OBJECT('name','prefix','type','STRING','required',true)), 'BOOLEAN', 'string.startsWith(''hello'',''he'') => true', 130
-  UNION ALL SELECT 690001008, 'string.endsWith', '后缀判断', 'String', '判断字符串后缀', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true), JSON_OBJECT('name','suffix','type','STRING','required',true)), 'BOOLEAN', 'string.endsWith(''hello'',''lo'') => true', 140
-  UNION ALL SELECT 690001014, 'string.indexOf', '子串位置', 'String', '返回子串首次出现位置', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true), JSON_OBJECT('name','keyword','type','STRING','required',true)), 'NUMBER', 'string.indexOf(''hello'',''l'') => 2', 150
-  UNION ALL SELECT 690001015, 'string.replace', '字符串替换', 'String', '替换字符串片段', JSON_ARRAY(JSON_OBJECT('name','value','type','STRING','required',true), JSON_OBJECT('name','target','type','STRING','required',true), JSON_OBJECT('name','replacement','type','STRING','required',true)), 'STRING', 'string.replace(''hello'',''l'',''x'') => ''hexxo''', 160
-  UNION ALL SELECT 690001016, 'seq.list', '创建列表', 'Collection', '按入参顺序创建列表', JSON_ARRAY(), 'COLLECTION', 'seq.list(1,2,3) => [1,2,3]', 310
-  UNION ALL SELECT 690001017, 'seq.set', '创建集合', 'Collection', '按入参顺序创建去重集合', JSON_ARRAY(), 'COLLECTION', 'seq.set(1,2,3) => [1,2,3]', 320
-  UNION ALL SELECT 690001018, 'seq.map', '创建映射', 'Collection', '按 key/value 入参创建映射', JSON_ARRAY(), 'MAP', 'seq.map(''a'',1,''b'',2) => {a:1,b:2}', 330
-  UNION ALL SELECT 690001009, 'date_to_string', '日期格式化', 'Date', '将日期格式化为字符串', JSON_ARRAY(JSON_OBJECT('name','date','type','DATE','required',true), JSON_OBJECT('name','pattern','type','STRING','required',true)), 'STRING', 'date_to_string(date, ''yyyy-MM-dd'')', 210
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM `ai_formula_function` existing
-  WHERE existing.tenant_id = 1
-    AND existing.function_code = seed.function_code
-);
-
-INSERT INTO `ai_formula_function_version` (
-  id, tenant_id, function_code, version, implementation_type, bean_name, method_name,
-  argument_schema, return_type, example, release_note, status,
-  create_by, create_time, create_dept, update_by, update_time
-)
-SELECT seed.id, 1, seed.function_code, '1.0.0', 'JAVA_BEAN', seed.bean_name, seed.method_name,
-       f.argument_schema, f.return_type, f.example, '内置函数初始版本', 'ENABLED',
-       NULL, NOW(), NULL, NULL, NOW()
-FROM (
-  SELECT 690002001 AS id, 'math.abs' AS function_code, 'formulaBuiltinFunctionProvider' AS bean_name, 'mathAbs' AS method_name
-  UNION ALL SELECT 690002002, 'math.round', 'formulaBuiltinFunctionProvider', 'mathRound'
-  UNION ALL SELECT 690002010, 'math.floor', 'formulaBuiltinFunctionProvider', 'mathFloor'
-  UNION ALL SELECT 690002011, 'math.ceil', 'formulaBuiltinFunctionProvider', 'mathCeil'
-  UNION ALL SELECT 690002003, 'math.max', 'formulaBuiltinFunctionProvider', 'mathMax'
-  UNION ALL SELECT 690002004, 'math.min', 'formulaBuiltinFunctionProvider', 'mathMin'
-  UNION ALL SELECT 690002012, 'math.pow', 'formulaBuiltinFunctionProvider', 'mathPow'
-  UNION ALL SELECT 690002013, 'math.sqrt', 'formulaBuiltinFunctionProvider', 'mathSqrt'
-  UNION ALL SELECT 690002005, 'string.length', 'formulaBuiltinFunctionProvider', 'stringLength'
-  UNION ALL SELECT 690002006, 'string.contains', 'formulaBuiltinFunctionProvider', 'stringContains'
-  UNION ALL SELECT 690002007, 'string.startsWith', 'formulaBuiltinFunctionProvider', 'stringStartsWith'
-  UNION ALL SELECT 690002008, 'string.endsWith', 'formulaBuiltinFunctionProvider', 'stringEndsWith'
-  UNION ALL SELECT 690002014, 'string.indexOf', 'formulaBuiltinFunctionProvider', 'stringIndexOf'
-  UNION ALL SELECT 690002015, 'string.replace', 'formulaBuiltinFunctionProvider', 'stringReplace'
-  UNION ALL SELECT 690002016, 'seq.list', 'formulaBuiltinFunctionProvider', 'seqList'
-  UNION ALL SELECT 690002017, 'seq.set', 'formulaBuiltinFunctionProvider', 'seqSet'
-  UNION ALL SELECT 690002018, 'seq.map', 'formulaBuiltinFunctionProvider', 'seqMap'
-  UNION ALL SELECT 690002009, 'date_to_string', 'formulaBuiltinFunctionProvider', 'dateToString'
-) seed
-JOIN `ai_formula_function` f
-  ON f.tenant_id = 1
- AND f.function_code = seed.function_code
-WHERE NOT EXISTS (
-  SELECT 1 FROM `ai_formula_function_version` existing
-  WHERE existing.tenant_id = 1
-    AND existing.function_code = seed.function_code
-    AND existing.version = '1.0.0'
-);
-
-INSERT INTO `ai_formula_function_install` (
-  id, tenant_id, function_code, installed_version, install_status, enabled, source_type,
-  installed_by, installed_time, create_by, create_time, create_dept, update_by, update_time
-)
-SELECT seed.id, 1, seed.function_code, '1.0.0', 'INSTALLED', 1, 'BUILTIN',
-       NULL, NOW(), NULL, NOW(), NULL, NULL, NOW()
-FROM (
-  SELECT 690003001 AS id, 'math.abs' AS function_code
-  UNION ALL SELECT 690003002, 'math.round'
-  UNION ALL SELECT 690003010, 'math.floor'
-  UNION ALL SELECT 690003011, 'math.ceil'
-  UNION ALL SELECT 690003003, 'math.max'
-  UNION ALL SELECT 690003004, 'math.min'
-  UNION ALL SELECT 690003012, 'math.pow'
-  UNION ALL SELECT 690003013, 'math.sqrt'
-  UNION ALL SELECT 690003005, 'string.length'
-  UNION ALL SELECT 690003006, 'string.contains'
-  UNION ALL SELECT 690003007, 'string.startsWith'
-  UNION ALL SELECT 690003008, 'string.endsWith'
-  UNION ALL SELECT 690003014, 'string.indexOf'
-  UNION ALL SELECT 690003015, 'string.replace'
-  UNION ALL SELECT 690003016, 'seq.list'
-  UNION ALL SELECT 690003017, 'seq.set'
-  UNION ALL SELECT 690003018, 'seq.map'
-  UNION ALL SELECT 690003009, 'date_to_string'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1 FROM `ai_formula_function_install` existing
-  WHERE existing.tenant_id = 1
-    AND existing.function_code = seed.function_code
-);

+ 0 - 2
forge-server/db/backup/V1.0.6__add_sys_org_code_parent.sql

@@ -1,2 +0,0 @@
-ALTER TABLE sys_org ADD org_parent_code varchar(100) NULL COMMENT '父级组织编码';
-ALTER TABLE sys_org CHANGE org_parent_code org_parent_code varchar(100) NULL COMMENT '父级组织编码' AFTER org_code;

+ 0 - 168
forge-server/db/backup/V1.0.70__consolidate_app_codegen_mode.sql

@@ -1,169 +0,0 @@
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT 1, '访问入口使用模式', 'ai_business_app_mode', 1, '访问入口在线运行或下载代码模式', 1, NOW(), 1, NOW(), 1
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type
-  WHERE tenant_id = 1
-    AND dict_type = 'ai_business_app_mode'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default,
-                           dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class,
-       seed.is_default, 1, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '在线运行' dict_label, 'DYNAMIC_RENDER' dict_value,
-         'ai_business_app_mode' dict_type, 'success' list_class, 'Y' is_default,
-         '在线搭建并由平台动态运行' remark
-  UNION ALL
-  SELECT 1, 2, '下载代码', 'CODE_DOWNLOAD',
-         'ai_business_app_mode', 'primary', 'N',
-         '下载完整功能代码后导入本地工程二次开发'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);
-
-UPDATE sys_dict_type
-SET dict_name = CASE dict_type
-                  WHEN 'ai_business_suite' THEN '业务域'
-                  WHEN 'ai_business_object_type' THEN '业务单元类型'
-                  WHEN 'ai_business_relation_type' THEN '业务单元关系类型'
-                  WHEN 'ai_business_app_entry_mode' THEN '访问入口打开方式'
-                  ELSE dict_name
-                END,
-    remark = CASE dict_type
-               WHEN 'ai_business_suite' THEN '企业应用装配平台业务域'
-               WHEN 'ai_business_object_type' THEN '业务单元/实体类型'
-               WHEN 'ai_business_relation_type' THEN '业务单元之间的引用、明细和关联列表关系'
-               WHEN 'ai_business_app_entry_mode' THEN '访问入口打开方式'
-               ELSE remark
-             END,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND dict_type IN (
-    'ai_business_suite',
-    'ai_business_object_type',
-    'ai_business_relation_type',
-    'ai_business_app_entry_mode'
-  );
-
-UPDATE sys_dict_data
-SET dict_label = CASE
-                   WHEN dict_type = 'ai_business_app_entry_mode' AND dict_value = 'RUNTIME' THEN '业务页面'
-                   WHEN dict_type = 'ai_business_app_entry_mode' AND dict_value = 'H5' THEN 'H5 入口'
-                   ELSE dict_label
-                 END,
-    remark = CASE
-               WHEN dict_type = 'ai_business_app_entry_mode' AND dict_value = 'RUNTIME' THEN '打开平台托管的业务页面'
-               WHEN dict_type = 'ai_business_app_entry_mode' AND dict_value = 'API' THEN '登记接口或集成资源'
-               ELSE remark
-             END,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND dict_type = 'ai_business_app_entry_mode'
-  AND dict_value IN ('RUNTIME', 'H5', 'API');
-
-SET @app_center_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND resource_type = 2
-    AND perms = 'ai:businessApp:list'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @app_center_menu_id, 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '设置功能代码' resource_name, 46 sort, 'ai:businessApp:code' perms, '维护访问入口代码包设置' remark
-  UNION ALL SELECT 1, '预览功能代码', 47, 'ai:businessApp:codePreview', '预览访问入口完整功能代码'
-  UNION ALL SELECT 1, '下载功能代码', 48, 'ai:businessApp:codeDownload', '下载访问入口完整功能代码'
-) seed
-WHERE @app_center_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.resource_type = 3
-      AND r.perms = seed.perms
-  );
-
-UPDATE sys_resource
-SET resource_name = CASE perms
-                      WHEN 'ai:businessApp:list' THEN '应用总览'
-                      WHEN 'ai:businessSuite:list' THEN '查看业务域'
-                      WHEN 'ai:businessSuite:edit' THEN '维护业务域'
-                      WHEN 'ai:businessObject:list' THEN '查看业务单元'
-                      WHEN 'ai:businessObject:add' THEN '新增业务单元'
-                      WHEN 'ai:businessObject:edit' THEN '编辑业务单元'
-                      WHEN 'ai:businessObject:delete' THEN '删除业务单元'
-                      WHEN 'ai:businessObject:relation' THEN '配置业务单元关系'
-                      WHEN 'ai:businessApp:add' THEN '新增访问入口'
-                      WHEN 'ai:businessApp:edit' THEN '编辑访问入口'
-                      WHEN 'ai:businessApp:delete' THEN '删除访问入口'
-                      WHEN 'ai:businessApp:status' THEN '启停访问入口'
-                      WHEN 'ai:businessApp:open' THEN '打开访问入口'
-                      ELSE resource_name
-                    END,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND perms IN (
-    'ai:businessApp:list',
-    'ai:businessSuite:list',
-    'ai:businessSuite:edit',
-    'ai:businessObject:list',
-    'ai:businessObject:add',
-    'ai:businessObject:edit',
-    'ai:businessObject:delete',
-    'ai:businessObject:relation',
-    'ai:businessApp:add',
-    'ai:businessApp:edit',
-    'ai:businessApp:delete',
-    'ai:businessApp:status',
-    'ai:businessApp:open'
-  );
-
-UPDATE sys_resource
-SET menu_status = 0,
-    visible = 0,
-    update_by = 1,
-    update_time = NOW()
-WHERE resource_type = 2
-  AND tenant_id IN (0, 1)
-  AND (
-    path IN ('/ai/crud-config', '/ai/crud-generator', '/ai/lowcode-builder', '/ai/lowcode-models', '/ai/page-template', '/generator/table', '/generator/template')
-    OR component IN ('ai/crud-config', 'ai/crud-generator', 'ai/lowcode-builder', 'ai/lowcode-models', 'ai/page-template', 'generator/table', 'generator/template')
-    OR perms IN ('ai:crud-config:list', 'ai:crud-gen:list', 'ai:crud-generator:use', 'ai:page-template:list')
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT rr.tenant_id, rr.role_id, target.id, NOW()
-FROM sys_role_resource rr
-JOIN sys_resource src ON src.id = rr.resource_id
-JOIN sys_resource target ON target.tenant_id = 1
-WHERE src.tenant_id = 1
-  AND src.perms IN ('ai:businessApp:list', 'ai:businessApp:edit', 'ai:businessApp:open')
-  AND target.perms IN ('ai:businessApp:code', 'ai:businessApp:codePreview', 'ai:businessApp:codeDownload')
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = rr.tenant_id
-      AND exists_rr.role_id = rr.role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 304
forge-server/db/backup/V1.0.71__restore_app_center_runtime_route_permissions.sql

@@ -1,308 +0,0 @@
-
-SET @app_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-    AND component = 'app-center/index'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_engine_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/engines'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @message_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND resource_name = '消息中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_hidden_parent_id := COALESCE(@app_engine_id, @app_overview_id, @app_root_id, 0);
-SET @app_permission_parent_id := COALESCE(@app_overview_id, @app_engine_id, @app_root_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, seed.parent_id, 2, seed.sort, seed.path, seed.component, 0,
-       0, NULL, '_self', 0, 1, 0, seed.perms, seed.icon,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '业务报表看板' resource_name, @app_hidden_parent_id parent_id, 31 sort,
-         '/app-center/stats' path, 'app-center/stats-dashboard' component,
-         'ai:businessStats:view' perms, 'ionicons5:BarChartOutline' icon, '应用中心报表看板隐藏路由' remark
-  UNION ALL
-  SELECT 1, '触发器配置', @app_hidden_parent_id, 32,
-         '/app-center/trigger', 'app-center/trigger',
-         'ai:businessTrigger:list', 'ionicons5:FlashOutline', '应用中心触发器配置隐藏路由'
-  UNION ALL
-  SELECT 1, '业务运行态页面', @app_permission_parent_id, 33,
-         '/ai/crud-page/:configKey', 'ai/crud-page',
-         'ai:businessRuntime:route', 'ionicons5:PlayCircleOutline', '应用中心通用运行态隐藏路由'
-  UNION ALL
-  SELECT 1, '访问入口跳转', @app_permission_parent_id, 34,
-         '/app-center/app/:appId', 'app-center/app-entry',
-         'ai:businessApp:entryRoute', 'ionicons5:OpenOutline', '应用中心访问入口跳转隐藏路由'
-  UNION ALL
-  SELECT 1, '消息模板配置', COALESCE(@message_root_id, @app_hidden_parent_id), 35,
-         '/message/template', 'message/template-list',
-         'message:template:route', 'ionicons5:MailOutline', '引擎中心消息模板隐藏路由'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = seed.tenant_id
-    AND r.client_code = 'pc'
-    AND r.resource_type = 2
-    AND r.path = seed.path
-);
-
-UPDATE sys_resource
-SET parent_id = CASE path
-                  WHEN '/app-center/stats' THEN @app_hidden_parent_id
-                  WHEN '/app-center/trigger' THEN @app_hidden_parent_id
-                  WHEN '/ai/crud-page/:configKey' THEN @app_permission_parent_id
-                  WHEN '/app-center/app/:appId' THEN @app_permission_parent_id
-                  WHEN '/message/template' THEN COALESCE(@message_root_id, @app_hidden_parent_id)
-                  ELSE parent_id
-                END,
-    resource_name = CASE path
-                      WHEN '/app-center/stats' THEN '业务报表看板'
-                      WHEN '/app-center/trigger' THEN '触发器配置'
-                      WHEN '/ai/crud-page/:configKey' THEN '业务运行态页面'
-                      WHEN '/app-center/app/:appId' THEN '访问入口跳转'
-                      WHEN '/message/template' THEN '消息模板配置'
-                      ELSE resource_name
-                    END,
-    component = CASE path
-                  WHEN '/app-center/stats' THEN 'app-center/stats-dashboard'
-                  WHEN '/app-center/trigger' THEN 'app-center/trigger'
-                  WHEN '/ai/crud-page/:configKey' THEN 'ai/crud-page'
-                  WHEN '/app-center/app/:appId' THEN 'app-center/app-entry'
-                  WHEN '/message/template' THEN 'message/template-list'
-                  ELSE component
-                END,
-    menu_status = 1,
-    visible = 0,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND client_code = 'pc'
-  AND resource_type = 2
-  AND path IN (
-    '/app-center/stats',
-    '/app-center/trigger',
-    '/ai/crud-page/:configKey',
-    '/app-center/app/:appId',
-    '/message/template'
-  );
-
-UPDATE sys_resource
-SET parent_id = @app_overview_id,
-    menu_status = 1,
-    visible = 0,
-    component = CASE path
-                  WHEN '/app-center/suite/:suiteCode' THEN 'app-center/suite.[suiteCode]'
-                  WHEN '/app-center/object/:objectCode' THEN 'app-center/object.[objectCode]'
-                  WHEN '/app-center/object/:objectCode/designer' THEN 'app-center/object-designer.[objectCode]'
-                  ELSE component
-                END,
-    update_by = 1,
-    update_time = NOW()
-WHERE @app_overview_id IS NOT NULL
-  AND tenant_id = 1
-  AND client_code = 'pc'
-  AND resource_type = 2
-  AND path IN (
-    '/app-center/suite/:suiteCode',
-    '/app-center/object/:objectCode',
-    '/app-center/object/:objectCode/designer'
-  );
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, seed.resource_name, @app_permission_parent_id, 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT '查看业务就绪度' resource_name, 36 sort, 'ai:businessReadiness:view' perms, '查看业务单元就绪度权限' remark
-  UNION ALL SELECT '查看关系运行入口', 37, 'ai:businessRelation:runtime', '查看业务对象关系运行入口权限'
-  UNION ALL SELECT '查看业务域验收', 38, 'ai:businessAcceptance:view', '查看业务域验收检查权限'
-  UNION ALL SELECT '查看引擎运行状态', 39, 'ai:businessEngine:runtime', '查看引擎运行状态汇总权限'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.resource_type = 3
-    AND r.perms = seed.perms
-);
-
-UPDATE sys_resource
-SET parent_id = @app_permission_parent_id,
-    menu_status = 1,
-    visible = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND resource_type = 3
-  AND perms IN (
-    'ai:businessApp:list',
-    'ai:businessSuite:list',
-    'ai:businessObject:list',
-    'ai:businessObject:relation',
-    'ai:businessBinding:config',
-    'ai:businessApp:open',
-    'ai:businessStats:view',
-    'ai:businessTrigger:list',
-    'ai:businessReadiness:view',
-    'ai:businessRelation:runtime',
-    'ai:businessAcceptance:view',
-    'ai:businessEngine:runtime'
-  );
-
-SET @app_suite_detail_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/suite/:suiteCode'
-  ORDER BY id LIMIT 1
-);
-
-SET @app_object_detail_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/object/:objectCode'
-  ORDER BY id LIMIT 1
-);
-
-SET @app_object_designer_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/object/:objectCode/designer'
-  ORDER BY id LIMIT 1
-);
-
-SET @app_stats_route_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/stats'
-  ORDER BY id LIMIT 1
-);
-
-SET @app_trigger_route_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/trigger'
-  ORDER BY id LIMIT 1
-);
-
-SET @runtime_route_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/ai/crud-page/:configKey'
-  ORDER BY id LIMIT 1
-);
-
-SET @app_entry_route_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/app-center/app/:appId'
-  ORDER BY id LIMIT 1
-);
-
-SET @message_template_route_id := (
-  SELECT id FROM sys_resource
-  WHERE tenant_id = 1 AND client_code = 'pc' AND resource_type = 2 AND path = '/message/template'
-  ORDER BY id LIMIT 1
-);
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT source.tenant_id, source.role_id, target.id, NOW()
-FROM (
-  SELECT DISTINCT rr.tenant_id, rr.role_id
-  FROM sys_role_resource rr
-  INNER JOIN sys_resource src ON src.id = rr.resource_id
-  WHERE src.tenant_id = 1
-    AND (
-      src.id IN (@app_root_id, @app_overview_id, @app_engine_id)
-      OR src.path LIKE '/app-center%'
-      OR src.path LIKE '/ai/crud-page/%'
-      OR src.perms IN (
-        'ai:businessApp:list',
-        'ai:businessSuite:list',
-        'ai:businessObject:list',
-        'ai:businessEngine:list',
-        'ai:businessApp:open',
-        'ai:businessBinding:config'
-      )
-      OR src.perms LIKE 'ai:business:suite-menu:%'
-    )
-) source
-INNER JOIN sys_resource target ON target.tenant_id = 1
-WHERE (
-    target.id IN (
-      @app_root_id,
-      @app_overview_id,
-      @app_engine_id,
-      @app_suite_detail_id,
-      @app_object_detail_id,
-      @app_object_designer_id,
-      @app_stats_route_id,
-      @app_trigger_route_id,
-      @runtime_route_id,
-      @app_entry_route_id,
-      @message_root_id,
-      @message_template_route_id
-    )
-    OR (
-      target.resource_type = 3
-      AND target.perms IN (
-        'ai:businessApp:list',
-        'ai:businessSuite:list',
-        'ai:businessObject:list',
-        'ai:businessObject:relation',
-        'ai:businessBinding:config',
-        'ai:businessApp:open',
-        'ai:businessStats:view',
-        'ai:businessTrigger:list',
-        'ai:businessReadiness:view',
-        'ai:businessRelation:runtime',
-        'ai:businessAcceptance:view',
-        'ai:businessEngine:runtime'
-      )
-    )
-  )
-  AND target.id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = source.tenant_id
-      AND exists_rr.role_id = source.role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 21
forge-server/db/backup/V1.0.72__require_file_storage_allowed_types.sql

@@ -1,22 +0,0 @@
-
-UPDATE sys_file_storage_config
-SET allowed_types = 'jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,txt,csv,zip,rar,mp4,mp3',
-    update_time = CURRENT_TIMESTAMP
-WHERE allowed_types IS NULL
-   OR TRIM(allowed_types) = ''
-   OR LOWER(CONCAT(',', REPLACE(allowed_types, ' ', ''), ',')) REGEXP ',(svg|html|htm|js|mjs|ts|vue|jsp|jspx|php|asp|aspx|sh|bash|bat|cmd|ps1|exe|dll|so|dylib|jar|war|ear|sql|md),';
-
-SET @allowed_types_nullable = (
-  SELECT IS_NULLABLE
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_file_storage_config'
-    AND COLUMN_NAME = 'allowed_types'
-);
-SET @sql = IF(@allowed_types_nullable = 'YES',
-  'ALTER TABLE sys_file_storage_config MODIFY COLUMN allowed_types varchar(500) NOT NULL COMMENT ''允许的文件类型(逗号分隔)''',
-  'SELECT ''Column sys_file_storage_config.allowed_types is already NOT NULL''');
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 28
forge-server/db/backup/V1.0.73__add_flow_model_designer_type.sql

@@ -1,29 +0,0 @@
-
-SET @table_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.TABLES
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_flow_model'
-);
-
-SET @column_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.COLUMNS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'sys_flow_model'
-    AND COLUMN_NAME = 'designer_type'
-);
-
-SET @sql = IF(
-  @table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_model ADD COLUMN designer_type VARCHAR(32) NOT NULL DEFAULT ''approval'' COMMENT ''设计器类型:approval-审批流程/business-业务流程'' AFTER flow_type',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-UPDATE sys_flow_model
-SET designer_type = 'approval'
-WHERE designer_type IS NULL OR designer_type = '';

+ 0 - 175
forge-server/db/backup/V1.0.74__add_flow_task_overdue_reminder.sql

@@ -1,176 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `sys_flow_overdue_reminder_record` (
-    `id` varchar(64) NOT NULL COMMENT '主键ID',
-    `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-    `task_id` varchar(64) NOT NULL COMMENT 'Flowable任务ID',
-    `process_instance_id` varchar(64) DEFAULT NULL COMMENT '流程实例ID',
-    `process_def_key` varchar(100) DEFAULT NULL COMMENT '流程定义KEY',
-    `task_def_key` varchar(100) DEFAULT NULL COMMENT '任务定义Key',
-    `reminder_key` varchar(160) NOT NULL COMMENT '提醒批次键',
-    `channel` varchar(20) NOT NULL COMMENT '推送渠道',
-    `template_code` varchar(50) DEFAULT NULL COMMENT '消息模板编码',
-    `receiver_user_ids` text COMMENT '接收人用户ID集合',
-    `message_id` bigint DEFAULT NULL COMMENT '消息ID',
-    `send_status` tinyint NOT NULL DEFAULT 0 COMMENT '发送状态:0-待发送/1-成功/2-失败',
-    `send_time` datetime DEFAULT NULL COMMENT '发送时间',
-    `error_message` varchar(1000) DEFAULT NULL COMMENT '失败原因',
-    `create_by` bigint DEFAULT NULL COMMENT '创建人ID',
-    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    `create_dept` bigint DEFAULT NULL COMMENT '创建部门ID',
-    `update_by` bigint DEFAULT NULL COMMENT '更新人ID',
-    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    PRIMARY KEY (`id`),
-    UNIQUE KEY `uk_flow_overdue_reminder` (`tenant_id`, `reminder_key`, `channel`),
-    KEY `idx_flow_overdue_task` (`tenant_id`, `task_id`, `send_time`),
-    KEY `idx_flow_overdue_status` (`tenant_id`, `send_status`, `create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流程任务逾期提醒记录';
-
-SET @node_config_table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_enabled'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_enabled tinyint NOT NULL DEFAULT 0 COMMENT ''是否启用逾期提醒''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_template_code'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_template_code varchar(50) DEFAULT NULL COMMENT ''逾期提醒消息模板编码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_channels'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_channels varchar(200) DEFAULT NULL COMMENT ''逾期提醒推送渠道,逗号分隔''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_repeat_mode'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_repeat_mode varchar(32) NOT NULL DEFAULT ''once'' COMMENT ''逾期提醒重复策略:once/interval''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_interval_minutes'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_interval_minutes int NOT NULL DEFAULT 1440 COMMENT ''重复提醒间隔分钟''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_flow_node_config'
-    AND column_name = 'overdue_reminder_max_times'
-);
-SET @ddl := IF(@node_config_table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_flow_node_config ADD COLUMN overdue_reminder_max_times int NOT NULL DEFAULT 1 COMMENT ''最大提醒次数''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT 1, '流程逾期提醒重复策略', 'sys_flow_overdue_repeat_mode', 1, '审批任务逾期提醒重复发送策略', 1, NOW(), 1, NOW(), 1
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type
-  WHERE tenant_id = 1
-    AND dict_type = 'sys_flow_overdue_repeat_mode'
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default,
-                           dict_status, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, 'sys_flow_overdue_repeat_mode',
-       NULL, seed.list_class, seed.is_default, 1, seed.remark, 1, NOW(), 1, NOW(), 1
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '仅一次' dict_label, 'once' dict_value, 'info' list_class, 'Y' is_default, '逾期后仅提醒一次' remark
-  UNION ALL SELECT 1, 2, '按间隔重复', 'interval', 'warning', 'N', '逾期后按配置间隔重复提醒'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = 'sys_flow_overdue_repeat_mode'
-    AND d.dict_value = seed.dict_value
-);
-
-INSERT INTO sys_message_template (tenant_id, template_code, template_name, type, title_template,
-                                  content_template, default_channel, enabled, remark,
-                                  create_by, create_time, update_by, update_time)
-SELECT 1, 'FLOW_TASK_OVERDUE', '流程任务逾期提醒', 'SYSTEM',
-       CONCAT('流程任务逾期:', '$', '{taskName}'),
-       CONCAT('流程「', '$', '{processName}', '」的任务「', '$', '{taskName}',
-              '」已逾期,截止时间:', '$', '{dueDate}', ',逾期 ', '$', '{overdueMinutes}',
-              ' 分钟。请及时处理:', '$', '{jumpUrl}'),
-       'WEB', 1, '审批任务逾期后提醒当前审批人', 1, NOW(), 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_message_template
-  WHERE tenant_id = 1
-    AND template_code = 'FLOW_TASK_OVERDUE'
-);
-
-INSERT INTO sys_message_biz_type (tenant_id, biz_type, biz_name, jump_url, jump_target, icon,
-                                  sort, enabled, remark, create_by, create_time, update_by, update_time)
-SELECT 1, 'FLOW_TASK_OVERDUE', '流程任务逾期提醒', CONCAT('/flow/todo?taskId=', '$', '{taskId}'), '_self',
-       'ionicons5:AlarmOutline', 30, 1, '流程审批任务逾期提醒消息', 1, NOW(), 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_message_biz_type
-  WHERE tenant_id = 1
-    AND biz_type = 'FLOW_TASK_OVERDUE'
-);

+ 0 - 530
forge-server/db/backup/V1.0.75__add_lowcode_runtime_datasource_fields.sql

@@ -1,531 +0,0 @@
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-    AND column_name = 'usage_scope'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE gen_datasource ADD COLUMN usage_scope varchar(32) NOT NULL DEFAULT ''BOTH'' COMMENT ''数据源用途范围:LOWCODE_RUNTIME/TENANT_BUSINESS/DEVELOPER_IMPORT/BOTH''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-    AND column_name = 'allow_runtime_write'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE gen_datasource ADD COLUMN allow_runtime_write tinyint NOT NULL DEFAULT 1 COMMENT ''是否允许低代码运行时写入''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-    AND column_name = 'allow_runtime_ddl'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE gen_datasource ADD COLUMN allow_runtime_ddl tinyint NOT NULL DEFAULT 0 COMMENT ''是否允许低代码执行运行时DDL''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-    AND column_name = 'readonly'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE gen_datasource ADD COLUMN readonly tinyint NOT NULL DEFAULT 0 COMMENT ''是否只读''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'gen_datasource'
-    AND column_name = 'risk_level'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE gen_datasource ADD COLUMN risk_level varchar(16) NOT NULL DEFAULT ''MEDIUM'' COMMENT ''风险等级:LOW/MEDIUM/HIGH''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-    AND column_name = 'runtime_datasource_id'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_lowcode_model ADD COLUMN runtime_datasource_id bigint DEFAULT NULL COMMENT ''模型运行数据源ID''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-    AND column_name = 'runtime_datasource_code'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_lowcode_model ADD COLUMN runtime_datasource_code varchar(64) DEFAULT NULL COMMENT ''模型运行数据源编码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-    AND column_name = 'runtime_table_name'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_lowcode_model ADD COLUMN runtime_table_name varchar(128) DEFAULT NULL COMMENT ''模型运行表名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-    AND column_name = 'table_mode'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_lowcode_model ADD COLUMN table_mode varchar(16) DEFAULT NULL COMMENT ''表模式:CREATE/EXISTING''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.statistics
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_lowcode_model'
-    AND index_name = 'idx_lowcode_model_runtime_ds'
-);
-SET @ddl := IF(@table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_lowcode_model ADD INDEX idx_lowcode_model_runtime_ds (tenant_id, runtime_datasource_id, status)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'runtime_datasource_id'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN runtime_datasource_id bigint DEFAULT NULL COMMENT ''运行数据源ID''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'runtime_datasource_code'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN runtime_datasource_code varchar(64) DEFAULT NULL COMMENT ''运行数据源编码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'runtime_datasource_snapshot'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN runtime_datasource_snapshot json DEFAULT NULL COMMENT ''运行数据源快照,不含密码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'runtime_table_name'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN runtime_table_name varchar(128) DEFAULT NULL COMMENT ''运行表名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'primary_key_field'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN primary_key_field varchar(64) NOT NULL DEFAULT ''id'' COMMENT ''主键字段名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'primary_key_column'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN primary_key_column varchar(64) NOT NULL DEFAULT ''id'' COMMENT ''主键列名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'primary_key_type'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN primary_key_type varchar(32) NOT NULL DEFAULT ''bigint'' COMMENT ''主键类型''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'tenant_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN tenant_strategy json DEFAULT NULL COMMENT ''租户隔离策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'audit_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN audit_strategy json DEFAULT NULL COMMENT ''审计字段策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND column_name = 'logic_delete_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config ADD COLUMN logic_delete_strategy json DEFAULT NULL COMMENT ''逻辑删除策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.statistics
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND index_name = 'idx_ai_crud_runtime_ds'
-);
-SET @ddl := IF(@table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_crud_config ADD INDEX idx_ai_crud_runtime_ds (tenant_id, runtime_datasource_id, publish_status)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'runtime_datasource_id'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN runtime_datasource_id bigint DEFAULT NULL COMMENT ''运行数据源ID''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'runtime_datasource_code'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN runtime_datasource_code varchar(64) DEFAULT NULL COMMENT ''运行数据源编码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'runtime_datasource_snapshot'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN runtime_datasource_snapshot json DEFAULT NULL COMMENT ''运行数据源快照,不含密码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'runtime_table_name'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN runtime_table_name varchar(128) DEFAULT NULL COMMENT ''运行表名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'primary_key_field'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN primary_key_field varchar(64) NOT NULL DEFAULT ''id'' COMMENT ''主键字段名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'primary_key_column'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN primary_key_column varchar(64) NOT NULL DEFAULT ''id'' COMMENT ''主键列名''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'primary_key_type'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN primary_key_type varchar(32) NOT NULL DEFAULT ''bigint'' COMMENT ''主键类型''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'tenant_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN tenant_strategy json DEFAULT NULL COMMENT ''租户隔离策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'audit_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN audit_strategy json DEFAULT NULL COMMENT ''审计字段策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config_version'
-    AND column_name = 'logic_delete_strategy'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_crud_config_version ADD COLUMN logic_delete_strategy json DEFAULT NULL COMMENT ''逻辑删除策略''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_tenant'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_tenant'
-    AND column_name = 'default_business_datasource_id'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_tenant ADD COLUMN default_business_datasource_id bigint DEFAULT NULL COMMENT ''默认业务数据源ID''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'sys_tenant'
-    AND column_name = 'default_business_datasource_code'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE sys_tenant ADD COLUMN default_business_datasource_code varchar(64) DEFAULT NULL COMMENT ''默认业务数据源编码''',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 17
forge-server/db/backup/V1.0.76__add_business_datasource_routing_config.sql

@@ -1,17 +0,0 @@
-INSERT INTO sys_config (tenant_id, config_name, config_key, config_value, config_type, config_desc, sort,
-                        create_by, create_time, update_by, update_time, create_dept)
-SELECT 1,
-       '业务租户数据源路由开关',
-       'business.datasource.tenant-routing-enabled',
-       'false',
-       'Y',
-       '控制 forge-business 是否按当前租户默认业务数据源切换 MyBatis-Plus ORM 数据源',
-       40,
-       1,
-       NOW(),
-       1,
-       NOW(),
-       1
-WHERE NOT EXISTS (
-    SELECT 1 FROM sys_config WHERE tenant_id = 1 AND config_key = 'business.datasource.tenant-routing-enabled'
-);

+ 0 - 175
forge-server/db/backup/V1.0.77__add_business_datasource_debug_menu.sql

@@ -1,176 +0,0 @@
-
-SET @app_center_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_datasource_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/generator/datasource'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @developer_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @debug_parent_id := COALESCE(@app_center_root_id, @developer_root_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '业务数据源调试', @debug_parent_id, 2, 6, '/business/datasource-debug', 'business/datasource-debug', 0,
-       0, NULL, '_self', 0, 1, 1, 'business:datasourceDebug:view', 'ionicons5:GitCompareOutline',
-       NULL, NULL, 0, 0, NULL, '租户业务数据源路由调试页面', 1, NOW(),
-       1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/business/datasource-debug'
-);
-
-UPDATE sys_resource
-SET parent_id = @debug_parent_id,
-    resource_name = '业务数据源调试',
-    component = 'business/datasource-debug',
-    perms = 'business:datasourceDebug:view',
-    icon = 'ionicons5:GitCompareOutline',
-    sort = 6,
-    visible = 1,
-    menu_status = 1,
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND client_code = 'pc'
-  AND resource_type = 2
-  AND path = '/business/datasource-debug';
-
-SET @debug_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/business/datasource-debug'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @debug_menu_id, 4, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 0, seed.perms, NULL,
-       seed.api_method, seed.api_url, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '业务数据源调试-当前路由' resource_name, 1 sort,
-         'business:datasourceDebug:current' perms, 'GET' api_method,
-         '/business/datasource-demo/current' api_url, '查询当前租户业务数据源路由' remark
-  UNION ALL
-  SELECT 1, '业务数据源调试-写入记录', 2,
-         'business:datasourceDebug:prepare', 'POST',
-         '/business/datasource-demo/prepare', '写入业务数据源调试记录'
-  UNION ALL
-  SELECT 1, '业务数据源调试-记录列表', 3,
-         'business:datasourceDebug:list', 'GET',
-         '/business/datasource-demo/list', '查询业务数据源调试记录'
-) seed
-WHERE @debug_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.client_code = 'pc'
-      AND r.resource_type = 4
-      AND r.api_method = seed.api_method
-      AND r.api_url = seed.api_url
-  );
-
-SET @admin_role_id := (
-  SELECT id
-  FROM sys_role
-  WHERE tenant_id = 1
-    AND role_key = 'admin'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT 1, @admin_role_id, target.id, NOW()
-FROM sys_resource target
-WHERE @admin_role_id IS NOT NULL
-  AND target.tenant_id = 1
-  AND target.client_code = 'pc'
-  AND (
-    target.path = '/business/datasource-debug'
-    OR target.api_url IN (
-      '/business/datasource-demo/current',
-      '/business/datasource-demo/prepare',
-      '/business/datasource-demo/list'
-    )
-  )
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = 1
-      AND exists_rr.role_id = @admin_role_id
-      AND exists_rr.resource_id = target.id
-  );
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT DISTINCT source.tenant_id, source.role_id, target.id, NOW()
-FROM (
-  SELECT DISTINCT rr.tenant_id, rr.role_id
-  FROM sys_role_resource rr
-  INNER JOIN sys_resource owned ON owned.id = rr.resource_id
-  WHERE owned.tenant_id = 1
-    AND owned.client_code = 'pc'
-    AND (
-      owned.id = @app_datasource_id
-      OR owned.path = '/generator/datasource'
-      OR owned.perms IN ('ai:datasource:list', 'gen:datasource:list')
-    )
-) source
-INNER JOIN sys_resource target ON target.tenant_id = 1
-WHERE target.client_code = 'pc'
-  AND (
-    target.path = '/business/datasource-debug'
-    OR target.api_url IN (
-      '/business/datasource-demo/current',
-      '/business/datasource-demo/prepare',
-      '/business/datasource-demo/list'
-    )
-  )
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = source.tenant_id
-      AND exists_rr.role_id = source.role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 15
forge-server/db/backup/V1.0.78__add_lowcode_app_page_summary_index.sql

@@ -1,16 +0,0 @@
-
-SET @index_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.statistics
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_crud_config'
-    AND index_name = 'idx_ai_crud_lowcode_page'
-);
-SET @ddl := IF(@index_exists = 0,
-  'ALTER TABLE ai_crud_config ADD INDEX idx_ai_crud_lowcode_page (tenant_id, mode, build_mode, update_time, id)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 65
forge-server/db/backup/V1.0.79__optimize_lowcode_runtime_document_queries.sql

@@ -1,66 +0,0 @@
-
-SET @table_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.TABLES
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'ai_crud_config'
-);
-
-SET @index_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.STATISTICS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'ai_crud_config'
-    AND INDEX_NAME = 'idx_ai_crud_runtime_object_lookup'
-);
-
-SET @sql = IF(
-  @table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_crud_config ADD INDEX idx_ai_crud_runtime_object_lookup (tenant_id, object_code, mode, build_mode, publish_status, publish_time)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.STATISTICS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'ai_crud_config'
-    AND INDEX_NAME = 'idx_ai_crud_runtime_config_lookup'
-);
-
-SET @sql = IF(
-  @table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_crud_config ADD INDEX idx_ai_crud_runtime_config_lookup (tenant_id, config_key, mode, build_mode, publish_status)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @table_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.TABLES
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'ai_business_flow_instance_link'
-);
-
-SET @index_exists = (
-  SELECT COUNT(*)
-  FROM information_schema.STATISTICS
-  WHERE TABLE_SCHEMA = DATABASE()
-    AND TABLE_NAME = 'ai_business_flow_instance_link'
-    AND INDEX_NAME = 'idx_ai_business_flow_business_latest'
-);
-
-SET @sql = IF(
-  @table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_business_flow_instance_link ADD INDEX idx_ai_business_flow_business_latest (tenant_id, business_key, start_time, create_time, id)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @sql;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 341
forge-server/db/backup/V1.0.7__add_lowcode_business_domain.sql


+ 0 - 37
forge-server/db/backup/V1.0.80__add_business_suite_hierarchy.sql

@@ -1,38 +0,0 @@
-
-SET @table_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.tables
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_suite'
-);
-
-SET @column_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.columns
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_suite'
-    AND column_name = 'parent_id'
-);
-SET @ddl := IF(@table_exists > 0 AND @column_exists = 0,
-  'ALTER TABLE ai_business_suite ADD COLUMN parent_id bigint DEFAULT NULL COMMENT ''上级业务域ID'' AFTER tenant_id',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;
-
-SET @index_exists := (
-  SELECT COUNT(1)
-  FROM information_schema.statistics
-  WHERE table_schema = DATABASE()
-    AND table_name = 'ai_business_suite'
-    AND index_name = 'idx_ai_business_suite_parent'
-);
-SET @ddl := IF(@table_exists > 0 AND @index_exists = 0,
-  'ALTER TABLE ai_business_suite ADD INDEX idx_ai_business_suite_parent (tenant_id, parent_id, sort_order, id)',
-  'SELECT 1'
-);
-PREPARE stmt FROM @ddl;
-EXECUTE stmt;
-DEALLOCATE PREPARE stmt;

+ 0 - 211
forge-server/db/backup/V1.0.81__add_sample_purchase_order_flow_test.sql

@@ -1,212 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `sample_purchase_order` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `order_no` varchar(64) NOT NULL COMMENT '采购单号',
-  `title` varchar(128) NOT NULL COMMENT '采购主题',
-  `supplier_name` varchar(128) NOT NULL COMMENT '供应商',
-  `amount_cent` bigint NOT NULL DEFAULT 0 COMMENT '采购金额,单位分',
-  `purchase_items` text DEFAULT NULL COMMENT '采购明细',
-  `need_date` date DEFAULT NULL COMMENT '需求日期',
-  `status` varchar(32) NOT NULL DEFAULT 'DRAFT' COMMENT '业务状态',
-  `applicant_id` bigint DEFAULT NULL COMMENT '申请人ID',
-  `applicant_name` varchar(64) DEFAULT NULL COMMENT '申请人名称',
-  `applicant_dept_id` bigint DEFAULT NULL COMMENT '申请部门ID',
-  `applicant_dept_name` varchar(128) DEFAULT NULL COMMENT '申请部门名称',
-  `business_key` varchar(128) DEFAULT NULL COMMENT '流程业务Key',
-  `process_instance_id` varchar(128) DEFAULT NULL COMMENT '流程实例ID',
-  `dept_leader_id` bigint DEFAULT NULL COMMENT '部门负责人ID',
-  `engineering_manager_id` bigint DEFAULT NULL COMMENT '工程部经理ID',
-  `countersign_user_ids` varchar(500) DEFAULT NULL COMMENT '会签用户ID,逗号分隔',
-  `cc_role_keys` varchar(500) DEFAULT NULL COMMENT '流程完成抄送角色编码,逗号分隔',
-  `arrival_list_file_ids` varchar(1000) DEFAULT NULL COMMENT '负责人节点上传清单文件ID',
-  `applicant_modify_remark` varchar(500) DEFAULT NULL COMMENT '申请人修改说明',
-  `dept_leader_remark` varchar(500) DEFAULT NULL COMMENT '部门负责人意见',
-  `engineering_manager_remark` varchar(500) DEFAULT NULL COMMENT '工程部经理意见',
-  `countersign_remark` varchar(500) DEFAULT NULL COMMENT '会签意见',
-  `reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建者',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新者',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_sample_purchase_order_no` (`tenant_id`, `order_no`),
-  UNIQUE KEY `uk_sample_purchase_order_business_key` (`tenant_id`, `business_key`),
-  KEY `idx_sample_purchase_order_status` (`tenant_id`, `status`, `update_time`),
-  KEY `idx_sample_purchase_order_process` (`tenant_id`, `process_instance_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购单审批测试表';
-
-INSERT INTO sys_dict_type (tenant_id, dict_name, dict_type, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_name, seed.dict_type, seed.dict_status, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, '采购单审批测试状态' dict_name, 'sample_purchase_order_status' dict_type, 1 dict_status, '采购单审批测试业务状态' remark
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_type t
-  WHERE t.tenant_id = seed.tenant_id
-    AND t.dict_type = seed.dict_type
-);
-
-INSERT INTO sys_dict_data (tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, dict_status, remark, create_time, update_time)
-SELECT seed.tenant_id, seed.dict_sort, seed.dict_label, seed.dict_value, seed.dict_type, NULL, seed.list_class, seed.is_default, 1, seed.remark, NOW(), NOW()
-FROM (
-  SELECT 1 tenant_id, 1 dict_sort, '草稿' dict_label, 'DRAFT' dict_value, 'sample_purchase_order_status' dict_type, 'default' list_class, 'Y' is_default, '草稿' remark
-  UNION ALL SELECT 1, 2, '审批中', 'IN_PROCESS', 'sample_purchase_order_status', 'info', 'N', '审批中'
-  UNION ALL SELECT 1, 3, '待修改', 'NEED_MODIFY', 'sample_purchase_order_status', 'warning', 'N', '被驳回后等待申请人修改'
-  UNION ALL SELECT 1, 4, '已通过', 'APPROVED', 'sample_purchase_order_status', 'success', 'N', '审批通过'
-  UNION ALL SELECT 1, 5, '已拒绝', 'REJECTED', 'sample_purchase_order_status', 'error', 'N', '流程拒绝结束'
-  UNION ALL SELECT 1, 6, '已取消', 'CANCELED', 'sample_purchase_order_status', 'default', 'N', '流程取消'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_dict_data d
-  WHERE d.tenant_id = seed.tenant_id
-    AND d.dict_type = seed.dict_type
-    AND d.dict_value = seed.dict_value
-);
-
-INSERT INTO sys_role (tenant_id, role_name, role_key, role_type, data_scope, sort, role_status, is_system, remark, create_by, create_time, update_by, update_time, create_dept)
-SELECT 1, '总经理', 'general_manager', 3, 1, 90, 1, 0, '采购单审批测试抄送角色,可按需绑定用户', 1, NOW(), 1, NOW(), 1
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_role
-  WHERE tenant_id = 1
-    AND role_key = 'general_manager'
-);
-
-SET @app_center_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @developer_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND parent_id = 0
-    AND resource_name = '开发者工具'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @business_parent_id := COALESCE(@app_center_root_id, @developer_root_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '业务测试', @business_parent_id, 1, 30, '/business', NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'business:test', 'ionicons5:BriefcaseOutline',
-       NULL, NULL, 0, 1, NULL, '业务测试目录', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND path = '/business'
-);
-
-SET @business_test_dir_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND path = '/business'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '采购单审批测试', @business_test_dir_id, 2, 10, '/business/purchase-order-test', 'business/purchase-order-test', 0,
-       0, NULL, '_self', 0, 1, 1, 'business:purchaseOrderTest:list', 'ionicons5:CartOutline',
-       NULL, NULL, 0, 0, NULL, '采购单审批流程联动测试页面', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE @business_test_dir_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource
-    WHERE tenant_id = 1
-      AND client_code = 'pc'
-      AND resource_type = 2
-      AND path = '/business/purchase-order-test'
-  );
-
-SET @purchase_test_menu_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/business/purchase-order-test'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT seed.tenant_id, seed.resource_name, @purchase_test_menu_id, 3, seed.sort, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, seed.perms, NULL,
-       NULL, NULL, 0, 0, NULL, seed.remark, 1, NOW(), 1, NOW(), 1, 'pc'
-FROM (
-  SELECT 1 tenant_id, '采购单查询' resource_name, 1 sort, 'business:purchaseOrderTest:query' perms, '采购单查询按钮权限' remark
-  UNION ALL SELECT 1, '采购单新增', 2, 'business:purchaseOrderTest:add', '采购单新增按钮权限'
-  UNION ALL SELECT 1, '采购单修改', 3, 'business:purchaseOrderTest:edit', '采购单修改按钮权限'
-  UNION ALL SELECT 1, '采购单删除', 4, 'business:purchaseOrderTest:remove', '采购单删除按钮权限'
-  UNION ALL SELECT 1, '采购单提交审批', 5, 'business:purchaseOrderTest:submit', '采购单提交审批按钮权限'
-  UNION ALL SELECT 1, '采购单初始化流程', 6, 'business:purchaseOrderTest:initFlow', '采购单测试流程初始化按钮权限'
-) seed
-WHERE @purchase_test_menu_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_resource r
-    WHERE r.tenant_id = seed.tenant_id
-      AND r.client_code = 'pc'
-      AND r.resource_type = 3
-      AND r.perms = seed.perms
-  );
-
-SET @admin_role_id := (
-  SELECT id
-  FROM sys_role
-  WHERE tenant_id = 1
-    AND role_key = 'admin'
-  ORDER BY id
-  LIMIT 1
-);
-
-INSERT INTO sys_role_resource (tenant_id, role_id, resource_id, create_time)
-SELECT 1, @admin_role_id, target.id, NOW()
-FROM sys_resource target
-WHERE @admin_role_id IS NOT NULL
-  AND target.tenant_id = 1
-  AND target.client_code = 'pc'
-  AND (
-    target.path IN ('/business', '/business/purchase-order-test')
-    OR target.perms LIKE 'business:purchaseOrderTest:%'
-  )
-  AND NOT EXISTS (
-    SELECT 1
-    FROM sys_role_resource exists_rr
-    WHERE exists_rr.tenant_id = 1
-      AND exists_rr.role_id = @admin_role_id
-      AND exists_rr.resource_id = target.id
-  );

+ 0 - 100
forge-server/db/backup/V1.0.82__seed_sample_purchase_order_flow_binding.sql

@@ -1,102 +0,0 @@
-
-INSERT INTO ai_business_binding (id, tenant_id, target_type, target_id, target_code, binding_type, binding_key,
-                                 binding_name, binding_config, description, status, sort_order, create_by,
-                                 create_time, create_dept, update_by, update_time)
-SELECT 1910000000000008201, 1, 'OBJECT', NULL, 'sample_purchase_order', 'FLOW', 'sample_purchase_order_approval',
-       '采购单审批测试流程',
-       '{
-         "flowModelKey":"sample_purchase_order_approval",
-         "flowModelName":"采购单审批测试流程",
-         "titleTemplate":"采购单审批-{orderNo}",
-         "startMode":"MANUAL",
-         "businessBinding":{
-           "mode":"ADAPTER",
-           "primaryKeyField":"id",
-           "tenantField":"tenant_id",
-           "titleField":"title",
-           "statusField":"status",
-           "ownerField":"applicantId"
-         },
-         "variableMapping":[
-           {"formField":"businessKey","flowVariable":"businessKey","label":"业务Key"},
-           {"formField":"orderNo","flowVariable":"orderNo","label":"采购单号"},
-           {"formField":"title","flowVariable":"title","label":"采购主题"},
-           {"formField":"amountCent","flowVariable":"amountCent","label":"采购金额分"},
-           {"formField":"deptLeaderId","flowVariable":"deptLeaderId","label":"部门负责人"},
-           {"formField":"engineeringManagerId","flowVariable":"engineeringManagerId","label":"工程部经理"},
-           {"formField":"countersignUserIds","flowVariable":"countersignUserList","label":"会签人员"}
-         ],
-         "nodeForms":[
-           {
-             "taskDefKey":"dept_leader_approve",
-             "taskName":"部门负责人审批",
-             "formMode":"BUSINESS_CODE_FORM",
-             "formKey":"sample_purchase_order_approval_form",
-             "formName":"采购单审批表单",
-             "providerKey":"samplePurchaseOrder",
-             "editMode":"EDITABLE",
-             "formRef":{"type":"BUSINESS_CODE_FORM","objectCode":"sample_purchase_order","providerKey":"samplePurchaseOrder","formKey":"sample_purchase_order_approval_form"},
-             "fieldPermissions":[
-               {"field":"arrivalListFileIds","label":"上传清单","readable":true,"writable":true,"required":false},
-               {"field":"deptLeaderRemark","label":"部门负责人意见","readable":true,"writable":true,"required":false}
-             ]
-           },
-           {
-             "taskDefKey":"engineering_manager_approve",
-             "taskName":"工程部经理审批",
-             "formMode":"BUSINESS_CODE_FORM",
-             "formKey":"sample_purchase_order_approval_form",
-             "formName":"采购单审批表单",
-             "providerKey":"samplePurchaseOrder",
-             "editMode":"EDITABLE",
-             "formRef":{"type":"BUSINESS_CODE_FORM","objectCode":"sample_purchase_order","providerKey":"samplePurchaseOrder","formKey":"sample_purchase_order_approval_form"},
-             "fieldPermissions":[
-               {"field":"engineeringManagerRemark","label":"工程部经理意见","readable":true,"writable":true,"required":false}
-             ]
-           },
-           {
-             "taskDefKey":"purchase_countersign",
-             "taskName":"采购会签",
-             "formMode":"BUSINESS_CODE_FORM",
-             "formKey":"sample_purchase_order_approval_form",
-             "formName":"采购单审批表单",
-             "providerKey":"samplePurchaseOrder",
-             "editMode":"EDITABLE",
-             "formRef":{"type":"BUSINESS_CODE_FORM","objectCode":"sample_purchase_order","providerKey":"samplePurchaseOrder","formKey":"sample_purchase_order_approval_form"},
-             "fieldPermissions":[
-               {"field":"countersignRemark","label":"会签意见","readable":true,"writable":true,"required":false}
-             ]
-           },
-           {
-             "taskDefKey":"applicant_modify",
-             "taskName":"申请人修改",
-             "formMode":"BUSINESS_CODE_FORM",
-             "formKey":"sample_purchase_order_approval_form",
-             "formName":"采购单审批表单",
-             "providerKey":"samplePurchaseOrder",
-             "editMode":"MODIFY_RESUBMIT",
-             "formRef":{"type":"BUSINESS_CODE_FORM","objectCode":"sample_purchase_order","providerKey":"samplePurchaseOrder","formKey":"sample_purchase_order_approval_form"},
-             "fieldPermissions":[
-               {"field":"title","label":"采购主题","readable":true,"writable":true,"required":true},
-               {"field":"supplierName","label":"供应商","readable":true,"writable":true,"required":true},
-               {"field":"amountCent","label":"采购金额分","readable":true,"writable":true,"required":true},
-               {"field":"purchaseItems","label":"采购明细","readable":true,"writable":true,"required":false},
-               {"field":"applicantModifyRemark","label":"申请人修改说明","readable":true,"writable":true,"required":false}
-             ]
-           }
-         ],
-         "conditionFlows":[],
-         "options":{"sample":true,"codeApp":true,"businessKeyPattern":"sample_purchase_order:{recordId}"}
-       }',
-       '采购单代码业务默认流程绑定,节点表单和字段权限由业务流程配置维护', 1, 1, 1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_binding
-  WHERE tenant_id = 1
-    AND target_type = 'OBJECT'
-    AND target_code = 'sample_purchase_order'
-    AND binding_type = 'FLOW'
-    AND binding_key = 'sample_purchase_order_approval'
-);

+ 0 - 79
forge-server/db/backup/V1.0.83__seed_sample_purchase_order_app_center_entry.sql

@@ -1,82 +0,0 @@
-
-INSERT INTO ai_business_suite (id, tenant_id, parent_id, suite_code, suite_name, icon, description, status,
-                               sort_order, options, create_by, create_time, create_dept, update_by, update_time)
-SELECT 1910000000000008301, 1, NULL, 'PURCHASE', '采购', 'ionicons5:CartOutline',
-       '采购申请、采购审批和供应商协同测试业务域', 1, 40,
-       '{"sample":true,"codeApp":true,"scenario":"sample_purchase_order_flow"}',
-       1, NOW(), 1, 1, NOW()
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_business_suite
-  WHERE tenant_id = 1
-    AND suite_code = 'PURCHASE'
-);
-
-SET @purchase_suite_id := (
-  SELECT id
-  FROM ai_business_suite
-  WHERE tenant_id = 1
-    AND suite_code = 'PURCHASE'
-  LIMIT 1
-);
-
-INSERT INTO ai_business_object (id, tenant_id, suite_code, object_code, object_name, object_type, model_id,
-                                model_code, display_field, icon, description, status, sort_order, options,
-                                design_status, config_key, last_publish_time, last_publish_version,
-                                designer_options, create_by, create_time, create_dept, update_by, update_time)
-SELECT 1910000000000008302, 1, 'PURCHASE', 'sample_purchase_order', '采购申请', 'TRANSACTION', NULL,
-       NULL, 'title', 'ionicons5:CartOutline',
-       '代码实现的采购单审批测试业务,业务流程配置维护节点表单和字段权限', 1, 10,
-       '{"sample":true,"codeApp":true,"businessType":"sample_purchase_order","flowModelKey":"sample_purchase_order_approval"}',
-       'PUBLISHED', NULL, NOW(), 1,
-       '{"codeApp":true,"documentManaged":false,"defaultPanel":"flow-app"}',
-       1, NOW(), 1, 1, NOW()
-WHERE @purchase_suite_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM ai_business_object
-    WHERE tenant_id = 1
-      AND suite_code = 'PURCHASE'
-      AND object_code = 'sample_purchase_order'
-  );
-
-SET @sample_purchase_order_object_id := (
-  SELECT id
-  FROM ai_business_object
-  WHERE tenant_id = 1
-    AND suite_code = 'PURCHASE'
-    AND object_code = 'sample_purchase_order'
-  LIMIT 1
-);
-
-UPDATE ai_business_binding
-SET target_id = @sample_purchase_order_object_id,
-    update_by = 1,
-    update_time = NOW()
-WHERE @sample_purchase_order_object_id IS NOT NULL
-  AND tenant_id = 1
-  AND target_type = 'OBJECT'
-  AND target_code = 'sample_purchase_order'
-  AND binding_type = 'FLOW'
-  AND binding_key = 'sample_purchase_order_approval'
-  AND target_id IS NULL;
-
-INSERT INTO ai_business_app (id, tenant_id, app_code, app_name, app_type, suite_code, object_code, entry_mode,
-                             entry_url, config_key, icon, description, status, sort_order, options, create_by,
-                             create_time, create_dept, update_by, update_time)
-SELECT 1910000000000008303, 1, 'PURCHASE_ORDER_APPROVAL_TEST', '采购单审批测试', 'BUSINESS',
-       'PURCHASE', 'sample_purchase_order', 'ROUTE',
-       '/business/purchase-order-test', NULL, 'ionicons5:ClipboardOutline',
-       '打开采购单审批测试页面,创建采购单并验证流程节点表单权限', 1, 10,
-       '{"sample":true,"codeApp":true,"flowConfigUrl":"/app-center/object-designer/sample_purchase_order?panel=flow-app&codeApp=1&name=采购申请"}',
-       1, NOW(), 1, 1, NOW()
-WHERE @sample_purchase_order_object_id IS NOT NULL
-  AND NOT EXISTS (
-    SELECT 1
-    FROM ai_business_app
-    WHERE tenant_id = 1
-      AND app_code = 'PURCHASE_ORDER_APPROVAL_TEST'
-  );

+ 0 - 19
forge-server/db/backup/V1.0.84__extend_sample_purchase_order_form_asset_fields.sql

@@ -1,20 +0,0 @@
-
-UPDATE ai_business_binding
-SET binding_config = REPLACE(
-    binding_config,
-    '{"field":"purchaseItems","label":"采购明细","readable":true,"writable":true,"required":false},
-               {"field":"applicantModifyRemark","label":"申请人修改说明","readable":true,"writable":true,"required":false}',
-    '{"field":"purchaseItems","label":"采购明细","readable":true,"writable":true,"required":false},
-               {"field":"needDate","label":"期望到货日期","readable":true,"writable":true,"required":false},
-               {"field":"applicantModifyRemark","label":"申请人修改说明","readable":true,"writable":true,"required":false}'
-  ),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND target_type = 'OBJECT'
-  AND target_code = 'sample_purchase_order'
-  AND binding_type = 'FLOW'
-  AND binding_key = 'sample_purchase_order_approval'
-  AND binding_config LIKE '%"taskDefKey":"applicant_modify"%'
-  AND binding_config NOT LIKE '%"field":"needDate"%';

+ 0 - 15
forge-server/db/backup/V1.0.85__fix_sample_purchase_order_designer_route.sql

@@ -1,16 +0,0 @@
-
-UPDATE ai_business_app
-SET options = JSON_SET(
-    COALESCE(options, JSON_OBJECT()),
-    '$.flowConfigUrl',
-    '/app-center/object/sample_purchase_order/designer?panel=flow-app&codeApp=1&name=采购申请'
-  ),
-    update_by = 1,
-    update_time = NOW()
-WHERE tenant_id = 1
-  AND app_code = 'PURCHASE_ORDER_APPROVAL_TEST'
-  AND (
-    JSON_UNQUOTE(JSON_EXTRACT(options, '$.flowConfigUrl')) IS NULL
-    OR JSON_UNQUOTE(JSON_EXTRACT(options, '$.flowConfigUrl')) <> '/app-center/object/sample_purchase_order/designer?panel=flow-app&codeApp=1&name=采购申请'
-  );

+ 0 - 112
forge-server/db/backup/V1.0.86__add_code_rule_generator.sql

@@ -1,113 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_code_rule` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `rule_code` varchar(64) NOT NULL COMMENT '规则编码',
-  `rule_name` varchar(128) NOT NULL COMMENT '规则名称',
-  `scene` varchar(64) NOT NULL DEFAULT 'COMMON' COMMENT '适用场景:COMMON通用/DOCUMENT单据/MATERIAL物料等',
-  `template` varchar(256) NOT NULL COMMENT '编码模板',
-  `reset_policy` varchar(32) NOT NULL DEFAULT 'AUTO' COMMENT '流水重置策略:AUTO/NONE/YEAR/MONTH/DAY/HOUR/MINUTE/SECOND',
-  `seq_length` int NOT NULL DEFAULT 4 COMMENT '默认流水号长度',
-  `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态:1启用 0停用',
-  `builtin` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否内置规则',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `options` json DEFAULT NULL COMMENT '扩展配置JSON',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_code_rule_code` (`tenant_id`, `rule_code`),
-  KEY `idx_ai_code_rule_scene` (`tenant_id`, `scene`, `status`),
-  KEY `idx_ai_code_rule_update` (`tenant_id`, `update_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-通用编码规则';
-
-INSERT INTO ai_code_rule (id, tenant_id, rule_code, rule_name, scene, template, reset_policy, seq_length,
-                          status, builtin, remark, options, create_by, create_time, create_dept, update_by, update_time)
-SELECT seed.id, 1, seed.rule_code, seed.rule_name, seed.scene, seed.template, seed.reset_policy, seed.seq_length,
-       1, 1, seed.remark, NULL, 1, NOW(), 1, 1, NOW()
-FROM (
-  SELECT 1910000000000008601 id, 'material_code' rule_code, '物料编码' rule_name, 'COMMON' scene,
-         CONCAT('WL', '$', '{yyyyMMddHHmmss}', '$', '{seq:3}') template, 'SECOND' reset_policy, 3 seq_length,
-         '适合物料编码:WL + 年月日时分秒 + 3位同秒流水' remark
-  UNION ALL
-  SELECT 1910000000000008602, 'document_daily_no', '通用单据日流水', 'COMMON',
-         CONCAT('DOC', '$', '{yyyyMMdd}', '$', '{seq:4}'), 'DAY', 4,
-         '适合普通业务单据:DOC + 年月日 + 4位日流水'
-  UNION ALL
-  SELECT 1910000000000008603, 'order_no', '订单编号', 'COMMON',
-         CONCAT('ORD', '$', '{yyyyMMdd}', '$', '{seq:5}'), 'DAY', 5,
-         '适合订单类单据:ORD + 年月日 + 5位日流水'
-  UNION ALL
-  SELECT 1910000000000008604, 'contract_no', '合同编号', 'COMMON',
-         CONCAT('HT', '$', '{yyyyMM}', '$', '{seq:5}'), 'MONTH', 5,
-         '适合合同类单据:HT + 年月 + 5位月流水'
-  UNION ALL
-  SELECT 1910000000000008605, 'customer_code', '客户编码', 'COMMON',
-         CONCAT('C', '$', '{seq:6}'), 'NONE', 6,
-         '适合主数据编码:C + 6位全局流水'
-  UNION ALL
-  SELECT 1910000000000008606, 'org_daily_no', '组织日流水', 'COMMON',
-         CONCAT('$', '{orgCode}', '$', '{yyyyMMdd}', '$', '{seq:4}'), 'DAY', 4,
-         '适合按组织隔离的日流水:组织编码 + 年月日 + 4位流水'
-) seed
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM ai_code_rule r
-  WHERE r.tenant_id = 1
-    AND r.rule_code = seed.rule_code
-);
-
-SET @app_root_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 1
-    AND resource_name = '应用中心'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @app_overview_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-    AND component = 'app-center/index'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @code_rule_parent_id := COALESCE(@app_root_id, @app_overview_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '编码规则', @code_rule_parent_id, 2, 8, '/app-center/code-rules', 'app-center/code-rules', 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessObject:code-rules', 'ionicons5:BarcodeOutline',
-       NULL, NULL, 0, 0, NULL, '通用编码规则维护页面', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.client_code = 'pc'
-    AND r.resource_type = 2
-    AND r.path = '/app-center/code-rules'
-);
-
-SET @code_rule_route_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center/code-rules'
-  ORDER BY id
-  LIMIT 1
-);

+ 0 - 71
forge-server/db/backup/V1.0.87__add_business_action_execution_log.sql

@@ -1,72 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_business_action_execution_log` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `suite_code` varchar(64) DEFAULT NULL COMMENT '业务套件编码',
-  `object_code` varchar(64) NOT NULL COMMENT '业务对象编码',
-  `record_id` varchar(128) NOT NULL DEFAULT '' COMMENT '业务记录ID',
-  `action_code` varchar(64) NOT NULL COMMENT '动作编码',
-  `action_name` varchar(128) DEFAULT NULL COMMENT '动作名称',
-  `execute_status` varchar(32) NOT NULL COMMENT '执行状态:RUNNING/SUCCESS/FAILED/TODO',
-  `request_digest` varchar(1024) DEFAULT NULL COMMENT '请求摘要',
-  `step_result` json DEFAULT NULL COMMENT '步骤执行结果JSON',
-  `result_message` varchar(500) DEFAULT NULL COMMENT '执行结果提示',
-  `error_message` varchar(2000) DEFAULT NULL COMMENT '错误信息',
-  `correlation_id` varchar(64) DEFAULT NULL COMMENT '链路ID',
-  `idempotency_key` varchar(128) DEFAULT NULL COMMENT '幂等键',
-  `duration_ms` bigint DEFAULT NULL COMMENT '执行耗时毫秒',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_action_idem` (`tenant_id`, `object_code`, `record_id`, `action_code`, `idempotency_key`),
-  KEY `idx_ai_business_action_record` (`tenant_id`, `object_code`, `record_id`, `create_time`),
-  KEY `idx_ai_business_action_code` (`tenant_id`, `object_code`, `action_code`, `execute_status`, `create_time`),
-  KEY `idx_ai_business_action_corr` (`tenant_id`, `correlation_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-通用动作执行日志';
-
-SET @app_center_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @business_action_parent_id := COALESCE(@app_center_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '执行业务动作', @business_action_parent_id, 3, 210, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessAction:execute', NULL,
-       NULL, NULL, 0, 0, NULL, '通用业务动作执行权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.client_code = 'pc'
-    AND r.perms = 'ai:businessAction:execute'
-);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '查看业务动作日志', @business_action_parent_id, 3, 211, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessAction:log', NULL,
-       NULL, NULL, 0, 0, NULL, '通用业务动作执行日志查看权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.client_code = 'pc'
-    AND r.perms = 'ai:businessAction:log'
-);

+ 0 - 109
forge-server/db/backup/V1.0.88__add_business_quantity_ledger.sql

@@ -1,110 +0,0 @@
-
-CREATE TABLE IF NOT EXISTS `ai_business_quantity_balance` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `account_code` varchar(128) NOT NULL COMMENT '数量账户编码',
-  `item_code` varchar(128) NOT NULL COMMENT '数量项编码',
-  `dimension_key` varchar(256) NOT NULL DEFAULT '' COMMENT '数量维度键',
-  `quantity` bigint NOT NULL DEFAULT 0 COMMENT '当前数量',
-  `locked_quantity` bigint NOT NULL DEFAULT 0 COMMENT '锁定数量',
-  `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1启用,0停用',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_qty_balance` (`tenant_id`, `account_code`, `item_code`, `dimension_key`),
-  KEY `idx_ai_business_qty_balance_item` (`tenant_id`, `item_code`, `dimension_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-通用数量余额';
-
-CREATE TABLE IF NOT EXISTS `ai_business_quantity_ledger` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `operation_type` varchar(32) NOT NULL COMMENT '操作类型:INBOUND/LOCK/RELEASE/COMMIT/TRANSFER',
-  `account_code` varchar(128) NOT NULL COMMENT '数量账户编码',
-  `item_code` varchar(128) NOT NULL COMMENT '数量项编码',
-  `dimension_key` varchar(256) NOT NULL DEFAULT '' COMMENT '数量维度键',
-  `quantity_delta` bigint NOT NULL DEFAULT 0 COMMENT '数量变动值',
-  `balance_quantity` bigint NOT NULL DEFAULT 0 COMMENT '操作后当前数量',
-  `locked_quantity` bigint NOT NULL DEFAULT 0 COMMENT '操作后锁定数量',
-  `target_account_code` varchar(128) DEFAULT NULL COMMENT '目标数量账户编码',
-  `target_item_code` varchar(128) DEFAULT NULL COMMENT '目标数量项编码',
-  `target_dimension_key` varchar(256) DEFAULT NULL COMMENT '目标数量维度键',
-  `source_object_code` varchar(64) DEFAULT NULL COMMENT '来源业务对象编码',
-  `source_record_id` varchar(128) DEFAULT NULL COMMENT '来源业务记录ID',
-  `source_detail_id` varchar(128) DEFAULT NULL COMMENT '来源明细ID',
-  `lock_id` bigint DEFAULT NULL COMMENT '关联锁定ID',
-  `correlation_id` varchar(64) DEFAULT NULL COMMENT '链路ID',
-  `idempotency_key` varchar(128) DEFAULT NULL COMMENT '幂等键',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `extra_data` json DEFAULT NULL COMMENT '扩展数据',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_qty_ledger_idem` (`tenant_id`, `idempotency_key`),
-  KEY `idx_ai_business_qty_ledger_item` (`tenant_id`, `account_code`, `item_code`, `dimension_key`, `create_time`),
-  KEY `idx_ai_business_qty_ledger_source` (`tenant_id`, `source_object_code`, `source_record_id`),
-  KEY `idx_ai_business_qty_ledger_corr` (`tenant_id`, `correlation_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-通用数量流水';
-
-CREATE TABLE IF NOT EXISTS `ai_business_quantity_lock` (
-  `id` bigint NOT NULL COMMENT '主键ID',
-  `tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
-  `lock_code` varchar(128) DEFAULT NULL COMMENT '锁定编码',
-  `account_code` varchar(128) NOT NULL COMMENT '数量账户编码',
-  `item_code` varchar(128) NOT NULL COMMENT '数量项编码',
-  `dimension_key` varchar(256) NOT NULL DEFAULT '' COMMENT '数量维度键',
-  `lock_quantity` bigint NOT NULL DEFAULT 0 COMMENT '锁定数量',
-  `released_quantity` bigint NOT NULL DEFAULT 0 COMMENT '已释放数量',
-  `committed_quantity` bigint NOT NULL DEFAULT 0 COMMENT '已扣减数量',
-  `lock_status` varchar(32) NOT NULL DEFAULT 'LOCKED' COMMENT '锁定状态:LOCKED/RELEASED/COMMITTED',
-  `source_object_code` varchar(64) DEFAULT NULL COMMENT '来源业务对象编码',
-  `source_record_id` varchar(128) DEFAULT NULL COMMENT '来源业务记录ID',
-  `source_detail_id` varchar(128) DEFAULT NULL COMMENT '来源明细ID',
-  `correlation_id` varchar(64) DEFAULT NULL COMMENT '链路ID',
-  `idempotency_key` varchar(128) DEFAULT NULL COMMENT '幂等键',
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
-  `create_by` bigint DEFAULT NULL COMMENT '创建人',
-  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `create_dept` bigint DEFAULT NULL COMMENT '创建部门',
-  `update_by` bigint DEFAULT NULL COMMENT '更新人',
-  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_ai_business_qty_lock_idem` (`tenant_id`, `idempotency_key`),
-  KEY `idx_ai_business_qty_lock_item` (`tenant_id`, `account_code`, `item_code`, `dimension_key`, `lock_status`),
-  KEY `idx_ai_business_qty_lock_source` (`tenant_id`, `source_object_code`, `source_record_id`, `source_detail_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI业务应用平台-通用数量锁定';
-
-SET @app_center_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @quantity_parent_id := COALESCE(@app_center_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '执行数量台账动作', @quantity_parent_id, 3, 212, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessQuantity:operate', NULL,
-       NULL, NULL, 0, 0, NULL, '通用数量台账动作权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.client_code = 'pc'
-    AND r.perms = 'ai:businessQuantity:operate'
-);

+ 0 - 28
forge-server/db/backup/V1.0.89__add_business_quantity_query_permission.sql

@@ -1,29 +0,0 @@
-
-SET @app_center_id := (
-  SELECT id
-  FROM sys_resource
-  WHERE tenant_id = 1
-    AND client_code = 'pc'
-    AND resource_type = 2
-    AND path = '/app-center'
-  ORDER BY id
-  LIMIT 1
-);
-
-SET @quantity_parent_id := COALESCE(@app_center_id, 0);
-
-INSERT INTO sys_resource (tenant_id, resource_name, parent_id, resource_type, sort, path, component, is_external,
-                          sso_enabled, sso_target_client, open_target, is_public, menu_status, visible, perms, icon,
-                          api_method, api_url, keep_alive, always_show, redirect, remark, create_by, create_time,
-                          update_by, update_time, create_dept, client_code)
-SELECT 1, '查看数量台账', @quantity_parent_id, 3, 213, NULL, NULL, 0,
-       0, NULL, '_self', 0, 1, 1, 'ai:businessQuantity:view', NULL,
-       NULL, NULL, 0, 0, NULL, '通用数量台账只读查询权限', 1, NOW(), 1, NOW(), 1, 'pc'
-WHERE NOT EXISTS (
-  SELECT 1
-  FROM sys_resource r
-  WHERE r.tenant_id = 1
-    AND r.client_code = 'pc'
-    AND r.perms = 'ai:businessQuantity:view'
-);

+ 0 - 0
forge-server/db/backup/V1.0.8__fix_lowcode_domain_workspace_route.sql


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio