feat(config): 按业务模块拆分 Mock 开关
用 VITE_MOCK_* 系列环境变量替换全局 VITE_USE_MOCK,各模块独立控制演示数据 启用,并新增 src/utils/mock-flags.ts 统一解析缺省值。文档库关闭演示库时 如实提示接口待接入,避免静默沿用本地数据或覆盖已保存内容。
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -11,7 +12,8 @@ import type {
|
||||
BackendPage,
|
||||
} from './types'
|
||||
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
// 审计日志当前只用于签署留痕,跟随签署工作台的开关;后续有独立页面时再拆出来。
|
||||
const useMockData = mockFlags.signing
|
||||
|
||||
function formatDateTime(value: string) {
|
||||
const date = new Date(value)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { unwrapApiResponse, unwrapNullableApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -30,8 +31,7 @@ import type {
|
||||
UpdateRolePermissionPolicyRequest,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示数据,避免联调环境因未注入变量而误入 Mock 分支。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.documentPermissions
|
||||
|
||||
export const isPermissionMockEnabled = useMockData
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -17,8 +18,7 @@ import type {
|
||||
TemplateVersionResponseDto,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示数据,避免联调环境因未注入变量而误入 Mock 分支。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.documents
|
||||
|
||||
export const isDocumentMockEnabled = useMockData
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { unwrapApiResponse, unwrapNullableApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -13,8 +14,7 @@ import type {
|
||||
UpdateDepartmentRequest,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示数据,避免联调环境因未注入变量而误入 Mock 分支。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.organization
|
||||
|
||||
function getRecords(data: BackendCollection<OrganizationResponseDto>) {
|
||||
return Array.isArray(data) ? data : (data.records ?? data.items ?? data.content ?? [])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { unwrapApiResponse, unwrapNullableApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -14,8 +15,7 @@ import type {
|
||||
UpdateApiPermissionRequest,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示权限目录。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.users
|
||||
|
||||
export const isApiPermissionMockEnabled = useMockData
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse } from '@/types/common'
|
||||
|
||||
@@ -13,7 +14,7 @@ import type {
|
||||
ReportTasksQueryDto,
|
||||
} from './types'
|
||||
|
||||
export const isReportsMockEnabled = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
export const isReportsMockEnabled = mockFlags.reports
|
||||
|
||||
function compactQuery(values: object) {
|
||||
return Object.fromEntries(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse } from '@/types/common'
|
||||
|
||||
@@ -14,8 +15,7 @@ import type {
|
||||
UpdateRoleRequest,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示数据,避免联调环境因未注入变量而误入 Mock 分支。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.users
|
||||
|
||||
const fallbackColors = ['#6b5bd2', '#0e6e8c', '#0f9d6c', '#d9821f', '#c65d5d']
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
import type { SystemSettingsResponse, UpdateSystemSettingsRequest } from './types'
|
||||
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
const useMockData = mockFlags.settings
|
||||
|
||||
const mockSettings: SystemSettingsResponse = {
|
||||
sections: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { unwrapApiResponse, unwrapNullableApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse, PageResult } from '@/types/common'
|
||||
|
||||
@@ -22,8 +23,7 @@ import type {
|
||||
UserRolesUpdateRequest,
|
||||
} from './types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示数据,避免联调环境因未注入变量而误入 Mock 分支。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
const useMockData = mockFlags.users
|
||||
|
||||
export const isUserMockEnabled = useMockData
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
import type {
|
||||
@@ -11,7 +12,7 @@ import type {
|
||||
SigningArtifact,
|
||||
} from './types'
|
||||
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
const useMockData = mockFlags.signing
|
||||
|
||||
type ArtifactCollection = SignArtifactResponseDto[] | ApiPageResponse<SignArtifactResponseDto>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getCampuses } from '@/api/management/organization'
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { request } from '@/utils/request'
|
||||
import type { ApiResponse } from '@/types/common'
|
||||
|
||||
@@ -18,7 +19,8 @@ import type {
|
||||
WorkbenchTodoTask,
|
||||
WorkbenchTrendPoint,
|
||||
} from './types'
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
|
||||
const useMockData = mockFlags.workbenchHome
|
||||
|
||||
interface MockCampusOverview {
|
||||
summary: WorkbenchOverviewResponse['summary']
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
|
||||
import { unwrapApiResponse } from '@/utils/api-response'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { readLocalSigningTemplates } from '@/utils/mock-document-library'
|
||||
import { MOCK_STORAGE_KEYS, readMockState, writeMockState } from '@/utils/mock-storage'
|
||||
import { request } from '@/utils/request'
|
||||
@@ -35,7 +36,7 @@ import type {
|
||||
VisitType,
|
||||
} from './types'
|
||||
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK !== 'false'
|
||||
const useMockData = mockFlags.signing
|
||||
|
||||
const mockPatients: PatientProfile[] = [
|
||||
{
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_APP_NAME: string
|
||||
readonly VITE_API_BASE_URL: string
|
||||
|
||||
/**
|
||||
* 各业务模块的 Mock 开关,取值只认 'true' / 'false',留空即使用模块缺省值。
|
||||
* 缺省值与各开关的含义见 src/utils/mock-flags.ts。
|
||||
*/
|
||||
readonly VITE_MOCK_WORKBENCH_HOME?: string
|
||||
readonly VITE_MOCK_SIGNING?: string
|
||||
readonly VITE_MOCK_DOCUMENTS?: string
|
||||
readonly VITE_MOCK_DOCUMENT_PERMISSIONS?: string
|
||||
readonly VITE_MOCK_REPORTS?: string
|
||||
readonly VITE_MOCK_USERS?: string
|
||||
readonly VITE_MOCK_ORGANIZATION?: string
|
||||
readonly VITE_MOCK_SETTINGS?: string
|
||||
}
|
||||
@@ -2,12 +2,12 @@ import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import { getCampuses } from '@/api/management/organization'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import type { CampusRecord } from '@/api/management/types'
|
||||
import type { WorkbenchCampus } from '@/api/workbench/types'
|
||||
|
||||
// 仅显式开启 VITE_USE_MOCK=true 时使用演示院区,避免真实接口联调时把 mock UUID
|
||||
// 作为 campusId 发给后端。
|
||||
const useMockData = import.meta.env.VITE_USE_MOCK === 'true'
|
||||
// 演示院区跟随组织数据开关:开着会把 mock 的 campusId 一并发给真实接口。
|
||||
const useMockData = mockFlags.organization
|
||||
|
||||
const mockCampusRecords: CampusRecord[] = [
|
||||
{ id: 'mock-campus-main', code: 'MAIN', name: '本部院区', status: 'ENABLED', sortNo: 1 },
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Mock 开关:按业务模块(对齐侧边栏菜单)独立控制。
|
||||
*
|
||||
* 背景:早期只有一个全局 VITE_USE_MOCK,一开全开、一关全关,而且各 API 文件的
|
||||
* 默认值约定还不一致(有的 `!== 'false'` 默认开,有的 `=== 'true'` 默认关)。
|
||||
* 文档库与签署工作台还依赖演示数据,其余模块已经接了真实接口,混在一起就只能整体
|
||||
* 切换,联调时很容易把真实接口的页面也带进 Mock 分支。
|
||||
*
|
||||
* 现在的约定:
|
||||
* - 每个模块读自己的环境变量,缺省值就是「这个模块默认要不要用演示数据」;
|
||||
* - 环境变量没配、或值不是 true / false 时一律用缺省值,联调环境不会被本地 .env 残留影响;
|
||||
* - 开关粒度对齐菜单,不按 API 文件拆。同一个菜单下的多个 API 模块共用一个开关,
|
||||
* 例如签署工作台同时覆盖签署任务与签署产物。
|
||||
*/
|
||||
|
||||
/** 环境变量未配置(或值不是 true / false)时按缺省值处理 */
|
||||
function resolveMockFlag(raw: string | undefined, fallback: boolean): boolean {
|
||||
if (raw === 'true') {
|
||||
return true
|
||||
}
|
||||
|
||||
if (raw === 'false') {
|
||||
return false
|
||||
}
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
export const mockFlags = {
|
||||
/** 首页:工作台概览、待办与趋势 */
|
||||
workbenchHome: resolveMockFlag(import.meta.env.VITE_MOCK_WORKBENCH_HOME, false),
|
||||
/** 签署工作台:签署任务、签署产物,以及仅用于签署留痕的审计日志 */
|
||||
signing: resolveMockFlag(import.meta.env.VITE_MOCK_SIGNING, true),
|
||||
/** 文档库管理:文书库与文书模板接口 */
|
||||
documents: resolveMockFlag(import.meta.env.VITE_MOCK_DOCUMENTS, true),
|
||||
/** 文档权限:模板权限配置与权限矩阵 */
|
||||
documentPermissions: resolveMockFlag(import.meta.env.VITE_MOCK_DOCUMENT_PERMISSIONS, false),
|
||||
/** 报表分析 */
|
||||
reports: resolveMockFlag(import.meta.env.VITE_MOCK_REPORTS, false),
|
||||
/** 用户与权限:用户、角色、接口权限目录 */
|
||||
users: resolveMockFlag(import.meta.env.VITE_MOCK_USERS, false),
|
||||
/**
|
||||
* 组织基础数据:院区与科室。
|
||||
* 不单独对应某个菜单,而是被首页、签署工作台、用户与权限和应用级院区选择器共用,
|
||||
* 所以独立成一个开关;开着会把演示院区的 UUID 一并发给真实接口。
|
||||
*/
|
||||
organization: resolveMockFlag(import.meta.env.VITE_MOCK_ORGANIZATION, false),
|
||||
/**
|
||||
* 系统设置。注意:系统设置页面目前直接用页面内的演示数据渲染,还没有消费
|
||||
* api/management/settings.ts,所以这个开关暂时只作用于该 API 模块。
|
||||
*/
|
||||
settings: resolveMockFlag(import.meta.env.VITE_MOCK_SETTINGS, false),
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { useRouter } from 'vue-router'
|
||||
import NewSigningTaskDialog from '@/components/signing/NewSigningTaskDialog.vue'
|
||||
import type { SigningTaskRecord, SigningTemplate } from '@/api/workbench/types'
|
||||
import type { CampusRecord, DepartmentRecord } from '@/api/management/types'
|
||||
import { mockFlags } from '@/utils/mock-flags'
|
||||
import { clearMockState } from '@/utils/mock-storage'
|
||||
|
||||
import DocumentFilterTabs from './components/DocumentFilterTabs.vue'
|
||||
@@ -25,9 +26,13 @@ import type {
|
||||
|
||||
// 原型阶段:文档库数据与文书内容全部来自本地真实附件(mock.ts + contents.ts),暂不调用后端接口。
|
||||
// 后续接入时,仅需将 loadLibrary / saveTemplate / handleWorkflow 中的本地数据操作替换为文档模板接口。
|
||||
// 是否使用本地演示库由 VITE_MOCK_DOCUMENTS 控制,缺省开启。
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const useMockLibrary = mockFlags.documents
|
||||
/** 关掉演示库后,文书库本应改由模板接口提供,但该路径尚未实现:如实提示,不静默沿用本地数据 */
|
||||
const apiLibraryPending = ref(false)
|
||||
const library = ref<DocumentDepartment[]>([])
|
||||
const selectedTemplate = ref<DocumentTemplate | null>(null)
|
||||
const signingTemplate = ref<SigningTemplate | null>(null)
|
||||
@@ -114,11 +119,26 @@ function cloneLibrary(source: DocumentDepartment[]): DocumentDepartment[] {
|
||||
}
|
||||
|
||||
function loadLibrary() {
|
||||
if (!useMockLibrary) {
|
||||
library.value = []
|
||||
apiLibraryPending.value = true
|
||||
return
|
||||
}
|
||||
|
||||
library.value = cloneLibrary(loadDocumentLibrary())
|
||||
}
|
||||
|
||||
// 演示数据落本地:刷新后文书库还在,不用每次重新建文书
|
||||
watch(library, (value) => saveDocumentLibrary(value), { deep: true })
|
||||
// 演示数据落本地:刷新后文书库还在,不用每次重新建文书。
|
||||
// 关闭演示库时不写本地,否则会把之前保存的演示文书覆盖成空库。
|
||||
watch(
|
||||
library,
|
||||
(value) => {
|
||||
if (useMockLibrary) {
|
||||
saveDocumentLibrary(value)
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
function handlePreview(template: DocumentTemplate) {
|
||||
selectedTemplate.value = template
|
||||
@@ -323,7 +343,12 @@ onMounted(loadLibrary)
|
||||
:statuses="statusTabs"
|
||||
/>
|
||||
|
||||
<div v-if="filteredTemplates.length" class="template-grid">
|
||||
<p v-if="apiLibraryPending" class="library-pending">
|
||||
已关闭本地演示库(VITE_MOCK_DOCUMENTS=false),但文档库尚未接入模板接口,暂时无法展示文书。
|
||||
改回 VITE_MOCK_DOCUMENTS=true 可继续使用演示库。
|
||||
</p>
|
||||
|
||||
<div v-else-if="filteredTemplates.length" class="template-grid">
|
||||
<DocumentTemplateCard
|
||||
v-for="template in filteredTemplates"
|
||||
:key="template.id"
|
||||
@@ -391,6 +416,17 @@ onMounted(loadLibrary)
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.library-pending {
|
||||
padding: 16px 20px;
|
||||
margin: 0 0 16px;
|
||||
color: var(--warn);
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
background: var(--card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 56px 24px;
|
||||
color: var(--mut);
|
||||
|
||||
@@ -408,7 +408,7 @@ function showImportMessage() {
|
||||
}
|
||||
|
||||
if (isUserMockEnabled) {
|
||||
ElMessage.info('批量导入需要切换到真实接口模式(VITE_USE_MOCK=false)')
|
||||
ElMessage.info('批量导入需要切换到真实接口模式(VITE_MOCK_USERS=false)')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ function resetPassword(user: UserTableRow) {
|
||||
}
|
||||
|
||||
if (isUserMockEnabled) {
|
||||
ElMessage.info('密码重置需要切换到真实接口模式(VITE_USE_MOCK=false)')
|
||||
ElMessage.info('密码重置需要切换到真实接口模式(VITE_MOCK_USERS=false)')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user