feat: 文档维护功能
This commit is contained in:
parent
e54bd8af41
commit
daeebcd1d1
40
docs/prod-data/服务中心.md
Normal file
40
docs/prod-data/服务中心.md
Normal file
@ -0,0 +1,40 @@
|
||||
| 序号 | 解决方案 | 合作伙伴 | 服务内容 |
|
||||
|------|----------|----------|----------|
|
||||
| 1 | 绿色企业认定 | 联合征信 | 提供企业绿色属性评估认证服务,核查企业碳排放表现,颁发绿色企业资质证书 |
|
||||
| 2 | 绿色项目认定 | 联合征信 | 对项目碳减排效果进行评估认证,核算项目产生的碳资产价值,出具绿色项目认定报告 |
|
||||
| 3 | 中小企业环境信息披露 | 联合征信 | 协助企业完成环境信息合规披露,编制ESG报告,满足监管要求的碳排放数据上报 |
|
||||
| 4 | 碳资产管理平台解决方案 | 零数科技 | 提供碳资产数字化管理服务,支持碳资产注册登记、交易撮合、结算清缴等全流程 |
|
||||
| 5 | 碳交易最优策略模拟平台解决方案 | 零数科技 | 基于AI算法模拟碳交易策略,辅助企业优化碳资产配置,降低履约成本 |
|
||||
| 6 | CCER 碳资产开发平台解决方案 | 零数科技 | 辅助开发核证自愿减排量(CCER)项目,追踪减排量签发流程,提供项目全周期管理 |
|
||||
| 7 | CBAM 辅助核算系统 | 欧冶云商 | 依据欧盟CBAM法规要求,辅助计算进口商品的隐含碳排放量,生成合规填报数据 |
|
||||
| 8 | 钢铁全产业链 EPD 平台 | 欧冶云商 | 提供钢铁产品环境产品声明(EPD)全流程服务,涵盖碳足迹计算、第三方审核及发布 |
|
||||
| 9 | OYLCA 工具 | 欧冶云商 | 提供生命周期碳足迹(LCA)评估工具,支持企业计算产品全生命周期的碳排放数据 |
|
||||
| 10 | 建筑节能降碳服务解决方案 | 时链科技 | 提供建筑能耗诊断、节能改造实施、碳减排量核算等一站式建筑降碳服务 |
|
||||
| 11 | 基于医院建筑运行特征智能化碳评价 | 上海建工四建 | 针对医院能耗特性进行数据分析,建立碳排放模型,输出智能化碳评价报告 |
|
||||
| 12 | 能碳智慧管家解决方案 | 上海电气 | 提供综合能源管理与碳排放监测平台,实时追踪企业碳足迹,智能优化用能策略 |
|
||||
| 13 | ISO 14064-1 温室气体核查认证解决方案 | TUV 北德 | 提供组织层面温室气体排放核查认证服务,出具国际认可的ISO 14064-1核查报告 |
|
||||
| 14 | ISO 14067 产品碳足迹核查认证解决方案 | TUV 北德 | 核查认证产品碳足迹数据,确保符合ISO 14067标准要求,出具产品碳标签认证 |
|
||||
| 15 | ISO 14068-1 碳中和核查认证解决方案 | TUV 北德 | 核查碳中和路径规划和抵消方案,认证组织或产品碳中和声明,出具权威核查证书 |
|
||||
| 16 | ISO 14064 盘查 & 核查服务流程 | 必维认证 | 提供温室气体排放量盘查及第三方核查服务,指导建立碳排放清单,完成核查认证 |
|
||||
| 17 | ISO 14067 产品碳足迹服务流程 | 必维认证 | 按照ISO 14067标准提供产品碳足迹核算服务,覆盖全生命周期碳排放量化与验证 |
|
||||
| 18 | ISO 14068 碳中和服务流程 | 必维认证 | 提供碳中和认证全流程服务,包括碳足迹核算、抵消方案评估及碳中和声明验证 |
|
||||
| 19 | PAS 2080 碳管理体系服务流程 | 必维认证 | 提供碳管理体系建设咨询服务,帮助企业建立符合PAS 2080标准的碳管理架构 |
|
||||
| 20 | CBAM 填报 & 核验服务流程 | 必维认证 | 提供欧盟碳边境调节机制合规服务,辅助完成CBAM数据填报、第三方核验及证书申请 |
|
||||
| 21 | HiQLCD 数据库 + HiQEditor | 易碳数科 | 提供碳排放因子数据库及编辑工具,支持企业建立产品碳足迹模型,自动生成报告 |
|
||||
| 22 | 积木 LCA 云 | 易碳数科 | 基于SaaS模式的生命周期评估云平台,提供模块化碳核算工具,支持多场景LCA分析 |
|
||||
| 23 | 积木碳云 | 易碳数科 | 提供企业碳管理云服务,涵盖碳排放监测、减排项目管理、碳资产对接等功能 |
|
||||
| 24 | 碳边境调节机制计算工具 CBAM TOOL | 易碳数科 | 依据欧盟CBAM法规提供在线碳排放计算工具,自动换算隐含碳排放量,生成合规报表 |
|
||||
| 25 | 零碳园区解决方案 | AMT 企源 | 提供零碳园区规划咨询、智慧能源系统建设、碳中和路径设计等全流程解决方案 |
|
||||
| 26 | 基于区块链技术的组织碳管理平台 | AMT 企源 | 利用区块链技术建立可信碳管理账本,实现组织碳排放数据的存证、溯源与共享 |
|
||||
| 27 | 可持续供应链溯源解决方案 | AMT 企源 | 基于区块链追踪供应链碳排放数据,确保上游原材料碳足迹透明可视 |
|
||||
| 28 | 基于区块链技术的能碳双控解决方案 | AMT 企源 | 结合区块链与能源管理系统,实现能耗与碳排放的协同管控,数据可信可追溯 |
|
||||
| 29 | 区块链驱动的全生命周期碳足迹溯源 | AMT 企源 | 通过区块链技术记录产品全生命周期碳数据,实现碳足迹的可信溯源与验证 |
|
||||
| 30 | 绿色产品生态设计平台 | AMT 企源 | 提供绿色产品生态设计工具,辅助企业进行低碳产品规划与生态化设计 |
|
||||
| 31 | ESG 综合服务平台 | AMT 企源 | 提供ESG评级提升、报告编制、信息披露等一站式ESG管理服务 |
|
||||
| 32 | CBAM 申报平台 | AMT 企源 | 提供CBAM数据采集、报表生成、在线申报等智能化申报服务 |
|
||||
| 33 | 可再生能源溯源解决方案(源侧) | 中国电气装备 | 提供可再生能源发电碳减排量核算与溯源服务,追踪绿色电力来源与消纳 |
|
||||
| 34 | 智能微电网自洽系统解决方案(网侧) | 中国电气装备 | 提供智能微电网能量管理解决方案,实现分布式能源的协调优化与碳排放控制 |
|
||||
| 35 | 零碳园区解决方案(荷侧) | 中国电气装备 | 提供园区负荷侧节能改造、智慧能源管理、碳排放监测等荷侧综合解决方案 |
|
||||
| 36 | 电化学储能解决方案(储侧) | 中国电气装备 | 提供储能系统建设与运维服务,通过移峰填谷优化碳排放结构 |
|
||||
| 37 | 碳数据库解决方案(装备侧) | 中国电气装备 | 提供能源装备碳排放数据库建设服务,支撑企业建立设备级碳排放计量体系 |
|
||||
| 38 | 虚拟电厂场景解决方案(调控侧) | 中国电气装备 | 提供虚拟电厂运营管理平台,聚合分布式能源参与碳减排交易,优化调控策略 |
|
||||
1121
docs/superpowers/plans/2026-04-28-平台文档管理功能实现计划.md
Normal file
1121
docs/superpowers/plans/2026-04-28-平台文档管理功能实现计划.md
Normal file
File diff suppressed because it is too large
Load Diff
253
docs/superpowers/specs/2026-04-28-平台文档管理功能设计.md
Normal file
253
docs/superpowers/specs/2026-04-28-平台文档管理功能设计.md
Normal file
@ -0,0 +1,253 @@
|
||||
# 平台文档管理功能设计方案
|
||||
|
||||
## 1. 需求概述
|
||||
|
||||
### 1.1 功能目标
|
||||
- 运营管理人员通过 `txw-yygl-web` 管理平台文档(增删改查)
|
||||
- 门户网站 `txw-mhzc-web` 通过 API 获取文档列表和内容,前端渲染 Markdown
|
||||
- 支持 Markdown 富文本编辑
|
||||
- 文档按分类管理,支持通过 URL 直接跳转至对应文档
|
||||
|
||||
### 1.2 关键需求点
|
||||
- 运营管理端:文档 CRUD + 分类管理
|
||||
- 门户前端:文档列表 + 文档详情页(支持 URL 直接访问)
|
||||
- 数据存储:`txw-mhzc` MySQL 数据库
|
||||
|
||||
---
|
||||
|
||||
## 2. 系统架构
|
||||
|
||||
### 2.1 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 运营管理端 │
|
||||
│ txw-yygl-web ←→ txw-yygl-service-biz ←→ txw-mhzc MySQL │
|
||||
│ (内部调用) (新建 document 库) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 门户前端 │
|
||||
│ txw-mhzc-web ←→ txw-gateway(聚合层) ←→ 同一 API │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 技术选型
|
||||
- 后端框架:Spring Boot(复用现有 `txw-yygl-service-biz`)
|
||||
- 前端框架:Vue 2 + TDesign(复用现有技术栈)
|
||||
- Markdown 编辑器:`mavon-editor`(轻量、Vue 2 兼容)
|
||||
- Markdown 渲染:`marked` + `highlight.js`
|
||||
- 数据库:MySQL(`txw-mhzc` 库)
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据库设计
|
||||
|
||||
### 3.1 文档分类表(document_category)
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | bigint | PK, AUTO_INCREMENT | 主键 |
|
||||
| name | varchar(100) | NOT NULL | 分类名称 |
|
||||
| sort | int | DEFAULT 0 | 排序号,越小越靠前 |
|
||||
| status | tinyint | DEFAULT 1 | 状态:0-禁用,1-启用 |
|
||||
| create_time | datetime | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
### 3.2 文档表(document)
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | bigint | PK, AUTO_INCREMENT | 主键 |
|
||||
| category_id | bigint | NOT NULL, FK | 所属分类ID |
|
||||
| title | varchar(200) | NOT NULL | 文档标题 |
|
||||
| content | text | NOT NULL | Markdown 正文内容 |
|
||||
| status | tinyint | DEFAULT 0 | 状态:0-草稿,1-已发布 |
|
||||
| sort | int | DEFAULT 0 | 排序号,越小越靠前 |
|
||||
| create_time | datetime | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
---
|
||||
|
||||
## 4. API 设计
|
||||
|
||||
### 4.1 文档分类接口
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 分类列表 | GET | /document/category/list | 获取所有启用的分类 |
|
||||
| 新增分类 | POST | /document/category | 新增文档分类 |
|
||||
| 编辑分类 | PUT | /document/category/{id} | 编辑分类信息 |
|
||||
| 删除分类 | DELETE | /document/category/{id} | 删除分类(需检查无关联文档)|
|
||||
|
||||
### 4.2 文档接口
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 文档列表 | GET | /document/list | 获取文档列表(支持分类筛选、状态筛选)|
|
||||
| 文档详情 | GET | /document/{id} | 获取文档详情(Markdown 内容)|
|
||||
| 新增文档 | POST | /document | 新增文档 |
|
||||
| 编辑文档 | PUT | /document/{id} | 编辑文档 |
|
||||
| 删除文档 | DELETE | /document/{id} | 删除文档 |
|
||||
|
||||
### 4.3 响应数据结构
|
||||
|
||||
**文档列表项(不含正文)**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"categoryName": "使用指南",
|
||||
"title": "如何注册账号",
|
||||
"status": 1,
|
||||
"sort": 1,
|
||||
"createTime": "2026-04-28 10:00:00",
|
||||
"updateTime": "2026-04-28 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
**文档详情(含正文)**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"categoryId": 1,
|
||||
"categoryName": "使用指南",
|
||||
"title": "如何注册账号",
|
||||
"content": "# 注册流程\n\n1. 点击注册按钮\n2. 填写企业信息\n...",
|
||||
"status": 1,
|
||||
"sort": 1,
|
||||
"createTime": "2026-04-28 10:00:00",
|
||||
"updateTime": "2026-04-28 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 前端页面设计
|
||||
|
||||
### 5.1 运营管理端(txw-yygl-web)
|
||||
|
||||
**路由:`/document/*`**
|
||||
|
||||
| 页面 | 路由 | 功能 |
|
||||
|------|------|------|
|
||||
| 文档列表 | /document/list | 分类筛选、状态筛选、搜索、新建按钮 |
|
||||
| 新增/编辑文档 | /document/edit/:id? | Markdown 编辑器、表单提交 |
|
||||
| 分类管理 | /document/category | 分类列表、增删改 |
|
||||
|
||||
**组件说明**
|
||||
- `DocumentList.vue` - 文档列表页
|
||||
- `DocumentEdit.vue` - 文档编辑页(含 mavon-editor)
|
||||
- `CategoryManage.vue` - 分类管理页
|
||||
|
||||
### 5.2 门户前端(txw-mhzc-web)
|
||||
|
||||
**路由:`/help/*` 或 `/document/*`**
|
||||
|
||||
| 页面 | 路由 | 功能 |
|
||||
|------|------|------|
|
||||
| 文档中心首页 | /help | 分类展示 + 文档列表 |
|
||||
| 文档详情页 | /help/:id | Markdown 渲染展示 |
|
||||
|
||||
**组件说明**
|
||||
- `DocumentCenter.vue` - 文档中心首页
|
||||
- `DocumentDetail.vue` - 文档详情页(含 marked 渲染)
|
||||
|
||||
---
|
||||
|
||||
## 6. 核心功能流程
|
||||
|
||||
### 6.1 文档创建/编辑流程
|
||||
```
|
||||
运营用户 → 文档列表页 → 新建/编辑 → Markdown编辑器填写内容 → 保存 → 更新数据库
|
||||
```
|
||||
|
||||
### 6.2 文档查看流程
|
||||
```
|
||||
普通用户 → 文档中心首页 → 选择分类 → 查看文档列表 → 点击文档 → URL变为 /help/:id → 渲染Markdown正文
|
||||
```
|
||||
|
||||
### 6.3 URL 直接访问流程
|
||||
```
|
||||
用户访问 /help/123 → 前端路由解析id → 调用API获取文档详情 → 渲染Markdown正文
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 技术实现要点
|
||||
|
||||
### 7.1 后端实现
|
||||
- 在 `txw-yygl-service-biz` 中新建 `DocumentController`、`DocumentService`、`DocumentMapper`
|
||||
- 新建 `DocumentCategoryController`、`DocumentCategoryService`、`DocumentCategoryMapper`
|
||||
- 使用 MyBatis-Plus 简化 CRUD 操作
|
||||
- 事务管理:新建/编辑文档在同一事务中执行
|
||||
|
||||
### 7.2 前端 Markdown 编辑器
|
||||
- 编辑端:使用 `mavon-editor`(支持预览切换、语法高亮)
|
||||
- 渲染端:使用 `marked` + `highlight.js`
|
||||
|
||||
### 7.3 路由配置
|
||||
- yygl-web:新增文档管理路由
|
||||
- mhzc-web:新增文档中心路由,支持 `/help/:id` 格式
|
||||
|
||||
---
|
||||
|
||||
## 8. 目录结构
|
||||
|
||||
### 8.1 后端(txw-yygl-service-biz)
|
||||
|
||||
```
|
||||
src/main/java/com/css/txw/yygl/
|
||||
├── controller/
|
||||
│ ├── DocumentController.java
|
||||
│ └── DocumentCategoryController.java
|
||||
├── service/
|
||||
│ ├── DocumentService.java
|
||||
│ ├── DocumentServiceImpl.java
|
||||
│ ├── DocumentCategoryService.java
|
||||
│ └── DocumentCategoryServiceImpl.java
|
||||
├── mapper/
|
||||
│ ├── DocumentMapper.java
|
||||
│ └── DocumentCategoryMapper.java
|
||||
├── entity/
|
||||
│ ├── Document.java
|
||||
│ └── DocumentCategory.java
|
||||
└── vo/
|
||||
├── DocumentListVO.java
|
||||
└── DocumentDetailVO.java
|
||||
```
|
||||
|
||||
### 8.2 前端(txw-yygl-web)
|
||||
|
||||
```
|
||||
src/pages/document/
|
||||
├── list/
|
||||
│ └── index.vue # 文档列表页
|
||||
├── edit/
|
||||
│ └── index.vue # 新增/编辑页
|
||||
└── category/
|
||||
└── index.vue # 分类管理页
|
||||
```
|
||||
|
||||
### 8.3 前端(txw-mhzc-web)
|
||||
|
||||
```
|
||||
src/pages/help/
|
||||
├── index.vue # 文档中心首页
|
||||
└── detail/
|
||||
└── index.vue # 文档详情页
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 测试要点
|
||||
|
||||
### 9.1 后端测试
|
||||
- 分类 CRUD:增删改查、状态切换
|
||||
- 文档 CRUD:增删改查、分类关联、状态管理
|
||||
- 异常场景:删除有关联文档的分类、查询不存在的文档
|
||||
|
||||
### 9.2 前端测试
|
||||
- Markdown 编辑器:编辑、预览切换
|
||||
- 文档列表:分类筛选、状态筛选、分页
|
||||
- 文档详情:Markdown 渲染、URL 直接访问
|
||||
@ -9,8 +9,15 @@ const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const ROOT = __dirname;
|
||||
const WEBS = ['txw-gxzx-web', 'txw-kxtfwzx-web', 'txw-mhzc-web', 'txw-tzzx-web', 'txw-ytzx-web', 'txw-yygl-web'];
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const WEBS = [
|
||||
// 'txw-gxzx-web',
|
||||
'txw-kxtfwzx-web',
|
||||
'txw-mhzc-web',
|
||||
'txw-tzzx-web',
|
||||
'txw-ytzx-web',
|
||||
'txw-yygl-web'
|
||||
];
|
||||
const LOCAL_PKG = 'local-nodemodules/@cssyq/ggzc-web';
|
||||
|
||||
function run(cmd, opts = {}) {
|
||||
|
||||
35825
txw-mhzc-web/package-lock.json
generated
35825
txw-mhzc-web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,9 @@
|
||||
"css-split-webpack-plugin": "0.2.6",
|
||||
"dayjs": "^1.10.4",
|
||||
"echarts": "^5.5.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^4.3.0",
|
||||
"qrcodejs2": "0.0.3",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"tdesign-icons-vue": "0.0.8",
|
||||
|
||||
25
txw-mhzc-web/src/pages/index/api/help/index.js
Normal file
25
txw-mhzc-web/src/pages/index/api/help/index.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { fetchSso } from '@/core/request';
|
||||
|
||||
const basurl = '/mhzc';
|
||||
|
||||
export default {
|
||||
getCategoryList() {
|
||||
return fetchSso({
|
||||
url: `${basurl}/document/category/list`,
|
||||
method: 'get',
|
||||
});
|
||||
},
|
||||
getDocumentList(params) {
|
||||
return fetchSso({
|
||||
url: `${basurl}/document/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
},
|
||||
getDocumentDetail(id) {
|
||||
return fetchSso({
|
||||
url: `${basurl}/document/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
},
|
||||
};
|
||||
@ -106,6 +106,11 @@ function zhanghugl() {
|
||||
return import(/* webpackChunkName: "zhanghugl" */ '@/pages/index/views/yhzx/zhanghugl/index.vue');
|
||||
}
|
||||
|
||||
// 帮助中心
|
||||
function help() {
|
||||
return import(/* webpackChunkName: "help" */ '@/pages/index/views/help/index.vue');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -306,4 +311,29 @@ export default [
|
||||
disableBack: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'help',
|
||||
path: '/help',
|
||||
component: help,
|
||||
meta: {
|
||||
title: '帮助中心',
|
||||
isShowSideBar: false,
|
||||
hasHome: true,
|
||||
breadCrumbs: [{ title: '帮助中心', to: '/help' }],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'helpIndex',
|
||||
path: '',
|
||||
component: () => import(/* webpackChunkName: "help" */ '@/pages/index/views/help/index.vue'),
|
||||
meta: { title: '帮助中心' }
|
||||
},
|
||||
{
|
||||
name: 'helpDetail',
|
||||
path: ':id',
|
||||
component: () => import(/* webpackChunkName: "help" */ '@/pages/index/views/help/detail/index.vue'),
|
||||
meta: { title: '帮助详情' }
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
55
txw-mhzc-web/src/pages/index/views/help/detail/index.vue
Normal file
55
txw-mhzc-web/src/pages/index/views/help/detail/index.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="document-detail">
|
||||
<div class="back-btn" @click="goBack">返回</div>
|
||||
<h1 class="doc-title">{{ document.title }}</h1>
|
||||
<div class="doc-content" v-html="renderedContent"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import marked from 'marked'
|
||||
import hljs from 'highlight.js'
|
||||
import 'highlight.js/styles/github.css'
|
||||
import api from '@/pages/index/api/help'
|
||||
|
||||
export default {
|
||||
name: 'DocumentDetail',
|
||||
data() {
|
||||
return {
|
||||
document: { id: null, title: '', content: '' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
renderedContent() {
|
||||
marked.setOptions({ highlight: (code, lang) => hljs.highlight(code, { language: lang }).value })
|
||||
return marked(this.document.content || '')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const id = this.$route.params.id
|
||||
if (id) {
|
||||
this.loadDocument(id)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadDocument(id) {
|
||||
const res = await api.getDocumentDetail(id)
|
||||
this.document = res.data
|
||||
},
|
||||
goBack() {
|
||||
this.$router.back()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.document-detail { padding: 20px; max-width: 800px; margin: 0 auto; }
|
||||
.back-btn { cursor: pointer; color: #0052d9; margin-bottom: 20px; }
|
||||
.doc-title { font-size: 24px; margin-bottom: 20px; }
|
||||
.doc-content { line-height: 1.8; }
|
||||
.doc-content :deep(h1) { font-size: 20px; margin: 20px 0 10px; }
|
||||
.doc-content :deep(h2) { font-size: 18px; margin: 16px 0 8px; }
|
||||
.doc-content :deep(pre) { background: #f5f5f5; padding: 12px; border-radius: 4px; overflow-x: auto; }
|
||||
.doc-content :deep(code) { font-family: monospace; }
|
||||
</style>
|
||||
76
txw-mhzc-web/src/pages/index/views/help/index.vue
Normal file
76
txw-mhzc-web/src/pages/index/views/help/index.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div class="help-center">
|
||||
<div class="category-list">
|
||||
<div
|
||||
v-for="cat in categoryList"
|
||||
:key="cat.id"
|
||||
:class="['category-item', { active: selectedCategoryId === cat.id }]"
|
||||
@click="selectCategory(cat.id)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="document-list">
|
||||
<div
|
||||
v-for="doc in documentList"
|
||||
:key="doc.id"
|
||||
class="document-item"
|
||||
@click="goToDetail(doc.id)"
|
||||
>
|
||||
<span class="doc-title">{{ doc.title }}</span>
|
||||
<span class="doc-date">{{ doc.createTime }}</span>
|
||||
</div>
|
||||
<div v-if="documentList.length === 0" class="empty">暂无文档</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/pages/index/api/help';
|
||||
|
||||
export default {
|
||||
name: 'HelpCenter',
|
||||
data() {
|
||||
return {
|
||||
categoryList: [],
|
||||
selectedCategoryId: null,
|
||||
documentList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCategoryList()
|
||||
this.loadDocumentList()
|
||||
},
|
||||
methods: {
|
||||
async loadCategoryList() {
|
||||
const res = await api.getCategoryList()
|
||||
this.categoryList = res.data
|
||||
},
|
||||
async loadDocumentList() {
|
||||
const res = await api.getDocumentList({ status: 1 })
|
||||
this.documentList = res.data
|
||||
},
|
||||
async selectCategory(categoryId) {
|
||||
this.selectedCategoryId = categoryId
|
||||
const res = await api.getDocumentList({ categoryId, status: 1 })
|
||||
this.documentList = res.data
|
||||
},
|
||||
goToDetail(id) {
|
||||
this.$router.push(`/help/${id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.help-center { padding: 20px; }
|
||||
.category-list { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
|
||||
.category-item { padding: 8px 16px; cursor: pointer; border-radius: 4px; background: #f5f5f5; }
|
||||
.category-item.active { background: #0052d9; color: #fff; }
|
||||
.document-list { display: flex; flex-direction: column; gap: 10px; }
|
||||
.document-item { padding: 12px; border: 1px solid #e5e5e5; border-radius: 4px; cursor: pointer; display: flex; justify-content: space-between; }
|
||||
.document-item:hover { background: #f5f5f5; }
|
||||
.doc-title { font-size: 14px; }
|
||||
.doc-date { font-size: 12px; color: #999; }
|
||||
.empty { text-align: center; padding: 40px; color: #999; }
|
||||
</style>
|
||||
@ -286,26 +286,26 @@ module.exports = {
|
||||
// 会误伤 SPA 路由 /view/mhzc/...,刷新时整页请求被转发到后端导致 Proxy error。必须用 ^ 限定为路径前缀。
|
||||
proxy: {
|
||||
'^/sso': {
|
||||
// target: 'http://localhost:9301',
|
||||
target: 'http://carbon.liantu.tech',
|
||||
target: 'http://localhost:9301',
|
||||
// target: 'http://carbon.liantu.tech',
|
||||
// target: 'http://10.23.20.13:94/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/mhzc': {
|
||||
// target: 'http://localhost:9302',
|
||||
target: 'http://carbon.liantu.tech',
|
||||
target: 'http://localhost:9302',
|
||||
// target: 'http://carbon.liantu.tech',
|
||||
// target: 'http://10.23.20.13:94/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/gxzx': {
|
||||
// target: 'http://localhost:9303',
|
||||
target: 'http://carbon.liantu.tech',
|
||||
target: 'http://localhost:9303',
|
||||
// target: 'http://carbon.liantu.tech',
|
||||
// target: 'http://10.23.20.13:94/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/yygl': {
|
||||
// target: 'http://localhost:20010',
|
||||
target: 'http://carbon.liantu.tech',
|
||||
target: 'http://localhost:20010',
|
||||
// target: 'http://carbon.liantu.tech',
|
||||
// target: 'http://10.23.20.13:94/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
|
||||
22900
txw-mhzc-web/yarn.lock
22900
txw-mhzc-web/yarn.lock
File diff suppressed because it is too large
Load Diff
22112
txw-yygl-web/package-lock.json
generated
22112
txw-yygl-web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@
|
||||
"dayjs": "^1.10.4",
|
||||
"echarts": "^5.5.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mavon-editor": "^2.10.0",
|
||||
"qrcodejs2": "0.0.3",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"tdesign-icons-vue": "0.0.8",
|
||||
|
||||
@ -43,17 +43,14 @@ request.interceptors.request.use(
|
||||
if (newConf.loading) {
|
||||
SingleLoading.startLoading();
|
||||
}
|
||||
// 设置随机数, 定位后端日志和解决浏览器缓存
|
||||
const { url } = newConf;
|
||||
if (url.indexOf('?') !== -1) {
|
||||
newConf.url = `${url}&t=${new Date().getTime()}`; // 请求添加时间戳
|
||||
} else {
|
||||
newConf.url = `${url}?t=${new Date().getTime()}`;
|
||||
}
|
||||
|
||||
// get请求映射params参数
|
||||
if (newConf.method === 'get' && newConf.params) {
|
||||
let url = `${newConf.url}?`;
|
||||
// 先加时间戳(如果 URL 还没参数)
|
||||
if (url.indexOf('?') === -1) {
|
||||
newConf.url = `${newConf.url}?t=${new Date().getTime()}&`;
|
||||
}
|
||||
// 再追加 params
|
||||
let paramsUrl = `${newConf.url}`;
|
||||
for (const propName of Object.keys(newConf.params)) {
|
||||
const value = newConf.params[propName];
|
||||
const part = `${encodeURIComponent(propName)}=`;
|
||||
@ -62,16 +59,23 @@ request.interceptors.request.use(
|
||||
for (const key of Object.keys(value)) {
|
||||
const params = `${propName}[${key}]`;
|
||||
const subPart = `${encodeURIComponent(params)}=`;
|
||||
url += `${subPart + encodeURIComponent(value[key])}&`;
|
||||
paramsUrl += `${subPart + encodeURIComponent(value[key])}&`;
|
||||
}
|
||||
} else {
|
||||
url += `${part + encodeURIComponent(value)}&`;
|
||||
paramsUrl += `${part + encodeURIComponent(value)}&`;
|
||||
}
|
||||
}
|
||||
}
|
||||
url = url.slice(0, -1);
|
||||
paramsUrl = paramsUrl.slice(0, -1);
|
||||
newConf.params = {};
|
||||
newConf.url = url;
|
||||
newConf.url = paramsUrl;
|
||||
} else {
|
||||
// 无 params 时,直接加时间戳
|
||||
if (url.indexOf('?') !== -1) {
|
||||
newConf.url = `${url}&t=${new Date().getTime()}`;
|
||||
} else {
|
||||
newConf.url = `${url}?t=${new Date().getTime()}`;
|
||||
}
|
||||
}
|
||||
return newConf;
|
||||
},
|
||||
|
||||
84
txw-yygl-web/src/pages/index/api/document/index.js
Normal file
84
txw-yygl-web/src/pages/index/api/document/index.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { fetchSso } from '@/core/request';
|
||||
|
||||
const headers = { 'token-Type': 'ADMIN' };
|
||||
const servicePrefix = 'yygl';
|
||||
|
||||
export default {
|
||||
// 分类列表
|
||||
getCategoryList() {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/category/list`,
|
||||
method: 'get',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 新增分类
|
||||
addCategory(data) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/category`,
|
||||
data: JSON.stringify(data),
|
||||
method: 'post',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 编辑分类
|
||||
updateCategory(id, data) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/category/${id}`,
|
||||
data: JSON.stringify(data),
|
||||
method: 'put',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 删除分类
|
||||
deleteCategory(id) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/category/${id}`,
|
||||
method: 'delete',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 文档列表
|
||||
getDocumentList(params) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 文档详情
|
||||
getDocumentDetail(id) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/${id}`,
|
||||
method: 'get',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 新增文档
|
||||
addDocument(data) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document`,
|
||||
data: JSON.stringify(data),
|
||||
method: 'post',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 编辑文档
|
||||
updateDocument(id, data) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/${id}`,
|
||||
data: JSON.stringify(data),
|
||||
method: 'put',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
// 删除文档
|
||||
deleteDocument(id) {
|
||||
return fetchSso({
|
||||
url: `${servicePrefix}/document/${id}`,
|
||||
method: 'delete',
|
||||
headers,
|
||||
});
|
||||
},
|
||||
};
|
||||
@ -7,6 +7,9 @@ function login() {
|
||||
function yhzx() {
|
||||
return import(/* webpackChunkName: "sbfdemo" */ '@/pages/index/views/glxtSy/glxtSy.vue');
|
||||
}
|
||||
function document() {
|
||||
return import(/* webpackChunkName: "document" */ '@/pages/index/views/document/index.vue');
|
||||
}
|
||||
export default [
|
||||
{
|
||||
name: 'login',
|
||||
@ -44,4 +47,41 @@ export default [
|
||||
disableBack: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'document',
|
||||
path: '/document',
|
||||
component: document,
|
||||
meta: {
|
||||
title: '文档管理',
|
||||
isShowSideBar: true,
|
||||
hasHome: true,
|
||||
breadCrumbs: [{ title: '文档管理', to: '/document' }],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'documentOverview',
|
||||
path: '',
|
||||
component: () => import(/* webpackChunkName: "document" */ '@/pages/index/views/document/overview/index.vue'),
|
||||
meta: { title: '文档概览' }
|
||||
},
|
||||
{
|
||||
name: 'documentList',
|
||||
path: 'list',
|
||||
component: () => import(/* webpackChunkName: "document" */ '@/pages/index/views/document/list/index.vue'),
|
||||
meta: { title: '文档列表' }
|
||||
},
|
||||
{
|
||||
name: 'documentEdit',
|
||||
path: 'edit/:id?',
|
||||
component: () => import(/* webpackChunkName: "document" */ '@/pages/index/views/document/edit/index.vue'),
|
||||
meta: { title: '文档编辑' }
|
||||
},
|
||||
{
|
||||
name: 'categoryManage',
|
||||
path: 'category',
|
||||
component: () => import(/* webpackChunkName: "document" */ '@/pages/index/views/document/category/index.vue'),
|
||||
meta: { title: '分类管理' }
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="category-manage-container">
|
||||
<div class="toolbar">
|
||||
<t-button theme="primary" @click="showAddDialog">新建分类</t-button>
|
||||
</div>
|
||||
<t-table :data="categoryList" :columns="columns" row-key="id">
|
||||
<template #operations="{ row }">
|
||||
<t-button size="small" @click="showEditDialog(row)">编辑</t-button>
|
||||
<t-button size="small" theme="danger" @click="deleteCategory(row.id)">删除</t-button>
|
||||
</template>
|
||||
</t-table>
|
||||
|
||||
<t-dialog :visible="dialogVisible" @close="dialogVisible = false" :header="isEdit ? '编辑分类' : '新建分类'">
|
||||
<t-form :model="category" label-width="80px">
|
||||
<t-form-item label="分类名称">
|
||||
<t-input v-model="category.name" />
|
||||
</t-form-item>
|
||||
<t-form-item label="排序号">
|
||||
<t-input-number v-model="category.sort" :min="0" />
|
||||
</t-form-item>
|
||||
<t-form-item label="状态">
|
||||
<t-radio-group v-model="category.status">
|
||||
<t-radio :value="0">禁用</t-radio>
|
||||
<t-radio :value="1">启用</t-radio>
|
||||
</t-radio-group>
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
<template #footer>
|
||||
<t-button @click="dialogVisible = false">取消</t-button>
|
||||
<t-button theme="primary" @click="saveCategory">确定</t-button>
|
||||
</template>
|
||||
</t-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/pages/index/api/document';
|
||||
|
||||
export default {
|
||||
name: 'CategoryManage',
|
||||
data() {
|
||||
return {
|
||||
categoryList: [],
|
||||
dialogVisible: false,
|
||||
isEdit: false,
|
||||
category: { id: null, name: '', sort: 0, status: 1 },
|
||||
columns: [
|
||||
{ colKey: 'id', title: 'ID' },
|
||||
{ colKey: 'name', title: '分类名称' },
|
||||
{ colKey: 'sort', title: '排序号' },
|
||||
{ colKey: 'status', title: '状态', formatter: (v) => v === 1 ? '启用' : '禁用' },
|
||||
{ colKey: 'operation', title: '操作', cell: 'operations' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCategoryList()
|
||||
},
|
||||
methods: {
|
||||
async loadCategoryList() {
|
||||
const res = await api.getCategoryList()
|
||||
this.categoryList = res.data
|
||||
},
|
||||
showAddDialog() {
|
||||
this.isEdit = false
|
||||
this.category = { id: null, name: '', sort: 0, status: 1 }
|
||||
this.dialogVisible = true
|
||||
},
|
||||
showEditDialog(row) {
|
||||
this.isEdit = true
|
||||
this.category = { ...row }
|
||||
this.dialogVisible = true
|
||||
},
|
||||
async saveCategory() {
|
||||
if (this.isEdit) {
|
||||
await api.updateCategory(this.category.id, this.category)
|
||||
} else {
|
||||
await api.addCategory(this.category)
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.loadCategoryList()
|
||||
},
|
||||
async deleteCategory(id) {
|
||||
await api.deleteCategory(id)
|
||||
this.$message.success('删除成功')
|
||||
this.loadCategoryList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.category-manage-container { padding: 20px; }
|
||||
.toolbar { margin-bottom: 20px; }
|
||||
</style>
|
||||
86
txw-yygl-web/src/pages/index/views/document/edit/index.vue
Normal file
86
txw-yygl-web/src/pages/index/views/document/edit/index.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="document-edit-container">
|
||||
<t-form :model="document" label-width="100px">
|
||||
<t-form-item label="所属分类">
|
||||
<t-select v-model="document.categoryId" :options="categoryOptions" placeholder="请选择分类" />
|
||||
</t-form-item>
|
||||
<t-form-item label="文档标题">
|
||||
<t-input v-model="document.title" placeholder="请输入文档标题" />
|
||||
</t-form-item>
|
||||
<t-form-item label="排序号">
|
||||
<t-input-number v-model="document.sort" :min="0" />
|
||||
</t-form-item>
|
||||
<t-form-item label="状态">
|
||||
<t-radio-group v-model="document.status">
|
||||
<t-radio :value="0">草稿</t-radio>
|
||||
<t-radio :value="1">已发布</t-radio>
|
||||
</t-radio-group>
|
||||
</t-form-item>
|
||||
<t-form-item label="文档内容">
|
||||
<mavon-editor v-model="document.content" />
|
||||
</t-form-item>
|
||||
<t-form-item>
|
||||
<t-button theme="primary" @click="saveDocument">保存</t-button>
|
||||
<t-button @click="goBack">取消</t-button>
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mavonEditor } from 'mavon-editor'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import api from '@/pages/index/api/document'
|
||||
|
||||
export default {
|
||||
name: 'DocumentEdit',
|
||||
components: { mavonEditor },
|
||||
data() {
|
||||
return {
|
||||
document: {
|
||||
id: null,
|
||||
categoryId: null,
|
||||
title: '',
|
||||
content: '',
|
||||
status: 0,
|
||||
sort: 0
|
||||
},
|
||||
categoryOptions: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCategoryList()
|
||||
const id = this.$route.params.id
|
||||
if (id) {
|
||||
this.loadDocument(id)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadCategoryList() {
|
||||
const res = await api.getCategoryList()
|
||||
this.categoryOptions = res.data.map(c => ({ label: c.name, value: c.id }))
|
||||
},
|
||||
async loadDocument(id) {
|
||||
const res = await api.getDocumentDetail(id)
|
||||
this.document = res.data
|
||||
},
|
||||
async saveDocument() {
|
||||
const id = this.document.id
|
||||
if (id) {
|
||||
await api.updateDocument(id, this.document)
|
||||
} else {
|
||||
await api.addDocument(this.document)
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.goBack()
|
||||
},
|
||||
goBack() {
|
||||
this.$router.back()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.document-edit-container { padding: 20px; }
|
||||
</style>
|
||||
17
txw-yygl-web/src/pages/index/views/document/index.vue
Normal file
17
txw-yygl-web/src/pages/index/views/document/index.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<div class="document-layout">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DocumentLayout'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.document-layout {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
70
txw-yygl-web/src/pages/index/views/document/list/index.vue
Normal file
70
txw-yygl-web/src/pages/index/views/document/list/index.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="document-list-container">
|
||||
<div class="filter-bar">
|
||||
<t-select v-model="filters.categoryId" :options="categoryOptions" placeholder="选择分类" clearable />
|
||||
<t-select v-model="filters.status" :options="statusOptions" placeholder="选择状态" clearable />
|
||||
<t-button @click="loadDocumentList">查询</t-button>
|
||||
<t-button theme="primary" @click="goToEdit()">新建文档</t-button>
|
||||
</div>
|
||||
<t-table :data="documentList" :columns="columns" row-key="id">
|
||||
<template #operations="{ row }">
|
||||
<t-button size="small" @click="goToEdit(row.id)">编辑</t-button>
|
||||
<t-button size="small" theme="danger" @click="deleteDocument(row.id)">删除</t-button>
|
||||
</template>
|
||||
</t-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/pages/index/api/document';
|
||||
|
||||
export default {
|
||||
name: 'DocumentList',
|
||||
data() {
|
||||
return {
|
||||
filters: { categoryId: null, status: null },
|
||||
categoryOptions: [],
|
||||
statusOptions: [
|
||||
{ label: '草稿', value: 0 },
|
||||
{ label: '已发布', value: 1 }
|
||||
],
|
||||
documentList: [],
|
||||
columns: [
|
||||
{ colKey: 'id', title: 'ID' },
|
||||
{ colKey: 'title', title: '标题' },
|
||||
{ colKey: 'categoryName', title: '分类' },
|
||||
{ colKey: 'status', title: '状态', formatter: (v) => v === 1 ? '已发布' : '草稿' },
|
||||
{ colKey: 'createTime', title: '创建时间' },
|
||||
{ colKey: 'operation', title: '操作', cell: 'operations' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCategoryList()
|
||||
this.loadDocumentList()
|
||||
},
|
||||
methods: {
|
||||
async loadCategoryList() {
|
||||
const res = await api.getCategoryList()
|
||||
this.categoryOptions = res.data.map(c => ({ label: c.name, value: c.id }))
|
||||
},
|
||||
async loadDocumentList() {
|
||||
const res = await api.getDocumentList(this.filters)
|
||||
this.documentList = res.data
|
||||
},
|
||||
goToEdit(id) {
|
||||
this.$router.push(id ? `/document/edit/${id}` : '/document/edit')
|
||||
},
|
||||
async deleteDocument(id) {
|
||||
await api.deleteDocument(id)
|
||||
this.$message.success('删除成功')
|
||||
this.loadDocumentList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.document-list-container { padding: 20px; }
|
||||
.filter-bar { display: flex; gap: 10px; margin-bottom: 20px; }
|
||||
</style>
|
||||
109
txw-yygl-web/src/pages/index/views/document/overview/index.vue
Normal file
109
txw-yygl-web/src/pages/index/views/document/overview/index.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="document-overview">
|
||||
<div class="overview-header">
|
||||
<h2>文档管理</h2>
|
||||
<p class="subtitle">管理文档内容和分类</p>
|
||||
</div>
|
||||
<div class="overview-cards">
|
||||
<div class="overview-card" @click="$router.push('/document/list')">
|
||||
<div class="card-icon">
|
||||
<t-icon name="document" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>文档列表</h3>
|
||||
<p>查看和管理所有文档</p>
|
||||
</div>
|
||||
<div class="card-arrow">
|
||||
<t-icon name="arrow-right" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-card" @click="$router.push('/document/category')">
|
||||
<div class="card-icon">
|
||||
<t-icon name="folder" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>分类管理</h3>
|
||||
<p>管理文档分类</p>
|
||||
</div>
|
||||
<div class="card-arrow">
|
||||
<t-icon name="arrow-right" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DocumentOverview'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.document-overview {
|
||||
padding: 24px;
|
||||
}
|
||||
.overview-header {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.overview-header h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
.subtitle {
|
||||
margin: 0;
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
.overview-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
.overview-card {
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
cursor: pointer;
|
||||
background: var(--td-bg-color-container);
|
||||
border: 1px solid var(--td-border-level-1-color);
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
align-items: center;
|
||||
}
|
||||
.overview-card:hover {
|
||||
border-color: var(--td-brand-color);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.card-icon {
|
||||
display: flex;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-right: 16px;
|
||||
font-size: 24px;
|
||||
color: var(--td-brand-color);
|
||||
background: var(--td-brand-color-light);
|
||||
border-radius: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.card-content {
|
||||
flex: 1;
|
||||
}
|
||||
.card-content h3 {
|
||||
margin: 0 0 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--td-text-color-primary);
|
||||
}
|
||||
.card-content p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
.card-arrow {
|
||||
font-size: 16px;
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
</style>
|
||||
@ -280,6 +280,18 @@ module.exports = {
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
|
||||
},
|
||||
proxy: {
|
||||
'^/sso': {
|
||||
target: 'http://localhost:9301',
|
||||
// target: 'http://carbon.liantu.tech',
|
||||
// target: 'http://10.23.20.13:94/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/yygl': {
|
||||
target: 'http://localhost:20010',
|
||||
changeOrigin: true,
|
||||
}
|
||||
},
|
||||
// proxy: {
|
||||
// // '/api': {
|
||||
// // // target: 'http://dzswj.mhnsrd.jcsj.tax.cn/sbzx/api/cxssb', // 云测试环境
|
||||
|
||||
@ -1196,6 +1196,11 @@
|
||||
"@types/conventional-commits-parser" "^5.0.0"
|
||||
chalk "^5.3.0"
|
||||
|
||||
"@fortawesome/fontawesome-free@^7.0.1":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.npmmirror.com/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz#188c1053ce422ad1f934d7df242a973fcb89636d"
|
||||
integrity sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==
|
||||
|
||||
"@gar/promisify@^1.0.1":
|
||||
version "1.1.3"
|
||||
resolved "http://10.23.10.90:4873/@gar%2fpromisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
@ -3768,7 +3773,7 @@ commander@2.17.x:
|
||||
resolved "http://10.23.10.90:4873/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
|
||||
|
||||
commander@^2.18.0, commander@^2.20.0:
|
||||
commander@^2.18.0, commander@^2.20.0, commander@^2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "http://10.23.10.90:4873/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
@ -4387,6 +4392,11 @@ cssesc@^3.0.0:
|
||||
resolved "http://10.23.10.90:4873/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
cssfilter@0.0.10:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.npmmirror.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
|
||||
integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==
|
||||
|
||||
cssnano-preset-default@^4.0.0, cssnano-preset-default@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "http://10.23.10.90:4873/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff"
|
||||
@ -8294,6 +8304,13 @@ mathml-tag-names@^2.0.1, mathml-tag-names@^2.1.3:
|
||||
resolved "http://10.23.10.90:4873/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
|
||||
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
|
||||
|
||||
mavon-editor@^2.10.0:
|
||||
version "2.10.4"
|
||||
resolved "https://registry.npmmirror.com/mavon-editor/-/mavon-editor-2.10.4.tgz#58d6c4dc208933f0ac4595c10c60655899ba8ba8"
|
||||
integrity sha512-CFsBLkgt/KZBDg+SJYe2fyYv4zClY149PiwpH0rDAiiP4ae1XNs0GC8nBsoTeipsHcebDLN1QMkt3bUsnMDjQw==
|
||||
dependencies:
|
||||
xss "^1.0.6"
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "http://10.23.10.90:4873/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@ -13703,6 +13720,14 @@ x-is-string@^0.1.0:
|
||||
resolved "http://10.23.10.90:4873/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82"
|
||||
integrity sha512-GojqklwG8gpzOVEVki5KudKNoq7MbbjYZCbyWzEz7tyPA7eleiE0+ePwOWQQRb5fm86rD3S8Tc0tSFf3AOv50w==
|
||||
|
||||
xss@^1.0.6:
|
||||
version "1.0.15"
|
||||
resolved "https://registry.npmmirror.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a"
|
||||
integrity sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==
|
||||
dependencies:
|
||||
commander "^2.20.3"
|
||||
cssfilter "0.0.10"
|
||||
|
||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "http://10.23.10.90:4873/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package com.css.txw.yygl.controller;
|
||||
|
||||
import com.css.ggzc.framework.common.pojo.CommonResult;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentCategoryDO;
|
||||
import com.css.txw.yygl.pojo.vo.CategoryVO;
|
||||
import com.css.txw.yygl.service.DocumentCategoryService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/document/category")
|
||||
@Tag(name = "文档分类管理")
|
||||
@Validated
|
||||
public class DocumentCategoryController {
|
||||
|
||||
@Resource
|
||||
private DocumentCategoryService categoryService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "分类列表")
|
||||
public CommonResult<List<CategoryVO>> getCategoryList() {
|
||||
return CommonResult.success(categoryService.getCategoryList());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "新增分类")
|
||||
public CommonResult<String> saveCategory(@RequestBody DocumentCategoryDO category) {
|
||||
categoryService.saveCategory(category);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "编辑分类")
|
||||
public CommonResult<String> updateCategory(@PathVariable Long id, @RequestBody DocumentCategoryDO category) {
|
||||
category.setId(id);
|
||||
categoryService.updateCategory(category);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除分类")
|
||||
public CommonResult<String> deleteCategory(@PathVariable Long id) {
|
||||
categoryService.deleteCategory(id);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.css.txw.yygl.controller;
|
||||
|
||||
import com.css.ggzc.framework.common.pojo.CommonResult;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentDO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentDetailVO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentListVO;
|
||||
import com.css.txw.yygl.service.DocumentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/document")
|
||||
@Tag(name = "文档管理")
|
||||
@Validated
|
||||
public class DocumentController {
|
||||
|
||||
@Resource
|
||||
private DocumentService documentService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "文档列表")
|
||||
public CommonResult<List<DocumentListVO>> getDocumentList(
|
||||
@RequestParam(required = false) Long categoryId,
|
||||
@RequestParam(required = false) Integer status) {
|
||||
return CommonResult.success(documentService.getDocumentList(categoryId, status));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "文档详情")
|
||||
public CommonResult<DocumentDetailVO> getDocumentDetail(@PathVariable Long id) {
|
||||
return CommonResult.success(documentService.getDocumentDetail(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "新增文档")
|
||||
public CommonResult<String> saveDocument(@RequestBody DocumentDO document) {
|
||||
documentService.saveDocument(document);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "编辑文档")
|
||||
public CommonResult<String> updateDocument(@PathVariable Long id, @RequestBody DocumentDO document) {
|
||||
document.setId(id);
|
||||
documentService.updateDocument(document);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除文档")
|
||||
public CommonResult<String> deleteDocument(@PathVariable Long id) {
|
||||
documentService.deleteDocument(id);
|
||||
return CommonResult.success("success");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.css.txw.yygl.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentCategoryDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface DocumentCategoryMapper extends BaseMapper<DocumentCategoryDO> {
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package com.css.txw.yygl.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface DocumentMapper extends BaseMapper<DocumentDO> {
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.css.txw.yygl.pojo.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@TableName(value = "txw_document_category")
|
||||
@Data
|
||||
public class DocumentCategoryDO implements Serializable {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField(value = "name")
|
||||
private String name;
|
||||
|
||||
@TableField(value = "sort")
|
||||
private Integer sort;
|
||||
|
||||
@TableField(value = "status")
|
||||
private Integer status;
|
||||
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.css.txw.yygl.pojo.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
@TableName(value = "txw_document")
|
||||
@Data
|
||||
public class DocumentDO implements Serializable {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField(value = "category_id")
|
||||
private Long categoryId;
|
||||
|
||||
@TableField(value = "title")
|
||||
private String title;
|
||||
|
||||
@TableField(value = "content")
|
||||
private String content;
|
||||
|
||||
@TableField(value = "status")
|
||||
private Integer status;
|
||||
|
||||
@TableField(value = "sort")
|
||||
private Integer sort;
|
||||
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.css.txw.yygl.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class CategoryVO {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Integer sort;
|
||||
private Integer status;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.css.txw.yygl.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class DocumentDetailVO {
|
||||
private Long id;
|
||||
private Long categoryId;
|
||||
private String categoryName;
|
||||
private String title;
|
||||
private String content;
|
||||
private Integer status;
|
||||
private Integer sort;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.css.txw.yygl.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class DocumentListVO {
|
||||
private Long id;
|
||||
private Long categoryId;
|
||||
private String categoryName;
|
||||
private String title;
|
||||
private Integer status;
|
||||
private Integer sort;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.css.txw.yygl.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentCategoryDO;
|
||||
import com.css.txw.yygl.pojo.vo.CategoryVO;
|
||||
import java.util.List;
|
||||
|
||||
public interface DocumentCategoryService extends IService<DocumentCategoryDO> {
|
||||
List<CategoryVO> getCategoryList();
|
||||
void saveCategory(DocumentCategoryDO category);
|
||||
void updateCategory(DocumentCategoryDO category);
|
||||
void deleteCategory(Long id);
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.css.txw.yygl.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentDO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentDetailVO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentListVO;
|
||||
import java.util.List;
|
||||
|
||||
public interface DocumentService extends IService<DocumentDO> {
|
||||
List<DocumentListVO> getDocumentList(Long categoryId, Integer status);
|
||||
DocumentDetailVO getDocumentDetail(Long id);
|
||||
void saveDocument(DocumentDO document);
|
||||
void updateDocument(DocumentDO document);
|
||||
void deleteDocument(Long id);
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package com.css.txw.yygl.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.css.txw.yygl.mapper.DocumentCategoryMapper;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentCategoryDO;
|
||||
import com.css.txw.yygl.pojo.vo.CategoryVO;
|
||||
import com.css.txw.yygl.service.DocumentCategoryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class DocumentCategoryServiceImpl extends ServiceImpl<DocumentCategoryMapper, DocumentCategoryDO>
|
||||
implements DocumentCategoryService {
|
||||
|
||||
@Override
|
||||
public List<CategoryVO> getCategoryList() {
|
||||
LambdaQueryWrapper<DocumentCategoryDO> wrapper = new LambdaQueryWrapper<DocumentCategoryDO>();
|
||||
wrapper.eq(DocumentCategoryDO::getStatus, 1);
|
||||
wrapper.orderByAsc(DocumentCategoryDO::getSort);
|
||||
List<DocumentCategoryDO> list = this.list(wrapper);
|
||||
return list.stream().map(c -> {
|
||||
CategoryVO vo = new CategoryVO();
|
||||
vo.setId(c.getId());
|
||||
vo.setName(c.getName());
|
||||
vo.setSort(c.getSort());
|
||||
vo.setStatus(c.getStatus());
|
||||
vo.setCreateTime(c.getCreateTime());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveCategory(DocumentCategoryDO category) {
|
||||
this.save(category);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void updateCategory(DocumentCategoryDO category) {
|
||||
this.updateById(category);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void deleteCategory(Long id) {
|
||||
this.removeById(id);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.css.txw.yygl.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.css.txw.yygl.mapper.DocumentCategoryMapper;
|
||||
import com.css.txw.yygl.mapper.DocumentMapper;
|
||||
import com.css.txw.yygl.pojo.domain.DocumentDO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentDetailVO;
|
||||
import com.css.txw.yygl.pojo.vo.DocumentListVO;
|
||||
import com.css.txw.yygl.service.DocumentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class DocumentServiceImpl extends ServiceImpl<DocumentMapper, DocumentDO> implements DocumentService {
|
||||
|
||||
@Autowired
|
||||
private DocumentCategoryMapper categoryMapper;
|
||||
|
||||
@Override
|
||||
public List<DocumentListVO> getDocumentList(Long categoryId, Integer status) {
|
||||
LambdaQueryWrapper<DocumentDO> wrapper = new LambdaQueryWrapper<DocumentDO>();
|
||||
if (categoryId != null) wrapper.eq(DocumentDO::getCategoryId, categoryId);
|
||||
if (status != null) wrapper.eq(DocumentDO::getStatus, status);
|
||||
wrapper.orderByAsc(DocumentDO::getSort).orderByDesc(DocumentDO::getCreateTime);
|
||||
List<DocumentDO> list = this.list(wrapper);
|
||||
return list.stream().map(doc -> {
|
||||
DocumentListVO vo = new DocumentListVO();
|
||||
vo.setId(doc.getId());
|
||||
vo.setCategoryId(doc.getCategoryId());
|
||||
vo.setTitle(doc.getTitle());
|
||||
vo.setStatus(doc.getStatus());
|
||||
vo.setSort(doc.getSort());
|
||||
vo.setCreateTime(doc.getCreateTime());
|
||||
vo.setUpdateTime(doc.getUpdateTime());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentDetailVO getDocumentDetail(Long id) {
|
||||
DocumentDO doc = this.getById(id);
|
||||
if (doc == null) return null;
|
||||
DocumentDetailVO vo = new DocumentDetailVO();
|
||||
vo.setId(doc.getId());
|
||||
vo.setCategoryId(doc.getCategoryId());
|
||||
vo.setTitle(doc.getTitle());
|
||||
vo.setContent(doc.getContent());
|
||||
vo.setStatus(doc.getStatus());
|
||||
vo.setSort(doc.getSort());
|
||||
vo.setCreateTime(doc.getCreateTime());
|
||||
vo.setUpdateTime(doc.getUpdateTime());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveDocument(DocumentDO document) {
|
||||
this.save(document);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void updateDocument(DocumentDO document) {
|
||||
this.updateById(document);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void deleteDocument(Long id) {
|
||||
this.removeById(id);
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ spring:
|
||||
name: txw-yygl
|
||||
|
||||
profiles:
|
||||
active: env
|
||||
active: local
|
||||
|
||||
server:
|
||||
port: 20010
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.css.txw.yygl.mapper.DocumentCategoryMapper">
|
||||
<resultMap id="BaseResultMap" type="com.css.txw.yygl.pojo.domain.DocumentCategoryDO">
|
||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="name" column="name" jdbcType="VARCHAR"/>
|
||||
<result property="sort" column="sort" jdbcType="INTEGER"/>
|
||||
<result property="status" column="status" jdbcType="TINYINT"/>
|
||||
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
|
||||
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">id,name,sort,status,create_time,update_time</sql>
|
||||
</mapper>
|
||||
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.css.txw.yygl.mapper.DocumentMapper">
|
||||
<resultMap id="BaseResultMap" type="com.css.txw.yygl.pojo.domain.DocumentDO">
|
||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="categoryId" column="category_id" jdbcType="BIGINT"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="content" column="content" jdbcType="VARCHAR"/>
|
||||
<result property="status" column="status" jdbcType="TINYINT"/>
|
||||
<result property="sort" column="sort" jdbcType="INTEGER"/>
|
||||
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
|
||||
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">id,category_id,title,content,status,sort,create_time,update_time</sql>
|
||||
</mapper>
|
||||
@ -0,0 +1,45 @@
|
||||
-- 文档分类表
|
||||
CREATE TABLE txw_document_category (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '分类名称',
|
||||
sort INT DEFAULT 0 COMMENT '排序号',
|
||||
status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
|
||||
) COMMENT '文档分类表';
|
||||
|
||||
-- 文档表
|
||||
CREATE TABLE txw_document (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
category_id BIGINT NOT NULL COMMENT '分类ID',
|
||||
title VARCHAR(200) NOT NULL COMMENT '文档标题',
|
||||
content TEXT NOT NULL COMMENT 'Markdown正文内容',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态:0-草稿,1-已发布',
|
||||
sort INT DEFAULT 0 COMMENT '排序号',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
FOREIGN KEY (category_id) REFERENCES document_category(id)
|
||||
) COMMENT '文档表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 测试数据
|
||||
-- ----------------------------
|
||||
|
||||
-- 插入文档分类数据
|
||||
INSERT INTO txw_document_category (id, name, sort, status, create_time, update_time) VALUES
|
||||
(1, '平台介绍', 1, 1, NOW(), NOW()),
|
||||
(2, '使用指南', 2, 1, NOW(), NOW()),
|
||||
(3, '常见问题', 3, 1, NOW(), NOW()),
|
||||
(4, '行业动态', 4, 1, NOW(), NOW()),
|
||||
(5, '规章制度', 5, 1, NOW(), NOW());
|
||||
|
||||
-- 插入文档数据
|
||||
INSERT INTO txw_document (id, category_id, title, content, status, sort, create_time, update_time) VALUES
|
||||
(1, 1, '关于我们', '# 关于我们\n\n碳信网是国内领先的碳排放管理平台...\n\n## 联系方式\n\n- 电话:400-xxx-xxxx\n- 邮箱:contact@tanxin.com', 1, 1, NOW(), NOW()),
|
||||
(2, 1, '平台公告', '# 平台公告\n\n欢迎使用碳信网平台,最新公告内容将在这里发布。', 1, 2, NOW(), NOW()),
|
||||
(3, 2, '快速入门', '# 快速入门\n\n## 第一步:注册账号\n\n点击注册按钮,填写企业信息...\n\n## 第二步:认证企业\n\n完成企业实名认证后,即可使用平台功能。', 1, 1, NOW(), NOW()),
|
||||
(4, 2, '企业认证指南', '# 企业认证指南\n\n企业认证需要提供以下材料:\n\n1. 营业执照\n2. 法人身份证\n3. 企业授权书', 1, 2, NOW(), NOW()),
|
||||
(5, 3, '如何注册账号?', '# 如何注册账号?\n\n## 注册步骤\n\n1. 点击右上角"注册"按钮\n2. 选择"企业用户"类型\n3. 填写基本信息\n4. 完成验证', 1, 1, NOW(), NOW()),
|
||||
(6, 3, '忘记密码怎么办?', '# 忘记密码怎么办?\n\n点击登录页的"忘记密码"链接,通过绑定的手机号或邮箱找回密码。', 1, 2, NOW(), NOW()),
|
||||
(7, 4, '2026年碳市场趋势分析', '# 2026年碳市场趋势分析\n\n## 市场概况\n\n2026年碳市场整体呈现稳中有升的趋势...\n\n## 政策解读\n\n最新政策对碳排放企业提出了更高的要求。', 1, 1, NOW(), NOW()),
|
||||
(8, 5, '用户协议', '# 用户协议\n\n## 第一条:总则\n\n本协议适用于碳信网所有用户...', 1, 1, NOW(), NOW());
|
||||
Loading…
Reference in New Issue
Block a user