diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..fa10d7c
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,9 @@
+ENV = 'development'
+
+# 接口地址
+# 许镇-本地服地址
+VUE_APP_BASE_API = 'http://192.168.99.63:8080'
+VUE_APP_WS_API = 'ws://192.168.99.63:8081'
+
+# 是否启用 babel-plugin-dynamic-import-node插件
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..9cb3545
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,8 @@
+ENV = 'production'
+
+# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇,Nginx 配置
+# 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http
+VUE_APP_BASE_API = 'http://172.22.0.23:8080'
+# VUE_APP_BASE_API = 'http://127.0.0.1:8080'
+# 如果接口是 http 形式, wss 需要改为 ws
+VUE_APP_WS_API = 'ws://172.22.0.23:7071'
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..0c290b7
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,197 @@
+module.exports = {
+ root: true,
+ parserOptions: {
+ parser: 'babel-eslint',
+ sourceType: 'module'
+ },
+ env: {
+ browser: true,
+ node: true,
+ es6: true,
+ },
+ extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+
+ rules: {
+ "vue/max-attributes-per-line": [2, {
+ "singleline": 10,
+ "multiline": {
+ "max": 1,
+ "allowFirstLine": false
+ }
+ }],
+ "vue/singleline-html-element-content-newline": "off",
+ "vue/multiline-html-element-content-newline":"off",
+ "vue/name-property-casing": ["error", "PascalCase"],
+ "vue/no-v-html": "off",
+ 'accessor-pairs': 2,
+ 'arrow-spacing': [2, {
+ 'before': true,
+ 'after': true
+ }],
+ 'block-spacing': [2, 'always'],
+ 'brace-style': [2, '1tbs', {
+ 'allowSingleLine': true
+ }],
+ 'camelcase': [0, {
+ 'properties': 'always'
+ }],
+ 'comma-dangle': [2, 'never'],
+ 'comma-spacing': [2, {
+ 'before': false,
+ 'after': true
+ }],
+ 'comma-style': [2, 'last'],
+ 'constructor-super': 2,
+ 'curly': [2, 'multi-line'],
+ 'dot-location': [2, 'property'],
+ 'eol-last': 2,
+ 'eqeqeq': ["error", "always", {"null": "ignore"}],
+ 'generator-star-spacing': [2, {
+ 'before': true,
+ 'after': true
+ }],
+ 'handle-callback-err': [2, '^(err|error)$'],
+ 'indent': [2, 2, {
+ 'SwitchCase': 1
+ }],
+ 'jsx-quotes': [2, 'prefer-single'],
+ 'key-spacing': [2, {
+ 'beforeColon': false,
+ 'afterColon': true
+ }],
+ 'keyword-spacing': [2, {
+ 'before': true,
+ 'after': true
+ }],
+ 'new-cap': [2, {
+ 'newIsCap': true,
+ 'capIsNew': false
+ }],
+ 'new-parens': 2,
+ 'no-array-constructor': 2,
+ 'no-caller': 2,
+ 'no-console': 'off',
+ 'no-class-assign': 2,
+ 'no-cond-assign': 2,
+ 'no-const-assign': 2,
+ 'no-control-regex': 0,
+ 'no-delete-var': 2,
+ 'no-dupe-args': 2,
+ 'no-dupe-class-members': 2,
+ 'no-dupe-keys': 2,
+ 'no-duplicate-case': 2,
+ 'no-empty-character-class': 2,
+ 'no-empty-pattern': 2,
+ 'no-eval': 2,
+ 'no-ex-assign': 2,
+ 'no-extend-native': 2,
+ 'no-extra-bind': 2,
+ 'no-extra-boolean-cast': 2,
+ 'no-extra-parens': [2, 'functions'],
+ 'no-fallthrough': 2,
+ 'no-floating-decimal': 2,
+ 'no-func-assign': 2,
+ 'no-implied-eval': 2,
+ 'no-inner-declarations': [2, 'functions'],
+ 'no-invalid-regexp': 2,
+ 'no-irregular-whitespace': 2,
+ 'no-iterator': 2,
+ 'no-label-var': 2,
+ 'no-labels': [2, {
+ 'allowLoop': false,
+ 'allowSwitch': false
+ }],
+ 'no-lone-blocks': 2,
+ 'no-mixed-spaces-and-tabs': 2,
+ 'no-multi-spaces': 2,
+ 'no-multi-str': 2,
+ 'no-multiple-empty-lines': [2, {
+ 'max': 1
+ }],
+ 'no-native-reassign': 2,
+ 'no-negated-in-lhs': 2,
+ 'no-new-object': 2,
+ 'no-new-require': 2,
+ 'no-new-symbol': 2,
+ 'no-new-wrappers': 2,
+ 'no-obj-calls': 2,
+ 'no-octal': 2,
+ 'no-octal-escape': 2,
+ 'no-path-concat': 2,
+ 'no-proto': 2,
+ 'no-redeclare': 2,
+ 'no-regex-spaces': 2,
+ 'no-return-assign': [2, 'except-parens'],
+ 'no-self-assign': 2,
+ 'no-self-compare': 2,
+ 'no-sequences': 2,
+ 'no-shadow-restricted-names': 2,
+ 'no-spaced-func': 2,
+ 'no-sparse-arrays': 2,
+ 'no-this-before-super': 2,
+ 'no-throw-literal': 2,
+ 'no-trailing-spaces': 2,
+ 'no-undef': 2,
+ 'no-undef-init': 2,
+ 'no-unexpected-multiline': 2,
+ 'no-unmodified-loop-condition': 2,
+ 'no-unneeded-ternary': [2, {
+ 'defaultAssignment': false
+ }],
+ 'no-unreachable': 2,
+ 'no-unsafe-finally': 2,
+ 'no-unused-vars': [2, {
+ 'vars': 'all',
+ 'args': 'none'
+ }],
+ 'no-useless-call': 2,
+ 'no-useless-computed-key': 2,
+ 'no-useless-constructor': 2,
+ 'no-useless-escape': 0,
+ 'no-whitespace-before-property': 2,
+ 'no-with': 2,
+ 'one-var': [2, {
+ 'initialized': 'never'
+ }],
+ 'operator-linebreak': [2, 'after', {
+ 'overrides': {
+ '?': 'before',
+ ':': 'before'
+ }
+ }],
+ 'padded-blocks': [2, 'never'],
+ 'quotes': [2, 'single', {
+ 'avoidEscape': true,
+ 'allowTemplateLiterals': true
+ }],
+ 'semi': [2, 'never'],
+ 'semi-spacing': [2, {
+ 'before': false,
+ 'after': true
+ }],
+ 'space-before-blocks': [2, 'always'],
+ 'space-before-function-paren': [2, 'never'],
+ 'space-in-parens': [2, 'never'],
+ 'space-infix-ops': 2,
+ 'space-unary-ops': [2, {
+ 'words': true,
+ 'nonwords': false
+ }],
+ 'spaced-comment': [2, 'always', {
+ 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+ }],
+ 'template-curly-spacing': [2, 'never'],
+ 'use-isnan': 2,
+ 'valid-typeof': 2,
+ 'wrap-iife': [2, 'any'],
+ 'yield-star-spacing': [2, 'both'],
+ 'yoda': [2, 'never'],
+ 'prefer-const': 2,
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+ 'object-curly-spacing': [2, 'always', {
+ objectsInObjects: false
+ }],
+ 'array-bracket-spacing': [2, 'never']
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef4e647
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+dist/
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+package-lock.json
\ No newline at end of file
diff --git a/.trae/documents/traffic-flow-screen-plan.md b/.trae/documents/traffic-flow-screen-plan.md
new file mode 100644
index 0000000..b770258
--- /dev/null
+++ b/.trae/documents/traffic-flow-screen-plan.md
@@ -0,0 +1,120 @@
+# 客流量大屏改造方案
+
+## Context(背景与目标)
+
+现有项目 `hs-flow‑screen` 是一个深色科技风的"借阅/通知大屏"(三栏布局:总借阅、借阅排行、进馆、阅读之星、通知、新书推荐)。用户希望仿照目标页面 `http://libraryu.seaeverit.com:15000/main?token=...` 做一个**客流量大屏**,目标页面布局为:顶部 Header → "客流量展示"标签 → 三列卡片(当日进馆折线图 / 当月进馆折线图 / 当年进馆数字翻牌)→ 全宽"累计客流量汇总"翻牌器。
+
+经确认的改造口径:
+1. **保留深色科技风视觉**(深蓝背景 `#010326`、白色文字、蓝色发光 `#1AC9FF`、`common-title`/`module-content` 蓝色样式),**不**改成目标页的白底橙色,只仿照**布局结构**。
+2. **保留现有 Header 组件**(动画线条 + 天气 iframe + 渐变标题),标题用"黄石图书馆"。
+3. **删除不再使用的旧组件目录**。
+4. **数据先用 mock**,预留接口对接位置。
+
+## 关键约束(基于源码确认)
+
+- 适配:rem 方案(`src/common/flexible.js`,1920 设计稿,1rem≈80px,范围 1366–2560),所有尺寸用 rem。
+- echarts 4:`this.$echarts` 全局已注册(`main.js`),用 `this.$echarts.init(this.$refs.chart)` + ref,**不要用 `getElementById`**(旧 `components/echart/*` 用 id 会有冲突)。
+- `resizeMixins.js`(`src/utils/resizeMixins.js`)提供自动 resize(要求组件 `data.chart` 字段),但其 `removeEventListener('reisze'…)` 拼写错误且不 dispose → 新组件须在 `beforeDestroy` 手动 `this.chart.dispose(); this.chart=null`。
+- 数字翻牌:`vue-count-to` 的 `CountTo`,用法 ``。
+- 滚动:`vue-seamless-scroll` 已 `Vue.use`,组件名 ``。
+- `.common-title` / `.module-content` 是 `.screen-main` 的后代选择器 → 新布局根容器必须仍是 `.screen-main`(叠加 `.traffic-main`)。
+- Header 标题 prop:`headerTitle`,`getCurrentTime()` 返回"YYYY年MM月DD日 HH:mm:ss"。
+- 端口 8080,`npm run serve` 自动开浏览器。
+
+## 新文件结构
+
+```
+src/views/
+├── index.vue # 改写:Header + ,删除旧的高度计算逻辑
+├── header/index.vue # 保留不动
+└── trafficFlow/
+ ├── index.vue # 新建:.screen-main.traffic-main 布局容器
+ └── components/
+ ├── DayInFlowChart.vue # 当日进馆折线图(按小时)
+ ├── MonthInFlowChart.vue # 当月进馆折线图(按日)
+ ├── YearInFlowCard.vue # 当年进馆数字翻牌(单个大数字)
+ └── TotalFlowSummary.vue # 累计客流量汇总(8 位翻牌卡片,横向可滚动)
+```
+
+## 实施步骤
+
+### 1. 新建 trafficFlow 4 个子组件 + index.vue(先建骨架,不破坏现有)
+- `DayInFlowChart.vue` / `MonthInFlowChart.vue`:``,`mixins:[resize]`,`data.chart=null` + mock 数据,`mounted` → `initChart()` → `setOption()`,`beforeDestroy` dispose。setOption 用蓝色系(线 `#1AC9FF`、轴 `#2C75E0`、分割线 `rgba(44,117,224,0.3)` 虚线、白色文字、`areaStyle` 用 `this.$echarts.graphic.LinearGradient` 蓝色渐变、`smooth:true`)。
+- `YearInFlowCard.vue`:``,mock `yearNum:1286500`。
+- `TotalFlowSummary.vue`:`totalNum:98765432` → `computed.digitList` 用 `padStart(8,'0').split('')` 固定 8 位,每位一个 ``,外裹 `` 横向滚动(`direction:2`)。预留 `fetchData()` 注释。
+- `trafficFlow/index.vue`:模板见下方。
+
+### 2. 在 `src/assets/styles/index.scss` 末尾追加客流量布局样式(不动现有任何规则)
+新增 `// ===== 客流量大屏布局 =====` 段,关键规则:
+- `.traffic-main { flex-direction:column; justify-content:flex-start; gap:0.125rem; }`(叠加在 `.screen-main` 上)
+- `.traffic-section-title`(顶部"客流量展示"标签,用 `title-big.png`)
+- `.traffic-row { display:flex; }`、`.traffic-row-3 { flex:1; gap:0.25rem; min-height:0; }`(min-height:0 防 echarts 高度坍缩)
+- `.traffic-card { flex:1; display:flex; flex-direction:column; min-width:0; .module-content{flex:1; overflow:hidden; padding:0.125rem 0.2rem;} }`
+- `.traffic-summary { height:1.6rem; }`
+- `.chart-box { width:100%; height:100%; }`
+- `.year-num`(当年大数字,`#1AC9FF` + text-shadow)、`.summary-digits`/`.digit-card`(每位翻牌,`num-img.png` 背景)
+
+### 3. 改写 `src/views/index.vue` 为极简入口
+```vue
+
+
+
+
+
+
+
+
+```
+(删除原 `calcXxxHeight`/`$refs`/resize 监听等所有逻辑)
+
+`trafficFlow/index.vue` 模板骨架:
+```vue
+
+
+
+```
+
+### 4. 启动验证一轮(`npm run serve`)
+确认:Header + "客流量展示" + 三卡片(两折线图初始化、一翻牌)+ 汇总翻牌滚动;控制台无 echarts 报错。
+
+### 5. 删除旧组件目录
+- `src/views/accessToLibrary/`、`totalLending/`、`lengingRanking/`、`newBookRecommend/`、`notice/`、`readStar/`、`todayBorrowed/`
+
+### 6. 可选清理
+- 删 `src/components/echart/`(删旧组件后无引用)、`src/common/scrollMixins.js`(全项目无引用)。
+- 清 `index.scss` 中三栏 `.screen-left/.screen-right/.screen-middle` 及旧组件死 CSS(留着不影响,但建议删三栏那三条以免误导)。
+
+## 接口对接预留(mock 阶段不做)
+- `src/api/library.js` 的 `FetchInitIntoNum` 已存在,保留不删。后续在 4 个组件的 `fetchData()`(已注释)中对接,字段参考 `historyPeopleNum`(累计)、`dayPeopleNum`/`monthPeopleNum`(当日/当月总数);按小时/按日粒度折线数据需后端补接口。
+
+## 验证
+1. `npm run serve` → `http://localhost:8080`:
+ - Header 显示"黄石图书馆" + 天气 + 每秒跳的时间
+ - 顶部"客流量展示"标签
+ - 第一行三列:左/中蓝色平滑折线图(带渐变面积)、右"当年进馆"0→1286500 翻牌动画
+ - 第二行"累计客流量汇总"8 位翻牌(num-img.png 蓝牌背景)横向滚动
+2. F12 控制台无 echarts init/id 重复/resize 报错
+3. 拖拽窗口:折线图随 resizeMixins 自动 resize,rem 尺寸随 flexible 重算
+4. 改 mock 数字热更新不残留旧 echarts 实例(dispose 生效)
+5. `npm run build` 无打包错误
+
+## 风险规避
+- echarts 容器高度坍缩:`.traffic-row-3 { min-height:0 }` + `.traffic-card .module-content { flex:1 }` 必须同时有;必要时给 `.chart-box` 兜底 `min-height:2rem`。
+- `seamless` 横向滚动可能因 8 位内容不够触发:调小 `limitMoveNum:1`,或不要滚动直接静态居中("可滚动"非硬需求)。
+- 顺序:先建新→改入口→验证→再删旧,避免白屏。
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..e763183
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,11 @@
+const plugins = ['@vue/babel-plugin-transform-vue-jsx', '@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-nullish-coalescing-operator']
+// 生产环境移除console
+if (process.env.NODE_ENV === 'production') {
+ plugins.push('transform-remove-console')
+}
+module.exports = {
+ plugins: plugins,
+ presets: [
+ '@vue/cli-plugin-babel/preset'
+ ]
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8cfd07c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "intelligence-screen",
+ "version": "1.0.0",
+ "description": "人流数据大屏",
+ "scripts": {
+ "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
+ "build": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build",
+ "lint": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service lint"
+ },
+ "dependencies": {
+ "@babel/core": "^7.19.0",
+ "@babel/preset-env": "^7.19.0",
+ "@jiaminghi/data-view": "^2.7.3",
+ "@types/echarts": "^4.4.3",
+ "axios": "^0.27.2",
+ "core-js": "^3.6.4",
+ "echarts": "^4.6.0",
+ "element-ui": "^2.15.10",
+ "vue": "^2.6.11",
+ "vue-awesome": "^4.0.2",
+ "vue-count-to": "^1.0.13",
+ "vue-router": "^3.1.5",
+ "vue-seamless-scroll": "^1.1.23",
+ "vuex": "^3.1.2"
+ },
+ "devDependencies": {
+ "@vue/cli-plugin-babel": "^4.2.0",
+ "@vue/cli-plugin-eslint": "^4.2.0",
+ "@vue/cli-service": "^4.2.0",
+ "babel-eslint": "^10.0.3",
+ "babel-plugin-transform-remove-console": "^6.9.4",
+ "eslint": "^6.7.2",
+ "eslint-plugin-vue": "^6.1.2",
+ "sass": "^1.25.0",
+ "sass-loader": "^8.0.2",
+ "vue-awesome-swiper": "^3.1.3",
+ "vue-template-compiler": "^2.6.11"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "node": true
+ },
+ "extends": [
+ "plugin:vue/essential",
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "parser": "babel-eslint"
+ },
+ "rules": {}
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..df36fcf
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..34c570f
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+ <%= htmlWebpackPlugin.options.title %>
+
+
+
+
+
+
+
+
diff --git a/public/static/branches.json b/public/static/branches.json
new file mode 100644
index 0000000..8e8d585
--- /dev/null
+++ b/public/static/branches.json
@@ -0,0 +1,19 @@
+{
+ "schemaVersion": "1.0",
+ "description": "图书馆大屏网点配置:网点编号与网点名称映射",
+ "branches": [
+ { "code": "HWXD", "name": "宏伟星都城市书房" },
+ { "code": "JTSF", "name": "中窑江滩城市书房" },
+ { "code": "QYG", "name": "群艺馆城市书房" },
+ { "code": "QSH", "name": "青山湖城市书房" },
+ { "code": "HSGQ", "name": "黄石港区城市书房" },
+ { "code": "SDGY", "name": "湿地公园城市书房" },
+ { "code": "SNSQ", "name": "神牛社区城市书房" },
+ { "code": "TSSF", "name": "铁山城市书房" },
+ { "code": "WSW", "name": "未苏湾城市书房" },
+ { "code": "SMZJ", "name": "市民之家城市书房" },
+ { "code": "RTFLY", "name": "儿童福利院城市书房" },
+ { "code": "D3、D4", "name": "保利时光绘城市书房" },
+ { "code": "D5", "name": "春湖公园城市书房" }
+ ]
+}
diff --git a/public/static/config.js b/public/static/config.js
new file mode 100644
index 0000000..ecfc7c0
--- /dev/null
+++ b/public/static/config.js
@@ -0,0 +1,4 @@
+window.g = {
+ AXIOS_TIMEOUT: 10000,
+ ApiUrl: 'http://192.168.99.63:8080' // 配置服务器地址
+}
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..f26dc75
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/src/api/library.js b/src/api/library.js
new file mode 100644
index 0000000..10f66a8
--- /dev/null
+++ b/src/api/library.js
@@ -0,0 +1,13 @@
+import request from '@/utils/request'
+
+export function FetchInitIntoNumHS(params) {
+ return request({
+ url: '/dxhtsg/initIntoNumHS',
+ method: 'get',
+ params: params
+ })
+}
+
+export default {
+ FetchInitIntoNumHS
+}
diff --git a/src/assets/fonts/YouSheBiaoTiHei.ttf b/src/assets/fonts/YouSheBiaoTiHei.ttf
new file mode 100644
index 0000000..3729151
Binary files /dev/null and b/src/assets/fonts/YouSheBiaoTiHei.ttf differ
diff --git a/src/assets/fonts/ZhenyanGB.ttf b/src/assets/fonts/ZhenyanGB.ttf
new file mode 100644
index 0000000..207e103
Binary files /dev/null and b/src/assets/fonts/ZhenyanGB.ttf differ
diff --git a/src/assets/fonts/fonts.css b/src/assets/fonts/fonts.css
new file mode 100644
index 0000000..1dffefd
--- /dev/null
+++ b/src/assets/fonts/fonts.css
@@ -0,0 +1,13 @@
+@font-face {
+ font-family: "ZhenyanGB";
+ src: url('ZhenyanGB.ttf');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "YouSheBiaoTiHei";
+ src: url('YouSheBiaoTiHei.ttf');
+ font-weight: normal;
+ font-style: normal;
+}
\ No newline at end of file
diff --git a/src/assets/iconfont/iconfont.css b/src/assets/iconfont/iconfont.css
new file mode 100644
index 0000000..a218315
--- /dev/null
+++ b/src/assets/iconfont/iconfont.css
@@ -0,0 +1,68 @@
+@font-face {
+ font-family: "iconfont"; /* Project id 3646564 */
+ src: url('iconfont.woff2?t=1663379994606') format('woff2'),
+ url('iconfont.woff?t=1663379994606') format('woff'),
+ url('iconfont.ttf?t=1663379994606') format('truetype'),
+ url('iconfont.svg?t=1663379994606#iconfont') format('svg');
+}
+
+.iconfont {
+ font-family: "iconfont" !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-a-no21:before {
+ content: "\e636";
+}
+
+.icon-a-21:before {
+ content: "\e637";
+}
+
+.icon-jianpan:before {
+ content: "\e634";
+}
+
+.icon-guanbi:before {
+ content: "\e630";
+}
+
+.icon-zuo:before {
+ content: "\e631";
+}
+
+.icon-benjiatushu:before {
+ content: "\e632";
+}
+
+.icon-remen:before {
+ content: "\e633";
+}
+
+.icon-you:before {
+ content: "\e62f";
+}
+
+.icon-tongzhi:before {
+ content: "\e628";
+}
+
+.icon-a-no3:before {
+ content: "\e629";
+}
+
+.icon-a-no1:before {
+ content: "\e62b";
+}
+
+.icon-a-3:before {
+ content: "\e62d";
+}
+
+.icon-a-1:before {
+ content: "\e62e";
+}
+
diff --git a/src/assets/iconfont/iconfont.js b/src/assets/iconfont/iconfont.js
new file mode 100644
index 0000000..8284bfe
--- /dev/null
+++ b/src/assets/iconfont/iconfont.js
@@ -0,0 +1 @@
+window._iconfont_svg_string_3646564='',function(t){var F=(F=document.getElementsByTagName("script"))[F.length-1],a=F.getAttribute("data-injectcss"),F=F.getAttribute("data-disable-injectsvg");if(!F){var l,p,h,i,c,d=function(F,a){a.parentNode.insertBefore(F,a)};if(a&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(F){console&&console.log(F)}}l=function(){var F,a=document.createElement("div");a.innerHTML=t._iconfont_svg_string_3646564,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(F=document.body).firstChild?d(a,F.firstChild):F.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(p=function(){document.removeEventListener("DOMContentLoaded",p,!1),l()},document.addEventListener("DOMContentLoaded",p,!1)):document.attachEvent&&(h=l,i=t.document,c=!1,M(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,o())})}function o(){c||(c=!0,h())}function M(){try{i.documentElement.doScroll("left")}catch(F){return void setTimeout(M,50)}o()}}(window);
\ No newline at end of file
diff --git a/src/assets/iconfont/iconfont.json b/src/assets/iconfont/iconfont.json
new file mode 100644
index 0000000..00e91de
--- /dev/null
+++ b/src/assets/iconfont/iconfont.json
@@ -0,0 +1,100 @@
+{
+ "id": "3646564",
+ "name": "智慧屏",
+ "font_family": "iconfont",
+ "css_prefix_text": "icon-",
+ "description": "",
+ "glyphs": [
+ {
+ "icon_id": "31879702",
+ "name": "no.2",
+ "font_class": "a-no21",
+ "unicode": "e636",
+ "unicode_decimal": 58934
+ },
+ {
+ "icon_id": "31879708",
+ "name": "2",
+ "font_class": "a-21",
+ "unicode": "e637",
+ "unicode_decimal": 58935
+ },
+ {
+ "icon_id": "31879044",
+ "name": "键盘",
+ "font_class": "jianpan",
+ "unicode": "e634",
+ "unicode_decimal": 58932
+ },
+ {
+ "icon_id": "31859389",
+ "name": "关闭",
+ "font_class": "guanbi",
+ "unicode": "e630",
+ "unicode_decimal": 58928
+ },
+ {
+ "icon_id": "31859390",
+ "name": "左",
+ "font_class": "zuo",
+ "unicode": "e631",
+ "unicode_decimal": 58929
+ },
+ {
+ "icon_id": "31859393",
+ "name": "本架图书",
+ "font_class": "benjiatushu",
+ "unicode": "e632",
+ "unicode_decimal": 58930
+ },
+ {
+ "icon_id": "31859394",
+ "name": "热门",
+ "font_class": "remen",
+ "unicode": "e633",
+ "unicode_decimal": 58931
+ },
+ {
+ "icon_id": "31859388",
+ "name": "右",
+ "font_class": "you",
+ "unicode": "e62f",
+ "unicode_decimal": 58927
+ },
+ {
+ "icon_id": "31804863",
+ "name": "通知",
+ "font_class": "tongzhi",
+ "unicode": "e628",
+ "unicode_decimal": 58920
+ },
+ {
+ "icon_id": "31804864",
+ "name": "no.3",
+ "font_class": "a-no3",
+ "unicode": "e629",
+ "unicode_decimal": 58921
+ },
+ {
+ "icon_id": "31804866",
+ "name": "no.1",
+ "font_class": "a-no1",
+ "unicode": "e62b",
+ "unicode_decimal": 58923
+ },
+ {
+ "icon_id": "31804868",
+ "name": "3",
+ "font_class": "a-3",
+ "unicode": "e62d",
+ "unicode_decimal": 58925
+ },
+ {
+ "icon_id": "31804869",
+ "name": "1",
+ "font_class": "a-1",
+ "unicode": "e62e",
+ "unicode_decimal": 58926
+ }
+ ]
+}
diff --git a/src/assets/iconfont/iconfont.svg b/src/assets/iconfont/iconfont.svg
new file mode 100644
index 0000000..1f96bc6
--- /dev/null
+++ b/src/assets/iconfont/iconfont.svg
@@ -0,0 +1,45 @@
+
+
+
diff --git a/src/assets/iconfont/iconfont.ttf b/src/assets/iconfont/iconfont.ttf
new file mode 100644
index 0000000..cd9dd4b
Binary files /dev/null and b/src/assets/iconfont/iconfont.ttf differ
diff --git a/src/assets/iconfont/iconfont.woff b/src/assets/iconfont/iconfont.woff
new file mode 100644
index 0000000..f9c8d7d
Binary files /dev/null and b/src/assets/iconfont/iconfont.woff differ
diff --git a/src/assets/iconfont/iconfont.woff2 b/src/assets/iconfont/iconfont.woff2
new file mode 100644
index 0000000..2552240
Binary files /dev/null and b/src/assets/iconfont/iconfont.woff2 differ
diff --git a/src/assets/images/default-img.png b/src/assets/images/default-img.png
new file mode 100644
index 0000000..01a60cb
Binary files /dev/null and b/src/assets/images/default-img.png differ
diff --git a/src/assets/images/header-bg.png b/src/assets/images/header-bg.png
new file mode 100644
index 0000000..84d92c1
Binary files /dev/null and b/src/assets/images/header-bg.png differ
diff --git a/src/assets/images/header-left.png b/src/assets/images/header-left.png
new file mode 100644
index 0000000..c713888
Binary files /dev/null and b/src/assets/images/header-left.png differ
diff --git a/src/assets/images/header-right.png b/src/assets/images/header-right.png
new file mode 100644
index 0000000..18abf63
Binary files /dev/null and b/src/assets/images/header-right.png differ
diff --git a/src/assets/images/notice.gif b/src/assets/images/notice.gif
new file mode 100644
index 0000000..17f9f0d
Binary files /dev/null and b/src/assets/images/notice.gif differ
diff --git a/src/assets/images/num-img.png b/src/assets/images/num-img.png
new file mode 100644
index 0000000..01bd009
Binary files /dev/null and b/src/assets/images/num-img.png differ
diff --git a/src/assets/images/star-1.png b/src/assets/images/star-1.png
new file mode 100644
index 0000000..d2f0f81
Binary files /dev/null and b/src/assets/images/star-1.png differ
diff --git a/src/assets/images/star-2.png b/src/assets/images/star-2.png
new file mode 100644
index 0000000..c00d713
Binary files /dev/null and b/src/assets/images/star-2.png differ
diff --git a/src/assets/images/star-3.png b/src/assets/images/star-3.png
new file mode 100644
index 0000000..82407a5
Binary files /dev/null and b/src/assets/images/star-3.png differ
diff --git a/src/assets/images/title-big.png b/src/assets/images/title-big.png
new file mode 100644
index 0000000..2d5a0b9
Binary files /dev/null and b/src/assets/images/title-big.png differ
diff --git a/src/assets/images/title.png b/src/assets/images/title.png
new file mode 100644
index 0000000..b5ddaea
Binary files /dev/null and b/src/assets/images/title.png differ
diff --git a/src/assets/images/top-line.png b/src/assets/images/top-line.png
new file mode 100644
index 0000000..33beb85
Binary files /dev/null and b/src/assets/images/top-line.png differ
diff --git a/src/assets/images/top.png b/src/assets/images/top.png
new file mode 100644
index 0000000..a4e606f
Binary files /dev/null and b/src/assets/images/top.png differ
diff --git a/src/assets/logo.png b/src/assets/logo.png
new file mode 100644
index 0000000..f3d2503
Binary files /dev/null and b/src/assets/logo.png differ
diff --git a/src/assets/styles/ball-running-animate.css b/src/assets/styles/ball-running-animate.css
new file mode 100644
index 0000000..55fcb8d
--- /dev/null
+++ b/src/assets/styles/ball-running-animate.css
@@ -0,0 +1,116 @@
+.ball-running-dots {
+ position: absolute;
+ top: 0.2rem;
+}
+.left-dots {
+ left: 136px;
+}
+.right-dots {
+ right: 200px;
+}
+.ball-running-dots > div {
+ position: relative;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.ball-running-dots {
+ display: block;
+ font-size: 0;
+ color: #316fd9;
+}
+.ball-running-dots > div {
+ display: inline-block;
+ float: none;
+ background-color: currentColor;
+ border: 0 solid currentColor;
+}
+.ball-running-dots {
+ width: 16px;
+ height: 16px;
+}
+.ball-running-dots > div {
+ position: absolute;
+ margin-left: 30px;
+ border-radius: 100%;
+}
+.left-dots > div {
+ animation: ball-running-dots-animate 2s linear infinite;
+}
+.right-dots > div {
+ animation: ball-running-dots-animate2 2s linear infinite;
+}
+.ball-running-dots > div:nth-child(1) {
+ animation-delay: 0s;
+}
+.ball-running-dots > div:nth-child(2) {
+ animation-delay: -0.8s;
+}
+.ball-running-dots > div:nth-child(3) {
+ animation-delay: -1.2s;
+}
+.ball-running-dots > div:nth-child(4) {
+ animation-delay: -1.6s;
+}
+@keyframes ball-running-dots-animate {
+ 0%{
+ width: 100%;
+ height: 100%;
+ transform: translateY(0) translateX(-500%) scale(-.1);
+ opacity: 0.5;
+ }
+ 80% {
+ transform: translateY(0) translateX(0);
+ }
+ 85% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(-125%) translateX(0);
+ }
+ 90% {
+ width: 200%;
+ height: 75%;
+ }
+ 95% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(-100%) translateX(-500%);
+ }
+ 100% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(0) translateX(-500%);
+ opacity: 1;
+ }
+}
+@keyframes ball-running-dots-animate2 {
+ 0%{
+ width: 100%;
+ height: 100%;
+ transform: translateY(0) translateX(500%) scale(-.1);
+ opacity: 0.5;
+ }
+ 80% {
+ transform: translateY(0) translateX(0);
+ }
+ 85% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(-125%) translateX(0);
+ }
+ 90% {
+ width: 200%;
+ height: 75%;
+ }
+ 95% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(-100%) translateX(500%);
+ }
+ 100% {
+ width: 100%;
+ height: 100%;
+ transform: translateY(0) translateX(500%);
+ opacity: 1;
+ }
+}
diff --git a/src/assets/styles/font-some.css b/src/assets/styles/font-some.css
new file mode 100644
index 0000000..0460bee
--- /dev/null
+++ b/src/assets/styles/font-some.css
@@ -0,0 +1,46 @@
+.chartNum{
+ display: flex;
+ justify-content: center;
+ margin-top: 0.25rem;
+}
+.box-items {
+ position: relative;
+ display: flex;
+ height: 0.6rem;
+ text-align: center;
+}
+/*滚动数字设置*/
+.number-item {
+ display: flex;
+ justify-content: center;
+ text-align: center;
+ width: 0.45rem;
+ height: 0.6rem;
+ line-height: 0.6rem;
+ margin-right: 0.125rem;
+ border: 1px solid #2C75E0;
+}
+.number-item span{
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+ writing-mode: vertical-rl;
+ text-orientation: upright;
+ overflow: hidden;
+}
+.number-item span i{
+ font-style: normal;
+ position: absolute;
+ top: 0.1rem;
+ left: 50%;
+ font-size: 0.325rem;
+ font-weight: bold;
+ color: #1AC9FF;
+ transform: translate(-50%,0);
+ transition: transform 1s ease-in-out;
+ letter-spacing: 10px;
+}
+.number-item:last-child {
+ margin-right: 0;
+}
diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss
new file mode 100644
index 0000000..04518d2
--- /dev/null
+++ b/src/assets/styles/index.scss
@@ -0,0 +1,710 @@
+#screen-container {
+ width: 100%;
+ height: 100vh;
+ padding: 0 0.175rem;
+ font-size: 0.25rem;
+ line-height: 0.35rem;
+ color: #fff;
+ background-color: #010326;
+ overflow: hidden;
+}
+
+// 头部主题标题
+.header-container{
+ position: relative;
+ width: 100%;
+ height: 1.125rem;
+ font-size: 0.3rem;
+ color: #fff;
+ &::before,
+ &::after{
+ content: "";
+ position: absolute;
+ top: 0;
+ width: 6.2rem;
+ height: 1.05rem;
+ }
+ &::before{
+ left: 0;
+ background: url('~@/assets/images/header-left.png') no-repeat top center;
+ }
+ &::after{
+ right: 0;
+ background: url('~@/assets/images/header-right.png') no-repeat top center;
+ }
+ .header-title{
+ position: relative;
+ width: 15.85rem;
+ height: 1.075rem;
+ margin: 0 auto;
+ background: url('~@/assets/images/header-bg.png') no-repeat top center;
+ background-size: cover;
+ h2{
+ font-size: 0.6rem;
+ font-family: "ZhenyanGB";
+ font-weight: normal;
+ line-height: 1.125rem;
+ text-align: center;
+ letter-spacing: 0.2rem;
+ background: linear-gradient(180deg, #FFFFFF 0%, #1AC9FF 100%);
+ background-clip: text;
+ color: transparent;
+ }
+ }
+ .header-text{
+ position: absolute;
+ top: 0.65rem;
+ }
+ .header-weather {
+ left: 0.6rem;
+ }
+ .header-date {
+ right: 0.375rem;
+ }
+}
+
+// 头部动态效果
+.line1,
+.line2{
+ position: absolute;
+ top: 0;
+}
+
+.line1{
+ right: 632px;
+ transform: rotateY(-180deg);
+}
+
+.line2{
+ left: 632px;
+}
+
+.top-line1,
+.top-line2{
+ display: block;
+ width: 7.925rem;
+ height: 1.075rem;
+ animation: topline 4s linear infinite both;
+}
+
+.top-line1{
+ background: url('~@/assets/images/top-line.png') no-repeat;
+}
+
+.top-line2{
+ background: url('~@/assets/images/top-line.png') no-repeat;
+}
+
+@keyframes topline {
+ from {
+ width: 0;
+ }
+ 50%,
+ to {
+ width: 643px;
+ }
+}
+
+// 主题内部部分
+.screen-main{
+ display: flex;
+ justify-content: space-between;
+ height: calc(100% - 1.38rem);
+ margin: 0.0625rem 0 0.5rem 0;
+ padding: 0 0.325rem;
+ overflow: hidden;
+ .screen-left,
+ .screen-right{
+ width: 6.375rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ }
+ .screen-middle{
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ margin: 0 0.5rem;
+ }
+ .screen-item{
+ margin-top: 0.25rem;
+ }
+ .common-title{
+ width: 100%;
+ height: 0.475rem;
+ line-height: 0.475rem;
+ padding-left: 0.525rem;
+ font-size: 0.325rem;
+ background: url('~@/assets/images/title.png') no-repeat center center;
+ background-size: cover;
+ font-family: 'YouSheBiaoTiHei';
+ letter-spacing: 0.1rem;
+ }
+ .module-content{
+ border: 1px solid #2C75E0;
+ box-shadow: inset 0px 0px 38px 1px rgba(44,117,224,0.5);
+ }
+ .small-module{
+ height: 3.75rem;
+ }
+ .medium-module{
+ height: 4.25rem;
+ }
+ .big-module{
+ // height: 6.8125rem;
+ }
+
+ //排行榜-推荐 - list
+ .lending-ranking{
+ flex: 1;
+ .module-content{
+ padding: 0 0.25rem;
+ overflow: hidden;
+ }
+ }
+ .book-list-item{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.1rem 0.25rem;
+ .book-img{
+ width: 0.825rem;
+ height: 1.075rem;
+ margin-right: 0.35rem;
+ background: url('~@/assets/images/default-img.png') no-repeat center center;
+ background-size: contain;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ img{
+ display: block;
+ width: 100%;
+ // height: 100%;
+ }
+ }
+ .book-info{
+ flex: 1;
+ margin-right: 0.35rem;
+ h4{
+ font-size: 0.25rem;
+ font-weight: normal;
+ }
+ p{
+ font-size: 0.2rem;
+ }
+ }
+ .ranking-num{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ .icon{
+ width: 0.5625rem;
+ height: 0.5625rem;
+ margin-right: 0.175rem;
+ }
+ }
+ }
+
+ // 进出馆人数
+ .accessToLib-container{
+ display: flex;
+ justify-content: space-between;
+ text-align: center;
+ align-items: center;
+ margin: 0.375rem 0 .25rem 0;
+ .accessToLib-item{
+ width: 2.75rem;
+ .panel-num{
+ display: block;
+ height: 0.85rem;
+ margin-top: 0.125rem;
+ line-height: 0.85rem;
+ font-size: 0.325rem;
+ font-weight: bold;
+ text-align: center;
+ color: #1AC9FF;
+ background: url('~@/assets/images/num-img.png') no-repeat center center;
+ background-size: cover;
+ }
+ }
+ }
+
+ // 视频
+ .video-box{
+ width: 100%;
+ height: 5.15rem;
+ }
+
+ // 阅读之星
+ .read-star{
+ flex: 1;
+ .common-title{
+ background: url('~@/assets/images/title-big.png') no-repeat center center;
+ background-size: cover;
+ }
+ .module-content{
+ padding: .25rem;
+ overflow: hidden;
+ .readstart-item{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 0.5rem;
+ padding: 0 0.25rem;
+ font-size: 0.2rem;
+ margin-bottom: 0.125rem;
+ background: linear-gradient(90deg, #0C2157 0%, rgba(44,117,224,0) 51%, #0C2157 100%);
+ .icon-star-1{
+ width: 0.35rem;
+ height: 0.3rem;
+ margin-left: -0.05rem;
+ margin-right: 0.2rem;
+ }
+ .icon-star-2{
+ width: 0.375rem;
+ height: 0.3rem;
+ margin-left: -0.0625rem;
+ margin-right: 0.2rem;
+ }
+ .icon-star-3{
+ width: 0.275rem;
+ height: 0.3rem;
+ margin-right: 0.25rem;
+ }
+ .star-num{
+ display: block;
+ width: 0.25rem;
+ height: 0.25rem;
+ margin-right: 0.25rem;
+ font-size: 0.2rem;
+ line-height: 0.25rem;
+ text-align: center;
+ border-radius: 50%;
+ color: #1AC9FF;
+ border: 1px solid #1AC9FF;
+ }
+ .star-info{
+ flex: 1;
+ margin-right: 0.25rem;
+ }
+ &.star1-bg{
+ background: url('~@/assets/images/star-1.png') no-repeat left top;
+ background-size: contain;
+ }
+ &.star2-bg{
+ background: url('~@/assets/images/star-2.png') no-repeat left top;
+ background-size: contain;
+ }
+ &.star3-bg{
+ background: url('~@/assets/images/star-3.png') no-repeat left top;
+ background-size: contain;
+ }
+ }
+
+ }
+ }
+
+ // 通知公告
+ // .notice{
+ // .module-content{
+ // display: flex;
+ // justify-content: space-between;
+ // width: 100%;
+ // padding: 0.25rem 0.375rem 0.5rem 0.375rem;
+ // .notice-icon-gif{
+ // display: block;
+ // width: 2.375rem;
+ // height: 2.875rem;
+ // background: url('~@/assets/images/notice.gif') no-repeat left top;
+ // background-size: contain;
+ // margin-right: 0.15rem;
+ // }
+ // .seamless-warp{
+ // width: calc(100vw);
+ // height: 3.1rem;
+ // overflow: hidden;
+ // .notice-txt {
+ // animation: myMove 20s linear infinite;
+ // animation-fill-mode: forwards;
+ // }
+ // @keyframes myMove {
+ // 0% {
+ // transform: translateY(2rem);
+ // }
+ // 100% {
+ // transform: translateY(-6rem);
+ // }
+ // }
+ // }
+ // }
+ // }
+ // 通知公告
+ .notice{
+ .module-content{
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ padding: 0.25rem 0.375rem 0.5rem 0.375rem;
+ .notice-icon-gif{
+ display: block;
+ width: 2.375rem;
+ height: 2.875rem;
+ background: url('~@/assets/images/notice.gif') no-repeat left top;
+ background-size: contain;
+ margin-right: 0.15rem;
+ }
+ .seamless-warp{
+ width: calc(100vw);
+ height: 3.1rem;
+ overflow: hidden;
+ }
+ }
+ }
+}
+
+// ===== 客流量大屏布局 =====
+// 单栏新布局,叠加在 .screen-main 基础上,不改动原有三栏规则
+.traffic-main{
+ flex-direction: column;
+ justify-content: flex-start;
+ gap: 0.3rem;
+ padding: 0.25rem;
+}
+
+// 顶部分类标签
+.traffic-section-title{
+ height: 0.55rem;
+ line-height: 0.55rem;
+ font-size: 0.375rem;
+ background: url('~@/assets/images/title-big.png') no-repeat center center;
+ background-size: cover;
+}
+
+// 行容器
+.traffic-row{
+ display: flex;
+}
+.traffic-row-3{
+ flex: 1;
+ gap: 0.25rem;
+ min-height: 0;
+}
+
+// 卡片:参考 HTML 的 card 样式,角标 + 顶部渐变线
+.traffic-card{
+ position: relative;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ background: rgba(0, 18, 52, 0.45);
+ border: 1px solid rgba(26, 201, 255, 0.22);
+ border-radius: 0.2rem;
+ box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06);
+ overflow: hidden;
+ &::before{
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background: linear-gradient(90deg, transparent, #1AC9FF, transparent);
+ opacity: 0.6;
+ z-index: 2;
+ }
+ .card-corner{
+ position: absolute;
+ width: 0.175rem;
+ height: 0.175rem;
+ border: 2px solid #1AC9FF;
+ opacity: 0.8;
+ z-index: 2;
+ &.tl{ top: -1px; left: -1px; border-right: none; border-bottom: none; }
+ &.tr{ top: -1px; right: -1px; border-left: none; border-bottom: none; }
+ &.bl{ bottom: -1px; left: -1px; border-right: none; border-top: none; }
+ &.br{ bottom: -1px; right: -1px; border-left: none; border-top: none; }
+ }
+ .card-header{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.2rem 0.275rem 0;
+ flex-shrink: 0;
+ }
+ .card-label{
+ display: flex;
+ align-items: center;
+ gap: 0.15rem;
+ font-size: 0.3rem;
+ font-weight: 600;
+ color: #f1f5f9;
+ &::before{
+ content: "";
+ width: 0.075rem;
+ height: 0.3rem;
+ background: #1AC9FF;
+ border-radius: 3px;
+ box-shadow: 0 0 0.1rem #1AC9FF;
+ }
+ }
+ .card-date{
+ font-size: 0.225rem;
+ color: #64748b;
+ font-variant-numeric: tabular-nums;
+ }
+ .module-content{
+ flex: 1;
+ overflow: hidden;
+ padding: 0.15rem 0.275rem 0.275rem;
+ border: none;
+ box-shadow: none;
+ }
+ .year-content{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+// 折线图容器
+.chart-box{
+ width: 100%;
+ height: 100%;
+ min-height: 2rem;
+}
+
+// 当日进馆 hero 卡片:特殊背景 + 发光边框 + 数字脉冲(仿参考页)
+.card-hero{
+ background:
+ radial-gradient(130% 110% at 50% 0%, rgba(26, 201, 255, 0.22) 0%, rgba(26, 201, 255, 0.05) 42%, transparent 72%),
+ linear-gradient(160deg, #042a52 0%, #021a36 58%, #020f24 100%);
+ border: 1px solid rgba(26, 201, 255, 0.55);
+ box-shadow:
+ 0 0 0.3rem rgba(26, 201, 255, 0.28),
+ inset 0 1px 0 rgba(255, 255, 255, 0.08);
+ &::before{
+ height: 3px;
+ opacity: 1;
+ background: linear-gradient(90deg, transparent, #1AC9FF, #7dd3fc, #1AC9FF, transparent);
+ }
+ .card-corner{
+ border-color: #1AC9FF;
+ opacity: 1;
+ width: 0.2rem;
+ height: 0.2rem;
+ }
+ .card-label::before{
+ box-shadow: 0 0 0.14rem #1AC9FF;
+ }
+ .stat-number{
+ text-shadow: 0 0 0.55rem rgba(26, 201, 255, 0.65);
+ animation: heroPulse 2.6s ease-in-out infinite;
+ }
+}
+@keyframes heroPulse{
+ 0%, 100% { text-shadow: 0 0 0.42rem rgba(26, 201, 255, 0.42); }
+ 50% { text-shadow: 0 0 0.62rem rgba(26, 201, 255, 0.82); }
+}
+
+// 当日进馆 - 数字卡片
+.stat-card{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ text-align: center;
+ .live-row{
+ margin-bottom: 0.225rem;
+ display: flex;
+ align-items: center;
+ .live-text{ font-size: 0.275rem; color: #94a3b8; }
+ }
+ .stat-number{
+ font-size: 1.5rem;
+ font-weight: 600;
+ line-height: 1;
+ font-variant-numeric: tabular-nums;
+ background: linear-gradient(180deg, #fff 0%, #7dd3fc 60%, #1AC9FF 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-shadow: 0 0 0.5rem rgba(26, 201, 255, 0.25);
+ margin-bottom: 0.15rem;
+ }
+ .stat-unit{
+ font-size: 0.3rem;
+ color: #94a3b8;
+ font-weight: 500;
+ }
+}
+
+.live-dot{
+ display: inline-block;
+ width: 0.15rem;
+ height: 0.15rem;
+ background: #34d399;
+ border-radius: 50%;
+ box-shadow: 0 0 0.125rem #34d399;
+ margin-right: 0.1rem;
+ animation: livePulse 1.4s infinite;
+}
+@keyframes livePulse{
+ 0%, 100%{ opacity: 1; transform: scale(1); }
+ 50%{ opacity: 0.6; transform: scale(1.3); }
+}
+
+// 汇总行
+.traffic-summary{
+ flex: 1.1;
+ min-height: 0;
+ .traffic-summary-inner{
+ position: relative;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ background: rgba(0, 18, 52, 0.45);
+ border: 1px solid rgba(26, 201, 255, 0.22);
+ border-radius: 0.2rem;
+ box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06);
+ overflow: hidden;
+ &::before{
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background: linear-gradient(90deg, transparent, #1AC9FF, transparent);
+ opacity: 0.6;
+ z-index: 2;
+ }
+ .card-corner{
+ position: absolute;
+ width: 0.175rem;
+ height: 0.175rem;
+ border: 2px solid #1AC9FF;
+ opacity: 0.8;
+ z-index: 2;
+ &.tl{ top: -1px; left: -1px; border-right: none; border-bottom: none; }
+ &.tr{ top: -1px; right: -1px; border-left: none; border-bottom: none; }
+ &.bl{ bottom: -1px; left: -1px; border-right: none; border-top: none; }
+ &.br{ bottom: -1px; right: -1px; border-left: none; border-top: none; }
+ }
+ }
+ .module-content{
+ flex: 1;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ border: none;
+ box-shadow: none;
+ padding: 0;
+ }
+}
+
+// 累计汇总 - 三栏
+.cumulative-card{
+ display: grid;
+ grid-template-columns: 4.25rem 1fr 3.25rem;
+ width: 100%;
+ height: 100%;
+ padding: 0.35rem 0.45rem;
+ gap: 0.4rem;
+ align-items: center;
+}
+.cumulative-left{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 0.2rem;
+ // padding-right: 0.4rem;
+ border-right: 1px solid rgba(26, 201, 255, 0.22);
+ .cumulative-title{ font-size: 0.5rem; font-weight: 700; color: #f1f5f9; }
+ .cumulative-subtitle{ font-size: 0.24rem; color: #94a3b8; line-height: 1.5; }
+}
+.mini-bars{
+ display: flex;
+ align-items: flex-end;
+ gap: 0.2rem;
+ margin-top: 0.125rem;
+ .mini-item{ display: flex; flex-direction: column; align-items: center; gap: 0.1rem; }
+ .mini-col{ height: 1.3rem; display: flex; align-items: flex-end; }
+ .mini-bar{
+ width: 0.375rem;
+ border-radius: 4px 4px 0 0;
+ background: linear-gradient(180deg, #1AC9FF 0%, rgba(26, 201, 255, 0.15) 100%);
+ box-shadow: 0 0 0.125rem rgba(26, 201, 255, 0.25);
+ }
+ .mini-label{ font-size: 0.15rem; color: #64748b; }
+}
+.cumulative-right{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.2rem;
+ position: relative;
+ &::before{
+ content: "";
+ position: absolute;
+ width: 6.5rem;
+ height: 3.25rem;
+ background: radial-gradient(ellipse at center, rgba(26, 201, 255, 0.12) 0%, transparent 70%);
+ pointer-events: none;
+ }
+ .digit-box{
+ width: 1.5rem;
+ height: 2.05rem;
+ background: linear-gradient(180deg, rgba(26, 201, 255, 0.22) 0%, rgba(26, 201, 255, 0.06) 100%);
+ border: 1px solid rgba(26, 201, 255, 0.22);
+ border-radius: 0.125rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.35rem;
+ font-weight: 800;
+ font-variant-numeric: tabular-nums;
+ color: #f1f5f9;
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), 0 4px 0.25rem rgba(0, 0, 0, 0.25);
+ text-shadow: 0 0 0.25rem rgba(26, 201, 255, 0.35);
+ position: relative;
+ overflow: hidden;
+ &::after{
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: rgba(0, 0, 0, 0.25);
+ z-index: 2;
+ }
+ // 翻牌滚动列表
+ .digit-roller{
+ display: flex;
+ flex-direction: column;
+ transition: transform 1.4s cubic-bezier(0.22, 1, 0.36, 1);
+ .digit-cell{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 2.05rem;
+ flex-shrink: 0;
+ }
+ }
+ }
+}
+.cumulative-illustration{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding-left: 0.25rem;
+ svg{
+ width: 3rem;
+ height: 3rem;
+ filter: drop-shadow(0 0 0.3rem rgba(26, 201, 255, 0.3));
+ }
+}
\ No newline at end of file
diff --git a/src/assets/styles/style.scss b/src/assets/styles/style.scss
new file mode 100644
index 0000000..66f20e8
--- /dev/null
+++ b/src/assets/styles/style.scss
@@ -0,0 +1,93 @@
+@import '~@/assets/iconfont/iconfont.css';
+
+// 全局样式
+* {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ box-sizing: border-box;
+ outline: none;
+}
+
+html {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+ background-color: #f1f1f1;
+ margin: 0;
+ padding: 0;
+}
+
+a {
+ color: #343440;
+ text-decoration: none;
+}
+
+ul{
+ margin: 0;
+ padding: 0;
+ li{
+ list-style: none;
+ }
+}
+
+img[src=""],img:not([src]){
+ opacity: 0;
+ border:none;
+ visibility: hidden;
+ max-width: none;
+}
+
+.clearfix {
+ &::after {
+ content: "";
+ display: table;
+ height: 0;
+ line-height: 0;
+ visibility: hidden;
+ clear: both;
+ }
+}
+
+pre{
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+ word-wrap: break-word;
+ white-space: pre-wrap;
+}
+
+/**滚动条的宽度*/
+::-webkit-scrollbar {
+ width: 4px;
+ height: 4px;
+}
+
+//滚动条的滑块
+::-webkit-scrollbar-thumb {
+ background-color: #13439E;
+ border-radius: 3px;
+}
+
+.icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ overflow: hidden;
+}
+
+//浮动
+.float-r {
+ float: right;
+}
+
+//文章一行显示,多余省略号显示
+.title-item {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/src/common/flexible.js b/src/common/flexible.js
new file mode 100644
index 0000000..fdb9fa5
--- /dev/null
+++ b/src/common/flexible.js
@@ -0,0 +1,147 @@
+(function(win, lib) {
+ var doc = win.document
+ var docEl = doc.documentElement
+ var metaEl = doc.querySelector('meta[name="viewport"]')
+ var flexibleEl = doc.querySelector('meta[name="flexible"]')
+ var dpr = 0
+ var scale = 0
+ var tid
+ var flexible = lib.flexible || (lib.flexible = {})
+
+ if (metaEl) {
+ console.warn('将根据已有的meta标签来设置缩放比例')
+ var match = metaEl
+ .getAttribute('content')
+ // eslint-disable-next-line no-useless-escape
+ .match(/initial\-scale=([\d\.]+)/)
+ if (match) {
+ scale = parseFloat(match[1])
+ dpr = parseInt(1 / scale)
+ }
+ } else if (flexibleEl) {
+ var content = flexibleEl.getAttribute('content')
+ if (content) {
+ // eslint-disable-next-line no-useless-escape
+ var initialDpr = content.match(/initial\-dpr=([\d\.]+)/)
+ // eslint-disable-next-line no-useless-escape
+ var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/)
+ if (initialDpr) {
+ dpr = parseFloat(initialDpr[1])
+ scale = parseFloat((1 / dpr).toFixed(2))
+ }
+ if (maximumDpr) {
+ dpr = parseFloat(maximumDpr[1])
+ scale = parseFloat((1 / dpr).toFixed(2))
+ }
+ }
+ }
+
+ if (!dpr && !scale) {
+ // eslint-disable-next-line no-unused-vars
+ var isAndroid = win.navigator.appVersion.match(/android/gi)
+ var isIPhone = win.navigator.appVersion.match(/iphone/gi)
+ var devicePixelRatio = win.devicePixelRatio
+ if (isIPhone) {
+ // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
+ if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
+ dpr = 3
+ } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
+ dpr = 2
+ } else {
+ dpr = 1
+ }
+ } else {
+ // 其他设备下,仍旧使用1倍的方案
+ dpr = 1
+ }
+ scale = 1 / dpr
+ }
+
+ docEl.setAttribute('data-dpr', dpr)
+ if (!metaEl) {
+ metaEl = doc.createElement('meta')
+ metaEl.setAttribute('name', 'viewport')
+ metaEl.setAttribute(
+ 'content',
+ 'initial-scale=' +
+ scale +
+ ', maximum-scale=' +
+ scale +
+ ', minimum-scale=' +
+ scale +
+ ', user-scalable=no'
+ )
+ if (docEl.firstElementChild) {
+ docEl.firstElementChild.appendChild(metaEl)
+ } else {
+ var wrap = doc.createElement('div')
+ wrap.appendChild(metaEl)
+ doc.write(wrap.innerHTML)
+ }
+ }
+
+ function refreshRem() {
+ var width = docEl.getBoundingClientRect().width
+ // 最小1366px,最大适配2560px
+ if (width / dpr < 1366) {
+ width = 1366 * dpr
+ } else if (width / dpr > 2560) {
+ width = 2560 * dpr
+ }
+ // 设置成24等份,设计稿时1920px的,这样1rem就是80px
+ var rem = width / 24
+ docEl.style.fontSize = rem + 'px'
+ flexible.rem = win.rem = rem
+ }
+
+ win.addEventListener(
+ 'resize',
+ function() {
+ clearTimeout(tid)
+ tid = setTimeout(refreshRem, 300)
+ },
+ false
+ )
+ win.addEventListener(
+ 'pageshow',
+ function(e) {
+ if (e.persisted) {
+ clearTimeout(tid)
+ tid = setTimeout(refreshRem, 300)
+ }
+ },
+ false
+ )
+
+ if (doc.readyState === 'complete') {
+ doc.body.style.fontSize = 12 * dpr + 'px'
+ } else {
+ doc.addEventListener(
+ 'DOMContentLoaded',
+ // eslint-disable-next-line no-unused-vars
+ function(e) {
+ doc.body.style.fontSize = 12 * dpr + 'px'
+ },
+ false
+ )
+ }
+
+ refreshRem()
+
+ flexible.dpr = win.dpr = dpr
+ flexible.refreshRem = refreshRem
+ flexible.rem2px = function(d) {
+ var val = parseFloat(d) * this.rem
+ if (typeof d === 'string' && d.match(/rem$/)) {
+ val += 'px'
+ }
+ return val
+ }
+ flexible.px2rem = function(d) {
+ var val = parseFloat(d) / this.rem
+ if (typeof d === 'string' && d.match(/px$/)) {
+ val += 'rem'
+ }
+ return val
+ }
+})(window, window['lib'] || (window['lib'] = {}))
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..84a19b6
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,49 @@
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import store from './store'
+
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+Vue.use(ElementUI)
+
+// 适配flex
+import '@/common/flexible.js'
+
+// 引入全局css
+import './assets/styles/style.scss'
+import './assets/iconfont/iconfont.js'
+import './assets/fonts/fonts.css'
+
+// 按需引入然后注册在vue原型上
+import { Message } from 'element-ui'
+Vue.prototype.$message = Message
+
+// 全局注册过滤 - 时间
+import { parseTime, getFormattedDate } from '@/utils/index.js'
+Vue.filter('parseTime', function(time, cFormat) {
+ return parseTime(time, cFormat)
+})
+Vue.prototype.getFormattedDate = getFormattedDate
+
+// 馆代码 1201为东西湖馆代码 / 本地测试用FTZN
+// Vue.prototype.libcode = 'FTZN'
+Vue.prototype.libcode = '1201'
+
+import axios from 'axios'
+Vue.prototype.$axios = axios
+
+// 引入echart
+import echarts from 'echarts'
+Vue.prototype.$echarts = echarts
+
+import scroll from 'vue-seamless-scroll'
+Vue.use(scroll)
+
+Vue.config.productionTip = false
+Vue.component(Message.name, Message)
+new Vue({
+ router,
+ store,
+ render: (h) => h(App)
+}).$mount('#app')
diff --git a/src/router/index.js b/src/router/index.js
new file mode 100644
index 0000000..2611efe
--- /dev/null
+++ b/src/router/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+
+Vue.use(VueRouter)
+
+const routes = [
+ {
+ path: '/',
+ name: 'index',
+ component: () => import('../views/index.vue'),
+ meta: {
+ title: '人流数据大屏'
+ }
+ }
+]
+
+const router = new VueRouter({
+ mode: 'hash',
+ routes
+})
+
+export default router
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..b2f39d8
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,15 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ state: {
+ },
+ mutations: {
+ },
+ actions: {
+ },
+ modules: {
+ }
+})
diff --git a/src/utils/index.js b/src/utils/index.js
new file mode 100644
index 0000000..6f2d4e5
--- /dev/null
+++ b/src/utils/index.js
@@ -0,0 +1,100 @@
+export function debounce(func, wait, immediate) {
+ let timeout, args, context, timestamp, result
+
+ const later = function() {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp
+
+ // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last)
+ } else {
+ timeout = null
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args)
+ if (!timeout) context = args = null
+ }
+ }
+ }
+
+ return function(...args) {
+ context = this
+ timestamp = +new Date()
+ const callNow = immediate && !timeout
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait)
+ if (callNow) {
+ result = func.apply(context, args)
+ context = args = null
+ }
+
+ return result
+ }
+}
+
+/**
+ * Parse the time to string
+ * @param {(Object|string|number)} time
+ * @param {string} cFormat
+ * @returns {string}
+ */
+export function parseTime(time, cFormat) {
+ if (arguments.length === 0) {
+ return null
+ }
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'undefined' || time === null || time === 'null') {
+ return ''
+ } else if (typeof time === 'object') {
+ date = time
+ } else {
+ if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+ time = parseInt(time)
+ }
+ if ((typeof time === 'number') && (time.toString().length === 10)) {
+ time = time * 1000
+ }
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return time_str
+}
+
+// 获取当前日期时间
+export function getCurrentTime() {
+ const yy = new Date().getFullYear()
+ const mm = new Date().getMonth() + 1
+ const dd = new Date().getDate()
+ const hh = new Date().getHours()
+ const mf = new Date().getMinutes() < 10 ? '0' + new Date().getMinutes() : new Date().getMinutes()
+ const ss = new Date().getSeconds() < 10 ? '0' + new Date().getSeconds() : new Date().getSeconds()
+ const time = yy + '年' + mm + '月' + dd + '日 ' + hh + ':' + mf + ':' + ss
+ return time
+}
+
+export function getFormattedDate(date, yearOffset = 0) {
+ date.setFullYear(date.getFullYear() + yearOffset)
+ const year = date.getFullYear()
+ const month = (date.getMonth() + 1).toString().padStart(2, '0')
+ const day = date.getDate().toString().padStart(2, '0')
+ return `${year}-${month}-${day}`
+}
diff --git a/src/utils/request.js b/src/utils/request.js
new file mode 100644
index 0000000..5571de8
--- /dev/null
+++ b/src/utils/request.js
@@ -0,0 +1,39 @@
+import axios from 'axios'
+// import { Message } from 'element-ui'
+
+// 创建axios实例
+// 生产环境 baseURL 走 public/static/config.js 的 window.g.ApiUrl,部署后改 config 即可切换后端,无需重新打包
+const service = axios.create({
+ baseURL: process.env.NODE_ENV === 'production' ? ((window.g && window.g.ApiUrl) || '') : '/',
+ timeout: (window.g && window.g.AXIOS_TIMEOUT) || 1000 * 30, // 请求超时时间
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+})
+
+// request拦截器
+service.interceptors.request.use(
+ config => {
+ // if (getToken()) {
+ // config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+ // }
+ const token = '' // 登录后生成用于识别用户身份,项目不需要直接去掉
+ config.headers['Authorization'] = token || ''
+ return config
+ },
+ error => {
+ console.error('error: ', error)
+ Promise.reject(error)
+ }
+)
+
+// response 拦截器
+service.interceptors.response.use(
+ response => {
+ return response.data
+ },
+ error => {
+ return Promise.reject(error)
+ }
+)
+export default service
diff --git a/src/utils/resizeMixins.js b/src/utils/resizeMixins.js
new file mode 100644
index 0000000..dbdffd8
--- /dev/null
+++ b/src/utils/resizeMixins.js
@@ -0,0 +1,26 @@
+// 混入代码 resize-mixins.js
+import { debounce } from '@/utils/index'
+const resizeChartMethod = '$__resizeChartMethod'
+
+export default {
+ data() {
+ // 在组件内部将图表init的引用映射到chart属性上
+ return {
+ chart: null
+ }
+ },
+ created() {
+ window.addEventListener('resize', this[resizeChartMethod], false)
+ },
+ beforeDestroy() {
+ window.removeEventListener('reisze', this[resizeChartMethod])
+ },
+ methods: {
+ // 通过lodash的防抖函数来控制resize的频率
+ [resizeChartMethod]: debounce(function() {
+ if (this.chart) {
+ this.chart.resize()
+ }
+ }, 100)
+ }
+}
diff --git a/src/views/header/index.vue b/src/views/header/index.vue
new file mode 100644
index 0000000..d69b897
--- /dev/null
+++ b/src/views/header/index.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
diff --git a/src/views/index.vue b/src/views/index.vue
new file mode 100644
index 0000000..a87a8f3
--- /dev/null
+++ b/src/views/index.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/trafficFlow/components/DayInFlowCard.vue b/src/views/trafficFlow/components/DayInFlowCard.vue
new file mode 100644
index 0000000..b3514b3
--- /dev/null
+++ b/src/views/trafficFlow/components/DayInFlowCard.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/src/views/trafficFlow/components/MonthInFlowChart.vue b/src/views/trafficFlow/components/MonthInFlowChart.vue
new file mode 100644
index 0000000..76f6c58
--- /dev/null
+++ b/src/views/trafficFlow/components/MonthInFlowChart.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
diff --git a/src/views/trafficFlow/components/TotalFlowSummary.vue b/src/views/trafficFlow/components/TotalFlowSummary.vue
new file mode 100644
index 0000000..c588a8c
--- /dev/null
+++ b/src/views/trafficFlow/components/TotalFlowSummary.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
diff --git a/src/views/trafficFlow/components/YearInFlowChart.vue b/src/views/trafficFlow/components/YearInFlowChart.vue
new file mode 100644
index 0000000..51fb5bc
--- /dev/null
+++ b/src/views/trafficFlow/components/YearInFlowChart.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
diff --git a/src/views/trafficFlow/index.vue b/src/views/trafficFlow/index.vue
new file mode 100644
index 0000000..98426d3
--- /dev/null
+++ b/src/views/trafficFlow/index.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
diff --git a/vue.config.js b/vue.config.js
new file mode 100644
index 0000000..239c12b
--- /dev/null
+++ b/vue.config.js
@@ -0,0 +1,68 @@
+const path = require('path')
+const resolve = dir => {
+ return path.join(__dirname, dir)
+}
+const name = '人流数据大屏'
+module.exports = {
+ publicPath: process.env.NODE_ENV === 'development' ? '/' : './',
+ outputDir: 'dist',
+ assetsDir: 'static',
+ lintOnSave: process.env.NODE_ENV === 'development',
+ productionSourceMap: false,
+ devServer: {
+ port: 8080,
+ open: true,
+ overlay: {
+ warnings: false,
+ errors: true
+ },
+ proxy: {
+ '/dxhtsg/': {
+ target: process.env.VUE_APP_BASE_API,
+ changeOrigin: true,
+ pathRewrite: {
+ '^/dxhtsg': 'dxhtsg'
+ }
+ },
+ '/qyzt/': {
+ target: process.env.VUE_APP_BASE_API,
+ changeOrigin: true,
+ pathRewrite: {
+ '^/qyzt': 'qyzt'
+ }
+ },
+ '/auth/': {
+ target: process.env.VUE_APP_BASE_API,
+ changeOrigin: true,
+ pathRewrite: {
+ '^/auth': 'auth'
+ }
+ }
+ }
+ },
+ configureWebpack: {
+ name: name,
+ resolve: {
+ alias: {
+ '@': resolve('src')
+ }
+ },
+ performance: {
+ hints: 'warning',
+ // 入口起点的最大体积
+ maxEntrypointSize: 50000000,
+ // 生成文件的最大体积
+ maxAssetSize: 30000000
+ }
+ },
+ chainWebpack: config => {
+ config.resolve
+ .alias.set('_c', resolve('src/components'))
+
+ config.plugin('html')
+ .tap(args => {
+ args[0].title = '人流数据大屏'
+ return args
+ })
+ }
+}