feat: 添加md文档预览
This commit is contained in:
parent
d966ffff1d
commit
f37f1051c0
@ -105,4 +105,4 @@
|
||||
"common-front": "link:D:\\shanghai\\txw2\\local-nodemodules\\@gt4\\common-front",
|
||||
"tdesign-gt-vue": "link:D:\\shanghai\\txw2\\local-nodemodules\\@gtff\\tdesign-gt-vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
txw-mhzc-web/public/docs/carbon-guide.md
Normal file
77
txw-mhzc-web/public/docs/carbon-guide.md
Normal file
@ -0,0 +1,77 @@
|
||||
# 可信碳链 — 接入流程指南
|
||||
|
||||

|
||||
|
||||
欢迎接入可信碳链!以下是完整的接入流程说明,帮助您快速完成身份创建、资质申请与技术联调。
|
||||
|
||||
## 第一步:创建 DID 账户
|
||||
|
||||
**操作目标**:生成您的去中心化身份标识(DID),作为后续所有操作的身份基础。
|
||||
|
||||
1. 访问 DID 管理台,完成管理台账号注册并登录。
|
||||
2. 在控制台中选择「创建 DID」或「导入已有 DID」,生成您的链上身份。
|
||||
3. 妥善保管 DID 相关凭证,这是您在可信碳链上的唯一身份标识。
|
||||
|
||||
> **注意**:DID 凭证一旦丢失将无法恢复,请务必安全保管。
|
||||
|
||||
## 第二步:申请 VC 颁发权限
|
||||
|
||||
**操作目标**:获得可信碳凭证(Verifiable Credential)的签发资质,成为合规颁证机构。
|
||||
|
||||
1. 进入管理台 > 签发管理,提交「申请成为颁证机构」。
|
||||
2. 按要求填写机构信息、资质材料并提交审核。
|
||||
3. 等待平台审核通过后,即可获得凭证签发权限。
|
||||
|
||||
```
|
||||
审核周期:3-5 个工作日
|
||||
资质要求:企业实名认证 + 相关行业资质
|
||||
```
|
||||
|
||||
## 第三步:创建可信碳凭证模板 & 访问令牌
|
||||
|
||||
**操作目标**:定义碳凭证的业务结构,并获取 DID 公共服务交互的安全令牌。
|
||||
|
||||
1. 进入管理台 > 凭证模板,点击「创建新模板」,配置凭证字段。
|
||||
2. 进入管理台 > 账户中心 > 访问令牌管理进行新增加令牌。
|
||||
|
||||

