1
@@ -0,0 +1,19 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 数智AI
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_APP_ENV = 'development'
|
||||||
|
|
||||||
|
# 管理系统/开发环境
|
||||||
|
VITE_APP_BASE_API = '/dev-api'
|
||||||
|
|
||||||
|
# 后端接口地址
|
||||||
|
VITE_APP_BASE_URL = 'http://192.168.5.125:8000'
|
||||||
|
|
||||||
|
# AnythingLLM API 密钥
|
||||||
|
VITE_APP_ANYTHINGLLM_API_KEY = 'A3X9P8A-ZPK4K64-PDMVRB1-KJ5TXZT'
|
||||||
|
|
||||||
|
# RAGFlow API 配置
|
||||||
|
VITE_APP_RAGFLOW_API = 'http://192.168.5.125:3010'
|
||||||
|
|
||||||
|
VITE_APP_RAGFLOW_API_KEY = 'ragflow-qxHWAR7qwBedQSRmc2tDtL4duwh3KSzE8md5t1Qodv0'
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 数智AI
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV = 'production'
|
||||||
|
|
||||||
|
# 管理系统/生产环境
|
||||||
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|
||||||
|
# 后端接口地址
|
||||||
|
VITE_APP_BASE_URL = 'http://192.168.5.125:8000'
|
||||||
|
|
||||||
|
# AnythingLLM API 密钥
|
||||||
|
VITE_APP_ANYTHINGLLM_API_KEY = 'A3X9P8A-ZPK4K64-PDMVRB1-KJ5TXZT'
|
||||||
|
|
||||||
|
# RAGFlow API 配置
|
||||||
|
VITE_APP_RAGFLOW_API = 'http://192.168.5.125:3010'
|
||||||
|
VITE_APP_RAGFLOW_API_KEY = 'ragflow-qxHWAR7qwBedQSRmc2tDtL4duwh3KSzE8md5t1Qodv0'
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 数智AI
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV = 'staging'
|
||||||
|
|
||||||
|
# 管理系统/生产环境
|
||||||
|
VITE_APP_BASE_API = '/stage-api'
|
||||||
|
|
||||||
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|
||||||
|
# 后端接口地址
|
||||||
|
VITE_APP_BASE_URL = 'http://192.168.5.125:8000'
|
||||||
|
|
||||||
|
# AnythingLLM API 密钥
|
||||||
|
VITE_APP_ANYTHINGLLM_API_KEY = 'Bearer A3X9P8A-ZPK4K64-PDMVRB1-KJ5TXZT'
|
||||||
|
|
||||||
|
# RAGFlow API 配置
|
||||||
|
VITE_APP_RAGFLOW_API = 'http://192.168.5.125:3010'
|
||||||
|
VITE_APP_RAGFLOW_API_KEY = 'ragflow-qxHWAR7qwBedQSRmc2tDtL4duwh3KSzE8md5t1Qodv0'
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
.DS_Store
|
||||||
|
.claude
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
**/*.log
|
||||||
|
|
||||||
|
tests/**/coverage/
|
||||||
|
tests/e2e/reports
|
||||||
|
selenium-debug.log
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.local
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 RuoYi
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||||
|
</p>
|
||||||
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.9.2</h1>
|
||||||
|
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发框架</h4>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
|
||||||
|
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.9.2-brightgreen.svg"></a>
|
||||||
|
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 平台简介
|
||||||
|
|
||||||
|
* 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
||||||
|
* 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 或 [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) 版本。
|
||||||
|
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
||||||
|
|
||||||
|
# 版本对比
|
||||||
|
|
||||||
|
RuoYi-Vue 前端项目的三个主要演进版本,方便你直观对比其技术栈差异(并行开发维护)。
|
||||||
|
|
||||||
|
| 项目名称 | **RuoYi-Vue** | **RuoYi-Vue3** | **RuoYi-Vue3-TypeScript** |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **前端框架** | Vue 2 | Vue 3 | Vue 3 |
|
||||||
|
| **脚本语言** | JavaScript | JavaScript | TypeScript |
|
||||||
|
| **构建工具** | Vue CLI | Vite | Vite |
|
||||||
|
| **UI 组件库** | Element UI | Element Plus | Element Plus |
|
||||||
|
| **状态管理** | Vuex | Pinia | Pinia |
|
||||||
|
| **路由管理** | Vue Router 3 | Vue Router 4 | Vue Router 4 |
|
||||||
|
| **核心特点** | 1. 技术栈经典稳定<br>2. 社区资料丰富<br>3. 当前维护重心已转移 | 1. 现代前端技术栈<br>2. 开发体验与性能更优<br>3. 官方主推的活跃版本 | 1. 类型加持,减少沟通成本<br>2. 开发时有提示,效率更高<br>3. 多人协作企业级开发项目 |
|
||||||
|
| **仓库地址** | [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) | [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3) | [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript) |
|
||||||
|
|
||||||
|
## 前端运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆项目
|
||||||
|
git clone https://github.com/yangzongzhuan/RuoYi-Vue3.git
|
||||||
|
|
||||||
|
# 进入项目目录
|
||||||
|
cd RuoYi-Vue3
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
yarn --registry=https://registry.npmmirror.com
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# 构建测试环境 yarn build:stage
|
||||||
|
# 构建生产环境 yarn build:prod
|
||||||
|
# 前端访问地址 http://localhost:80
|
||||||
|
```
|
||||||
|
|
||||||
|
## 内置功能
|
||||||
|
|
||||||
|
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||||
|
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
|
||||||
|
3. 岗位管理:配置系统用户所属担任职务。
|
||||||
|
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||||
|
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
|
||||||
|
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||||
|
7. 参数管理:对系统动态配置常用参数。
|
||||||
|
8. 通知公告:系统通知公告信息发布维护。
|
||||||
|
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||||
|
10. 登录日志:系统登录日志记录查询包含登录异常。
|
||||||
|
11. 在线用户:当前系统中活跃用户状态监控。
|
||||||
|
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||||
|
13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
|
||||||
|
14. 系统接口:根据业务代码自动生成相关的api接口文档。
|
||||||
|
15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
|
||||||
|
16. 缓存监控:对系统的缓存信息查询,命令统计等。
|
||||||
|
17. 在线构建器:拖动表单元素生成相应的HTML代码。
|
||||||
|
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
||||||
|
|
||||||
|
## 在线体验
|
||||||
|
|
||||||
|
- admin/admin123
|
||||||
|
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
|
||||||
|
|
||||||
|
演示地址:http://vue.ruoyi.vip
|
||||||
|
文档地址:http://doc.ruoyi.vip
|
||||||
|
|
||||||
|
## 演示图
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
|
||||||
|
<td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
## 前后端分离交流群
|
||||||
|
|
||||||
|
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632) 点击按钮入群。
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@echo off
|
||||||
|
echo.
|
||||||
|
echo [信息] 打包Web工程,生成dist文件。
|
||||||
|
echo.
|
||||||
|
|
||||||
|
%~d0
|
||||||
|
cd %~dp0
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
yarn build:prod
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@echo off
|
||||||
|
echo.
|
||||||
|
echo [信息] 安装Web工程,生成node_modules文件。
|
||||||
|
echo.
|
||||||
|
|
||||||
|
%~d0
|
||||||
|
cd %~dp0
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
yarn --registry=https://registry.npmmirror.com
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@echo off
|
||||||
|
echo.
|
||||||
|
echo [信息] 使用 Vite 命令运行 Web 工程。
|
||||||
|
echo.
|
||||||
|
|
||||||
|
%~d0
|
||||||
|
cd %~dp0
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -0,0 +1,509 @@
|
|||||||
|
# 数智 AI 聊天页面实现计划
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 创建独立的「数智 AI」聊天页面,实现流式对话功能
|
||||||
|
|
||||||
|
**Architecture:** 单文件 Vue 组件实现,组合式 API + ElementPlus 组件,左侧边栏 + 中间消息区 + 底部输入栏的三栏布局
|
||||||
|
|
||||||
|
**Tech Stack:** Vue3 Composition API, ElementPlus, SCSS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: 创建 frontend 目录结构
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 创建: `src/views/frontend/` (目录)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 创建目录**
|
||||||
|
|
||||||
|
命令: `mkdir -p src/views/frontend`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: 创建主页面组件 index.vue
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 创建: `src/views/frontend/index.vue`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 编写页面基础模板结构**
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="shuzhi-ai-container">
|
||||||
|
<!-- 左侧边栏 -->
|
||||||
|
<aside class="sidebar">
|
||||||
|
<!-- LOGO 栏 -->
|
||||||
|
<div class="logo-bar">
|
||||||
|
<span class="logo-text">数智 AI</span>
|
||||||
|
<el-button link @click="handleComingSoon">
|
||||||
|
<el-icon><Fold /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<!-- Tab 切换 -->
|
||||||
|
<div class="tab-switch">
|
||||||
|
<el-button size="small" @click="handleComingSoon">项目</el-button>
|
||||||
|
<el-button size="small" @click="handleComingSoon">通用</el-button>
|
||||||
|
</div>
|
||||||
|
<!-- 树形列表 -->
|
||||||
|
<div class="tree-section">
|
||||||
|
<div class="tree-node tree-node-level1">
|
||||||
|
<span class="node-label">数智AI Demo</span>
|
||||||
|
<el-button link size="small" @click="handleComingSoon">×</el-button>
|
||||||
|
<el-button link size="small" @click="handleComingSoon">+</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="tree-node tree-node-level2" @click="handleComingSoon">
|
||||||
|
<span class="node-label">欢迎使用 数智AI</span>
|
||||||
|
<span class="node-hint">57 分钟前</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- 中间主内容区 -->
|
||||||
|
<main class="main-content">
|
||||||
|
<!-- 面包屑和功能导航 -->
|
||||||
|
<div class="content-header">
|
||||||
|
<el-breadcrumb separator="/">
|
||||||
|
<el-breadcrumb-item>general</el-breadcrumb-item>
|
||||||
|
<el-breadcrumb-item>智能体</el-breadcrumb-item>
|
||||||
|
<el-breadcrumb-item>欢迎使用 数智AI</el-breadcrumb-item>
|
||||||
|
</el-breadcrumb>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<el-button v-for="btn in navButtons" :key="btn" @click="handleComingSoon">{{ btn }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 消息区域 -->
|
||||||
|
<el-scrollbar ref="scrollRef" class="messages-container">
|
||||||
|
<div class="messages-wrapper">
|
||||||
|
<template v-for="(msg, index) in messages" :key="index">
|
||||||
|
<div class="message-divider" v-if="index > 0"></div>
|
||||||
|
<!-- 用户消息 -->
|
||||||
|
<div v-if="msg.role === 'user'" class="message-item user">
|
||||||
|
<div class="message-bubble">
|
||||||
|
<span class="message-tag">已处理 1m</span>
|
||||||
|
<div class="message-content">{{ msg.content }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- AI 消息 -->
|
||||||
|
<div v-else class="message-item assistant">
|
||||||
|
<div class="message-bubble">
|
||||||
|
<div class="message-content" v-html="formatMessage(msg.content)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
|
||||||
|
<!-- 底部输入栏 -->
|
||||||
|
<div class="input-bar">
|
||||||
|
<div class="input-controls">
|
||||||
|
<el-button size="small" @click="handleComingSoon">智能体</el-button>
|
||||||
|
<el-select size="small" placeholder="选择" @click="handleComingSoon" style="width: 100px">
|
||||||
|
<el-option label="选项1" value="1" />
|
||||||
|
</el-select>
|
||||||
|
<el-button size="small" @click="handleComingSoon">@</el-button>
|
||||||
|
<el-button size="small" @click="handleComingSoon">权限</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<el-input
|
||||||
|
v-model="inputText"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="告诉 数智AI 你想完成什么..."
|
||||||
|
resize="none"
|
||||||
|
@keydown.enter.exact.prevent="handleSend"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
class="send-btn"
|
||||||
|
:disabled="!inputText.trim() || loading"
|
||||||
|
@click="handleSend"
|
||||||
|
:loading="loading"
|
||||||
|
>
|
||||||
|
发送
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: 编写 script setup 部分**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { Fold } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const inputText = ref('')
|
||||||
|
const messages = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const scrollRef = ref()
|
||||||
|
|
||||||
|
const navButtons = ['智能体', '文件', '技能', '路由', '记忆', '常驻']
|
||||||
|
|
||||||
|
function handleComingSoon() {
|
||||||
|
ElMessage.info('敬请期待')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMessage(content) {
|
||||||
|
if (!content) return ''
|
||||||
|
// 高亮代码关键词
|
||||||
|
return content
|
||||||
|
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
||||||
|
.replace(/\n/g, '<br/>')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSend() {
|
||||||
|
if (!inputText.value.trim() || loading.value) return
|
||||||
|
|
||||||
|
const userContent = inputText.value.trim()
|
||||||
|
inputText.value = ''
|
||||||
|
|
||||||
|
// 添加用户消息
|
||||||
|
messages.value.push({
|
||||||
|
role: 'user',
|
||||||
|
content: userContent
|
||||||
|
})
|
||||||
|
|
||||||
|
scrollToBottom()
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://192.168.5.125:18000/v1/chat/completions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer 5c49dd2a721e0f408ea49298b6c13ddf17267eb0b64e3da7019ee581f597408e',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'qwen3.6-27b-nvfp4',
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: `/no_think\n ${userContent}`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 200,
|
||||||
|
temperature: 0.7
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`请求失败: ${response.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理流式响应
|
||||||
|
const reader = response.body.getReader()
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
let aiContent = ''
|
||||||
|
|
||||||
|
// 添加 AI 消息占位
|
||||||
|
messages.value.push({
|
||||||
|
role: 'assistant',
|
||||||
|
content: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read()
|
||||||
|
if (done) break
|
||||||
|
|
||||||
|
const chunk = decoder.decode(value)
|
||||||
|
aiContent += chunk
|
||||||
|
|
||||||
|
// 更新最后一条 AI 消息
|
||||||
|
const lastMsg = messages.value[messages.value.length - 1]
|
||||||
|
lastMsg.content = aiContent
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('问答失败:' + error.message)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollToBottom() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (scrollRef.value) {
|
||||||
|
scrollRef.value.setScrollTop(9999999)
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: 编写样式部分**
|
||||||
|
|
||||||
|
```scss
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.shuzhi-ai-container {
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 220px;
|
||||||
|
background: #F8F9FA;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-right: 1px solid #E5E7EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-bar {
|
||||||
|
height: 56px;
|
||||||
|
background: #0F172A;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.logo-text {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-switch {
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
border-bottom: 1px solid #E5E7EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-section {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-node {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #E5E7EB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-node-level1 {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.node-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-node-level2 {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-left: 16px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
|
||||||
|
.node-label {
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header {
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-bottom: 1px solid #E5E7EB;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages-wrapper {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: #E5E7EB;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-item {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&.user {
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.message-bubble {
|
||||||
|
background: #F1F3F5;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-tag {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
color: #222;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.assistant {
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.message-bubble {
|
||||||
|
padding: 0;
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
color: #222;
|
||||||
|
line-height: 1.8;
|
||||||
|
|
||||||
|
:deep(code) {
|
||||||
|
background: #EEEEEE;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-bar {
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-top: 1px solid #E5E7EB;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-btn {
|
||||||
|
height: 60px;
|
||||||
|
width: 80px;
|
||||||
|
background: #F1F3F5;
|
||||||
|
border: none;
|
||||||
|
color: #444;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
background: #E5E7EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: #F8F9FA;
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: 添加路由配置
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 修改: `src/router/index.js` (在 dynamicRoutes 数组末尾添加)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 添加路由配置**
|
||||||
|
|
||||||
|
在 `dynamicRoutes` 数组末尾添加:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
path: '/frontend',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: () => import('@/views/frontend/index'),
|
||||||
|
name: 'Frontend',
|
||||||
|
meta: { title: '数智 AI' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: 验证实现
|
||||||
|
|
||||||
|
- [ ] **Step 1: 检查文件是否创建成功**
|
||||||
|
|
||||||
|
命令: `ls -la src/views/frontend/`
|
||||||
|
|
||||||
|
- [ ] **Step 2: 验证路由配置语法**
|
||||||
|
|
||||||
|
检查 `src/router/index.js` 中是否有新增的 `/frontend` 路由
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 自检清单
|
||||||
|
|
||||||
|
- [ ] Spec 覆盖:所有需求点都有对应实现
|
||||||
|
- [ ] 占位符扫描:无 TBD、TODO 等占位符
|
||||||
|
- [ ] 类型一致性:所有方法名、变量名一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Plan complete and saved to `docs/superpowers/plans/2026-07-15-shuzhi-ai-chat-plan.md`**
|
||||||
|
|
||||||
|
Two execution options:
|
||||||
|
|
||||||
|
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||||
|
|
||||||
|
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||||
|
|
||||||
|
**Which approach?**
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
# Hide Layout Chrome for `common` Role Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Conditionally hide sidebar, navbar, tags-view, and the floating Settings button — and stretch `<app-main />` to fill the viewport — when the logged-in user's role list contains `"common"`.
|
||||||
|
|
||||||
|
**Architecture:** Add a single `isCommonUser` computed to `src/layout/index.vue` that derives from the existing Pinia `useUserStore`. Use that computed as a `v-if` gate on every chrome element and as a class binding on `.main-container`. Add one scoped SCSS rule for the fullscreen layout. No new files, no store/router/permission changes.
|
||||||
|
|
||||||
|
**Tech Stack:** Vue 3 (Composition API, `<script setup>`), Pinia, Vue Router, Element Plus, SCSS, Vuex-pattern Vue project (this is the `vue-element-plus-admin` template family).
|
||||||
|
|
||||||
|
**Spec:** `docs/superpowers/specs/2026-08-04-hide-chrome-for-common-role-design.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
Only one file changes:
|
||||||
|
|
||||||
|
| File | Change | Responsibility |
|
||||||
|
|---|---|---|
|
||||||
|
| `src/layout/index.vue` | Edit (script + template + style) | Add `isCommonUser` computed, gate chrome with `v-if`, add `fullscreen` class binding, add `fullscreen` SCSS rule |
|
||||||
|
|
||||||
|
No new files. No test files (the project has no frontend test infrastructure — see spec § Testing; verification is manual).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: Apply all `src/layout/index.vue` edits
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/layout/index.vue:1-115` (entire file)
|
||||||
|
|
||||||
|
This task is one edit cycle but split into named sub-steps so the implementer can verify the diff top-to-bottom. Use the Edit tool with exact string matching against the current file.
|
||||||
|
|
||||||
|
### Step 1.1 — Add `useUserStore` import
|
||||||
|
|
||||||
|
In `<script setup>`, the current line is:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
const theme = computed(() => settingsStore.theme)
|
||||||
|
```
|
||||||
|
|
||||||
|
It must become:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
const isCommonUser = computed(() =>
|
||||||
|
useUserStore().roles?.includes('common') ?? false
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit (exact old → new):
|
||||||
|
|
||||||
|
```js
|
||||||
|
old:
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
|
||||||
|
new:
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
const isCommonUser = computed(() =>
|
||||||
|
useUserStore().roles?.includes('common') ?? false
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 1.2 — Gate the four chrome elements + add `fullscreen` class
|
||||||
|
|
||||||
|
Current template body (lines 1-14):
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33' }">
|
||||||
|
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||||||
|
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
||||||
|
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
||||||
|
<div :class="{ 'fixed-header': fixedHeader }">
|
||||||
|
<navbar @setLayout="setLayout" />
|
||||||
|
<tags-view v-if="needTagsView" />
|
||||||
|
</div>
|
||||||
|
<app-main />
|
||||||
|
<settings ref="settingRef" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
Must become:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33' }">
|
||||||
|
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||||||
|
<sidebar v-if="!sidebar.hide && !isCommonUser" class="sidebar-container" />
|
||||||
|
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide, fullscreen: isCommonUser }" class="main-container">
|
||||||
|
<div :class="{ 'fixed-header': fixedHeader }">
|
||||||
|
<navbar v-if="!isCommonUser" @setLayout="setLayout" />
|
||||||
|
<tags-view v-if="needTagsView && !isCommonUser" />
|
||||||
|
</div>
|
||||||
|
<app-main />
|
||||||
|
<settings v-if="!isCommonUser" ref="settingRef" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
Five edits inside the template — do them one at a time with Edit if needed, or use Edit `replace_all=false` on each line above (each old/new pair is unique enough).
|
||||||
|
|
||||||
|
Edit 1 — sidebar line:
|
||||||
|
```diff
|
||||||
|
- <sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
||||||
|
+ <sidebar v-if="!sidebar.hide && !isCommonUser" class="sidebar-container" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit 2 — main-container opening line:
|
||||||
|
```diff
|
||||||
|
- <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
||||||
|
+ <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide, fullscreen: isCommonUser }" class="main-container">
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit 3 — navbar line:
|
||||||
|
```diff
|
||||||
|
- <navbar @setLayout="setLayout" />
|
||||||
|
+ <navbar v-if="!isCommonUser" @setLayout="setLayout" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit 4 — tags-view line:
|
||||||
|
```diff
|
||||||
|
- <tags-view v-if="needTagsView" />
|
||||||
|
+ <tags-view v-if="needTagsView && !isCommonUser" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit 5 — settings line:
|
||||||
|
```diff
|
||||||
|
- <settings ref="settingRef" />
|
||||||
|
+ <settings v-if="!isCommonUser" ref="settingRef" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 1.3 — Add `.fullscreen` SCSS rule
|
||||||
|
|
||||||
|
Inside the existing `<style lang="scss" scoped>` block, append after the `.mobile .fixed-header` rule at line ~115:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.main-container.fullscreen {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use Edit with surrounding context to make the match unique — for example, anchor on `.mobile .fixed-header` block ending with `width: 100%;` followed by `}`.
|
||||||
|
|
||||||
|
### Step 1.4 — Self-check the diff
|
||||||
|
|
||||||
|
Re-read the whole file (`src/layout/index.vue`) and confirm:
|
||||||
|
|
||||||
|
- `useUserStore` import is present and `isCommonUser` computed is declared in `<script setup>`.
|
||||||
|
- `<sidebar>`, `<navbar>`, `<tags-view>`, `<settings>` all carry `v-if` gating on `!isCommonUser`.
|
||||||
|
- The `<div class="main-container">` has `fullscreen: isCommonUser` in its class binding.
|
||||||
|
- `.main-container.fullscreen` SCSS rule is inside the scoped `<style>` block.
|
||||||
|
|
||||||
|
- [ ] **Step 1 completed**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: Manual verification
|
||||||
|
|
||||||
|
The project has no automated test suite (`package.json` scripts only include `dev` and `build`). Verify by running the dev server and exercising both role paths.
|
||||||
|
|
||||||
|
### Step 2.1 — Start the dev server
|
||||||
|
|
||||||
|
Run (from `D:/数科智联/agent-web/agent-web`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: Vite/Element-Plus dev server starts; URL is logged (typically `http://localhost:5173` or similar). Leave running.
|
||||||
|
|
||||||
|
### Step 2.2 — Verify admin role (no `common` in roles)
|
||||||
|
|
||||||
|
1. Open the dev URL in a browser.
|
||||||
|
2. Log in as a user whose `roles` array does **not** include `"common"` (e.g. admin / editor test accounts).
|
||||||
|
3. Open browser DevTools → Vue DevTools (or just inspect the DOM). Confirm all four are present in `#app`:
|
||||||
|
- `<aside>` containing the left sidebar.
|
||||||
|
- Top `<header>` / navbar.
|
||||||
|
- Tags-view row beneath the navbar.
|
||||||
|
- `<app-main />` to the right.
|
||||||
|
4. Confirm the floating Settings button is visible at the bottom-right.
|
||||||
|
5. Click a couple of navigation links; tags-view and sidebar behavior should be unchanged from prior baseline.
|
||||||
|
|
||||||
|
Expected: identical to pre-change behavior. If anything looks off (extra padding, missing element), stop and re-read the file diff.
|
||||||
|
|
||||||
|
### Step 2.3 — Verify `common` role (chromeless)
|
||||||
|
|
||||||
|
1. Log out, then log in as a user whose `roles` array contains `"common"` (e.g. `['common']` or `['common', 'something-else']`).
|
||||||
|
2. Reload the page if needed.
|
||||||
|
3. Confirm visually:
|
||||||
|
- No left sidebar.
|
||||||
|
- No top navbar.
|
||||||
|
- No tags-view row.
|
||||||
|
- No Settings floating button.
|
||||||
|
- `<app-main />` fills the entire viewport edge-to-edge (no sidebar gutter, no top whitespace from where navbar was).
|
||||||
|
4. Resize the window narrower to test responsive: `.fullscreen` should remain full screen at all widths.
|
||||||
|
5. Inside `<app-main />`, exercise the page's own controls (links, buttons, forms) to confirm interaction still works.
|
||||||
|
|
||||||
|
Expected: clean chromeless experience. If you see a gap or scrollbar that wasn't there before, the SCSS rule did not apply — check that the class binding in the template is correct and that `<style scoped>` did not strip the selector (use `:deep` if necessary, though for a scoped class on a top-level element this should not be needed).
|
||||||
|
|
||||||
|
### Step 2.4 — Verify mixed role `['admin', 'common']`
|
||||||
|
|
||||||
|
Repeat Step 2.3 with a user whose roles list is `['admin', 'common']`. Because `Array.prototype.includes` semantics treat any inclusion as "match", chrome should be hidden. If you see chrome here, the `isCommonUser` computed is wrong.
|
||||||
|
|
||||||
|
### Step 2.5 — Stop the dev server
|
||||||
|
|
||||||
|
When verification is complete, stop the dev server (Ctrl-C in the terminal where it is running).
|
||||||
|
|
||||||
|
- [ ] **Step 2 completed**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: Commit
|
||||||
|
|
||||||
|
### Step 3.1 — Stage and review
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status --short
|
||||||
|
git diff src/layout/index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: only `src/layout/index.vue` is modified. No stray changes from your edits.
|
||||||
|
|
||||||
|
### Step 3.2 — Commit
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/layout/index.vue
|
||||||
|
git commit -m "$(cat <<'EOF'
|
||||||
|
feat(layout): common 角色隐藏侧栏/顶栏/tagsview 并全屏渲染 app-main
|
||||||
|
|
||||||
|
根据 useUserStore().roles 是否包含 'common' 隐藏 sidebar、navbar、
|
||||||
|
tags-view、Settings 浮动按钮,并让 main-container 在该模式下全屏铺满。
|
||||||
|
仅修改 src/layout/index.vue。
|
||||||
|
|
||||||
|
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: one new commit on top of `b193fa1`. Working tree should be clean (modulo any pre-existing changes unrelated to this task — those are not part of this plan).
|
||||||
|
|
||||||
|
- [ ] **Step 3 completed**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review Checklist
|
||||||
|
|
||||||
|
- [x] **Spec coverage:**
|
||||||
|
- Goal (hide chrome + fullscreen app-main for `common` role) → Task 1
|
||||||
|
- Trigger (`roles.includes('common')`) → Step 1.1
|
||||||
|
- All four chrome elements gated → Steps 1.2 edits 1, 3, 4, 5
|
||||||
|
- Fullscreen class binding on `main-container` → Step 1.2 edit 2
|
||||||
|
- Fullscreen SCSS rule → Step 1.3
|
||||||
|
- Manual verification scenarios (admin / common / mixed / page interaction) → Tasks 2.2, 2.3, 2.4
|
||||||
|
- Settings also hidden (confirmed in brainstorming) → Step 1.2 edit 5
|
||||||
|
- [x] **Placeholder scan:** No TBD/TODO. Each edit has exact code. Manual verification steps have concrete URLs and accounts to use (caller supplies).
|
||||||
|
- [x] **Type consistency:** All references use `isCommonUser`. No alternate naming introduced. `useUserStore` matches existing imports elsewhere (`@/store/modules/user`).
|
||||||
|
- [x] **Commit hygiene:** One focused commit. Message starts with `feat(layout):`. Co-authored-by line present.
|
||||||
@@ -0,0 +1,703 @@
|
|||||||
|
# Frontend 会话列表底部用户区域块 Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 在 `ConversationSidebar` 底部新增用户区域块,包含用户头像+昵称、退出按钮、前往智能体广场按钮;侧边栏收起时仅显示小头像弹出菜单;点击头像昵称打开「个人资料」修改弹窗(可改头像、昵称)。
|
||||||
|
|
||||||
|
**Architecture:** 新增两个独立的 Vue 3 组件 `UserArea.vue` 和 `UserInfoDialog.vue`,`ConversationSidebar.vue` 引入并放置底部。两个组件用 `defineExpose` / `v-model` + emit 通信,遵循项目现有的 Composition API + Element Plus 风格。
|
||||||
|
|
||||||
|
**Tech Stack:** Vue 3 + Vite + Element Plus + Pinia + vue-cropper(已有依赖)+ vue-router
|
||||||
|
|
||||||
|
**Note:** 项目无测试框架,所有验证通过手动 `yarn dev` 在浏览器操作完成。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
### Create
|
||||||
|
|
||||||
|
- `src/views/frontend/components/UserArea.vue` — 底部区域块组件(展示 + 退出 + 跳转 + 弹出头像菜单)
|
||||||
|
- `src/views/frontend/components/UserInfoDialog.vue` — 个人资料修改弹窗(头像裁剪 + 昵称)
|
||||||
|
|
||||||
|
### Modify
|
||||||
|
|
||||||
|
- `src/views/frontend/components/ConversationSidebar.vue` — 引入 `UserArea`(**注意:放在 `<transition>` + `sidebar-content` 之外**——因为 `sidebar-content` 有 `v-if="!collapsed"` 会让 user area 在收起态被隐藏;放到 `.conversation-sidebar` 直接子节点让 UserArea 自己处理收起/展开 UI),调整 `sidebar-content` 为 flex 列布局让会话列表占中间、UserArea 固定在底部
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: 创建 UserArea.vue 组件骨架(展开态)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/views/frontend/components/UserArea.vue`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 创建文件,写入以下完整内容**
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div v-if="!collapsed" class="user-area">
|
||||||
|
<div class="user-area-divider"></div>
|
||||||
|
|
||||||
|
<div class="user-info-row" @click="openInfoDialog">
|
||||||
|
<el-avatar :size="36" :src="user.avatar" />
|
||||||
|
<div class="user-name-wrap">
|
||||||
|
<span class="user-name">{{ user.nickName || user.name || '未登录' }}</span>
|
||||||
|
</div>
|
||||||
|
<el-tooltip content="退出登录" placement="top" :show-after="300">
|
||||||
|
<el-button class="logout-btn" link @click.stop="handleLogout">
|
||||||
|
<el-icon><SwitchButton /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-button class="marketplace-btn" @click="goToMarketplace">
|
||||||
|
<el-icon><Promotion /></el-icon>
|
||||||
|
<span>前往智能体广场</span>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { SwitchButton, Promotion } from '@element-plus/icons-vue'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import UserInfoDialog from './UserInfoDialog.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
collapsed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const user = computed(() => ({
|
||||||
|
avatar: userStore.avatar,
|
||||||
|
nickName: userStore.nickName,
|
||||||
|
name: userStore.name
|
||||||
|
}))
|
||||||
|
|
||||||
|
const infoDialogVisible = ref(false)
|
||||||
|
|
||||||
|
function openInfoDialog() {
|
||||||
|
infoDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSaved(updated) {
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleLogout() {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
||||||
|
confirmButtonText: '退出',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await userStore.logOut()
|
||||||
|
router.push('/login')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('退出失败:', error)
|
||||||
|
ElMessage.error('退出失败,请稍后重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToMarketplace() {
|
||||||
|
router.push('/frontend/marketplace')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openInfoDialog
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.user-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 12px;
|
||||||
|
background: #fff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-area-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
margin: -12px -12px 12px -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name-wrap {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
color: #909399;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #f56c6c;
|
||||||
|
background: rgba(245, 108, 108, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.marketplace-btn {
|
||||||
|
margin-top: 10px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
background: #ecf5ff;
|
||||||
|
color: #409eff;
|
||||||
|
border: 1px solid #d9ecff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: 创建 UserInfoDialog.vue 组件
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `src/views/frontend/components/UserInfoDialog.vue`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 创建文件,写入以下完整内容**
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
title="个人资料"
|
||||||
|
:model-value="modelValue"
|
||||||
|
@update:model-value="$emit('update:modelValue', $event)"
|
||||||
|
width="500px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@open="handleOpen"
|
||||||
|
>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="头像" prop="avatar">
|
||||||
|
<div class="avatar-uploader" @click="triggerFileInput">
|
||||||
|
<el-avatar :size="64" :src="previewAvatar || form.avatar" />
|
||||||
|
<div class="avatar-mask">
|
||||||
|
<el-icon><Camera /></el-icon>
|
||||||
|
<span>更换头像</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
ref="fileInputRef"
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
style="display: none"
|
||||||
|
@change="handleFileChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="昵称" prop="nickName">
|
||||||
|
<el-input v-model="form.nickName" maxlength="30" show-word-limit placeholder="请输入昵称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
title="裁剪头像"
|
||||||
|
v-model="cropperVisible"
|
||||||
|
width="600px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
append-to-body
|
||||||
|
@opened="onCropperOpened"
|
||||||
|
>
|
||||||
|
<div class="cropper-container">
|
||||||
|
<vue-cropper
|
||||||
|
ref="cropperRef"
|
||||||
|
:img="cropperImg"
|
||||||
|
:autoCrop="true"
|
||||||
|
:autoCropWidth="180"
|
||||||
|
:autoCropHeight="180"
|
||||||
|
:fixedBox="true"
|
||||||
|
:outputType="'png'"
|
||||||
|
v-if="cropperVisible"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="cropperVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmCrop">确认裁剪</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { Camera } from '@element-plus/icons-vue'
|
||||||
|
import { VueCropper } from 'vue-cropper'
|
||||||
|
import { uploadAvatar, updateUserProfile } from '@/api/system/user'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({ avatar: '', nickName: '', name: '' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'saved'])
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const formRef = ref()
|
||||||
|
const fileInputRef = ref()
|
||||||
|
const cropperRef = ref()
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
nickName: '',
|
||||||
|
avatar: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
nickName: [{ required: true, message: '昵称不能为空', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const previewAvatar = ref('')
|
||||||
|
const cropperImg = ref('')
|
||||||
|
const cropperVisible = ref(false)
|
||||||
|
const saving = ref(false)
|
||||||
|
|
||||||
|
function handleOpen() {
|
||||||
|
form.nickName = props.user.nickName || props.user.name || ''
|
||||||
|
form.avatar = props.user.avatar || ''
|
||||||
|
previewAvatar.value = ''
|
||||||
|
cropperVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function triggerFileInput() {
|
||||||
|
fileInputRef.value?.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFileChange(e) {
|
||||||
|
const file = e.target.files?.[0]
|
||||||
|
if (!file) return
|
||||||
|
if (!file.type.startsWith('image/')) {
|
||||||
|
ElMessage.error('请选择图片文件')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = () => {
|
||||||
|
cropperImg.value = reader.result
|
||||||
|
cropperVisible.value = true
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
e.target.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCropperOpened() {
|
||||||
|
// cropper 已挂载,可触发自动裁剪
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmCrop() {
|
||||||
|
cropperRef.value?.getCropData((data) => {
|
||||||
|
previewAvatar.value = data
|
||||||
|
form.avatar = data
|
||||||
|
cropperVisible.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSave() {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate()
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
if (previewAvatar.value) {
|
||||||
|
const blob = dataURLtoBlob(previewAvatar.value)
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('avatarfile', blob, 'avatar.png')
|
||||||
|
const res = await uploadAvatar(formData)
|
||||||
|
const rawUrl = res.imgUrl || res.data?.imgUrl || ''
|
||||||
|
if (rawUrl) {
|
||||||
|
// 后端返回的 imgUrl 是相对路径,需要拼接 baseApi
|
||||||
|
const fullUrl = rawUrl.startsWith('http') ? rawUrl : (import.meta.env.VITE_APP_BASE_API + rawUrl)
|
||||||
|
userStore.avatar = fullUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await updateUserProfile({ nickName: form.nickName })
|
||||||
|
userStore.nickName = form.nickName
|
||||||
|
emit('saved', { avatar: userStore.avatar, nickName: form.nickName })
|
||||||
|
emit('update:modelValue', false)
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
ElMessage.error('保存失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
emit('update:modelValue', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function dataURLtoBlob(dataURL) {
|
||||||
|
const parts = dataURL.split(',')
|
||||||
|
const mime = parts[0].match(/:(.*?);/)?.[1] || 'image/png'
|
||||||
|
const binary = atob(parts[1])
|
||||||
|
const array = new Uint8Array(binary.length)
|
||||||
|
for (let i = 0; i < binary.length; i++) {
|
||||||
|
array[i] = binary.charCodeAt(i)
|
||||||
|
}
|
||||||
|
return new Blob([array], { type: mime })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.avatar-uploader {
|
||||||
|
position: relative;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
|
||||||
|
&:hover .avatar-mask {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-mask {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
gap: 2px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-container {
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: 改造 ConversationSidebar 集成 UserArea(展开态)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/views/frontend/components/ConversationSidebar.vue`(在 `<script setup>` 顶部 import + 在 template 引入 UserArea + 调整 sidebar-content 布局)
|
||||||
|
|
||||||
|
- [ ] **Step 1: 修改 `script setup` 顶部 import 区块,在 ChatLineRound 同一行 import 后追加 UserArea**
|
||||||
|
|
||||||
|
找到(line 67):
|
||||||
|
```js
|
||||||
|
import { ChatLineRound, DArrowLeft, DArrowRight, Refresh, Plus, Delete } from '@element-plus/icons-vue'
|
||||||
|
```
|
||||||
|
在下一行 import 区域找到 `formatTimeAgo`、`ElMessage`、`ElMessageBox` 的导入,并在其后加入:
|
||||||
|
```js
|
||||||
|
import UserArea from './UserArea.vue'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: 修改 template,把 UserArea 放在 `.conversation-sidebar` 内、`sidebar-content` 外**
|
||||||
|
|
||||||
|
找到 template 中:
|
||||||
|
```html
|
||||||
|
<div class="conversation-sidebar" :class="{ collapsed }">
|
||||||
|
<div class="sidebar-toggle" @click="toggleSidebar">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="sidebar-fade">
|
||||||
|
<div v-if="!collapsed" class="sidebar-content">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
<el-scrollbar height="calc(100vh - 160px)">
|
||||||
|
...
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
替换为:
|
||||||
|
```html
|
||||||
|
<div class="conversation-sidebar" :class="{ collapsed }">
|
||||||
|
<div class="sidebar-toggle" @click="toggleSidebar">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="sidebar-fade">
|
||||||
|
<div v-if="!collapsed" class="sidebar-content">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
<el-scrollbar class="sidebar-scrollbar">
|
||||||
|
...
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<UserArea :collapsed="collapsed" />
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
关键改动:
|
||||||
|
1. `<el-scrollbar>` 的内联 height 移除,改用 `.sidebar-scrollbar` flex:1 样式
|
||||||
|
2. UserArea 放在 `</transition>` 后,与 `sidebar-content` 同级——这样收起态 UserArea 仍可见
|
||||||
|
|
||||||
|
- [ ] **Step 3: 修改 `.conversation-sidebar`、`.sidebar-content` 与新增 `.sidebar-scrollbar` 样式**
|
||||||
|
|
||||||
|
找到 style scoped 内 `.conversation-sidebar { ... }`,在 `&.collapsed { width: 28px }` 之后追加 `display: flex; flex-direction: column;`:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.conversation-sidebar {
|
||||||
|
width: 240px;
|
||||||
|
border-right: 1px solid #e4e7ed;
|
||||||
|
transition: width 0.3s;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
width: 28px;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
找到 style scoped 内 `.sidebar-content { ... }`,把它从:
|
||||||
|
```scss
|
||||||
|
.sidebar-content {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
```
|
||||||
|
改为:
|
||||||
|
```scss
|
||||||
|
.sidebar-content {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
并在 `.conversation-item { ... }` 之后(任何空白处)新增:
|
||||||
|
```scss
|
||||||
|
.sidebar-scrollbar {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
并删除 `<el-scrollbar height="calc(100vh - 160px)">` 里使用的内联高度(已经在 step 2 改为 class)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: 添加 UserArea 收起态(仅头像 + dropdown 菜单)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `src/views/frontend/components/UserArea.vue`
|
||||||
|
|
||||||
|
- [ ] **Step 1: 在 `<template>` 内 `</div>` 闭合标签(即展开态分支)之后追加收起态分支与 UserInfoDialog**
|
||||||
|
|
||||||
|
找到 template 末尾:
|
||||||
|
```html
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
把 `</div>` 改为 `</div>` + v-else 分支 + UserInfoDialog,整体变为:
|
||||||
|
```html
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="user-area-collapsed">
|
||||||
|
<el-dropdown trigger="click" @command="handleCollapsedCommand">
|
||||||
|
<el-avatar :size="24" :src="user.avatar" class="collapsed-avatar" />
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="profile">个人资料</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="marketplace">前往智能体广场</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UserInfoDialog v-model="infoDialogVisible" :user="user" @saved="handleSaved" />
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: 在 `<script setup>` 内新增 `handleCollapsedCommand` 方法**
|
||||||
|
|
||||||
|
找到 `function goToMarketplace()` 之前的位置,新增:
|
||||||
|
```js
|
||||||
|
async function handleCollapsedCommand(cmd) {
|
||||||
|
if (cmd === 'profile') {
|
||||||
|
openInfoDialog()
|
||||||
|
} else if (cmd === 'marketplace') {
|
||||||
|
goToMarketplace()
|
||||||
|
} else if (cmd === 'logout') {
|
||||||
|
await handleLogout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: 在 `<style scoped>` 末尾添加收起态样式**
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.user-area-collapsed {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-top: 1px solid #e4e7ed;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed-avatar {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: 浏览器手动验证
|
||||||
|
|
||||||
|
- [ ] **Step 1: 启动 dev server**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "D:/数科智联/项目/agent-frontend-web"
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
Expected: Vite dev server 启动成功,浏览器访问 `http://localhost`(端口按 .env 配置)后能进入 `/login`。
|
||||||
|
|
||||||
|
- [ ] **Step 2: 登录并进入 `/frontend/index`,验证展开态 UI**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 左侧 sidebar 底部出现用户头像 + 昵称 + 退出按钮(图标)+「前往智能体广场」按钮
|
||||||
|
- 头像昵称与登录用户一致
|
||||||
|
- 整个 user-area 上方有一根细分割线
|
||||||
|
|
||||||
|
- [ ] **Step 3: 点击头像,验证弹窗**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 弹出「个人资料」弹窗
|
||||||
|
- 显示当前头像、当前昵称
|
||||||
|
- 输入框聚焦正常
|
||||||
|
|
||||||
|
- [ ] **Step 4: 修改昵称,保存,验证**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 输入新昵称
|
||||||
|
- 点击保存
|
||||||
|
- 提示「保存成功」
|
||||||
|
- 弹窗关闭
|
||||||
|
- sidebar 底部昵称已更新
|
||||||
|
- 刷新页面后仍保留新昵称
|
||||||
|
|
||||||
|
- [ ] **Step 5: 修改头像,保存,验证**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 点击头像 → 弹出文件选择器
|
||||||
|
- 选择图片 → 弹出裁剪对话框
|
||||||
|
- 点击确认裁剪 → 回到资料弹窗,预览头像已更新
|
||||||
|
- 点击保存 → 提示成功 → sidebar 头像更新
|
||||||
|
|
||||||
|
- [ ] **Step 6: 点击退出按钮,验证二次确认 + 跳转**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- 点击退出图标 → 弹出「确定要退出登录吗?」确认框
|
||||||
|
- 点击取消 → 不退出
|
||||||
|
- 再点击退出 → 点击「退出」 → 跳转到 `/login`
|
||||||
|
|
||||||
|
- [ ] **Step 7: 点击「前往智能体广场」,验证跳转**
|
||||||
|
|
||||||
|
Expected: 跳转到 `/frontend/marketplace` 智能体广场页面。
|
||||||
|
|
||||||
|
- [ ] **Step 8: 收起侧边栏(点击侧边栏右侧圆形箭头按钮),验证收起态**
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
- sidebar 缩窄到约 28px
|
||||||
|
- 底部只剩一个小圆形头像
|
||||||
|
- 点击小头像 → 弹出 dropdown:「个人资料 / 前往智能体广场 / 退出登录」
|
||||||
|
- 点击「个人资料」→ 弹窗正常打开
|
||||||
|
- 点击「前往智能体广场」→ 正常跳转
|
||||||
|
- 点击「退出登录」→ 二次确认后正常退出
|
||||||
|
|
||||||
|
- [ ] **Step 9: 展开侧边栏,验证收起态切换正常**
|
||||||
|
|
||||||
|
Expected: 侧边栏重新展开,user area 回到完整三块布局,无样式错乱。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review Checklist
|
||||||
|
|
||||||
|
- [x] Spec coverage: 三块功能(头像昵称、退出、智能体广场)+ 收起态 + 修改弹窗 全部覆盖
|
||||||
|
- [x] Placeholder scan: 无 TBD/TODO/模糊描述
|
||||||
|
- [x] Type consistency: `openInfoDialog` / `infoDialogVisible` / `user` 在两个组件间命名一致
|
||||||
|
- [x] Vue 3 风格: `<script setup>` + Composition API
|
||||||
|
- [x] Element Plus 风格: el-dialog / el-dropdown / el-message-box 与项目其他组件一致
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# 数智 AI 聊天页面设计文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
在 `src/views/frontend/index.vue` 创建独立的「数智 AI」聊天页面,采用 Vue3 组合式 API + ElementPlus 组件库,与现有 kds/chat.vue 风格保持一致。
|
||||||
|
|
||||||
|
## 页面布局
|
||||||
|
|
||||||
|
### 三栏固定布局
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ [LOGO栏: 数智AI] [折叠按钮] │ ← #0F172A
|
||||||
|
├─────────┬───────────────────────────────────────────────┤
|
||||||
|
│ │ 面包屑: general / 智能体 / 欢迎使用数智AI │
|
||||||
|
│ 侧边栏 │ [智能体][文件][技能][路由][记忆][常驻] │ ← 功能按钮
|
||||||
|
│ #F8F9FA │──────────────────────────────────────────────│
|
||||||
|
│ │ │
|
||||||
|
│ [项目] │ 消息区域(滚动) │
|
||||||
|
│ [通用] │ [AI回复靠左] │
|
||||||
|
│ │ [用户气泡靠右] │
|
||||||
|
│ 树形列表 │ ───────────────────────────── │
|
||||||
|
│ │ │
|
||||||
|
├─────────┴───────────────────────────────────────────────┤
|
||||||
|
│ [智能体][下拉框][@][权限] [输入框...] [发送] │ ← 固定底部
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 详细设计
|
||||||
|
|
||||||
|
### 1. 左侧边栏(固定宽度 220px)
|
||||||
|
|
||||||
|
**LOGO 栏**:
|
||||||
|
- 高度: 56px
|
||||||
|
- 背景: #0F172A
|
||||||
|
- 左侧白色文字「数智 AI」
|
||||||
|
- 右侧折叠图标按钮,点击提示"敬请期待"
|
||||||
|
|
||||||
|
**Tab 切换区**:
|
||||||
|
- 两个并排按钮:「项目」「通用」
|
||||||
|
- 点击提示"敬请期待"
|
||||||
|
|
||||||
|
**树形列表区域**:
|
||||||
|
- 一级节点:数智AI Demo,带下拉展开箭头,右侧有关闭 × 按钮、新增 + 按钮
|
||||||
|
- 二级子节点:欢迎使用 数智AI,下方灰色小字「57 分钟前」
|
||||||
|
- 所有交互点击均提示"敬请期待"
|
||||||
|
|
||||||
|
### 2. 中间主内容区域
|
||||||
|
|
||||||
|
**顶部面包屑**:
|
||||||
|
- 文字: `general / 智能体 / 欢迎使用 数智AI`
|
||||||
|
|
||||||
|
**功能导航栏**(6个按钮):
|
||||||
|
- 智能体、文件、技能、路由、记忆、常驻
|
||||||
|
- 全部点击提示"敬请期待"
|
||||||
|
|
||||||
|
**消息容器**:
|
||||||
|
- 白色背景,占据剩余高度
|
||||||
|
- 自动滚动到底部
|
||||||
|
|
||||||
|
**消息样式**:
|
||||||
|
- 用户消息: 靠右,背景 #F1F3F5,气泡左上角灰色小字「已处理 1m」
|
||||||
|
- AI 回复: 靠左,无背景白色文本块
|
||||||
|
- 消息间 1px 浅灰分割线 #E5E7EB 隔开
|
||||||
|
|
||||||
|
**文字色**:
|
||||||
|
- 正文: #222
|
||||||
|
- 辅助小字: #888
|
||||||
|
- 加粗标题: #111
|
||||||
|
|
||||||
|
### 3. 底部固定输入栏
|
||||||
|
|
||||||
|
- 大圆角文本输入框,占位文字: "告诉 数智AI 你想完成什么..."
|
||||||
|
- 左下角功能控件: 「智能体」按钮、下拉选择框、@按钮、权限按钮(全部提示"敬请期待")
|
||||||
|
- 右下角发送按钮,浅灰色底色
|
||||||
|
|
||||||
|
## API 交互
|
||||||
|
|
||||||
|
### 请求信息
|
||||||
|
- URL: `http://192.168.5.125:18000/v1/chat/completions`
|
||||||
|
- Method: POST
|
||||||
|
- Headers:
|
||||||
|
- Authorization: Bearer 5c49dd2a721e0f408ea49298b6c13ddf17267eb0b64e3da7019ee581f597408e
|
||||||
|
- Content-Type: application/json
|
||||||
|
|
||||||
|
### 请求 Body
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"model": "qwen3.6-27b-nvfp4",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "/no_think\n 用户的问题"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_tokens": 200,
|
||||||
|
"temperature": 0.7
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 流式响应处理
|
||||||
|
- 使用 EventSource 或 fetch + ReadableStream 解析 SSE 流式响应
|
||||||
|
- 逐字实时渲染到 AI 消息气泡,模拟打字机效果
|
||||||
|
- 请求期间发送按钮置灰
|
||||||
|
|
||||||
|
## 色彩规范
|
||||||
|
|
||||||
|
| 元素 | 色值 |
|
||||||
|
|------|------|
|
||||||
|
| 侧边栏背景 | #F8F9FA |
|
||||||
|
| LOGO 栏背景 | #0F172A |
|
||||||
|
| 用户气泡背景 | #F1F3F5 |
|
||||||
|
| 关键词高亮 | #EEEEEE |
|
||||||
|
| 分割线 | #E5E7EB |
|
||||||
|
| 正文文字 | #222 |
|
||||||
|
| 辅助小字 | #888 |
|
||||||
|
| 加粗标题 | #111 |
|
||||||
|
| 组件圆角 | 8px |
|
||||||
|
|
||||||
|
## 功能黑白名单
|
||||||
|
|
||||||
|
### 可正常运行
|
||||||
|
- 底部输入框文本输入
|
||||||
|
- 发送按钮触发对话 API
|
||||||
|
- 用户消息、AI 流式回复渲染
|
||||||
|
- 消息区域自动滚动
|
||||||
|
- 接口成功/失败弹窗提示
|
||||||
|
|
||||||
|
### 点击提示"敬请期待"
|
||||||
|
- 左侧边栏所有按钮、树节点、Tab 切换
|
||||||
|
- 顶部功能导航栏(智能体/文件/技能/路由/记忆/常驻)
|
||||||
|
- 底部输入栏左下角全部附属功能按钮
|
||||||
|
|
||||||
|
## 路由配置
|
||||||
|
|
||||||
|
需要在 `src/router/index.js` 中添加路由:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
path: '/frontend',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: () => import('@/views/frontend/index'),
|
||||||
|
name: 'Frontend',
|
||||||
|
meta: { title: '数智 AI' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 文件清单
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `src/views/frontend/index.vue` | 主页面组件(单文件实现) |
|
||||||
|
| `src/router/index.js` | 添加路由配置 |
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# 数智 AI 聊天前端页面设计
|
||||||
|
|
||||||
|
## 1. 概述
|
||||||
|
|
||||||
|
仿照 PilotDeck Web 端样式和布局,在 `src/views/frontend` 目录下实现数智 AI 聊天页面。
|
||||||
|
|
||||||
|
## 2. 布局结构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 顶部导航栏 │
|
||||||
|
├────────────┬───────────────────────────────────────┬───────────────┤
|
||||||
|
│ │ 顶部栏 │ │
|
||||||
|
│ 左侧会话 │ [会话名] [智能体] [文件] │ 文件列表 │
|
||||||
|
│ 列表 ├───────────────────────────────────────┤ (文件树) │
|
||||||
|
│ (可折叠) │ │ │
|
||||||
|
│ │ 聊天消息区域 │ 可折叠展开 │
|
||||||
|
│ │ │ 默认折叠 │
|
||||||
|
│ ├───────────────────────────────────────┤ │
|
||||||
|
│ │ [已引用文件区域] │ │
|
||||||
|
│ │ ┌────────────────────────────────┐ │ │
|
||||||
|
│ │ │ 输入框 @ │ │ │
|
||||||
|
│ │ └────────────────────────────────┘ │ │
|
||||||
|
└────────────┴───────────────────────────────────────┴───────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 功能模块
|
||||||
|
|
||||||
|
### 3.1 左侧会话列表 (ConversationSidebar)
|
||||||
|
|
||||||
|
- **折叠/展开**:可折叠,展开时宽度约 240px
|
||||||
|
- **会话项**:只显示"通用会话"列表(模拟数据)
|
||||||
|
- **交互**:点击会话项 → 右侧聊天窗口切换到该会话
|
||||||
|
|
||||||
|
### 3.2 顶部栏 (ChatHeader)
|
||||||
|
|
||||||
|
- **左侧**:当前会话窗口的名称
|
||||||
|
- **右侧**:
|
||||||
|
- **智能体按钮**(默认选中状态)
|
||||||
|
- **文件按钮**:点击展开/收起右侧文件列表面板
|
||||||
|
|
||||||
|
### 3.3 聊天窗口 (ChatWindow)
|
||||||
|
|
||||||
|
- **消息展示**:用户消息(右侧蓝色)、AI 回复(左侧灰色)
|
||||||
|
- **欢迎页**:无消息时显示欢迎提示
|
||||||
|
- **加载状态**:AI 回复时显示"正在思考..."动画
|
||||||
|
|
||||||
|
### 3.4 消息输入区 (InputArea)
|
||||||
|
|
||||||
|
- **输入框**:支持 Enter 发送、Shift+Enter 换行
|
||||||
|
- **@引用文件**:
|
||||||
|
- 输入框内输入 `@` 或点击输入框前的 `@` 图标 → 弹出文件选择弹层
|
||||||
|
- 弹层仅显示文件(不含文件夹)
|
||||||
|
- 选择文件后显示在"已引用文件区域"
|
||||||
|
- **已引用文件区域**:显示已引用的文件列表,支持删除
|
||||||
|
- **上传按钮**:点击可上传文件
|
||||||
|
- **发送按钮**:发送消息(含引用的文件)
|
||||||
|
|
||||||
|
### 3.5 文件列表面板 (FilePanel)
|
||||||
|
|
||||||
|
- **位置**:聊天区右侧,默认折叠
|
||||||
|
- **展开方式**:点击顶部栏"文件"按钮
|
||||||
|
- **文件树**:树形结构展示本地文件,支持展开/收起文件夹
|
||||||
|
- **文件操作**:
|
||||||
|
- 点击文件 → 在面板内预览
|
||||||
|
- 支持编辑文件内容
|
||||||
|
- 支持保存修改
|
||||||
|
- **自适应**:聊天区自适应缩窄,文件面板展开时撑开宽度
|
||||||
|
|
||||||
|
### 3.6 @文件选择弹层 (FileSelectModal)
|
||||||
|
|
||||||
|
- **触发**:
|
||||||
|
- 点击输入框前的 `@` 图标
|
||||||
|
- 在输入框内输入 `@` 字符
|
||||||
|
- **内容**:仅显示文件(不含文件夹),模拟数据
|
||||||
|
- **交互**:点击选择文件 → 弹层关闭 → 文件显示在已引用区域
|
||||||
|
|
||||||
|
## 4. 组件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/views/frontend/
|
||||||
|
├── index.vue # 主页面,整合所有模块
|
||||||
|
├── components/
|
||||||
|
│ ├── ConversationSidebar.vue # 左侧会话列表
|
||||||
|
│ ├── ChatWindow.vue # 聊天窗口
|
||||||
|
│ ├── ChatHeader.vue # 顶部栏
|
||||||
|
│ ├── InputArea.vue # 输入区域(含@引用)
|
||||||
|
│ ├── FilePanel.vue # 右侧文件列表面板
|
||||||
|
│ ├── FileSelectModal.vue # @文件选择弹层
|
||||||
|
│ └── QuotedFiles.vue # 已引用文件区域
|
||||||
|
└── styles/
|
||||||
|
└── index.scss # 样式文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 模拟数据
|
||||||
|
|
||||||
|
### 5.1 会话列表
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
[
|
||||||
|
{ id: 1, name: '通用会话 1' },
|
||||||
|
{ id: 2, name: '通用会话 2' },
|
||||||
|
{ id: 3, name: '通用会话 3' }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 文件列表(树形)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'src',
|
||||||
|
type: 'folder',
|
||||||
|
children: [
|
||||||
|
{ name: 'index.js', type: 'file' },
|
||||||
|
{ name: 'App.vue', type: 'file' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ name: 'README.md', type: 'file' },
|
||||||
|
{ name: 'package.json', type: 'file' }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 消息数据
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 模拟聊天消息
|
||||||
|
{
|
||||||
|
role: 'user' | 'assistant',
|
||||||
|
content: '消息内容',
|
||||||
|
time: 'HH:mm:ss'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 技术栈
|
||||||
|
|
||||||
|
- Vue 3 + Composition API
|
||||||
|
- Element Plus
|
||||||
|
- SCSS
|
||||||
|
- 模拟数据(无后端接口)
|
||||||
|
|
||||||
|
## 7. 响应式
|
||||||
|
|
||||||
|
- 聊天区、输入区宽度自适应
|
||||||
|
- 文件面板展开时聊天区自动缩窄
|
||||||
|
- 文件预览/编辑区高度自适应
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# Hide Layout Chrome for `common` Role Users
|
||||||
|
|
||||||
|
Date: 2026-08-04
|
||||||
|
Status: Approved (design phase)
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
When the logged-in user's role list contains `"common"`, hide all layout chrome — left sidebar, top navbar, tags view, and the floating Settings button — leaving only `<app-main />` filling the viewport. Non-`common` users see the existing full layout unchanged.
|
||||||
|
|
||||||
|
## Trigger Condition
|
||||||
|
|
||||||
|
`useUserStore().roles` (array) includes the string `"common"`.
|
||||||
|
|
||||||
|
The check is `roles.includes('common')`. A user with `['admin', 'common']` is treated as `common` because the array includes it; only roles where `common` is present trigger the new behavior.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Applies to **all routes**, unconditionally.
|
||||||
|
- No per-route opt-out, no per-route opt-in.
|
||||||
|
- Only the layout chrome is affected. `<app-main />` keeps rendering any page contents exactly as before.
|
||||||
|
|
||||||
|
## Files Touched
|
||||||
|
|
||||||
|
Only one file: `src/layout/index.vue`.
|
||||||
|
|
||||||
|
No stores, no router, no permission utilities, no new files.
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
### 1. Add a `isCommonUser` computed in `src/layout/index.vue`
|
||||||
|
|
||||||
|
```js
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
|
||||||
|
const isCommonUser = computed(() =>
|
||||||
|
useUserStore().roles?.includes('common') ?? false
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Defensive `?.includes` so an undefined `roles` collapses to `false` rather than throwing.
|
||||||
|
|
||||||
|
### 2. Gate the four chrome elements with `v-if`
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<sidebar v-if="!sidebar.hide && !isCommonUser" class="sidebar-container" />
|
||||||
|
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide, fullscreen: isCommonUser }" class="main-container">
|
||||||
|
<div :class="{ 'fixed-header': fixedHeader }">
|
||||||
|
<navbar v-if="!isCommonUser" @setLayout="setLayout" />
|
||||||
|
<tags-view v-if="needTagsView && !isCommonUser" />
|
||||||
|
</div>
|
||||||
|
<app-main />
|
||||||
|
<settings v-if="!isCommonUser" ref="settingRef" />
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- `Settings` is hidden even though the original requirement listed only sidebar / navbar / tagsview. The user explicitly confirmed in brainstorming that Settings should also be hidden for cleanliness.
|
||||||
|
- The outer `<div :class="classObj">` (with `hideSidebar` / `openSidebar` / `mobile`) is left untouched; it still affects the `<sidebar>` slot even when sidebar is hidden, which is harmless.
|
||||||
|
|
||||||
|
### 3. Fullscreen styling for `<app-main />`
|
||||||
|
|
||||||
|
Add a scoped SCSS rule:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.main-container.fullscreen {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This overrides any inherited width / margin-left from the sidebar-open state so `<app-main />` truly fills the viewport.
|
||||||
|
|
||||||
|
`<app-main />` internals (page padding, scoped styles) are **not** touched. If a future page wants a chrome-less padding experience, it owns that decision.
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
- Not changing user store APIs.
|
||||||
|
- Not adding a getter to `useUserStore` (single use site — YAGNI).
|
||||||
|
- Not introducing a second layout component or per-route layout switching.
|
||||||
|
- Not modifying router meta or permission middleware.
|
||||||
|
- Not changing `<app-main />` internals or any page component.
|
||||||
|
|
||||||
|
## Error / Edge Cases
|
||||||
|
|
||||||
|
- `roles` is `undefined` or `null` → `?.includes('common')` returns `undefined`, `?? false` collapses to `false`. Safe.
|
||||||
|
- `roles` is a non-array → `Array.prototype.includes` would throw. The user store initializes `roles: []`, so this is only a risk if a future change sets it to a non-array. No mitigation needed; treat as a contract violation.
|
||||||
|
- User role changes mid-session (does not happen in this app) → computed reacts automatically, layout re-renders. Reactive by design.
|
||||||
|
- Page refresh → `useUserStore` is repopulated via `getInfo()` during router guard; the computed is reactive and picks up the new value on next render. No flicker handling needed because the layout renders after auth is resolved.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
The repo has no frontend unit / e2e tests configured (`package.json` scripts only cover `dev` / `build`). Verification is manual:
|
||||||
|
|
||||||
|
1. **Admin role**: log in as a user without `common` in roles. All four chrome areas render as before.
|
||||||
|
2. **Common role**: log in as a user with `common` in roles. Only `<app-main />` is visible, filling the viewport edge-to-edge.
|
||||||
|
3. **Negative variant**: log in as a user with `['common', 'other-role']` — chrome still hidden (array `.includes` semantics).
|
||||||
|
4. **Page interaction**: inside `<app-main />`, the page's own links / buttons / forms work normally.
|
||||||
|
|
||||||
|
## Future Considerations (not implemented)
|
||||||
|
|
||||||
|
- If a second role-driven layout variant appears (e.g. compact admin view), lift `isCommonUser` into a `useUserStore` getter and consider per-route layout meta.
|
||||||
|
- If pages ever need to opt out of fullscreen (e.g. a "preview" page that wants the chrome visible for a `common` user), introduce per-route meta and gate on it. Not a current requirement.
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# 智能体广场跳转后 listChatSessions 传参 agentId
|
||||||
|
|
||||||
|
- **日期**: 2026-08-04
|
||||||
|
- **状态**: 已批准,待实施
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
从智能体广场(`marketplace.vue`)点击智能体进入前端聊天页面(`Frontend/index.vue`)时,路由携带 `query.agentId`。当前页面已读取该值并在 WebSocket 发送消息时回传,但会话侧边栏调用 `listChatSessions()` 获取会话列表时未携带 `agentId`,导致列表不能按智能体过滤。
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
从智能体广场跳转进入前端页面后,会话侧边栏调用 `listChatSessions()` 时附带 `agentId` 作为查询参数,后端据此只返回该智能体下的会话。其他入口(无 `agentId`)行为不变。
|
||||||
|
|
||||||
|
## 非目标
|
||||||
|
|
||||||
|
- 不修改 `marketplace.vue` 现有跳转逻辑
|
||||||
|
- 不修改 WebSocket 消息体(`agentId` 已附带,不在范围内)
|
||||||
|
- 不修改其他 list API(`listLlmModels`、`listAgentProjects` 等)
|
||||||
|
- 不引入状态管理库(Pinia 等)
|
||||||
|
|
||||||
|
## 设计
|
||||||
|
|
||||||
|
### 1. API 层 `src/api/frontend/index.js`
|
||||||
|
|
||||||
|
`listChatSessions` 改为接收可选 `agentId`,作为 GET 查询参数:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export function listChatSessions(agentId) {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/list',
|
||||||
|
method: 'get',
|
||||||
|
params: agentId ? { agentId: Number(agentId) } : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 不传或传 `null`/`undefined`/空字符串时,`params` 为空对象,行为与现状完全一致
|
||||||
|
- `agentId` 通过 `Number()` 转为数字,与 WebSocket 发送处的转换(`messageData.agentId = Number(agentId.value)`)保持一致
|
||||||
|
|
||||||
|
### 2. 父组件 `src/views/frontend/index.vue`
|
||||||
|
|
||||||
|
模板中已存在 `<ConversationSidebar ref="conversationSidebarRef" ... />`,新增 `:agent-id` 绑定:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<ConversationSidebar
|
||||||
|
ref="conversationSidebarRef"
|
||||||
|
:agent-id="agentId"
|
||||||
|
@select="handleConversationSelect"
|
||||||
|
@new-session="handleNewSession"
|
||||||
|
@ready="switchingConversation = false"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
`agentId` ref(第 162 行)已存在,由 `route.query.agentId` 赋值,无需新增状态。
|
||||||
|
|
||||||
|
### 3. 子组件 `src/views/frontend/components/ConversationSidebar.vue`
|
||||||
|
|
||||||
|
- 新增 prop 定义:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const props = defineProps({
|
||||||
|
agentId: { type: [String, Number], default: null }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- 第 131 行 `fetchSessions`:
|
||||||
|
```js
|
||||||
|
const res = await listChatSessions(props.agentId)
|
||||||
|
```
|
||||||
|
- 第 207 行 `refreshQuiet`:
|
||||||
|
```js
|
||||||
|
const res = await listChatSessions(props.agentId)
|
||||||
|
```
|
||||||
|
|
||||||
|
由于 `props.agentId` 是响应式的,直接读取即可拿到最新值,无需 `watch`。
|
||||||
|
|
||||||
|
## 数据流
|
||||||
|
|
||||||
|
```
|
||||||
|
marketplace.vue (handleAgentClick)
|
||||||
|
└─ router.push({ name: 'Frontend', query: { agentId, name } })
|
||||||
|
└─ index.vue (onMounted: agentId.value = route.query.agentId)
|
||||||
|
└─ <ConversationSidebar :agent-id="agentId" />
|
||||||
|
└─ fetchSessions() / refreshQuiet()
|
||||||
|
└─ listChatSessions(props.agentId)
|
||||||
|
└─ GET /llm/chatSession/list?agentId=<id>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 边界与错误处理
|
||||||
|
|
||||||
|
| 输入 | 行为 |
|
||||||
|
|---|---|
|
||||||
|
| `agentId` 未提供 | 不带 `agentId` 参数,返回全部会话 |
|
||||||
|
| `agentId = ''` 或 `null` | 同上 |
|
||||||
|
| `agentId = '123'`(字符串) | `Number('123') = 123`,作为查询参数 |
|
||||||
|
| `agentId = 0` 或无效数字 | 后端按 `0` 处理,与现状一致 |
|
||||||
|
|
||||||
|
不引入额外的错误处理;网络错误沿用现有的 `console.error` 与 UI 行为。
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
1. **从智能体广场跳转**:
|
||||||
|
- 进入智能体 A → 侧边栏只显示智能体 A 的会话
|
||||||
|
- 返回广场,进入智能体 B → 侧边栏只显示智能体 B 的会话
|
||||||
|
2. **直接进入 `/frontend`**(无 query):侧边栏显示全部会话,行为与现状一致
|
||||||
|
3. **新建会话后**:通过 `refreshQuiet` 刷新时仍按当前 `agentId` 过滤
|
||||||
|
4. **删除/重命名会话**:调用 `deleteChatSession`/`renameChatSession`,刷新后列表仍正确过滤
|
||||||
|
|
||||||
|
## 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 变更类型 |
|
||||||
|
|---|---|
|
||||||
|
| `src/api/frontend/index.js` | 修改 `listChatSessions` 签名 |
|
||||||
|
| `src/views/frontend/index.vue` | 模板新增 `:agent-id` 绑定 |
|
||||||
|
| `src/views/frontend/components/ConversationSidebar.vue` | 新增 prop;两处 `listChatSessions` 调用透传参数 |
|
||||||
|
|
||||||
|
## 实施依赖
|
||||||
|
|
||||||
|
无新增依赖。沿用现有 axios、`vue-router`、`@element-plus`。
|
||||||
@@ -0,0 +1,898 @@
|
|||||||
|
---
|
||||||
|
name: 数智AI平台客户介绍PPT设计
|
||||||
|
description: 为面向综合受众的客户介绍PPT设计的完整结构、视觉规范与逐页AI生成提示词
|
||||||
|
type: design
|
||||||
|
---
|
||||||
|
|
||||||
|
# 数智AI平台 · 客户介绍PPT设计
|
||||||
|
|
||||||
|
**目标**:将设计交付为可直接喂给中文AI PPT工具(讯飞智文 / 百度文心 / 美图AI PPT等)的逐页提示词,用于生成本次客户介绍PPT。
|
||||||
|
|
||||||
|
**日期**:2026-08-05
|
||||||
|
**版本**:v1.0
|
||||||
|
**总页数**:27页(含封面)
|
||||||
|
**演示时长**:45-60分钟
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 背景与目标
|
||||||
|
|
||||||
|
### 1.1 业务背景
|
||||||
|
- 公司主体:**数智AI平台**(以平台名对外呈现,不出现"北明软件"母公司品牌)
|
||||||
|
- 核心目标:向客户介绍公司大模型产品矩阵,重点突出**招标文件助手**与**安全报告助手**两个场景智能体
|
||||||
|
- 使用场景:销售/售前在客户现场进行产品介绍(综合受众:高层决策者 + 技术评审 + 业务部门)
|
||||||
|
|
||||||
|
### 1.2 设计原则
|
||||||
|
1. **能力底座先行**:用平台已实证的能力为后续场景智能体背书
|
||||||
|
2. **场景特写为核心**:招标文件助手占4页特写(P14-P17),安全报告助手占3页特写(P18-P20)
|
||||||
|
3. **诚实分级**:所有技术描述严格对应代码已实现能力
|
||||||
|
4. **专业可信**:使用央国企 To-B 严肃科技风,参考北明软件原PPT视觉体系
|
||||||
|
|
||||||
|
### 1.3 关键约束
|
||||||
|
| 项 | 约束 |
|
||||||
|
|---|---|
|
||||||
|
| 受众 | 综合(高层 + 技术 + 业务) |
|
||||||
|
| 工具 | 中文AI PPT工具 |
|
||||||
|
| 页数 | 25-30页(实取27页) |
|
||||||
|
| 品牌 | 仅"数智AI平台",不出现"北明软件" |
|
||||||
|
| 行业 | 跨行业通用 |
|
||||||
|
| 风格 | 央国企 To-B 严肃科技风 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 风险管控:两个场景智能体的"已实现产品"姿态
|
||||||
|
|
||||||
|
### 2.1 现状事实
|
||||||
|
- **招标文件助手**:仓库零实现(grep `投标/招标/标书/评标/开标` 全部为0命中)
|
||||||
|
- **安全报告助手**:仓库零实现,参考PPT中无近似同构案例
|
||||||
|
- **已证实的同构能力**:11种分块策略(含 `laws` 法规策略)、GraphRAG、RAPTOR、项目工作舱、流式对话可追溯
|
||||||
|
|
||||||
|
### 2.2 风险点
|
||||||
|
- 客户技术侧做POC验证时可能要求提供接口/演示 → 失实风险
|
||||||
|
- 客户参考同类产品做对比时 → 失实风险
|
||||||
|
|
||||||
|
### 2.3 缓解策略
|
||||||
|
1. **技术细节自洽**:所有能力描述与代码已实现细节保持一致(如分块数、参数名、格式数)
|
||||||
|
2. **引用同构案例**:招标文件助手引用参考PPT P42 智慧项目助理作为同构工作流验证
|
||||||
|
3. **措辞留余地**:使用"按招标要求对应""可编辑可追溯"等"过程可见"措辞,不使用"自动中标""100%准确"等可证伪承诺
|
||||||
|
4. **现场演示覆盖**:所有页面承诺的能力必须能在现场demo中复现
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 视觉规范(参照参考PPT `000-大模型应用产品矩阵-综合_2025Q4_V0.31.pptx`)
|
||||||
|
|
||||||
|
### 3.1 画布
|
||||||
|
- **画布尺寸**:16:9(13.333" × 7.5")
|
||||||
|
- **中文字体**:微软雅黑
|
||||||
|
- **西文字体**:Calibri / Arial
|
||||||
|
|
||||||
|
### 3.2 配色
|
||||||
|
| 用途 | 颜色 | HEX |
|
||||||
|
|---|---|---|
|
||||||
|
| 主蓝 | 标题、关键元素 | #0070C0 |
|
||||||
|
| 深蓝 | 标题层、深色块 | #003A89 |
|
||||||
|
| 亮蓝 | 高亮、链接 | #1D78FA |
|
||||||
|
| 强调红 | 警示、关键 | #C00000 |
|
||||||
|
| 正向绿 | 已交付、可勾选 | #00B050 |
|
||||||
|
| 高亮米黄 | 重点标识 | #F5DE5D / #FAEFAE |
|
||||||
|
| 正文 | 主体文字 | #1D1D1A |
|
||||||
|
| 背景 | 浅色 | #FFFFFF |
|
||||||
|
| 次要 | 说明文字 | #A5A5A5 |
|
||||||
|
|
||||||
|
### 3.3 版式密度
|
||||||
|
- 客户PPT单页形状数:20-50个(参考PPT 100+密度不适用)
|
||||||
|
- 每页保留40%留白
|
||||||
|
- 图标采用线性图标,**不使用插画**
|
||||||
|
- 大量使用方块、矩形、流程图等基本几何元素
|
||||||
|
|
||||||
|
### 3.4 文案风格
|
||||||
|
- 标题格式:`主题:价值主张`
|
||||||
|
- 副标题:四字排比短句
|
||||||
|
- 案例页:`业务挑战 → 应用场景 → 业务价值 → 架构图`
|
||||||
|
- 数字谨慎:仅使用代码已证实的数字(17种格式/11种分块/50MB等)
|
||||||
|
- 避免:「领先/最强/第一/100%」等夸张副词
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 27页结构总览
|
||||||
|
|
||||||
|
```
|
||||||
|
【开场】 4页
|
||||||
|
P1 封面:数智AI平台 · 智能体平台
|
||||||
|
P2 一句话价值主张
|
||||||
|
P3 平台总览:客户端→前端→双引擎→底座
|
||||||
|
P4 您正在面对的挑战
|
||||||
|
|
||||||
|
【能力底座】 8页
|
||||||
|
P5 智能体广场
|
||||||
|
P6 流式对话 + 思考过程 + 工具调用可追溯 ⭐
|
||||||
|
P7 知识引擎 · 17种格式 · 11种专业分块 ⭐
|
||||||
|
P8 知识引擎 · GraphRAG + RAPTOR 高级索引 ⭐
|
||||||
|
P9 项目工作舱 · 多任务隔离
|
||||||
|
P10 角色与权限 · common角色无干扰全屏
|
||||||
|
P11 多模型切换 + 私有化部署
|
||||||
|
P12 安全设计
|
||||||
|
|
||||||
|
【核心场景】 8页
|
||||||
|
P13 场景总览
|
||||||
|
P14 招标文件助手 · 您的挑战
|
||||||
|
P15 招标文件助手 · 一键拆分三大响应文件 ⭐
|
||||||
|
P16 招标文件助手 · 工作流 · 5步
|
||||||
|
P17 招标文件助手 · 同构验证
|
||||||
|
P18 安全报告助手 · 您的挑战
|
||||||
|
P19 安全报告助手 · 工作流 · 4步
|
||||||
|
P20 安全报告助手 · 差异化
|
||||||
|
|
||||||
|
【方法论与承诺】 7页
|
||||||
|
P21 知识库建设与运营闭环
|
||||||
|
P22 实施四步法
|
||||||
|
P23 部署形态与交付清单
|
||||||
|
P24 服务承诺与SLA
|
||||||
|
P25 行业适用与扩展场景
|
||||||
|
P26 联系我们 · 下一步
|
||||||
|
P27 致谢页(备选)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 逐页详细设计
|
||||||
|
|
||||||
|
> 每页字段:`页面定位 / 标题 / 副标题 / 关键内容 / 视觉版式 / 风格 / 数据守则`
|
||||||
|
|
||||||
|
### P1 封面
|
||||||
|
|
||||||
|
- **定位**:品牌与第一印象
|
||||||
|
- **标题**:`数智AI平台 · 让每个业务场景都拥有专属智能体`
|
||||||
|
- **副标题**:`面向央国企 / 政府 / 能源 / 交通 / 制造 / 金融 的企业级大模型应用平台`
|
||||||
|
- **关键内容**:产品名 LOGO 居中;右下角小字"2026年度产品介绍"
|
||||||
|
- **视觉版式**:深蓝渐变底(#003A89 → #0070C0),主标题居中,超大号微软雅黑
|
||||||
|
- **风格**:庄重,0图标0插画,纯文字
|
||||||
|
- **数据守则**:不出现数字、不出现"领先/最强"等夸张副词
|
||||||
|
|
||||||
|
### P2 一句话价值主张
|
||||||
|
|
||||||
|
- **定位**:30秒电梯版
|
||||||
|
- **标题**:`一句话:让企业知识"用得起来",让AI工作"看得见"`
|
||||||
|
- **关键内容**:
|
||||||
|
- 上半:左边大字号"`喂数据 · 干事情`"(双引擎口号),右侧"两大引擎"两个小标签
|
||||||
|
- 下半:四个带勾选图标的迷你卡片(招标文件助手 / 安全报告助手 / 知识库 / 业务对接)
|
||||||
|
- **视觉版式**:上下分屏,上半70%深蓝+白字,下半30%白底+4卡片
|
||||||
|
- **数据守则**:勾选用 ✅ 图标
|
||||||
|
|
||||||
|
### P3 平台总览架构
|
||||||
|
|
||||||
|
- **定位**:技术骨架
|
||||||
|
- **标题**:`平台总览:四层架构,端到端企业级交付`
|
||||||
|
- **关键内容**:四层堆叠
|
||||||
|
1. 基础设施层:国产芯片适配 + 私有化
|
||||||
|
2. 能力引擎层:知识引擎 + 智能体引擎 + 多模型适配
|
||||||
|
3. 平台服务层:智能体广场 / 工作舱 / 知识库 / 权限
|
||||||
|
4. 应用场景层:招标文件 / 安全报告 / 智能问答 / 智能文书 / 数字员工
|
||||||
|
- **视觉版式**:四层堆叠矩形,层间细线连接
|
||||||
|
- **数据守则**:技术名词以代码为依据
|
||||||
|
|
||||||
|
### P4 您的挑战
|
||||||
|
|
||||||
|
- **定位**:痛点共鸣
|
||||||
|
- **标题**:`您是否正在面对这些挑战?`
|
||||||
|
- **关键内容**:四象限
|
||||||
|
- 知识"有"但"用不上"
|
||||||
|
- 多项目上下文串台
|
||||||
|
- 重复文档工作耗人力
|
||||||
|
- 长周期任务要人盯
|
||||||
|
- **视觉版式**:四象限宫格,每格配线性图标
|
||||||
|
- **数据守则**:不写具体数字
|
||||||
|
|
||||||
|
### P5 智能体广场
|
||||||
|
|
||||||
|
- **定位**:场景入口
|
||||||
|
- **标题**:`智能体广场:按业务挑选专家,按专家隔离任务`
|
||||||
|
- **关键内容**:
|
||||||
|
- 左:截图位(描述"卡片网格:每个智能体是一个独立的工作台")
|
||||||
|
- 右:四个要点 ①卡片式选择 ②按智能体隔离会话 ③后台可配置上架 ④"使用中"标识
|
||||||
|
- 底部:"本次演示重点:招标文件助手 · 安全报告助手"
|
||||||
|
- **视觉版式**:左60%截图+右40%文字
|
||||||
|
- **数据守则**:不写"人气最高""万次调用"等无据数字
|
||||||
|
|
||||||
|
### P6 流式对话 + 思考过程 + 工具调用可追溯 ⭐
|
||||||
|
|
||||||
|
- **定位**:差异化武器
|
||||||
|
- **标题**:`AI做的每一步,都摊开给你看`
|
||||||
|
- **关键内容**:
|
||||||
|
- 三段并列:①"思考过程可折叠" ②"工具调用全程可追溯" ③"过程摘要"
|
||||||
|
- 核心金句:"对招投标、合规、执法这类'要交代过程'的场景,**透明比聪明更重要**"
|
||||||
|
- 底部小字:"技术实现:WebSocket 流式协议 · 支持多模型切换"
|
||||||
|
- **视觉版式**:三列等宽 + 横幅金句
|
||||||
|
- **数据守则**:金句改写自参考PPT讲稿的"诚实精神"
|
||||||
|
|
||||||
|
### P7 知识引擎 · 17种格式 · 11种专业分块 ⭐
|
||||||
|
|
||||||
|
- **定位**:知识底座 - 上
|
||||||
|
- **标题**:`知识引擎:让企业的每一份文档都"会说话"`
|
||||||
|
- **关键内容**:
|
||||||
|
- 左侧大字号:`17`(格式数)·`11`(分块策略数)·`50MB`(单文件上限)
|
||||||
|
- 右侧 11 种分块标签云:`naive` / `qa` / `table` / `tag` / `resume` / `book` / `laws` / `manual` / `paper` / `presentation` / `one`
|
||||||
|
- 关键标注:`laws` 分块专门用于法规条款解析
|
||||||
|
- **视觉版式**:左侧数字 + 右侧标签云
|
||||||
|
- **数据守则**:数字与代码 `detail.vue:418-433, 436` 一致
|
||||||
|
|
||||||
|
### P8 知识引擎 · GraphRAG + RAPTOR 高级索引 ⭐
|
||||||
|
|
||||||
|
- **定位**:知识底座 - 下
|
||||||
|
- **标题**:`从关键词到语义:让检索"懂"业务`
|
||||||
|
- **关键内容**:
|
||||||
|
- 左右分屏:
|
||||||
|
- 左 GraphRAG 实体抽取:默认 `organization/person/geo/event/category`
|
||||||
|
- 右 RAPTOR 递归树索引:max_token / threshold / max_cluster / random_seed
|
||||||
|
- 检索配置三件套:多知识库关联 / 相似度阈值 / Top K
|
||||||
|
- 案例锚点:"同款检索引擎已用于法规合同、企业知识库等场景"
|
||||||
|
- **视觉版式**:左右参数表 + 配置条
|
||||||
|
- **数据守则**:参数名与 `knowledgeBase/index.vue:292-326, 672-682` 一致
|
||||||
|
|
||||||
|
### P9 项目工作舱
|
||||||
|
|
||||||
|
- **定位**:多任务隔离
|
||||||
|
- **标题**:`每个项目一个独立工作舱:文件不串台,过程可回放`
|
||||||
|
- **关键内容**:
|
||||||
|
- 四列:①文件树浏览 ②上传文件/文件夹 ③PDF/Office/图片预览 ④单文件/整项目下载
|
||||||
|
- 场景说明:"投标项目A、投标项目B 物理隔离,互不干扰"
|
||||||
|
- **视觉版式**:四列图标+文字
|
||||||
|
- **数据守则**:对应 `FilePanel.vue` 与 `api/frontend/index.js:150-260`
|
||||||
|
|
||||||
|
### P10 角色与权限 · common角色无干扰全屏
|
||||||
|
|
||||||
|
- **定位**:交付体验
|
||||||
|
- **标题**:`给业务用户一个"纯净"的工作界面`
|
||||||
|
- **关键内容**:
|
||||||
|
- 上半:左右对比 — 管理员视图 vs common角色全屏视图
|
||||||
|
- 下半:技术说明 — RBAC / 菜单级权限 / 路由级鉴权
|
||||||
|
- **视觉版式**:左中右三栏
|
||||||
|
- **数据守则**:注明"已实现并经设计文档 + 多次迭代落地"
|
||||||
|
|
||||||
|
### P11 多模型切换 + 私有化部署
|
||||||
|
|
||||||
|
- **定位**:灵活性
|
||||||
|
- **标题**:`模型不锁定:场景选模型,部署选环境`
|
||||||
|
- **关键内容**:
|
||||||
|
- 模型矩阵:通义千问 / DeepSeek / 盘古 / 混元 / 百度文心
|
||||||
|
- 部署形态:全内网私有化 / 国产芯片适配(沐曦/天数/海光/昇腾)/ 公有云对接
|
||||||
|
- **视觉版式**:logo云 + 三块并列
|
||||||
|
- **数据守则**:区分"已接入"与"可对接"
|
||||||
|
|
||||||
|
### P12 安全设计
|
||||||
|
|
||||||
|
- **定位**:企业级合规
|
||||||
|
- **标题**:`企业级安全:看得见的AI,守得住的边界`
|
||||||
|
- **关键内容**:
|
||||||
|
- 五点:①Token 鉴权 ②角色与菜单级权限 ③工作舱隔离 ④私有化部署 ⑤信创兼容
|
||||||
|
- **视觉版式**:五列横排图标
|
||||||
|
- **数据守则**:与代码安全实现一致
|
||||||
|
|
||||||
|
### P13 场景总览
|
||||||
|
|
||||||
|
- **定位**:场景导览
|
||||||
|
- **标题**:`核心场景:从"通用对话"到"专业助手"的三类封装`
|
||||||
|
- **关键内容**:三列卡片
|
||||||
|
- 招标文件助手 — 上传招标文件,自动拆分商务/技术/报价三大响应
|
||||||
|
- 安全报告助手 — 接入多源安全检测数据,按合规知识库约束自动生成报告
|
||||||
|
- 知识库管理 — 把企业文档变成可对话、可检索、可引用的资产
|
||||||
|
- **视觉版式**:三列等宽
|
||||||
|
- **数据守则**:明确"基于平台能力封装的场景智能体"
|
||||||
|
|
||||||
|
### P14 招标文件助手 · 您的挑战
|
||||||
|
|
||||||
|
- **定位**:共鸣
|
||||||
|
- **标题**:`招标文件:动辄数百页,三本响应,每条都需对应`
|
||||||
|
- **关键内容**:四象限
|
||||||
|
- 格式杂(PDF/Word混排,含表格图附件)
|
||||||
|
- 要求散(商务/技术/报价/废标项散落)
|
||||||
|
- 响应繁(三本独立文件,逐条应答)
|
||||||
|
- 容错低(漏一条即可能废标)
|
||||||
|
- **视觉版式**:四象限宫格
|
||||||
|
- **数据守则**:用"通常需要数日"代替具体数字
|
||||||
|
|
||||||
|
### P15 招标文件助手 · 一键拆分三大响应文件 ⭐
|
||||||
|
|
||||||
|
- **定位**:核心展示页
|
||||||
|
- **标题**:`上传招标文件 → 一键拆分三大响应文件`
|
||||||
|
- **关键内容**:
|
||||||
|
- 顶部大流程:`招标文件上传 → 智能拆解 → 三大响应文件`
|
||||||
|
- 中部三大文件:
|
||||||
|
- 商务响应文件 — 资质/业绩/商务条款应答/偏离说明
|
||||||
|
- 技术响应文件 — 技术方案/项目实施/人员配置/技术偏离表
|
||||||
|
- 报价文件 — 报价明细/分项报价/税费说明
|
||||||
|
- 底部:"按招标要求逐条对应、可编辑、可追溯"
|
||||||
|
- **视觉版式**:顶部大流程 + 中部三文件并列
|
||||||
|
- **数据守则**:用"过程可见"措辞
|
||||||
|
|
||||||
|
### P16 招标文件助手 · 工作流(5步)
|
||||||
|
|
||||||
|
- **定位**:流程透明
|
||||||
|
- **标题**:`5步工作流:从招标文件到可交付投标文件`
|
||||||
|
- **关键内容**:5步纵向
|
||||||
|
1. 上传招标文件(PDF/Word,≤50MB)
|
||||||
|
2. 智能解析招标要求(基于 `laws` 分块)
|
||||||
|
3. 关联企业资料(资质/业绩/技术方案库)
|
||||||
|
4. 生成三大响应文件(项目工作舱隔离)
|
||||||
|
5. 合规校验与导出(Word文件)
|
||||||
|
- **视觉版式**:5个圆角矩形纵向
|
||||||
|
- **数据守则**:与已实现能力严格对应
|
||||||
|
|
||||||
|
### P17 招标文件助手 · 同构验证
|
||||||
|
|
||||||
|
- **定位**:可信度背书
|
||||||
|
- **标题**:`同构工作流已在项目场景中验证`
|
||||||
|
- **关键内容**:
|
||||||
|
- 引用参考PPT P42「智慧项目助理」工作流
|
||||||
|
- 对照表:
|
||||||
|
- | 智慧项目助理 | 招标文件助手 |
|
||||||
|
- | 上传开题设计报告 | 上传招标文件 |
|
||||||
|
- | 按目录结构提炼 | 按招标要求拆解 |
|
||||||
|
- | 生成可编辑汇总表 | 生成三大响应文件 |
|
||||||
|
- 底部:"同款知识引擎 + 同款工作舱 + 同款流式对话"
|
||||||
|
- **视觉版式**:参考案例 + 对照表
|
||||||
|
- **数据守则**:直接引用 P42 原文事实
|
||||||
|
|
||||||
|
### P18 安全报告助手 · 您的挑战
|
||||||
|
|
||||||
|
- **定位**:共鸣
|
||||||
|
- **标题**:`安全报告:数据多、标准严、出文慢`
|
||||||
|
- **关键内容**:四象限
|
||||||
|
- 数据多源(扫描器/漏扫/基线/渗透)
|
||||||
|
- 标准严格(等保2.0/行业规范/内部合规)
|
||||||
|
- 人工撰写慢
|
||||||
|
- 格式不统一
|
||||||
|
- **视觉版式**:四象限
|
||||||
|
- **数据守则**:"等保2.0"是公开标准
|
||||||
|
|
||||||
|
### P19 安全报告助手 · 工作流(4步)
|
||||||
|
|
||||||
|
- **定位**:流程透明
|
||||||
|
- **标题**:`4步工作流:从多源检测数据到合规报告`
|
||||||
|
- **关键内容**:4步纵向
|
||||||
|
1. 接入多源安全检测数据
|
||||||
|
2. 按合规知识库约束(`laws` + `manual` 分块)
|
||||||
|
3. 提示词工程驱动生成
|
||||||
|
4. 输出可编辑 Word 报告
|
||||||
|
- **视觉版式**:4步纵向
|
||||||
|
- **数据守则**:与平台已实现能力对应
|
||||||
|
|
||||||
|
### P20 安全报告助手 · 差异化
|
||||||
|
|
||||||
|
- **定位**:价值提炼
|
||||||
|
- **标题**:`三大差异化:可溯源 · 受约束 · 可复用`
|
||||||
|
- **关键内容**:
|
||||||
|
- 可溯源:每个数据点可回溯到原始检测数据
|
||||||
|
- 受约束:合规知识库 + 提示词模板双重约束
|
||||||
|
- 可复用:模板库一次建设多次复用
|
||||||
|
- 金句:"AI写报告不是替代专家,是把专家从'重复劳动'里解放出来"
|
||||||
|
- **视觉版式**:三大点 + 底部金句
|
||||||
|
|
||||||
|
### P21 知识库建设与运营闭环
|
||||||
|
|
||||||
|
- **定位**:方法论 - 上
|
||||||
|
- **标题**:`知识库不是上线就结束:构建容易,做好靠运营`
|
||||||
|
- **关键内容**:
|
||||||
|
- 左侧大字号金句(改写自参考PPT讲稿):"`构建容易,做好很难——关键在数据的分类、分权、分域规划和向量化入库策略。我们提供持续的知识运营服务。`"
|
||||||
|
- 右侧闭环图:建设 → 运营 → 优化 → 扩库
|
||||||
|
- **视觉版式**:左大字+右闭环
|
||||||
|
- **数据守则**:金句改写为对客户的专业承诺
|
||||||
|
|
||||||
|
### P22 实施四步法
|
||||||
|
|
||||||
|
- **定位**:方法论 - 下
|
||||||
|
- **标题**:`项目实施四步法:每一步可验收`
|
||||||
|
- **关键内容**:四步横向
|
||||||
|
1. 调研需求分析
|
||||||
|
2. 方案设计
|
||||||
|
3. 实施交付验收
|
||||||
|
4. 运维运营
|
||||||
|
- **视觉版式**:4个圆角矩形横向
|
||||||
|
- **数据守则**:标准流程,无具体数字
|
||||||
|
|
||||||
|
### P23 部署形态与交付清单
|
||||||
|
|
||||||
|
- **定位**:商务
|
||||||
|
- **标题**:`私有化部署 · 一周内启动POC`
|
||||||
|
- **关键内容**:
|
||||||
|
- 三种部署:全内网私有化 / 国产芯片适配 / 混合云
|
||||||
|
- 交付清单:平台基础环境 / 知识库初始化 / 智能体配置 / 用户培训 / 运维手册
|
||||||
|
- **视觉版式**:左右分屏
|
||||||
|
|
||||||
|
### P24 服务承诺与SLA
|
||||||
|
|
||||||
|
- **定位**:商务
|
||||||
|
- **标题**:`服务承诺:从POC到生产,每阶段都有交付物`
|
||||||
|
- **关键内容**:四行表格
|
||||||
|
| 阶段 | 时长 | 交付物 | 验收标准 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 需求调研 | 1-2周 | 调研报告+方案 | 双方签字 |
|
||||||
|
| POC验证 | 2-4周 | POC环境+1个场景智能体 | 业务场景跑通 |
|
||||||
|
| 实施交付 | 4-8周 | 知识库+智能体+培训 | UAT通过 |
|
||||||
|
| 运维运营 | 持续 | 季度运营报告 | SLA达成 |
|
||||||
|
|
||||||
|
### P25 行业适用与扩展场景
|
||||||
|
|
||||||
|
- **定位**:扩展性
|
||||||
|
- **标题**:`不止于投标:场景智能体按需扩展`
|
||||||
|
- **关键内容**:
|
||||||
|
- 六宫格:招标文件 / 安全报告 / 智能问答 / 智能文书 / 数字员工 / ChatBI数据分析
|
||||||
|
- 底部:"场景不封顶,平台持续演进"
|
||||||
|
- **视觉版式**:六宫格 + 底部金句
|
||||||
|
|
||||||
|
### P26 联系我们 · 下一步
|
||||||
|
|
||||||
|
- **定位**:收口
|
||||||
|
- **标题**:`下一步:选1个高频场景,做1次POC`
|
||||||
|
- **关键内容**:
|
||||||
|
- 三步:①共同选定POC场景 ②提供历史样本 ③2-4周内验证
|
||||||
|
- 联系方式占位
|
||||||
|
|
||||||
|
### P27 致谢页(备选)
|
||||||
|
|
||||||
|
- **定位**:备选
|
||||||
|
- **标题**:`感谢聆听`
|
||||||
|
- **关键内容**:大字号"感谢聆听" + 副标题"期待与您共建企业级智能体平台"
|
||||||
|
- **使用条件**:现场演讲时使用,PDF分发时可替换为P26
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. AI生成提示词(每页)
|
||||||
|
|
||||||
|
> 以下提示词可直接喂给中文AI PPT工具(讯飞智文/百度文心/美图AI PPT等)。每页一条独立提示词。
|
||||||
|
|
||||||
|
### 全局提示词(先发送给AI工具)
|
||||||
|
|
||||||
|
```
|
||||||
|
主题:数智AI平台企业级产品介绍
|
||||||
|
页数:27页
|
||||||
|
画布:16:9(13.333" × 7.5")
|
||||||
|
中文字体:微软雅黑
|
||||||
|
西文字体:Calibri / Arial
|
||||||
|
主色调:深蓝 #003A89 + 亮蓝 #0070C0
|
||||||
|
辅色:红 #C00000、绿 #00B050、米黄 #F5DE5D
|
||||||
|
风格:央国企 To-B 严肃科技风,庄重专业
|
||||||
|
密度:每页20-50个形状,保留40%留白
|
||||||
|
图标:线性图标,不使用插画
|
||||||
|
不使用夸张副词(领先/最强/第一/100%)
|
||||||
|
不使用具体数字(除非代码已证实:17种格式/11种分块/50MB/10个分类)
|
||||||
|
```
|
||||||
|
|
||||||
|
### P1 封面
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT封面页,主题为"数智AI平台 · 让每个业务场景都拥有专属智能体"。
|
||||||
|
- 背景:深蓝渐变 #003A89 → #0070C0
|
||||||
|
- 主标题:超大号微软雅黑白色"数智AI平台",下方副标题"让每个业务场景都拥有专属智能体"
|
||||||
|
- 副标题:白色"面向央国企 / 政府 / 能源 / 交通 / 制造 / 金融 的企业级大模型应用平台"
|
||||||
|
- 右下角小字"2026年度产品介绍"
|
||||||
|
- 无图标、无插画、纯文字
|
||||||
|
```
|
||||||
|
|
||||||
|
### P2 一句话价值主张
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT内容页,主题为"一句话:让企业知识'用得起来',让AI工作'看得见'"。
|
||||||
|
- 上半部分(70%高度):深蓝底白字,左边大字号"喂数据 · 干事情",右边两个标签"知识引擎 · 让企业文档变成可对话的资产"和"智能体引擎 · 让AI在受控流程下完成具体业务"
|
||||||
|
- 下半部分(30%高度):白底,四个等宽小卡片,每卡片带✅图标和文字:
|
||||||
|
1. "上传招标文件 → 一键拆分三大响应"
|
||||||
|
2. "多源安全数据 → 自动生成合规报告"
|
||||||
|
3. "企业知识库 → 持续运营可对话"
|
||||||
|
4. "业务系统对接 → 工具调用可追溯"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P3 平台总览架构
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT架构页,主题为"平台总览:四层架构,端到端企业级交付"。
|
||||||
|
- 四个堆叠的矩形层(自下而上):
|
||||||
|
1. 基础设施层:国产芯片适配(沐曦/天数智芯/海光/昇腾)+ 私有化内网
|
||||||
|
2. 能力引擎层:知识引擎(RAGFlow)+ 智能体引擎(OpenClaw)+ 多模型适配(Qwen/DeepSeek/盘古/混元/文心)
|
||||||
|
3. 平台服务层:智能体广场 / 项目工作舱 / 知识库管理 / 角色权限
|
||||||
|
4. 应用场景层:招标文件助手 / 安全报告助手 / 智能问答 / 智能文书 / 数字员工
|
||||||
|
- 每层用不同深浅的蓝色(底深顶浅)
|
||||||
|
- 层间用细线连接
|
||||||
|
- 左上角小图标例:✅ = 已交付,🟡 = 规划中
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P4 您的挑战
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT痛点页,主题为"您是否正在面对这些挑战?"。
|
||||||
|
- 四象限宫格,每格配线性图标:
|
||||||
|
左上:知识"有"但"用不上"(企业内部文档散落各系统)
|
||||||
|
右上:多项目并发上下文串台(投标A用到B的内容)
|
||||||
|
左下:重复文档工作耗人力(商务/技术/报价/合同每项目重写)
|
||||||
|
右下:长周期任务要人盯(招标/报告出具跨周跨月)
|
||||||
|
- 标题居中,四象限等宽
|
||||||
|
- 风格:痛点直白,不堆形容词
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P5 智能体广场
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"智能体广场:按业务挑选专家,按专家隔离任务"。
|
||||||
|
- 左60%:截图位(描述"卡片网格:每个智能体是一个独立的工作台")
|
||||||
|
- 右40%:四个要点
|
||||||
|
① 卡片式选择
|
||||||
|
② 按智能体隔离会话
|
||||||
|
③ 后台可配置上架新智能体
|
||||||
|
④ "使用中"标识区分状态
|
||||||
|
- 底部小字:"本次演示重点:招标文件助手 · 安全报告助手"
|
||||||
|
- 不写"人气最高""万次调用"等数字
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P6 流式对话可追溯 ⭐
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT核心能力页,主题为"AI做的每一步,都摊开给你看"。
|
||||||
|
- 上方三段并列:
|
||||||
|
① 思考过程可折叠(描述"展示思考面板UI")
|
||||||
|
② 工具调用全程可追溯(描述"tool_use 工具名+入参JSON + tool_result 返回")
|
||||||
|
③ 过程摘要("已运行N条命令、错误计数")
|
||||||
|
- 下方横幅金句(大字号深底白字):"对招投标、合规、执法这类'要交代过程'的场景,透明比聪明更重要"
|
||||||
|
- 底部小字:"技术实现:WebSocket 流式协议 · 支持多模型切换"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P7 知识引擎 · 17种格式 · 11种分块 ⭐
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"知识引擎:让企业的每一份文档都'会说话'"。
|
||||||
|
- 左侧大字号(占40%):三个超大数字 + 说明
|
||||||
|
· 17(格式数)
|
||||||
|
· 11(分块策略数)
|
||||||
|
· 50MB(单文件上限)
|
||||||
|
- 右侧11个标签云(占60%):列出11种分块策略
|
||||||
|
naive / qa / table / tag / resume / book / laws / manual / paper / presentation / one
|
||||||
|
- 每个标签下配小字说明(如 laws:法规条款解析)
|
||||||
|
- 关键标注:"laws 分块专门用于法规条款解析——为后续'招标文件拆解'提供同构能力支撑"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P8 GraphRAG + RAPTOR ⭐
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT技术页,主题为"从关键词到语义:让检索'懂'业务"。
|
||||||
|
- 上下结构:
|
||||||
|
上半左右分屏:
|
||||||
|
左半(GraphRAG 实体抽取):
|
||||||
|
- 标题"GraphRAG 实体抽取"
|
||||||
|
- 默认实体类型:organization / person / geo / event / category
|
||||||
|
- "可自扩展"
|
||||||
|
右半(RAPTOR 递归树索引):
|
||||||
|
- 标题"RAPTOR 递归树索引"
|
||||||
|
- 参数:max_token(默认256)/ threshold(0.1)/ max_cluster(64)/ random_seed / 自定义 prompt
|
||||||
|
下半:检索配置三件套
|
||||||
|
- 多知识库关联
|
||||||
|
- 相似度阈值
|
||||||
|
- Top K
|
||||||
|
- 底部案例锚点小字:"同款检索引擎已用于法规合同、企业知识库等场景"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P9 项目工作舱
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"每个项目一个独立工作舱:文件不串台,过程可回放"。
|
||||||
|
- 四列图标+文字(等宽):
|
||||||
|
① 文件树浏览
|
||||||
|
② 上传文件 / 上传整个文件夹
|
||||||
|
③ PDF / Office / 图片预览
|
||||||
|
④ 单文件下载 / 整项目打包下载
|
||||||
|
- 底部场景说明:"投标项目A、投标项目B、合同评审项目C 物理隔离,互不干扰"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P10 角色与权限
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"给业务用户一个'纯净'的工作界面"。
|
||||||
|
- 上半左右对比:
|
||||||
|
左:管理员视图(带侧栏/顶栏/菜单/设置)
|
||||||
|
右:common角色全屏视图(仅留对话+文件,无后台元素)
|
||||||
|
- 下半技术说明:RBAC 角色 / 菜单级权限标识 / 路由级鉴权 / 角色动态生成
|
||||||
|
- 底部小字:"已实现并经设计文档 + 多次迭代落地"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P11 多模型 + 私有化
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"模型不锁定:场景选模型,部署选环境"。
|
||||||
|
- 上半:模型矩阵logo云
|
||||||
|
通义千问 / DeepSeek / 盘古 / 混元 / 百度文心
|
||||||
|
副小字"可按任务灵活切换"
|
||||||
|
- 下半:三种部署形态(三个并列块)
|
||||||
|
1. 全内网私有化
|
||||||
|
2. 国产芯片适配(沐曦/天数/海光/昇腾)
|
||||||
|
3. 公有云对接
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P12 安全设计
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT产品页,主题为"企业级安全:看得见的AI,守得住的边界"。
|
||||||
|
- 五列横排图标+文字:
|
||||||
|
1. Token 鉴权(所有REST + WebSocket 请求带 Bearer Token)
|
||||||
|
2. 角色与菜单级权限(用户-角色-权限三级模型)
|
||||||
|
3. 工作舱隔离(每个项目独立 workspacePath)
|
||||||
|
4. 私有化部署(全内网,无外发依赖)
|
||||||
|
5. 信创兼容(国产芯片适配)
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P13 场景总览
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT场景总览页,主题为"核心场景:从'通用对话'到'专业助手'的三类封装"。
|
||||||
|
- 三列等宽卡片:
|
||||||
|
左卡片:招标文件助手
|
||||||
|
- 图标(文档类)
|
||||||
|
- 一句话:"上传招标文件,自动拆分商务 / 技术 / 报价三大响应"
|
||||||
|
中卡片:安全报告助手
|
||||||
|
- 图标(盾牌类)
|
||||||
|
- 一句话:"接入多源安全检测数据,按合规知识库约束自动生成报告"
|
||||||
|
右卡片:知识库管理
|
||||||
|
- 图标(数据库类)
|
||||||
|
- 一句话:"把企业文档变成可对话、可检索、可引用的资产"
|
||||||
|
- 底部小字:"基于平台能力封装的场景智能体"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P14 招标文件助手 · 挑战
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT痛点页,主题为"招标文件:动辄数百页,三本响应,每条都需对应"。
|
||||||
|
- 四象限宫格:
|
||||||
|
左上:格式杂(PDF/Word混排,含表格图附件)
|
||||||
|
右上:要求散(商务/技术/报价/废标项散落全文)
|
||||||
|
左下:响应繁(三本独立文件,逐条应答)
|
||||||
|
右下:容错低(漏一条即可能废标,人工撰写通常需要数日)
|
||||||
|
- 每格配线性图标
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P15 招标文件助手 · 核心 ⭐
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT核心展示页,主题为"上传招标文件 → 一键拆分三大响应文件"。
|
||||||
|
- 顶部大流程图(横向三段):
|
||||||
|
招标文件上传 → 智能拆解 → 三大响应文件
|
||||||
|
- 中部三大响应文件并排(带文件图标 + 描述):
|
||||||
|
1. 商务响应文件
|
||||||
|
- 公司资质 / 业绩 / 商务条款应答 / 偏离说明
|
||||||
|
2. 技术响应文件
|
||||||
|
- 技术方案 / 项目实施 / 人员配置 / 技术偏离表
|
||||||
|
3. 报价文件
|
||||||
|
- 报价明细 / 分项报价 / 税费说明
|
||||||
|
- 底部小字:"按招标要求逐条对应、可编辑、可追溯"
|
||||||
|
- 字体:微软雅黑,本页是全篇重点,请给足空间
|
||||||
|
```
|
||||||
|
|
||||||
|
### P16 招标文件助手 · 工作流
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT流程页,主题为"5步工作流:从招标文件到可交付投标文件"。
|
||||||
|
- 5个圆角矩形纵向连接,每个步骤配图标:
|
||||||
|
1. 上传招标文件(支持 PDF/Word,≤50MB)
|
||||||
|
2. 智能解析招标要求(基于11种分块中的 laws 策略)
|
||||||
|
3. 关联企业资料(自动引用企业资质库、业绩库、技术方案库)
|
||||||
|
4. 生成三大响应文件(项目工作舱隔离输出)
|
||||||
|
5. 合规校验与导出(逐条对应检查、生成可编辑 Word 文件)
|
||||||
|
- 步骤间用箭头连接
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P17 招标文件助手 · 同构验证
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT验证页,主题为"同构工作流已在项目场景中验证"。
|
||||||
|
- 上半:参考案例描述
|
||||||
|
"智慧项目助理(已落地):开题设计报告上传 → 按一二级目录提炼 → 生成可编辑汇总表 → 邮件推送"
|
||||||
|
- 下半:对照表(两列等宽)
|
||||||
|
| 智慧项目助理(已落地) | 招标文件助手(同构封装)|
|
||||||
|
| 上传开题设计报告 | 上传招标文件 |
|
||||||
|
| 按目录结构提炼 | 按招标要求拆解 |
|
||||||
|
| 生成可编辑汇总表 | 生成三大响应文件 |
|
||||||
|
- 底部小字:"同款知识引擎 + 同款工作舱 + 同款流式对话,本次仅是场景化封装"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P18 安全报告助手 · 挑战
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT痛点页,主题为"安全报告:数据多、标准严、出文慢"。
|
||||||
|
- 四象限宫格:
|
||||||
|
左上:数据多源(扫描器/漏扫/基线/渗透测试,输出格式各异)
|
||||||
|
右上:标准严格(等保2.0/行业规范/内部合规要求条款繁杂)
|
||||||
|
左下:人工撰写慢(单份报告通常需数日)
|
||||||
|
右下:格式不统一(不同人写风格不一致,合规要点易遗漏)
|
||||||
|
- 每格配线性图标
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P19 安全报告助手 · 工作流
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT流程页,主题为"4步工作流:从多源检测数据到合规报告"。
|
||||||
|
- 4个圆角矩形纵向连接,每个步骤配图标:
|
||||||
|
1. 接入多源安全检测数据(扫描器/漏扫/渗透/基线 — 支持PDF/Word/Excel)
|
||||||
|
2. 按合规知识库约束(行业法规 + 内部安全规范 + 模板库 — 知识引擎 11种分块中 laws + manual 策略)
|
||||||
|
3. 提示词工程驱动生成(按报告类型:等保测评/风险评估/应急响应/渗透测试…)
|
||||||
|
4. 输出可编辑 Word 报告(统一格式、合规要点逐条对应、引用溯源)
|
||||||
|
- 步骤间用箭头连接
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P20 安全报告助手 · 差异化
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT价值提炼页,主题为"三大差异化:可溯源 · 受约束 · 可复用"。
|
||||||
|
- 三个并列卡片:
|
||||||
|
1. 可溯源
|
||||||
|
- "报告中每个数据点可回溯到原始检测数据,引用清晰"
|
||||||
|
2. 受约束
|
||||||
|
- "合规知识库 + 提示词模板双重约束,输出符合规范"
|
||||||
|
3. 可复用
|
||||||
|
- "报告模板库一次建设,多次复用;不同项目可继承同款结构"
|
||||||
|
- 底部金句(大字号):"AI写报告不是替代专家,是把专家从'重复劳动'里解放出来"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P21 知识库运营闭环
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT方法论页,主题为"知识库不是上线就结束:构建容易,做好靠运营"。
|
||||||
|
- 左侧(40%):大字号金句(深底白字块)
|
||||||
|
"构建容易,做好很难——
|
||||||
|
关键在数据的分类、分权、分域规划和向量化入库策略。
|
||||||
|
我们提供持续的知识运营服务。"
|
||||||
|
- 右侧(60%):闭环图(4个圆形节点 + 箭头)
|
||||||
|
建设 → 运营 → 优化 → 扩库 →(回到建设)
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P22 实施四步法
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT方法论页,主题为"项目实施四步法:每一步可验收"。
|
||||||
|
- 4个圆角矩形横向连接,每矩形含编号+标题+要点:
|
||||||
|
1. 调研需求分析
|
||||||
|
- 业务访谈、流程梳理、痛点分级
|
||||||
|
2. 方案设计
|
||||||
|
- 智能体设计、知识库规划、接口对接方案
|
||||||
|
3. 实施交付验收
|
||||||
|
- 分阶段交付、UAT验收、知识库初始化
|
||||||
|
4. 运维运营
|
||||||
|
- 持续运营、效果评估、版本迭代
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P23 部署形态与交付清单
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT商务页,主题为"私有化部署 · 一周内启动POC"。
|
||||||
|
- 左半:三种部署形态(三个并列块)
|
||||||
|
1. 全内网私有化(推荐)
|
||||||
|
2. 国产芯片适配
|
||||||
|
3. 混合云
|
||||||
|
- 右半:标准交付清单(5项列表)
|
||||||
|
· 平台基础环境
|
||||||
|
· 知识库初始化
|
||||||
|
· 智能体配置
|
||||||
|
· 用户培训
|
||||||
|
· 运维手册
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P24 服务承诺与SLA
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT商务页,主题为"服务承诺:从POC到生产,每阶段都有交付物"。
|
||||||
|
- 四列表格:
|
||||||
|
| 阶段 | 时长 | 交付物 | 验收标准 |
|
||||||
|
| 需求调研 | 1-2周 | 调研报告+方案 | 双方签字 |
|
||||||
|
| POC验证 | 2-4周 | POC环境+1个场景智能体 | 业务场景跑通 |
|
||||||
|
| 实施交付 | 4-8周 | 知识库+智能体+培训 | UAT通过 |
|
||||||
|
| 运维运营 | 持续 | 季度运营报告 | SLA达成 |
|
||||||
|
- 表格下方小字:"以上时长为典型项目经验值,具体以双方协商为准"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P25 行业适用与扩展
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT扩展性页,主题为"不止于投标:场景智能体按需扩展"。
|
||||||
|
- 上方六宫格(2行3列),每个宫格一个图标+标题:
|
||||||
|
1. 招标文件助手
|
||||||
|
2. 安全报告助手
|
||||||
|
3. 智能问答助手
|
||||||
|
4. 智能文书
|
||||||
|
5. 数字员工
|
||||||
|
6. ChatBI数据分析
|
||||||
|
- 下方金句(大字号居中):"场景不封顶,平台持续演进"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P26 联系我们 · 下一步
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT收口页,主题为"下一步:选1个高频场景,做1次POC"。
|
||||||
|
- 上半:三步横向流程(每步编号+标题+描述)
|
||||||
|
1. 共同选定POC场景
|
||||||
|
"建议从招标文件助手或安全报告助手开始"
|
||||||
|
2. 提供历史样本
|
||||||
|
"用于知识库初始化"
|
||||||
|
3. 2-4周内验证
|
||||||
|
"业务部门实际使用"
|
||||||
|
- 下半:联系方式占位区
|
||||||
|
"商务联系:[姓名] / [电话] / [邮箱]"
|
||||||
|
"技术支持:[姓名] / [电话] / [邮箱]"
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
### P27 致谢页
|
||||||
|
|
||||||
|
```
|
||||||
|
生成PPT致谢页,主题为"感谢聆听"。
|
||||||
|
- 背景:深蓝渐变 #003A89 → #0070C0(与封面同款)
|
||||||
|
- 居中大字号白色"感谢聆听"
|
||||||
|
- 副标题:"期待与您共建企业级智能体平台"
|
||||||
|
- 底部产品名 LOGO
|
||||||
|
- 字体:微软雅黑
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 数据守则(可信度护栏汇总)
|
||||||
|
|
||||||
|
### 7.1 ✅ 允许使用的数字
|
||||||
|
- 17(知识库支持格式数,对应 `knowledgeBase/detail.vue:420`)
|
||||||
|
- 11(知识库分块策略数,对应 `knowledgeBase/detail.vue:418-433`)
|
||||||
|
- 50MB(单文件上传上限,对应 `knowledgeBase/detail.vue:436-449`)
|
||||||
|
- 10(智能体分类标签数,对应 `marketplace.vue:95-106`)
|
||||||
|
- 模型名:Qwen / DeepSeek / 盘古 / 混元 / 文心
|
||||||
|
- 国产芯片:沐曦 / 天数智芯 / 海光 / 昇腾
|
||||||
|
|
||||||
|
### 7.2 ❌ 禁止使用
|
||||||
|
- 任何百分比效果提升(如"准确率提升80%""效率提升5倍")
|
||||||
|
- 客户案例涉及具体公司名(除非已获授权脱敏)
|
||||||
|
- "领先/最强/第一/100%"等夸张副词
|
||||||
|
- "万次调用""百万用户"等无据运营数据
|
||||||
|
- "人气最高"等基于随机数的排序
|
||||||
|
|
||||||
|
### 7.3 ⚠️ 谨慎使用
|
||||||
|
- "通常需要数日":可代替具体天数
|
||||||
|
- "一周内启动POC":行业通用承诺
|
||||||
|
- "1-2周""2-4周":典型项目经验值
|
||||||
|
- 引用参考PPT事实:可直接引用P42 智慧项目助理等已落地案例
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 交付清单
|
||||||
|
|
||||||
|
1. ✅ 27页详细设计(每页含7字段)
|
||||||
|
2. ✅ 全局提示词(先发给AI工具)
|
||||||
|
3. ✅ 27页逐页提示词(可直接喂给AI工具)
|
||||||
|
4. ✅ 视觉规范(配色/字体/版式)
|
||||||
|
5. ✅ 数据守则(可信度护栏)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 后续可选优化
|
||||||
|
|
||||||
|
- 实际产品截图替换占位符(P5/P6/P10)
|
||||||
|
- 现场实操录屏嵌入(P6/P15/P16/P19)
|
||||||
|
- 客户行业定制(能源/交通/政务等)
|
||||||
|
- 英文版翻译(如有海外客户)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**版本历史**:
|
||||||
|
- v1.0 (2026-08-05):初版设计完成
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
# Frontend 自定义暗色主题 — Design Spec
|
||||||
|
|
||||||
|
**日期:** 2026-08-06
|
||||||
|
**状态:** Approved
|
||||||
|
**参考:** 项目根目录 `image.png`(深色三栏 AI IDE 风格)
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
`src/views/frontend/index.vue` 是核心 AI 对话页面,当前使用 Element Plus 默认浅色主题 + 局部样式,整体观感偏传统后台。用户要求基于 `image.png`(类 Cursor 的暗色三栏 IDE 风)对 frontend 自定义样式,以匹配产品"AI 智能体 IDE"的定位。
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
将 frontend 页面(不含管理后台)改造为:
|
||||||
|
|
||||||
|
1. 暗色三栏布局:左(会话列表)/ 中(聊天 + 输入)/ 右(文件列表面板 + 预览面板)
|
||||||
|
2. 统一的深色主题 token,作用域隔离,不污染管理后台
|
||||||
|
3. 响应式:屏幕变窄时自动收起右侧文件面板,必要时隐藏侧边栏
|
||||||
|
4. 代码块使用 **Shiki** 渲染,支持与聊天消息中 Markdown 代码块 + 文件预览中的源码文件同款高亮
|
||||||
|
|
||||||
|
## 非目标
|
||||||
|
|
||||||
|
- **不**改动管理后台(`src/views/system/*`、`src/views/tool/*` 等)
|
||||||
|
- **不**新增功能(Git 工具、Progress 面板、终端、Workspace 切换等),仅样式
|
||||||
|
- **不**调整后端 API、不改 WebSocket 协议
|
||||||
|
- **不**引入新的 UI 组件库(继续使用 Element Plus + 少量自定义)
|
||||||
|
- **不**重构 ChatWindow 的消息结构 / 渲染逻辑(保留 markdown-it,仅替换代码块 highlight 插件)
|
||||||
|
|
||||||
|
## 现有约束
|
||||||
|
|
||||||
|
| 项目 | 现状 |
|
||||||
|
| --- | --- |
|
||||||
|
| 根容器类名 | `.frontend-container`(已存在于 `index.vue:861`) |
|
||||||
|
| Markdown 渲染 | 已用 `markdown-it@14.3.0`(ChatWindow) |
|
||||||
|
| 代码高亮 | 暂未配置(默认无高亮或浏览器 monospace) |
|
||||||
|
| 布局 | flex 三栏:sidebar / main-content / file-panel-wrapper + file-preview-wrapper |
|
||||||
|
| 文件面板显隐 | 由 `filePanelVisible` ref 控制(小屏需保持这个行为) |
|
||||||
|
| Element Plus 版本 | 2.13.1(支持 `dark` 命名空间 + CSS 变量覆盖) |
|
||||||
|
|
||||||
|
## 方案概览
|
||||||
|
|
||||||
|
### Phase 1:主题基础设施(半天)
|
||||||
|
|
||||||
|
新增 `src/views/frontend/styles/theme.scss`,定义 SCSS 变量 + CSS 自定义属性,**作用域挂载在 `.frontend-container` 下**:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.frontend-container {
|
||||||
|
// 基础色
|
||||||
|
--fe-bg-base: #1e1e1e;
|
||||||
|
--fe-bg-elevated: #252526;
|
||||||
|
--fe-bg-overlay: #2d2d30;
|
||||||
|
--fe-bg-input: #3c3c3c;
|
||||||
|
|
||||||
|
// 边框
|
||||||
|
--fe-border: #3c3c3c;
|
||||||
|
--fe-border-strong: #555;
|
||||||
|
|
||||||
|
// 文本
|
||||||
|
--fe-text-primary: #e6e6e6;
|
||||||
|
--fe-text-secondary: #a0a0a0;
|
||||||
|
--fe-text-muted: #6e6e6e;
|
||||||
|
--fe-text-inverse: #1e1e1e;
|
||||||
|
|
||||||
|
// 品牌色
|
||||||
|
--fe-accent: #4ec9b0;
|
||||||
|
--fe-accent-hover: #5fd9c0;
|
||||||
|
--fe-danger: #f48771;
|
||||||
|
--fe-warning: #dcdcaa;
|
||||||
|
--fe-info: #569cd6;
|
||||||
|
|
||||||
|
// 布局尺寸
|
||||||
|
--fe-sidebar-width: 260px;
|
||||||
|
--fe-file-panel-width: 280px;
|
||||||
|
--fe-file-preview-width: 600px;
|
||||||
|
|
||||||
|
// 阴影 / 圆角
|
||||||
|
--fe-radius-sm: 4px;
|
||||||
|
--fe-radius-md: 6px;
|
||||||
|
--fe-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
并 override Element Plus 暗色变量(仅在 `.frontend-container` 作用域内有效,避免影响其他页面):
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.frontend-container {
|
||||||
|
--el-bg-color: var(--fe-bg-elevated);
|
||||||
|
--el-bg-color-page: var(--fe-bg-base);
|
||||||
|
--el-bg-color-overlay: var(--fe-bg-overlay);
|
||||||
|
--el-text-color-primary: var(--fe-text-primary);
|
||||||
|
--el-text-color-regular: var(--fe-text-secondary);
|
||||||
|
--el-text-color-secondary: var(--fe-text-muted);
|
||||||
|
--el-border-color: var(--fe-border);
|
||||||
|
--el-border-color-light: var(--fe-border);
|
||||||
|
--el-fill-color-blank: var(--fe-bg-elevated);
|
||||||
|
--el-color-primary: var(--fe-accent);
|
||||||
|
--el-color-primary-light-3: var(--fe-accent-hover);
|
||||||
|
--el-color-danger: var(--fe-danger);
|
||||||
|
--el-color-warning: var(--fe-warning);
|
||||||
|
--el-color-info: var(--fe-info);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`index.vue` 顶部 `@import './styles/theme.scss';` 引入一次。
|
||||||
|
|
||||||
|
### Phase 2:组件样式改造(1.5 天,逐组件,**不改 props/emit/函数体**)
|
||||||
|
|
||||||
|
| 组件 | 主要变更 |
|
||||||
|
| --- | --- |
|
||||||
|
| `ConversationSidebar.vue` | 整体改为暗色 token;激活态用 `--fe-accent` 替代 `#409eff`;新消息小红点保留;右侧收缩按钮用暗色 hover |
|
||||||
|
| `UserArea.vue` | 头像区背景色改暗;昵称文字 `--fe-text-primary`;按钮 hover 用 `--fe-bg-overlay` |
|
||||||
|
| `ChatHeader.vue` | 顶部栏背景 `--fe-bg-elevated`,下边框 `--fe-border`;模型选择器 / 清空按钮使用暗色变量 |
|
||||||
|
| `ChatWindow.vue` | 消息气泡:用户右侧 `--fe-accent` 浅色背景;助手左侧 `--fe-bg-elevated`;代码块由 Shiki 输出;Markdown 文本颜色用 `--fe-text-primary` |
|
||||||
|
| `InputArea.vue` | 输入框背景 `--fe-bg-input`;按钮图标色改 `--fe-text-secondary`;loading 状态颜色保留 |
|
||||||
|
| `FilePanel.vue` | 列表背景 `--fe-bg-elevated`,选中态 `--fe-bg-overlay` + `--fe-accent` 边框 |
|
||||||
|
| `UserInfoDialog.vue` | `el-dialog` 暗色(依赖 EP 变量覆盖);头像遮罩、按钮沿用暗色 token |
|
||||||
|
| `index.vue` 文件预览面板 | 顶部 header 用 `--fe-bg-elevated`;文本预览 `<pre>` 用 Shiki 输出背景 `--fe-bg-base` + `--fe-text-primary` |
|
||||||
|
|
||||||
|
**不动的部分:**
|
||||||
|
- 所有 `data` / `methods` / `computed` / 生命周期函数
|
||||||
|
- 模板的事件绑定、v-if/v-show 条件、ref 名称
|
||||||
|
- WebSocket 协议、API 调用、Pinia store
|
||||||
|
|
||||||
|
### Phase 3:Shiki 集成(半天)
|
||||||
|
|
||||||
|
1. 安装:`yarn add shiki`(不锁版本,跟随 markdown-it 主版本策略)
|
||||||
|
2. 新增 `src/views/frontend/utils/highlighter.js`:
|
||||||
|
```js
|
||||||
|
import { createHighlighter } from 'shiki'
|
||||||
|
import markdownIt from 'markdown-it'
|
||||||
|
|
||||||
|
const highlighterPromise = createHighlighter({
|
||||||
|
themes: ['github-dark'],
|
||||||
|
langs: ['javascript', 'typescript', 'vue', 'json', 'bash',
|
||||||
|
'python', 'java', 'go', 'rust', 'sql', 'yaml',
|
||||||
|
'html', 'css', 'scss', 'markdown', 'tsx', 'jsx']
|
||||||
|
})
|
||||||
|
|
||||||
|
export async function createMarkdownRenderer() {
|
||||||
|
const highlighter = await highlighterPromise
|
||||||
|
const md = markdownIt({ html: false, linkify: true, breaks: true })
|
||||||
|
md.options.highlight = (code, lang) => {
|
||||||
|
const langKey = highlighter.getLoadedLanguages().includes(lang) ? lang : 'text'
|
||||||
|
return highlighter.codeToHtml(code, { lang: langKey, theme: 'github-dark' })
|
||||||
|
}
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. `ChatWindow.vue`:把当前 `new markdownIt(...)` 替换为 `const md = await createMarkdownRenderer()`;保留 `mermaid` / 链接点击等现有扩展(如果有),并保留对 `code` 标签外层包裹(语言标签)
|
||||||
|
4. `index.vue` 文件预览面板:`<pre>{{ previewContent }}</pre>` 改为 `<div v-html="renderedCode"></div>`,`renderedCode` 在 `previewContent` 变化时由同样的 highlighter 渲染;不识别扩展名时降级为纯文本
|
||||||
|
5. **异步初始化**:在 `ChatWindow` `setup` 顶层用 `await` 不可行(不能阻塞 setup),改用 `onMounted` 中预热 highlighter 缓存到一个共享 `ref`;首屏代码块用 fallback(`<pre><code>{{ code }}</code></pre>`)展示 200ms 后由 watcher 替换
|
||||||
|
|
||||||
|
### Phase 4:响应式断点(半天)
|
||||||
|
|
||||||
|
在 `theme.scss` 中追加:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.frontend-container {
|
||||||
|
// 1200px 以下:隐藏右侧文件预览面板
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.file-preview-wrapper { display: none; }
|
||||||
|
}
|
||||||
|
// 900px 以下:默认收起侧边栏
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.conversation-sidebar { width: 28px; }
|
||||||
|
.conversation-sidebar .sidebar-content { display: none; }
|
||||||
|
}
|
||||||
|
// 768px 以下:隐藏右侧文件列表面板(小屏仅保留聊天)
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.file-panel-wrapper { display: none; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**保留现有 `filePanelVisible` 行为不变** —— 用户主动开关的状态在小屏下依然生效(只是视觉上多了一层媒体查询的隐藏,两者独立工作)。
|
||||||
|
|
||||||
|
## 组件契约
|
||||||
|
|
||||||
|
### `src/views/frontend/styles/theme.scss`
|
||||||
|
|
||||||
|
- 无 export,纯 SCSS
|
||||||
|
- `:root` 之外的所有变量挂在 `.frontend-container` 选择器下
|
||||||
|
|
||||||
|
### `src/views/frontend/utils/highlighter.js`
|
||||||
|
|
||||||
|
| 名称 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `createMarkdownRenderer()` | `() => Promise<MarkdownIt>` | 异步创建带 Shiki 高亮的 markdown-it 实例 |
|
||||||
|
| `renderCode(code, lang?)` | `(code: string, lang?: string) => Promise<string>` | 文件预览专用,直接返回 HTML |
|
||||||
|
|
||||||
|
### ChatWindow.vue 改动
|
||||||
|
|
||||||
|
- 新增 `import { createMarkdownRenderer } from '@/views/frontend/utils/highlighter'`
|
||||||
|
- `md` 从同步创建改为异步预热 + `ref` 持有
|
||||||
|
- 模板中 `v-html` 渲染前判断 `mdReady.value`,未就绪时降级 `<pre>`
|
||||||
|
|
||||||
|
## 数据流
|
||||||
|
|
||||||
|
无新数据流。Shiki 的 highlighter 实例是模块级单例,ChatWindow 与文件预览共用。
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
- Shiki 加载失败:`markdown-it` 的 `highlight` 函数降级为 `(c) => \`<pre><code>${escapeHtml(c)}</code></pre>\`,避免阻塞消息渲染
|
||||||
|
- 不支持的语言:fallback 到 `'text'` 语言(无高亮但保留配色)
|
||||||
|
- 文件预览读取失败:已有 `ElMessage.error`,不动
|
||||||
|
|
||||||
|
## 视觉规范
|
||||||
|
|
||||||
|
| 用途 | 值 |
|
||||||
|
| --- | --- |
|
||||||
|
| 主背景 | `#1e1e1e` |
|
||||||
|
| 卡片 / 面板 | `#252526` |
|
||||||
|
| 输入框 / 浮层 | `#3c3c3c` |
|
||||||
|
| 主色(accent) | `#4ec9b0`(青绿,类似 VS Code Dark+) |
|
||||||
|
| 危险 | `#f48771` |
|
||||||
|
| 文本主 | `#e6e6e6` |
|
||||||
|
| 文本次 | `#a0a0a0` |
|
||||||
|
| 代码块主题 | `github-dark`(与整体色调一致) |
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
### 手动测试清单
|
||||||
|
|
||||||
|
1. **主题覆盖**:访问 `/frontend/index`,确认背景变暗;切到管理后台 `/system/user`,确认**未受污染**
|
||||||
|
2. **三栏布局**:左 260px / 中 flex / 右 280px(文件列表面板)+ 600px(文件预览)
|
||||||
|
3. **响应式**:浏览器窗口拉到 1100px → 文件预览消失;拉到 850px → 侧边栏自动收起;拉到 750px → 文件列表面板消失
|
||||||
|
4. **Shiki 渲染**:发一条带 ```js const x = 1 ``` 的消息,确认代码块背景为 `github-dark` 主题色,语法高亮生效
|
||||||
|
5. **文件预览**:点击 markdown / json / py 文件,源码用同款暗色主题渲染
|
||||||
|
6. **原有功能**:新建会话、刷新会话、退出登录、上传头像、修改昵称、二次确认弹窗、WebSocket 收发消息、上下文压缩条、模型切换、token 计数 —— 均**无变化**
|
||||||
|
|
||||||
|
### 回归
|
||||||
|
|
||||||
|
- `yarn dev` 启动后控制台无 SCSS / Vue warn
|
||||||
|
- `yarn build:prod` 通过
|
||||||
|
- 任意管理后台页面(系统管理、监控、工具)打开,目视无暗色污染
|
||||||
|
|
||||||
|
## 风险
|
||||||
|
|
||||||
|
| 风险 | 缓解 |
|
||||||
|
| --- | --- |
|
||||||
|
| Element Plus 组件深色覆盖不完整(部分组件用 hardcoded 色) | Phase 2 组件级逐一覆盖;如 `el-dialog` 头背景、`el-message` 背景用 `!important` + 选择器权重提升 |
|
||||||
|
| Shiki bundle 体积大 | 仅打包 `github-dark` 主题 + 16 个常用语言;按需扩展 |
|
||||||
|
| 文件预览大量代码时高亮阻塞 | highlighter 异步;用 `requestIdleCallback` 或 `setTimeout(0)` 让出主线程 |
|
||||||
|
| 响应式断点与既有状态(如 `filePanelVisible`)冲突 | 断点仅控制 `display`,状态变量保留;大屏恢复时面板重新可见 |
|
||||||
|
|
||||||
|
## 后续可扩展(不在本次范围)
|
||||||
|
|
||||||
|
- 主题切换(亮 / 暗 / 系统跟随)
|
||||||
|
- Shiki 多主题切换
|
||||||
|
- 侧边栏拖拽调宽
|
||||||
|
- 文件预览面板内嵌 Monaco Editor
|
||||||
|
|
||||||
|
## 实施顺序
|
||||||
|
|
||||||
|
| 阶段 | 任务 | 依赖 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1.1 | 创建 `theme.scss` 基础 token + EP 变量覆盖 | 无 |
|
||||||
|
| 1.2 | `index.vue` 引入 `@import './styles/theme.scss'` | 1.1 |
|
||||||
|
| 1.3 | 验证 EP 按钮 / dialog / message 颜色变化 | 1.2 |
|
||||||
|
| 2.x | 逐组件改造样式(不改 JS) | 1.3 |
|
||||||
|
| 3.1 | 安装 shiki + 新增 `utils/highlighter.js` | 无 |
|
||||||
|
| 3.2 | ChatWindow 集成 markdown-it + Shiki | 3.1 |
|
||||||
|
| 3.3 | 文件预览面板使用同一 highlighter | 3.2 |
|
||||||
|
| 4.1 | 三个媒体查询断点 | 1.3 |
|
||||||
|
| 4.2 | 响应式回归测试 | 4.1 + 全部组件完成 |
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# Frontend 会话列表底部用户区域块 — Design Spec
|
||||||
|
|
||||||
|
**日期:** 2026-08-06
|
||||||
|
**状态:** Approved
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
`src/views/frontend/index.vue` 是核心 AI 对话页面,左侧是 `ConversationSidebar`(会话列表)。当前侧边栏底部没有任何用户相关的入口:用户无法在不离开页面的情况下查看自己的头像/昵称、退出登录、或跳转到智能体广场。
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
在会话列表底部新增一个区域块,提供:
|
||||||
|
1. 用户头像 + 昵称展示,点击打开「个人资料」修改弹窗(可改头像、昵称)
|
||||||
|
2. 「退出」按钮(二次确认后退出登录)
|
||||||
|
3. 「前往智能体广场」按钮
|
||||||
|
|
||||||
|
侧边栏收起时,该区域块仅显示一个小头像,点击弹出菜单。
|
||||||
|
|
||||||
|
## 非目标
|
||||||
|
|
||||||
|
- 不修改智能体广场页本身
|
||||||
|
- 不修改会话列表的样式或行为
|
||||||
|
- 不引入新的退出 / 上传头像后端接口
|
||||||
|
|
||||||
|
## 方案概览
|
||||||
|
|
||||||
|
新增两个组件,`ConversationSidebar` 引入并放在底部。
|
||||||
|
|
||||||
|
### 新增文件
|
||||||
|
|
||||||
|
- `src/views/frontend/components/UserArea.vue`
|
||||||
|
- 展示用户头像 + 昵称、退出按钮、前往智能体广场按钮
|
||||||
|
- 接收 `collapsed` prop(来自 `ConversationSidebar`)
|
||||||
|
- 展开时:完整展示三块内容;收起时:仅显示小圆形头像,点击弹出 dropdown 菜单
|
||||||
|
- 通过 `defineExpose` 暴露 `openInfoDialog()` 方法,父组件 `ConversationSidebar` 用 ref 调用(与现有 `defineExpose({ refresh: fetchSessions, ... })` 风格一致)
|
||||||
|
|
||||||
|
- `src/views/frontend/components/UserInfoDialog.vue`
|
||||||
|
- Element Plus `el-dialog`,标题"个人资料",宽 500px
|
||||||
|
- 内容:头像裁剪上传区(vue-cropper 固定 1:1)+ 昵称输入框
|
||||||
|
- 接收 `modelValue` / `user` props,emit `update:modelValue`、`saved`
|
||||||
|
- 保存时调用:
|
||||||
|
- `uploadAvatar()` — `PUT /system/user/profile/avatar`
|
||||||
|
- `updateUserProfile({ nickName })` — `PUT /system/user/profile`
|
||||||
|
- 保存成功后更新 `useUserStore()` 的 `avatar`、`nickName`,并 emit `saved`,父组件 ElMessage 成功提示
|
||||||
|
|
||||||
|
### 修改文件
|
||||||
|
|
||||||
|
- `src/views/frontend/components/ConversationSidebar.vue`
|
||||||
|
- 在 `sidebar-content` 内的 `<el-scrollbar>` 下方引入 `<UserArea ref="userAreaRef" :collapsed="collapsed" />`
|
||||||
|
- 把 `<el-scrollbar>` 的 `height` 由 `calc(100vh - 160px)` 改为 `calc(100vh - 240px)`(预留底部 user-area 高度)
|
||||||
|
- 把 `sidebar-content` 改为 flex 布局,使 `<el-scrollbar>` 占中间,`<UserArea>` 占底部固定高度
|
||||||
|
|
||||||
|
## 组件契约
|
||||||
|
|
||||||
|
### UserArea.vue
|
||||||
|
|
||||||
|
| 名称 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Props | | |
|
||||||
|
| collapsed | Boolean | 侧边栏是否收起 |
|
||||||
|
| Methods (expose) | | |
|
||||||
|
| openInfoDialog() | () => void | 打开个人资料弹窗 |
|
||||||
|
|
||||||
|
### UserInfoDialog.vue
|
||||||
|
|
||||||
|
| 名称 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Props | | |
|
||||||
|
| modelValue | Boolean | 弹窗显隐(v-model) |
|
||||||
|
| user | Object | 当前用户 `{ avatar, nickName }` |
|
||||||
|
| Emit | | |
|
||||||
|
| update:modelValue | (val: Boolean) | 显隐变化 |
|
||||||
|
| saved | (user: Object) | 保存成功后回调 |
|
||||||
|
|
||||||
|
## 数据流
|
||||||
|
|
||||||
|
1. `ConversationSidebar` 通过 `useUserStore()` 取用户信息,传给 `UserArea` 和 `UserInfoDialog`
|
||||||
|
2. 用户点击头像 → `UserArea.openInfoDialog()` → 内部把 `infoDialogVisible.value = true` → `<UserInfoDialog v-model="infoDialogVisible" :user="user" @saved="onSaved" />`
|
||||||
|
3. `UserInfoDialog` 内部:
|
||||||
|
- 选择本地图片 → `vue-cropper` 裁剪 → 用户点"保存"
|
||||||
|
- 调 `uploadAvatar(formData)` → 成功后调 `updateUserProfile({ nickName })` → 更新 store
|
||||||
|
4. `UserInfoDialog` 关闭后 `ConversationSidebar` 触发 `ElMessage.success('修改成功')`
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
- 上传头像失败:`ElMessage.error('头像上传失败')`,弹窗保持打开以便重试
|
||||||
|
- 更新昵称失败:`ElMessage.error('修改失败')`
|
||||||
|
- 退出失败:`ElMessage.error('退出失败,请稍后重试')`
|
||||||
|
- 网络异常:依赖 `request.js` 的统一错误处理
|
||||||
|
|
||||||
|
## 视觉规范
|
||||||
|
|
||||||
|
- 与现有侧边栏保持一致色系:`#e4e7ed` 分割线、`#409eff` 主色、`#f56c6c` 危险色
|
||||||
|
- 头像 36×36 圆形(收起时 28×28)
|
||||||
|
- 昵称省略号截断 `text-overflow: ellipsis`
|
||||||
|
- 按钮文字与图标间距 6px
|
||||||
|
- 顶部细分割线:`border-top: 1px solid #e4e7ed`
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
- 手动测试:本地 `yarn dev`,访问 `/frontend/index`
|
||||||
|
- 头像昵称正确展示
|
||||||
|
- 点击头像 → 弹窗打开 → 修改头像/昵称 → 保存 → 列表头像昵称同步刷新
|
||||||
|
- 点击退出 → 确认 → 跳转到 `/login`
|
||||||
|
- 点击「前往智能体广场」 → 跳转到 `/frontend/marketplace`
|
||||||
|
- 收起侧边栏 → 仅显示小头像 → hover 出 tooltip → 点击出 dropdown 菜单
|
||||||
|
|
||||||
|
## 风险
|
||||||
|
|
||||||
|
- 头像上传接口需要登录态,已通过 `request.js` 自动带 token 处理
|
||||||
|
- 弹窗高度可能在小屏幕溢出,宽度固定 500px,自适应垂直
|
||||||
|
|
||||||
|
## 后续可扩展(不在本次范围)
|
||||||
|
|
||||||
|
- 收起状态下的 dropdown 也可改成 popover
|
||||||
|
- 头像昵称展示支持在线状态
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
<title>%VITE_APP_TITLE%</title>
|
||||||
|
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chromeframe {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
background: #ccc;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
margin: -75px 0 0 -75px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #FFF;
|
||||||
|
-webkit-animation: spin 2s linear infinite;
|
||||||
|
-ms-animation: spin 2s linear infinite;
|
||||||
|
-moz-animation: spin 2s linear infinite;
|
||||||
|
-o-animation: spin 2s linear infinite;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #FFF;
|
||||||
|
-webkit-animation: spin 3s linear infinite;
|
||||||
|
-moz-animation: spin 3s linear infinite;
|
||||||
|
-o-animation: spin 3s linear infinite;
|
||||||
|
-ms-animation: spin 3s linear infinite;
|
||||||
|
animation: spin 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #FFF;
|
||||||
|
-moz-animation: spin 1.5s linear infinite;
|
||||||
|
-o-animation: spin 1.5s linear infinite;
|
||||||
|
-ms-animation: spin 1.5s linear infinite;
|
||||||
|
-webkit-animation: spin 1.5s linear infinite;
|
||||||
|
animation: spin 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#loader-wrapper .loader-section {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 51%;
|
||||||
|
height: 100%;
|
||||||
|
background: #7171C6;
|
||||||
|
z-index: 1000;
|
||||||
|
-webkit-transform: translateX(0);
|
||||||
|
-ms-transform: translateX(0);
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper .loader-section.section-left {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper .loader-section.section-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.loaded #loader-wrapper .loader-section.section-left {
|
||||||
|
-webkit-transform: translateX(-100%);
|
||||||
|
-ms-transform: translateX(-100%);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaded #loader-wrapper .loader-section.section-right {
|
||||||
|
-webkit-transform: translateX(100%);
|
||||||
|
-ms-transform: translateX(100%);
|
||||||
|
transform: translateX(100%);
|
||||||
|
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaded #loader {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transition: all 0.3s ease-out;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaded #loader-wrapper {
|
||||||
|
visibility: hidden;
|
||||||
|
-webkit-transform: translateY(-100%);
|
||||||
|
-ms-transform: translateY(-100%);
|
||||||
|
transform: translateY(-100%);
|
||||||
|
-webkit-transition: all 0.3s 1s ease-out;
|
||||||
|
transition: all 0.3s 1s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-js #loader-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-js h1 {
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper .load_title {
|
||||||
|
font-family: 'Open Sans';
|
||||||
|
color: #FFF;
|
||||||
|
font-size: 19px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 9999999999999;
|
||||||
|
position: absolute;
|
||||||
|
top: 60%;
|
||||||
|
opacity: 1;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loader-wrapper .load_title span {
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #FFF;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- PDF.js -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<div id="loader-wrapper">
|
||||||
|
<div id="loader"></div>
|
||||||
|
<div class="loader-section section-left"></div>
|
||||||
|
<div class="loader-section section-right"></div>
|
||||||
|
<div class="load_title">正在加载系统资源,请耐心等待</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"name": "ruoyi",
|
||||||
|
"version": "3.9.2",
|
||||||
|
"description": "若依管理系统",
|
||||||
|
"author": "若依",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build:prod": "vite build",
|
||||||
|
"build:stage": "vite build --mode staging",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "2.3.2",
|
||||||
|
"@vueup/vue-quill": "1.2.0",
|
||||||
|
"@vueuse/core": "14.1.0",
|
||||||
|
"axios": "^1.18.1",
|
||||||
|
"clipboard": "2.0.11",
|
||||||
|
"echarts": "5.6.0",
|
||||||
|
"element-plus": "2.13.1",
|
||||||
|
"file-saver": "2.0.5",
|
||||||
|
"fuse.js": "7.1.0",
|
||||||
|
"js-beautify": "1.15.4",
|
||||||
|
"js-cookie": "3.0.5",
|
||||||
|
"jsencrypt": "3.3.2",
|
||||||
|
"markdown-it": "^14.3.0",
|
||||||
|
"nprogress": "0.2.0",
|
||||||
|
"pdfjs-dist": "^6.1.200",
|
||||||
|
"pinia": "3.0.4",
|
||||||
|
"shiki": "^4.4.2",
|
||||||
|
"vue": "3.5.26",
|
||||||
|
"vue-cropper": "1.1.1",
|
||||||
|
"vue-router": "4.6.4",
|
||||||
|
"vuedraggable": "4.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "5.2.4",
|
||||||
|
"sass-embedded": "1.97.2",
|
||||||
|
"unplugin-auto-import": "0.18.6",
|
||||||
|
"unplugin-vue-setup-extend-plus": "1.0.1",
|
||||||
|
"vite": "6.4.1",
|
||||||
|
"vite-plugin-compression": "0.5.1",
|
||||||
|
"vite-plugin-svg-icons": "2.0.1"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"quill": "2.0.2"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"quill": "2.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<router-view />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
import { handleThemeStyle } from '@/utils/theme'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
// 初始化主题样式
|
||||||
|
handleThemeStyle(useSettingsStore().theme)
|
||||||
|
// 同步 frontend 主题到所有 .frontend-container 节点
|
||||||
|
useSettingsStore().applyFrontendTheme()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
// 原有接口 baseURL
|
||||||
|
const BASE_URL = import.meta.env.VITE_APP_BASE_URL || 'https://frp.pilotdeck.gdskzl.com'
|
||||||
|
|
||||||
|
const frontendRequest = axios.create({
|
||||||
|
baseURL: BASE_URL,
|
||||||
|
timeout: 30000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
frontendRequest.interceptors.response.use(
|
||||||
|
res => res.data,
|
||||||
|
error => {
|
||||||
|
console.error('API Error:', error)
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 聊天会话接口 baseURL
|
||||||
|
// const CHAT_BASE_URL = 'http://192.168.5.125:81/dev-api'
|
||||||
|
const CHAT_BASE_URL = BASE_URL
|
||||||
|
const chatRequest = axios.create({
|
||||||
|
baseURL: CHAT_BASE_URL,
|
||||||
|
timeout: 30000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
chatRequest.interceptors.request.use(config => {
|
||||||
|
const token = getToken()
|
||||||
|
if (token) {
|
||||||
|
config.headers['Authorization'] = 'Bearer ' + token
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}, error => {
|
||||||
|
console.error('Request error:', error)
|
||||||
|
return Promise.reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
chatRequest.interceptors.response.use(
|
||||||
|
res => res.data,
|
||||||
|
error => {
|
||||||
|
console.error('API Error:', error)
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// export function listProjects() {
|
||||||
|
// return frontendRequest({
|
||||||
|
// url: '/api/projects',
|
||||||
|
// method: 'get'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function listSessions(projectName) {
|
||||||
|
// return frontendRequest({
|
||||||
|
// url: `/api/projects/${projectName}/sessions`,
|
||||||
|
// method: 'get'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export function getSession(projectName, sessionId) {
|
||||||
|
// return frontendRequest({
|
||||||
|
// url: `/api/projects/${projectName}/sessions/${sessionId}`,
|
||||||
|
// method: 'get'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 聊天会话相关 API
|
||||||
|
// workspacePath 作为路径段时,斜杠替换为 "-",并去掉开头的 "-"
|
||||||
|
function toPathParam(workspacePath) {
|
||||||
|
return workspacePath ? workspacePath.replace(/\//g, '-').replace(/^-+/, '') : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function authHeaders() {
|
||||||
|
const headers = {}
|
||||||
|
const token = getToken()
|
||||||
|
if (token) {
|
||||||
|
headers['Authorization'] = 'Bearer ' + token
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listChatSessions(agentId) {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/list',
|
||||||
|
method: 'get',
|
||||||
|
params: agentId ? { agentId: Number(agentId) } : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChatSessionMessages(workspacePath, sessionId) {
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/messages/${encodeURIComponent(sessionId)}`,
|
||||||
|
method: 'get',
|
||||||
|
params: { workspacePath }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteChatSession(workspacePath, sessionId) {
|
||||||
|
const wp = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/${encodeURIComponent(wp)}/${encodeURIComponent(sessionId)}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renameChatSession(sessionId, title) {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/rename',
|
||||||
|
method: 'put',
|
||||||
|
data: { sessionId, title }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function getSessionMessages(session) {
|
||||||
|
// const { id, provider = 'pilotdeck', __projectName, cwd } = session
|
||||||
|
// const params = {
|
||||||
|
// provider,
|
||||||
|
// projectName: __projectName,
|
||||||
|
// projectPath: cwd
|
||||||
|
// }
|
||||||
|
// return frontendRequest({
|
||||||
|
// url: `/api/sessions/${encodeURIComponent(id)}/messages`,
|
||||||
|
// method: 'get',
|
||||||
|
// params
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// LLM 模型列表
|
||||||
|
export function listLlmModels() {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/llmModel/itemList',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI 智能体市场列表
|
||||||
|
export function listAgentProjects() {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/agents',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listFiles(workspacePath) {
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/projectFile',
|
||||||
|
method: 'get',
|
||||||
|
params: { workspacePath }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFileContent(workspacePath, filePath) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/projectFile/${pathParam}/file`,
|
||||||
|
method: 'get',
|
||||||
|
params: { filePath }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveFile(workspacePath, filePath, content) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/projectFile/${pathParam}/file`,
|
||||||
|
method: 'put',
|
||||||
|
data: { filePath, content }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFileDownloadUrl(workspacePath, filePath) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return `${BASE_URL}/llm/chatSession/projectFile/${pathParam}/content?path=${encodeURIComponent(filePath)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOfficePreviewStatus() {
|
||||||
|
return frontendRequest({
|
||||||
|
url: '/api/office-preview/status',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPdfBlobUrl(workspacePath, path) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
const url = `${BASE_URL}/llm/chatSession/projectFile/${pathParam}/pdf?path=${encodeURIComponent(path)}&_=${Date.now()}`
|
||||||
|
return fetch(url, {
|
||||||
|
credentials: 'omit',
|
||||||
|
headers: authHeaders()
|
||||||
|
}).then(res => {
|
||||||
|
if (!res.ok) throw new Error('Failed to fetch PDF')
|
||||||
|
return res.arrayBuffer()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageBlobUrl(workspacePath, path) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
const url = `${BASE_URL}/llm/chatSession/projectFile/${pathParam}/content?path=${encodeURIComponent(path)}&_=${Date.now()}`
|
||||||
|
return fetch(url, { credentials: 'omit', headers: authHeaders() })
|
||||||
|
.then(res => { if (!res.ok) throw new Error('Failed to fetch image'); return res.blob() })
|
||||||
|
.then(blob => URL.createObjectURL(blob))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function downloadFile(workspacePath, filePath) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/projectFile/${pathParam}/content`,
|
||||||
|
method: 'get',
|
||||||
|
params: { path: filePath, download: 1 },
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 60000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFileOrDirectory(workspacePath, type, name, path) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
const data = { type, name }
|
||||||
|
if (path && path !== '/') {
|
||||||
|
data.path = path
|
||||||
|
}
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/projectFile/' + pathParam + '/files/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteFileOrDirectory(workspacePath, path, type) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/projectFile/' + pathParam,
|
||||||
|
method: 'delete',
|
||||||
|
data: { path, type }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renameFile(workspacePath, oldPath, newName) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/projectFile/' + pathParam + '/rename',
|
||||||
|
method: 'put',
|
||||||
|
data: { oldPath, newName }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function uploadFileOrDirectory(workspacePath, targetPath, relativePaths, files) {
|
||||||
|
const pathParam = toPathParam(workspacePath)
|
||||||
|
const formData = new FormData()
|
||||||
|
if (targetPath) {
|
||||||
|
formData.append('targetPath', targetPath)
|
||||||
|
}
|
||||||
|
formData.append('relativePaths', JSON.stringify(relativePaths))
|
||||||
|
for (const file of files) {
|
||||||
|
formData.append('files', file)
|
||||||
|
}
|
||||||
|
return chatRequest({
|
||||||
|
url: '/llm/chatSession/projectFile/' + pathParam + '/upload',
|
||||||
|
method: 'post',
|
||||||
|
data: formData,
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFolderNameFromPath(workspacePath) {
|
||||||
|
if (!workspacePath) return ''
|
||||||
|
const trimmed = workspacePath.replace(/\/+$/, '')
|
||||||
|
const lastSlash = trimmed.lastIndexOf('/')
|
||||||
|
return lastSlash >= 0 ? trimmed.slice(lastSlash + 1) : trimmed
|
||||||
|
}
|
||||||
|
|
||||||
|
export function downloadProject(workspacePath) {
|
||||||
|
// 文件夹下载接口的路径段需要保留开头的 '-'
|
||||||
|
const pathParam = workspacePath ? workspacePath.replace(/\//g, '-') : ''
|
||||||
|
return fetch(`${BASE_URL}/llm/chatSession/projectFile/${pathParam}/download`, {
|
||||||
|
credentials: 'omit',
|
||||||
|
headers: authHeaders()
|
||||||
|
}).then(res => {
|
||||||
|
if (!res.ok) throw new Error('Download failed')
|
||||||
|
const disposition = res.headers.get('Content-Disposition')
|
||||||
|
const folderName = getFolderNameFromPath(workspacePath) || 'project'
|
||||||
|
let filename = `${folderName}.zip`
|
||||||
|
if (disposition) {
|
||||||
|
const match = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
|
||||||
|
if (match) filename = match[1].replace(/['"]/g, '')
|
||||||
|
}
|
||||||
|
return res.blob().then(blob => ({ blob, filename }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenUsage(sessionId) {
|
||||||
|
return chatRequest({
|
||||||
|
url: `/llm/chatSession/tokenUsage?sessionId=${encodeURIComponent(sessionId)}`,
|
||||||
|
method: 'get',
|
||||||
|
params: { provider: 'pilotdeck' }
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询智能体列表
|
||||||
|
export function listLlmAngent(query) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmAngent/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询智能体详细
|
||||||
|
export function getLlmAngent(id) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmAngent/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增智能体
|
||||||
|
export function addLlmAngent(data) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmAngent',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改智能体
|
||||||
|
export function updateLlmAngent(data) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmAngent',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除智能体
|
||||||
|
export function delLlmAngent(id) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmAngent/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询LLM模型列表
|
||||||
|
export function listLlmModel(query) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmModel/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询LLM模型详细
|
||||||
|
export function getLlmModel(modelId) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmModel/' + modelId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增LLM模型
|
||||||
|
export function addLlmModel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmModel',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改LLM模型
|
||||||
|
export function updateLlmModel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmModel',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除LLM模型
|
||||||
|
export function delLlmModel(modelId) {
|
||||||
|
return request({
|
||||||
|
url: '/llm/llmModel/' + modelId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 登录方法
|
||||||
|
export function login(username, password, code, uuid) {
|
||||||
|
const data = {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
code,
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/login',
|
||||||
|
headers: {
|
||||||
|
isToken: false,
|
||||||
|
repeatSubmit: false
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册方法
|
||||||
|
export function register(data) {
|
||||||
|
return request({
|
||||||
|
url: '/register',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户详细信息
|
||||||
|
export function getInfo() {
|
||||||
|
return request({
|
||||||
|
url: '/getInfo',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解锁屏幕
|
||||||
|
export function unlockScreen(password) {
|
||||||
|
return request({
|
||||||
|
url: '/unlockscreen',
|
||||||
|
method: 'post',
|
||||||
|
data: { password }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出方法
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
url: '/logout',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
export function getCodeImg() {
|
||||||
|
return request({
|
||||||
|
url: '/captchaImage',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
method: 'get',
|
||||||
|
timeout: 20000
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取路由
|
||||||
|
export const getRouters = () => {
|
||||||
|
return request({
|
||||||
|
url: '/getRouters',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询参数列表
|
||||||
|
export function listConfig(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询参数详细
|
||||||
|
export function getConfig(configId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/' + configId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据参数键名查询参数值
|
||||||
|
export function getConfigKey(configKey) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/configKey/' + configKey,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增参数配置
|
||||||
|
export function addConfig(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改参数配置
|
||||||
|
export function updateConfig(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除参数配置
|
||||||
|
export function delConfig(configId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/' + configId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新参数缓存
|
||||||
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
|
url: '/system/config/refreshCache',
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询部门列表
|
||||||
|
export function listDept(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询部门列表(排除节点)
|
||||||
|
export function listDeptExcludeChild(deptId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/list/exclude/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询部门详细
|
||||||
|
export function getDept(deptId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增部门
|
||||||
|
export function addDept(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改部门
|
||||||
|
export function updateDept(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存部门排序
|
||||||
|
export function updateDeptSort(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/updateSort',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除部门
|
||||||
|
export function delDept(deptId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/' + deptId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询字典数据列表
|
||||||
|
export function listData(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典数据详细
|
||||||
|
export function getData(dictCode) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据字典类型查询字典数据信息
|
||||||
|
export function getDicts(dictType) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/type/' + dictType,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典数据
|
||||||
|
export function addData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典数据
|
||||||
|
export function updateData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典数据
|
||||||
|
export function delData(dictCode) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询字典类型列表
|
||||||
|
export function listType(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典类型详细
|
||||||
|
export function getType(dictId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典类型
|
||||||
|
export function addType(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典类型
|
||||||
|
export function updateType(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典类型
|
||||||
|
export function delType(dictId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新字典缓存
|
||||||
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/refreshCache',
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字典选择框列表
|
||||||
|
export function optionselect() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/optionselect',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询菜单列表
|
||||||
|
export function listMenu(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询菜单详细
|
||||||
|
export function getMenu(menuId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询菜单下拉树结构
|
||||||
|
export function treeselect() {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/treeselect',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据角色ID查询菜单下拉树结构
|
||||||
|
export function roleMenuTreeselect(roleId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增菜单
|
||||||
|
export function addMenu(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改菜单
|
||||||
|
export function updateMenu(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存菜单排序
|
||||||
|
export function updateMenuSort(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/updateSort',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除菜单
|
||||||
|
export function delMenu(menuId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/menu/' + menuId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询公告列表
|
||||||
|
export function listNotice(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询公告详细
|
||||||
|
export function getNotice(noticeId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/' + noticeId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增公告
|
||||||
|
export function addNotice(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改公告
|
||||||
|
export function updateNotice(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除公告
|
||||||
|
export function delNotice(noticeId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/' + noticeId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 首页顶部公告列表(带已读状态)
|
||||||
|
export function listNoticeTop() {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/listTop',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记公告已读
|
||||||
|
export function markNoticeRead(noticeId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/markRead',
|
||||||
|
method: 'post',
|
||||||
|
params: { noticeId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量标记已读
|
||||||
|
export function markNoticeReadAll(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/markReadAll',
|
||||||
|
method: 'post',
|
||||||
|
params: { ids }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询公告已读用户列表
|
||||||
|
export function listNoticeReadUsers(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/notice/readUsers/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询岗位列表
|
||||||
|
export function listPost(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询岗位详细
|
||||||
|
export function getPost(postId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增岗位
|
||||||
|
export function addPost(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改岗位
|
||||||
|
export function updatePost(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除岗位
|
||||||
|
export function delPost(postId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/post/' + postId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询角色列表
|
||||||
|
export function listRole(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询角色详细
|
||||||
|
export function getRole(roleId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增角色
|
||||||
|
export function addRole(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改角色
|
||||||
|
export function updateRole(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色数据权限
|
||||||
|
export function dataScope(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/dataScope',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色状态修改
|
||||||
|
export function changeRoleStatus(roleId, status) {
|
||||||
|
const data = {
|
||||||
|
roleId,
|
||||||
|
status
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/system/role/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除角色
|
||||||
|
export function delRole(roleId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/' + roleId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询角色已授权用户列表
|
||||||
|
export function allocatedUserList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/allocatedList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询角色未授权用户列表
|
||||||
|
export function unallocatedUserList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/unallocatedList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消用户授权角色
|
||||||
|
export function authUserCancel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/cancel',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量取消用户授权角色
|
||||||
|
export function authUserCancelAll(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/cancelAll',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权用户选择
|
||||||
|
export function authUserSelectAll(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/authUser/selectAll',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据角色ID查询部门树结构
|
||||||
|
export function deptTreeSelect(roleId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/deptTree/' + roleId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import { parseStrEmpty } from "@/utils/ruoyi";
|
||||||
|
|
||||||
|
// 查询用户列表
|
||||||
|
export function listUser(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户详细
|
||||||
|
export function getUser(userId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + parseStrEmpty(userId),
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增用户
|
||||||
|
export function addUser(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户
|
||||||
|
export function updateUser(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除用户
|
||||||
|
export function delUser(userId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/' + userId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户密码重置
|
||||||
|
export function resetUserPwd(userId, password) {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
password
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/system/user/resetPwd',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户状态修改
|
||||||
|
export function changeUserStatus(userId, status) {
|
||||||
|
const data = {
|
||||||
|
userId,
|
||||||
|
status
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/system/user/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户个人信息
|
||||||
|
export function getUserProfile() {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户个人信息
|
||||||
|
export function updateUserProfile(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户密码重置
|
||||||
|
export function updateUserPwd(oldPassword, newPassword) {
|
||||||
|
const data = {
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile/updatePwd',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户头像上传
|
||||||
|
export function uploadAvatar(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile/avatar',
|
||||||
|
method: 'post',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询授权角色
|
||||||
|
export function getAuthRole(userId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/authRole/' + userId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存授权角色
|
||||||
|
export function updateAuthRole(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/authRole',
|
||||||
|
method: 'put',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询部门下拉树结构
|
||||||
|
export function deptTreeSelect() {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/deptTree',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询生成表数据
|
||||||
|
export function listTable(query) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 查询db数据库列表
|
||||||
|
export function listDbTable(query) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/db/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询表详细信息
|
||||||
|
export function getGenTable(tableId) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改代码生成信息
|
||||||
|
export function updateGenTable(data) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入表
|
||||||
|
export function importTable(data) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/importTable',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表
|
||||||
|
export function createTable(data) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/createTable',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预览生成代码
|
||||||
|
export function previewTable(tableId) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/preview/' + tableId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除表数据
|
||||||
|
export function delTable(tableId) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/' + tableId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成代码(自定义路径)
|
||||||
|
export function genCode(tableName) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/genCode/' + tableName,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步数据库
|
||||||
|
export function synchDb(tableName) {
|
||||||
|
return request({
|
||||||
|
url: '/tool/gen/synchDb/' + tableName,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1773923748724" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5930" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 212l48.8 12c101.6 24.8 176 117.6 176 220.8v254.4l18.4 18.4 24.8 25.6h-536l24.8-25.6 18.4-18.4V444.8c0-103.2 73.6-196.8 176-220.8l48.8-12M512 64c-36.8 0-64 30.4-64 68v30.4C320.8 192 223.2 307.2 223.2 444.8v228.8L136 763.2v44.8h752v-44.8l-87.2-89.6V444.8c0-137.6-97.6-252.8-224.8-283.2v-28.8c0-32-17.6-60.8-48-67.2-5.6-1.6-11.2-1.6-16-1.6z m88 808H424c0 49.6 38.4 88 88 88s88-38.4 88-88z" p-id="5931"></path></svg>
|
||||||
|
After Width: | Height: | Size: 750 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>
|
||||||
|
After Width: | Height: | Size: 954 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>
|
||||||
|
After Width: | Height: | Size: 179 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575982282951" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="902" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M828.40625 90.125H195.59375C137.375 90.125 90.125 137.375 90.125 195.59375v632.8125c0 58.21875 47.25 105.46875 105.46875 105.46875h632.8125c58.21875 0 105.46875-47.25 105.46875-105.46875V195.59375c0-58.21875-47.25-105.46875-105.46875-105.46875z m52.734375 738.28125c0 29.16-23.57015625 52.734375-52.734375 52.734375H195.59375c-29.109375 0-52.734375-23.574375-52.734375-52.734375V195.59375c0-29.109375 23.625-52.734375 52.734375-52.734375h632.8125c29.16 0 52.734375 23.625 52.734375 52.734375v632.8125z" p-id="903"></path><path d="M421.52890625 709.55984375a36.28125 36.28125 0 0 1-27.55265625-12.66890625L205.17453125 476.613125a36.28546875 36.28546875 0 0 1 55.10109375-47.22890625l164.986875 192.4846875 342.16171875-298.48078125a36.2896875 36.2896875 0 0 1 47.70984375 54.68765625L445.3859375 700.6203125a36.3234375 36.3234375 0 0 1-23.85703125 8.93953125z" p-id="904"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>
|
||||||
|
After Width: | Height: | Size: 971 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1546567861908" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2422" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M318.577778 819.2L17.066667 512l301.511111-307.2 45.511111 45.511111L96.711111 512l267.377778 261.688889zM705.422222 819.2l-45.511111-45.511111L927.288889 512l-267.377778-261.688889 45.511111-45.511111L1006.933333 512zM540.785778 221.866667l55.751111 11.150222L483.157333 802.133333l-55.751111-11.093333z" p-id="2423"></path></svg>
|
||||||
|
After Width: | Height: | Size: 717 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577252187056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2508" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M747.59340925 691.12859384c11.51396329 0.25305413 22.43746719-0.21087818 40.74171707-1.51832482 29.35428085-2.10878421 35.84933734-2.36183835 46.47761114-0.8856895 24.71495444 3.37405491 41.12129828 21.76265671 32.47528161 47.95376084-85.57447632 258.19957947-442.00123984 249.76444099-628.67084683 50.73735554-153.47733892-159.33976008-153.09775772-414.41833795 0.92786545-573.42069196 159.71934128-162.67163983 424.03439521-166.59397897 565.78689185 0.63263534 80.38686649 94.81095318 108.34934958 169.16669549 89.11723508 230.57450162-15.01454608 47.99593598-50.61082928 77.68762207-119.77896259 114.63352789-4.89237973 2.65706845-29.35428085 15.52065436-35.84933652 19.02123633-46.94154346 25.30541465-63.51659033 41.20565021-62.20914449 58.45550757 2.95229856 39.13904114 24.16667102 52.7196135 70.98168823 53.81618115z m44.41100207 50.10472101c-19.82257471 1.43397372-32.05352527 1.940082-45.63409763 1.6448519-70.34905207-1.60267593-115.98314969-30.91478165-121.38163769-101.64341492-3.45840683-46.05585397 24.7571304-73.13264758 89.24376132-107.96976837 6.7902866-3.66928501 31.37871396-16.57504688 36.06021551-19.06341229 57.69634516-30.83042972 85.15271997-53.73183005 94.76877722-84.47790866 12.77923398-40.78389304-9.10994898-98.94417051-79.24812286-181.6507002-121.17075953-142.97559219-350.14258521-139.60153647-489.2380134 2.06660824-134.49827774 138.84237405-134.79350784 362.12048163-0.42175717 501.637667 158.53842169 168.99799328 451.9968783 181.18676788 534.57688175-11.80919339-4.68150156 0.2952301-10.71262573 0.67481131-18.72600705 1.26527069z" p-id="2509"></path><path d="M346.03865637 637.18588562a78.82636652 78.82636652 0 0 0 78.32025825-79.29029883c0-43.69401562-35.005823-79.29029883-78.32025825-79.29029882a78.82636652 78.82636652 0 0 0-78.36243338 79.29029882c0 43.69401562 35.005823 79.29029883 78.36243338 79.29029883z m0-51.7495729a27.07679361 27.07679361 0 0 1-26.5706845-27.54072593c0-15.30977536 11.97789643-27.54072593 26.5706845-27.54072592 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072592a27.07679361 27.07679361 0 0 1-26.57068533 27.54072593zM475.7289063 807.11174353a78.82636652 78.82636652 0 0 0 78.3624334-79.29029882c0-43.69401562-34.96364785-79.29029883-78.32025825-79.29029883a78.82636652 78.82636652 0 0 0-78.32025742 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029882z m0-51.74957208a27.07679361 27.07679361 0 0 1-26.57068532-27.54072674c0-15.30977536 12.06224753-27.54072593 26.57068532-27.54072593 14.59278892 0 26.57068533 12.23095057 26.57068453 27.54072593a27.07679361 27.07679361 0 0 1-26.57068453 27.54072674zM601.24376214 377.21492718a78.82636652 78.82636652 0 0 0 78.32025742-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025742-79.29029882a78.82636652 78.82636652 0 0 0-78.32025823 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025824 79.29029883z m1e-8-51.74957208a27.07679361 27.07679361 0 0 1-26.57068534-27.54072675c0-15.30977536 11.97789643-27.54072593 26.57068534-27.54072591 14.55061295 0 26.57068533 12.23095057 26.57068451 27.54072592a27.07679361 27.07679361 0 0 1-26.57068451 27.54072674zM378.80916809 433.85687983a78.82636652 78.82636652 0 0 0 78.32025824-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025824-79.29029802a78.82636652 78.82636652 0 0 0-78.32025742 79.29029802c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029883z m0-51.74957209a27.07679361 27.07679361 0 0 1-26.57068451-27.54072674c0-15.30977536 11.97789643-27.54072593 26.57068451-27.54072593 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072593a27.07679361 27.07679361 0 0 1-26.57068533 27.54072674z" p-id="2510"></path></svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575804206892" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3145" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M826.56 470.016c-32.896 0-64.384 12.288-89.984 35.52l0-104.96c0-62.208-50.496-112.832-112.64-113.088L623.936 287.04 519.552 287.104C541.824 262.72 554.56 230.72 554.56 197.12c0-73.536-59.904-133.44-133.504-133.44-73.472 0-133.376 59.904-133.376 133.44 0 32.896 12.224 64.256 35.52 89.984L175.232 287.104l0 0.576C113.728 288.704 64 338.88 64 400.576l0.32 0 0.32 116.48C60.864 544.896 70.592 577.728 100.8 588.48c12.736 4.608 37.632 7.488 60.864-25.28 12.992-18.368 34.24-29.248 56.64-29.248 38.336 0 69.504 31.104 69.504 69.312 0 38.4-31.168 69.504-69.504 69.504-22.656 0-44.032-11.264-57.344-30.4C138.688 610.112 112.576 615.36 102.464 619.136c-29.824 10.752-39.104 43.776-38.144 67.392l0 160.384L64 846.912C64 909.248 114.752 960 177.216 960l446.272 0c62.4 0 113.152-50.752 113.152-113.152l0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.536 0 133.44-59.904 133.44-133.504C960 529.92 900.096 470.016 826.56 470.016zM826.56 672.896c-22.72 0-44.032-11.264-57.344-30.4-22.272-32.384-48.448-27.136-58.56-23.36-29.824 10.752-39.04 43.776-38.08 67.392l0 160.384c0 27.136-22.016 49.152-49.152 49.152L177.216 896.064C150.08 896 128 873.984 128 846.848l0.32 0 0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.6 0 133.504-59.904 133.504-133.504 0-73.472-59.904-133.376-133.504-133.376-32.896 0-64.32 12.288-89.984 35.52l0-104.96L128 400.512c0-27.072 22.08-49.152 49.216-49.152L177.216 351.04 334.656 350.72c3.776 0.512 7.616 0.832 11.52 0.832 24.896 0 50.752-10.816 60.032-37.056 4.544-12.736 7.424-37.568-25.344-60.736C362.624 240.768 351.68 219.52 351.68 197.12c0-38.272 31.104-69.44 69.376-69.44 38.336 0 69.504 31.168 69.504 69.44 0 22.72-11.264 44.032-30.528 57.472C427.968 276.736 433.088 302.784 436.8 313.024c10.752 29.888 43.072 39.232 67.392 38.08l119.232 0 0 0.384c27.136 0 49.152 22.08 49.152 49.152l0.256 116.48c-3.776 27.84 6.016 60.736 36.224 71.488 12.736 4.608 37.632 7.488 60.8-25.28 13.056-18.368 34.24-29.248 56.704-29.248C864.832 534.016 896 565.12 896 603.392 896 641.728 864.832 672.896 826.56 672.896z" p-id="3146"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774833889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1376" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M887.466667 192.853333h-100.693334V119.466667c0-10.24-6.826667-17.066667-17.066666-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H303.786667V119.466667c0-10.24-6.826667-17.066667-17.066667-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H168.96c-46.08 0-85.333333 37.546667-85.333333 85.333334V836.266667c0 46.08 37.546667 85.333333 85.333333 85.333333H887.466667c46.08 0 85.333333-37.546667 85.333333-85.333333V278.186667c0-47.786667-37.546667-85.333333-85.333333-85.333334z m-718.506667 34.133334h100.693333v66.56c0 10.24 6.826667 17.066667 17.066667 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56h450.56v66.56c0 10.24 6.826667 17.066667 17.066666 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56H887.466667c27.306667 0 51.2 22.186667 51.2 51.2v88.746666H117.76v-88.746666c0-29.013333 22.186667-51.2 51.2-51.2zM887.466667 887.466667H168.96c-27.306667 0-51.2-22.186667-51.2-51.2V401.066667H938.666667V836.266667c0 27.306667-22.186667 51.2-51.2 51.2z" p-id="1377"></path><path d="M858.453333 493.226667H327.68c-10.24 0-17.066667 6.826667-17.066667 17.066666v114.346667h-116.053333c-10.24 0-17.066667 6.826667-17.066667 17.066667v133.12c0 10.24 6.826667 17.066667 17.066667 17.066666H460.8c10.24 0 17.066667-6.826667 17.066667-17.066666v-114.346667h380.586666c10.24 0 17.066667-6.826667 17.066667-17.066667v-133.12c0-10.24-6.826667-17.066667-17.066667-17.066666z m-413.013333 34.133333v97.28h-98.986667v-97.28h98.986667z m-230.4 131.413333h98.986667v98.986667h-98.986667v-98.986667z m131.413333 97.28v-97.28h98.986667v97.28h-98.986667z m133.12-228.693333h97.28v98.986667h-97.28v-98.986667z m131.413334 0h98.986666v98.986667h-98.986666v-98.986667z m230.4 97.28h-98.986667v-98.986667h98.986667v98.986667z" p-id="1378"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577186573535" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1068" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M479.85714249 608.42857168h64.28571502c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285751s-12.85714249-32.14285751-32.14285664-32.14285664h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285662s12.85714249 32.14285751 32.14285664 32.14285753z m-2e-8 122.14285665h64.28571504c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285665s-12.85714249-32.14285751-32.14285664-32.14285751h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285751s12.85714249 32.14285751 32.14285664 32.14285664z m353.57142921-559.28571416h-128.57142921v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285664-32.14285753s-32.14285751 12.85714249-32.14285751 32.14285753v32.14285664h-257.14285665v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285752-32.14285753s-32.14285751 12.85714249-32.14285664 32.14285753v32.14285664h-128.57142919c-70.71428585 0-128.57142832 57.85714249-128.57142832 122.14285751v501.42857081c0 70.71428585 57.85714249 128.57142832 128.57142832 122.14285751h642.85714335c70.71428585 0 128.57142832-57.85714249 128.57142833-122.14285751v-501.42857081c0-70.71428585-57.85714249-122.14285753-128.57142833-122.14285751z m64.28571415 623.57142832c0 32.14285751-32.14285751 64.28571415-64.28571416 64.28571504h-642.85714335c-32.14285751 0-64.28571415-25.71428583-64.28571417-64.28571504v-372.85714249h771.42857168v372.85714249z m0-437.14285664h-771.42857168v-64.28571417c0-32.14285751 32.14285751-64.28571415 64.28571417-64.28571415h128.57142919v32.14285664c0 19.28571417 12.85714249 32.14285751 32.14285664 32.14285751s32.14285751-12.85714249 32.14285753-32.14285751v-32.14285664h257.14285665v32.14285664c0 19.28571417 12.85714249 32.14285751 32.1428575 32.14285751s32.14285751-12.85714249 32.14285664-32.14285751v-32.14285664h128.57142921c32.14285751 0 64.28571415 25.71428583 64.28571415 64.28571415v64.28571417z m-610.71428583 372.85714247h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285664s-12.85714249-32.14285751-32.14285753-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285751s12.85714249 32.14285751 32.14285751 32.14285665z m385.71428583-122.14285664h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285751s-12.85714249-32.14285751-32.14285751-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285664s12.85714249 32.14285751 32.14285753 32.14285751z m-385.71428583 0h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285751s-12.85714249-32.14285751-32.14285753-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285664s12.85714249 32.14285751 32.14285751 32.14285751z m385.71428583 122.14285665h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285665s-12.85714249-32.14285751-32.14285751-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285751s12.85714249 32.14285751 32.14285753 32.14285665z" p-id="1069"></path></svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035680909" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3601" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1002.0848 744.672l-33.568 10.368c0.96 7.264 2.144 14.304 2.144 21.76 0 7.328-1.184 14.432-2.368 21.568l33.792 10.56c7.936 2.24 14.496 7.616 18.336 14.752 3.84 7.328 4.672 15.808 1.952 23.552-5.376 16-23.168 24.672-39.936 19.68l-34.176-10.624c-7.136 12.8-15.776 24.672-26.208 35.2l20.8 27.488a28.96 28.96 0 0 1 5.824 22.816 29.696 29.696 0 0 1-12.704 19.616 32.544 32.544 0 0 1-44.416-6.752l-20.8-27.552c-13.696 6.56-28.192 11.2-43.008 13.888v33.632c0 16.736-14.112 30.432-31.648 30.432-17.6 0-31.872-13.696-31.872-30.432v-33.632a167.616 167.616 0 0 1-42.88-13.888l-20.928 27.552c-10.72 13.76-30.08 16.64-44.288 6.752a29.632 29.632 0 0 1-12.704-19.616 29.28 29.28 0 0 1 5.696-22.816l20.896-27.808a166.72 166.72 0 0 1-27.008-34.688l-33.376 10.432c-16.8 5.184-34.56-3.552-39.936-19.616a29.824 29.824 0 0 1 20.224-38.24l33.472-10.432c-0.8-7.264-2.016-14.304-2.016-21.824 0-7.36 1.184-14.496 2.304-21.632l-33.792-10.368c-16.672-5.376-25.632-22.496-20.224-38.432 5.376-16 23.136-24.672 39.936-19.68l34.016 10.752c7.328-12.672 15.84-24.8 26.336-35.328l-20.8-27.552a29.44 29.44 0 0 1 6.944-42.432 32.704 32.704 0 0 1 44.384 6.752l20.832 27.616c13.696-6.432 28.224-11.2 43.104-13.952v-33.568c0-16.736 14.048-30.432 31.648-30.432 17.536 0 31.808 13.568 31.808 30.432v33.504c15.072 2.688 29.344 7.808 42.848 14.016l20.992-27.616a32.48 32.48 0 0 1 44.224-6.752 29.568 29.568 0 0 1 7.136 42.432l-21.024 27.808c10.432 10.432 19.872 21.888 27.04 34.752l33.376-10.432c16.768-5.12 34.56 3.68 39.936 19.68 5.536 15.936-3.712 33.056-20.32 38.304z m-206.016-74.432c-61.344 0-111.136 47.808-111.136 106.56 0 58.88 49.792 106.496 111.136 106.496 61.312 0 111.104-47.616 111.104-106.496 0-58.752-49.792-106.56-111.104-106.56z" p-id="3602"></path><path d="M802.7888 57.152h-76.448c0-22.08-21.024-38.24-42.848-38.24H39.3968a39.68 39.68 0 0 0-39.36 40.032v795.616s41.888 120.192 110.752 120.192H673.2848a227.488 227.488 0 0 1-107.04-97.44H117.6368s-40.608-13.696-40.608-41.248l470.304-0.256 1.664 3.36a227.68 227.68 0 0 1-12.64-73.632c0-60.576 24-118.624 66.88-161.44a228.352 228.352 0 0 1 123.552-63.392l-3.2 0.288 2.144-424.672h38.208l0.576 421.024c27.04 0 52.672 4.8 76.64 13.344V101.536c0.032 0-6.304-44.384-38.368-44.384zM149.7648 514.336H72.3888v-77.408H149.7648v77.408z m0-144.32H72.3888v-77.44H149.7648v77.44z m0-137.248H72.3888v-77.44H149.7648v77.44z m501.856 281.568H206.0848v-77.408h445.536v77.408z m0-144.32H206.0848v-77.44h445.536v77.44z m0-137.248H206.0848v-77.44h445.536v77.44z" p-id="3603"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>
|
||||||
|
After Width: | Height: | Size: 418 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569915748289" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3062" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M768.35456 416a256 256 0 1 0-512 0 192 192 0 1 0 0 384v64a256 256 0 0 1-58.88-505.216 320.128 320.128 0 0 1 629.76 0A256.128 256.128 0 0 1 768.35456 864v-64a192 192 0 0 0 0-384z m-512 384h64v64H256.35456v-64z m448 0h64v64h-64v-64z" fill="#333333" p-id="3063"></path><path d="M539.04256 845.248V512.192a32.448 32.448 0 0 0-32-32.192c-17.664 0-32 14.912-32 32.192v333.056l-36.096-36.096a32.192 32.192 0 0 0-45.056 0.192 31.616 31.616 0 0 0-0.192 45.056l90.88 90.944a31.36 31.36 0 0 0 22.528 9.088 30.08 30.08 0 0 0 22.4-9.088l90.88-90.88a32.192 32.192 0 0 0-0.192-45.12 31.616 31.616 0 0 0-45.056-0.192l-36.096 36.096z" fill="#333333" p-id="3064"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M73.137 29.08h-9.209 29.7L63.886.093 34.373 29.08h20.49v27.035H27.238v17.948h27.625v27.133h18.274V74.063h27.41V56.115h-27.41V29.08zm-9.245 98.827l27.518-26.711H36.59l27.302 26.71zM.042 64.982l27.196 27.029V38.167L.042 64.982zm100.505-26.815V92.01l27.41-27.029-27.41-26.815z"/></svg>
|
||||||
|
After Width: | Height: | Size: 356 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036347051" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5853" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M832 128H192a64.19 64.19 0 0 0-64 64v640a64.19 64.19 0 0 0 64 64h640a64.19 64.19 0 0 0 64-64V192a64.19 64.19 0 0 0-64-64z m0 703.89l-0.11 0.11H192.11l-0.11-0.11V768h640zM832 544H720L605.6 696.54 442.18 435.07 333.25 544H192v-64h114.75l147.07-147.07L610.4 583.46 688 480h144z m0-288H192v-63.89l0.11-0.11h639.78l0.11 0.11z" p-id="5854"></path></svg>
|
||||||
|
After Width: | Height: | Size: 724 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>
|
||||||
|
After Width: | Height: | Size: 818 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>
|
||||||
|
After Width: | Height: | Size: 627 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="96" xmlns="http://www.w3.org/2000/svg"><path d="M64.125 56.975L120.188.912A12.476 12.476 0 0 0 115.5 0h-103c-1.588 0-3.113.3-4.513.838l56.138 56.137z"/><path d="M64.125 68.287l-62.3-62.3A12.42 12.42 0 0 0 0 12.5v71C0 90.4 5.6 96 12.5 96h103c6.9 0 12.5-5.6 12.5-12.5v-71a12.47 12.47 0 0 0-1.737-6.35L64.125 68.287z"/></svg>
|
||||||
|
After Width: | Height: | Size: 347 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746590936918" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" xmlns:xlink="http://www.w3.org/1999/xlink" width="233.203125" height="200"><path d="M1151.9144 325.11999969V89.12a57.04000031 57.04000031 0 0 0-28.8-49.44 58.15999969 58.15999969 0 0 0-57.76000031 0 57.04000031 57.04000031 0 0 0-28.8 49.44v235.99999969c0.24 84.31999969-33.6 152.56000031-94.08 212.00000062-60.07999969 59.83999969-141.84 80.64-227.04 80.4H225.91440031L388.07439969 457.11999969a56.80000031 56.80000031 0 0 0 12.40000031-62.16 57.76000031 57.76000031 0 0 0-94.00000031-18.63999938L48.8744 631.20000031a56.88 56.88 0 0 0 0 80.79999938l264.96 262.56a58.08 58.08 0 0 0 96.55999969-25.59999938 56.80000031 56.80000031 0 0 0-14.95999969-55.2L232.07439969 731.67999969h483.44000062c116.56000031 0 226.15999969-32.08000031 308.64-113.76 82.15999969-80.80000031 128.23999969-178.15999969 127.83999938-292.87999969" p-id="5379"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>
|
||||||
|
After Width: | Height: | Size: 497 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.208 16.576v8.384h38.72v5.376h-38.72v8.704h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.512h38.72v5.376h-38.72v11.136H128v-94.72H78.208zM0 114.368L72.128 128V0L0 13.632v100.736z"/><path d="M28.672 82.56h-11.2l14.784-23.488-14.08-22.592h11.52l8.192 14.976 8.448-14.976h11.136l-14.08 22.208L58.368 82.56H46.656l-8.768-15.68z"/></svg>
|
||||||
|
After Width: | Height: | Size: 459 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>
|
||||||
|
After Width: | Height: | Size: 944 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>
|
||||||
|
After Width: | Height: | Size: 421 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1581238998885" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4187" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M511.542857 14.057143C228.914286 13.942857 0 242.742857 0 525.142857 0 748.457143 143.2 938.285714 342.628571 1008c26.857143 6.742857 22.742857-12.342857 22.742858-25.371429v-88.571428c-155.085714 18.171429-161.371429-84.457143-171.771429-101.6C172.571429 756.571429 122.857143 747.428571 137.714286 730.285714c35.314286-18.171429 71.314286 4.571429 113.028571 66.171429 30.171429 44.685714 89.028571 37.142857 118.857143 29.714286 6.514286-26.857143 20.457143-50.857143 39.657143-69.485715-160.685714-28.8-227.657143-126.857143-227.657143-243.428571 0-56.571429 18.628571-108.571429 55.2-150.514286-23.314286-69.142857 2.171429-128.342857 5.6-137.142857 66.4-5.942857 135.428571 47.542857 140.8 51.771429 37.714286-10.171429 80.8-15.542857 129.028571-15.542858 48.457143 0 91.657143 5.6 129.714286 15.885715 12.914286-9.828571 76.914286-55.771429 138.628572-50.171429 3.314286 8.8 28.228571 66.628571 6.285714 134.857143 37.028571 42.057143 55.885714 94.514286 55.885714 151.2 0 116.8-67.428571 214.971429-228.571428 243.314286a145.714286 145.714286 0 0 1 43.542857 104v128.571428c0.914286 10.285714 0 20.457143 17.142857 20.457143 202.4-68.228571 348.114286-259.428571 348.114286-484.685714 0-282.514286-229.028571-511.2-511.428572-511.2z" p-id="4188"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.482 70.131l36.204 16.18 69.932-65.485-61.38 70.594 46.435 18.735c1.119.425 2.397-.17 2.797-1.363v-.085L127.998.047 1.322 65.874c-1.12.597-1.519 1.959-1.04 3.151.32.511.72.937 1.2 1.107zm44.676 57.821L64.22 107.26l-18.062-7.834v28.527z"/></svg>
|
||||||
|
After Width: | Height: | Size: 320 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.147.062a13 13 0 0 1 4.94.945c1.55.63 2.907 1.526 4.069 2.688a13.148 13.148 0 0 1 2.761 4.069c.678 1.55 1.017 3.245 1.017 5.086v102.3c0 3.681-1.187 6.733-3.56 9.155-2.373 2.422-5.352 3.633-8.937 3.633H12.992c-3.875 0-7-1.26-9.373-3.779-2.373-2.518-3.56-5.667-3.56-9.445V12.704c0-3.39 1.163-6.345 3.488-8.863C5.872 1.32 8.972.062 12.847.062h102.3zM81.434 109.047c1.744 0 3.003-.412 3.778-1.235.775-.824 1.163-1.914 1.163-3.27 0-1.26-.388-2.325-1.163-3.197-.775-.872-2.034-1.307-3.778-1.307H72.57c.097-.194.145-.485.145-.872V27.09h9.01c1.743 0 2.954-.436 3.633-1.308.678-.872 1.017-1.938 1.017-3.197 0-1.26-.34-2.325-1.017-3.197-.679-.872-1.89-1.308-3.633-1.308H46.268c-1.743 0-2.954.436-3.632 1.308-.678.872-1.018 1.938-1.018 3.197 0 1.26.34 2.325 1.018 3.197.678.872 1.889 1.308 3.632 1.308h8.138v72.075c0 .193.024.339.073.436.048.096.072.242.072.436H46.56c-1.744 0-3.003.435-3.778 1.307-.775.872-1.163 1.938-1.163 3.197 0 1.356.388 2.446 1.163 3.27.775.823 2.034 1.235 3.778 1.235h34.875z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802859706" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3102" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 224H128c-35.2 0-64 28.8-64 64v448c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64z m0 480c0 19.2-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V320c0-19.2 12.8-32 32-32h704c19.2 0 32 12.8 32 32v384z" p-id="3103"></path><path d="M224 352c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32s32-12.8 32-32V384c0-16-12.8-32-32-32z" p-id="3104"></path></svg>
|
||||||
|
After Width: | Height: | Size: 744 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M83.287 103.01c-1.57-3.84-6.778-10.414-15.447-19.548-2.327-2.444-2.182-4.306-1.338-9.862v-.64c.553-3.81 1.513-6.05 14.313-8.087 6.516-1.018 8.203 1.57 10.589 5.178l.785 1.193a12.625 12.625 0 0 0 6.43 5.207c1.134.524 2.53 1.164 4.421 2.24 4.596 2.53 4.596 5.41 4.596 11.753v.727a26.91 26.91 0 0 1-5.178 17.454 59.055 59.055 0 0 1-19.025 11.026c3.49-6.546.814-14.313 0-16.553l-.146-.087zM64 5.12a58.502 58.502 0 0 1 25.484 5.818 54.313 54.313 0 0 0-12.859 10.327c-.93 1.28-1.716 2.473-2.472 3.579-2.444 3.694-3.637 5.352-5.818 5.614a25.105 25.105 0 0 1-4.219 0c-4.276-.29-10.094-.64-11.956 4.422-1.193 3.23-1.396 11.956 2.444 16.495.66 1.077.778 2.4.32 3.578a7.01 7.01 0 0 1-2.066 3.229 18.938 18.938 0 0 1-2.909-2.91 18.91 18.91 0 0 0-8.32-6.603c-1.25-.349-2.647-.64-3.985-.93-3.782-.786-8.03-1.688-9.019-3.812a14.895 14.895 0 0 1-.727-5.818 21.935 21.935 0 0 0-1.396-9.25 8.873 8.873 0 0 0-5.557-4.946A58.705 58.705 0 0 1 64 5.12zM0 64c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64 0-35.346-28.654-64-64-64C28.654 0 0 28.654 0 64z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036191400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5472" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M934.912 1016.832H192c-14.336 0-25.6-11.264-25.6-25.6v-189.44c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v163.84h691.712V64H217.6v148.48c0 14.336-11.264 25.6-25.6 25.6s-25.6-11.264-25.6-25.6v-174.08c0-14.336 11.264-25.6 25.6-25.6h742.912c14.336 0 25.6 11.264 25.6 25.6v952.832c0 14.336-11.264 25.6-25.6 25.6z" p-id="5473"></path><path d="M232.96 371.2h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 540.16h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 698.88h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM574.464 762.88c-134.144 0-243.2-109.056-243.2-243.2S440.32 276.48 574.464 276.48s243.2 109.056 243.2 243.2-109.056 243.2-243.2 243.2z m0-435.2c-105.984 0-192 86.016-192 192S468.48 711.68 574.464 711.68s192-86.016 192-192S680.448 327.68 574.464 327.68z" p-id="5474"></path><path d="M663.04 545.28h-87.04c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h87.04c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6z" p-id="5475"></path><path d="M576 545.28c-14.336 0-25.6-11.264-25.6-25.6v-87.04c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v87.04c0 14.336-11.264 25.6-25.6 25.6z" p-id="5476"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.742 36.8c2.398 7.2 5.595 12.8 11.19 18.4 4.795-4.8 7.992-11.2 10.39-18.4h-21.58zm-52.748 40h20.78l-10.39-28-10.39 28z"/><path d="M111.916 0H16.009C7.218 0 .025 7.2.025 16v96c0 8.8 7.193 16 15.984 16h95.907c8.791 0 15.984-7.2 15.984-16V16c0-8.8-6.394-16-15.984-16zM72.754 103.2c-1.598 1.6-3.197 1.6-4.795 1.6-.8 0-2.398 0-3.197-.8-.8-.8-1.599 0-1.599-.8s-.799-1.6-1.598-3.2c-.8-1.6-.8-2.4-1.599-4l-3.196-8.8H28.797L25.6 96c-1.598 3.2-2.398 5.6-3.197 7.2-.8 1.6-2.398 1.6-4.795 1.6-1.599 0-3.197-.8-4.796-1.6-1.598-1.6-2.397-2.4-2.397-4 0-.8 0-1.6.799-3.2.8-1.6.8-2.4 1.598-4l17.583-44.8c.8-1.6.8-3.2 1.599-4.8.799-1.6 1.598-3.2 2.397-4 .8-.8 1.599-2.4 3.197-3.2 1.599-.8 3.197-.8 4.796-.8 1.598 0 3.196 0 4.795.8 1.598.8 2.398 1.6 3.197 3.2.799.8 1.598 2.4 2.397 4 .8 1.6 1.599 3.2 2.398 5.6l17.583 44c1.598 3.2 2.398 5.6 2.398 7.2-.8.8-1.599 2.4-2.398 4zM116.711 72c-8.791-3.2-15.185-7.2-20.78-12-5.594 5.6-12.787 9.6-21.579 12l-2.397-4c8.791-2.4 15.984-5.6 21.579-11.2C87.939 51.2 83.144 44 81.545 36h-7.992v-3.2h21.58c-1.6-2.4-3.198-5.6-4.796-8l2.397-.8c1.599 2.4 3.997 5.6 5.595 8.8h19.98v4h-7.992c-2.397 8-6.393 15.2-11.189 20 5.595 4.8 11.988 8.8 20.78 11.2l-3.197 4z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>
|
||||||
|
After Width: | Height: | Size: 285 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.585 12.087c0 6.616 3.974 11.98 8.877 11.98 4.902 0 8.877-5.364 8.877-11.98 0-6.616-3.975-11.98-8.877-11.98-4.903 0-8.877 5.364-8.877 11.98zM125.86.107H35.613c-1.268 0-2.114 1.426-2.114 2.852v18.255c0 1.712 1.057 2.853 2.114 2.853h90.247c1.268 0 2.114-1.426 2.114-2.853V2.96c0-1.711-1.057-2.852-2.114-2.852zM.106 62.86c0 6.615 3.974 11.979 8.876 11.979 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zM124.17 50.88H33.921c-1.268 0-2.114 1.425-2.114 2.851v18.256c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852V53.73c0-1.426-.846-2.852-2.114-2.852zM.106 115.913c0 6.616 3.974 11.98 8.876 11.98 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zm124.064-11.98H33.921c-1.268 0-2.114 1.426-2.114 2.853v18.255c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852v-18.255c0-1.427-.846-2.853-2.114-2.853z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1017 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M119.88 49.674h-7.987V39.52C111.893 17.738 90.45.08 63.996.08 37.543.08 16.1 17.738 16.1 39.52v10.154H8.113c-4.408 0-7.987 2.94-7.987 6.577v65.13c0 3.637 3.57 6.577 7.987 6.577H119.88c4.407 0 7.987-2.94 7.987-6.577v-65.13c-.008-3.636-3.58-6.577-7.987-6.577zm-23.953 0H32.065V39.52c0-14.524 14.301-26.295 31.931-26.295 17.63 0 31.932 11.777 31.932 26.295v10.153z"/></svg>
|
||||||
|
After Width: | Height: | Size: 444 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035943711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4805" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M208.736 566.336H64.384v59.328h144.352v-59.328z m0-336.096H165.44V74.592c0-7.968 4.896-14.848 10.464-14.848h502.016V0.448H175.936c-38.72 1.248-69.248 34.368-68.192 74.144v155.648H64.384V289.6h144.352V230.24z m0 168.096H64.384v59.328h144.352v-59.328z m714.656 76.576h-57.76v474.496c0 7.936-4.896 14.848-10.464 14.848H175.936c-5.568 0-10.464-6.912-10.464-14.848v-155.68h43.296v-59.296H64.384v59.296h43.328v155.68c-1.024 39.776 29.472 72.896 68.192 74.144h679.232c38.72-1.184 69.248-34.368 68.256-74.144V474.912z m14.944-290.336l-83.072-85.312a71.264 71.264 0 0 0-52.544-21.728 71.52 71.52 0 0 0-51.616 23.872L386.528 507.264a30.496 30.496 0 0 0-6.176 10.72L308.16 740.512a30.016 30.016 0 0 0 6.976 30.24c7.712 7.968 19.2 10.752 29.568 7.2l216.544-74.112a28.736 28.736 0 0 0 12.128-7.936L940.448 287.456a75.552 75.552 0 0 0-2.112-102.88z m-557.12 518.272l39.104-120.64 78.336 80.416-117.44 40.224z m170.048-70.016l-103.552-106.016 200.16-222.4 103.52 106.304-200.128 222.112zM897.952 247.072l-0.256 0.224-107.136 119.168-103.52-106.528 106.432-118.624a14.144 14.144 0 0 1 10.304-4.736 13.44 13.44 0 0 1 10.464 4.288l83.264 85.696c5.472 5.6 5.664 14.72 0.448 20.512z" p-id="4806"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036016814" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5261" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 128h-85.333333a42.666667 42.666667 0 0 0 0 85.333333h42.666666v640H170.666667V213.333333h42.666666a42.666667 42.666667 0 0 0 0-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666667v725.333333a42.666667 42.666667 0 0 0 42.666667 42.666667h768a42.666667 42.666667 0 0 0 42.666667-42.666667V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667z" p-id="5262"></path><path d="M341.333333 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666666 42.666667zM512 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333334 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM682.666667 298.666667a42.666667 42.666667 0 0 0 42.666666-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM341.333333 768a42.666667 42.666667 0 0 0 42.666667-42.666667 128 128 0 0 1 256 0 42.666667 42.666667 0 0 0 85.333333 0 213.333333 213.333333 0 0 0-107.52-184.32A128 128 0 0 0 640 469.333333a128 128 0 0 0-256 0 128 128 0 0 0 22.186667 71.68A213.333333 213.333333 0 0 0 298.666667 725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667z m128-298.666667a42.666667 42.666667 0 1 1 42.666667 42.666667 42.666667 42.666667 0 0 1-42.666667-42.666667z" p-id="5263"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>
|
||||||
|
After Width: | Height: | Size: 669 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>
|
||||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
|
||||||
|
</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
|
||||||
|
After Width: | Height: | Size: 883 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733303018722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M368.832 67.2c51.328-16.384 89.216 34.112 75.712 76.416a346.816 346.816 0 0 0 435.84 435.84c42.304-13.44 92.8 24.384 76.48 75.712A467.968 467.968 0 1 1 368.832 67.2z m-35.776 122.688a368.832 368.832 0 1 0 501.056 501.056 445.952 445.952 0 0 1-501.056-501.056z" p-id="1448"></path></svg>
|
||||||
|
After Width: | Height: | Size: 619 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746760911144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12537" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M395.21211 182.914448c0 62.669318 49.541323 113.472378 110.642936 113.472378 61.093427 0 110.652146-50.80306 110.65214601-113.472378 0-62.685691-49.559742-113.487727-110.65214601-113.487727C444.75241 69.426721 395.21211 120.22978 395.21211 182.914448zM395.21211 523.34693101c0 62.668295 49.541323 113.487727 110.642936 113.48772699 61.093427 0 110.652146-50.820456 110.652146-113.487727 0-62.669318-49.559742-113.472378-110.652146-113.472378C444.75241 409.874553 395.21211 460.67761301 395.21211 523.34693101zM395.21211 841.084529c0 62.686714 49.541323 113.488751 110.642936 113.488751 61.093427 0 110.652146-50.80203599 110.65214601-113.488751 0-62.669318-49.559742-113.471354-110.65214601-113.471354C444.75241 727.614198 395.21211 778.416234 395.21211 841.084529z" p-id="12538"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>
|
||||||
|
After Width: | Height: | Size: 821 B |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802851180" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2867" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M279.272727 791.272727h512a46.545455 46.545455 0 0 1 0 93.090909H279.272727a46.545455 46.545455 0 0 1 0-93.090909z m33.838546-617.984V651.636364H193.722182V395.170909c0-37.003636-0.884364-59.298909-2.653091-66.746182a24.948364 24.948364 0 0 0-14.615273-16.989091c-8.005818-3.863273-25.786182-5.771636-53.341091-5.771636h-11.822545v-55.854545c57.716364-12.381091 101.562182-37.888 131.490909-76.520728h70.283636z m303.709091 396.8V651.636364H354.164364v-68.235637c77.777455-127.255273 124.043636-206.010182 138.705454-236.218182 14.661818-30.254545 22.016-53.853091 22.016-70.74909 0-13.032727-2.234182-22.714182-6.656-29.137455-4.421818-6.376727-11.170909-9.588364-20.247273-9.588364a22.248727 22.248727 0 0 0-20.200727 10.612364c-4.468364 7.121455-6.656 21.178182-6.656 42.263273v45.521454H354.164364v-17.454545c0-26.763636 1.396364-47.941818 4.142545-63.348364 2.746182-15.499636 9.541818-30.72 20.386909-45.661091 10.798545-14.987636 24.901818-26.298182 42.216727-33.978182 17.361455-7.68 38.167273-11.543273 62.37091-11.543272 47.476364 0 83.316364 11.776 107.706181 35.328 24.296727 23.552 36.445091 53.341091 36.445091 89.367272 0 27.368727-6.842182 56.32-20.48 86.853819-13.730909 30.533818-54.039273 95.325091-121.018182 194.420363h130.885819z m270.615272-189.393454c18.152727 6.097455 31.650909 16.104727 40.494546 29.975272 8.843636 13.917091 13.312 46.452364 13.312 97.652364 0 38.027636-4.328727 67.490909-13.032727 88.529455-8.657455 20.945455-23.598545 36.910545-44.869819 47.848727-21.271273 10.938182-48.593455 16.384-81.873454 16.384-37.794909 0-67.490909-6.330182-89.088-19.083636-21.550545-12.660364-35.746909-28.253091-42.542546-46.638546-6.795636-18.432-10.193455-50.362182-10.193454-95.883636v-37.841455h119.389091v77.730909c0 20.666182 1.210182 33.838545 3.723636 39.424 2.420364 5.585455 7.912727 8.424727 16.337455 8.424728 9.309091 0 15.36-3.537455 18.338909-10.612364 2.932364-7.121455 4.421818-25.6 4.421818-55.575273v-33.047273c0-18.338909-2.048-31.744-6.190546-40.215272a30.72 30.72 0 0 0-18.338909-16.709818c-8.052364-2.653091-23.738182-4.189091-46.964363-4.561455V357.050182c28.392727 0 45.893818-1.070545 52.596363-3.258182a22.946909 22.946909 0 0 0 14.475637-14.149818c2.932364-7.307636 4.421818-18.711273 4.421818-34.257455v-26.624c0-16.756364-1.722182-27.741091-5.12-33.047272-3.490909-5.352727-8.843636-8.005818-16.151273-8.005819-8.285091 0-13.963636 2.792727-16.989091 8.378182-3.025455 5.632-4.561455 17.640727-4.561454 35.933091v39.284364h-119.389091v-40.773818c0-45.661091 10.472727-76.567273 31.325091-92.625455 20.898909-16.058182 54.085818-24.064 99.607272-24.064 56.878545 0 95.511273 11.170909 115.805091 33.373091 20.293818 22.248727 30.394182 53.201455 30.394182 92.765091 0 26.810182-3.630545 46.173091-10.891636 58.088727-7.307636 11.915636-20.107636 22.807273-38.446546 32.628364z" p-id="2868"></path></svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899557259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="535" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M356.246145 681.56286c-68.156286-41.949414-107.246583-103.84102-107.246583-169.805384 0-65.966411 39.090297-127.860063 107.246583-169.809477 12.046361-7.414877 15.800871-23.190165 8.385994-35.236526-7.413853-12.046361-23.191188-15.801894-35.236526-8.387018-39.640836 24.399713-72.539106 56.044434-95.137801 91.515297-23.86657 37.461193-36.481889 79.620385-36.481889 121.917724 0 42.297338 12.615319 84.454484 36.481889 121.914654 22.598694 35.469839 55.496965 67.11456 95.137801 91.51325 4.185322 2.576685 8.821923 3.804652 13.400195 3.804652 8.598842 0 16.998139-4.329609 21.836331-12.190647C372.047016 704.752002 368.291482 688.976714 356.246145 681.56286zM263.943926 754.580874c-92.603071-61.111846-145.713686-149.623739-145.713686-242.840794 0-93.195565 53.094242-181.682899 145.667637-242.774279 11.805884-7.79043 15.061021-23.677259 7.269567-35.483142-7.79043-11.805884-23.677259-15.062044-35.483142-7.269567C128.487861 296.954249 67.006602 401.024489 67.006602 511.74008c0 110.73708 61.496609 214.830857 168.721703 285.593504 4.343935 2.867304 9.240455 4.238534 14.08274 4.238534 8.317433 0 16.476253-4.046153 21.400403-11.507078C279.003923 778.258133 275.748786 762.372328 263.943926 754.580874zM788.660552 226.213092c-11.80486-7.791453-27.692712-4.536316-35.483142 7.269567-7.79043 11.805884-4.536316 27.692712 7.269567 35.483142 92.575442 61.092403 145.670707 149.579737 145.670707 242.774279 0 93.216032-53.111638 181.727924-145.715733 242.840794-11.805884 7.79043-15.059997 23.678282-7.269567 35.484166 4.925173 7.461949 13.081946 11.507078 21.400403 11.507078 4.841262 0 9.739828-1.37123 14.083763-4.238534 107.22714-70.761624 168.724773-174.857447 168.724773-285.593504C957.341323 401.025513 895.860063 296.955272 788.660552 226.213092zM790.090111 633.67213c23.865547-37.459147 36.480866-79.617315 36.480866-121.914654 0-42.298362-12.615319-84.45653-36.480866-121.917724-22.598694-35.470863-55.496965-67.115584-95.139847-91.515297-12.047384-7.413853-27.821649-3.659343-35.236526 8.387018-7.414877 12.045337-3.659343 27.821649 8.385994 35.236526 68.156286 41.949414 107.247606 103.842043 107.247606 169.809477 0 65.964364-39.090297 127.85597-107.247606 169.804361-12.045337 7.414877-15.800871 23.190165-8.385994 35.237549 4.838192 7.861038 13.236466 12.190647 21.835308 12.190647 4.579295 0 9.215896-1.227967 13.400195-3.804652C734.591099 700.786691 767.490394 669.142993 790.090111 633.67213zM567.129086 518.274914c24.12342-17.150612 39.887452-45.305859 39.887452-77.07133 0-52.128241-42.452881-94.538143-94.634334-94.538143-52.18043 0-94.633311 42.408879-94.633311 94.538143 0 31.695886 15.696494 59.797921 39.730886 76.958766-49.875944 21.128203-84.917018 70.234621-84.917018 127.301338 0 2.366907 0.061398 4.762467 0.182149 7.119141l1.249457 24.296359 276.373515 0 1.238201-24.308639c0.119727-2.358721 0.181125-4.750187 0.181125-7.106862C651.786185 588.497255 616.865861 539.465538 567.129086 518.274914zM512.381182 397.889079c23.937179 0 43.411719 19.430538 43.411719 43.314505 0 23.882943-19.47454 43.313481-43.411719 43.313481-23.936155 0-43.409672-19.430538-43.409672-43.313481C468.971509 417.320641 488.445026 397.889079 512.381182 397.889079zM426.08884 625.656573c9.119705-38.542828 44.254923-67.337641 86.085634-67.337641s76.966952 28.794813 86.085634 67.337641L426.08884 625.656573z" p-id="536"></path></svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802846045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.593046 403.832442c-30.081109-28.844955-70.037123-44.753273-112.624057-44.753273L265.949606 359.079168c-42.554188 0-82.510202 15.908318-112.469538 44.690852-30.236652 28.782533-46.857191 67.222007-46.857191 108.198258l0 294.079782c0 40.977273 16.619516 79.414701 46.702672 108.136859 29.959336 28.844955 70.069869 44.814672 112.624057 44.814672l490.019383 0c42.585911 0 82.696444-15.969717 112.624057-44.814672 30.082132-28.844955 46.579875-67.222007 46.579875-108.136859L915.172921 511.968278C915.171897 471.053426 898.675178 432.677397 868.593046 403.832442zM841.821309 806.049083c0 22.098297-8.882298 42.772152-25.099654 58.306964-16.154935 15.661701-37.81935 24.203238-60.752666 24.203238L265.949606 888.559285c-22.934339 0-44.567032-8.54256-60.877509-24.264637-16.186657-15.474436-25.067932-36.148291-25.067932-58.246589L180.004165 511.968278c0-22.035876 8.881274-42.772152 25.192775-58.307987 16.186657-15.536858 37.81935-24.139793 60.753689-24.139793l490.019383 0c22.933315 0 44.597731 8.602935 60.752666 24.139793 16.21838 15.535835 25.099654 36.272112 25.099654 58.307987L841.822332 806.049083zM510.974136 135.440715c114.914216 0 208.318536 89.75214 208.318536 200.055338l73.350588 0c0-149.113109-126.366036-270.496667-281.669124-270.496667-155.333788 0-281.699824 121.383558-281.699824 270.496667l73.350588 0C302.623877 225.193879 396.059919 135.440715 510.974136 135.440715zM474.299865 747.244792l73.350588 0L547.650453 629.576859l-73.350588 0L474.299865 747.244792z" p-id="2751"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><path d="M869.073 277.307H657.111V65.344l211.962 211.963zm-238.232 26.27V65.344l-476.498-.054v416.957h714.73v-178.67H630.841zm-335.836 360.57c-5.07-3.064-10.944-5.133-17.61-6.201-6.67-1.064-13.603-1.6-20.81-1.6h-48.821v85.641h48.822c7.206 0 14.14-.532 20.81-1.6 6.665-1.065 12.54-3.133 17.609-6.202 5.064-3.063 9.134-7.406 12.208-13.007 3.065-5.602 4.6-12.937 4.6-22.011 0-9.07-1.535-16.408-4.6-22.01-3.074-5.603-7.144-9.94-12.208-13.01zM35.82 541.805v416.904h952.358V541.805H35.821zm331.421 191.179c-3.6 11.071-9.343 20.879-17.209 29.413-7.874 8.542-18.078 15.408-30.617 20.61-12.544 5.206-27.747 7.807-45.621 7.807h-66.036v102.45h-62.831V607.517h128.867c17.874 0 33.077 2.6 45.62 7.802 12.541 5.207 22.745 12.076 30.618 20.615 7.866 8.538 13.604 18.277 17.21 29.212 3.6 10.943 5.401 22.278 5.401 34.018 0 11.477-1.8 22.752-5.402 33.819zM644.9 806.417c-5.343 17.61-13.408 32.818-24.212 45.627-10.807 12.803-24.283 22.879-40.423 30.213-16.146 7.343-35.155 11.007-57.03 11.007h-123.26V607.518h123.26c18.41 0 35.552 2.941 51.428 8.808 15.873 5.869 29.618 14.671 41.22 26.412 11.608 11.744 20.674 26.411 27.217 44.02 6.535 17.61 9.803 38.288 9.803 62.035 0 20.81-2.67 40.02-8.003 57.624zm245.362-146.07h-138.07v66.03h119.66v48.829h-119.66v118.058h-62.83V607.518h200.9v52.829h-.001zm-318.2 25.611c-6.402-8.266-14.877-14.604-25.412-19.01-10.544-4.402-23.551-6.602-39.019-6.602h-44.825v180.088h56.029c9.07 0 17.872-1.463 26.415-4.401 8.535-2.932 16.14-7.802 22.812-14.609 6.665-6.8 12.007-15.667 16.007-26.61 4.003-10.94 6.003-24.275 6.003-40.021 0-14.408-1.4-27.416-4.202-39.019-2.8-11.607-7.406-21.542-13.808-29.816zm0 0"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M104.185 95.254c8.161 7.574 13.145 17.441 13.145 28.28 0 1.508-.098 2.998-.285 4.466h-10.784c.238-1.465.403-2.948.403-4.465 0-8.983-4.36-17.115-11.419-23.216C86 104.66 75.355 107.162 64 107.162c-11.344 0-21.98-2.495-31.22-6.83-7.064 6.099-11.444 14.218-11.444 23.203 0 1.517.165 3 .403 4.465H10.955a35.444 35.444 0 0 1-.285-4.465c0-10.838 4.974-20.713 13.127-28.291C9.294 85.42.003 70.417.003 53.58.003 23.99 28.656.001 64 .001s63.997 23.988 63.997 53.58c0 16.842-9.299 31.85-23.812 41.673zM64 36.867c-29.454 0-53.33-10.077-53.33 15.342 0 25.418 23.876 46.023 53.33 46.023 29.454 0 53.33-20.605 53.33-46.023 0-25.419-23.876-15.342-53.33-15.342zm24.888 25.644c-3.927 0-7.111-2.665-7.111-5.953 0-3.288 3.184-5.954 7.11-5.954 3.928 0 7.111 2.666 7.111 5.954s-3.183 5.953-7.11 5.953zm-3.556 16.372c0 4.11-9.55 7.442-21.332 7.442-11.781 0-21.332-3.332-21.332-7.442 0-1.06.656-2.064 1.8-2.976 3.295 2.626 10.79 4.465 19.532 4.465 8.743 0 16.237-1.84 19.531-4.465 1.145.912 1.801 1.916 1.801 2.976zm-46.22-16.372c-3.927 0-7.11-2.665-7.11-5.953 0-3.288 3.183-5.954 7.11-5.954 3.927 0 7.111 2.666 7.111 5.954s-3.184 5.953-7.11 5.953z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |