ssts-hospital-web-master项目实战记录四十三:项目迁移-核心模块实现(useFlowPage)
记录时间:2024-03-18
一、useFlowPage模块实现
types/page-config.ts
// 定义 PageCheckDo 类型
interface PageCheckDo {
function: string
meaning: string
msg: string
voice: string
}
// 定义 PageLink 类型
interface PageLink {
use: string
linkName: string
Key: string
url: string
}
// 定义 PageCommit 类型
interface PageCommit {
button: string
function: string
meaning: string
msg: string
voice: string
}
// 定义 PagePromptCase 类型
interface PagePromptCase {
value: string
msg: string
voice: string
}
// 定义 PagePrompt 类型
interface PagePrompt {
scope: string
case: PagePromptCase[]
}
// 定义 PageConfig 类型
interface PageConfig {
name: string
description: string
value: string
showInfo: string
title: string
subTitle?: string
comment: string
msg: string
voice: string
image?: string
flash?: string
currentUrl?: string
checkDo?: PageCheckDo[]
link?: PageLink[]
commit?: PageCommit[]
prompt?: PagePrompt[]
}
export type {
PageCheckDo,
PageLink,
PageCommit,
PagePromptCase,
PagePrompt,
PageConfig
}
types/flow-config.ts
import { PageConfig } from './page-config'
// 定义 FlowConfig 类型
interface FlowConfig {
use: string
key: string
name: string
value: string
comment: string
remark: string
pages: PageConfig[]
}
// 定义 FlowsConfig 类型
interface FlowsConfig {
root: { flow: FlowConfig[] }
}
export type { FlowConfig, FlowsConfig }
types/flow-page.ts
import { FlowConfig } from './flow-config'
// 定义 CheckDoResult 类型
interface CheckDoResult {
isPageValid: boolean
msg: string
voice: string
}
// 定义 DisplayInfo 类型
interface DisplayInfo {
flowName: string
navigation: string
isShowInfo: boolean
comment: string
title: string
subTitle: string
msg: string
voice: string
image: string
flash: string
}
service/flow-page/config-mapper.ts
import { useDeviceDriver } from '../device-driver'
// 函数映射器,将函数名映射到实际的函数
const FunctionMapper = {
CheckDeviceStatus: async (deviceNames: string) => {
const useDD = useDeviceDriver()
return await useDD.CheckDeviceStatus(deviceNames)
}
}
export { FunctionMapper }
service/flow-page/config-parser.ts
import {
FlowsConfig,
FlowConfig,
PageConfig,
PageCheckDo,
CheckDoResult,
PageNavigation
} from '@/types'
import { serveFile } from '@/common'
import { FunctionMapper } from './config-mapper'
// 加载流程配置
const loadFlowsConfig = async function (flowConfigFile: string) {
try {
const result = await serveFile(flowConfigFile)
return JSON.parse(result) as FlowsConfig
} catch (error) {
console.log('loadFlowsConfig', error)
}
}
// 解析在用流程配置
const parseFlowInUse = function (
flowsConfig: FlowsConfig,
flowKey: string
): FlowConfig | undefined {
if (
!flowsConfig ||
!flowsConfig.root ||
!Array.isArray(flowsConfig.root.flow) ||
!flowKey
) {
return // 提前返回以避免无效操作
}
let flow = {} as FlowConfig
const flowList = flowsConfig.root.flow // 直接从flowsConfig中获取flow数组
const foundFlow = flowList.find(
(flow: FlowConfig) => flow.key === flowKey && flow.use === '1'
) // 查找符合条件的flow
if (!foundFlow) {
return // 如果没找到,则返回undefined
}
// 如果找到了匹配的flow,则更新状态
flow = {
...foundFlow, // 使用展开语法复制找到的flow的属性
pages: Array.isArray(foundFlow.pages) ? foundFlow.pages : [] // 如果不是数组,则设置为空数组
}
return flow
}
// 解析页面配置
const parsePageConfig = function (
flowConfig: FlowConfig,
pageName: string
): PageConfig | undefined {
if (
!flowConfig ||
!flowConfig.pages ||
!Array.isArray(flowConfig.pages) ||
!pageName
) {
return // 提前返回以避免无效操作
}
let page = {} as PageConfig
const pageList = flowConfig.pages // 直接从pages中获取page数组
const foundPage = pageList.find((page: PageConfig) => page.name === pageName) // 查找符合条件的flow
if (!foundPage) {
return // 如果没找到,则返回undefined
}
// 如果找到了匹配的page,则更新状态
page = {
...foundPage, // 使用展开语法复制找到的page的属性
checkDo: Array.isArray(foundPage.checkDo) ? foundPage.checkDo : [] // 如果不是数组,则设置为空数组
}
return page
}
// 检查配置函数执行结果
const checkDoConfig = async function (
checkDoConfig: PageCheckDo[]
): Promise<CheckDoResult> {
const result: CheckDoResult = {
isPageValid: true,
msg: '',
voice: ''
}
for (const config of checkDoConfig) {
const functionName = config.function.split('(')[0]
const functionArgs = config.function.slice(functionName.length + 1, -1) // 去除函数名和括号
if (FunctionMapper[functionName]) {
try {
const msg = await FunctionMapper[functionName](functionArgs)
if (msg != null && msg != '') {
result.isPageValid = false
result.msg = `${config.msg}:${msg}` // 拼接错误信息
result.voice = config.voice
break // 如果不需要检查所有配置,可以在第一个失败时跳出循环
}
} catch (error) {
result.isPageValid = false
result.msg = `CheckDo(): 函数执行出错: ${error}`
result.voice = config.voice
break // 如果不需要检查所有配置,可以在第一个出错时跳出循环
}
} else {
result.isPageValid = false
result.msg = `CheckDo():未知函数: ${functionName}`
result.voice = config.voice
break // 如果遇到未知函数,可以直接跳出循环
}
}
console.log(result) // 打印结果,用于调试或日志记录
return result
}
// 创建导航栏
const createNavigationHtml = function (
flowName: string,
value: string,
currStep?: string
) {
const arr = value.split('/')
const navStrArr: string[] = []
const lineStrArr: string[] = []
for (let i = 0; i < arr.length; i++) {
const cicleClass = i === arr.length - 1 ? 'cicle_select' : 'cicle_unselect'
const lineClass =
i === arr.findIndex((step) => step === currStep)
? 'line_select'
: 'line_unselect'
lineStrArr.push(
`<div class="${cicleClass}"><div class="cicle_point"></div></div>`
)
lineStrArr.push(`<div class="${lineClass}"></div>`)
if (i !== arr.length - 1) {
lineStrArr.push(
`<div class="cicle_unselect"><div class="cicle_point"></div></div>`
)
}
const spanClass = arr[i] === currStep ? 'bar_select' : 'bar_unselect'
navStrArr.push(`<span class="${spanClass}">${arr[i] || 'null'}</span>`)
}
let flowStr = ''
let stepStr = ''
if (flowName) {
flowStr = `<div id="div_Flow" style="float: left;">
<div class="img_flow"></div>
<span class="span_flow">${flowName}</span>
</div>`
if (navStrArr.length && lineStrArr.length) {
stepStr = `<div id="div_Nav" style="float: left; width: 785px;">
<div class="bar_text">${navStrArr.join('')}</div>
<div class="bar_img">${lineStrArr.join('')}</div>
</div>`
}
}
return flowStr + stepStr
}
// 创建页面导航
const createPageNavigation = function (
pages: PageConfig[],
pageName: string,
currentUrl: string
): PageNavigation {
const pageNavigation = {} as PageNavigation
if (pages.length > 0) {
const realPage = pages.find((page) => page.name.toLowerCase() === pageName)
const currentPage = pages.find(
(page) => page.name.toLowerCase() === currentUrl.toLowerCase()
)
if (realPage) {
const realIndex = pages.indexOf(realPage)
if (realIndex > 0) {
pageNavigation.prevUrl = pages[realIndex - 1].name
}
}
if (currentPage) {
pageNavigation.currentUrl = currentUrl
pageNavigation.firstUrl = pages[0].name
pageNavigation.lastUrl = pages[pages.length - 1].name
const currentIndex = pages.indexOf(currentPage)
if (currentIndex < pages.length - 1) {
pageNavigation.nextUrl = pages[currentIndex + 1].name
}
}
}
return pageNavigation
}
export {
loadFlowsConfig,
parseFlowInUse,
parsePageConfig,
checkDoConfig,
createNavigationHtml,
createPageNavigation
}
service/flow-page/flow-page.ts
import { FlowPageType, DisplayInfo, PageNavigation } from '@/types'
import {
loadFlowsConfig,
parseFlowInUse,
parsePageConfig,
checkDoConfig,
createNavigationHtml,
createPageNavigation
} from './config-parser'
const FlowPage: FlowPageType = {
flowKey: '',
pageName: '',
isPageFound: false, // 默认页面未找到
isPageValid: true, // 默认页面有效
displayInfo: {} as DisplayInfo,
pageNavigation: {} as PageNavigation,
initProps() {
this.flowKey = ''
this.pageName = ''
this.isPageFound = false
this.isPageValid = true
this.displayInfo = {} as DisplayInfo
this.pageNavigation = {} as PageNavigation
},
async getFlowConfigInUse(
flowDir: string,
flowFileName: string,
flowKey: string
) {
this.initProps()
const flowsConfig = await loadFlowsConfig(`${flowDir}/${flowFileName}.json`)
if (flowsConfig) {
const flowInUse = parseFlowInUse(flowsConfig, flowKey)
return flowInUse
}
},
async getFlowPageByConfig(flowConfig, flowKey, pageName, customDisplayInfo) {
this.initProps()
this.flowKey = flowKey
this.pageName = pageName
const pageConfig = parsePageConfig(flowConfig, pageName)
if (pageConfig) {
this.isPageFound = true
// 页面信息(文字、语音、图片、动画等)
this.displayInfo.flowName = flowConfig.name
this.displayInfo.navigation = createNavigationHtml(
this.displayInfo.flowName,
pageConfig.value,
pageConfig.description
)
this.displayInfo.isShowInfo = pageConfig.showInfo == '1' ? true : false
this.displayInfo.title = pageConfig.title
this.displayInfo.subTitle = pageConfig.subTitle ? pageConfig.subTitle : ''
this.displayInfo.comment = pageConfig.comment
this.displayInfo.msg = pageConfig.msg
this.displayInfo.voice = pageConfig.voice
this.displayInfo.image = pageConfig.image ? pageConfig.image : ''
this.displayInfo.flash = pageConfig.flash ? pageConfig.flash : ''
if (customDisplayInfo) {
this.displayInfo = Object.assign(this.displayInfo, customDisplayInfo)
}
// 页面导航
let currentUrl = pageName
if (pageConfig.currentUrl) {
const currentPageConfig = flowConfig.pages.find(
(page) =>
page.name.toLowerCase() === pageConfig.currentUrl?.toLowerCase()
)
if (currentPageConfig) {
currentUrl = currentPageConfig.name
}
}
this.pageNavigation = createPageNavigation(
flowConfig.pages,
pageName.toLowerCase(),
currentUrl
)
// 页面检查
if (pageConfig.checkDo) {
const checkDoResult = await checkDoConfig(pageConfig.checkDo)
this.isPageValid = checkDoResult.isPageValid
this.displayInfo.msg = checkDoResult.msg
this.displayInfo.voice = checkDoResult.voice
}
}
}
}
export { FlowPage }
二、调用示例
test-hook-use-flow-page.vue
<script setup lang="ts">
import { ref } from 'vue'
import { useSystemStore } from '@/store'
import { useFlowPage } from '@/service/flow-page'
const systemStore = useSystemStore()
const flowPage = useFlowPage()
const flowDir = 'web/biz-basic/flow'
const flowFileName = ref('')
const flowKey = ref('')
const pageName = ref('')
const flowPageInfo = ref('')
const updateFlowPage = async () => {
const flowConfig = await flowPage.getFlowConfigInUse(
flowDir,
flowFileName.value,
flowKey.value
)
if (flowConfig) {
systemStore.setDictFlow(flowConfig)
flowPage.getFlowPageByConfig(flowConfig, flowKey.value, pageName.value)
}
flowPageInfo.value = JSON.stringify(flowPage, null, 2)
}
const setFlowValues = (key: string, page: string) => {
flowFileName.value = key // 假设 fileName 与 flowKey 相同
flowKey.value = key
pageName.value = page
}
const test1 = async () => {
setFlowValues('IDCardSign', 'SelectCardType')
updateFlowPage()
}
const test2 = async () => {
setFlowValues('RealTimeRegister', 'SelectCardType')
updateFlowPage()
}
const test3 = async () => {
setFlowValues('RealTimeRegister', 'ReadIDCard')
updateFlowPage()
}
const test4 = async () => {
setFlowValues('RealTimeRegister', 'InputSSCardPwd')
updateFlowPage()
}
</script>
<template>
<div>
<fieldset>
<button @click="test1">建档:第一页面</button>
<br />
<button @click="test2">当日挂号:第一页面</button>
<button @click="test3">当日挂号:存在的页面</button>
<button @click="test4">当日挂号:不存在的页面</button>
</fieldset>
<fieldset>
<legend>{{ flowKey }}: {{ pageName }}</legend>
<pre>{{ flowPageInfo }}</pre>
</fieldset>
</div>
</template>
<style scoped>
fieldset {
border: 1px solid #ccc;
padding: 1em;
margin: 1em 0;
}
legend {
font-weight: bold;
}
button {
margin-right: 1em;
}
button.active {
font-weight: bold;
}
pre {
white-space: pre-wrap;
/* 保持空白符和换行符,但允许换行 */
word-wrap: break-word;
/* 防止长单词溢出容器 */
font-family: monospace;
/* 使用等宽字体 */
text-align: left;
/* 确保左对齐 */
}
</style>
二、运行测试