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

feat: [data-models/atricle] 重新梳理模型,提供基础封装

zhangyuhan 1 год назад
Родитель
Сommit
1d6644e8f1

+ 47 - 0
data/data-models/core/base.js

@@ -0,0 +1,47 @@
+/**
+ * 数据模型基类
+ */
+class BaseModel {
+  model = null
+  transformModel = null
+
+  /**
+   * 构造函数,初始化模型和转换函数
+   */
+  constructor() {
+    this.model = this.createModel()
+    this.transformModel = this.transform.bind(this)
+  }
+
+  /**
+   * 数据转换方法,用于格式化和更新模型数据
+   * @param {Object} data - 要转换的数据
+   * @param {boolean} isInit - 是否为初始化状态,默认为false
+   * @returns {Object} 返回格式化后的模型数据
+   */
+  transform(data, isInit = false) {
+    const model = this.formatModel(data, isInit)
+    this.model = model
+    return model
+  }
+
+  /**
+   * 预留的格式化模型方法,用于子类覆盖以实现特定的数据格式化逻辑
+   * @param {Object} data - 要格式化的数据
+   * @param {boolean} isInit - 是否为初始化状态,默认为false
+   * @returns {Object} 返回格式化后的数据
+   */
+  formatModel (data, isInit = false) {
+    return data
+  }
+
+  /**
+   * 预留的格式化创建方法,创建一个空的模型对象,用于子类初始化或重写以提供特定的模型结构
+   * @returns {Object} 返回一个空的模型对象
+   */
+  createModel () {
+    return {}
+  }
+}
+
+export default BaseModel

+ 1 - 1
data/data-models/index.js

@@ -1 +1 @@
-export * from './modules/article'
+export * from './modules'

+ 2 - 0
data/data-models/modules/article/index.js

@@ -0,0 +1,2 @@
+export * from './model/content'
+export * from './model/expand'

+ 38 - 0
data/data-models/modules/article/model/content.js

@@ -0,0 +1,38 @@
+import BaseModel from '../../../core/base'
+import useSummaryModel from '../transform/summary'
+import useCommonTitleModel from '../transform/content'
+
+class ContentModel extends BaseModel {
+  constructor(config) {
+    super(config)
+  }
+  createModel() {
+    return {
+      content: useCommonTitleModel().createModel(),
+      summary: useSummaryModel().createModel()
+    }
+  }
+
+  formatModel(data, isInit = false) {
+    const result = this.createModel()
+    // 基础信息
+    if (data?.baseInfo) {
+      result.content = useCommonTitleModel().transformModel(data)
+    }
+    // 摘要
+    if (data?.abstract) {
+      result.summary = useSummaryModel().transformModel(data)
+    }
+    return result
+  }
+}
+
+/**
+ * /publicapply/detail/baseInfo
+ * 基础信息接口数据模型转换
+ */
+function useContentModel() {
+  return new ContentModel()
+}
+
+export default useContentModel

+ 54 - 0
data/data-models/modules/article/model/expand.js

@@ -0,0 +1,54 @@
+import BaseModel from '../../../core/base'
+import tranProjectProgress from '../transform/project-progress'
+import tranServices from '../transform/services'
+
+class ContentExpandModel extends BaseModel {
+  constructor(config) {
+    super(config)
+  }
+  createModel() {
+    return {
+      projectProgress: {},
+      services: [],
+      recommendProjects: [],
+      recommendBuyers: [],
+      recommendWinners: [],
+      recommendCustomers: []
+    }
+  }
+
+  formatModel(data, isInit = false) {
+    const result = this.createModel()
+    // 项目进度
+    if (data?.schedule) {
+      result.projectProgress = tranProjectProgress(data.schedule)
+    }
+    // 服务推荐
+    if (data?.services) {
+      result.services = tranServices(data.services)
+    }
+    if (data?.recommend?.ahead) {
+      result.recommendProjects = data.recommend.ahead
+    }
+    if (data?.recommend?.buyer) {
+      result.recommendBuyers = data.recommend.buyer
+    }
+    if (data?.recommend?.winner) {
+      result.recommendWinners = data.recommend.winner
+    }
+    if (data?.customerRec) {
+      result.recommendCustomers = data.customerRec
+    }
+    return result
+  }
+}
+
+/**
+ * /publicapply/detail/advancedInfo
+ * 扩展信息接口数据模型转换
+ */
+function useContentExpandModel() {
+  return new ContentExpandModel()
+}
+
+export default useContentExpandModel

+ 99 - 0
data/data-models/modules/article/transform/content.js

