-
9.env.development
-
9.env.production
-
197.eslintrc.js
-
23.gitignore
-
37README.md
-
11babel.config.js
-
56package.json
-
BINpublic/favicon.ico
-
19public/index.html
-
4public/static/config.js
-
16src/App.vue
-
84src/api/inquiryMachine.js
-
BINsrc/assets/404_images/404.png
-
BINsrc/assets/404_images/404_cloud.png
-
BINsrc/assets/fonts/HuXiaoBoNanShenTi.otf
-
BINsrc/assets/fonts/YouSheBiaoTiHei.ttf
-
BINsrc/assets/fonts/ZhenyanGB.ttf
-
19src/assets/fonts/fonts.css
-
80src/assets/iconfont/iconfont.css
-
1src/assets/iconfont/iconfont.js
-
121src/assets/iconfont/iconfont.json
-
51src/assets/iconfont/iconfont.svg
-
BINsrc/assets/iconfont/iconfont.ttf
-
BINsrc/assets/iconfont/iconfont.woff
-
BINsrc/assets/iconfont/iconfont.woff2
-
BINsrc/assets/images/default-img.png
-
BINsrc/assets/images/empty.png
-
BINsrc/assets/images/index/320 180 down.png
-
BINsrc/assets/images/index/320 180 up.png
-
BINsrc/assets/images/index/400 620 left.png
-
BINsrc/assets/images/index/400 620 right.png
-
BINsrc/assets/images/index/760 180 down.png
-
BINsrc/assets/images/index/760 180 up.png
-
BINsrc/assets/images/index/activities.png
-
BINsrc/assets/images/index/bg.png
-
BINsrc/assets/images/index/brief.png
-
BINsrc/assets/images/index/digital.png
-
BINsrc/assets/images/index/guide.png
-
BINsrc/assets/images/index/logo.png
-
BINsrc/assets/images/index/newbook.png
-
BINsrc/assets/images/index/search.png
-
BINsrc/assets/images/index/title.png
-
BINsrc/assets/images/list-title.png
-
BINsrc/assets/images/local-bg.png
-
BINsrc/assets/images/top.png
-
BINsrc/assets/logo.png
-
87src/assets/styles/index.scss
-
209src/assets/styles/quillEditor.css
-
80src/assets/styles/style.scss
-
147src/common/flexible.js
-
61src/common/scrollMixins.js
-
41src/main.js
-
98src/router/index.js
-
48src/store/column.js
-
13src/store/index.js
-
92src/utils/index.js
-
55src/utils/request.js
-
26src/utils/resizeMixins.js
-
90src/views/columnLayout.vue
-
173src/views/columnListMix.vue
-
93src/views/columnListMixDetail.vue
-
64src/views/imgTxtDetail.vue
-
293src/views/index.vue
-
174src/views/menu.vue
-
228src/views/module/bookDetails.vue
-
434src/views/module/waterfall.vue
-
282src/views/newBookRecommend.vue
-
158src/views/old.vue
-
342src/views/waterfallFlow.vue
-
160src/views/waterfallFlow2.vue
-
61vue.config.js
@ -0,0 +1,9 @@ |
|||||
|
ENV = 'development' |
||||
|
|
||||
|
# 接口地址 |
||||
|
|
||||
|
# 许镇-本地服地址 |
||||
|
VUE_APP_BASE_API = 'http://192.168.99.72:14000' |
||||
|
|
||||
|
# 是否启用 babel-plugin-dynamic-import-node插件 |
||||
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true |
||||
@ -0,0 +1,9 @@ |
|||||
|
ENV = 'production' |
||||
|
|
||||
|
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇,Nginx 配置 |
||||
|
# 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http |
||||
|
# VUE_APP_BASE_API = 'https://openapitest.aiyxlib.com' |
||||
|
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://192.168.99.107:7071' |
||||
@ -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'] |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
@ -0,0 +1,37 @@ |
|||||
|
自助查询机 |
||||
|
|
||||
|
```bash |
||||
|
# install dependency |
||||
|
npm install |
||||
|
|
||||
|
# develop |
||||
|
npm run serve |
||||
|
|
||||
|
# 构建生产环境 |
||||
|
npm run build |
||||
|
|
||||
|
``` |
||||
|
```bash |
||||
|
## 项目结构 |
||||
|
├── src # 源代码 |
||||
|
│ ├── api # 所有请求 |
||||
|
│ ├── assets # 主题 字体等静态资源 |
||||
|
│ ├── router # 路由 |
||||
|
│ ├── views # views 所有页面 |
||||
|
│ │ ├── module |
||||
|
│ │ │ ├── bookDetails.vue # 书籍详情 |
||||
|
│ │ ├── activityDetail # 活动详情 |
||||
|
│ │ ├── activityFeed # 活动资讯list |
||||
|
│ │ ├── digitalResource # 数字资源 |
||||
|
│ │ ├── libraryIntroduction # 图书馆简介 |
||||
|
│ │ ├── newBookRecommend # 新书推荐 |
||||
|
│ ├── App.vue # 入口页面 |
||||
|
│ ├── main.js # 入口文件 加载组件 初始化等 注意:Vue.prototype.libcode使用 |
||||
|
├── .env.xxx # 环境变量配置 |
||||
|
├── .eslintrc.js # eslint 配置项 |
||||
|
├── .babelrc # babel-loader 配置 |
||||
|
├── .travis.yml # 自动化CI配置 |
||||
|
├── vue.config.js # vue-cli 配置 |
||||
|
├── postcss.config.js # postcss 配置 |
||||
|
└── package.json # package.json |
||||
|
``` |
||||
@ -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' |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
{ |
||||
|
"name": "intelligence-inquiry-machine", |
||||
|
"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": "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.9", |
||||
|
"swiper": "^8.4.2", |
||||
|
"vue": "^2.6.11", |
||||
|
"vue-awesome": "^4.0.2", |
||||
|
"vue-awesome-swiper": "^3.1.3", |
||||
|
"vue-router": "^3.1.5", |
||||
|
"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-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" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<meta name="referrer" content="no-referrer"> |
||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
||||
|
<title><%= htmlWebpackPlugin.options.title %></title> |
||||
|
<script type="text/javascript" src="/static/config.js"></script> |
||||
|
</head> |
||||
|
<body> |
||||
|
<noscript> |
||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
||||
|
</noscript> |
||||
|
<div id="app"></div> |
||||
|
<!-- built files will be auto injected --> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,4 @@ |
|||||
|
window.g = { |
||||
|
AXIOS_TIMEOUT: 10000, |
||||
|
ApiUrl: 'http://192.168.3.5:8080' // 配置服务器地址
|
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<template> |
||||
|
<div id="app"> |
||||
|
<router-view /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
body { |
||||
|
margin: 0; |
||||
|
} |
||||
|
#app { |
||||
|
font-family: Avenir, Helvetica, Arial, sans-serif; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,84 @@ |
|||||
|
import request from '@/utils/request' |
||||
|
import qs from 'qs' |
||||
|
|
||||
|
// 查询机栏目管理详情
|
||||
|
export function FetchQueryTopicDetails(params) { |
||||
|
return request({ |
||||
|
url: '/api/queryMachine/getQueryMenuDetails', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 根据栏目id获取内容
|
||||
|
export function FetchInitQueryTopicContext(params) { |
||||
|
return request({ |
||||
|
url: '/api/queryMachine/initQueryTopicContext', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新书推荐
|
||||
|
export function FetchNewBook(params) { |
||||
|
return request({ |
||||
|
url: '/api/screenSetting/getNewBook' + '?' + qs.stringify(params, { indices: false }), |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 通过isbn获取图书详细信息
|
||||
|
export function FetchMarcByISBN(params) { |
||||
|
return request({ |
||||
|
url: '/api/screenSetting/marcByISBN' + '?' + qs.stringify(params, { indices: false }), |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 数字资源
|
||||
|
export function initNumberResoures(params) { |
||||
|
return request({ |
||||
|
url: '/dxhtsg/initNumberResoures', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新书推荐
|
||||
|
export function FetchNewBookRecommend(params) { |
||||
|
return request({ |
||||
|
url: '/dxhtsg/newBookRecommend', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 通过isbn获取图书封面
|
||||
|
export function FetchCoverByISBN(params) { |
||||
|
return request({ |
||||
|
url: '/dxhtsg/getCoverByISBN', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
// responseType: 'blob'
|
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 图书详情
|
||||
|
export function getBookDetailsByISBN(params) { |
||||
|
return request({ |
||||
|
url: '/api/bookBasice/getBookBasiceByISBN', |
||||
|
method: 'get', |
||||
|
params: params |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export default { |
||||
|
FetchQueryTopicDetails, |
||||
|
FetchInitQueryTopicContext, |
||||
|
FetchNewBook, |
||||
|
FetchMarcByISBN, |
||||
|
FetchNewBookRecommend, |
||||
|
FetchCoverByISBN, |
||||
|
initNumberResoures, |
||||
|
getBookDetailsByISBN |
||||
|
} |
||||
|
After Width: 1014 | Height: 556 | Size: 96 KiB |
|
After Width: 152 | Height: 138 | Size: 4.7 KiB |
@ -0,0 +1,19 @@ |
|||||
|
@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; |
||||
|
} |
||||
|
@font-face { |
||||
|
font-family: "HuXiaoBoNanShenTi"; |
||||
|
src: url('HuXiaoBoNanShenTi.otf'); |
||||
|
font-weight: normal; |
||||
|
font-style: normal; |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
@font-face { |
||||
|
font-family: "iconfont"; /* Project id 3646564 */ |
||||
|
src: url('iconfont.woff2?t=1664428017869') format('woff2'), |
||||
|
url('iconfont.woff?t=1664428017869') format('woff'), |
||||
|
url('iconfont.ttf?t=1664428017869') format('truetype'), |
||||
|
url('iconfont.svg?t=1664428017869#iconfont') format('svg'); |
||||
|
} |
||||
|
|
||||
|
.iconfont { |
||||
|
font-family: "iconfont" !important; |
||||
|
font-size: 16px; |
||||
|
font-style: normal; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
} |
||||
|
|
||||
|
.icon-weizhi:before { |
||||
|
content: "\e639"; |
||||
|
} |
||||
|
|
||||
|
.icon-youhua:before { |
||||
|
content: "\e635"; |
||||
|
} |
||||
|
|
||||
|
.icon-zuohua:before { |
||||
|
content: "\e638"; |
||||
|
} |
||||
|
|
||||
|
.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"; |
||||
|
} |
||||
|
|
||||
1
src/assets/iconfont/iconfont.js
File diff suppressed because it is too large
View File
@ -0,0 +1,121 @@ |
|||||
|
{ |
||||
|
"id": "3646564", |
||||
|
"name": "东西湖图书馆", |
||||
|
"font_family": "iconfont", |
||||
|
"css_prefix_text": "icon-", |
||||
|
"description": "", |
||||
|
"glyphs": [ |
||||
|
{ |
||||
|
"icon_id": "32102019", |
||||
|
"name": "位置", |
||||
|
"font_class": "weizhi", |
||||
|
"unicode": "e639", |
||||
|
"unicode_decimal": 58937 |
||||
|
}, |
||||
|
{ |
||||
|
"icon_id": "31966175", |
||||
|
"name": "右滑", |
||||
|
"font_class": "youhua", |
||||
|
"unicode": "e635", |
||||
|
"unicode_decimal": 58933 |
||||
|
}, |
||||
|
{ |
||||
|
"icon_id": "31966176", |
||||
|
"name": "左滑", |
||||
|
"font_class": "zuohua", |
||||
|
"unicode": "e638", |
||||
|
"unicode_decimal": 58936 |
||||
|
}, |
||||
|
{ |
||||
|
"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 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
51
src/assets/iconfont/iconfont.svg
File diff suppressed because it is too large
View File
|
After Width: 440 | Height: 526 | Size: 51 KiB |
|
After Width: 200 | Height: 200 | Size: 6.0 KiB |
|
After Width: 324 | Height: 184 | Size: 24 KiB |
|
After Width: 324 | Height: 184 | Size: 26 KiB |
|
After Width: 404 | Height: 624 | Size: 60 KiB |
|
After Width: 404 | Height: 624 | Size: 33 KiB |
|
After Width: 764 | Height: 184 | Size: 31 KiB |
|
After Width: 764 | Height: 184 | Size: 28 KiB |
|
After Width: 215 | Height: 201 | Size: 8.2 KiB |
|
After Width: 1920 | Height: 1080 | Size: 680 KiB |
|
After Width: 234 | Height: 201 | Size: 8.1 KiB |
|
After Width: 245 | Height: 200 | Size: 11 KiB |
|
After Width: 153 | Height: 200 | Size: 8.6 KiB |
|
After Width: 675 | Height: 90 | Size: 12 KiB |
|
After Width: 225 | Height: 200 | Size: 8.7 KiB |
|
After Width: 240 | Height: 201 | Size: 9.9 KiB |
|
After Width: 445 | Height: 111 | Size: 11 KiB |
|
After Width: 494 | Height: 76 | Size: 15 KiB |
|
After Width: 83 | Height: 346 | Size: 6.5 KiB |
|
After Width: 1920 | Height: 200 | Size: 263 KiB |
|
After Width: 200 | Height: 200 | Size: 6.7 KiB |
@ -0,0 +1,87 @@ |
|||||
|
#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; |
||||
|
} |
||||
|
|
||||
|
.content-main{ |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
height: 880px; |
||||
|
background: #F4F4F4; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.introduction-main { |
||||
|
padding: 30px 40px; |
||||
|
.nav-menu { |
||||
|
background: #ffffff; |
||||
|
width: 300px; |
||||
|
ul { |
||||
|
margin-top: 30px; |
||||
|
li { |
||||
|
height: 90px; |
||||
|
font-size: 30px; |
||||
|
font-family: Source Han Sans CN-Regular, Source Han Sans CN; |
||||
|
font-weight: 400; |
||||
|
line-height: 90px; |
||||
|
text-align: center; |
||||
|
margin-bottom: 20px; |
||||
|
&:hover { |
||||
|
background: #e4e4e4; |
||||
|
} |
||||
|
&.is-active { |
||||
|
background: linear-gradient( |
||||
|
318deg, |
||||
|
#38b8d9 0%, |
||||
|
#5394f1 45%, |
||||
|
#a0a9ef 100% |
||||
|
); |
||||
|
color: #ffffff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.introduction-info { |
||||
|
margin-left: 30px; |
||||
|
background: #ffffff; |
||||
|
width: 1510px; |
||||
|
padding: 20px; |
||||
|
overflow-y: auto; |
||||
|
.info-title { |
||||
|
height: 100px; |
||||
|
text-align: center; |
||||
|
font-size: 38px; |
||||
|
font-family: Source Han Sans CN-Regular, Source Han Sans CN; |
||||
|
font-weight: 400; |
||||
|
color: #333333; |
||||
|
line-height: 100px; |
||||
|
} |
||||
|
.info-img { |
||||
|
background: url("~@/assets/images/top.png") no-repeat center -5px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.activity-list li { |
||||
|
height: 90px; |
||||
|
margin: 0 40px; |
||||
|
border-bottom: 1px solid #d9d9d9; |
||||
|
font-size: 30px; |
||||
|
line-height: 90px; |
||||
|
padding: 0 20px; |
||||
|
span.date { |
||||
|
float: right; |
||||
|
} |
||||
|
.activity-title { |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
width: calc(100% - 282px); |
||||
|
display: inline-block; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,209 @@ |
|||||
|
.ql-align-center{ |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before { |
||||
|
content: "黑体"; |
||||
|
font-family: "SimHei"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before { |
||||
|
content: "微软雅黑"; |
||||
|
font-family: "Microsoft YaHei"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before { |
||||
|
content: "楷体"; |
||||
|
font-family: "KaiTi"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before { |
||||
|
content: "仿宋"; |
||||
|
font-family: "FangSong"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before { |
||||
|
content: "Arial"; |
||||
|
font-family: "Arial"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before { |
||||
|
content: "Times New Roman"; |
||||
|
font-family: "Times New Roman"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before, |
||||
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before { |
||||
|
content: "sans-serif"; |
||||
|
font-family: "sans-serif"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-SimSun { |
||||
|
font-family: "SimSun"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-SimHei { |
||||
|
font-family: "SimHei"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-Microsoft-YaHei { |
||||
|
font-family: "Microsoft YaHei"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-KaiTi { |
||||
|
font-family: "KaiTi"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-FangSong { |
||||
|
font-family: "FangSong"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-Arial { |
||||
|
font-family: "Arial"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-Times-New-Roman { |
||||
|
font-family: "Times New Roman"; |
||||
|
} |
||||
|
|
||||
|
.ql-font-sans-serif { |
||||
|
font-family: "sans-serif"; |
||||
|
} |
||||
|
|
||||
|
/* 字号设置 */ |
||||
|
/* 默认字号 */ |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label::before, |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item::before { |
||||
|
content: "12px"; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before{ |
||||
|
content: "12px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before{ |
||||
|
content: "14px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before{ |
||||
|
content: "16px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before{ |
||||
|
content: "18px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before{ |
||||
|
content: "20px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="22px"]::before{ |
||||
|
content: "22px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before{ |
||||
|
content: "26px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="28px"]::before{ |
||||
|
content: "28px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="30px"]::before{ |
||||
|
content: "30px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before { |
||||
|
content: "12px"; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-12px { |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before { |
||||
|
content: "14px"; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-14px { |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before { |
||||
|
content: "16px"; |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-16px { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before { |
||||
|
content: "18px"; |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-18px { |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { |
||||
|
content: "20px"; |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-20px { |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="22px"]::before { |
||||
|
content: "22px"; |
||||
|
font-size: 22px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-22px { |
||||
|
font-size: 22px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="26px"]::before { |
||||
|
content: "26px"; |
||||
|
font-size: 26px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-26px { |
||||
|
font-size: 26px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="28px"]::before { |
||||
|
content: "28px"; |
||||
|
font-size: 28px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-28px { |
||||
|
font-size: 28px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="30px"]::before { |
||||
|
content: "30px"; |
||||
|
font-size: 30px; |
||||
|
} |
||||
|
|
||||
|
.ql-size-30px { |
||||
|
font-size: 30px; |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
@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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.clearfix { |
||||
|
&::after { |
||||
|
content: ""; |
||||
|
display: table; |
||||
|
height: 0; |
||||
|
line-height: 0; |
||||
|
visibility: hidden; |
||||
|
clear: both; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/**滚动条的宽度*/ |
||||
|
::-webkit-scrollbar { |
||||
|
width: 10px; |
||||
|
height: 10px; |
||||
|
} |
||||
|
|
||||
|
//滚动条的滑块 |
||||
|
::-webkit-scrollbar-thumb { |
||||
|
background-color: #44A9E4; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
.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; |
||||
|
} |
||||
@ -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'] = {})) |
||||
@ -0,0 +1,61 @@ |
|||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
scrollDom: null, |
||||
|
interval: null, |
||||
|
scrollTimer: null, // 滚动定时器
|
||||
|
pauseTimer: null, // 暂停定时器
|
||||
|
timeout: null, |
||||
|
step: null |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
}, |
||||
|
mounted() { |
||||
|
// this.dataCompleteFun()
|
||||
|
}, |
||||
|
destroyed() { |
||||
|
// 清理定时器
|
||||
|
clearTimeout(this.pauseTimer) |
||||
|
this.pauseTimer = null |
||||
|
clearInterval(this.scrollTimer) |
||||
|
this.scrollTimer = null |
||||
|
// 清理点击监听
|
||||
|
window.document.removeEventListener('click', this.pauseScroll) |
||||
|
}, |
||||
|
methods: { |
||||
|
autoScroll() { |
||||
|
// 滚动长度为0
|
||||
|
if (this.scrollDom.scrollHeight - this.scrollDom.clientHeight > 0) { |
||||
|
// 如果定时器存在
|
||||
|
if (this.scrollTimer) { |
||||
|
// 则先清除
|
||||
|
clearInterval(this.scrollTimer) |
||||
|
clearTimeout(this.pauseTimer) |
||||
|
this.scrollTimer = null |
||||
|
this.pauseTimer = null |
||||
|
} |
||||
|
this.scrollTimer = setInterval(() => { |
||||
|
const scrollHeight = this.scrollDom.scrollHeight |
||||
|
const clientHeight = this.scrollDom.clientHeight |
||||
|
const scroll = scrollHeight - clientHeight |
||||
|
// 获取当前滚动条距离顶部高度
|
||||
|
const scrollTop = this.scrollDom.scrollTop |
||||
|
// 当滚动到底部时,间隔时间后重回顶部开始
|
||||
|
if (scrollTop + this.step >= scroll) { |
||||
|
this.scrollDom.scrollTop = scroll |
||||
|
this.pauseTimer = setTimeout(() => { |
||||
|
this.scrollDom.scrollTop = 0 |
||||
|
this.autoScroll() |
||||
|
}, this.timeout) |
||||
|
} else { // 没有则继续滚动
|
||||
|
this.scrollDom.scrollTop = scrollTop + this.step |
||||
|
} |
||||
|
// console.log(scrollHeight, clientHeight, scroll, scrollTop)
|
||||
|
}, this.interval) |
||||
|
} else { |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
import Vue from 'vue' |
||||
|
import App from './App.vue' |
||||
|
import router from './router' |
||||
|
import store from './store' |
||||
|
|
||||
|
// 适配flex
|
||||
|
import '@/common/flexible.js' |
||||
|
|
||||
|
// 引入全局css
|
||||
|
import './assets/styles/style.scss' |
||||
|
import './assets/iconfont/iconfont.js' |
||||
|
import './assets/fonts/fonts.css' |
||||
|
import './assets/styles/quillEditor.css' |
||||
|
|
||||
|
import ElementUI from 'element-ui' |
||||
|
import 'element-ui/lib/theme-chalk/index.css' |
||||
|
Vue.use(ElementUI) |
||||
|
|
||||
|
import axios from 'axios' |
||||
|
Vue.prototype.$axios = axios |
||||
|
|
||||
|
// 馆代码 1501 江夏图书馆 1201 东西湖图书馆 FTZN 本地
|
||||
|
// Vue.prototype.libcode = 'FTZN'
|
||||
|
// Vue.prototype.libcode = '1501'
|
||||
|
|
||||
|
import { parseTime } from '@/utils/index.js' |
||||
|
Vue.filter('parseTime', function(time, cFormat) { |
||||
|
return parseTime(time, cFormat) |
||||
|
}) |
||||
|
|
||||
|
// 引入echart
|
||||
|
import echarts from 'echarts' |
||||
|
Vue.prototype.$echarts = echarts |
||||
|
|
||||
|
Vue.config.productionTip = false |
||||
|
|
||||
|
new Vue({ |
||||
|
router, |
||||
|
store, |
||||
|
render: (h) => h(App) |
||||
|
}).$mount('#app') |
||||
@ -0,0 +1,98 @@ |
|||||
|
import Vue from 'vue' |
||||
|
import VueRouter from 'vue-router' |
||||
|
import ColumnLayout from '@/views/columnLayout' |
||||
|
import ColumnListMix from '@/views/columnListMix' |
||||
|
import ColumnListMixDetail from '@/views/columnListMixDetail' |
||||
|
|
||||
|
Vue.use(VueRouter) |
||||
|
|
||||
|
const routes = [ |
||||
|
{ |
||||
|
path: '/', |
||||
|
name: 'index', |
||||
|
component: () => import('@/views/index.vue'), |
||||
|
meta: { |
||||
|
title: '首页' |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
path: '/NewBookRecommend', |
||||
|
name: 'NewBookRecommend', |
||||
|
component: () => import('@/views/newBookRecommend.vue'), |
||||
|
meta: { |
||||
|
title: '新书推荐' |
||||
|
} |
||||
|
}, |
||||
|
// {
|
||||
|
// path: '/DigitalResource',
|
||||
|
// name: 'DigitalResource',
|
||||
|
// component: () => import('@/views/digitalResource.vue'),
|
||||
|
// meta: {
|
||||
|
// title: '数字资源'
|
||||
|
// }
|
||||
|
// },
|
||||
|
// {
|
||||
|
// path: '/LibraryIntroduction',
|
||||
|
// name: 'LibraryIntroduction',
|
||||
|
// component: () => import('@/views/libraryIntroduction.vue'),
|
||||
|
// meta: {
|
||||
|
// title: '图书馆简介'
|
||||
|
// }
|
||||
|
// },
|
||||
|
// {
|
||||
|
// path: '/ActivityFeed',
|
||||
|
// name: 'ActivityFeed',
|
||||
|
// component: () => import('@/views/activityFeed.vue'),
|
||||
|
// meta: {
|
||||
|
// title: '活动咨询'
|
||||
|
// }
|
||||
|
// },
|
||||
|
// {
|
||||
|
// path: '/ActivityDetail',
|
||||
|
// name: 'ActivityDetail',
|
||||
|
// component: () => import('@/views/activityDetail.vue'),
|
||||
|
// meta: {
|
||||
|
// title: '活动详情'
|
||||
|
// }
|
||||
|
// },
|
||||
|
{ |
||||
|
path: '/menu', |
||||
|
name: 'menu', |
||||
|
component: () => import('@/views/menu.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/imgTxtDetail', |
||||
|
name: 'imgTxtDetail', |
||||
|
component: () => import('@/views/imgTxtDetail.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/column', |
||||
|
name: 'ColumnLayout', |
||||
|
component: ColumnLayout, |
||||
|
redirect: '/column/list', |
||||
|
children: [ |
||||
|
{ |
||||
|
path: 'list', |
||||
|
name: 'ColumnListMix', |
||||
|
component: ColumnListMix |
||||
|
}, |
||||
|
{ |
||||
|
path: 'detail', |
||||
|
name: 'ColumnListMixDetail', |
||||
|
component: ColumnListMixDetail |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
path: '/waterfallFlow', |
||||
|
name: 'waterfallFlow', |
||||
|
component: () => import('@/views/waterfallFlow.vue') |
||||
|
} |
||||
|
] |
||||
|
|
||||
|
const router = new VueRouter({ |
||||
|
mode: 'hash', |
||||
|
routes |
||||
|
}) |
||||
|
|
||||
|
export default router |
||||
@ -0,0 +1,48 @@ |
|||||
|
|
||||
|
// 初始状态
|
||||
|
const state = { |
||||
|
tabList: [], |
||||
|
libcode: '', |
||||
|
selectMenuIndex: 0 |
||||
|
} |
||||
|
|
||||
|
// mutations
|
||||
|
const mutations = { |
||||
|
// 设置专栏数据
|
||||
|
setColumnData(state, payload) { |
||||
|
state.tabList = payload.tabList || [] |
||||
|
state.libcode = payload.libcode || '' |
||||
|
state.selectMenuIndex = payload.selectMenuIndex || 0 |
||||
|
}, |
||||
|
|
||||
|
// 更新选中的菜单索引
|
||||
|
setSelectMenuIndex(state, index) { |
||||
|
state.selectMenuIndex = index |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// actions
|
||||
|
const actions = { |
||||
|
updateColumnData({ commit }, data) { |
||||
|
commit('setColumnData', data) |
||||
|
}, |
||||
|
|
||||
|
updateSelectIndex({ commit }, index) { |
||||
|
commit('setSelectMenuIndex', index) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// getters
|
||||
|
const getters = { |
||||
|
getTabList: state => state.tabList, |
||||
|
getLibcode: state => state.libcode, |
||||
|
getSelectIndex: state => state.selectMenuIndex |
||||
|
} |
||||
|
|
||||
|
export default { |
||||
|
namespaced: true, |
||||
|
state, |
||||
|
mutations, |
||||
|
actions, |
||||
|
getters |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
import Vue from 'vue' |
||||
|
import Vuex from 'vuex' |
||||
|
import column from './column' |
||||
|
|
||||
|
Vue.use(Vuex) |
||||
|
|
||||
|
// 创建并导出store实例
|
||||
|
export default new Vuex.Store({ |
||||
|
modules: { |
||||
|
column // 注册column模块
|
||||
|
} |
||||
|
}) |
||||
|
|
||||
@ -0,0 +1,92 @@ |
|||||
|
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 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 获取当前日期时间
|
||||
|
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 |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 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 |
||||
|
} |
||||
@ -0,0 +1,55 @@ |
|||||
|
import axios from 'axios' |
||||
|
import { Message } from 'element-ui' |
||||
|
|
||||
|
// 创建axios实例
|
||||
|
const service = axios.create({ |
||||
|
// baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/', // api 的 base_url
|
||||
|
baseURL: process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API, // api 的 base_url
|
||||
|
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 => { |
||||
|
const errorMsg = response.data.errMsg |
||||
|
if (response.status === 200) { |
||||
|
// console.log(response.data.data)
|
||||
|
if (response.data instanceof Blob) { |
||||
|
return response.data |
||||
|
} else if (response.data.data) { |
||||
|
return response.data.data |
||||
|
} else { |
||||
|
return response.data |
||||
|
} |
||||
|
} else { |
||||
|
Message.error({ |
||||
|
message: errorMsg, |
||||
|
duration: 5000 |
||||
|
}) |
||||
|
Promise.reject() |
||||
|
} |
||||
|
}, |
||||
|
error => { |
||||
|
return Promise.reject(error) |
||||
|
} |
||||
|
) |
||||
|
export default service |
||||
@ -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) |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,90 @@ |
|||||
|
<template> |
||||
|
<div class="content-main introduction-main"> |
||||
|
<div class="nav-menu"> |
||||
|
<ul> |
||||
|
<li |
||||
|
v-for="(item,index) in tabList" |
||||
|
:key="index" |
||||
|
:class="{ 'is-active': selectMenuIndex === index }" |
||||
|
@click="selectMenuChange(item, index)" |
||||
|
> |
||||
|
{{ item.title }} |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="introduction-info"> |
||||
|
<router-view /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchQueryTopicDetails } from '@/api/inquiryMachine' |
||||
|
export default { |
||||
|
name: 'ColumnLayout', |
||||
|
data() { |
||||
|
return { |
||||
|
libcode: '', |
||||
|
tabList: [], |
||||
|
selectMenuIndex: 0 |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
const savedIndex = localStorage.getItem('selectIndex') |
||||
|
if (savedIndex !== null) { |
||||
|
this.selectMenuIndex = parseInt(savedIndex) |
||||
|
} |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
methods: { |
||||
|
getQueryTopicDetails() { |
||||
|
const params = { 'id': this.$route.query.menuId } |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log('接口返回数据:', res) |
||||
|
if (res && res.queryTopicList && res.queryTopicList.length > 0) { |
||||
|
this.tabList = res.queryTopicList |
||||
|
this.libcode = res.queryMenu.libcode |
||||
|
// this.$store.commit |
||||
|
this.$store.commit('column/setColumnData', { |
||||
|
tabList: this.tabList, |
||||
|
libcode: this.libcode, |
||||
|
selectMenuIndex: this.selectMenuIndex |
||||
|
}) |
||||
|
console.log('Vuex设置成功:', this.$store.state.column.tabList) |
||||
|
} else { |
||||
|
console.error('接口返回的queryTopicList为空或格式错误') |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
console.error('接口请求失败:', err) |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
}, |
||||
|
selectMenuChange(item, index) { |
||||
|
this.selectMenuIndex = index |
||||
|
localStorage.setItem('selectIndex', index) |
||||
|
this.$store.commit('column/setSelectMenuIndex', index) |
||||
|
const targetRoute = { |
||||
|
name: 'ColumnListMix', |
||||
|
query: this.$route.query |
||||
|
} |
||||
|
const currentRoute = this.$router.currentRoute |
||||
|
if (currentRoute.name === targetRoute.name && |
||||
|
JSON.stringify(currentRoute.query) === JSON.stringify(targetRoute.query)) { |
||||
|
if (this.$children.length > 0) { |
||||
|
this.$children[0].getInitQueryTopicContext(item) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
this.$router.push(targetRoute).then(() => { |
||||
|
if (this.$children.length > 0) { |
||||
|
this.$children[0].getInitQueryTopicContext(item) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
</style> |
||||
@ -0,0 +1,173 @@ |
|||||
|
<template> |
||||
|
<div style="height:calc(100%);"> |
||||
|
<div v-if="detailData && tabList[selectMenuIndex].type ===1" class="new-detial-info"> |
||||
|
<h2 class="detail-title">{{ detailData.overTitle }}</h2> |
||||
|
<div class="detail-date">发布时间:{{ detailData.create_time }}</div> |
||||
|
<div class="detail-content" v-html="detailData.introHtml" /> |
||||
|
|
||||
|
</div> |
||||
|
<ul v-else-if="infoList.length !== 0 && (tabList[selectMenuIndex].type ===2 || tabList[selectMenuIndex]===3)" class="activity-list"> |
||||
|
<li v-for="(item,index) in infoList" :key="index" @click="toDetail(item)"> |
||||
|
<div class="activity-title">{{ item.overTitle?item.overTitle:'' }}</div> |
||||
|
<span class="date">{{ item.create_time }}</span> |
||||
|
</li> |
||||
|
</ul> |
||||
|
<Waterfall |
||||
|
v-else-if="infoList.length !== 0 && tabList[selectMenuIndex].type ===4" |
||||
|
:list="infoList" |
||||
|
:columns="columns" |
||||
|
:loading="loading" |
||||
|
:placeholder="placeholderImg" |
||||
|
:total-items="totalItems" |
||||
|
@scroll-end="loadMoreData" |
||||
|
/> |
||||
|
<div v-else style="height:calc(100%);display: flex; flex-direction: column; justify-content:center ; align-items: center;"> |
||||
|
<img style="display: block;" src="~@/assets/images/empty.png"> |
||||
|
<p style="font-size: 30px;">暂无相关数据</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Waterfall from './module/waterfall.vue' |
||||
|
import { mapState } from 'vuex' |
||||
|
import { FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
export default { |
||||
|
name: 'ColumnListMix', |
||||
|
components: { |
||||
|
Waterfall |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
detailData: {}, |
||||
|
infoList: [], |
||||
|
columns: 2, |
||||
|
dataList: [], |
||||
|
loading: false, |
||||
|
currentPage: 0, |
||||
|
pageSize: 10, |
||||
|
totalItems: 0, |
||||
|
placeholderImg: require('@/assets/images/default-img.png') |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapState('column', ['tabList', 'libcode', 'selectMenuIndex']) |
||||
|
}, |
||||
|
watch: { |
||||
|
$route: { |
||||
|
handler() { |
||||
|
console.log('当前Vuex中的tabList:', this.$store.state.column.tabList) |
||||
|
if (this.tabList.length > 0) { |
||||
|
this.getInitQueryTopicContext(this.tabList[this.selectMenuIndex]) |
||||
|
} else { |
||||
|
const timer = setTimeout(() => { |
||||
|
if (this.tabList.length > 0) { |
||||
|
this.getInitQueryTopicContext(this.tabList[this.selectMenuIndex]) |
||||
|
} else { |
||||
|
console.log('重试后tabList仍为空') |
||||
|
} |
||||
|
clearTimeout(timer) |
||||
|
}, 500) |
||||
|
} |
||||
|
}, |
||||
|
immediate: true |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
getInitQueryTopicContext(result) { |
||||
|
console.log(result.type) |
||||
|
const params = { |
||||
|
'page': this.currentPage, |
||||
|
'size': this.pageSize, |
||||
|
'libcode': this.libcode, |
||||
|
'topicId': result.id, |
||||
|
'topicType': result.type |
||||
|
} |
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
if (res.totalElements) { |
||||
|
this.totalItems = res.totalElements |
||||
|
} |
||||
|
const linkSrc = process.env.NODE_ENV === 'production' |
||||
|
? window.g.ApiUrl |
||||
|
: process.env.VUE_APP_BASE_API |
||||
|
|
||||
|
if (res && res.content.length > 0) { |
||||
|
if (result.type === 4) { |
||||
|
const formattedData = res.content.map(item => ({ |
||||
|
id: item.id || `item-${Date.now()}-${Math.random()}`, |
||||
|
type: 'image', |
||||
|
title: item.overTitle || '无标题', |
||||
|
image: item.imgUrl ? `${linkSrc}/api/fileRelevant/getImg?imgType=2&imgId=${item.imgUrl}` : this.placeholderImg, |
||||
|
linkUrl: item.linkUrl || '#' |
||||
|
})) |
||||
|
|
||||
|
this.infoList = [...this.infoList, ...formattedData] |
||||
|
} else if (result.type === 1) { |
||||
|
this.detailData = res.content[0] |
||||
|
} else { |
||||
|
this.infoList = res.content |
||||
|
} |
||||
|
} else { |
||||
|
this.infoList = [] |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
}, |
||||
|
loadMoreData() { |
||||
|
if (this.dataList.length >= this.totalItems) { |
||||
|
return |
||||
|
} |
||||
|
if (this.loading) return |
||||
|
|
||||
|
this.currentPage++ |
||||
|
this.getInitQueryTopicContext(this.tabList[this.selectMenuIndex]) |
||||
|
}, |
||||
|
|
||||
|
isAllDataLoaded() { |
||||
|
if (this.totalItems > 0) { |
||||
|
return this.dataList.length >= this.totalItems |
||||
|
} |
||||
|
return this.currentPage > 0 && this.dataList.length % this.pageSize !== 0 |
||||
|
}, |
||||
|
toDetail(item) { |
||||
|
// itemId: item.id |
||||
|
this.$router.push({ |
||||
|
name: 'ColumnListMixDetail', |
||||
|
query: { |
||||
|
...this.$route.query |
||||
|
} |
||||
|
}) |
||||
|
localStorage.setItem('columnListMixDetail', JSON.stringify(item)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.detail-title{ |
||||
|
font-size: 32px; |
||||
|
font-family: Source Han Sans CN-Regular, Source Han Sans CN; |
||||
|
font-weight: 400; |
||||
|
color: #333333; |
||||
|
line-height: 100px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.detail-date{ |
||||
|
text-align: center; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
.detail-content{ |
||||
|
::v-deep p{ |
||||
|
span{ |
||||
|
display: block !important; |
||||
|
text-indent:2em !important; |
||||
|
} |
||||
|
img{ |
||||
|
display: block; |
||||
|
margin: 10px auto; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,93 @@ |
|||||
|
<template> |
||||
|
<div class="detail-content"> |
||||
|
<div v-if="detailData" class="detail-info"> |
||||
|
<h2 class="detail-title">{{ detailData.overTitle }}</h2> |
||||
|
<div class="detail-date">发布时间:{{ detailData.create_time }}</div> |
||||
|
<div class="detail-content" v-html="detailData.introHtml" /> |
||||
|
</div> |
||||
|
|
||||
|
<div v-else-if="loading"> |
||||
|
<p>加载中...</p> |
||||
|
</div> |
||||
|
|
||||
|
<div v-else> |
||||
|
<p>加载详情失败</p> |
||||
|
<button @click="reloadDetail">重新加载</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'ColumnListMixDetail', |
||||
|
data() { |
||||
|
return { |
||||
|
detailData: null, |
||||
|
loading: true |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.loadDetailData() |
||||
|
}, |
||||
|
methods: { |
||||
|
loadDetailData() { |
||||
|
this.loading = true |
||||
|
|
||||
|
const storedData = localStorage.getItem('columnListMixDetail') |
||||
|
if (storedData) { |
||||
|
this.detailData = JSON.parse(storedData) |
||||
|
this.loading = false |
||||
|
return |
||||
|
} |
||||
|
// 方式2: 如果需要从接口重新获取(推荐) |
||||
|
// const itemId = this.$route.query.itemId |
||||
|
// if (itemId) { |
||||
|
// FetchTopicDetail({ id: itemId }).then(res => { |
||||
|
// this.detailData = res.data |
||||
|
// }).catch(err => { |
||||
|
// console.error('获取详情失败', err) |
||||
|
// }).finally(() => { |
||||
|
// this.loading = false |
||||
|
// }) |
||||
|
// } else { |
||||
|
// this.loading = false |
||||
|
// } |
||||
|
}, |
||||
|
// 重新加载详情 |
||||
|
reloadDetail() { |
||||
|
this.loadDetailData() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.detail-info{ |
||||
|
.detail-title{ |
||||
|
font-size: 32px; |
||||
|
font-family: Source Han Sans CN-Regular, Source Han Sans CN; |
||||
|
font-weight: 400; |
||||
|
color: #333333; |
||||
|
line-height: 100px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.detail-date{ |
||||
|
text-align: center; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
.detail-content{ |
||||
|
::v-deep p{ |
||||
|
span{ |
||||
|
display: block !important; |
||||
|
text-indent:2em !important; |
||||
|
} |
||||
|
img{ |
||||
|
display: block; |
||||
|
margin: 10px auto; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,64 @@ |
|||||
|
<template> |
||||
|
<div class="content-main introduction-main"> |
||||
|
<div class="new-detial-info" v-html="rawHtml" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchQueryTopicDetails, FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
export default { |
||||
|
name: 'ImgTxtDetail', |
||||
|
data() { |
||||
|
return { |
||||
|
rawHtml: '' |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
methods: { |
||||
|
getQueryTopicDetails() { |
||||
|
const params = { |
||||
|
'id': this.$route.query.menuId |
||||
|
} |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log(res) |
||||
|
if (res && res.queryTopicList.length > 0) { |
||||
|
this.getInitQueryTopicContext(res) |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
}, |
||||
|
getInitQueryTopicContext(result) { |
||||
|
const params = { |
||||
|
'page': 0, |
||||
|
'size': 10, |
||||
|
'libcode': result.queryMenu.libcode, |
||||
|
'topicId': result.queryTopicList[0].id, |
||||
|
'topicType': result.queryTopicList[0].type |
||||
|
} |
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
console.log(res) |
||||
|
if (res && res.content.length > 0) { |
||||
|
this.rawHtml = res.content[0].introHtml |
||||
|
} else { |
||||
|
this.rawHtml = '暂无数据' |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.new-detial-info { |
||||
|
background: #ffffff; |
||||
|
width: 100%; |
||||
|
padding: 20px; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,293 @@ |
|||||
|
<template> |
||||
|
<div v-if="pageError" class="wscn-http404-container"> |
||||
|
<div class="wscn-http404"> |
||||
|
<div class="pic-404"> |
||||
|
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404"> |
||||
|
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404"> |
||||
|
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404"> |
||||
|
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> |
||||
|
</div> |
||||
|
<div class="bullshit"> |
||||
|
<div class="bullshit__oops">OOPS!</div> |
||||
|
<div class="bullshit__headline">{{ message }}</div> |
||||
|
<div class="bullshit__info">请检查您输入的网址是否正确</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchQueryTopicDetails } from '@/api/inquiryMachine' |
||||
|
export default { |
||||
|
name: 'Home', |
||||
|
data() { |
||||
|
return { |
||||
|
pageError: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
message() { |
||||
|
return '暂未查到相关页面......' |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
console.log('this.router.path', this.$route.query) |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
methods: { |
||||
|
getQueryTopicDetails() { |
||||
|
const params = { |
||||
|
'id': this.$route.query.menuId |
||||
|
} |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
this.pageError = false |
||||
|
console.log(res) |
||||
|
// res.queryTopicList[0].type = 1 // 图文详情 |
||||
|
// res.queryTopicList[0].type = 2 // 文字列表 - 图文详情 |
||||
|
// res.queryTopicList[0].type = 3 // 图文列表 - 图文详情 |
||||
|
// res.queryTopicList[0].type = 4 // 图文列表 - 外部跳转 |
||||
|
|
||||
|
// res.queryMenu.type = 1 // 菜单 |
||||
|
// res.queryMenu.type = 2 && res.queryTopicList.length === 1 && res.queryTopicList[0].type==1 // 即进入imgTxtDetail页面 |
||||
|
// res.queryMenu.type = 3 && res.queryTopicList.length >0 // 即进入columnListMix页面 |
||||
|
// res.queryMenu.type = 4 // 即直接进入newBookRecommend页面 |
||||
|
localStorage.setItem('menuId', res.queryMenu.id) |
||||
|
localStorage.setItem('menuInfo', JSON.stringify(res)) |
||||
|
|
||||
|
// 根据不同条件跳转不同页面 |
||||
|
if (res.queryMenu.type === 1) { |
||||
|
// 带菜单页面 |
||||
|
this.$router.push({ |
||||
|
path: '/menu', |
||||
|
query: { 'menuId': res.queryMenu.id } |
||||
|
}) |
||||
|
} else if (res.queryMenu.type === 2 && res.queryTopicList.length === 1 && res.queryTopicList[0].type === 1) { |
||||
|
// 进入不带栏目得纯图文详情页面 |
||||
|
// , 'topicId': res.queryTopicList[0].id |
||||
|
this.$router.push({ |
||||
|
path: '/imgTxtDetail', |
||||
|
query: { 'menuId': res.queryMenu.id } |
||||
|
}) |
||||
|
} else if (res.queryMenu.type === 3 && res.queryTopicList.length > 1) { |
||||
|
// 进入columnListMix页面 |
||||
|
this.$router.push({ |
||||
|
path: '/column', |
||||
|
query: { 'menuId': res.queryMenu.id } |
||||
|
}) |
||||
|
} else if (res.queryMenu.type === 3 && res.queryTopicList.length === 1 && res.queryTopicList[0].type === 4) { |
||||
|
// 进入waterfallFlow页面 |
||||
|
this.$router.push({ |
||||
|
path: '/waterfallFlow', |
||||
|
query: { 'menuId': res.queryMenu.id } |
||||
|
}) |
||||
|
} else if (res.queryMenu.type === 4) { |
||||
|
// 进入newBookRecommend页面 |
||||
|
this.$router.push({ |
||||
|
path: '/newBookRecommend', |
||||
|
query: { 'menuId': res.queryMenu.id, 'libcode': res.queryMenu.libcode } |
||||
|
}) |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
// this.$message.error('接口错误') |
||||
|
this.pageError = true |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.wscn-http404-container{ |
||||
|
transform: translate(-50%,-50%); |
||||
|
position: absolute; |
||||
|
top: 40%; |
||||
|
left: 50%; |
||||
|
} |
||||
|
.wscn-http404 { |
||||
|
position: relative; |
||||
|
width: 1200px; |
||||
|
padding: 0 50px; |
||||
|
overflow: hidden; |
||||
|
.pic-404 { |
||||
|
position: relative; |
||||
|
float: left; |
||||
|
width: 600px; |
||||
|
overflow: hidden; |
||||
|
&__parent { |
||||
|
width: 100%; |
||||
|
} |
||||
|
&__child { |
||||
|
position: absolute; |
||||
|
&.left { |
||||
|
width: 80px; |
||||
|
top: 17px; |
||||
|
left: 220px; |
||||
|
opacity: 0; |
||||
|
animation-name: cloudLeft; |
||||
|
animation-duration: 2s; |
||||
|
animation-timing-function: linear; |
||||
|
animation-fill-mode: forwards; |
||||
|
animation-delay: 1s; |
||||
|
} |
||||
|
&.mid { |
||||
|
width: 46px; |
||||
|
top: 10px; |
||||
|
left: 420px; |
||||
|
opacity: 0; |
||||
|
animation-name: cloudMid; |
||||
|
animation-duration: 2s; |
||||
|
animation-timing-function: linear; |
||||
|
animation-fill-mode: forwards; |
||||
|
animation-delay: 1.2s; |
||||
|
} |
||||
|
&.right { |
||||
|
width: 62px; |
||||
|
top: 100px; |
||||
|
left: 500px; |
||||
|
opacity: 0; |
||||
|
animation-name: cloudRight; |
||||
|
animation-duration: 2s; |
||||
|
animation-timing-function: linear; |
||||
|
animation-fill-mode: forwards; |
||||
|
animation-delay: 1s; |
||||
|
} |
||||
|
@keyframes cloudLeft { |
||||
|
0% { |
||||
|
top: 17px; |
||||
|
left: 220px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
20% { |
||||
|
top: 33px; |
||||
|
left: 188px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
80% { |
||||
|
top: 81px; |
||||
|
left: 92px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
100% { |
||||
|
top: 97px; |
||||
|
left: 60px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
} |
||||
|
@keyframes cloudMid { |
||||
|
0% { |
||||
|
top: 10px; |
||||
|
left: 420px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
20% { |
||||
|
top: 40px; |
||||
|
left: 360px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
70% { |
||||
|
top: 130px; |
||||
|
left: 180px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
100% { |
||||
|
top: 160px; |
||||
|
left: 120px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
} |
||||
|
@keyframes cloudRight { |
||||
|
0% { |
||||
|
top: 100px; |
||||
|
left: 500px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
20% { |
||||
|
top: 120px; |
||||
|
left: 460px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
80% { |
||||
|
top: 180px; |
||||
|
left: 340px; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
100% { |
||||
|
top: 200px; |
||||
|
left: 300px; |
||||
|
opacity: 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.bullshit { |
||||
|
position: relative; |
||||
|
float: left; |
||||
|
width: 300px; |
||||
|
padding: 30px 0; |
||||
|
overflow: hidden; |
||||
|
&__oops { |
||||
|
font-size: 32px; |
||||
|
font-weight: bold; |
||||
|
line-height: 40px; |
||||
|
color: #1482f0; |
||||
|
opacity: 0; |
||||
|
margin-bottom: 20px; |
||||
|
animation-name: slideUp; |
||||
|
animation-duration: 0.5s; |
||||
|
animation-fill-mode: forwards; |
||||
|
} |
||||
|
&__headline { |
||||
|
font-size: 20px; |
||||
|
line-height: 24px; |
||||
|
color: #222; |
||||
|
font-weight: bold; |
||||
|
opacity: 0; |
||||
|
margin-bottom: 10px; |
||||
|
animation-name: slideUp; |
||||
|
animation-duration: 0.5s; |
||||
|
animation-delay: 0.1s; |
||||
|
animation-fill-mode: forwards; |
||||
|
} |
||||
|
&__info { |
||||
|
font-size: 13px; |
||||
|
line-height: 21px; |
||||
|
color: grey; |
||||
|
opacity: 0; |
||||
|
margin-bottom: 30px; |
||||
|
animation-name: slideUp; |
||||
|
animation-duration: 0.5s; |
||||
|
animation-delay: 0.2s; |
||||
|
animation-fill-mode: forwards; |
||||
|
} |
||||
|
&__return-home { |
||||
|
display: block; |
||||
|
float: left; |
||||
|
width: 110px; |
||||
|
height: 36px; |
||||
|
background: #1482f0; |
||||
|
border-radius: 100px; |
||||
|
text-align: center; |
||||
|
color: #ffffff; |
||||
|
opacity: 0; |
||||
|
font-size: 14px; |
||||
|
line-height: 36px; |
||||
|
cursor: pointer; |
||||
|
animation-name: slideUp; |
||||
|
animation-duration: 0.5s; |
||||
|
animation-delay: 0.3s; |
||||
|
animation-fill-mode: forwards; |
||||
|
} |
||||
|
@keyframes slideUp { |
||||
|
0% { |
||||
|
transform: translateY(60px); |
||||
|
opacity: 0; |
||||
|
} |
||||
|
100% { |
||||
|
transform: translateY(0); |
||||
|
opacity: 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,174 @@ |
|||||
|
<template> |
||||
|
<!-- 活动咨询 --> |
||||
|
<div class="content-main introduction-main"> |
||||
|
<div class="nav-menu"> |
||||
|
<ul> |
||||
|
<li |
||||
|
v-for="(item,index) in tabList" |
||||
|
:key="index" |
||||
|
:class="{ 'is-active': selectMenuIndex === index }" |
||||
|
@click="selectMenuChange(item, index)" |
||||
|
> |
||||
|
{{ item.title }} |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="introduction-info"> |
||||
|
<ul v-if="rightColumnTab.length !== 0" class="menu-tab-list"> |
||||
|
<li |
||||
|
v-for="(item,index) in rightColumnTab" |
||||
|
:key="item.id" |
||||
|
:class="{ 'active': columeIndex === index }" |
||||
|
@click="handleColumnClick(item, index)" |
||||
|
> |
||||
|
{{ item.title }} |
||||
|
</li> |
||||
|
</ul> |
||||
|
<div style="height: calc(100% - 60px);"> |
||||
|
<ul v-if="infoList.length !== 0" class="activity-list"> |
||||
|
<li v-for="item in infoList" :key="item.id" @click="toDetail(item)"> |
||||
|
<div class="activity-title">{{ item.overTitle?item.overTitle:'' }}</div> |
||||
|
<span class="date">{{ item.create_time }}</span> |
||||
|
</li> |
||||
|
</ul> |
||||
|
<div v-else style="height:calc(100%);display: flex; flex-direction: column; justify-content:center ; align-items: center;"> |
||||
|
<img style="display: block;" src="~@/assets/images/empty.png"> |
||||
|
<p style="font-size: 30px;">暂无相关数据</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchQueryTopicDetails, FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
export default { |
||||
|
name: 'ActivityFeed', |
||||
|
data() { |
||||
|
return { |
||||
|
libcode: '', |
||||
|
tabList: [], |
||||
|
selectMenuIndex: 0, |
||||
|
rightColumnTab: [], |
||||
|
columeIndex: 0, |
||||
|
infoList: [] |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
methods: { |
||||
|
getQueryTopicDetails() { |
||||
|
const params = { 'id': this.$route.query.menuId } |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log('接口返回数据:', res) |
||||
|
if (res && res.queryMenu) { |
||||
|
this.tabList = res.queryMenu.children |
||||
|
this.libcode = res.queryMenu.libcode |
||||
|
this.rightColumnTab = [] |
||||
|
this.tabList.forEach(childMenu => { |
||||
|
if (childMenu.queryMenuTopics && childMenu.queryMenuTopics.length > 0) { |
||||
|
childMenu.queryMenuTopics.forEach(menuTopic => { |
||||
|
if (menuTopic.queryTopic) { |
||||
|
this.rightColumnTab.push(menuTopic.queryTopic) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
if (this.rightColumnTab.length > 0) { |
||||
|
this.columeIndex = 0 // 默认选中第一个 |
||||
|
const defaultTopic = this.rightColumnTab[0] // 获取默认选中的queryTopic |
||||
|
this.getInitQueryTopicContext(defaultTopic) // 传入默认topic请求数据 |
||||
|
} |
||||
|
} else { |
||||
|
this.tabList = [] |
||||
|
this.rightColumnTab = [] |
||||
|
this.infoList = [] |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
console.error('接口请求失败:', err) |
||||
|
this.$message.error('接口错误') |
||||
|
this.rightColumnTab = [] |
||||
|
this.infoList = [] |
||||
|
}) |
||||
|
}, |
||||
|
getInitQueryTopicContext(currentTopic) { |
||||
|
const params = { |
||||
|
'page': 0, |
||||
|
'size': 10, |
||||
|
'libcode': this.libcode, |
||||
|
'topicId': currentTopic.id, // 传当前选中queryTopic的id(原代码传result.id错误) |
||||
|
'topicType': currentTopic.type // 传当前选中queryTopic的type(原代码传result.type错误) |
||||
|
} |
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
if (res && res.content.length > 0) { |
||||
|
this.infoList = res.content |
||||
|
} else { |
||||
|
this.infoList = [] // 无数据时清空列表 |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
this.infoList = [] |
||||
|
}) |
||||
|
}, |
||||
|
handleColumnClick(currentTopic, index) { |
||||
|
this.columeIndex = index // 更新选中索引 |
||||
|
this.getInitQueryTopicContext(currentTopic) // 传入当前topic请求数据 |
||||
|
}, |
||||
|
selectMenuChange(childMenu, index) { |
||||
|
this.selectMenuIndex = index |
||||
|
this.rightColumnTab = [] |
||||
|
if (childMenu.queryMenuTopics && childMenu.queryMenuTopics.length > 0) { |
||||
|
childMenu.queryMenuTopics.forEach(menuTopic => { |
||||
|
if (menuTopic.queryTopic) { |
||||
|
this.rightColumnTab.push(menuTopic.queryTopic) |
||||
|
} |
||||
|
}) |
||||
|
if (this.rightColumnTab.length > 0) { |
||||
|
this.columeIndex = 0 |
||||
|
this.getInitQueryTopicContext(this.rightColumnTab[0]) |
||||
|
} else { |
||||
|
this.infoList = [] |
||||
|
} |
||||
|
} else { |
||||
|
this.rightColumnTab = [] |
||||
|
this.infoList = [] |
||||
|
} |
||||
|
}, |
||||
|
toDetail(item) { |
||||
|
this.$router.push('/ActivityDetail') |
||||
|
localStorage.setItem('selectIndex', JSON.stringify(this.selectMenuIndex)) |
||||
|
localStorage.setItem('activityDetail', JSON.stringify(item)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.menu-tab-list{ |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
font-size: 26px; |
||||
|
// padding: 10px 0; |
||||
|
border-bottom: 2px solid #D9D9D9; |
||||
|
li{ |
||||
|
padding: 10px 20px; |
||||
|
margin-right: 20px; |
||||
|
&.active{ |
||||
|
position: relative; |
||||
|
color:#5394F1; |
||||
|
&::before{ |
||||
|
position: absolute; |
||||
|
bottom: -2px; |
||||
|
left: 0; |
||||
|
content: ''; |
||||
|
width: 100%; |
||||
|
height: 2px; |
||||
|
background-color: #5394F1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,228 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<el-dialog |
||||
|
title="图书详情" |
||||
|
:visible.sync="dialogVisible" |
||||
|
width="60%" |
||||
|
> |
||||
|
<!-- :before-close="handleClose" --> |
||||
|
<div class="dialog-setting"> |
||||
|
<div class="book-details-box"> |
||||
|
<div class="book-details"> |
||||
|
<div class="book-cover"> |
||||
|
<img :src="bookData.imgPath ? bookData.imgPath : ''" :onerror="defaultImg"> |
||||
|
</div> |
||||
|
<div class="book-desc"> |
||||
|
<h3>{{ bookData.title }}</h3> |
||||
|
<p class="book-from">作者:{{ bookData.author }}</p> |
||||
|
<p v-if="bookData.publisher" class="book-from">出版社:{{ bookData.publisher }}</p> |
||||
|
<p class="book-brief"> 简介:{{ bookData.summary }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="book-local"> |
||||
|
<!-- <span v-if="bookData.bookPlace">所在位置:{{ bookData.bookPlace }}</span> --> |
||||
|
<!-- 待定:热门图书/新书推荐跳转到 场馆导航操作 --> |
||||
|
<!-- <span v-else>所在位置</span> --> |
||||
|
<div class="local-title"> |
||||
|
所在位置 |
||||
|
</div> |
||||
|
<ul class="local-list"> |
||||
|
<template v-if="!bookData.places || bookData.places.length === 0"> |
||||
|
<li class="local-none"> |
||||
|
<span>当前图书暂未查到位置信息</span> |
||||
|
</li> |
||||
|
</template> |
||||
|
<template v-else> |
||||
|
<li |
||||
|
v-for="(item, index) in bookData.places" |
||||
|
:key="index" |
||||
|
class="local-list-info" |
||||
|
@click="toBookNav(index)" |
||||
|
> |
||||
|
<svg class="icon svg-icon" aria-hidden="true"> |
||||
|
<use xlink:href="#icon-weizhi" /> |
||||
|
</svg> |
||||
|
<span>{{ item.shelfName }}</span> |
||||
|
</li> |
||||
|
</template> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'BookDetails', |
||||
|
data() { |
||||
|
return { |
||||
|
dialogVisible: false, |
||||
|
bookData: {}, |
||||
|
defaultImg: 'this.src="' + require('@/assets/images/default-img.png') + '"' |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
}, |
||||
|
methods: { |
||||
|
toBookNav(index) { |
||||
|
const linkSrc = process.env.VUE_APP_BASE_API |
||||
|
window.location.href = linkSrc + '/anchoring/goNavigation.do?libcode=1201&barcode=' + this.bookData.places[index].barcode |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
::v-deep .el-dialog{ |
||||
|
position: fixed; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
margin-top: 0 !important; |
||||
|
transform: translate(-50%,-50%); |
||||
|
border-radius: 24px; |
||||
|
.el-dialog__body{ |
||||
|
padding: 0 40px 40px 40px ; |
||||
|
z-index: 999; |
||||
|
} |
||||
|
} |
||||
|
::v-deep .el-dialog__header{ |
||||
|
text-align: center; |
||||
|
padding-top:0 ; |
||||
|
padding-bottom:4px ; |
||||
|
.el-dialog__title{ |
||||
|
display: inline-block; |
||||
|
font-family: "ZhenyanGB"; |
||||
|
font-size: 40px; |
||||
|
width: 494px; |
||||
|
height: 76px; |
||||
|
line-height: 76px; |
||||
|
background: url('~@/assets/images/list-title.png') no-repeat 0 0; |
||||
|
} |
||||
|
} |
||||
|
::v-deep .el-dialog__headerbtn{ |
||||
|
background-color: #3F92F6; |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
border-radius: 50%; |
||||
|
.el-dialog__close{ |
||||
|
color: #fff; |
||||
|
font-size: 30px; |
||||
|
} |
||||
|
} |
||||
|
.book-details-box{ |
||||
|
.book-details{ |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
padding: 30px 0; |
||||
|
.book-cover{ |
||||
|
width: 318px; |
||||
|
height: 382px; |
||||
|
margin-right: 40px; |
||||
|
img{ |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
.book-desc{ |
||||
|
flex: 1; |
||||
|
color: #333; |
||||
|
overflow: hidden; |
||||
|
h3{ |
||||
|
font-size: 40px; |
||||
|
font-weight: normal; |
||||
|
} |
||||
|
.book-from{ |
||||
|
width: 100%; |
||||
|
font-size: 30px; |
||||
|
} |
||||
|
h3,.book-from{ |
||||
|
text-overflow: -o-ellipsis-lastline; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 2; |
||||
|
line-clamp: 2; |
||||
|
-webkit-box-orient: vertical; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
.book-brief{ |
||||
|
font-size: 24px; |
||||
|
margin-bottom: 20px; |
||||
|
text-overflow: -o-ellipsis-lastline; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 4; |
||||
|
line-clamp: 4; |
||||
|
-webkit-box-orient: vertical; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// .book-local{ |
||||
|
// border: 1px solid #3F92F6; |
||||
|
// background: #D0E0F9; |
||||
|
// border-radius: 52px; |
||||
|
// height: 64px; |
||||
|
// line-height: 64px; |
||||
|
// text-align: center; |
||||
|
// font-size: 30px; |
||||
|
// color: #333; |
||||
|
// overflow: hidden; |
||||
|
// white-space: nowrap; |
||||
|
// text-overflow: ellipsis; |
||||
|
// } |
||||
|
.book-local { |
||||
|
height: 343px; |
||||
|
color: #333; |
||||
|
display: flex; |
||||
|
// border-radius: 52px; |
||||
|
// line-height: 64px; |
||||
|
// text-align: center; |
||||
|
// font-size: 30px; |
||||
|
// overflow: hidden; |
||||
|
// white-space: nowrap; |
||||
|
// text-overflow: ellipsis; |
||||
|
.local-title { |
||||
|
width: 83px; |
||||
|
height: 100%; |
||||
|
background: url("~@/assets/images/local-bg.png") no-repeat; |
||||
|
writing-mode: vertical-rl; |
||||
|
text-align: center; |
||||
|
line-height: 83px; |
||||
|
font-size: 30px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.local-list { |
||||
|
flex: 1; |
||||
|
border: 1px solid #3f92f6; |
||||
|
border-left: none; |
||||
|
background: #d0e0f9; |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
position: relative; |
||||
|
font-size: 26px; |
||||
|
.local-list-info { |
||||
|
height: 56px; |
||||
|
line-height: 56px; |
||||
|
background-color: #fff; |
||||
|
// margin-right: 8px; |
||||
|
margin-bottom: 15px; |
||||
|
padding-left: 13px; |
||||
|
span { |
||||
|
margin-left: 19px; |
||||
|
} |
||||
|
} |
||||
|
.local-none { |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
position: absolute; |
||||
|
// left: 50%; |
||||
|
top: 50%; |
||||
|
transform: translateY(-50%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,434 @@ |
|||||
|
<template> |
||||
|
<!-- 参考 https://blog.csdn.net/weixin_44198965/article/details/147831036 --> |
||||
|
<div class="waterfall-container"> |
||||
|
<!-- 列容器 --> |
||||
|
<div ref="columnWrapper" class="waterfall-column-wrapper"> |
||||
|
<!-- 瀑布流项 --> |
||||
|
<div |
||||
|
v-for="(item, index) in renderedList" |
||||
|
:key="item.id || index" |
||||
|
v-lazy-load="item.image || item.cover" |
||||
|
class="waterfall-item" |
||||
|
> |
||||
|
<!-- 图片类型 --> |
||||
|
<div v-if="item.type === 'image'" class="item-content" @click="jump(item.linkUrl)"> |
||||
|
<img |
||||
|
:src="placeholder" |
||||
|
:alt="item.title || '图片'" |
||||
|
class="item-image" |
||||
|
> |
||||
|
<div v-if="item.title" class="item-title">{{ item.title }}</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 视频类型 --> |
||||
|
<div v-else-if="item.type === 'video'" class="item-content"> |
||||
|
<video |
||||
|
:poster="placeholder" |
||||
|
controls |
||||
|
class="item-video" |
||||
|
> |
||||
|
<source :src="item.videoUrl" type="video/mp4"> |
||||
|
</video> |
||||
|
<div v-if="item.title" class="item-title">{{ item.title }}</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 图文类型 --> |
||||
|
<div v-else class="item-content"> |
||||
|
<img |
||||
|
v-if="item.image" |
||||
|
:src="placeholder" |
||||
|
:alt="item.title || '图文'" |
||||
|
class="item-image" |
||||
|
> |
||||
|
<div v-if="item.title" class="item-title">{{ item.title }}</div> |
||||
|
<div v-if="item.desc" class="item-desc">{{ item.desc }}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 加载状态 --> |
||||
|
<div v-if="loading" class="loading-more"> |
||||
|
加载中... |
||||
|
</div> |
||||
|
<div v-if="isComplete && renderedList.length > 0" class="load-complete"> |
||||
|
没有更多内容了 |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'Waterfall', |
||||
|
|
||||
|
directives: { |
||||
|
lazyLoad: { |
||||
|
inserted(el, binding, vnode) { |
||||
|
const observer = new IntersectionObserver((entries) => { |
||||
|
entries.forEach(entry => { |
||||
|
if (entry.isIntersecting) { |
||||
|
const img = el.tagName === 'IMG' ? el : el.querySelector('img') |
||||
|
if (img) { |
||||
|
img.src = binding.value |
||||
|
// 图片加载完成后重新布局 |
||||
|
img.onload = () => { |
||||
|
vnode.context.layoutItems() |
||||
|
} |
||||
|
// 图片加载错误处理 |
||||
|
img.onerror = () => { |
||||
|
if (vnode.context.placeholder) { |
||||
|
img.src = vnode.context.placeholder |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
observer.unobserve(el) |
||||
|
} |
||||
|
}) |
||||
|
}, { |
||||
|
rootMargin: '0px 0px 100px 0px' // 提前100px加载 |
||||
|
}) |
||||
|
|
||||
|
observer.observe(el) |
||||
|
|
||||
|
el._observer = observer |
||||
|
}, |
||||
|
unbind(el) { |
||||
|
if (el._observer) { |
||||
|
el._observer.disconnect() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 定义组件props |
||||
|
props: { |
||||
|
// 数据源数组 |
||||
|
list: { |
||||
|
type: Array, |
||||
|
required: true, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
// 列数配置 |
||||
|
columns: { |
||||
|
type: Number, |
||||
|
default: 2, |
||||
|
validator: function(value) { |
||||
|
return value >= 1 && value <= 5 // 限制列数在1-5之间 |
||||
|
} |
||||
|
}, |
||||
|
// 列间距 |
||||
|
gap: { |
||||
|
type: Number, |
||||
|
default: 10 |
||||
|
}, |
||||
|
// 是否开启懒加载 |
||||
|
lazyLoad: { |
||||
|
type: Boolean, |
||||
|
default: true |
||||
|
}, |
||||
|
// 触底加载的阈值(距离底部多少像素触发加载) |
||||
|
loadThreshold: { |
||||
|
type: Number, |
||||
|
default: 100 |
||||
|
}, |
||||
|
// 图片加载时的占位图 |
||||
|
placeholder: { |
||||
|
type: String, |
||||
|
default: '改成你的图片' |
||||
|
}, |
||||
|
totalItems: { |
||||
|
type: Number, |
||||
|
default: 0 |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
data() { |
||||
|
return { |
||||
|
waterfallRef: null, // 瀑布流容器引用 |
||||
|
columnHeights: [], // 每列当前高度数组 |
||||
|
columnWrapperRef: null, // 列容器引用 |
||||
|
loading: false, // 加载状态 |
||||
|
isComplete: false, // 是否已加载全部数据 |
||||
|
renderedList: [], // 已渲染的数据列表 |
||||
|
pageSize: 20, // 每次加载的数据量 |
||||
|
currentPage: 1 // 当前页码 |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
// 计算列宽度(根据容器宽度和列数计算) |
||||
|
columnWidth() { |
||||
|
if (!this.waterfallRef) return 0 |
||||
|
const containerWidth = this.waterfallRef.clientWidth |
||||
|
return (containerWidth - (this.columns - 1) * this.gap) / this.columns |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
watch: { |
||||
|
// 监听列数变化 |
||||
|
columns(newVal, oldVal) { |
||||
|
if (newVal !== oldVal) { |
||||
|
this.resetLayout() |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 监听数据源变化 |
||||
|
list: { |
||||
|
handler(newList) { |
||||
|
this.renderedList = newList // 直接同步父组件数据(无需分页切片) |
||||
|
this.$nextTick(() => this.layoutItems()) |
||||
|
}, |
||||
|
deep: true |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
mounted() { |
||||
|
this.scrollContainer = this.$el |
||||
|
this.waterfallRef = this.$el |
||||
|
this.columnWrapperRef = this.$el.querySelector('.waterfall-column-wrapper') |
||||
|
|
||||
|
this.resetLayout() |
||||
|
if (this.lazyLoad) { |
||||
|
this.scrollContainer.addEventListener('scroll', this.handleScroll) |
||||
|
} |
||||
|
window.addEventListener('resize', this.handleResize) |
||||
|
}, |
||||
|
|
||||
|
beforeDestroy() { |
||||
|
if (this.lazyLoad && this.scrollContainer) { |
||||
|
this.scrollContainer.removeEventListener('scroll', this.handleScroll) |
||||
|
} |
||||
|
window.removeEventListener('resize', this.handleResize) |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
// 初始化列高度数组 |
||||
|
initColumnHeights() { |
||||
|
this.columnHeights = new Array(this.columns).fill(0) |
||||
|
}, |
||||
|
|
||||
|
// 初始化渲染数据 |
||||
|
initRenderList() { |
||||
|
this.renderedList = this.list.slice(0, this.pageSize) |
||||
|
this.currentPage = 1 |
||||
|
this.isComplete = this.renderedList.length >= this.list.length |
||||
|
}, |
||||
|
|
||||
|
// 重置瀑布流布局 |
||||
|
resetLayout() { |
||||
|
this.initColumnHeights() |
||||
|
this.initRenderList() |
||||
|
this.$nextTick(() => { |
||||
|
this.layoutItems() |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
// 瀑布流布局算法 |
||||
|
layoutItems() { |
||||
|
if (!this.columnWrapperRef || !this.waterfallRef) return |
||||
|
|
||||
|
// 获取所有子元素 |
||||
|
const items = this.columnWrapperRef.children |
||||
|
if (!items || items.length === 0) return |
||||
|
|
||||
|
// 初始化列高度 |
||||
|
this.initColumnHeights() |
||||
|
|
||||
|
// 临时列高度副本用于计算 |
||||
|
const tempColumnHeights = [...this.columnHeights] |
||||
|
|
||||
|
// 遍历所有子元素进行布局 |
||||
|
Array.from(items).forEach((item, index) => { |
||||
|
// 找到当前最短的列 |
||||
|
const minHeight = Math.min(...tempColumnHeights) |
||||
|
const columnIndex = tempColumnHeights.indexOf(minHeight) |
||||
|
|
||||
|
// 计算位置 |
||||
|
const left = columnIndex * (this.columnWidth + this.gap) |
||||
|
const top = minHeight |
||||
|
|
||||
|
// 应用样式 |
||||
|
item.style.position = 'absolute' |
||||
|
item.style.width = `${this.columnWidth}px` |
||||
|
item.style.left = `${left}px` |
||||
|
item.style.top = `${top}px` |
||||
|
item.style.transition = 'all 0.3s ease' |
||||
|
|
||||
|
// 更新列高度 |
||||
|
tempColumnHeights[columnIndex] += item.clientHeight + this.gap |
||||
|
}) |
||||
|
|
||||
|
// 更新列高度 |
||||
|
this.columnHeights = tempColumnHeights |
||||
|
|
||||
|
// 设置容器高度 |
||||
|
const maxHeight = Math.max(...tempColumnHeights) |
||||
|
this.columnWrapperRef.style.height = `${maxHeight}px` |
||||
|
}, |
||||
|
|
||||
|
// 滚动事件处理 |
||||
|
// handleScroll() { |
||||
|
// if (this.loading || this.isComplete) return |
||||
|
|
||||
|
// const scrollTop = document.documentElement.scrollTop || document.body.scrollTop |
||||
|
// const windowHeight = window.innerHeight |
||||
|
// const scrollHeight = document.documentElement.scrollHeight |
||||
|
|
||||
|
// // 判断是否触底 |
||||
|
// if (scrollTop + windowHeight >= scrollHeight - this.loadThreshold) { |
||||
|
// this.loadMore() |
||||
|
// } |
||||
|
// }, |
||||
|
|
||||
|
handleScroll() { |
||||
|
if (this.loading || (this.totalItems > 0 && this.renderedList.length >= this.totalItems)) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// 获取滚动容器(父组件的.content-main) |
||||
|
const scrollContainer = this.$parent.$el.querySelector('.content-main') || window |
||||
|
let scrollTop, clientHeight, scrollHeight |
||||
|
|
||||
|
if (scrollContainer === window) { |
||||
|
scrollTop = document.documentElement.scrollTop || document.body.scrollTop |
||||
|
clientHeight = window.innerHeight |
||||
|
scrollHeight = document.documentElement.scrollHeight |
||||
|
} else { |
||||
|
// 关键:用滚动容器的实际尺寸计算(避免父组件padding影响) |
||||
|
scrollTop = scrollContainer.scrollTop |
||||
|
clientHeight = scrollContainer.clientHeight |
||||
|
scrollHeight = scrollContainer.scrollHeight |
||||
|
} |
||||
|
|
||||
|
// 触底阈值:距离底部100px时触发加载(可调整) |
||||
|
if (scrollTop + clientHeight >= scrollHeight - this.loadThreshold) { |
||||
|
this.$emit('scroll-end') // 触发父组件的loadMoreData |
||||
|
console.log('触发加载更多') |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 加载更多数据 |
||||
|
loadMore() { |
||||
|
if (this.loading || this.isComplete) return |
||||
|
|
||||
|
this.loading = true |
||||
|
|
||||
|
// 模拟异步加载 |
||||
|
setTimeout(() => { |
||||
|
try { |
||||
|
const nextPage = this.currentPage + 1 |
||||
|
const startIndex = (nextPage - 1) * this.pageSize |
||||
|
const endIndex = nextPage * this.pageSize |
||||
|
|
||||
|
if (startIndex >= this.list.length) { |
||||
|
this.isComplete = true |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
const newItems = this.list.slice(startIndex, endIndex) |
||||
|
this.renderedList = [...this.renderedList, ...newItems] |
||||
|
this.currentPage = nextPage |
||||
|
|
||||
|
// 检查是否已加载全部数据 |
||||
|
if (endIndex >= this.list.length) { |
||||
|
this.isComplete = true |
||||
|
} |
||||
|
|
||||
|
// 等待DOM更新后重新布局 |
||||
|
this.$nextTick(() => { |
||||
|
this.layoutItems() |
||||
|
}) |
||||
|
} catch (error) { |
||||
|
console.error('加载更多数据失败:', error) |
||||
|
} finally { |
||||
|
this.loading = false |
||||
|
} |
||||
|
}, 500) |
||||
|
}, |
||||
|
jump(url) { |
||||
|
window.location.href = url |
||||
|
}, |
||||
|
// 响应式处理窗口大小变化 |
||||
|
handleResize() { |
||||
|
this.resetLayout() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.waterfall-container { |
||||
|
position: relative; |
||||
|
width: calc(100%); |
||||
|
height: 800px; |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
|
||||
|
.waterfall-column-wrapper { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.waterfall-item { |
||||
|
margin-bottom: 10px; |
||||
|
break-inside: avoid; |
||||
|
box-sizing: border-box; |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
overflow: hidden; |
||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.waterfall-item:hover { |
||||
|
transform: translateY(-5px); |
||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.item-content { |
||||
|
padding: 12px; |
||||
|
} |
||||
|
|
||||
|
.item-image, .item-video { |
||||
|
width: 100%; |
||||
|
border-radius: 4px; |
||||
|
display: block; |
||||
|
background: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
.item-video { |
||||
|
aspect-ratio: 9/16; |
||||
|
object-fit: cover; |
||||
|
} |
||||
|
|
||||
|
.item-title { |
||||
|
margin-top: 8px; |
||||
|
font-size: 24px; |
||||
|
line-height: 1.4; |
||||
|
color: #333; |
||||
|
font-weight: bold; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 2; |
||||
|
-webkit-box-orient: vertical; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.item-desc { |
||||
|
margin-top: 6px; |
||||
|
font-size: 12px; |
||||
|
color: #666; |
||||
|
line-height: 1.4; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 3; |
||||
|
-webkit-box-orient: vertical; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.loading-more, .load-complete { |
||||
|
text-align: center; |
||||
|
padding: 20px 0; |
||||
|
color: #999; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,282 @@ |
|||||
|
<template> |
||||
|
<!-- 新书推荐 --> |
||||
|
<div class="content-main new-main"> |
||||
|
<div class="swiper-container"> |
||||
|
<div class="swiper-wrapper new-book-list"> |
||||
|
<div v-for="(item,index) in rankingList" :key="index" class="swiper-slide" @click="handleDetails(index)"> |
||||
|
<div class="book-list-item"> |
||||
|
<div class="book-img"> |
||||
|
<img :src="item.imgPath" :onerror="defaultImg"> |
||||
|
</div> |
||||
|
<div class="book-info"> |
||||
|
<h4 class="title-item">{{ item.name }}</h4> |
||||
|
<p>作者:{{ item.author }}</p> |
||||
|
<p>出版社:{{ item.publisher }}</p> |
||||
|
<p>出版年份:{{ item.publisherdate }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="icon iconfont prev-btn"> |
||||
|
<svg class="icon svg-icon" aria-hidden="true"> |
||||
|
<use xlink:href="#icon-zuohua" /> |
||||
|
</svg> |
||||
|
</div> |
||||
|
<div class="icon iconfont next-btn"> |
||||
|
<svg class="icon svg-icon" aria-hidden="true"> |
||||
|
<use xlink:href="#icon-youhua" /> |
||||
|
</svg> |
||||
|
</div> |
||||
|
</div> |
||||
|
<BookDetails ref="detailDom" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { Swiper } from 'vue-awesome-swiper' |
||||
|
import 'swiper/swiper-bundle.css' |
||||
|
// import { FetchNewBookRecommend, FetchCoverByISBN, getBookDetailsByISBN } from '@/api/inquiryMachine' |
||||
|
import { FetchNewBook, FetchMarcByISBN, getBookDetailsByISBN } from '@/api/inquiryMachine' |
||||
|
import BookDetails from './module/bookDetails.vue' |
||||
|
export default { |
||||
|
name: 'NewBookRecommend', |
||||
|
components: { |
||||
|
BookDetails |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
defaultImg: 'this.src="' + require('@/assets/images/default-img.png') + '"', |
||||
|
coverUrl: null, |
||||
|
rankingList: [] |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getNewBook() |
||||
|
}, |
||||
|
mounted() { |
||||
|
}, |
||||
|
methods: { |
||||
|
initSwiper() { |
||||
|
this.$nextTick(() => { |
||||
|
new Swiper('.swiper-container', { |
||||
|
touchEventsTarget: '.swiper-container', |
||||
|
slidesPerView: 5, |
||||
|
spaceBetween: 20, |
||||
|
centeredSlides: true, |
||||
|
observer: true, |
||||
|
// loop: true, |
||||
|
centeredSlidesBounds: true, |
||||
|
watchSlidesVisibility: true, |
||||
|
navigation: { |
||||
|
nextEl: '.next-btn', |
||||
|
prevEl: '.prev-btn' |
||||
|
} |
||||
|
// on: { |
||||
|
// click: function() { |
||||
|
// alert(this.clickedIndex) |
||||
|
// } |
||||
|
// } |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
getNewBook() { |
||||
|
console.log('this.$route.query.libcode', this.$route.query.libcode) |
||||
|
const params = { |
||||
|
'libcode': this.$route.query.libcode, |
||||
|
'size': 40 |
||||
|
} |
||||
|
FetchNewBook(params).then(res => { |
||||
|
// 图片地址格式 http://192.168.99.67:8080/downloadFile/qytsg/ae281b90-b100-4541-9379-3e104854652c.png |
||||
|
// 图片地址格式 http://192.168.99.72:14000/api/fileRelevant/getImg?imgType=2&imgId=c964bcab-ec82-43f0-8653-04d930d7da4a |
||||
|
const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API |
||||
|
console.log('res.data', res) |
||||
|
this.rankingList = res.map(item => { |
||||
|
if (item.imgPath) { |
||||
|
item.imgPath = linkSrc + '/api/fileRelevant/getImg?imgType=2&imgId=' + item.imgPath |
||||
|
return Promise.resolve(item) |
||||
|
} else { |
||||
|
const params = { |
||||
|
'sIsbn': item.isbn |
||||
|
} |
||||
|
return FetchMarcByISBN(params).then(response => { |
||||
|
const result = JSON.parse(response.data)[0] |
||||
|
if (result.srcurl) { |
||||
|
item.imgPath = result.srcurl |
||||
|
return item |
||||
|
} else if (result.img) { |
||||
|
item.imgPath = 'data:image/png;base64,' + result.img |
||||
|
return item |
||||
|
} else { |
||||
|
return null |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
Promise.all(this.rankingList).then(results => { |
||||
|
this.rankingList = results.filter(item => item !== null) |
||||
|
this.initSwiper() |
||||
|
}) |
||||
|
|
||||
|
console.log('this.rankingList', this.rankingList) |
||||
|
}) |
||||
|
}, |
||||
|
// getBookList() { |
||||
|
// const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API |
||||
|
// const params = { |
||||
|
// libcode: this.libcode, |
||||
|
// pageNo: 1, |
||||
|
// pageSize: 10 |
||||
|
// } |
||||
|
// FetchNewBookRecommend(params).then(res => { |
||||
|
// console.log(res) |
||||
|
// this.rankingList = res.newbookList.map((item, index) => { |
||||
|
// if (item.nbImgPath) { |
||||
|
// item.cover = linkSrc + '/downloadFile' + item.nbImgPath |
||||
|
// } else { |
||||
|
// item.cover = null |
||||
|
// } |
||||
|
// return item |
||||
|
// }) |
||||
|
// this.initSwiper() |
||||
|
// }).catch(() => { |
||||
|
// this.$message.error('接口错误') |
||||
|
// }) |
||||
|
// }, |
||||
|
// getCoverByISBN(isbn, item) { |
||||
|
// const params = { |
||||
|
// isbn: isbn |
||||
|
// } |
||||
|
// FetchCoverByISBN(params).then((res) => { |
||||
|
// // item.cover = window.URL.createObjectURL(res) |
||||
|
// item.cover = res |
||||
|
// this.rankingList.push(item) |
||||
|
// this.initSwiper() |
||||
|
// }) |
||||
|
// }, |
||||
|
// 详情 |
||||
|
handleDetails(index) { |
||||
|
const params = { |
||||
|
isbn: this.rankingList[index].isbn.replace(/\-/g, '') |
||||
|
} |
||||
|
getBookDetailsByISBN(params).then(res => { |
||||
|
const linkSrc = process.env.NODE_ENV === 'production' ? window.g.ApiUrl : process.env.VUE_APP_BASE_API |
||||
|
res.imgPath = linkSrc + '/api/fileRelevant/getImg?imgType=2&imgId=' + res.bookCover |
||||
|
this.$refs.detailDom.bookData = res |
||||
|
|
||||
|
this.$refs.detailDom.dialogVisible = true |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.new-main{ |
||||
|
position: relative; |
||||
|
padding: 0 50px; |
||||
|
} |
||||
|
.new-book-list{ |
||||
|
color: #333; |
||||
|
.book-list-item{ |
||||
|
width: 100%; |
||||
|
box-shadow: 0px 0px 20px 1px #D2D2D2; |
||||
|
border-radius: 2px 2px 2px 2px; |
||||
|
} |
||||
|
.book-img{ |
||||
|
height: 6.575rem; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
overflow: hidden; |
||||
|
img{ |
||||
|
display: block; |
||||
|
width: 100%; |
||||
|
// height: 100%; |
||||
|
} |
||||
|
} |
||||
|
.book-info{ |
||||
|
padding: 10px 20px; |
||||
|
h4{ |
||||
|
font-weight: normal; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
p{ |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.icon{ |
||||
|
height: 1.1em; |
||||
|
} |
||||
|
.prev-btn, |
||||
|
.next-btn{ |
||||
|
position: absolute; |
||||
|
bottom: 60px; |
||||
|
font-size: 60px; |
||||
|
// color: #71C09E; |
||||
|
z-index: 999; |
||||
|
} |
||||
|
|
||||
|
.prev-btn{ |
||||
|
left: 100px; |
||||
|
} |
||||
|
|
||||
|
.next-btn{ |
||||
|
right: 100px; |
||||
|
} |
||||
|
|
||||
|
.swiper-container { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
.swiper-slide { |
||||
|
display: -webkit-box; |
||||
|
display: -ms-flexbox; |
||||
|
display: -webkit-flex; |
||||
|
display: flex; |
||||
|
-webkit-box-pack: center; |
||||
|
-ms-flex-pack: center; |
||||
|
-webkit-justify-content: center; |
||||
|
justify-content: center; |
||||
|
-webkit-box-align: center; |
||||
|
-ms-flex-align: center; |
||||
|
-webkit-align-items: center; |
||||
|
align-items: center; |
||||
|
transition: 300ms; |
||||
|
transform: scale(0.84); |
||||
|
.book-info{ |
||||
|
line-height: 20px; |
||||
|
font-size: 16px; |
||||
|
h4{ |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.swiper-slide.swiper-slide-prev, |
||||
|
.swiper-slide.swiper-slide-next { |
||||
|
font-size: 28px; |
||||
|
transform: scale(0.9); |
||||
|
.book-info{ |
||||
|
line-height: 28px; |
||||
|
font-size: 22px; |
||||
|
h4{ |
||||
|
font-size: 28px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.swiper-slide-active,.swiper-slide-duplicate-active { |
||||
|
transform: scaleX(1); |
||||
|
.book-info{ |
||||
|
line-height: 40px; |
||||
|
font-size: 28px; |
||||
|
h4{ |
||||
|
font-size: 40px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,158 @@ |
|||||
|
<template> |
||||
|
<!-- 数字资源 --> |
||||
|
<div class="content-main"> |
||||
|
<div class="swiper mySwiper"> |
||||
|
<div class="swiper-wrapper"> |
||||
|
<div v-for="(item,index) in swiperListTemp" :key="index" class="swiper-slide img-module"> |
||||
|
<div v-for="(cell,i) in item" :key="i" :class="{'item-big': i % 4 === 0 || i % 4 === 3, 'item-small': i % 4 === 1 || i % 4 === 2, 'main-item': true}" @click="jump(cell.linkUrl)"> |
||||
|
<img :src="cell.image" :alt="cell.overTitle || '图片'"> |
||||
|
<div class="title"> |
||||
|
{{ cell.overTitle }} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { Swiper } from 'vue-awesome-swiper' |
||||
|
import 'swiper/swiper-bundle.css' |
||||
|
import { FetchQueryTopicDetails, FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
|
||||
|
export default { |
||||
|
name: 'WaterfallFlow', |
||||
|
data() { |
||||
|
return { |
||||
|
rankingList: [] |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
swiperListTemp() { |
||||
|
let index = 0 |
||||
|
const count = 4 |
||||
|
const arrTemp = [] |
||||
|
const experts = this.rankingList |
||||
|
for (let i = 0; i < this.rankingList.length; i++) { |
||||
|
index = parseInt(i / count) |
||||
|
if (arrTemp.length <= index) { |
||||
|
arrTemp.push([]) |
||||
|
} |
||||
|
arrTemp[index].push(experts[i]) |
||||
|
} |
||||
|
return arrTemp |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.initSwiper() |
||||
|
}, |
||||
|
methods: { |
||||
|
initSwiper() { |
||||
|
this.$nextTick(() => { |
||||
|
new Swiper('.swiper', {}) |
||||
|
}) |
||||
|
}, |
||||
|
getQueryTopicDetails() { |
||||
|
const params = { |
||||
|
'id': this.$route.query.menuId |
||||
|
} |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log(res) |
||||
|
if (res && res.queryTopicList.length > 0) { |
||||
|
this.getInitQueryTopicContext(res) |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
}, |
||||
|
getInitQueryTopicContext(result) { |
||||
|
const params = { |
||||
|
'page': 0, |
||||
|
'size': 10, |
||||
|
'libcode': result.queryMenu.libcode, |
||||
|
'topicId': result.queryTopicList[0].id, |
||||
|
'topicType': result.queryTopicList[0].type |
||||
|
} |
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
const linkSrc = process.env.NODE_ENV === 'production' |
||||
|
? window.g.ApiUrl |
||||
|
: process.env.VUE_APP_BASE_API |
||||
|
|
||||
|
if (res && res.content && res.content.length > 0) { |
||||
|
this.rankingList = res.content.map(item => { |
||||
|
if (item && item.imgUrl) { |
||||
|
return { |
||||
|
...item, |
||||
|
image: `${linkSrc}/api/fileRelevant/getImg?imgType=2&imgId=${item.imgUrl}` |
||||
|
} |
||||
|
} |
||||
|
return { |
||||
|
...item, |
||||
|
image: null |
||||
|
} |
||||
|
}) |
||||
|
} else { |
||||
|
this.rankingList = [] |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('接口错误') |
||||
|
}) |
||||
|
}, |
||||
|
jump(url) { |
||||
|
window.location.href = url |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
.img-module { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
padding: 40px; |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
align-content: space-between; |
||||
|
.main-item { |
||||
|
position: relative; |
||||
|
img { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
border-radius: 30px; |
||||
|
} |
||||
|
.title { |
||||
|
position: absolute; |
||||
|
left: 50%; |
||||
|
top: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
font-family: "HuXiaoBoNanShenTi"; |
||||
|
font-size: 80px; |
||||
|
color: #333; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 3; |
||||
|
line-clamp: 3; |
||||
|
-webkit-box-orient: vertical; |
||||
|
} |
||||
|
} |
||||
|
.item-big { |
||||
|
width: 1000px; |
||||
|
height: 390px; |
||||
|
} |
||||
|
.item-small { |
||||
|
width: 800px; |
||||
|
height: 310px; |
||||
|
.title { |
||||
|
font-size: 64px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,342 @@ |
|||||
|
<template> |
||||
|
<!-- 数字资源 --> |
||||
|
<div class="content-main"> |
||||
|
<div class="swiper mySwiper"> |
||||
|
<div class="swiper-wrapper"> |
||||
|
<!-- 每个swiper-slide包含4个项目 --> |
||||
|
<div v-for="(group, groupIndex) in swiperGroups" :key="groupIndex" class="swiper-slide"> |
||||
|
<div class="img-module"> |
||||
|
<div |
||||
|
v-for="(cell, i) in group" |
||||
|
:key="i" |
||||
|
:class="{'item-big': i % 4 === 0 || i % 4 === 3, 'item-small': i % 4 === 1 || i % 4 === 2, 'main-item': true}" |
||||
|
@click="jump(cell.linkUrl)" |
||||
|
> |
||||
|
<img v-if="cell.image" :src="cell.image" :alt="cell.overTitle || '图片'"> |
||||
|
<div v-else class="placeholder" /> |
||||
|
<div class="title"> |
||||
|
{{ cell.overTitle }} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Swiper导航按钮 --> |
||||
|
<div class="swiper-button-prev" /> |
||||
|
<div class="swiper-button-next" /> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 加载更多按钮 --> |
||||
|
<div class="load-more" @click="loadMore"> |
||||
|
<span v-if="isLoading">加载中...</span> |
||||
|
<span v-else-if="hasMore">加载更多</span> |
||||
|
<!-- <span v-else>没有更多数据了</span> --> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { Swiper } from 'vue-awesome-swiper' |
||||
|
import 'swiper/swiper-bundle.css' |
||||
|
import { FetchQueryTopicDetails, FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
|
||||
|
export default { |
||||
|
name: 'WaterfallFlow', |
||||
|
components: { |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
rankingList: [], |
||||
|
swiperInstance: null, |
||||
|
pageParams: { |
||||
|
page: 0, |
||||
|
size: 100, |
||||
|
libcode: '', |
||||
|
topicId: '', |
||||
|
topicType: '' |
||||
|
}, |
||||
|
|
||||
|
hasMore: true, |
||||
|
isLoading: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// 将数据分成每组4个的数组,保持原始样式结构 |
||||
|
swiperGroups() { |
||||
|
const groups = [] |
||||
|
const itemsPerGroup = 4 |
||||
|
|
||||
|
for (let i = 0; i < this.rankingList.length; i += itemsPerGroup) { |
||||
|
// 从当前索引开始,截取4个元素作为一组 |
||||
|
groups.push(this.rankingList.slice(i, i + itemsPerGroup)) |
||||
|
} |
||||
|
|
||||
|
return groups |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
mounted() { |
||||
|
// 监听数据变化,更新Swiper |
||||
|
this.$watch('swiperGroups', (newVal) => { |
||||
|
if (newVal.length > 0) { |
||||
|
this.initSwiper() |
||||
|
} |
||||
|
}, { immediate: false }) |
||||
|
}, |
||||
|
methods: { |
||||
|
initSwiper() { |
||||
|
this.$nextTick(() => { |
||||
|
if (this.swiperInstance) { |
||||
|
this.swiperInstance.destroy(true, true) |
||||
|
} |
||||
|
|
||||
|
// 创建新实例,保持横向滑动效果 |
||||
|
this.swiperInstance = new Swiper('.mySwiper', { |
||||
|
direction: 'horizontal', |
||||
|
slidesPerView: 1, // 每次显示一个组 |
||||
|
speed: 500, |
||||
|
loop: false, |
||||
|
navigation: { |
||||
|
nextEl: '.swiper-button-next', |
||||
|
prevEl: '.swiper-button-prev' |
||||
|
}, |
||||
|
pagination: { |
||||
|
el: '.swiper-pagination', |
||||
|
clickable: true, |
||||
|
renderBullet: function(index, className) { |
||||
|
return `<span class="${className}">${index + 1}</span>` |
||||
|
} |
||||
|
}, |
||||
|
observer: true, |
||||
|
observeParents: true |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
getQueryTopicDetails() { |
||||
|
const params = { |
||||
|
'id': this.$route.query.menuId |
||||
|
} |
||||
|
|
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log('主题详情:', res) |
||||
|
if (res && res.queryTopicList && res.queryTopicList.length > 0) { |
||||
|
this.pageParams.libcode = res.queryMenu.libcode |
||||
|
this.pageParams.topicId = res.queryTopicList[0].id |
||||
|
this.pageParams.topicType = res.queryTopicList[0].type |
||||
|
|
||||
|
this.loadMore() |
||||
|
} else { |
||||
|
this.hasMore = false |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('获取主题详情失败') |
||||
|
this.hasMore = false |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
loadMore() { |
||||
|
if (this.isLoading || !this.hasMore) return |
||||
|
|
||||
|
this.isLoading = true |
||||
|
|
||||
|
const params = { |
||||
|
page: this.pageParams.page, |
||||
|
size: this.pageParams.size, |
||||
|
libcode: this.pageParams.libcode, |
||||
|
topicId: this.pageParams.topicId, |
||||
|
topicType: this.pageParams.topicType |
||||
|
} |
||||
|
|
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
console.log('获取数据:', res) |
||||
|
|
||||
|
if (res && res.content && res.content.length > 0) { |
||||
|
const linkSrc = process.env.NODE_ENV === 'production' |
||||
|
? window.g.ApiUrl |
||||
|
: process.env.VUE_APP_BASE_API |
||||
|
|
||||
|
const newItems = res.content.map(item => ({ |
||||
|
...item, |
||||
|
image: item.imgUrl ? `${linkSrc}/api/fileRelevant/getImg?imgType=2&imgId=${item.imgUrl}` : null |
||||
|
})) |
||||
|
|
||||
|
this.rankingList = [...this.rankingList, ...newItems] |
||||
|
|
||||
|
this.hasMore = newItems.length >= this.pageParams.size |
||||
|
|
||||
|
this.pageParams.page++ |
||||
|
} else { |
||||
|
this.hasMore = false |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('获取数据失败') |
||||
|
}).finally(() => { |
||||
|
this.isLoading = false |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
jump(url) { |
||||
|
if (url) { |
||||
|
window.location.href = url |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
// 保持原始样式不变 |
||||
|
.img-module { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
padding: 40px; |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
align-content: space-between; |
||||
|
|
||||
|
.main-item { |
||||
|
position: relative; |
||||
|
cursor: pointer; |
||||
|
transition: transform 0.3s ease; |
||||
|
|
||||
|
&:hover { |
||||
|
transform: translateY(-5px); |
||||
|
} |
||||
|
|
||||
|
img { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
border-radius: 30px; |
||||
|
object-fit: cover; |
||||
|
} |
||||
|
|
||||
|
.placeholder { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
background-color: #f5f5f5; |
||||
|
border-radius: 30px; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
position: absolute; |
||||
|
left: 50%; |
||||
|
top: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
font-family: "HuXiaoBoNanShenTi"; |
||||
|
font-size: 80px; |
||||
|
color: #333; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
display: -webkit-box; |
||||
|
-webkit-line-clamp: 3; |
||||
|
line-clamp: 3; |
||||
|
-webkit-box-orient: vertical; |
||||
|
text-shadow: 0 2px 4px rgba(255, 255, 255, 0.8); |
||||
|
padding: 0 20px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.item-big { |
||||
|
width: 1000px; |
||||
|
height: 390px; |
||||
|
} |
||||
|
|
||||
|
.item-small { |
||||
|
width: 800px; |
||||
|
height: 310px; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 64px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 加载更多按钮样式 |
||||
|
.load-more { |
||||
|
position: fixed; |
||||
|
bottom: 20px; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
padding: 30px 0; |
||||
|
font-size: 18px; |
||||
|
color: #666; |
||||
|
z-index: 9999; |
||||
|
cursor: pointer; |
||||
|
transition: color 0.3s; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #007bff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Swiper导航按钮样式 |
||||
|
.swiper-button-prev, |
||||
|
.swiper-button-next { |
||||
|
width: 50px; |
||||
|
height: 50px; |
||||
|
background-color: rgba(255, 255, 255, 0.8); |
||||
|
border-radius: 50%; |
||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
||||
|
|
||||
|
&::after { |
||||
|
font-size: 20px; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.swiper-button-prev { |
||||
|
left: 10px; |
||||
|
} |
||||
|
|
||||
|
.swiper-button-next { |
||||
|
right: 10px; |
||||
|
} |
||||
|
|
||||
|
.swiper-pagination { |
||||
|
bottom: 0; |
||||
|
|
||||
|
.swiper-pagination-bullet { |
||||
|
width: 12px; |
||||
|
height: 12px; |
||||
|
margin: 0 6px; |
||||
|
background-color: #ddd; |
||||
|
|
||||
|
&.swiper-pagination-bullet-active { |
||||
|
background-color: #007bff; |
||||
|
width: 30px; |
||||
|
border-radius: 6px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 1920px) { |
||||
|
.item-big { |
||||
|
width: calc(50% - 20px); |
||||
|
height: auto; |
||||
|
} |
||||
|
|
||||
|
.item-small { |
||||
|
width: calc(25% - 20px); |
||||
|
height: auto; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 1200px) { |
||||
|
.main-item .title { |
||||
|
font-size: 60px; |
||||
|
} |
||||
|
|
||||
|
.item-small .title { |
||||
|
font-size: 48px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,160 @@ |
|||||
|
<template> |
||||
|
<div class="content-main" style="padding: 40px;"> |
||||
|
<waterfall |
||||
|
:list="dataList" |
||||
|
:columns="columns" |
||||
|
:loading="loading" |
||||
|
:placeholder="placeholderImg" |
||||
|
:total-items="totalItems" |
||||
|
@scroll-end="loadMoreData" |
||||
|
/> |
||||
|
</div> |
||||
|
<!-- <div class="controls"> |
||||
|
<button :class="{ active: columns === 2 }" @click="columns = 2">2列</button> |
||||
|
<button :class="{ active: columns === 3 }" @click="columns = 3">3列</button> |
||||
|
<button :class="{ active: columns === 4 }" @click="columns = 4">4列</button> |
||||
|
</div> --> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Waterfall from './module/waterfall.vue' |
||||
|
import { FetchQueryTopicDetails, FetchInitQueryTopicContext } from '@/api/inquiryMachine' |
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
Waterfall |
||||
|
}, |
||||
|
|
||||
|
data() { |
||||
|
return { |
||||
|
columns: 2, |
||||
|
dataList: [], |
||||
|
loading: false, |
||||
|
currentPage: 0, |
||||
|
pageSize: 10, |
||||
|
totalItems: 0, |
||||
|
topicInfo: null, |
||||
|
placeholderImg: require('@/assets/images/default-img.png') |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
created() { |
||||
|
this.getQueryTopicDetails() |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
getQueryTopicDetails() { |
||||
|
this.loading = true |
||||
|
const params = { |
||||
|
'id': this.$route.query.menuId |
||||
|
} |
||||
|
FetchQueryTopicDetails(params).then(res => { |
||||
|
console.log('主题详情数据:', res) |
||||
|
if (res && res.queryTopicList && res.queryTopicList.length > 0) { |
||||
|
this.topicInfo = res |
||||
|
this.currentPage = 0 |
||||
|
this.getInitQueryTopicContext() |
||||
|
} else { |
||||
|
this.$message.warning('未找到相关主题数据') |
||||
|
this.loading = false |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('获取主题详情失败') |
||||
|
this.loading = false |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
// 获取主题内容 |
||||
|
getInitQueryTopicContext() { |
||||
|
if (!this.topicInfo) return |
||||
|
|
||||
|
this.loading = true |
||||
|
const params = { |
||||
|
'page': this.currentPage, |
||||
|
'size': this.pageSize, |
||||
|
'libcode': this.topicInfo.queryMenu.libcode, |
||||
|
'topicId': this.topicInfo.queryTopicList[0].id, |
||||
|
'topicType': this.topicInfo.queryTopicList[0].type |
||||
|
} |
||||
|
|
||||
|
FetchInitQueryTopicContext(params).then(res => { |
||||
|
this.loading = false |
||||
|
// console.log('res.totalElements', res.totalElements) |
||||
|
if (res.totalElements) { |
||||
|
this.totalItems = res.totalElements |
||||
|
} |
||||
|
|
||||
|
const linkSrc = process.env.NODE_ENV === 'production' |
||||
|
? window.g.ApiUrl |
||||
|
: process.env.VUE_APP_BASE_API |
||||
|
|
||||
|
if (res && res.content && res.content.length > 0) { |
||||
|
const formattedData = res.content.map(item => ({ |
||||
|
id: item.id || `item-${Date.now()}-${Math.random()}`, |
||||
|
type: 'image', |
||||
|
title: item.overTitle || '无标题', |
||||
|
image: item.imgUrl ? `${linkSrc}/api/fileRelevant/getImg?imgType=2&imgId=${item.imgUrl}` : this.placeholderImg, |
||||
|
linkUrl: item.linkUrl || '#' |
||||
|
})) |
||||
|
|
||||
|
this.dataList = [...this.dataList, ...formattedData] |
||||
|
// console.log(`第${this.currentPage + 1}页加载后总条数:`, this.dataList.length) |
||||
|
} else { |
||||
|
this.totalItems = this.dataList.length |
||||
|
} |
||||
|
}).catch(() => { |
||||
|
this.$message.error('获取主题内容失败') |
||||
|
this.loading = false |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
// 加载更多数据 |
||||
|
loadMoreData() { |
||||
|
if (this.dataList.length >= this.totalItems) { |
||||
|
// console.log('已加载全部5条数据') |
||||
|
return |
||||
|
} |
||||
|
if (this.loading) return |
||||
|
|
||||
|
this.currentPage++ |
||||
|
// console.log('开始加载第', this.currentPage + 1, '页') |
||||
|
this.getInitQueryTopicContext() |
||||
|
}, |
||||
|
|
||||
|
isAllDataLoaded() { |
||||
|
if (this.totalItems > 0) { |
||||
|
return this.dataList.length >= this.totalItems |
||||
|
} |
||||
|
return this.currentPage > 0 && this.dataList.length % this.pageSize !== 0 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/index.scss"; |
||||
|
// .controls { |
||||
|
// margin-bottom: 20px; |
||||
|
// display: flex; |
||||
|
// gap: 10px; |
||||
|
// padding: 0 16px; |
||||
|
// } |
||||
|
|
||||
|
// .controls button { |
||||
|
// padding: 8px 16px; |
||||
|
// background: #f0f0f0; |
||||
|
// border: none; |
||||
|
// border-radius: 4px; |
||||
|
// cursor: pointer; |
||||
|
// transition: all 0.2s ease; |
||||
|
// } |
||||
|
|
||||
|
// .controls button:hover { |
||||
|
// background: #e0e0e0; |
||||
|
// } |
||||
|
|
||||
|
// .controls button.active { |
||||
|
// background: #ff2442; |
||||
|
// color: white; |
||||
|
// } |
||||
|
</style> |
||||
@ -0,0 +1,61 @@ |
|||||
|
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: 3000, |
||||
|
open: true, |
||||
|
overlay: { |
||||
|
warnings: false, |
||||
|
errors: true |
||||
|
}, |
||||
|
proxy: { |
||||
|
'/api': { |
||||
|
target: process.env.VUE_APP_BASE_API, |
||||
|
changeOrigin: true, |
||||
|
pathRewrite: { |
||||
|
'^/api': 'api' |
||||
|
} |
||||
|
}, |
||||
|
'/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 = name |
||||
|
return args |
||||
|
}) |
||||
|
} |
||||
|
} |
||||