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>
 

二、运行测试

 

 

 

 

 

 

posted @ 2024-03-16 19:37  lizhigang  阅读(5)  评论(0编辑  收藏  举报