|
||||
|
||||
## 第四步:下载 SDK 并完成接入联调
|
||||
|
||||
**操作目标**:将可信碳能力集成到您的业务系统,实现碳数字身份证的签发与管理。
|
||||
|
||||
| 步骤 | 内容 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | 下载 SDK | 获取平台提供的 SDK 开发工具包 |
|
||||
| 2 | 申请鉴权信息 | 申请 appId(应用标识)与 secretKey(密钥) |
|
||||
| 3 | 集成开发 | 参考官方接入文档,将 SDK 集成到您的业务系统中 |
|
||||
| 4 | 接口联调 | 调用接口实现碳数据上链、VC 签发/验证等功能 |
|
||||
| 5 | 上线验证 | 联调通过后,即可正式上线 |
|
||||
|
||||
```javascript
|
||||
// SDK 初始化示例
|
||||
import { CarbonChain } from '@carbon/sdk';
|
||||
|
||||
const carbon = new CarbonChain({
|
||||
appId: 'your-app-id',
|
||||
secretKey: 'your-secret-key',
|
||||
did: 'your-did'
|
||||
});
|
||||
|
||||
await carbon.init();
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何获取 DID?
|
||||
A: 在 DID 管理台创建或导入已有 DID。
|
||||
|
||||
### Q: VC 审核需要多长时间?
|
||||
A: 一般 3-5 个工作日。
|
||||
|
||||
### Q: 支持哪些开发语言?
|
||||
A: 支持 Java、Python、Node.js、Go 等主流语言。
|
||||
|
||||
---
|
||||
|
||||
**技术支持**:如有疑问,请联系 support@carbonchain.com
|
||||
6
txw-mhzc-web/public/marked.js
Normal file
6
txw-mhzc-web/public/marked.js
Normal file
File diff suppressed because one or more lines are too long
@ -106,6 +106,11 @@ function zhanghugl() {
|
||||
return import(/* webpackChunkName: "zhanghugl" */ '@/pages/index/views/yhzx/zhanghugl/index.vue');
|
||||
}
|
||||
|
||||
// md文档查看器
|
||||
function mdviewer() {
|
||||
return import(/* webpackChunkName: "mdviewer" */ '@/pages/index/views/mdviewer/index.vue');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -306,4 +311,16 @@ export default [
|
||||
disableBack: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mdviewer',
|
||||
path: '/mdviewer',
|
||||
component: mdviewer,
|
||||
meta: {
|
||||
title: '文档预览',
|
||||
isShowSideBar: false,
|
||||
hasHome: true,
|
||||
breadCrumbs: [{ title: '首页', to: '/home' }, { title: '文档预览', to: '/mdviewer' }],
|
||||
disableBack: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
311
txw-mhzc-web/src/pages/index/views/mdviewer/index.vue
Normal file
311
txw-mhzc-web/src/pages/index/views/mdviewer/index.vue
Normal file
@ -0,0 +1,311 @@
|
||||
<template>
|
||||
<div class="md-viewer">
|
||||
<div v-if="loading">加载中...</div>
|
||||
<div v-else-if="error" v-html="error"></div>
|
||||
<div v-else v-html="renderedContent"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MdViewer',
|
||||
data() {
|
||||
return {
|
||||
content: '',
|
||||
loading: true,
|
||||
error: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
renderedContent() {
|
||||
if (!window.marked || !window.marked.parse) return '<p>marked 未加载</p>';
|
||||
return window.marked.parse(this.content);
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadMarked();
|
||||
this.fetchMdContent();
|
||||
},
|
||||
methods: {
|
||||
loadMarked() {
|
||||
return new Promise((resolve) => {
|
||||
if (window.marked) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
fetch('marked.js')
|
||||
.then((r) => r.text())
|
||||
.then((code) => {
|
||||
// 使用 iframe 来执行脚本,确保 window 是正确的
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
const iframeWindow = iframe.contentWindow;
|
||||
iframeWindow.eval(code);
|
||||
window.marked = iframeWindow.marked;
|
||||
document.body.removeChild(iframe);
|
||||
resolve();
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('marked 加载失败', e);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
fetchMdContent() {
|
||||
const { file } = this.$route.query;
|
||||
if (!file) {
|
||||
this.content = '# 未指定文件\n\n请使用 ?file=xxx 传递文件路径';
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
// 测试模式
|
||||
if (file === 'test') {
|
||||
this.content = `# 测试文档
|
||||
|
||||

|
||||
|
||||
## 这是一个测试
|
||||
|
||||
- 列表项1
|
||||
- 列表项2
|
||||
|
||||
**粗体** 和 *斜体*
|
||||
|
||||

