ARCHITECTURE.md 17 KB

张江高新区青浦园产业地图 — 架构与业务流程说明

本文档面向二次开发与维护,描述当前仓库的技术栈、目录结构、运行时链路、数据与地图逻辑、认证与配置,以及可扩展点。
仓库 package.json 中项目名为 shqpgov_school_district_inquiry,与业务展示名称不一致,以页面标题「张江高新区青浦园产业地图」为准。


1. 项目概览

1.1 产品定位

单页大屏类应用:在 Leaflet 二维地图 上展示青浦区 园区边界行政区划重点企业点位,两侧面板提供产业统计(ECharts)、园区列表、图层与图例控制、企业搜索与底图切换。业务数据当前以 前端静态 GeoJSON/JS 模块 为主,非实时接口驱动(「立即同步」为前端模拟)。

1.2 技术栈

类别 技术
框架 Vue 2.6、Vue Router 3(hash)、Vuex 3
UI Element UI 2
地图 Leaflet 1.3.1(public/index.html 全局引入)、Esri Leaflet 3、jQuery(部分 DOM 操作)
图表 ECharts 5
空间分析 @turf/turf 7、proj4
HTTP axios(src/utils/request.js 封装)
构建 Vue CLI 5、vue.config.jspublicPath: './'、打包文件名带时间戳

1.3 外部脚本与全局变量

public/index.html 在打包前加载:

  • ./static/config/config.js:定义 systemConfigmap2DViewer 等全局对象(非 ES 模块)。
  • Leaflet、Esri Leaflet、proj4、leaflet.draw、shpjs、turf、createAuth.js(混淆脚本,提供登录密码加密相关 AesEncryptUtil)。
  • 百度地图 WebGL API(ak=...callback=initialize)—— 当前业务主路径以 Leaflet 为主,需确认是否仍依赖百度回调。

Vue 入口 src/main.js$Coordinatecoordinate)、$Decryptaes.js)、$CryptoJS(实为 publicFunction.js 默认导出)、$dayjs$proj4$bus 挂到实例上。


2. 目录结构(源码层面)

Industry_map/
├── public/
│   ├── index.html                 # 全局脚本、Leaflet CSS/JS
│   └── static/
│       ├── config/config.js       # systemConfig、地图全局 map2DViewer 等
│       ├── images/                # 大屏装饰、图例、marker 图标
│       └── plugins/               # Leaflet 插件、createAuth.js 等
├── src/
│   ├── main.js                    # 应用入口
│   ├── App.vue                    # 根组件:启动时登录
│   ├── router/index.js            # 路由(实质单页)
│   ├── store/index.js             # Vuex:token、用户信息、底图类型等
│   ├── views/
│   │   ├── qpjyj.vue              # 【主页面】产业地图大屏布局与业务编排
│   │   ├── industryDatas.js       # 企业 FeatureCollection 式数组(体积大)
│   │   ├── parkDatas.js           # 园区多边形
│   │   ├── qpDivisionDatas.js     # 区县边界
│   │   ├── qpStreetDatas.js       # 乡镇/街道边界
│   │   └── kewei_cydt_project.js  # 按统一社会信用代码扩展企业工商等字段
│   ├── components/
│   │   ├── map/appMap.vue         # Leaflet 地图:底图、marker、面、Popup
│   │   └── card/                  # 卡片壳、饼图、柱状图
│   ├── api/common.js              # 当前仅 OAuth 登录
│   ├── utils/
│   │   ├── request.js             # axios 实例、拦截器里带 token 头
│   │   ├── encrypt‌.js            # 登录封装(调用 common.login)
│   │   ├── publicFunction.js      # Turf 几何包含、面积、坐标处理等
│   │   ├── aes.js                 # 另一套 AES 加解密(与 encrypt 流程区分)
│   │   └── coordinate.js          # 坐标相关工具
│   ├── directives/drag.js
│   └── assets/                    # 全局样式、字体
├── vue.config.js                  # 代理 /proxy_oauth、别名 @$、@static
└── package.json

3. 应用启动与路由

3.1 启动顺序

  1. 浏览器加载 index.html 中的 config.jscreateAuth.js、Leaflet 等。
  2. Webpack 入口 main.js:注册 Element UI、v-drag、无缝滚动;router.beforeEach 根据 meta.title 设置 document.title
  3. 挂载根实例,App.vuemounted 中调用 encrypt‌()(无参则走默认账号,见下节)。
  4. 路由 //* 均渲染 src/views/qpjyj.vuemode: 'hash'

3.2 主页面与地图的显示条件

qpjyj.vue 中:

<AppMap v-if="$store.state.token" ... />

OAuth 返回 token 写入 Vuex/localStorage 后 才挂载地图组件,避免无 token 时政务底图 URL 缺少 proxyToken


4. 认证与网络