@@ -0,0 +1,99 @@
+import BaseModel from '../../../core/base'
+import { dateFormatter, formatMoney } from '@jy/util'
+
+class CommonContentModel extends BaseModel {
+  constructor(config) {
+    super(config)
+  }
+
+  createModel() {
+    const contentModel = {
+      id: '',
+      title: '',
+      // 项目信息
+      projectName: '',
+      projectCode: '',
+      // 高亮词组
+      keys: [],
+      tags: [],
+      time: '',
+      // 计算信息
+      isSelfSite: false,
+      // TDK
+      tdk: {
+        title: '',
+        keywords: '',
+        description: ''
+      }
+    }
+    return contentModel
+  }
+
+  formatModel(data, isInit = false) {
+    const result = this.createModel()
+    const { baseInfo } = data
+    result.id = baseInfo.id
+    result.title = baseInfo.title
+    result.projectName = baseInfo?.projectName
+    result.projectCode = baseInfo?.projectCode
+    result.isSelfSite = baseInfo?.site === '剑鱼信息发布平台'
+    result.time = baseInfo?.publishTime
+      ? dateFormatter(baseInfo.publishTime * 1000, 'yyyy-MM-dd')
+      : ''
+    // TDK
+    result.tdk.title = baseInfo.title
+    result.tdk.description = baseInfo?.description
+    result.tdk.keywords = baseInfo?.keywords
+    // Tags
+    result.tags = this.tranTags(data)
+    return result
+  }
+
+  tranTags(data) {
+    const { baseInfo } = data
+    const defaultURL = 'javascript:volid(0);'
+
+    const area = [baseInfo?.area, baseInfo?.city, baseInfo?.district]
+      .filter((v) => v)
+      .join('-')
+
+    const typeItem = {
+      label: baseInfo?.topType,
+      link: defaultURL
+    }
+    if (baseInfo?.subType) {
+      typeItem.label = baseInfo.subType
+      typeItem.link = baseInfo?.subTypeUrl
+    }
+
+    const amountItem = {
+      label: formatMoney(baseInfo?.bidAmount ?? baseInfo?.budget ?? ''),
+      link: defaultURL
+    }
+
+    const tags = [
+      // 地区
+      {
+        label: area,
+        link: baseInfo?.areaUrl || defaultURL
+      },
+      // type
+      typeItem,
+      // buyer_class
+      {
+        label: baseInfo?.buyerClass,
+        link: defaultURL
+      },
+      // amount
+      amountItem
+    ].filter((v) => v.label)
+
+    return tags
+  }
+}
+
+function useCommonContentModel() {
+  return new CommonContentModel()
+}
+
+export default useCommonContentModel

+ 38 - 0
data/data-models/modules/article/transform/project-progress.js

@@ -0,0 +1,38 @@
+import { dateFromNow } from '@jy/util'
+
+/**
+ * 模型转换-招标、采购进度数据
+ * @param data
+ * @return {{id: string, tag: *, time: (*|string), isActive: *, title: string}}
+ */
+function tranProjectProgressItem(data) {
+  const { id = '', title = '' } = data
+  return {
+    id,
+    tag: data?.toptype || data?.subtype,
+    time: data?.publishTime ? dateFromNow(data?.publishTime * 1000) : '',
+    isActive: data?.label,
+    title
+  }
+}
+
+/**
+ * 模型转换-招标、采购进度数据列表
+ * @param data
+ * @return {{name: string, list: *[]}}
+ */
+function tranProjectProgress(data) {
+  const projectProgressModel = {
+    list: [],
+    name: ''
+  }
+
+  projectProgressModel.list = data.list.map((item) =>
+    tranProjectProgressItem(item)
+  )
+  projectProgressModel.name = data.projectName
+
+  return projectProgressModel
+}
+
+export default tranProjectProgress

+ 33 - 0
data/data-models/modules/article/transform/services.js

@@ -0,0 +1,33 @@
+/**
+ * 模型转换-推荐服务
+ */
+function tranServiceItem(data) {
+  const result = {
+    title: data?.title,
+    content: data?.subtitle || '',
+    buttons: data?.buttons || []
+  }
+  if (data?.tip) {
+    // TODO 获取平台
+    const env = 'PC'
+    const link = data?.labelUrl ? data.labelUrl[env] || '' : ''
+    result.header = {
+      tip: data?.tip,
+      more: {
+        label: data?.labelName || '',
+        url: link
+      }
+    }
+  }
+  return result
+}
+
+/**
+ * 模型转换-推荐服务列表
+ * @param list
+ */
+function tranServices(list) {
+  return list.map((item) => tranServiceItem(item))
+}
+
+export default tranServices

+ 223 - 0
data/data-models/modules/article/transform/summary.js