|
||||
|
||||
\`\`\`javascript
|
||||
console.log('Hello World');
|
||||
\`\`\`
|
||||
|
||||
> 引用文本
|
||||
|
||||
[链接](https://example.com)
|
||||
|
||||
| 表头1 | 表头2 |
|
||||
|-------|-------|
|
||||
| 单元格1 | 单元格2 |
|
||||
|
||||

|
||||
|
||||
### 图片测试
|
||||
|
||||
支持本地图片和外链图片
|
||||
|
||||

|
||||
`;
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
fetch(file)
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error('404');
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
this.content = data;
|
||||
})
|
||||
.catch(() => {
|
||||
this.error = '<h1>加载失败</h1><p>文件:' + file + '</p>';
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.md-viewer {
|
||||
max-width: 820px;
|
||||
margin: 30px auto;
|
||||
padding: 50px 60px;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
|
||||
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.9;
|
||||
color: #374151;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.md-viewer h1 {
|
||||
font-size: 2.2em;
|
||||
font-weight: 800;
|
||||
margin: 0 0 25px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 3px solid transparent;
|
||||
border-image: linear-gradient(90deg, #667eea, #764ba2) 1;
|
||||
color: #1a1a2e;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.md-viewer h2 {
|
||||
font-size: 1.5em;
|
||||
font-weight: 700;
|
||||
margin: 35px 0 18px;
|
||||
padding: 10px 0 10px 16px;
|
||||
border-left: 4px solid;
|
||||
border-image: linear-gradient(180deg, #667eea, #764ba2) 1;
|
||||
color: #1a1a2e;
|
||||
background: linear-gradient(90deg, rgba(102,126,234,0.08) 0%, transparent 100%);
|
||||
}
|
||||
|
||||
.md-viewer h3 {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
margin: 28px 0 14px;
|
||||
color: #2d3748;
|
||||
padding-left: 12px;
|
||||
border-left: 3px solid #667eea;
|
||||
}
|
||||
|
||||
.md-viewer h4 {
|
||||
font-size: 1.05em;
|
||||
font-weight: 600;
|
||||
margin: 20px 0 10px;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.md-viewer p {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.md-viewer ul,
|
||||
.md-viewer ol {
|
||||
margin: 16px 0;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.md-viewer li {
|
||||
margin: 10px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.md-viewer ul li::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
top: 12px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.md-viewer blockquote {
|
||||
margin: 20px 0;
|
||||
padding: 16px 24px;
|
||||
background: linear-gradient(135deg, rgba(102,126,234,0.08) 0%, rgba(118,75,162,0.08) 100%);
|
||||
border-left: 4px solid #667eea;
|
||||
border-radius: 0 12px 12px 0;
|
||||
color: #4a5568;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.md-viewer blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.md-viewer code {
|
||||
padding: 3px 8px;
|
||||
background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
|
||||
border-radius: 6px;
|
||||
font-family: 'Fira Code', 'SFMono-Regular', Consolas, monospace;
|
||||
font-size: 0.88em;
|
||||
color: #d53f8c;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.md-viewer pre {
|
||||
margin: 20px 0;
|
||||
padding: 20px 24px;
|
||||
background: linear-gradient(135deg, #1e1e1e 0%, #2d2d30 100%);
|
||||
border-radius: 12px;
|
||||
overflow-x: auto;
|
||||
box-shadow: inset 0 2px 8px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.md-viewer pre code {
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: #d4d4d4;
|
||||
font-size: 0.85em;
|
||||
line-height: 1.7;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.md-viewer a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
border-bottom: 1px dashed #667eea;
|
||||
}
|
||||
|
||||
.md-viewer a:hover {
|
||||
color: #764ba2;
|
||||
border-bottom: 1px solid #764ba2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.md-viewer table {
|
||||
width: 100%;
|
||||
margin: 24px 0;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.md-viewer th {
|
||||
background: #f8fafc;
|
||||
color: #1a1a2e;
|
||||
font-weight: 600;
|
||||
padding: 16px 20px;
|
||||
text-align: left;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.md-viewer td {
|
||||
padding: 14px 20px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.md-viewer tr:hover td {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.md-viewer hr {
|
||||
margin: 30px 0;
|
||||
border: none;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, #e2e8f0, transparent);
|
||||
}
|
||||
|
||||
.md-viewer img {
|
||||
max-width: 100%;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.1);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.md-viewer input[type="checkbox"] {
|
||||
margin-right: 8px;
|
||||
accent-color: #667eea;
|
||||
}
|
||||
|
||||
.md-viewer strong {
|
||||
color: #2d3748;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.md-viewer em {
|
||||
color: #718096;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@ -281,6 +281,7 @@ module.exports = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
|
||||
'Content-Security-Policy': "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.bootcdn.net https://cdnjs.cloudflare.com",
|
||||
},
|
||||
// Vue CLI prepareProxy 用 pathname.match(代理键) 判断;键写 '/mhzc' 会变成匹配路径里任意位置的 /mhzc,
|
||||
// 会误伤 SPA 路由 /view/mhzc/...,刷新时整页请求被转发到后端导致 Proxy error。必须用 ^ 限定为路径前缀。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user