初始化仓库
This commit is contained in:
commit
a3e1479bda
24
.env
Normal file
24
.env
Normal file
@ -0,0 +1,24 @@
|
||||
# 代理接口前缀
|
||||
VITE_API_PREFIX = '/api'
|
||||
|
||||
# 接口地址,可在其它环境配置文件进行覆盖
|
||||
VITE_API_URL = 'http://localhost:10010'
|
||||
|
||||
# 静态资源地址
|
||||
VITE_RESOURCE_PREFIX = 'http://localhost:10010/resource'
|
||||
|
||||
# 站点配置
|
||||
# - 站点标题
|
||||
VITE_SITE_TITLE = '天津市南开区民政局'
|
||||
# - 站点副标题
|
||||
VITE_SITE_SUB_TITLE = ''
|
||||
# - 主办单位
|
||||
VITE_SITE_ORGANIZATION = '天津市南开区民政局'
|
||||
# - 备案号
|
||||
VITE_SITE_ICP = '津ICP备2021010010号-3'
|
||||
# - 地址
|
||||
VITE_SITE_ADDRESS = '天津市南开区'
|
||||
|
||||
# SEO配置
|
||||
VITE_SEO_KEYWORDS = '天津市南开区民政局'
|
||||
VITE_SEO_DESCRIPTION = '天津市南开区民政局'
|
1
.env.development
Normal file
1
.env.development
Normal file
@ -0,0 +1 @@
|
||||
VITE_APP_ENV = 'development'
|
4
.env.production
Normal file
4
.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# 接口地址
|
||||
VITE_API_URL = 'http://localhost:10010/'
|
4
.env.staging
Normal file
4
.env.staging
Normal file
@ -0,0 +1,4 @@
|
||||
VITE_APP_ENV = 'staging'
|
||||
|
||||
# 接口地址
|
||||
VITE_API_URL = 'http://localhost:10010/'
|
18
.eslintrc.cjs
Normal file
18
.eslintrc.cjs
Normal file
@ -0,0 +1,18 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'plugin:nuxt/recommended',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
},
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 0, // 针对单个单词组件报错的规则关闭
|
||||
}
|
||||
}
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
75
.kit/kit.json
Normal file
75
.kit/kit.json
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "eva-cms-website-gov",
|
||||
"label": "eva-cms-website-gov",
|
||||
"version": "1.0.0.3",
|
||||
"private": false,
|
||||
"receivable": false,
|
||||
"compiler": "static",
|
||||
"repository": "",
|
||||
"branch": "",
|
||||
"supportedDatabases": [],
|
||||
"presetPlugins": [],
|
||||
"prices": [
|
||||
{
|
||||
"type": "FREE",
|
||||
"value": 0
|
||||
}
|
||||
],
|
||||
"builds": [
|
||||
{
|
||||
"name": "安装项目依赖",
|
||||
"type": "Markdown",
|
||||
"content": "执行以下命令安装项目依赖\n```shell\nnpm install --registry https://registry.npmmirror.com\n```",
|
||||
"contentType": "string"
|
||||
},
|
||||
{
|
||||
"name": "启动项目",
|
||||
"type": "Markdown",
|
||||
"content": "待项目依赖安装完成后,执行以下命令即可启动项目\n```shell\nnpm run dev\n```",
|
||||
"contentType": "string"
|
||||
}
|
||||
],
|
||||
"unbuilds": [],
|
||||
"variables": [
|
||||
{
|
||||
"id": "4DJOSGBHZ22OWW",
|
||||
"type": "variable",
|
||||
"name": "title",
|
||||
"label": "站点标题",
|
||||
"inputType": "input",
|
||||
"required": true,
|
||||
"hidden": false,
|
||||
"defaultValue": "伊娃CMS政企门户主题",
|
||||
"compiler": "static",
|
||||
"remark": ""
|
||||
},
|
||||
{
|
||||
"id": "1YFFECYGK5GGOC",
|
||||
"type": "variable",
|
||||
"name": "subTitle",
|
||||
"label": "站点副标题",
|
||||
"inputType": "input",
|
||||
"required": true,
|
||||
"hidden": false,
|
||||
"defaultValue": "金镐开源组织研发,免费、开源、轻量、高规范",
|
||||
"compiler": "static",
|
||||
"remark": ""
|
||||
}
|
||||
],
|
||||
"translator": {
|
||||
"output": ".kit/translated",
|
||||
"filepath": "",
|
||||
"content": "if (filename === '.env') {\n content = content\n .replace('伊娃CMS政企门户主题', '${title}')\n .replace('金镐开源组织研发,免费、开源、轻量、高规范', '${subTitle}')\n}\nreturn content"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"path": ".env",
|
||||
"compiler": "freemarker",
|
||||
"withoutIfNotExists": false,
|
||||
"enableExpress": "",
|
||||
"variables": []
|
||||
}
|
||||
],
|
||||
"introduce": "🇨🇳Eva CMS 政企门户站点主题,采用Nuxt3 + Element Plus + Sass实现。前后端分离,扩展功能更方便。",
|
||||
"readme": "<div align=\"center\">\n <img src=\"https://adjustrd-public.oss-cn-shenzhen.aliyuncs.com/eva-cms/logo.png\" width=\"120px\" style=\"width:80px;height:80px;\" />\n <h1>伊娃CMS政企门户主题</h1>\n</div>\n\n## 在线演示 & 技术文档\n\n- 演示地址/政企门户主题:[http://gov.eva-cms.goldpankit.com/](http://gov.eva-cms.goldpankit.com/)\n- 演示地址/后台管理:[http://admin.eva-cms.goldpankit.com/](http://admin.eva-cms.goldpankit.com/)\n- 官方文档:[https://www.yuque.com/u21334242/eva-cms](https://www.yuque.com/u21334242/eva-cms)\n\n\n## 金镐开源组织生态项目\n\n| 版本 | 说明 | 开源地址 | 构建地址 |\n|---------------------|-------------------|--------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|\n| eva-cms | 伊娃CMS后端 | [https://gitee.com/goldpankit/eva-cms](https://gitee.com/goldpankit/eva-cms) | [http://goldpankit.com/space/Eva/eva-cms](http://goldpankit.com/space/Eva/eva-cms) |\n| eva-cms-admin-front | 伊娃CMS后台管理前端 | [https://gitee.com/goldpankit/eva-cms-admin-front](https://gitee.com/goldpankit/eva-cms-admin-front) | [http://goldpankit.com/space/Eva/eva-cms-admin-front](http://goldpankit.com/space/Eva/eva-cms-admin-front) |\n| eva-cms-website-gov | 伊娃CMS政企门户主题站点前端 | [https://gitee.com/goldpankit/eva-cms-website-gov](https://gitee.com/goldpankit/eva-cms-website-gov) | [http://goldpankit.com/space/Eva/eva-cms-website-gov](http://goldpankit.com/space/Eva/eva-cms-website-gov) |\n| eva-server | 伊娃权限系统单工程版本 | [https://gitee.com/goldpankit/eva-server](https://gitee.com/goldpankit/eva-server) | [http://goldpankit.com/space/Eva/eva-server](http://goldpankit.com/space/Eva/eva-server) |\n| eva-server-modules | 伊娃权限系统Maven多模块版本 | [https://gitee.com/goldpankit/eva-server-modules](https://gitee.com/goldpankit/eva-server-modules) | [http://www.goldpankit.com/space/Eva/eva-server-modules](http://www.goldpankit.com/space/Eva/eva-server-modules) |\n| eva-vue2 | 伊娃权限系统前端vue2版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue2/](https://gitee.com/goldpankit/eva-vue/tree/vue2/) | [http://goldpankit.com/space/Eva/eva-vue2](http://goldpankit.com/space/Eva/eva-vue2) |\n| eva-vue3-options | 伊娃权限系统前端vue3选项式版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue3-options/](https://gitee.com/goldpankit/eva-vue/tree/vue3-options/) | [http://www.goldpankit.com/space/Eva/eva-vue3-options](http://www.goldpankit.com/space/Eva/eva-vue3-options) |\n\n\n## 项目特点\n\n1. 可扩展的功能模块,默认情况下提供了文章管理、栏目管理、资源管理、模板管理等CMS系统的基础模块,以及用户管理、角色管理、菜单管理等权限系统基础模块,使用GoldPanKit可进一步进行源码级功能模块的扩展。\n2. 不用担心存在BUG,如果存在BUG,使用GoldPanKit可实现一键升级。\n3. 不用担心存在安全漏洞,如果存在安全漏洞,GoldPanKit会进行提醒并支持一键升级。\n4. 规范化代码 + 详细的代码注释。\n5. 基于Eva 4权限系统进行研发,安全稳定!\n6. 丰富的插件市场,可使用GoldPanKit进行单表、多表的页面生成。\n\n## 绝对优势\n\n结合GoldPanKit可实现代码直接生成到项目中,安装更多的功能模块,一键修复BUG等。\n\n## 项目预览\n\n**登录页**\n\n\n**文章管理**\n\n\n**栏目管理**\n\n\n**资源管理**\n\n\n\n**模板管理**\n\n"
|
||||
}
|
24
.kit/translated/.env
Normal file
24
.kit/translated/.env
Normal file
@ -0,0 +1,24 @@
|
||||
# 代理接口前缀
|
||||
VITE_API_PREFIX = '/api'
|
||||
|
||||
# 接口地址,可在其它环境配置文件进行覆盖
|
||||
VITE_API_URL = 'http://localhost:10020'
|
||||
|
||||
# 静态资源地址
|
||||
VITE_RESOURCE_PREFIX = '/resource'
|
||||
|
||||
# 站点配置
|
||||
# - 站点标题
|
||||
VITE_SITE_TITLE = '${title}'
|
||||
# - 站点副标题
|
||||
VITE_SITE_SUB_TITLE = '${subTitle}'
|
||||
# - 主办单位
|
||||
VITE_SITE_ORGANIZATION = '金镐开源组织'
|
||||
# - 备案号
|
||||
VITE_SITE_ICP = '湘ICP备2021010010号-3'
|
||||
# - 地址
|
||||
VITE_SITE_ADDRESS = '湖南省郴州市桂阳县'
|
||||
|
||||
# SEO配置
|
||||
VITE_SEO_KEYWORDS = '伊娃CMS,轻量级CMS系统,政府门户主题'
|
||||
VITE_SEO_DESCRIPTION = '伊娃CMS政府门户主题,基于Nuxt3、Element Plus、SpringBoot、MyBatisPlus、MySQL等主流技术栈构建,轻量、简洁、质量。'
|
1
.kit/translated/.env.development
Normal file
1
.kit/translated/.env.development
Normal file
@ -0,0 +1 @@
|
||||
VITE_APP_ENV = 'development'
|
4
.kit/translated/.env.production
Normal file
4
.kit/translated/.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# 接口地址
|
||||
VITE_API_URL = 'http://localhost:10020/'
|
4
.kit/translated/.env.staging
Normal file
4
.kit/translated/.env.staging
Normal file
@ -0,0 +1,4 @@
|
||||
VITE_APP_ENV = 'staging'
|
||||
|
||||
# 接口地址
|
||||
VITE_API_URL = 'http://localhost:10020/'
|
18
.kit/translated/.eslintrc.cjs
Normal file
18
.kit/translated/.eslintrc.cjs
Normal file
@ -0,0 +1,18 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'plugin:nuxt/recommended',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
},
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 0, // 针对单个单词组件报错的规则关闭
|
||||
}
|
||||
}
|
19
.kit/translated/.gitignore
vendored
Normal file
19
.kit/translated/.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
5
.kit/translated/.prettierignore
Normal file
5
.kit/translated/.prettierignore
Normal file
@ -0,0 +1,5 @@
|
||||
# 规范代码格式时的忽略文件
|
||||
.*
|
||||
*.json
|
||||
*.md
|
||||
node_modules/**
|
8
.kit/translated/.prettierrc.json
Normal file
8
.kit/translated/.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
21
.kit/translated/LICENSE
Normal file
21
.kit/translated/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 金镐开源组织
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
55
.kit/translated/README.md
Normal file
55
.kit/translated/README.md
Normal file
@ -0,0 +1,55 @@
|
||||
<div align="center">
|
||||
<img src="https://adjustrd-public.oss-cn-shenzhen.aliyuncs.com/eva-cms/logo.png" width="120px" style="width:80px;height:80px;" />
|
||||
<h1>伊娃CMS政企门户主题</h1>
|
||||
</div>
|
||||
|
||||
## 在线演示 & 技术文档
|
||||
|
||||
- 演示地址/政企门户主题:[http://gov.eva-cms.goldpankit.com/](http://gov.eva-cms.goldpankit.com/)
|
||||
- 演示地址/后台管理:[http://admin.eva-cms.goldpankit.com/](http://admin.eva-cms.goldpankit.com/)
|
||||
- 官方文档:[https://www.yuque.com/u21334242/eva-cms](https://www.yuque.com/u21334242/eva-cms)
|
||||
|
||||
|
||||
## 金镐开源组织生态项目
|
||||
|
||||
| 版本 | 说明 | 开源地址 | 构建地址 |
|
||||
|---------------------|-------------------|--------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| eva-cms | 伊娃CMS后端 | [https://gitee.com/goldpankit/eva-cms](https://gitee.com/goldpankit/eva-cms) | [http://goldpankit.com/space/Eva/eva-cms](http://goldpankit.com/space/Eva/eva-cms) |
|
||||
| eva-cms-admin-front | 伊娃CMS后台管理前端 | [https://gitee.com/goldpankit/eva-cms-admin-front](https://gitee.com/goldpankit/eva-cms-admin-front) | [http://goldpankit.com/space/Eva/eva-cms-admin-front](http://goldpankit.com/space/Eva/eva-cms-admin-front) |
|
||||
| eva-cms-website-gov | 伊娃CMS政企门户主题站点前端 | [https://gitee.com/goldpankit/eva-cms-website-gov](https://gitee.com/goldpankit/eva-cms-website-gov) | [http://goldpankit.com/space/Eva/eva-cms-website-gov](http://goldpankit.com/space/Eva/eva-cms-website-gov) |
|
||||
| eva-server | 伊娃权限系统单工程版本 | [https://gitee.com/goldpankit/eva-server](https://gitee.com/goldpankit/eva-server) | [http://goldpankit.com/space/Eva/eva-server](http://goldpankit.com/space/Eva/eva-server) |
|
||||
| eva-server-modules | 伊娃权限系统Maven多模块版本 | [https://gitee.com/goldpankit/eva-server-modules](https://gitee.com/goldpankit/eva-server-modules) | [http://www.goldpankit.com/space/Eva/eva-server-modules](http://www.goldpankit.com/space/Eva/eva-server-modules) |
|
||||
| eva-vue2 | 伊娃权限系统前端vue2版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue2/](https://gitee.com/goldpankit/eva-vue/tree/vue2/) | [http://goldpankit.com/space/Eva/eva-vue2](http://goldpankit.com/space/Eva/eva-vue2) |
|
||||
| eva-vue3-options | 伊娃权限系统前端vue3选项式版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue3-options/](https://gitee.com/goldpankit/eva-vue/tree/vue3-options/) | [http://www.goldpankit.com/space/Eva/eva-vue3-options](http://www.goldpankit.com/space/Eva/eva-vue3-options) |
|
||||
|
||||
|
||||
## 项目特点
|
||||
|
||||
1. 可扩展的功能模块,默认情况下提供了文章管理、栏目管理、资源管理、模板管理等CMS系统的基础模块,以及用户管理、角色管理、菜单管理等权限系统基础模块,使用GoldPanKit可进一步进行源码级功能模块的扩展。
|
||||
2. 不用担心存在BUG,如果存在BUG,使用GoldPanKit可实现一键升级。
|
||||
3. 不用担心存在安全漏洞,如果存在安全漏洞,GoldPanKit会进行提醒并支持一键升级。
|
||||
4. 规范化代码 + 详细的代码注释。
|
||||
5. 基于Eva 4权限系统进行研发,安全稳定!
|
||||
6. 丰富的插件市场,可使用GoldPanKit进行单表、多表的页面生成。
|
||||
|
||||
## 绝对优势
|
||||
|
||||
结合GoldPanKit可实现代码直接生成到项目中,安装更多的功能模块,一键修复BUG等。
|
||||
|
||||
## 项目预览
|
||||
|
||||
**登录页**
|
||||

|
||||
|
||||
**文章管理**
|
||||

|
||||
|
||||
**栏目管理**
|
||||

|
||||
|
||||
**资源管理**
|
||||

|
||||

|
||||
|
||||
**模板管理**
|
||||

|
6
.kit/translated/api/client.js
Normal file
6
.kit/translated/api/client.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取客户端配置
|
||||
export function fetchConfig () {
|
||||
return request.get('/client/config')
|
||||
}
|
6
.kit/translated/api/cms/article.js
Normal file
6
.kit/translated/api/cms/article.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取文章分页数据
|
||||
export function fetchArticlePage (data) {
|
||||
return request.post('/article/profile/page', data)
|
||||
}
|
11
.kit/translated/api/cms/category.js
Normal file
11
.kit/translated/api/cms/category.js
Normal file
@ -0,0 +1,11 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取栏目树
|
||||
export function fetchCategoryTree () {
|
||||
return request.post('/category/tree')
|
||||
}
|
||||
|
||||
// 获取子栏目树
|
||||
export function fetchSubCategoryTree (parentCategoryUid) {
|
||||
return request.post(`/category/${parentCategoryUid}/tree`)
|
||||
}
|
6
.kit/translated/api/cms/resource.js
Normal file
6
.kit/translated/api/cms/resource.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取资源列表
|
||||
export function fetchResources (groupUid) {
|
||||
return request.post(`/resource/${groupUid}/list`)
|
||||
}
|
6
.kit/translated/api/cms/search.js
Normal file
6
.kit/translated/api/cms/search.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 站内搜索
|
||||
export function search (data) {
|
||||
return request.post('/search', data)
|
||||
}
|
6
.kit/translated/api/cms/template.js
Normal file
6
.kit/translated/api/cms/template.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取模板数据
|
||||
export function fetchTemplateData (data) {
|
||||
return request.post('/template/data', data)
|
||||
}
|
5
.kit/translated/app.vue
Normal file
5
.kit/translated/app.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
64
.kit/translated/assets/style/app.scss
Normal file
64
.kit/translated/assets/style/app.scss
Normal file
@ -0,0 +1,64 @@
|
||||
html body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: url("/public/images/background.jpg") repeat;
|
||||
background-color: var(--page-background);
|
||||
font-size: var(--font-size-base);
|
||||
font-family: var(--font-family-base);
|
||||
min-width: var(--body-min-width);
|
||||
.content-wrap {
|
||||
width: var(--page-width);
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
&:link {
|
||||
color: var(--font-color);
|
||||
}
|
||||
}
|
||||
// 加载动画
|
||||
#nprogress {
|
||||
--loading-color: red;
|
||||
// 改变进度条的颜色
|
||||
.bar {
|
||||
background: var(--loading-color) !important;
|
||||
}
|
||||
// 改变进度条的阴影颜色
|
||||
.peg {
|
||||
box-shadow: 0 0 10px var(--loading-color), 0 0 5px var(--loading-color) !important; /* 这里设置阴影颜色 */
|
||||
}
|
||||
// 改变进度条的旋转动画颜色
|
||||
.spinner-icon {
|
||||
border-top-color: var(--loading-color) !important;
|
||||
border-left-color: var(--loading-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单
|
||||
.el-menu {
|
||||
--el-menu-bg-color: var(--primary-color-dark);
|
||||
--el-menu-text-color: var(--color-white);
|
||||
--el-menu-hover-bg-color: var(--primary-color-dark);
|
||||
--el-bg-color-overlay: var(--primary-color-dark);
|
||||
--el-menu-item-font-size: var(--font-size-large);
|
||||
--el-border-color-light: var(--primary-color-dark);
|
||||
}
|
||||
|
||||
// 页面标题
|
||||
.page-title {
|
||||
--font-size-title: 25px;
|
||||
color: var(--primary-color-dark);
|
||||
font-size: var(--font-size-title);
|
||||
margin: 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
34
.kit/translated/assets/style/theme.scss
Normal file
34
.kit/translated/assets/style/theme.scss
Normal file
@ -0,0 +1,34 @@
|
||||
body {
|
||||
// 页面
|
||||
--page-width: 1280px;
|
||||
--page-background: #f7f7f7;
|
||||
// - body最小宽度,避免屏幕过窄时页面溢出
|
||||
--body-min-width: calc(var(--page-width) + 60px);
|
||||
// 主题色
|
||||
--primary-color: #224b9d;
|
||||
--primary-color-light: #285dc4;
|
||||
--primary-color-light-deep: #e5ebff;
|
||||
--primary-color-dark: #224da2;
|
||||
--primary-color-dark-deep: #16336b;
|
||||
// 字体
|
||||
--font-size-base: 16px;
|
||||
--font-size-small: 14px;
|
||||
--font-size-middle: 18px;
|
||||
--font-size-large: 20px;
|
||||
--font-family-base: "微软雅黑";
|
||||
--font-color: #333;
|
||||
// 背景色
|
||||
--background-color: #f7f7f7;
|
||||
// 颜色
|
||||
--color-white: #ffffff;
|
||||
--color-gray: #999;
|
||||
--color-gray-light: #ccc;
|
||||
--color-keyword: #ff0000;
|
||||
// 边框
|
||||
--border-color: #eee;
|
||||
// 子栏目树
|
||||
--sub-category-width: 275px;
|
||||
|
||||
// 覆盖element-plus的默认字体大小
|
||||
--el-font-size-base: var(--font-size-base);
|
||||
}
|
95
.kit/translated/components/cms/ArticleList.vue
Normal file
95
.kit/translated/components/cms/ArticleList.vue
Normal file
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<ul v-if="articles.length > 0" class="article-list">
|
||||
<li v-for="article in articles" :key="article.uid">
|
||||
<nuxt-link :to="`/article/${article.uid}`" target="_blank">
|
||||
<span class="title" v-html="getTitle(article)"></span>
|
||||
<span class="date">{{ article.updatedAt }}</span>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
</ul>
|
||||
<EmptyTip v-else/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyTip from '@/components/common/EmptyTip'
|
||||
|
||||
export default {
|
||||
name: 'ArticleList',
|
||||
components: { EmptyTip },
|
||||
props: {
|
||||
// 文章列表
|
||||
articles: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 关键字
|
||||
keyword: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取标题
|
||||
getTitle (article) {
|
||||
// 存在关键字时,为关键字添加em标签
|
||||
if (this.keyword != null && this.keyword.trim().length > 0) {
|
||||
return article.title.replace(new RegExp(this.keyword, 'g'), `<em>${this.keyword}</em>`)
|
||||
}
|
||||
return article.title
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul.article-list {
|
||||
padding: 10px 0 15px;
|
||||
li {
|
||||
border-bottom: 1px dashed var(--color-gray-light);
|
||||
&:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
li a {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px 10px 15px 25px;
|
||||
color: var(--font-color);
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
// 前方灰点
|
||||
&::before {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: var(--color-gray);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
// 标题
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
padding-right: 20px;
|
||||
// 关键字
|
||||
:deep(em) {
|
||||
font-style: normal;
|
||||
color: var(--color-keyword);
|
||||
}
|
||||
}
|
||||
// 日期
|
||||
.date {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-gray);
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
63
.kit/translated/components/cms/ArticlePreview.vue
Normal file
63
.kit/translated/components/cms/ArticlePreview.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="article-preview">
|
||||
<!-- 标题 -->
|
||||
<h2>{{ data.title }}</h2>
|
||||
<!-- 信息 -->
|
||||
<ul class="article-information">
|
||||
<li>
|
||||
<label>发布时间:</label>
|
||||
{{ data.updatedAt || data.createdAt }}
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 内容 -->
|
||||
<article v-html="data.content"></article>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
export default {
|
||||
name: 'ArticlePreview',
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.article-preview {
|
||||
--article-title: 30px;
|
||||
--article-content-font-size: 16px;
|
||||
--article-content-font-color: #555;
|
||||
// 标题
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: var(--primary-color);
|
||||
font-size: var(--article-title);
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
padding: 0 20px;
|
||||
word-break: break-all;
|
||||
}
|
||||
// 文章信息
|
||||
.article-information {
|
||||
color: var(--color-gray);
|
||||
line-height: 36px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: 0 20px;
|
||||
}
|
||||
// 文章内容
|
||||
article {
|
||||
padding: 0 30px;
|
||||
overflow: hidden;
|
||||
font-size: var(--article-content-font-size);
|
||||
color: var(--article-content-font-color);
|
||||
line-height: 1.8;
|
||||
:deep(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
81
.kit/translated/components/cms/CategoryIcon.vue
Normal file
81
.kit/translated/components/cms/CategoryIcon.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<!-- 网络图标 -->
|
||||
<img
|
||||
v-if="isNetworkIcon"
|
||||
class="category-icon image-icon"
|
||||
:src="value"
|
||||
alt="栏目图标"
|
||||
:style="{ width: sizeWidth }"
|
||||
/>
|
||||
<!-- class图标 -->
|
||||
<i
|
||||
v-else-if="isClassIcon"
|
||||
class="category-icon"
|
||||
:class="value"
|
||||
:style="{ 'font-size': size }"
|
||||
></i>
|
||||
<!-- 不正确的图标 -->
|
||||
<span class="category-icon holder" v-else-if="withHolder"><em>x</em></span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'CategoryIcon',
|
||||
props: {
|
||||
// 图标值
|
||||
value: {},
|
||||
// 尺寸
|
||||
size: {
|
||||
default: 'inherit'
|
||||
},
|
||||
// 如果图标不存在,是否显示占位符
|
||||
withHolder: {
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// size对应的width值
|
||||
sizeWidth () {
|
||||
if (this.size === 'inherit') {
|
||||
return '16px'
|
||||
}
|
||||
return this.size
|
||||
},
|
||||
// 判断是否为class图标
|
||||
isClassIcon () {
|
||||
if (this.value == null || this.value === '') {
|
||||
return false
|
||||
}
|
||||
return !this.value.startsWith('/') &&
|
||||
!this.value.startsWith('http://') && !this.value.startsWith('https://')
|
||||
},
|
||||
// 判断是否为网络图标
|
||||
isNetworkIcon () {
|
||||
if (this.value == null || this.value === '') {
|
||||
return false
|
||||
}
|
||||
return this.value.startsWith('/') ||
|
||||
this.value.startsWith('http://') || this.value.startsWith('https://')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.holder {
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: red !important;
|
||||
background: #e0e0e0;
|
||||
em {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
82
.kit/translated/components/cms/CategoryTree.vue
Normal file
82
.kit/translated/components/cms/CategoryTree.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="category-tree">
|
||||
<el-tree
|
||||
:data="data"
|
||||
node-key="uid"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'title'
|
||||
}"
|
||||
:current-node-key="selected"
|
||||
:highlight-current="true"
|
||||
:default-expand-all="true"
|
||||
:expand-on-click-node="false"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<nuxt-link :to="data.uri">{{ data.title }}</nuxt-link>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CategoryTree',
|
||||
props: {
|
||||
// 栏目树结构
|
||||
data : {},
|
||||
// 选中的节点唯一标识
|
||||
selected: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.category-tree {
|
||||
height: 800px;
|
||||
background-color: var(--background-color);
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
:deep(.el-tree) {
|
||||
--el-tree-node-content-height: auto;
|
||||
background-color: var(--background-color);
|
||||
.el-tree-node__content {
|
||||
border-radius: 8px;
|
||||
a {
|
||||
height: 100%;
|
||||
min-height: 50px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
text-wrap: initial;
|
||||
}
|
||||
.el-tree-node__expand-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// 选中状态
|
||||
.is-current {
|
||||
& > .el-tree-node__content {
|
||||
background-color: var(--primary-color-light);
|
||||
color: var(--color-white);
|
||||
a {
|
||||
color: var(--color-white) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: var(--font-color) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
144
.kit/translated/components/cms/SpecialColumn.vue
Normal file
144
.kit/translated/components/cms/SpecialColumn.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="special-column">
|
||||
<div class="title-wrap">
|
||||
<label>专题专栏</label>
|
||||
<!-- 箭头 -->
|
||||
<span/>
|
||||
</div>
|
||||
<div class="swiper-wrap">
|
||||
<swiper
|
||||
class="swiper-container"
|
||||
ref="swiper"
|
||||
:speed="500"
|
||||
:slidesPerView="4"
|
||||
:loop="true"
|
||||
:autoplay="{
|
||||
delay: 1500,
|
||||
disableOnInteraction: false // 触摸后是否停止自动移动
|
||||
}"
|
||||
:modules="modules"
|
||||
@mouseenter="$refs.swiper.$el.swiper.autoplay.stop()"
|
||||
@mouseleave="$refs.swiper.$el.swiper.autoplay.start()"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in getIcons" :key="index">
|
||||
<nuxt-link target="_blank" :to="JSON.parse(item.value).link">
|
||||
<img
|
||||
:src="getImageURL(JSON.parse(item.value).image)"
|
||||
:alt="item.title"
|
||||
/>
|
||||
</nuxt-link>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import { Autoplay } from 'swiper/modules'
|
||||
import 'swiper/scss'
|
||||
import 'swiper/scss/free-mode'
|
||||
import { getImageURL } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
name: 'SpecialColumn',
|
||||
components: { Swiper, SwiperSlide },
|
||||
props: {
|
||||
icons: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 获取图标
|
||||
getIcons () {
|
||||
if (this.icons.length < 5 || this.icons.length > 7) {
|
||||
return this.icons
|
||||
}
|
||||
return [...this.icons, ...this.icons]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modules: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getImageURL
|
||||
},
|
||||
created () {
|
||||
this.modules = [Autoplay]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.special-column {
|
||||
display: flex;
|
||||
// 标题
|
||||
.title-wrap {
|
||||
height: 100px;
|
||||
width: 40px;
|
||||
margin: auto 20px auto 0;
|
||||
padding: 0 14px;
|
||||
background: linear-gradient(90deg, var(--primary-color-light) 0%, var(--primary-color) 100%);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
// 箭头
|
||||
& > span {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
top: calc(50% - 10px);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom:10px solid transparent;
|
||||
border-top: 10px solid transparent;
|
||||
border-left: 12px solid var(--primary-color);
|
||||
}
|
||||
// 专题文字
|
||||
label {
|
||||
display: block;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
// 轮播列表
|
||||
.swiper-wrap {
|
||||
width: calc(100% - 80px);
|
||||
height: 100px;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
// 轮播项
|
||||
.swiper-slide {
|
||||
// 给定最大宽度,避免swiper没有计算出width时图片临时性展示过大
|
||||
max-width: 25%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
&:first-of-type {
|
||||
padding-left: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
padding-right: 0;
|
||||
}
|
||||
& > a {
|
||||
display: block;
|
||||
height: 100px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
131
.kit/translated/components/common/DataListTabs.vue
Normal file
131
.kit/translated/components/common/DataListTabs.vue
Normal file
@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="data-list-tabs">
|
||||
<!-- 页签 -->
|
||||
<div class="tabs-header">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(tab, index) in data"
|
||||
:key="tab.label"
|
||||
:class="{ hover: activeIndex === index }"
|
||||
@mouseover="trigger === 'hover' ? changeTab(index) : null"
|
||||
@click="trigger === 'click' ? changeTab(index) : null"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</li>
|
||||
</ul>
|
||||
<nuxt-link
|
||||
v-if="withMore && currentTab.moreLink != null"
|
||||
:to="currentTab.moreLink"
|
||||
>
|
||||
更多<el-icon><ElIconDArrowRight /></el-icon>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<!-- 搜索表单 -->
|
||||
<slot name="search"></slot>
|
||||
<!-- 数据列表 -->
|
||||
<slot v-if="items.length > 0" :items="items" :tab="data[activeIndex]">
|
||||
<ArticleList :articles="items"/>
|
||||
</slot>
|
||||
<!-- 暂无数据 -->
|
||||
<EmptyTip v-else/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyTip from "~/components/common/EmptyTip.vue";
|
||||
import ArticleList from "~/components/cms/ArticleList.vue";
|
||||
|
||||
export default {
|
||||
name: 'DataListTabs',
|
||||
components: {ArticleList, EmptyTip},
|
||||
emits: ['changeTab'],
|
||||
props: {
|
||||
// 数据,[{ label: '', items: [ { title: '', updateTime: '' } ] }]
|
||||
data: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否‘更多’按钮
|
||||
withMore: {
|
||||
default: true
|
||||
},
|
||||
// 触发方式
|
||||
trigger: {
|
||||
default: 'hover'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前选中的tab
|
||||
currentTab () {
|
||||
return this.data[this.activeIndex]
|
||||
},
|
||||
// 获取展示列表
|
||||
items () {
|
||||
if (this.currentTab == null) {
|
||||
return
|
||||
}
|
||||
return this.currentTab.items
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 切换tab
|
||||
* @param index 坐标
|
||||
*/
|
||||
changeTab (index) {
|
||||
this.activeIndex = index
|
||||
this.$emit('changeTab', index)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 当前选中的tab索引
|
||||
activeIndex: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.data-list-tabs {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
overflow: hidden;
|
||||
// 页签头
|
||||
.tabs-header {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: var(--primary-color);
|
||||
ul {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding-right: 100px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
li {
|
||||
padding: 8px 15px;
|
||||
cursor: default;
|
||||
font-size: var(--font-size-middle);
|
||||
flex-shrink: 0;
|
||||
&.hover {
|
||||
font-weight: bold;
|
||||
border-bottom: 3px solid var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更多
|
||||
a {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: var(--font-size-small);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--primary-color) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
33
.kit/translated/components/common/EmptyTip.vue
Normal file
33
.kit/translated/components/common/EmptyTip.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<el-empty
|
||||
:image-size="imageSize"
|
||||
:description="description"
|
||||
:class="{ 'el-empty__no-text': !description }"
|
||||
>
|
||||
<slot></slot>
|
||||
</el-empty>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmptyTip',
|
||||
props: {
|
||||
// 同el-empty image-size
|
||||
imageSize: {
|
||||
default: 55
|
||||
},
|
||||
// 同el-empty description
|
||||
description: {
|
||||
default: '暂无数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-empty.el-empty__no-text {
|
||||
:deep(.el-empty__description) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
54
.kit/translated/components/common/PageBreadCrumb.vue
Normal file
54
.kit/translated/components/common/PageBreadCrumb.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="page-breadcrumb">
|
||||
<span>当前所在位置:</span>
|
||||
<ul>
|
||||
<li v-for="(item,index) in data" :key="item.uid">
|
||||
<nuxt-link v-if="item.uri != null && item.uri !== ''" :to="item.uri">
|
||||
{{ item.title }}
|
||||
</nuxt-link>
|
||||
<span v-else>{{ item.title }}</span>
|
||||
<el-icon v-if="index < data.length - 1"><ArrowRight /></el-icon>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ArrowRight } from '@element-plus/icons-vue'
|
||||
export default {
|
||||
name: 'PageBreadCrumb',
|
||||
components: { ArrowRight },
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-breadcrumb {
|
||||
background-color: #fff;
|
||||
height: 50px;
|
||||
line-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
color: var(--color-gray);
|
||||
ul {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--font-color);
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.el-icon {
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
296
.kit/translated/components/common/Pagination.vue
Normal file
296
.kit/translated/components/common/Pagination.vue
Normal file
@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<div v-if="pageCount > 1" class="pagination">
|
||||
<div class="pagination-content">
|
||||
<!-- 总数 -->
|
||||
<span class="pagination-info">共 <em>{{ modelValue.total }}</em> 条</span>
|
||||
<ul>
|
||||
<!-- 上一页 -->
|
||||
<li :class="{ disabled: modelValue.page <= 1 }">
|
||||
<el-icon v-if="modelValue.page <= 1"><ArrowLeft/></el-icon>
|
||||
<nuxt-link v-else :to="getPageUrl(modelValue.page - 1)">
|
||||
<el-icon><ArrowLeft/></el-icon>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
<!-- 前置分页 -->
|
||||
<li
|
||||
v-for="pageIndex in prevPages"
|
||||
:key="pageIndex"
|
||||
:class="{ selected: pageIndex === modelValue.page }"
|
||||
>
|
||||
<nuxt-link :to="getPageUrl(pageIndex)">{{ pageIndex }}</nuxt-link>
|
||||
</li>
|
||||
<!-- 前置翻页器:存在中间页码 || 完全展示了后置页码 -->
|
||||
<li v-if="centerPages.length > 0 || afterPages.length === limitPageCount" class="page-control">
|
||||
<nuxt-link :to="getPageUrl(modelValue.page-limitPageCount < 1 ? 1 : modelValue.page-limitPageCount)">
|
||||
<span>...</span>
|
||||
<el-icon><DArrowLeft /></el-icon>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
<!-- 中间分页 -->
|
||||
<li
|
||||
v-for="pageIndex in centerPages"
|
||||
:key="pageIndex"
|
||||
:class="{ selected: pageIndex === modelValue.page }"
|
||||
>
|
||||
<nuxt-link :to="getPageUrl(pageIndex)">{{ pageIndex }}</nuxt-link>
|
||||
</li>
|
||||
<!-- 后置翻页器:存在中间页码 || 完全展示了前面的页码但总页数要大于前方展示的页码数 -->
|
||||
<li v-if="centerPages.length > 0 || (prevPages.length === limitPageCount && pageCount > limitPageCount)" class="page-control">
|
||||
<nuxt-link :to="getPageUrl(modelValue.page+limitPageCount > pageCount ? pageCount : modelValue.page+limitPageCount)">
|
||||
<span>...</span>
|
||||
<el-icon><DArrowRight /></el-icon>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
<!-- 后置分页 -->
|
||||
<li
|
||||
v-for="pageIndex in afterPages"
|
||||
:key="pageIndex"
|
||||
:class="{ selected: pageIndex === modelValue.page }"
|
||||
>
|
||||
<nuxt-link :to="getPageUrl(pageIndex)">{{ pageIndex }}</nuxt-link>
|
||||
</li>
|
||||
<!-- 下一页 -->
|
||||
<li :class="{ disabled: modelValue.page >= pageCount }">
|
||||
<el-icon v-if="modelValue.page >= pageCount"><ArrowRight /></el-icon>
|
||||
<nuxt-link v-else :to="getPageUrl(modelValue.page + 1)">
|
||||
<el-icon><ArrowRight/></el-icon>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 跳转 -->
|
||||
<div class="pagination-info pagination-jump">
|
||||
前往
|
||||
<el-input-number
|
||||
v-model="targetPage"
|
||||
:controls="false"
|
||||
:max="pageCount"
|
||||
@keydown.enter="jump"
|
||||
/>
|
||||
页
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ArrowLeft, DArrowLeft, ArrowRight, DArrowRight } from '@element-plus/icons-vue'
|
||||
|
||||
export default {
|
||||
name: 'Pagination',
|
||||
components: { ArrowLeft, DArrowLeft, ArrowRight, DArrowRight },
|
||||
emits: ['update:modelValue', 'page-change'],
|
||||
props: {
|
||||
// 分页值,e.g: { page: 1, capacity: 10, total: 100 }
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 获取页码链接函数
|
||||
getPageUrl: {
|
||||
type: Function,
|
||||
default: function (page) {
|
||||
return `?page=${page}`
|
||||
}
|
||||
},
|
||||
// 最多一次性展示多少个页码
|
||||
limitPageCount: {
|
||||
type: Number,
|
||||
default: 5
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
targetPage: 1,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 最大同时展示的页码数量,其中4 = 首页 + 页面控制按钮 + 尾页 + 页面控制按钮
|
||||
maxPageCount () {
|
||||
return this.limitPageCount + 4
|
||||
},
|
||||
// 总页数
|
||||
pageCount () {
|
||||
return Math.ceil(this.modelValue.total / this.modelValue.capacity)
|
||||
},
|
||||
// 中间数
|
||||
limitPageCountHalf () {
|
||||
return Math.floor(this.limitPageCount / 2)
|
||||
},
|
||||
// 前置分页
|
||||
prevPages () {
|
||||
// 总页不超过maxPageCount,全部展示
|
||||
if (this.pageCount <= this.maxPageCount) {
|
||||
return new Array(this.pageCount)
|
||||
.fill(0)
|
||||
.map((item, index) => index + 1)
|
||||
}
|
||||
// 当前页码在头部(即当前页码 <= limitPageCount)
|
||||
if (this.modelValue.page < this.limitPageCount) {
|
||||
return new Array(this.limitPageCount)
|
||||
.fill(0)
|
||||
.map((item, index) => index + 1)
|
||||
}
|
||||
return [1]
|
||||
},
|
||||
// 中间分页,展示5条
|
||||
centerPages () {
|
||||
if (this.pageCount <= this.maxPageCount) {
|
||||
return []
|
||||
}
|
||||
// 当前页码不在头和尾部(即当前页码 > limitPageCount && 当前页码 < pageCount - limitPageCount)
|
||||
if (this.modelValue.page >= this.limitPageCount && this.modelValue.page <= this.pageCount - this.limitPageCount + 1) {
|
||||
const pages = []
|
||||
for (let i = 0; i < this.limitPageCount; i++) {
|
||||
// 中间页面
|
||||
if (i === this.limitPageCountHalf) {
|
||||
pages.push(this.modelValue.page)
|
||||
continue
|
||||
}
|
||||
// 左右两侧页码
|
||||
pages.push(this.modelValue.page - this.limitPageCountHalf + i)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
return []
|
||||
},
|
||||
// 后置分页
|
||||
afterPages () {
|
||||
if (this.pageCount <= this.maxPageCount) {
|
||||
return []
|
||||
}
|
||||
// 当前页码在尾部(当前页码 >= pageCount - limitPageCount + 1)
|
||||
if (this.modelValue.page > this.pageCount - this.limitPageCount + 1) {
|
||||
return new Array(this.limitPageCount)
|
||||
.fill(0)
|
||||
.map((item, index) => {
|
||||
return this.pageCount - this.limitPageCount + index + 1
|
||||
})
|
||||
}
|
||||
return [this.pageCount]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听分页数据发生变化,刷新目标页码
|
||||
'modelValue.page': {
|
||||
immediate: true,
|
||||
handler (newValue) {
|
||||
if (this.targetPage !== newValue) {
|
||||
this.targetPage = newValue
|
||||
this.$router.replace(this.getPageUrl(newValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 跳转指定页
|
||||
jump () {
|
||||
if (this.targetPage < 1) {
|
||||
this.targetPage = 1
|
||||
}
|
||||
this.$router.push(this.getPageUrl(this.targetPage))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pagination {
|
||||
--page-item-size: 35px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
.pagination-content {
|
||||
width: 800px;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
// 页码列表
|
||||
ul {
|
||||
display: flex;
|
||||
margin: 0 30px;
|
||||
li {
|
||||
width: var(--page-item-size);
|
||||
height: var(--page-item-size);
|
||||
background: var(--background-color);
|
||||
margin-right: 3px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: var(--page-item-size);
|
||||
text-align: center;
|
||||
color: #333;
|
||||
&:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.el-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
// 选中状态
|
||||
&.selected {
|
||||
a {
|
||||
color: var(--color-white);
|
||||
background: var(--primary-color);
|
||||
&:hover {
|
||||
color: var(--color-white);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 禁用状态
|
||||
&.disabled {
|
||||
color: var(--color-gray);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
// 页面控制
|
||||
&.page-control {
|
||||
a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.el-icon {
|
||||
display: none;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
&:hover {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
.el-icon {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 附加信息
|
||||
.pagination-info {
|
||||
color: var(--color-gray);
|
||||
em {
|
||||
color: var(--font-color);
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
// 跳转
|
||||
.pagination-jump {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-input-number {
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
99
.kit/translated/components/common/PopUpSelect.vue
Normal file
99
.kit/translated/components/common/PopUpSelect.vue
Normal file
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="pop-up-select" @mouseover="active = true" @mouseout="active = false">
|
||||
<span>{{ title }} <el-icon><ElIconArrowUpBold/></el-icon></span>
|
||||
<ul
|
||||
:class="{ active: active, leave: !active }"
|
||||
@mouseover="active = true"
|
||||
@mouseout="active = false"
|
||||
>
|
||||
<li v-for="option in data" :key="option.title">
|
||||
<nuxt-link target="_blank" :to="option.value">{{ option.title }}</nuxt-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PopUpSelect',
|
||||
props: {
|
||||
title: String,
|
||||
data: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pop-up-select {
|
||||
position: relative;
|
||||
height: 40px;
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #e4e7ed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&>span {
|
||||
width: 100%;
|
||||
padding: 5px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.el-icon {
|
||||
color: #aaa;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: -1px;
|
||||
background-color: #FFFFFF;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-bottom: 0;
|
||||
z-index: 9;
|
||||
height: 0;
|
||||
&.active {
|
||||
height: auto;
|
||||
animation: pop-up linear 0.5s 1;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&.leave {
|
||||
display: none;
|
||||
}
|
||||
li {
|
||||
&:hover {
|
||||
background-color: rgb(216.8, 235.6, 255);
|
||||
}
|
||||
a {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 10px 10px 10px 25px;
|
||||
color: var(--font-color);
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes pop-up {
|
||||
0% {
|
||||
max-height: 0;
|
||||
}
|
||||
100% {
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
91
.kit/translated/components/common/SegmentedFilter.vue
Normal file
91
.kit/translated/components/common/SegmentedFilter.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="segment-selector">
|
||||
<label>{{ data.title }}</label>
|
||||
<ul>
|
||||
<li
|
||||
v-for="item in items"
|
||||
:class="{'is-active': modelValue === item.value}"
|
||||
:key="item.id"
|
||||
@click="handleSelect(item.value)"
|
||||
>{{ item.label }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SegmentedFilter',
|
||||
emits: ['update:modelValue', 'change'],
|
||||
props: {
|
||||
data: {
|
||||
default: () => {
|
||||
return {
|
||||
children: []
|
||||
}
|
||||
}
|
||||
},
|
||||
modelValue: {}
|
||||
},
|
||||
computed: {
|
||||
items () {
|
||||
return [
|
||||
{
|
||||
id: 0,
|
||||
label: '不限',
|
||||
value: ''
|
||||
},
|
||||
...this.data.items
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 处理选中
|
||||
*
|
||||
* @param value 触发对象
|
||||
*/
|
||||
handleSelect (value) {
|
||||
if (value === this.modelValue) {
|
||||
return
|
||||
}
|
||||
this.$emit('update:modelValue', value)
|
||||
this.$emit('change', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.segment-selector {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
|
||||
label {
|
||||
width: 75px;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
line-height: 30px;
|
||||
color: var(--color-gray);
|
||||
text-align: right;
|
||||
}
|
||||
ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
line-height: 30px;
|
||||
gap: 5px;
|
||||
li {
|
||||
height: 30px;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
background-color: var(--background-color);
|
||||
&:hover {
|
||||
color: var(--primary-color-dark);
|
||||
}
|
||||
&.is-active {
|
||||
background-color: var(--primary-color-light-deep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
90
.kit/translated/components/home/Carousel.vue
Normal file
90
.kit/translated/components/home/Carousel.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="carousel">
|
||||
<el-carousel
|
||||
ref="carousel"
|
||||
motion-blur
|
||||
:pause-on-hover="true"
|
||||
>
|
||||
<el-carousel-item v-for="item in data" :key="item.id">
|
||||
<nuxt-link target="_blank" :to="JSON.parse(item.value).link">
|
||||
<img :src="getImageURL(JSON.parse(item.value).image)" :alt="item.title"/>
|
||||
<p>{{ item.title }}</p>
|
||||
</nuxt-link>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getImageURL } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
name: 'Carousel',
|
||||
props: {
|
||||
// 轮播数据
|
||||
data: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getImageURL
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.carousel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
:deep(.el-carousel) {
|
||||
// 原点占位宽度
|
||||
--indicators-width: 200px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.el-carousel__container {
|
||||
height: 100% !important;
|
||||
}
|
||||
// 轮播项
|
||||
.el-carousel__item {
|
||||
background-color: #efdfdf;
|
||||
a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
p {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
bottom: 0;
|
||||
padding: 8px var(--indicators-width) 8px 20px;
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
color: var(--color-white);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
// 轮播圆点
|
||||
.el-carousel__indicators {
|
||||
width: var(--indicators-width);
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 5px;
|
||||
left: initial;
|
||||
transform: none;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
103
.kit/translated/components/home/WebsiteNav.vue
Normal file
103
.kit/translated/components/home/WebsiteNav.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div class="website-nav-wrap">
|
||||
<div class="title-wrap">
|
||||
<img src="/images/link.png" alt="">
|
||||
<h3>网站导航</h3>
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
v-for="(title, index) in navList"
|
||||
v-show="data[index] != null && data[index].length > 0"
|
||||
:key="title"
|
||||
>
|
||||
<PopUpSelect :title="title" :data="data[index]"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PopUpSelect from '@/components/common/PopUpSelect.vue'
|
||||
|
||||
export default {
|
||||
name: 'WebsiteNav',
|
||||
components: { PopUpSelect },
|
||||
props: {
|
||||
data: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
navList: ['国家级链接', '省级链接', '市级链接', '其他链接']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.website-nav-wrap {
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
// 标题
|
||||
.title-wrap {
|
||||
color: var(--primary-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-right: 30px;
|
||||
h3 {
|
||||
margin: 0;
|
||||
padding-left: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
img {
|
||||
width: 20px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
}
|
||||
// 网站
|
||||
ul {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
gap: 20px;
|
||||
&>li {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
&:first-of-type {
|
||||
justify-content: flex-start;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.el-tooltip__trigger:focus {
|
||||
outline: none;
|
||||
}
|
||||
.el-dropdown {
|
||||
width: 100%;
|
||||
.dropdown-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #1b1b1b;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.el-icon--right {
|
||||
padding-left: 100px;
|
||||
color: #aaa;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dropdown-menu__item) {
|
||||
min-width: 220px;
|
||||
a {
|
||||
color: #1b1b1b;
|
||||
}
|
||||
}
|
||||
</style>
|
137
.kit/translated/components/layout/Categories.vue
Normal file
137
.kit/translated/components/layout/Categories.vue
Normal file
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div class="categories">
|
||||
<div class="content-wrap">
|
||||
<el-menu
|
||||
:popper-offset="0"
|
||||
popper-class="categories-popper"
|
||||
mode="horizontal"
|
||||
:show-timeout="0"
|
||||
:hide-timeout="0"
|
||||
>
|
||||
<CategoryChildren
|
||||
v-for="category in categories"
|
||||
:key="category.uid"
|
||||
:index="category.uid"
|
||||
:category="category"
|
||||
/>
|
||||
</el-menu>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CategoryChildren from '@/components/layout/CategoryChildren'
|
||||
|
||||
export default {
|
||||
name: 'Categories',
|
||||
components: { CategoryChildren },
|
||||
props: {
|
||||
// 栏目树
|
||||
categories: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.categories {
|
||||
background-color: var(--primary-color-dark);
|
||||
:deep(.el-menu) {
|
||||
// 选中的栏目,Nuxt会自动选中并增加该class
|
||||
.router-link-active {
|
||||
background-color: var(--color-white);
|
||||
color: var(--primary-color-dark) !important;
|
||||
border-radius: 8px;
|
||||
line-height: 38px;
|
||||
font-weight: bold;
|
||||
transition: all .3s;
|
||||
&:hover {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
// 栏目标题
|
||||
a,label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
color: var(--color-white);
|
||||
cursor: pointer;
|
||||
padding: 0 35px;
|
||||
.category-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.image-icon {
|
||||
width: 20px !important;
|
||||
}
|
||||
}
|
||||
// 隐藏下拉箭头
|
||||
.el-sub-menu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
// 根栏目
|
||||
.el-menu-item,.el-sub-menu {
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
border-bottom: 0 !important;
|
||||
&.is-active {
|
||||
color: var(--primary-color-dark) !important;
|
||||
}
|
||||
}
|
||||
// 存在子栏目的栏目标题
|
||||
.el-sub-menu__title {
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.categories-popper {
|
||||
border: 0 !important;
|
||||
.el-menu {
|
||||
background-color: #fff !important;
|
||||
// 子栏目标题
|
||||
a,label {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: left;
|
||||
color: var(--font-color);
|
||||
&:hover {
|
||||
color: var(--color-white);
|
||||
}
|
||||
}
|
||||
.el-menu-item {
|
||||
min-width: 200px;
|
||||
background-color: #fff;
|
||||
font-size: var(--font-size-middle);
|
||||
text-align: center;
|
||||
transition: none;
|
||||
&:hover {
|
||||
background-color: var(--primary-color-light);
|
||||
color: var(--color-white);
|
||||
}
|
||||
}
|
||||
// 带子栏目的标题
|
||||
.el-sub-menu__title {
|
||||
background-color: var(--color-white);
|
||||
font-size: var(--font-size-middle);
|
||||
// 箭头
|
||||
.el-sub-menu__icon-arrow {
|
||||
color: var(--font-color);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--primary-color-light);
|
||||
a {
|
||||
color: var(--color-white) !important;
|
||||
}
|
||||
.el-sub-menu__icon-arrow {
|
||||
color: var(--color-white) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
65
.kit/translated/components/layout/CategoryChildren.vue
Normal file
65
.kit/translated/components/layout/CategoryChildren.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-menu-item
|
||||
v-if="category.children == null || category.children.length == 0"
|
||||
:key="index"
|
||||
:index="index + '#' + category.path"
|
||||
>
|
||||
<template v-if="category.uri != null && category.uri !== ''">
|
||||
<!-- 外部链接,新窗口打开 -->
|
||||
<nuxt-link v-if="category.type === 'OUT_LINK'" :to="category.uri" target="_blank">
|
||||
<CategoryIcon :value="category.icon" :with-holder="false"/>
|
||||
{{category.title}}
|
||||
</nuxt-link>
|
||||
<!-- 内部链接 || 常规栏目配置了模板,当前页打开 -->
|
||||
<nuxt-link v-else :to="category.uri">
|
||||
<CategoryIcon :value="category.icon" :with-holder="false"/>
|
||||
{{category.title}}
|
||||
</nuxt-link>
|
||||
</template>
|
||||
<!-- 常规栏目 -->
|
||||
<label v-else>{{ category.title }}</label>
|
||||
</el-menu-item>
|
||||
<el-sub-menu v-else :index="index">
|
||||
<template #title>
|
||||
<template v-if="category.uri != null && category.uri !== ''">
|
||||
<!-- 外部链接,新窗口打开 -->
|
||||
<nuxt-link v-if="category.type === 'OUT_LINK'" :to="category.uri" target="_blank">
|
||||
<CategoryIcon :value="category.icon" :with-holder="false"/>
|
||||
{{category.title}}
|
||||
</nuxt-link>
|
||||
<!-- 内部链接 || 常规栏目配置了模板,当前页打开 -->
|
||||
<nuxt-link v-else :to="category.uri">
|
||||
<CategoryIcon :value="category.icon" :with-holder="false"/>
|
||||
{{category.title}}
|
||||
</nuxt-link>
|
||||
</template>
|
||||
<!-- 常规栏目未配置模板(目录) -->
|
||||
<label v-else>
|
||||
<CategoryIcon :value="category.icon" :with-holder="false"/>
|
||||
{{ category.title }}
|
||||
</label>
|
||||
</template>
|
||||
<CategoryChildren
|
||||
v-for="(child, idx) in category.children"
|
||||
:category="child"
|
||||
:key="index + '-' + idx"
|
||||
:index="String(index + '-' + idx)"
|
||||
/>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CategoryIcon from '@/components/cms/CategoryIcon'
|
||||
export default {
|
||||
name: 'CategoryChildren',
|
||||
components: { CategoryIcon },
|
||||
props: {
|
||||
// 栏目
|
||||
category: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
index: String,
|
||||
}
|
||||
}
|
||||
</script>
|
85
.kit/translated/components/layout/SearchInput.vue
Normal file
85
.kit/translated/components/layout/SearchInput.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
size="large"
|
||||
placeholder="请输入搜索关键字"
|
||||
clearable
|
||||
@keydown.enter="search"
|
||||
>
|
||||
<template #append>
|
||||
<el-button :icon="ElIconSearch" @click="search">搜索</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'SearchInput',
|
||||
setup () {
|
||||
const route = useRoute()
|
||||
const keyword = route.query.kwd || ''
|
||||
return {
|
||||
keyword: ref(keyword)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 路由参数变化时,触发数据搜索
|
||||
'$route.query': function (newQuery) {
|
||||
this.keyword = newQuery.kwd == null ? '' : newQuery.kwd.trim()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 执行搜索
|
||||
search () {
|
||||
this.keyword = this.keyword.trim()
|
||||
if (this.keyword === '') {
|
||||
return
|
||||
}
|
||||
// 如果当前在搜索页,直接替换路径
|
||||
if (this.$route.path === '/search') {
|
||||
this.$router.push({ path: '/search', query: { kwd: this.keyword } })
|
||||
return
|
||||
}
|
||||
// 打开搜索页
|
||||
window.open(`/search?kwd=${this.keyword}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-input {
|
||||
width: 300px;
|
||||
border-radius: 40px;
|
||||
overflow: hidden;
|
||||
:deep(.el-input__wrapper) {
|
||||
box-shadow: none;
|
||||
.el-input__inner {
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
}
|
||||
// 搜索按钮
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0 10px;
|
||||
width: 65px;
|
||||
background-color: var(--primary-color-dark-deep);
|
||||
box-shadow: none;
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--color-white);
|
||||
overflow: hidden;
|
||||
.el-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.el-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
58
.kit/translated/components/layout/WebFooter.vue
Normal file
58
.kit/translated/components/layout/WebFooter.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div class="web-footer">
|
||||
<ul class="content-wrap">
|
||||
<li>
|
||||
主办单位:{{ organization }}
|
||||
</li>
|
||||
<li>
|
||||
网站标识码:
|
||||
<img class="icon-icp" src="/images/icp.png" alt="icp"/>
|
||||
<nuxt-link to="https://beian.miit.gov.cn" target="_blank">{{ icp }}</nuxt-link>
|
||||
</li>
|
||||
<li>地址:{{ address }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'WebFooter',
|
||||
setup () {
|
||||
return {
|
||||
organization: import.meta.env.VITE_SITE_ORGANIZATION,
|
||||
icp: import.meta.env.VITE_SITE_ICP,
|
||||
address: import.meta.env.VITE_SITE_ADDRESS,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.web-footer {
|
||||
height: 100%;
|
||||
background-color: var(--primary-color-dark);
|
||||
padding: 50px 0;
|
||||
color: var(--color-white);
|
||||
.content-wrap {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
color: var(--color-white);
|
||||
background-color: transparent;
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--color-white);
|
||||
a {
|
||||
color: var(--color-white);
|
||||
}
|
||||
.icon-icp {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
64
.kit/translated/components/layout/WebHeader.vue
Normal file
64
.kit/translated/components/layout/WebHeader.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="web-header">
|
||||
<div class="content-wrap">
|
||||
<div class="title-wrap">
|
||||
<h1>{{ title }}</h1>
|
||||
<h2>{{ subTitle }}</h2>
|
||||
</div>
|
||||
<div class="search-wrap">
|
||||
<SearchInput/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchInput from './SearchInput'
|
||||
|
||||
export default {
|
||||
name: 'WebHeader',
|
||||
components: { SearchInput },
|
||||
async setup () {
|
||||
return {
|
||||
title: import.meta.env.VITE_SITE_TITLE,
|
||||
subTitle: import.meta.env.VITE_SITE_SUB_TITLE
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.web-header {
|
||||
padding: 50px 0;
|
||||
background: linear-gradient(to bottom, var(--primary-color), var(--primary-color-light));
|
||||
color: var(--color-white);
|
||||
.content-wrap {
|
||||
width: var(--page-width);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
background-color: transparent;
|
||||
// 标题
|
||||
.title-wrap {
|
||||
flex-grow: 1;
|
||||
h1,h2 {
|
||||
margin: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 42px;
|
||||
}
|
||||
h2 {
|
||||
color: var(--primary-color-light-deep);
|
||||
font-size: 16px;
|
||||
}
|
||||
a {
|
||||
color: var(--primary-color-light-deep);
|
||||
}
|
||||
}
|
||||
// 搜索
|
||||
.search-wrap {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
74
.kit/translated/error.vue
Normal file
74
.kit/translated/error.vue
Normal file
@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div class="error-page">
|
||||
<div class="content-wrap">
|
||||
<h1 v-if="error.statusCode === 404">找不到您要访问的资源!</h1>
|
||||
<h1 v-else>{{ error.message }}</h1>
|
||||
<p>{{ error.url }} - {{ error.statusCode }}</p>
|
||||
<pre v-if="error.statusCode !== 404">错误详情:<br/>{{ errorDetail }}</pre>
|
||||
<div class="opera">
|
||||
<nuxt-link to="/" class="button">返回首页</nuxt-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
error: {}
|
||||
},
|
||||
computed: {
|
||||
errorDetail () {
|
||||
return JSON.stringify(this.error, null, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.error-page {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: var(--background-color);
|
||||
padding-top: 200px;
|
||||
box-sizing: border-box;
|
||||
.content-wrap {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 50px 100px;
|
||||
background-color: var(--color-white);
|
||||
text-align: center;
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
p {
|
||||
color: var(--color-gray);
|
||||
}
|
||||
pre {
|
||||
font-size: var(--font-size-small);
|
||||
text-align: left;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
color: var(--color-gray);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.opera {
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding-top: 20px;
|
||||
}
|
||||
.button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background-color: var(--primary-color);
|
||||
color: var(--color-white);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
108
.kit/translated/layouts/category.vue
Normal file
108
.kit/translated/layouts/category.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="category-detail-layout">
|
||||
<Head>
|
||||
<Title>{{ selectedCategory.title }}</Title>
|
||||
<Meta type="keywords" :content="siteConfig.keywords"/>
|
||||
<Meta type="description" :content="siteConfig.description"/>
|
||||
</Head>
|
||||
<header>
|
||||
<WebHeader/>
|
||||
<Categories :categories="categories"/>
|
||||
</header>
|
||||
<main>
|
||||
<!-- 修改el语言为中文 -->
|
||||
<el-config-provider :locale="zhCn">
|
||||
<div class="content-wrap category-detail-wrap">
|
||||
<!-- 页面面包屑 -->
|
||||
<PageBreadCrumb :data="breadcrumbs"/>
|
||||
<div class="detail-wrap__body">
|
||||
<!-- 栏目树 -->
|
||||
<div class="detail-wrap__categories">
|
||||
<CategoryTree :data="subCategories" :selected="selectedCategory.uid"/>
|
||||
</div>
|
||||
<!-- 主要内容 -->
|
||||
<div class="detail-wrap__content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-config-provider>
|
||||
</main>
|
||||
<footer>
|
||||
<WebFooter/>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WebHeader from '@/components/layout/WebHeader'
|
||||
import WebFooter from '@/components/layout/WebFooter'
|
||||
import Categories from '@/components/layout/Categories'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
import CategoryTree from '@/components/cms/CategoryTree';
|
||||
import PageBreadCrumb from '@/components/common/PageBreadCrumb'
|
||||
|
||||
export default {
|
||||
components: { Categories, WebFooter, WebHeader, CategoryTree, PageBreadCrumb},
|
||||
props: {
|
||||
// 栏目树
|
||||
categories: {
|
||||
required: true
|
||||
},
|
||||
// 子栏目树
|
||||
subCategories: {
|
||||
required: true
|
||||
},
|
||||
// 选中的子栏目
|
||||
selectedCategory: {
|
||||
required: true
|
||||
},
|
||||
// 面包屑
|
||||
breadcrumbs: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zhCn,
|
||||
siteConfig: {
|
||||
title: import.meta.env.VITE_SITE_TITLE,
|
||||
keywords: import.meta.env.VITE_SEO_KEYWORDS,
|
||||
description: import.meta.env.VITE_SEO_DESCRIPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
// 栏目详情
|
||||
.category-detail-wrap {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
.detail-wrap__body {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
// 栏目树
|
||||
.detail-wrap__categories {
|
||||
height: auto;
|
||||
width: 275px;
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
}
|
||||
// 内容
|
||||
.detail-wrap__content {
|
||||
flex-grow: 1;
|
||||
padding: 10px 30px;
|
||||
overflow: hidden;
|
||||
& > h2 {
|
||||
font-size: var(--font-size-large);
|
||||
margin: 0;
|
||||
color: var(--primary-color);
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
49
.kit/translated/layouts/default.vue
Normal file
49
.kit/translated/layouts/default.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="default-layout">
|
||||
<Head>
|
||||
<Title>{{ siteConfig.title }}</Title>
|
||||
<Meta type="keywords" :content="siteConfig.keywords"/>
|
||||
<Meta type="description" :content="siteConfig.description"/>
|
||||
</Head>
|
||||
<header>
|
||||
<WebHeader/>
|
||||
<Categories :categories="categories"/>
|
||||
</header>
|
||||
<main>
|
||||
<!-- 修改el语言为中文 -->
|
||||
<el-config-provider :locale="zhCn">
|
||||
<slot></slot>
|
||||
</el-config-provider>
|
||||
</main>
|
||||
<footer>
|
||||
<WebFooter/>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WebHeader from '@/components/layout/WebHeader'
|
||||
import WebFooter from '@/components/layout/WebFooter'
|
||||
import Categories from '@/components/layout/Categories'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
|
||||
export default {
|
||||
components: { Categories, WebFooter, WebHeader},
|
||||
props: {
|
||||
// 栏目树
|
||||
categories: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
zhCn,
|
||||
siteConfig: {
|
||||
title: import.meta.env.VITE_SITE_TITLE,
|
||||
keywords: import.meta.env.VITE_SEO_KEYWORDS,
|
||||
description: import.meta.env.VITE_SEO_DESCRIPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
71
.kit/translated/nuxt.config.ts
Normal file
71
.kit/translated/nuxt.config.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
import sitemap from './utils/sitemap'
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2024-07-10',
|
||||
devtools: { enabled: true },
|
||||
sitemap,
|
||||
app: {
|
||||
// head配置
|
||||
head: {
|
||||
title: import.meta.env.VITE_SITE_TITLE,
|
||||
charset: 'utf-8',
|
||||
viewport: 'width=device-width, initial-scale=1',
|
||||
htmlAttrs: {
|
||||
lang: 'zh',
|
||||
},
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1, user-scalable=no' },
|
||||
{ name: 'screen-orientation', content: 'portrait' },
|
||||
],
|
||||
script: [
|
||||
],
|
||||
}
|
||||
},
|
||||
css: [
|
||||
// 全局样式
|
||||
'@/assets/style/app.scss',
|
||||
'@/assets/style/theme.scss',
|
||||
'@/public/icons/cms/iconfont.css'
|
||||
],
|
||||
vite: {
|
||||
css: {
|
||||
// 修复启动时出现The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: 'modern-compiler'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 接口代理配置
|
||||
server: {
|
||||
proxy: {
|
||||
// 接口代理
|
||||
[import.meta.env.VITE_API_PREFIX]: {
|
||||
target: import.meta.env.VITE_API_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path:any) => path.replace(new RegExp(`^${import.meta.env.VITE_API_PREFIX}`), '')
|
||||
},
|
||||
// 资源代理
|
||||
[import.meta.env.VITE_RESOURCE_PREFIX]: {
|
||||
target: `${import.meta.env.VITE_API_URL}${import.meta.env.VITE_RESOURCE_PREFIX}`,
|
||||
changeOrigin: true,
|
||||
rewrite: (path:any) => path.replace(new RegExp(`^${import.meta.env.VITE_RESOURCE_PREFIX}`), '')
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
// 扩展内容
|
||||
modules: [
|
||||
'dayjs-nuxt',
|
||||
'@element-plus/nuxt',
|
||||
// 导入element-plus图标
|
||||
'@pinia/nuxt',
|
||||
'nuxt-swiper',
|
||||
'@nuxtjs/sitemap'
|
||||
],
|
||||
plugins: [
|
||||
'~/plugins/nprogress.js',
|
||||
'~/plugins/messagebox.js',
|
||||
'~/plugins/nprogress.js',
|
||||
]
|
||||
})
|
10511
.kit/translated/package-lock.json
generated
Normal file
10511
.kit/translated/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
47
.kit/translated/package.json
Normal file
47
.kit/translated/package.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "eva-cms-website-gov",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "nuxt dev --dotenv .env.development",
|
||||
"staging": "nuxt dev --dotenv .env.staging",
|
||||
"build": "nuxt build --dotenv .env.production",
|
||||
"build:staging": "nuxt build --dotenv .env.staging",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"lint": "eslint src",
|
||||
"fix": "eslint layouts --fix"
|
||||
},
|
||||
"overrides": {
|
||||
"vue": "latest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@nuxtjs/sitemap": "^6.1.2",
|
||||
"@pinia/nuxt": "^0.5.3",
|
||||
"axios": "^1.7.4",
|
||||
"element-plus": "^2.8.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"nuxt": "^3.12.4",
|
||||
"nuxt-swiper": "^1.2.2",
|
||||
"pinia": "^2.2.1",
|
||||
"vue": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@element-plus/nuxt": "^1.0.9",
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"dayjs-nuxt": "^2.1.9",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-nuxt": "^4.0.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.77.8"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.15.0",
|
||||
"npm": "8.19.4",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
98
.kit/translated/pages/article/[articleUid].vue
Normal file
98
.kit/translated/pages/article/[articleUid].vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<NuxtLayout name="default" :categories="categoryTree">
|
||||
<Head>
|
||||
<Title>{{ articleData.title }}</Title>
|
||||
<Meta name="keywords" :content="articleData.keywords" />
|
||||
<Meta name="description" :content="articleData.contentDigest" />
|
||||
</Head>
|
||||
<div class="content-wrap">
|
||||
<div class="content">
|
||||
<ArticlePreview :data="articleData"/>
|
||||
<!-- 附件 -->
|
||||
<div v-if="attachments.length > 0" class="attachment-wrap">
|
||||
<h4>本文附件</h4>
|
||||
<ul>
|
||||
<li v-for="attach of attachments" :key="attach.uid">
|
||||
<a :href="$getAttachURL(attach.fileKey, attach.name)" target="_blank">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span>{{ attach.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { definePageMeta } from '#imports'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { Document } from '@element-plus/icons-vue'
|
||||
import ArticlePreview from '@/components/cms/ArticlePreview'
|
||||
import { fetchTemplateData } from '@/api/cms/template'
|
||||
import { strictPackage } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: { ArticlePreview, Document },
|
||||
async setup () {
|
||||
// 去掉默认布局
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
})
|
||||
const route = useRoute()
|
||||
const data = strictPackage(await fetchTemplateData({
|
||||
path: '/article/[articleUid].vue',
|
||||
parameters: {
|
||||
articleUid: route.params.articleUid,
|
||||
mode: route.query.mode
|
||||
}
|
||||
}))
|
||||
return {
|
||||
// 栏目树
|
||||
categoryTree: data.CATEGORIES_TREE,
|
||||
// 文章数据
|
||||
articleData: data.ARTICLE_DETAIL,
|
||||
// 附件列表
|
||||
attachments: data.ARTICLE_DETAIL.attachments == null ?
|
||||
[] : JSON.parse(data.ARTICLE_DETAIL.attachments)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-wrap {
|
||||
background: var(--color-white);
|
||||
padding: 30px;
|
||||
.content {
|
||||
border: 1px solid var(--border-color);
|
||||
// 附件
|
||||
.attachment-wrap {
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: 20px 30px;
|
||||
h4 {
|
||||
color: var(--primary-color-dark);
|
||||
margin: 0;
|
||||
}
|
||||
ul {
|
||||
margin-top: 10px;
|
||||
li {
|
||||
padding: 3px 0;
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--primary-color);
|
||||
&:hover {
|
||||
color: var(--primary-color-light);
|
||||
}
|
||||
.el-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
129
.kit/translated/pages/category/[categoryUid]/articles.vue
Normal file
129
.kit/translated/pages/category/[categoryUid]/articles.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<NuxtLayout name="default" :categories="categoryTree">
|
||||
<Head>
|
||||
<Title>{{ category.title }}</Title>
|
||||
</Head>
|
||||
<div class="content-wrap">
|
||||
<!-- 页面面包屑 -->
|
||||
<PageBreadCrumb :data="breadcrumbs"/>
|
||||
<div class="wrap-body">
|
||||
<!-- 主要内容 -->
|
||||
<div class="content">
|
||||
<h2 class="page-title">{{ category.title }}</h2>
|
||||
<ArticleList :articles="articles" />
|
||||
<Pagination v-model="pagination" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { definePageMeta } from '#imports'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import PageBreadCrumb from '@/components/common/PageBreadCrumb'
|
||||
import Pagination from '@/components/common/Pagination'
|
||||
import CategoryUtil from '@/utils/category'
|
||||
import ArticleList from '@/components/cms/ArticleList'
|
||||
import { strictPackage } from '@/utils/util'
|
||||
import { fetchTemplateData } from '@/api/cms/template'
|
||||
import { fetchArticlePage } from '@/api/cms/article'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArticleList,
|
||||
Pagination,
|
||||
PageBreadCrumb
|
||||
},
|
||||
async setup () {
|
||||
// 去掉默认布局
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
})
|
||||
const route = useRoute()
|
||||
const data = strictPackage(await fetchTemplateData({
|
||||
path: '/category/[categoryUid]/articles.vue',
|
||||
targetUid: route.params.categoryUid,
|
||||
targetType: 'CATEGORY',
|
||||
parameters: {
|
||||
categoryUid: route.params.categoryUid
|
||||
}
|
||||
}))
|
||||
// 获取分页所使用的栏目UID
|
||||
const categoryUid = data.ARTICLE_PAGE_PARAMETERS.categoryUid
|
||||
const categoryUtil = new CategoryUtil(data.CATEGORIES_TREE)
|
||||
const category = categoryUtil.getCategory(categoryUid)
|
||||
if (category == null) {
|
||||
throw new Error(`栏目不存在,栏目UID:${categoryUid}`)
|
||||
}
|
||||
return {
|
||||
category,
|
||||
categoryTree: data.CATEGORIES_TREE,
|
||||
// 查询文章分页数据的栏目ID
|
||||
categoryUid,
|
||||
// 面包屑
|
||||
breadcrumbs: categoryUtil.getBreadcrumb(categoryUid),
|
||||
// 文章列表数据
|
||||
articles: ref(data.ARTICLE_PAGE.records),
|
||||
// 分页数据
|
||||
pagination: ref({
|
||||
page: data.ARTICLE_PAGE.page,
|
||||
capacity: data.ARTICLE_PAGE.capacity,
|
||||
total: data.ARTICLE_PAGE.total
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 路由参数变化时,触发数据搜索
|
||||
'$route.query': function (newQuery) {
|
||||
this.handlePageChange(Number(newQuery.page) || 1)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 页码变更
|
||||
*
|
||||
* @param page 新页码
|
||||
*/
|
||||
handlePageChange (page) {
|
||||
this.pagination.page = page
|
||||
fetchArticlePage({
|
||||
page: this.pagination.page,
|
||||
capacity: this.pagination.capacity,
|
||||
model: {
|
||||
categoryUid: this.categoryUid
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
this.pagination.page = page
|
||||
this.pagination.total = data.total
|
||||
this.articles = data.records
|
||||
})
|
||||
.catch(e => console.error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-wrap {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
}
|
||||
.wrap-body {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
// 栏目树
|
||||
.category-wrap {
|
||||
width: 275px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
// 内容
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
padding: 10px 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
103
.kit/translated/pages/category/[categoryUid]/index.vue
Normal file
103
.kit/translated/pages/category/[categoryUid]/index.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<NuxtLayout
|
||||
name="category"
|
||||
:categories="categoryTree"
|
||||
:subCategories="subCategoryTree"
|
||||
:selected-category="{
|
||||
uid: articlePageCategoryUid,
|
||||
title: category.title
|
||||
}"
|
||||
:breadcrumbs="breadcrumbs"
|
||||
>
|
||||
<ArticleList :articles="articles" />
|
||||
<Pagination v-model="pagination" />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { definePageMeta } from '#imports'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import Pagination from '@/components/common/Pagination'
|
||||
import CategoryUtil from '@/utils/category'
|
||||
import ArticleList from '@/components/cms/ArticleList'
|
||||
import { fetchTemplateData } from '@/api/cms/template'
|
||||
import { fetchArticlePage } from '@/api/cms/article'
|
||||
import { strictPackage } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArticleList,
|
||||
Pagination
|
||||
},
|
||||
async setup () {
|
||||
// 去掉默认布局
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
})
|
||||
const route = useRoute()
|
||||
const data = strictPackage(await fetchTemplateData({
|
||||
path: '/category/[categoryUid]/index.vue',
|
||||
targetUid: route.params.categoryUid,
|
||||
targetType: 'CATEGORY',
|
||||
parameters: {
|
||||
categoryUid: route.params.categoryUid
|
||||
}
|
||||
}))
|
||||
// 获取分页所使用的栏目UID
|
||||
const articlePageCategoryUid = data.ARTICLE_PAGE_PARAMETERS.categoryUid
|
||||
const categoryUtil = new CategoryUtil(data.CATEGORIES_TREE)
|
||||
const category = categoryUtil.getCategory(articlePageCategoryUid)
|
||||
if (category == null) {
|
||||
throw new Error(`找不到栏目,UID: ${articlePageCategoryUid}`)
|
||||
}
|
||||
return {
|
||||
categoryUid: route.params.categoryUid,
|
||||
categoryTree: data.CATEGORIES_TREE,
|
||||
subCategoryTree: data.SUB_CATEGORIES_TREE,
|
||||
category: categoryUtil.getCategory(articlePageCategoryUid),
|
||||
// 查询文章分页数据的栏目ID
|
||||
articlePageCategoryUid,
|
||||
// 面包屑
|
||||
breadcrumbs: categoryUtil.getBreadcrumb(articlePageCategoryUid),
|
||||
// 文章列表数据
|
||||
articles: ref(data.ARTICLE_PAGE.records),
|
||||
// 分页数据
|
||||
pagination: ref({
|
||||
page: data.ARTICLE_PAGE.page,
|
||||
capacity: data.ARTICLE_PAGE.capacity,
|
||||
total: data.ARTICLE_PAGE.total
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 路由参数变化时,触发数据搜索
|
||||
'$route.query': function (newQuery) {
|
||||
this.handlePageChange(Number(newQuery.page) || 1)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 页码变更
|
||||
*
|
||||
* @param page 新页码
|
||||
*/
|
||||
handlePageChange (page) {
|
||||
this.pagination.page = page
|
||||
fetchArticlePage({
|
||||
page: this.pagination.page,
|
||||
capacity: this.pagination.capacity,
|
||||
model: {
|
||||
categoryUid: this.articlePageCategoryUid
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
this.pagination.page = page
|
||||
this.pagination.total = data.total
|
||||
this.articles = data.records
|
||||
})
|
||||
.catch(e => console.error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
179
.kit/translated/pages/index.vue
Normal file
179
.kit/translated/pages/index.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<NuxtLayout name="default" :categories="categoryTree">
|
||||
<div class="content-wrap">
|
||||
<!-- 第一部分 -->
|
||||
<div class="block row row-wrap">
|
||||
<!-- 轮播图 -->
|
||||
<div>
|
||||
<Carousel :data="carouselList"/>
|
||||
</div>
|
||||
<div>
|
||||
<DataListTabs :data="dtData"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 第二部分 -->
|
||||
<div class="block row">
|
||||
<div>
|
||||
<DataListTabs :data="ldzcData"/>
|
||||
</div>
|
||||
<div>
|
||||
<DataListTabs :data="dwgkData"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 第三部分 -->
|
||||
<ul class="block row row-wrap col-3" style="padding-bottom: 0;">
|
||||
<li><DataListTabs :data="tzggData"/></li>
|
||||
<li><DataListTabs :data="pqgsTabs"/></li>
|
||||
<li><DataListTabs :data="phgsTabs"/></li>
|
||||
<li><DataListTabs :data="bdcdjznTabs"/></li>
|
||||
<li><DataListTabs :data="wlaqxcTabs"/></li>
|
||||
<li><DataListTabs :data="djgzTabs"/></li>
|
||||
</ul>
|
||||
<!-- 专题专栏 -->
|
||||
<div class="block">
|
||||
<SpecialColumn :icons="subjectData"/>
|
||||
</div>
|
||||
<!-- 网站导航 -->
|
||||
<div class="website-nav">
|
||||
<WebsiteNav :data="websiteNavData"/>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
<script>
|
||||
import { definePageMeta } from '#imports'
|
||||
import DataListTabs from '@/components/common/DataListTabs'
|
||||
import SpecialColumn from '@/components/cms/SpecialColumn'
|
||||
import Carousel from '@/components/home/Carousel'
|
||||
import WebsiteNav from '@/components/home/WebsiteNav'
|
||||
import CategoryUtil from '@/utils/category'
|
||||
import { fetchTemplateData } from '@/api/cms/template'
|
||||
import { strictPackage } from '@/utils/util'
|
||||
export default {
|
||||
components: {
|
||||
WebsiteNav,
|
||||
Carousel,
|
||||
SpecialColumn,
|
||||
DataListTabs
|
||||
},
|
||||
async setup () {
|
||||
// 去掉默认布局
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
})
|
||||
const pageData = strictPackage(await fetchTemplateData({
|
||||
path: '/index.vue',
|
||||
targetUid: 'sy',
|
||||
targetType: 'CATEGORY'
|
||||
}))
|
||||
const categoryTitleMap = {
|
||||
snyw: '省内要闻',
|
||||
gnyw: '国内要闻',
|
||||
ldzc: '领导之窗',
|
||||
dwgk: '单位概况',
|
||||
tzgg: '通知公告',
|
||||
pqgs: '批前公示',
|
||||
phgs: '批后公示',
|
||||
bdcdjzn: '不动产登记指南',
|
||||
wlaqxc: '网络安全宣传',
|
||||
djgz: '党建工作',
|
||||
}
|
||||
const categoryUtil = new CategoryUtil(pageData.CATEGORIES_TREE)
|
||||
const getTab = (categoryUid, data = []) => {
|
||||
const category = categoryUtil.getCategory(categoryUid)
|
||||
if (category == null) {
|
||||
throw new Error(`找不到栏目,UID: ${categoryUid}`)
|
||||
}
|
||||
return {
|
||||
code: categoryUid,
|
||||
label: categoryTitleMap[categoryUid],
|
||||
moreLink: category.uri,
|
||||
items: data
|
||||
}
|
||||
}
|
||||
const dataListTabs = pageData.MULTIPLE_CATEGORY_ARTICLES
|
||||
// 资源数据
|
||||
const resources = pageData.MULTIPLE_RESOURCES
|
||||
return {
|
||||
// 栏目树
|
||||
categoryTree: pageData.CATEGORIES_TREE,
|
||||
// 走马灯
|
||||
carouselList: pageData.MULTIPLE_RESOURCES.HOME_CAROUSEL,
|
||||
// 动态数据
|
||||
dtData: [
|
||||
getTab('snyw', dataListTabs.snyw),
|
||||
getTab('gnyw', dataListTabs.gnyw),
|
||||
],
|
||||
// 专题数据
|
||||
subjectData: resources.ZHUAN_LAN,
|
||||
// 网站导航数据
|
||||
websiteNavData: [
|
||||
resources.SITE_NAVIGAT_1,
|
||||
resources.SITE_NAVIGAT_2,
|
||||
resources.SITE_NAVIGAT_3,
|
||||
resources.FRIENDLY_LINKS
|
||||
],
|
||||
ldzcData: [getTab('ldzc', dataListTabs.ldzc)],
|
||||
dwgkData: [getTab('dwgk', dataListTabs.dwgk)],
|
||||
tzggData: [getTab('tzgg', dataListTabs.tzgg)],
|
||||
pqgsTabs: [getTab('pqgs', dataListTabs.pqgs)],
|
||||
phgsTabs: [getTab('phgs', dataListTabs.phgs)],
|
||||
bdcdjznTabs: [getTab('bdcdjzn', dataListTabs.bdcdjzn)],
|
||||
wlaqxcTabs: [getTab('wlaqxc', dataListTabs.wlaqxc)],
|
||||
djgzTabs: [getTab('djgz', dataListTabs.djgz)],
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.default-layout {
|
||||
.content-wrap {
|
||||
// 数据块的高度
|
||||
--data-block-height: 360px;
|
||||
// 网站导航
|
||||
.website-nav {
|
||||
padding: 15px 20px;
|
||||
background-color: #EAF1FB;
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
// 数据列表
|
||||
.data-list-tabs {
|
||||
:deep(ul.article-list) {
|
||||
height: var(--data-block-height);
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0;
|
||||
& > li {
|
||||
border-bottom: 0 !important;
|
||||
a {
|
||||
padding: 10px 10px 10px 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.block {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
& > * {
|
||||
width: 49%;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
// 自动换行
|
||||
&.row-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
&.col-3 {
|
||||
& > * {
|
||||
width: 32%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
107
.kit/translated/pages/search.vue
Normal file
107
.kit/translated/pages/search.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<NuxtLayout name="default" :categories="categoryTree">
|
||||
<div class="content-wrap">
|
||||
<h2>搜索到 <em>{{ articlePage.pagination.total }}</em> 条记录</h2>
|
||||
<ArticleList :articles="articlePage.data" :keyword="keyword"/>
|
||||
<Pagination
|
||||
v-model="articlePage.pagination"
|
||||
:get-page-url="page => {
|
||||
return `/search?kwd=${keyword}&page=${page}`
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { definePageMeta } from '#imports'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import Pagination from '@/components/common/Pagination'
|
||||
import ArticleList from '@/components/cms/ArticleList'
|
||||
import { fetchTemplateData } from '@/api/cms/template'
|
||||
import { search } from '@/api/cms/search'
|
||||
import { strictPackage } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
components: { ArticleList, Pagination },
|
||||
async setup () {
|
||||
// 去掉默认布局
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
})
|
||||
const route = useRoute()
|
||||
const keyword = route.query.kwd || ''
|
||||
// 获取模板数据
|
||||
const data = strictPackage(await fetchTemplateData({
|
||||
path: '/search.vue',
|
||||
parameters: {
|
||||
keyword
|
||||
}
|
||||
}))
|
||||
return {
|
||||
keyword,
|
||||
// 栏目树
|
||||
categoryTree: data.CATEGORIES_TREE,
|
||||
// 文章数据
|
||||
articlePage: ref({
|
||||
// 文章列表
|
||||
data: data.SEARCH_PAGE.articlePage.records,
|
||||
// 分页数据
|
||||
pagination: {
|
||||
page: data.SEARCH_PAGE.articlePage.page,
|
||||
capacity: data.SEARCH_PAGE.articlePage.capacity,
|
||||
total: data.SEARCH_PAGE.articlePage.total
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 路由参数变化时,触发数据搜索
|
||||
'$route.query': function (newQuery) {
|
||||
this.keyword = newQuery.kwd || ''
|
||||
this.handlePageChange(Number(newQuery.page) || 1)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 页码变更
|
||||
*
|
||||
* @param page 新页码
|
||||
*/
|
||||
handlePageChange (page) {
|
||||
this.articlePage.pagination.page = page
|
||||
search({
|
||||
page: this.articlePage.pagination.page,
|
||||
capacity: this.articlePage.pagination.capacity,
|
||||
model: this.keyword
|
||||
})
|
||||
.then(data => {
|
||||
this.articlePage.data = data.articlePage.records
|
||||
this.articlePage.pagination.total = data.articlePage.total
|
||||
})
|
||||
.catch(e => {
|
||||
this.$tip.apiFailed(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-wrap {
|
||||
background-color: var(--color-white);
|
||||
padding: 20px;
|
||||
h2 {
|
||||
margin: 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding-bottom: 10px;
|
||||
font-weight: normal;
|
||||
em {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
28
.kit/translated/plugins/global.js
Normal file
28
.kit/translated/plugins/global.js
Normal file
@ -0,0 +1,28 @@
|
||||
// imports
|
||||
import request from '@/utils/request'
|
||||
import {getImageURL, getDictLabel, getAttachURL} from '@/utils/util'
|
||||
|
||||
/**
|
||||
* 扩展全局属性,此处封装为方法,方便做框架级调整
|
||||
*
|
||||
* @param app 挂载对象
|
||||
* @param key 属性
|
||||
* @param value 值
|
||||
*/
|
||||
const extendsProperty = (app, key, value) => {
|
||||
app[key] = value
|
||||
}
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
const app = nuxtApp.vueApp.config.globalProperties
|
||||
nuxtApp.provide('request', request)
|
||||
// 去掉警告信息
|
||||
nuxtApp.vueApp.config.warnHandler = (msg, instance, trace) => {
|
||||
console.warn('此处忽略WARN内容,避免展示大量不必要的WARN信息');
|
||||
}
|
||||
// 获取图片地址
|
||||
app.$getImageURL = getImageURL
|
||||
// 获取附件地址
|
||||
app.$getAttachURL = getAttachURL
|
||||
// 获取字典数据
|
||||
app.$d = getDictLabel
|
||||
})
|
24
.kit/translated/plugins/message.js
Normal file
24
.kit/translated/plugins/message.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
nuxtApp.vueApp.config.globalProperties.$tip = {
|
||||
...ElMessage,
|
||||
apiSuccess (message) {
|
||||
return ElMessage.success(message)
|
||||
},
|
||||
apiFailed (e) {
|
||||
if (e === 'cancel') {
|
||||
return
|
||||
}
|
||||
console.error && console.error('接口提示错误', e)
|
||||
// 检查是否存在全局错误
|
||||
const globalErrorDom = document.querySelector('.el-message--error')
|
||||
if (globalErrorDom != null) {
|
||||
return
|
||||
}
|
||||
if (typeof e === 'string') {
|
||||
return ElMessage.error(e)
|
||||
}
|
||||
return ElMessage.error(e.message)
|
||||
}
|
||||
}
|
||||
})
|
24
.kit/translated/plugins/messagebox.js
Normal file
24
.kit/translated/plugins/messagebox.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
export default defineNuxtPlugin(nuxtApp => {
|
||||
nuxtApp.vueApp.config.globalProperties.$dialog = {
|
||||
...ElMessageBox,
|
||||
/**
|
||||
* 重要提醒
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @param title 提醒标题
|
||||
* @param extConfig 扩展配置
|
||||
* @returns {Promise}
|
||||
*/
|
||||
attentionConfirm (message, title = '重要提醒', extConfig = {}) {
|
||||
return ElMessageBox.confirm(message, title, {
|
||||
showCancelButton: false,
|
||||
showClose: false,
|
||||
closeOnClickModal: false,
|
||||
closeOnPressEscape: false,
|
||||
type: 'warning',
|
||||
...extConfig
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
11
.kit/translated/plugins/nprogress.js
Normal file
11
.kit/translated/plugins/nprogress.js
Normal file
@ -0,0 +1,11 @@
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.hook('page:start', () => {
|
||||
NProgress.start()
|
||||
})
|
||||
nuxtApp.hook('page:finish', () => {
|
||||
NProgress.done()
|
||||
})
|
||||
})
|
BIN
.kit/translated/public/favicon.ico
Normal file
BIN
.kit/translated/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
539
.kit/translated/public/icons/cms/demo.css
Normal file
539
.kit/translated/public/icons/cms/demo.css
Normal file
@ -0,0 +1,539 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
1361
.kit/translated/public/icons/cms/demo_index.html
Normal file
1361
.kit/translated/public/icons/cms/demo_index.html
Normal file
File diff suppressed because it is too large
Load Diff
219
.kit/translated/public/icons/cms/iconfont.css
Normal file
219
.kit/translated/public/icons/cms/iconfont.css
Normal file
@ -0,0 +1,219 @@
|
||||
@font-face {
|
||||
font-family: "cmsfont"; /* Project id 4718675 */
|
||||
src: url('iconfont.woff2?t=1731151023913') format('woff2'),
|
||||
url('iconfont.woff?t=1731151023913') format('woff'),
|
||||
url('iconfont.ttf?t=1731151023913') format('truetype');
|
||||
}
|
||||
|
||||
.cmsfont {
|
||||
font-family: "cmsfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.cms-home1:before {
|
||||
content: "\e637";
|
||||
}
|
||||
|
||||
.cms-org1:before {
|
||||
content: "\e6ae";
|
||||
}
|
||||
|
||||
.cms-home2:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.cms-home3:before {
|
||||
content: "\e638";
|
||||
}
|
||||
|
||||
.cms-cooperation1:before {
|
||||
content: "\e65a";
|
||||
}
|
||||
|
||||
.cms-org2:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.cms-special-subject1:before {
|
||||
content: "\e87a";
|
||||
}
|
||||
|
||||
.cms-org3:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.cms-home4:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.cms-cooperation3:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.cms-org4:before {
|
||||
content: "\e7ca";
|
||||
}
|
||||
|
||||
.cms-special-subject2:before {
|
||||
content: "\e671";
|
||||
}
|
||||
|
||||
.cms-public1:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.cms-dynamic2:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.cms-cooperation4:before {
|
||||
content: "\e777";
|
||||
}
|
||||
|
||||
.cms-dynamic3:before {
|
||||
content: "\e672";
|
||||
}
|
||||
|
||||
.cms-home5:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.cms-special-subject3:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.cms-cooperation5:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.cms-special-subject4:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.cms-home6:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.cms-policy1:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.cms-policy2:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.cms-home7:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.cms-policy3:before {
|
||||
content: "\e667";
|
||||
}
|
||||
|
||||
.cms-policy4:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.cms-policy5:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.cms-home8:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.cms-gov1:before {
|
||||
content: "\e753";
|
||||
}
|
||||
|
||||
.cms-cooperation2-copy:before {
|
||||
content: "\ebc9";
|
||||
}
|
||||
|
||||
.cms-category:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.cms-category1:before {
|
||||
content: "\e6a4";
|
||||
}
|
||||
|
||||
.cms-category2:before {
|
||||
content: "\e6a7";
|
||||
}
|
||||
|
||||
.cms-category3:before {
|
||||
content: "\e63b";
|
||||
}
|
||||
|
||||
.cms-service:before {
|
||||
content: "\e6d8";
|
||||
}
|
||||
|
||||
.cms-article:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.cms-goods:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.cms-template:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.cms-material:before {
|
||||
content: "\e66d";
|
||||
}
|
||||
|
||||
.cms-template2:before {
|
||||
content: "\e666";
|
||||
}
|
||||
|
||||
.cms-content:before {
|
||||
content: "\e890";
|
||||
}
|
||||
|
||||
.cms-content2:before {
|
||||
content: "\e6b2";
|
||||
}
|
||||
|
||||
.cms-content3:before {
|
||||
content: "\e681";
|
||||
}
|
||||
|
||||
.cms-article2:before {
|
||||
content: "\e7d3";
|
||||
}
|
||||
|
||||
.cms-material2:before {
|
||||
content: "\e665";
|
||||
}
|
||||
|
||||
.cms-article3:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.cms-content4:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.cms-service2:before {
|
||||
content: "\e694";
|
||||
}
|
||||
|
||||
.cms-material3:before {
|
||||
content: "\e7ef";
|
||||
}
|
||||
|
||||
.cms-service3:before {
|
||||
content: "\e636";
|
||||
}
|
||||
|
||||
.cms-goods2:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
1
.kit/translated/public/icons/cms/iconfont.js
Normal file
1
.kit/translated/public/icons/cms/iconfont.js
Normal file
File diff suppressed because one or more lines are too long
366
.kit/translated/public/icons/cms/iconfont.json
Normal file
366
.kit/translated/public/icons/cms/iconfont.json
Normal file
@ -0,0 +1,366 @@
|
||||
{
|
||||
"id": "4718675",
|
||||
"name": "eva-cms",
|
||||
"font_family": "cmsfont",
|
||||
"css_prefix_text": "cms-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "166640",
|
||||
"name": "首页",
|
||||
"font_class": "home1",
|
||||
"unicode": "e637",
|
||||
"unicode_decimal": 58935
|
||||
},
|
||||
{
|
||||
"icon_id": "974813",
|
||||
"name": "机构",
|
||||
"font_class": "org1",
|
||||
"unicode": "e6ae",
|
||||
"unicode_decimal": 59054
|
||||
},
|
||||
{
|
||||
"icon_id": "1129603",
|
||||
"name": "首页",
|
||||
"font_class": "home2",
|
||||
"unicode": "e627",
|
||||
"unicode_decimal": 58919
|
||||
},
|
||||
{
|
||||
"icon_id": "1244100",
|
||||
"name": "首页",
|
||||
"font_class": "home3",
|
||||
"unicode": "e638",
|
||||
"unicode_decimal": 58936
|
||||
},
|
||||
{
|
||||
"icon_id": "2570131",
|
||||
"name": "合作",
|
||||
"font_class": "cooperation1",
|
||||
"unicode": "e65a",
|
||||
"unicode_decimal": 58970
|
||||
},
|
||||
{
|
||||
"icon_id": "5744737",
|
||||
"name": "组织机构",
|
||||
"font_class": "org2",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "5838824",
|
||||
"name": "专题",
|
||||
"font_class": "special-subject1",
|
||||
"unicode": "e87a",
|
||||
"unicode_decimal": 59514
|
||||
},
|
||||
{
|
||||
"icon_id": "5873042",
|
||||
"name": "组织机构",
|
||||
"font_class": "org3",
|
||||
"unicode": "e620",
|
||||
"unicode_decimal": 58912
|
||||
},
|
||||
{
|
||||
"icon_id": "6865351",
|
||||
"name": "首页",
|
||||
"font_class": "home4",
|
||||
"unicode": "e610",
|
||||
"unicode_decimal": 58896
|
||||
},
|
||||
{
|
||||
"icon_id": "7814499",
|
||||
"name": "合作/招商",
|
||||
"font_class": "cooperation3",
|
||||
"unicode": "e606",
|
||||
"unicode_decimal": 58886
|
||||
},
|
||||
{
|
||||
"icon_id": "7876369",
|
||||
"name": "组织机构",
|
||||
"font_class": "org4",
|
||||
"unicode": "e7ca",
|
||||
"unicode_decimal": 59338
|
||||
},
|
||||
{
|
||||
"icon_id": "9466859",
|
||||
"name": "专题",
|
||||
"font_class": "special-subject2",
|
||||
"unicode": "e671",
|
||||
"unicode_decimal": 58993
|
||||
},
|
||||
{
|
||||
"icon_id": "10158782",
|
||||
"name": "公开",
|
||||
"font_class": "public1",
|
||||
"unicode": "e63f",
|
||||
"unicode_decimal": 58943
|
||||
},
|
||||
{
|
||||
"icon_id": "11032202",
|
||||
"name": "动态",
|
||||
"font_class": "dynamic2",
|
||||
"unicode": "e612",
|
||||
"unicode_decimal": 58898
|
||||
},
|
||||
{
|
||||
"icon_id": "11521307",
|
||||
"name": "合作",
|
||||
"font_class": "cooperation4",
|
||||
"unicode": "e777",
|
||||
"unicode_decimal": 59255
|
||||
},
|
||||
{
|
||||
"icon_id": "12129940",
|
||||
"name": "动态",
|
||||
"font_class": "dynamic3",
|
||||
"unicode": "e672",
|
||||
"unicode_decimal": 58994
|
||||
},
|
||||
{
|
||||
"icon_id": "16290378",
|
||||
"name": "首页",
|
||||
"font_class": "home5",
|
||||
"unicode": "e628",
|
||||
"unicode_decimal": 58920
|
||||
},
|
||||
{
|
||||
"icon_id": "16994568",
|
||||
"name": "专题",
|
||||
"font_class": "special-subject3",
|
||||
"unicode": "e607",
|
||||
"unicode_decimal": 58887
|
||||
},
|
||||
{
|
||||
"icon_id": "18028238",
|
||||
"name": "合作",
|
||||
"font_class": "cooperation5",
|
||||
"unicode": "e61a",
|
||||
"unicode_decimal": 58906
|
||||
},
|
||||
{
|
||||
"icon_id": "18272239",
|
||||
"name": "专题",
|
||||
"font_class": "special-subject4",
|
||||
"unicode": "e61e",
|
||||
"unicode_decimal": 58910
|
||||
},
|
||||
{
|
||||
"icon_id": "18758196",
|
||||
"name": "首页",
|
||||
"font_class": "home6",
|
||||
"unicode": "e669",
|
||||
"unicode_decimal": 58985
|
||||
},
|
||||
{
|
||||
"icon_id": "21800726",
|
||||
"name": "政策",
|
||||
"font_class": "policy1",
|
||||
"unicode": "e61d",
|
||||
"unicode_decimal": 58909
|
||||
},
|
||||
{
|
||||
"icon_id": "22236044",
|
||||
"name": "政策",
|
||||
"font_class": "policy2",
|
||||
"unicode": "e65c",
|
||||
"unicode_decimal": 58972
|
||||
},
|
||||
{
|
||||
"icon_id": "22771475",
|
||||
"name": "首页",
|
||||
"font_class": "home7",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "22843424",
|
||||
"name": "政策",
|
||||
"font_class": "policy3",
|
||||
"unicode": "e667",
|
||||
"unicode_decimal": 58983
|
||||
},
|
||||
{
|
||||
"icon_id": "34547473",
|
||||
"name": "政策",
|
||||
"font_class": "policy4",
|
||||
"unicode": "e609",
|
||||
"unicode_decimal": 58889
|
||||
},
|
||||
{
|
||||
"icon_id": "34548382",
|
||||
"name": "政策",
|
||||
"font_class": "policy5",
|
||||
"unicode": "e60a",
|
||||
"unicode_decimal": 58890
|
||||
},
|
||||
{
|
||||
"icon_id": "41012044",
|
||||
"name": "首页",
|
||||
"font_class": "home8",
|
||||
"unicode": "e617",
|
||||
"unicode_decimal": 58903
|
||||
},
|
||||
{
|
||||
"icon_id": "42192435",
|
||||
"name": "政府",
|
||||
"font_class": "gov1",
|
||||
"unicode": "e753",
|
||||
"unicode_decimal": 59219
|
||||
},
|
||||
{
|
||||
"icon_id": "42408386",
|
||||
"name": "合作",
|
||||
"font_class": "cooperation2-copy",
|
||||
"unicode": "ebc9",
|
||||
"unicode_decimal": 60361
|
||||
},
|
||||
{
|
||||
"icon_id": "1757454",
|
||||
"name": "所有栏目列表",
|
||||
"font_class": "category",
|
||||
"unicode": "e625",
|
||||
"unicode_decimal": 58917
|
||||
},
|
||||
{
|
||||
"icon_id": "20605189",
|
||||
"name": "树",
|
||||
"font_class": "category1",
|
||||
"unicode": "e6a4",
|
||||
"unicode_decimal": 59044
|
||||
},
|
||||
{
|
||||
"icon_id": "20683172",
|
||||
"name": "新建下级栏目",
|
||||
"font_class": "category2",
|
||||
"unicode": "e6a7",
|
||||
"unicode_decimal": 59047
|
||||
},
|
||||
{
|
||||
"icon_id": "39691573",
|
||||
"name": "栏目管理",
|
||||
"font_class": "category3",
|
||||
"unicode": "e63b",
|
||||
"unicode_decimal": 58939
|
||||
},
|
||||
{
|
||||
"icon_id": "680102",
|
||||
"name": "服务",
|
||||
"font_class": "service",
|
||||
"unicode": "e6d8",
|
||||
"unicode_decimal": 59096
|
||||
},
|
||||
{
|
||||
"icon_id": "924719",
|
||||
"name": "文章",
|
||||
"font_class": "article",
|
||||
"unicode": "e624",
|
||||
"unicode_decimal": 58916
|
||||
},
|
||||
{
|
||||
"icon_id": "1137786",
|
||||
"name": "商品",
|
||||
"font_class": "goods",
|
||||
"unicode": "e67b",
|
||||
"unicode_decimal": 59003
|
||||
},
|
||||
{
|
||||
"icon_id": "1367324",
|
||||
"name": "模板",
|
||||
"font_class": "template",
|
||||
"unicode": "e60f",
|
||||
"unicode_decimal": 58895
|
||||
},
|
||||
{
|
||||
"icon_id": "1509751",
|
||||
"name": "素材",
|
||||
"font_class": "material",
|
||||
"unicode": "e66d",
|
||||
"unicode_decimal": 58989
|
||||
},
|
||||
{
|
||||
"icon_id": "1680696",
|
||||
"name": "模板",
|
||||
"font_class": "template2",
|
||||
"unicode": "e666",
|
||||
"unicode_decimal": 58982
|
||||
},
|
||||
{
|
||||
"icon_id": "2076263",
|
||||
"name": "内容",
|
||||
"font_class": "content",
|
||||
"unicode": "e890",
|
||||
"unicode_decimal": 59536
|
||||
},
|
||||
{
|
||||
"icon_id": "2786517",
|
||||
"name": "内容字段管理",
|
||||
"font_class": "content2",
|
||||
"unicode": "e6b2",
|
||||
"unicode_decimal": 59058
|
||||
},
|
||||
{
|
||||
"icon_id": "3005918",
|
||||
"name": "内容",
|
||||
"font_class": "content3",
|
||||
"unicode": "e681",
|
||||
"unicode_decimal": 59009
|
||||
},
|
||||
{
|
||||
"icon_id": "8798005",
|
||||
"name": "我的文章",
|
||||
"font_class": "article2",
|
||||
"unicode": "e7d3",
|
||||
"unicode_decimal": 59347
|
||||
},
|
||||
{
|
||||
"icon_id": "10940098",
|
||||
"name": "素材",
|
||||
"font_class": "material2",
|
||||
"unicode": "e665",
|
||||
"unicode_decimal": 58981
|
||||
},
|
||||
{
|
||||
"icon_id": "11124968",
|
||||
"name": "文章",
|
||||
"font_class": "article3",
|
||||
"unicode": "e615",
|
||||
"unicode_decimal": 58901
|
||||
},
|
||||
{
|
||||
"icon_id": "14559362",
|
||||
"name": "内容",
|
||||
"font_class": "content4",
|
||||
"unicode": "e616",
|
||||
"unicode_decimal": 58902
|
||||
},
|
||||
{
|
||||
"icon_id": "15765349",
|
||||
"name": "服务",
|
||||
"font_class": "service2",
|
||||
"unicode": "e694",
|
||||
"unicode_decimal": 59028
|
||||
},
|
||||
{
|
||||
"icon_id": "18494060",
|
||||
"name": "素材资源",
|
||||
"font_class": "material3",
|
||||
"unicode": "e7ef",
|
||||
"unicode_decimal": 59375
|
||||
},
|
||||
{
|
||||
"icon_id": "19449190",
|
||||
"name": "服务",
|
||||
"font_class": "service3",
|
||||
"unicode": "e636",
|
||||
"unicode_decimal": 58934
|
||||
},
|
||||
{
|
||||
"icon_id": "31313020",
|
||||
"name": "商品",
|
||||
"font_class": "goods2",
|
||||
"unicode": "e61f",
|
||||
"unicode_decimal": 58911
|
||||
}
|
||||
]
|
||||
}
|
BIN
.kit/translated/public/icons/cms/iconfont.ttf
Normal file
BIN
.kit/translated/public/icons/cms/iconfont.ttf
Normal file
Binary file not shown.
BIN
.kit/translated/public/icons/cms/iconfont.woff
Normal file
BIN
.kit/translated/public/icons/cms/iconfont.woff
Normal file
Binary file not shown.
BIN
.kit/translated/public/icons/cms/iconfont.woff2
Normal file
BIN
.kit/translated/public/icons/cms/iconfont.woff2
Normal file
Binary file not shown.
BIN
.kit/translated/public/images/background.jpg
Normal file
BIN
.kit/translated/public/images/background.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
BIN
.kit/translated/public/images/icp.png
Normal file
BIN
.kit/translated/public/images/icp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
.kit/translated/public/images/link.png
Normal file
BIN
.kit/translated/public/images/link.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
2
.kit/translated/public/robots.txt
Normal file
2
.kit/translated/public/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /_nuxt/
|
3
.kit/translated/server/tsconfig.json
Normal file
3
.kit/translated/server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
1
.kit/translated/startup.sh
Normal file
1
.kit/translated/startup.sh
Normal file
@ -0,0 +1 @@
|
||||
pm2 start server/index.mjs --name 'eva-cms-website-gov' --instances max
|
14
.kit/translated/stores/index.js
Normal file
14
.kit/translated/stores/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { fetchConfig } from '@/api/client'
|
||||
|
||||
export const useDefaultStore = defineStore('default', {
|
||||
state: () => ({
|
||||
// 客户端配置(包含系统配置和字典数据)
|
||||
clientConfig: null
|
||||
}),
|
||||
actions: {
|
||||
async fetchConfig () {
|
||||
this.clientConfig = await fetchConfig()
|
||||
}
|
||||
}
|
||||
})
|
4
.kit/translated/tsconfig.json
Normal file
4
.kit/translated/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
81
.kit/translated/utils/category.js
Normal file
81
.kit/translated/utils/category.js
Normal file
@ -0,0 +1,81 @@
|
||||
class CategoryUtil {
|
||||
#tree = []
|
||||
constructor (tree) {
|
||||
this.#tree = tree
|
||||
this.#fillParent(this.#tree)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取面包屑
|
||||
*
|
||||
* @param uid
|
||||
* @returns {*[]}
|
||||
*/
|
||||
getBreadcrumb (uid) {
|
||||
let target = this.#getNode(this.#tree, uid)
|
||||
if (target == null) {
|
||||
return []
|
||||
}
|
||||
const nodes = []
|
||||
while (target != null) {
|
||||
nodes.push(target)
|
||||
target = target.parent
|
||||
}
|
||||
return nodes.map(node => {
|
||||
return {
|
||||
uid: node.uid,
|
||||
title: node.title,
|
||||
uri: node.uri
|
||||
}
|
||||
}).reverse()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取栏目
|
||||
*
|
||||
* @param uid
|
||||
* @returns {*|null}
|
||||
*/
|
||||
getCategory (uid) {
|
||||
return this.#getNode(this.#tree, uid)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目标节点
|
||||
*
|
||||
* @param categoryList 栏目列表
|
||||
* @param uid 栏目唯一标识
|
||||
* @returns {*|null}
|
||||
*/
|
||||
#getNode (categoryList, uid) {
|
||||
for (const node of categoryList) {
|
||||
if (node.uid === uid) {
|
||||
return node
|
||||
}
|
||||
if (node.children != null && node.children.length > 0) {
|
||||
const result = this.#getNode(node.children, uid)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充父节点
|
||||
*
|
||||
* @param categoryList 栏目列表
|
||||
* @param parent 父节点
|
||||
*/
|
||||
#fillParent (categoryList, parent) {
|
||||
for (const node of categoryList) {
|
||||
node.parent = parent
|
||||
if (node.children != null && node.children.length > 0) {
|
||||
this.#fillParent(node.children, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CategoryUtil
|
79
.kit/translated/utils/request.js
Normal file
79
.kit/translated/utils/request.js
Normal file
@ -0,0 +1,79 @@
|
||||
import axios from 'axios'
|
||||
import { trim } from './util'
|
||||
|
||||
// 默认配置
|
||||
axios.defaults.headers.common['Content-Type'] = 'application/json;charset=UTF-8'
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: '/api',
|
||||
// 请求超时时间
|
||||
timeout: 60000
|
||||
})
|
||||
|
||||
// 添加请求拦截器
|
||||
axiosInstance.interceptors.request.use(function (config) {
|
||||
// 服务端调用,使用全路径
|
||||
if (window === undefined) {
|
||||
config.baseURL = import.meta.env.VITE_API_URL
|
||||
}
|
||||
// 导出处理
|
||||
if (config.download === true) {
|
||||
config.responseType = 'blob'
|
||||
}
|
||||
// 参数去空格
|
||||
if (config.trim === true) {
|
||||
if (config.data != null) {
|
||||
config.data = trim(config.data)
|
||||
}
|
||||
if (config.params != null) {
|
||||
config.params = trim(config.params)
|
||||
}
|
||||
}
|
||||
return config
|
||||
}, function (error) {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// 添加响应拦截器
|
||||
axiosInstance.interceptors.response.use(function (response) {
|
||||
// 下载接口处理
|
||||
if (response.headers['x-opera-type'] === 'download') {
|
||||
if (response.config.responseType !== 'blob') {
|
||||
return Promise.reject(new Error('下载接口返回类型错误,请检查接口定义是否缺少download标识!'))
|
||||
}
|
||||
// Blob类型数据,导出下载文件时,如果接口未正确执行,返回类型为Blob
|
||||
return new Promise((resolve, reject) => {
|
||||
if (response.data.type !== 'application/json') {
|
||||
resolve(response)
|
||||
return
|
||||
}
|
||||
const blob = new Blob([response.data])
|
||||
const fileReader = new FileReader()
|
||||
// 读取Blob内容
|
||||
fileReader.readAsText(blob, 'utf-8')
|
||||
fileReader.onload = function () {
|
||||
const result = JSON.parse(fileReader.result)
|
||||
// 业务失败
|
||||
if (!result.success) {
|
||||
reject(result)
|
||||
return
|
||||
}
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 对响应数据做点什么
|
||||
if (response.data.success) {
|
||||
return response.data.data
|
||||
}
|
||||
console.error('接口错误', response.data.message)
|
||||
return Promise.reject(response.data)
|
||||
}, function (error) {
|
||||
if (error.response.status === 500) {
|
||||
return Promise.reject(new Error('网络繁忙,请稍后再试!'))
|
||||
}
|
||||
// 对响应错误做点什么
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
export default axiosInstance
|
30
.kit/translated/utils/sitemap.js
Normal file
30
.kit/translated/utils/sitemap.js
Normal file
@ -0,0 +1,30 @@
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
// 缓存时间为一天
|
||||
cacheMaxAgeSeconds: 60 * 60 * 24,
|
||||
// 自动检测最后更新时间
|
||||
autoLastmod: true,
|
||||
// 排除的链接
|
||||
exclude: [],
|
||||
// 发起请求获取链接
|
||||
urls: async () => {
|
||||
return await axios.post(`${import.meta.env.VITE_API_URL}/search`, {
|
||||
page: 1,
|
||||
capacity: 100,
|
||||
model: ''
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data.code !== 200) {
|
||||
throw new Error(res.data.message)
|
||||
}
|
||||
// 循环构建地址
|
||||
return res.data.data.articlePage.records.map(article => {
|
||||
return `/article/${article.uid}`
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
120
.kit/translated/utils/util.js
Normal file
120
.kit/translated/utils/util.js
Normal file
@ -0,0 +1,120 @@
|
||||
import { useDefaultStore } from '../stores'
|
||||
|
||||
// 获取Store
|
||||
function getStore () {
|
||||
return useDefaultStore()
|
||||
}
|
||||
|
||||
/**
|
||||
* 为对象、数组、字符串等数据去空
|
||||
*
|
||||
* @param data 数据
|
||||
* @returns {string|null|*}
|
||||
*/
|
||||
export function trim (data) {
|
||||
if (data == null) {
|
||||
return null
|
||||
}
|
||||
if (typeof data === 'string') {
|
||||
return data.trim()
|
||||
}
|
||||
if (data instanceof Array) {
|
||||
for (const item of data) {
|
||||
trim(item)
|
||||
}
|
||||
}
|
||||
if (typeof data === 'object') {
|
||||
for (const key in data) {
|
||||
data[key] = trim(data[key])
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码表达式获取字典或数据标签
|
||||
*
|
||||
* @param codeExpress 编码表达式
|
||||
* 语法1:“字典编码.数据编码”,如GENDER.MALE
|
||||
* 语法2:“字典编码”,如GENDER
|
||||
*/
|
||||
export function getDictLabel (codeExpress) {
|
||||
const dictMap = getStore().clientConfig.dictMap
|
||||
if (dictMap == null) {
|
||||
return ''
|
||||
}
|
||||
const codes = codeExpress.split('.')
|
||||
const dictCode = codes[0]
|
||||
const dataValue = codes[1]
|
||||
const dict = dictMap[dictCode]
|
||||
if (dict == null) {
|
||||
return codeExpress
|
||||
}
|
||||
// 如果不存在数据编码,则直接返回字典名称
|
||||
if (dataValue == null) {
|
||||
return dict.name
|
||||
}
|
||||
const data = dict.dataList.find(d => d.value === dataValue)
|
||||
if (data == null) {
|
||||
return codeExpress
|
||||
}
|
||||
return data.label
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图片路径
|
||||
*
|
||||
* @param fileKey 文件key
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getImageURL (fileKey) {
|
||||
if (fileKey.startsWith('http://') || fileKey.startsWith('https://')) {
|
||||
return fileKey
|
||||
}
|
||||
return `${import.meta.env.VITE_RESOURCE_PREFIX}/oss/image?f=${fileKey}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取附件路径
|
||||
*
|
||||
* @param fileKey 文件key
|
||||
* @param filename 文件名称
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getAttachURL (fileKey, filename) {
|
||||
if (fileKey.startsWith('http://') || fileKey.startsWith('https://')) {
|
||||
return fileKey
|
||||
}
|
||||
return `${import.meta.env.VITE_RESOURCE_PREFIX}/oss/attach?f=${fileKey}&fn=${filename}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 严格包装模板数据
|
||||
* - 返回代理对象,获取不到模板数据时将抛出错误
|
||||
*
|
||||
* @param templateData 模板数据
|
||||
* @param defaultValues 数据默认值
|
||||
* @return Proxy
|
||||
*/
|
||||
export function strictPackage (templateData, defaultValues = {}) {
|
||||
if (templateData == null) {
|
||||
return null
|
||||
}
|
||||
if (templateData instanceof Array) {
|
||||
return templateData
|
||||
}
|
||||
if (typeof templateData !== 'object') {
|
||||
return templateData
|
||||
}
|
||||
return new Proxy(templateData, {
|
||||
get (target, key) {
|
||||
if (target[key] === undefined) {
|
||||
if (defaultValues[key] != null) {
|
||||
return defaultValues[key]
|
||||
}
|
||||
throw new Error(`缺少 ${key} 数据配置`)
|
||||
}
|
||||
return target[key]
|
||||
}
|
||||
})
|
||||
}
|
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@ -0,0 +1,5 @@
|
||||
# 规范代码格式时的忽略文件
|
||||
.*
|
||||
*.json
|
||||
*.md
|
||||
node_modules/**
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 金镐开源组织
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
55
README.md
Normal file
55
README.md
Normal file
@ -0,0 +1,55 @@
|
||||
<div align="center">
|
||||
<img src="https://adjustrd-public.oss-cn-shenzhen.aliyuncs.com/eva-cms/logo.png" width="120px" style="width:80px;height:80px;" />
|
||||
<h1>伊娃CMS政企门户主题</h1>
|
||||
</div>
|
||||
|
||||
## 在线演示 & 技术文档
|
||||
|
||||
- 演示地址/政企门户主题:[http://gov.eva-cms.goldpankit.com/](http://gov.eva-cms.goldpankit.com/)
|
||||
- 演示地址/后台管理:[http://admin.eva-cms.goldpankit.com/](http://admin.eva-cms.goldpankit.com/)
|
||||
- 官方文档:[https://www.yuque.com/u21334242/eva-cms](https://www.yuque.com/u21334242/eva-cms)
|
||||
|
||||
|
||||
## 金镐开源组织生态项目
|
||||
|
||||
| 版本 | 说明 | 开源地址 | 构建地址 |
|
||||
|---------------------|-------------------|--------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| eva-cms | 伊娃CMS后端 | [https://gitee.com/goldpankit/eva-cms](https://gitee.com/goldpankit/eva-cms) | [http://goldpankit.com/space/Eva/eva-cms](http://goldpankit.com/space/Eva/eva-cms) |
|
||||
| eva-cms-admin-front | 伊娃CMS后台管理前端 | [https://gitee.com/goldpankit/eva-cms-admin-front](https://gitee.com/goldpankit/eva-cms-admin-front) | [http://goldpankit.com/space/Eva/eva-cms-admin-front](http://goldpankit.com/space/Eva/eva-cms-admin-front) |
|
||||
| eva-cms-website-gov | 伊娃CMS政企门户主题站点前端 | [https://gitee.com/goldpankit/eva-cms-website-gov](https://gitee.com/goldpankit/eva-cms-website-gov) | [http://goldpankit.com/space/Eva/eva-cms-website-gov](http://goldpankit.com/space/Eva/eva-cms-website-gov) |
|
||||
| eva-server | 伊娃权限系统单工程版本 | [https://gitee.com/goldpankit/eva-server](https://gitee.com/goldpankit/eva-server) | [http://goldpankit.com/space/Eva/eva-server](http://goldpankit.com/space/Eva/eva-server) |
|
||||
| eva-server-modules | 伊娃权限系统Maven多模块版本 | [https://gitee.com/goldpankit/eva-server-modules](https://gitee.com/goldpankit/eva-server-modules) | [http://www.goldpankit.com/space/Eva/eva-server-modules](http://www.goldpankit.com/space/Eva/eva-server-modules) |
|
||||
| eva-vue2 | 伊娃权限系统前端vue2版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue2/](https://gitee.com/goldpankit/eva-vue/tree/vue2/) | [http://goldpankit.com/space/Eva/eva-vue2](http://goldpankit.com/space/Eva/eva-vue2) |
|
||||
| eva-vue3-options | 伊娃权限系统前端vue3选项式版本 | [https://gitee.com/goldpankit/eva-vue/tree/vue3-options/](https://gitee.com/goldpankit/eva-vue/tree/vue3-options/) | [http://www.goldpankit.com/space/Eva/eva-vue3-options](http://www.goldpankit.com/space/Eva/eva-vue3-options) |
|
||||
|
||||
|
||||
## 项目特点
|
||||
|
||||
1. 可扩展的功能模块,默认情况下提供了文章管理、栏目管理、资源管理、模板管理等CMS系统的基础模块,以及用户管理、角色管理、菜单管理等权限系统基础模块,使用GoldPanKit可进一步进行源码级功能模块的扩展。
|
||||
2. 不用担心存在BUG,如果存在BUG,使用GoldPanKit可实现一键升级。
|
||||
3. 不用担心存在安全漏洞,如果存在安全漏洞,GoldPanKit会进行提醒并支持一键升级。
|
||||
4. 规范化代码 + 详细的代码注释。
|
||||
5. 基于Eva 4权限系统进行研发,安全稳定!
|
||||
6. 丰富的插件市场,可使用GoldPanKit进行单表、多表的页面生成。
|
||||
|
||||
## 绝对优势
|
||||
|
||||
结合GoldPanKit可实现代码直接生成到项目中,安装更多的功能模块,一键修复BUG等。
|
||||
|
||||
## 项目预览
|
||||
|
||||
**登录页**
|
||||

|
||||
|
||||
**文章管理**
|
||||

|
||||
|
||||
**栏目管理**
|
||||

|
||||
|
||||
**资源管理**
|
||||

|
||||

|
||||
|
||||
**模板管理**
|
||||

|
6
api/client.js
Normal file
6
api/client.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取客户端配置
|
||||
export function fetchConfig () {
|
||||
return request.get('/client/config')
|
||||
}
|
6
api/cms/article.js
Normal file
6
api/cms/article.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取文章分页数据
|
||||
export function fetchArticlePage (data) {
|
||||
return request.post('/article/profile/page', data)
|
||||
}
|
11
api/cms/category.js
Normal file
11
api/cms/category.js
Normal file
@ -0,0 +1,11 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取栏目树
|
||||
export function fetchCategoryTree () {
|
||||
return request.post('/category/tree')
|
||||
}
|
||||
|
||||
// 获取子栏目树
|
||||
export function fetchSubCategoryTree (parentCategoryUid) {
|
||||
return request.post(`/category/${parentCategoryUid}/tree`)
|
||||
}
|
6
api/cms/resource.js
Normal file
6
api/cms/resource.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取资源列表
|
||||
export function fetchResources (groupUid) {
|
||||
return request.post(`/resource/${groupUid}/list`)
|
||||
}
|
6
api/cms/search.js
Normal file
6
api/cms/search.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 站内搜索
|
||||
export function search (data) {
|
||||
return request.post('/search', data)
|
||||
}
|
6
api/cms/template.js
Normal file
6
api/cms/template.js
Normal file
@ -0,0 +1,6 @@
|
||||
import request from '@/utils/request.js'
|
||||
|
||||
// 获取模板数据
|
||||
export function fetchTemplateData (data) {
|
||||
return request.post('/template/data', data)
|
||||
}
|
5
app.vue
Normal file
5
app.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
84
assets/style/app.scss
Normal file
84
assets/style/app.scss
Normal file
@ -0,0 +1,84 @@
|
||||
@import "variables";
|
||||
html body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: url("/public/images/background.jpg") repeat;
|
||||
background-color: var(--page-background);
|
||||
font-size: var(--font-size-base);
|
||||
font-family: var(--font-family-base);
|
||||
min-width: var(--body-min-width);
|
||||
.content-wrap {
|
||||
max-width: var(--page-width);
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
&:link {
|
||||
color: var(--font-color);
|
||||
}
|
||||
}
|
||||
// 加载动画
|
||||
#nprogress {
|
||||
--loading-color: red;
|
||||
// 改变进度条的颜色
|
||||
.bar {
|
||||
background: var(--loading-color) !important;
|
||||
}
|
||||
// 改变进度条的阴影颜色
|
||||
.peg {
|
||||
box-shadow: 0 0 10px var(--loading-color), 0 0 5px var(--loading-color) !important; /* 这里设置阴影颜色 */
|
||||
}
|
||||
// 改变进度条的旋转动画颜色
|
||||
.spinner-icon {
|
||||
border-top-color: var(--loading-color) !important;
|
||||
border-left-color: var(--loading-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单
|
||||
.el-menu {
|
||||
--el-menu-bg-color: var(--primary-color-dark);
|
||||
--el-menu-text-color: var(--color-white);
|
||||
--el-menu-hover-bg-color: var(--primary-color-dark);
|
||||
--el-bg-color-overlay: var(--primary-color-dark);
|
||||
--el-menu-item-font-size: var(--font-size-large);
|
||||
--el-border-color-light: var(--primary-color-dark);
|
||||
}
|
||||
|
||||
// 页面标题
|
||||
.page-title {
|
||||
--font-size-title: 25px;
|
||||
color: var(--primary-color-dark);
|
||||
font-size: var(--font-size-title);
|
||||
margin: 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// 首页内容宽度
|
||||
@media (max-width: $--mobile-max-width) {
|
||||
html body {
|
||||
--page-width: 100%;
|
||||
--body-min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端
|
||||
@media (max-width: $--mobile-max-width) {
|
||||
html body {
|
||||
// 边距
|
||||
--gap: 15px;
|
||||
--gap-mini: 8px;
|
||||
--gap-midele: 20px;
|
||||
--gap-large: 25px;
|
||||
--gap-huge: 30px;
|
||||
}
|
||||
}
|
40
assets/style/theme.scss
Normal file
40
assets/style/theme.scss
Normal file
@ -0,0 +1,40 @@
|
||||
body {
|
||||
// 页面
|
||||
--page-width: 1280px;
|
||||
--page-background: #f7f7f7;
|
||||
// - body最小宽度,避免屏幕过窄时页面溢出
|
||||
--body-min-width: calc(var(--page-width) + 60px);
|
||||
// 主题色
|
||||
--primary-color: #224b9d;
|
||||
--primary-color-light: #285dc4;
|
||||
--primary-color-light-deep: #e5ebff;
|
||||
--primary-color-dark: #224da2;
|
||||
--primary-color-dark-deep: #16336b;
|
||||
// 字体
|
||||
--font-size-base: 16px;
|
||||
--font-size-small: 14px;
|
||||
--font-size-middle: 18px;
|
||||
--font-size-large: 20px;
|
||||
--font-family-base: "微软雅黑";
|
||||
--font-color: #333;
|
||||
// 背景色
|
||||
--background-color: #f7f7f7;
|
||||
// 颜色
|
||||
--color-white: #ffffff;
|
||||
--color-gray: #999;
|
||||
--color-gray-light: #ccc;
|
||||
--color-keyword: #ff0000;
|
||||
// 边框
|
||||
--border-color: #eee;
|
||||
// 子栏目树
|
||||
--sub-category-width: 275px;
|
||||
|
||||
// 覆盖element-plus的默认字体大小
|
||||
--el-font-size-base: var(--font-size-base);
|
||||
// 边距
|
||||
--gap: 20px;
|
||||
--gap-mini: 10px;
|
||||
--gap-midele: 30px;
|
||||
--gap-large: 40px;
|
||||
--gap-huge: 50px;
|
||||
}
|
11
assets/style/variables.scss
Normal file
11
assets/style/variables.scss
Normal file
@ -0,0 +1,11 @@
|
||||
// bootstrap默认断点
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 768px,
|
||||
lg: 992px,
|
||||
xl: 1200px,
|
||||
xxl: 1400px
|
||||
);
|
||||
// 移动端最大宽度,小于此宽度,视为手机访问
|
||||
$--mobile-max-width: map-get($grid-breakpoints, sm);
|
95
components/cms/ArticleList.vue
Normal file
95
components/cms/ArticleList.vue
Normal file
@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<ul v-if="articles.length > 0" class="article-list">
|
||||
<li v-for="article in articles" :key="article.uid">
|
||||
<nuxt-link :to="`/article/${article.uid}`" target="_blank">
|
||||
<span class="title" v-html="getTitle(article)"></span>
|
||||
<span v-if="article.updatedAt" class="date">{{ article.updatedAt }}</span>
|
||||
</nuxt-link>
|
||||
</li>
|
||||
</ul>
|
||||
<EmptyTip v-else/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyTip from '@/components/common/EmptyTip'
|
||||
|
||||
export default {
|
||||
name: 'ArticleList',
|
||||
components: { EmptyTip },
|
||||
props: {
|
||||
// 文章列表
|
||||
articles: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 关键字
|
||||
keyword: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取标题
|
||||
getTitle (article) {
|
||||
// 存在关键字时,为关键字添加em标签
|
||||
if (this.keyword != null && this.keyword.trim().length > 0) {
|
||||
return article.title.replace(new RegExp(this.keyword, 'g'), `<em>${this.keyword}</em>`)
|
||||
}
|
||||
return article.title
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul.article-list {
|
||||
padding: 10px 0 15px;
|
||||
li {
|
||||
border-bottom: 1px dashed var(--color-gray-light);
|
||||
&:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
li a {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px 10px 15px 25px;
|
||||
color: var(--font-color);
|
||||
text-decoration: none;
|
||||
gap: 20px;
|
||||
&:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
// 前方灰点
|
||||
&::before {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: var(--color-gray);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 10px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
// 标题
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// 关键字
|
||||
:deep(em) {
|
||||
font-style: normal;
|
||||
color: var(--color-keyword);
|
||||
}
|
||||
}
|
||||
// 日期
|
||||
.date {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-gray);
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
91
components/cms/ArticlePreview.vue
Normal file
91
components/cms/ArticlePreview.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="article-preview">
|
||||
<!-- 标题 -->
|
||||
<h2>{{ data.title }}</h2>
|
||||
<!-- 信息 -->
|
||||
<ul class="article-information">
|
||||
<li>
|
||||
<label>发布时间:</label>
|
||||
{{ data.updatedAt || data.createdAt }}
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 内容 -->
|
||||
<article v-html="data.content"></article>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
export default {
|
||||
name: 'ArticlePreview',
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/style/variables";
|
||||
.article-preview {
|
||||
--article-title: 30px;
|
||||
--article-content-font-size: 16px;
|
||||
--article-content-font-color: #555;
|
||||
// 标题
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: var(--primary-color);
|
||||
font-size: var(--article-title);
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
padding: 0 var(--gap);
|
||||
word-break: break-all;
|
||||
}
|
||||
// 文章信息
|
||||
.article-information {
|
||||
color: var(--color-gray);
|
||||
line-height: 36px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
padding: 0 var(--gap);
|
||||
}
|
||||
// 文章内容
|
||||
article {
|
||||
padding: 0 var(--gap-midele);
|
||||
overflow: hidden;
|
||||
font-size: var(--article-content-font-size);
|
||||
color: var(--article-content-font-color);
|
||||
line-height: 1.8;
|
||||
:deep(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $--mobile-max-width) {
|
||||
.article-preview {
|
||||
--article-title: 20px;
|
||||
// 标题
|
||||
h2 {
|
||||
font-size: var(--article-title);
|
||||
line-height: 25px;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
// 文章信息
|
||||
.article-information {
|
||||
line-height: 25px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
// 文章内容
|
||||
article {
|
||||
padding: 10px;
|
||||
font-size: var(--article-content-font-size);
|
||||
line-height: 1.5;
|
||||
:deep(iframe) {
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
81
components/cms/CategoryIcon.vue
Normal file
81
components/cms/CategoryIcon.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<!-- 网络图标 -->
|
||||
<img
|
||||
v-if="isNetworkIcon"
|
||||
class="category-icon image-icon"
|
||||
:src="value"
|
||||
alt="栏目图标"
|
||||
:style="{ width: sizeWidth }"
|
||||
/>
|
||||
<!-- class图标 -->
|
||||
<i
|
||||
v-else-if="isClassIcon"
|
||||
class="category-icon"
|
||||
:class="value"
|
||||
:style="{ 'font-size': size }"
|
||||
></i>
|
||||
<!-- 不正确的图标 -->
|
||||
<span class="category-icon holder" v-else-if="withHolder"><em>x</em></span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'CategoryIcon',
|
||||
props: {
|
||||
// 图标值
|
||||
value: {},
|
||||
// 尺寸
|
||||
size: {
|
||||
default: 'inherit'
|
||||
},
|
||||
// 如果图标不存在,是否显示占位符
|
||||
withHolder: {
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// size对应的width值
|
||||
sizeWidth () {
|
||||
if (this.size === 'inherit') {
|
||||
return '16px'
|
||||
}
|
||||
return this.size
|
||||
},
|
||||
// 判断是否为class图标
|
||||
isClassIcon () {
|
||||
if (this.value == null || this.value === '') {
|
||||
return false
|
||||
}
|
||||
return !this.value.startsWith('/') &&
|
||||
!this.value.startsWith('http://') && !this.value.startsWith('https://')
|
||||
},
|
||||
// 判断是否为网络图标
|
||||
isNetworkIcon () {
|
||||
if (this.value == null || this.value === '') {
|
||||
return false
|
||||
}
|
||||
return this.value.startsWith('/') ||
|
||||
this.value.startsWith('http://') || this.value.startsWith('https://')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.holder {
|
||||
width: 16px !important;
|
||||
height: 16px !important;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: red !important;
|
||||
background: #e0e0e0;
|
||||
em {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
82
components/cms/CategoryTree.vue
Normal file
82
components/cms/CategoryTree.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="category-tree">
|
||||
<el-tree
|
||||
:data="data"
|
||||
node-key="uid"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'title'
|
||||
}"
|
||||
:current-node-key="selected"
|
||||
:highlight-current="true"
|
||||
:default-expand-all="true"
|
||||
:expand-on-click-node="false"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<nuxt-link :to="data.uri">{{ data.title }}</nuxt-link>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CategoryTree',
|
||||
props: {
|
||||
// 栏目树结构
|
||||
data : {},
|
||||
// 选中的节点唯一标识
|
||||
selected: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.category-tree {
|
||||
height: 800px;
|
||||
background-color: var(--background-color);
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
:deep(.el-tree) {
|
||||
--el-tree-node-content-height: auto;
|
||||
background-color: var(--background-color);
|
||||
.el-tree-node__content {
|
||||
border-radius: 8px;
|
||||
a {
|
||||
height: 100%;
|
||||
min-height: 50px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
text-wrap: initial;
|
||||
}
|
||||
.el-tree-node__expand-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// 选中状态
|
||||
.is-current {
|
||||
& > .el-tree-node__content {
|
||||
background-color: var(--primary-color-light);
|
||||
color: var(--color-white);
|
||||
a {
|
||||
color: var(--color-white) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
a {
|
||||
color: var(--font-color) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
171
components/cms/SpecialColumn.vue
Normal file
171
components/cms/SpecialColumn.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div class="special-column">
|
||||
<div class="title-wrap">
|
||||
<label>专题专栏</label>
|
||||
<!-- 箭头 -->
|
||||
<span/>
|
||||
</div>
|
||||
<div class="swiper-wrap">
|
||||
<swiper
|
||||
class="swiper-container"
|
||||
ref="swiper"
|
||||
:speed="500"
|
||||
:slidesPerView="numberColumns"
|
||||
:loop="true"
|
||||
:autoplay="{
|
||||
delay: 1500,
|
||||
disableOnInteraction: false // 触摸后是否停止自动移动
|
||||
}"
|
||||
:modules="modules"
|
||||
@mouseenter="$refs.swiper.$el.swiper.autoplay.stop()"
|
||||
@mouseleave="$refs.swiper.$el.swiper.autoplay.start()"
|
||||
>
|
||||
<swiper-slide v-for="(item, index) in getIcons" :key="index">
|
||||
<nuxt-link target="_blank" :to="JSON.parse(item.value).link">
|
||||
<img
|
||||
:src="getImageURL(JSON.parse(item.value).image)"
|
||||
:alt="item.title"
|
||||
/>
|
||||
</nuxt-link>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import { Autoplay } from 'swiper/modules'
|
||||
import 'swiper/scss'
|
||||
import 'swiper/scss/free-mode'
|
||||
import { getImageURL } from '@/utils/util'
|
||||
|
||||
export default {
|
||||
name: 'SpecialColumn',
|
||||
components: { Swiper, SwiperSlide },
|
||||
props: {
|
||||
icons: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 获取图标
|
||||
getIcons () {
|
||||
if (
|
||||
this.icons.length < this.numberColumns + 1 ||
|
||||
this.icons.length > this.numberColumns + 3
|
||||
) {
|
||||
return this.icons
|
||||
}
|
||||
return [...this.icons, ...this.icons]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
numberColumns: 4,
|
||||
modules: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getImageURL
|
||||
},
|
||||
created () {
|
||||
if (this.$device.isMobile) {
|
||||
this.numberColumns = 2
|
||||
}
|
||||
this.modules = [Autoplay]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/style/variables";
|
||||
.special-column {
|
||||
--height: 100px;
|
||||
--img-border-radius: 20px;
|
||||
// 标题宽度
|
||||
--title-width: 34px
|
||||
}
|
||||
@media (max-width: $--mobile-max-width) {
|
||||
.special-column {
|
||||
--height: 50px;
|
||||
--img-border-radius: 10px;
|
||||
// 标题宽度
|
||||
--title-width: 40px
|
||||
}
|
||||
.title-wrap > label{
|
||||
overflow: hidden;
|
||||
font-size: 12px!important;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
.special-column {
|
||||
display: flex;
|
||||
// 标题
|
||||
.title-wrap {
|
||||
height: var(--height);
|
||||
width: var(--title-width);
|
||||
margin: auto 20px auto 0;
|
||||
padding: 0 var(--gap-mini);
|
||||
background: linear-gradient(90deg, var(--primary-color-light) 0%, var(--primary-color) 100%);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
// 箭头
|
||||
& > span {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
top: calc(50% - 10px);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom:10px solid transparent;
|
||||
border-top: 10px solid transparent;
|
||||
border-left: 12px solid var(--primary-color);
|
||||
}
|
||||
// 专题文字
|
||||
label {
|
||||
display: block;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
// 轮播列表
|
||||
.swiper-wrap {
|
||||
width: calc(100% - 80px);
|
||||
height: calc(50% - 10px);
|
||||
flex-grow: 1;
|
||||
// 轮播项
|
||||
.swiper-slide {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
&:first-of-type {
|
||||
padding-left: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
padding-right: 0;
|
||||
}
|
||||
& > a {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 90%;
|
||||
height: var(--height);
|
||||
border-radius: var(--img-border-radius);
|
||||
margin-left: var(--gap);
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
131
components/common/DataListTabs.vue
Normal file
131
components/common/DataListTabs.vue
Normal file
@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="data-list-tabs">
|
||||
<!-- 页签 -->
|
||||
<div class="tabs-header">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(tab, index) in data"
|
||||
:key="tab.label"
|
||||
:class="{ hover: activeIndex === index }"
|
||||
@mouseover="trigger === 'hover' ? changeTab(index) : null"
|
||||
@click="trigger === 'click' ? changeTab(index) : null"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</li>
|
||||
</ul>
|
||||
<nuxt-link
|
||||
v-if="withMore && currentTab.moreLink != null"
|
||||
:to="currentTab.moreLink"
|
||||
>
|
||||
更多<el-icon><ElIconDArrowRight /></el-icon>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<!-- 搜索表单 -->
|
||||
<slot name="search"></slot>
|
||||
<!-- 数据列表 -->
|
||||
<slot v-if="items.length > 0" :items="items" :tab="data[activeIndex]">
|
||||
<ArticleList :articles="items"/>
|
||||
</slot>
|
||||
<!-- 暂无数据 -->
|
||||
<EmptyTip v-else/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyTip from "~/components/common/EmptyTip.vue";
|
||||
import ArticleList from "~/components/cms/ArticleList.vue";
|
||||
|
||||
export default {
|
||||
name: 'DataListTabs',
|
||||
components: {ArticleList, EmptyTip},
|
||||
emits: ['changeTab'],
|
||||
props: {
|
||||
// 数据,[{ label: '', items: [ { title: '', updateTime: '' } ] }]
|
||||
data: {
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否‘更多’按钮
|
||||
withMore: {
|
||||
default: true
|
||||
},
|
||||
// 触发方式
|
||||
trigger: {
|
||||
default: 'hover'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前选中的tab
|
||||
currentTab () {
|
||||
return this.data[this.activeIndex]
|
||||
},
|
||||
// 获取展示列表
|
||||
items () {
|
||||
if (this.currentTab == null) {
|
||||
return
|
||||
}
|
||||
return this.currentTab.items
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 切换tab
|
||||
* @param index 坐标
|
||||
*/
|
||||
changeTab (index) {
|
||||
this.activeIndex = index
|
||||
this.$emit('changeTab', index)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 当前选中的tab索引
|
||||
activeIndex: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.data-list-tabs {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
overflow: hidden;
|
||||
// 页签头
|
||||
.tabs-header {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: var(--primary-color);
|
||||
ul {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding-right: 100px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
li {
|
||||
padding: 8px 15px;
|
||||
cursor: default;
|
||||
font-size: var(--font-size-middle);
|
||||
flex-shrink: 0;
|
||||
&.hover {
|
||||
font-weight: bold;
|
||||
border-bottom: 3px solid var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更多
|
||||
a {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: var(--font-size-small);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--primary-color) !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user