@@ -0,0 +1,223 @@
+import BaseModel from '../../../core/base'
+import { dateFormatter, formatMoney } from '@jy/util'
+
+/**
+ * 摘要 Item 基础类
+ */
+class SummaryItem {
+  constructor(map, data, config = { formatter: null, expands: {}, type: '' }) {
+    this.map = map
+    this.data = data
+    this.configMap = {}
+    this.config = config
+  }
+
+  append(key, { formatter = null, expands = {}, type } = {}) {
+    this.configMap[key] = {
+      formatter,
+      expands,
+      type
+    }
+  }
+
+  customCreate({ label, type, key, value, expands, formatter } = {}) {
+    return {
+      label,
+      type,
+      data: {
+        key,
+        value: typeof formatter === 'function' ? formatter(value) : value,
+        ...expands
+      }
+    }
+  }
+
+  create(key) {
+    const formatter = this.configMap[key]?.formatter || this.config.formatter
+    const value = this.data[key]
+    const expands = this.configMap[key]?.expands || this.config.expands
+    const type = this.configMap[key]?.type || this.config.type
+    return this.customCreate({
+      label: this.map[key],
+      type,
+      key,
+      value,
+      expands,
+      formatter
+    })
+  }
+
+  createList(list = Object.keys(this.map)) {
+    return list.map((key) => this.create(key))
+  }
+}
+class SummaryModel extends BaseModel {
+  constructor(config) {
+    super(config)
+  }
+
+  createModel() {
+    return {
+      list: [],
+      // 采购单位
+      buyers: [],
+      // 中标单位
+      winners: []
+    }
+  }
+
+  formatModel(data, isInit = false) {
+    const { baseInfo, abstract } = data
+    const isProposed = baseInfo?.subType === '拟建'
+    const model = isProposed
+      ? this.tranSummaryOfProposed(abstract.proposed)
+      : this.tranSummaryOfDefault(abstract.default)
+    return model
+  }
+
+  tranSummaryOfDefault(summary) {
+    const result = this.createModel()
+    const summaryMap = {
+      buyer: '采购单位',
+      buyerContactInfo: '采购联系人/电话',
+      agency: '代理机构',
+      agencyContactInfo: '代理联系人/电话',
+      signEndTime: '报名截止日期',
+      bidEndTime: '投标截止日期'
+    }
+
+    // 采购单位
+    if (summary?.buyer) {
+      result.buyers.push({
+        name: summary.buyer
+      })
+    }
+
+    const summaryItem = new SummaryItem(summaryMap, summary)
+    // 特殊字段处理
+    summaryItem.append('buyer', {
+      type: 'unit'
+    })
+    summaryItem.append('buyerContactInfo', {
+      type: 'contact'
+    })
+
+    const formatFn = (time) => {
+      if (time) {
+        return dateFormatter(time * 1000, 'yyyy-MM-dd')
+      } else {
+        return time
+      }
+    }
+
+    summaryItem.append('signEndTime', {
+      formatter: formatFn
+    })
+    summaryItem.append('bidEndTime', {
+      formatter: formatFn
+    })
+
+    const list = summaryItem.createList()
+    // 特殊字段处理
+    // TODO 中标候选人公示时,需要特殊处理
+    if (Array.isArray(summary?.winnerInfos)) {
+      summary.winnerInfos.forEach((item) => {
+        // 中标单位
+        if (item?.winner) {
+          result.winners.push({
+            name: item?.winner,
+            id: item?.winnerId
+          })
+        }
+
+        list.push(
+          summaryItem.customCreate({
+            label: '中标单位',
+            type: 'unit',
+            expands: {
+              value: item?.winner,
+              id: item?.winnerId,
+              _origin: item
+            }
+          })
+        )
+        list.push(
+          summaryItem.customCreate({
+            label: '中标联系人/电话',
+            type: 'contact',
+            expands: {
+              value: item?.winnerContactInfo,
+              id: item?.winnerId,
+              _origin: item
+            }
+          })
+        )
+      })
+    }
+
+    // TODO 确认金额字段
+    list.push(
+      summaryItem.customCreate({
+        label: '中标金额(元)',
+        expands: {
+          value: '测试金额'
+        }
+      })
+    )
+
+    result.list = list
+
+    return result
+  }
+
+  tranSummaryOfProposed(summary) {
+    const result = this.createModel()
+    const summaryMap = {
+      projectName: '项目名称',
+      area: '省份',
+      buyer: '业主单位',
+      buyerClass: '业主类型',
+      totalInvestment: '总投资',
+      projectPeriod: '建设年限',
+      address: '建设地点',
+      approveDept: '审批机关',
+      approveContent: '审批事项',
+      approveCode: '审批代码',
+      approvalNumber: '批准文号',
+      approveTime: '审批时间',
+      approveStatus: '审批结果',
+      content: '建设内容'
+    }
+    // 采购单位
+    if (summary?.buyer) {
+      result.buyers.push({
+        name: summary.buyer
+      })
+    }
+
+    const summaryItem = new SummaryItem(summaryMap, summary)
+    // 特殊字段处理
+    summaryItem.append('address', {
+      expands: {
+        row: true
+      }
+    })
+    summaryItem.append('content', {
+      expands: {
+        row: true
+      }
+    })
+    summaryItem.append('totalInvestment', {
+      formatter: formatMoney
+    })
+
+    result.list = summaryItem.createList()
+    return result
+  }
+}
+
+function useSummaryModel() {
+  return new SummaryModel()
+}
+
+export default useSummaryModel

+ 1 - 0
data/data-models/modules/index.js

@@ -0,0 +1 @@
+export * from './article'