4.1 默认登录流程(src/utils/encrypt‌.js

  • 无参数:使用 systemConfig.defaultAccount.usernameconfig.js 中为 user_kwyzt)与 AesEncryptUtil.getPassword()(来自 createAuth.js)调用 api.login
  • 有参数:校验用户名密码后使用 AesEncryptUtil.getPassword(loginObj.password) 加密密码再登录;成功则 sessionStorage.sessionUserInfo 保存明文账号信息(用于刷新页时复登)。

登录接口:POST ${systemConfig.oauthServiceUrl}/user/pwd/login,表单 application/x-www-form-urlencoded,字段含 userNamepasswordclientId

成功:result.code == 200result.message 作为 token 存入 Vuex 与 localStorage.TOKENresult.contentuserInfo

4.2 开发环境代理

vue.config.js

  • devServer.port: 2024
  • /proxy_oauth/http://121.43.55.7:10086/oauthpathRewrite 去掉前缀)

生产/配置里 oauthServiceUrl 与底图域名需与部署环境一致;当前 config.js 中 oauth 为直连 IP 端口。

4.3 axios 封装(src/utils/request.js

  • 请求拦截器:config.headers.token = localStorage.getItem("TOKEN")
  • 导出 getpostformpostBody 等;post 函数内部引用未定义的 ls,若调用会报错——当前业务主要使用 postform(登录)。

5. 状态管理(Vuex)

src/store/index.js 核心字段:

state 含义
token 与 localStorage TOKEN 同步
userInfo 登录返回内容
baseMapType 底图类型枚举(与页面实际切换逻辑部分重叠)
windowsSize 视口宽高
mapMethodsCollectiontreeDataCollection 预留/历史地图能力
year 首页年份字符串(当前大屏主要统计未绑定该字段)

变更:setTokensetUserStatesetUserInfo


6. 主页面业务:qpjyj.vue

6.1 布局结构

  • 顶栏:标题、数据同步区(日期时间 +「立即同步」)、企业搜索(类型:企业名称 / 企业地址 / 统一社会信用代码)。
  • 主体:全屏 AppMap;左侧三张 Card(产业分布汇总、产业筛选说明、图层控制);右侧 Card(饼图热度、柱状集聚程度、园区列表)。
  • 浮动:左右收起侧栏、左下底图切换、右下图例多选。

6.2 数据流与初始化(initMap

地图组件 mapInit 完成后触发 @mapInitinitMap()

  1. 区县边界qpDivisionDataspieaddParkPolygon('区县行政边界', item, false)
  2. 乡镇边界qpStreetDataspieaddParkPolygon('乡镇行政边界', item, false)
  3. 企业点位:遍历 industryDatas,按 统一社会信用代码kewei_cydt_project 合并属性(如 trd_scope 经营范围等),再 addCompanyMarker(company)
  4. 园区initParkDatas() 内遍历 parkDatas,用 Turf 计算包含关系与统计,绘制 所有园区范围边界,并填充 parkList;延时后默认 changePark(parkList[0])

6.3 园区与统计逻辑(initParkDatas

对每个园区多边形:

  • properties.area:通过 $CryptoJS.calculateMultiPolygonAreaInHectare(geometry) 得到公顷数文案。
  • 对每个企业: isGeometryAContainsGeometryB(园区, 企业点) 判断是否入园。
  • 饼图数据 echartsDatas:按 properties.所属产业 三类(医药器械制造、高端智能装备、新一代信息技术)计数。
  • 柱状 barEchartsDatas:按 properties.专业 映射到「规上工业」「规上服务业」「其他」(无 专业 则归为其他)。
  • 主导产业:饼图三项中取 value 最大者写入园区对象的 主导产业企业数量 为饼图三项之和。

切换园区 changeParkfitBounds 该园区面,并把该园区上的 echartsDatas / barEchartsDatas 赋给右侧面板图表。

6.4 搜索

search():在 industryDatas 内存数组上按所选字段 includes 关键字过滤,去重信用代码,结果列表点击 panToLocation 飞行到企业点。

6.5 图例与图层

  • 图例checkedLegends 变化时调用 appMap.changeMarkerState(产业名, state) 控制对应分组 marker 显隐。
  • 图层开关LayerControls 中「区县/乡镇/所有园区范围边界」开关 → appMap.changeLayerControl(item),在地图侧批量 addLayer / removeLayer 面与面心文字 marker。

6.6 底图切换

baseMapServicesAppMapbaseMapServices 键一致:shmap_blue_webshmap_normal_webarcgisImagery。政务瓦片 URL 含 proxyToken= + localStorage TOKEN

6.7 「数据同步」

handleSyncsyncData()setTimeout 2 秒模拟,成功后更新 lastSyncTimestartAutoSync(定时 30 分钟)在 mounted 中注释掉,未对接真实刷新数据接口;若二次开发对接后端,应替换 syncData 并考虑重新拉取或热更新 industryDatas 等数据源。

6.8 左侧「产业分布」静态数

industrialDistributionSum 中三类企业数为 写死的展示文案(如 30 / 114 / 124),与地图统计无联动;改版时可改为由 industryDatas 聚合或接口返回。


7. 地图组件:appMap.vue

7.1 初始化

  • L.map 中心约 [31.146..., 121.111...]minZoom 9,maxZoom 18,去掉默认 zoom 控件。
  • loadBaseMap(activeBaseMap)L.tileLayer 或预留 wms / esriVector
  • zoomend:缩放 ≥15 显示企业 marker 上的 .title 文字,否则隐藏(jQuery 操作 class)。

7.2 企业 Marker

  • addCompanyMarkerL.divIcon 拼 HTML,图标取自 legendsTypes[所属产业].imageUrl所属产业 必须在 legendsTypes 中有配置,否则运行时会报错。
  • Popup:企业名称、信用代码、地址、专业、产业、经营范围(来自合并后的 trd_scope)。
  • 按产业分桶:this.markers[产业名][企业title] = marker

7.3 面图层

  • pieaddParkPolygon(title, data, toCenter):用 publicFun.latLngsToReverse2 处理坐标后 L.geoJSON,样式颜色来自 layerColor[title]
  • 区县/乡镇/园区:园区面与中心 marker 可点击,$emit('changePark', data);园区 Popup 含主导产业、企业数、parkInfo[园区名] 的简介文案(硬编码在 appMap.vueparkInfo 对象)。

7.4 图层显隐

changeLayerControl(item):根据 item.name 找到 layerControlPolygon[item.name] 下所有 key,同步切换 polygon 与 markers['polygon'][key] 标签点。


8. 数据模块约定

8.1 industryDatas.js

  • GeoJSON Feature 数组:geometryPoint,坐标 [lng, lat]
  • properties 至少包含:企业名称企业地址统一社会信用代码所属产业专业(用于柱状分类)等。

8.2 kewei_cydt_project.js

  • uni_sc_id 与企业的 统一社会信用代码 匹配,Object.assign 合并到 properties,供 Popup 中经营范围等展示。

8.3 parkDatas.js

  • 园区 MultiPolygonproperties.name2 为园区展示名(与 parkInfo、列表、统计 key 一致)。

8.4 行政区划数据

  • qpDivisionDatasproperties.quxian 作为 title
  • qpStreetDatasproperties.zhenjie 作为 title

9. 公共几何与工具(publicFunction.js

与地图强相关导出包括:

  • latLngsToReverse2:多级坐标数组处理(与 Leaflet GeoJSON .latLng 顺序适配有关,需与现有数据坐标系一致)。
  • calculateMultiPolygonAreaInHectare:基于 Turf 的面积换算公顷。
  • isGeometryAContainsGeometryB:判断企业点是否落在园区/行政面内。

二次开发若更换坐标系(WGS84 / GCJ-02 / 地方坐标),需统一修正 数据底图 或在此处增加纠偏。

config.jslonCorrectParams / latCorrectParams 注释为 WGS84→ 上海 2000 类偏移,需在代码中确认是否被实际调用(当前 qpjyj 主路径未直接引用)。


10. 构建与部署注意

  • publicPath: './':适合静态资源相对路径部署(子目录或本地文件)。
  • 文件名带时间戳:利于缓存刷新;若 CDN 需同步规则。
  • configureWebpack.resolve.fallback.zlib:指向 browserify-zlib,与部分打包依赖有关。

11. 二次开发建议清单

  1. 数据改为接口驱动:将 industryDatas / parkDatas 等改为 API + 前端缓存,同步按钮调用真实任务;注意 TOKEN 与跨域。
  2. 统一产业/图例配置:避免 legendsTypes、左侧静态数、图例 checkbox、industrialDistribution 多处硬编码不一致。
  3. OAuth 与底图环境config.js 中 URL 抽为环境变量或部署时注入;开发可用 proxy_oauth 同源代理。
  4. 依赖清理:确认百度地图脚本是否必需;request.js 中未使用的 post / ls 引用可修复或删除以免误用。
  5. TypeScript/模块:长期可逐步把全局 systemConfig 迁入模块并在 vue.config 中定义 ProvidePlugin 或显式 import,便于类型检查。
  6. 大屏适配:已有 windowsSize state,可在布局中进一步使用;地图 resize 已监听 invalidateSize

12. 昼夜主题与本地配色

界面三套换肤由 左下角底图 决定(标准版政务 → 白天;暗蓝色政务 → 黑夜;卫星影像 → 卫星专用暗色 UI cyan,仅叠层、不改影像),主题配置 按当前模式编辑 Token;持久化见 THEME.md

13. 关键文件索引

用途 路径
入口 src/main.js
登录与 token src/App.vuesrc/utils/encrypt‌.jssrc/api/common.js
全局配置(非打包) public/static/config/config.js
主界面 src/views/qpjyj.vue
地图 src/components/map/appMap.vue
企业数据 src/views/industryDatas.js
园区数据 src/views/parkDatas.js
工商扩展 src/views/kewei_cydt_project.js
几何工具 src/utils/publicFunction.js
HTTP src/utils/request.js
主题 Token src/utils/uiTheme.jsdocs/THEME.md

文档版本:与仓库当前代码同步整理;若后续有路由拆分、接口落地或数据迁移,请在本文件追加「变更记录」小节。