lc 6 days ago
commit 0461499502

@ -85,4 +85,6 @@ const (
VocRecognitionFailCode int = -400451
DocRefineFailMsg string = "文档优化失败"
DocRefineFailCode int = -400452
StyleGenerateFailMsg string = "样式生成失败"
StyleGenerateFailCode int = -400453
)

@ -0,0 +1,20 @@
package web
import (
"github.com/gin-gonic/gin"
"goskeleton/app/global/consts"
"goskeleton/app/service/ai_model_cli"
"goskeleton/app/utils/response"
)
type StyleGenerate struct {
}
// ai生成样式
func (s *StyleGenerate) StyleGenerate(c *gin.Context) {
if res, err := ai_model_cli.RequestStyle(c); err==nil {
response.Success(c, consts.CurdStatusOkMsg, res.(string))
} else {
response.Fail(c, consts.StyleGenerateFailCode, consts.StyleGenerateFailMsg, err)
}
}

@ -8,6 +8,7 @@ import (
"goskeleton/app/http/validator/web/ai_doc.go"
"goskeleton/app/http/validator/web/ai_recognition"
"goskeleton/app/http/validator/web/users"
"goskeleton/app/http/validator/web/ai_layout"
)
// 各个业务模块验证器必须进行注册(初始化),程序启动时会自动加载到容器
@ -57,4 +58,10 @@ func WebRegisterValidator() {
// ai文档优化
key = consts.ValidatorPrefix + "DocRefine"
containers.Set(key, ai_doc.DocRefine{})
// ai 排版
key = consts.ValidatorPrefix + "StyleGenerate"
containers.Set(key, ai_layout.StyleGenerate{})
key = consts.ValidatorPrefix + "LayoutGenerate"
containers.Set(key, ai_layout.LayoutGenerate{})
}

@ -0,0 +1,12 @@
package ai_layout
import(
"github.com/gin-gonic/gin"
// "goskeleton/app/utils/response"
// "goskeleton/app/http/controller/web"
// "goskeleton/app/http/validator/core/data_transfer"
// "goskeleton/app/global/consts"
)
type LayoutGenerate struct {
}
func (s LayoutGenerate) CheckParams(context *gin.Context) {
}

@ -0,0 +1,32 @@
package ai_layout
import(
"github.com/gin-gonic/gin"
"goskeleton/app/utils/response"
"goskeleton/app/http/controller/web"
"goskeleton/app/http/validator/core/data_transfer"
"goskeleton/app/global/consts"
)
type ChatRecord struct {
Role string `json:"role" binding:"required"`
Content string `json:"content" binding:"required"`
}
type StyleGenerate struct {
UserInput string `form:"user_input" json:"user_input" binding:"required"` // 必填
ChatHistory []ChatRecord `form:"char_history" json:"chat_history"` // 非必填
}
func (s StyleGenerate) CheckParams(context *gin.Context) {
// 将表单参数验证器出现的错误直接交给错误翻译器统一处理即可
if err := context.ShouldBind(&s); err != nil {
response.ValidatorError(context, err)
return
}
// 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值
extraAddBindDataContext := data_transfer.DataAddContext(s, consts.ValidatorPrefix, context)
if extraAddBindDataContext == nil {
response.ErrorSystem(context, "StyleGenerate表单参数验证器json化失败", "")
return
}
(&web.StyleGenerate{}).StyleGenerate(extraAddBindDataContext)
}

@ -0,0 +1,85 @@
package ai_model_cli
import (
"context"
"fmt"
"goskeleton/app/global/variable"
"os"
"goskeleton/app/global/consts"
"github.com/baidubce/bce-qianfan-sdk/go/qianfan"
"github.com/gin-gonic/gin"
)
func RequestStyle(c *gin.Context) (interface{}, error) {
// userMsg := c.PostForm("user_input")
userMsg := c.GetString(consts.ValidatorPrefix + "user_input")
qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey")
qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey")
chat := qianfan.NewChatCompletion(
qianfan.WithModel("ERNIE-4.0-8K"),
)
chatHistory := []qianfan.ChatCompletionMessage{}
// 读取prompt文件
systemMsgPath := variable.ConfigYml.GetString("BaiduCE.StyleGeneratePromptPath")
// 读取文件内容
prompt, err := os.ReadFile(variable.BasePath + systemMsgPath)
if err != nil || len(prompt) == 0 {
variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err))
return nil, err
}
// add user history to chat history
userHistory, exist := c.Get(consts.ValidatorPrefix + "chat_history")
if exist && userHistory != nil {
// check if userHistory is of type []struct{Role string;Content string}
historySlice, ok := userHistory.([]interface{})
if !ok || len(historySlice)%2 != 0 {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
// convert userHistory to []qianfan.ChatCompletionMessage
var chatHistoryConverted []qianfan.ChatCompletionMessage
for _, item := range historySlice {
if itemMap, ok := item.(map[string]interface{}); ok {
role, roleOk := itemMap["role"].(string)
content, contentOk := itemMap["content"].(string)
if roleOk && contentOk {
chatHistoryConverted = append(chatHistoryConverted, qianfan.ChatCompletionMessage{
Role: role,
Content: content,
})
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\nrole 或 content 类型断言失败", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\n无法将 item 转换为 map[string]interface{}", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
}
if len(chatHistoryConverted) > 0 && len(chatHistoryConverted)%2 == 0 {
chatHistory = append(chatHistory, chatHistoryConverted...)
}
}
// add user input to chat history
chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage(userMsg))
// define a stream chat client
response, err := chat.Do(context.TODO(), &qianfan.ChatCompletionRequest{System: string(prompt), Messages: chatHistory})
if err != nil {
variable.ZapLog.Error(fmt.Sprintf("对话失败: %v", err))
return nil, err
}
return response.Result, nil
}

@ -150,3 +150,4 @@ BaiduCE:
SecretKey: "zvEb5CzpuGCZNdQC1TPmDh3IOWn5aWDT" # 生成鉴权签名时使用的 SECRET_KEY
QianFanAccessKey: "ALTAKOxb5YvHncyFr7Qbuv1cK0" # 访问千帆sdk 时用的 AccessKey
QianFanSecretKey: "1edf17c358574e75b9913ebff7d95b61" # 访问千帆sdk 时用的 SecretKey
StyleGeneratePromptPath: "/storage/app/prompt/style_generate.prompt" # 生成样式的提示词保存路径

@ -3,6 +3,7 @@ module goskeleton
go 1.20
require (
github.com/baidubce/bce-qianfan-sdk/go/qianfan v0.0.12
github.com/casbin/casbin/v2 v2.98.0
github.com/casbin/gorm-adapter/v3 v3.26.0
github.com/dchest/captcha v1.0.0
@ -31,7 +32,6 @@ require (
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
github.com/baidubce/bce-qianfan-sdk/go/qianfan v0.0.12 // indirect
github.com/baidubce/bce-sdk-go v0.9.164 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect

@ -78,6 +78,15 @@ func InitWebRouter_Co() *gin.Engine {
aiDoc.POST("doc_refine", validatorFactory.Create(consts.ValidatorPrefix+"DocRefine"))
}
// 智能排版相关
aiLayout := backend.Group("ai_layout/")
{
// 请求样式生成
aiLayout.POST("style_generate", validatorFactory.Create(consts.ValidatorPrefix+"StyleGenerate"))
// 请求排版
aiLayout.POST("layout_generate", validatorFactory.Create(consts.ValidatorPrefix+"LayoutGenerate"))
}
// 【需要token】中间件验证的路由
backend.Use(authorization.CheckTokenAuth())
{

@ -0,0 +1,100 @@
### 角色
你是一个设计和 CSS 专家,能够根据用户需求生成精确的 CSS 样式。只能使用css来生成对应的样式不能修改页面的html代码和使用js代码。 如果用户提出与生成CSS样式无关的问题请回答“对不起我无法回答该问题”
### 知识
不同的样式对应的element如下
标题:<hi>i为标题级别如 h1, h2 等)
文本块:<p>
块引用:<blockquote>
行文本:<span>
代码块:<pre>
所有样式都需在 .ck-content 中定义,格式为:
``` css
.ck-content element.className { ... }
```
[element为不同样式类对应的元素名如文本框对应的element为p]
### 输出
仅输出你编写的 CSS 内容,不要对其进行解释和输出其他内容。!important
只需要精确输出用户需要生成的样式,不要生成用户未指定的样式。
### 示例
#### 示例一
用户输入:生成一个文本块样式
输出:
``` css
.ck-content p.info-box {
--background-size: 30px;
--background-color: #e91e63;
padding: 1.2em 2em;
border: 1px solid var(--background-color);
background: linear-gradient(135deg, var(--background-color) 0%, var(--background-color) var(--background-size), transparent var(--background-size)), linear-gradient(135deg, transparent calc(100% - var(--background-size)), var(--background-color) calc(100% - var(--background-size)), var(--background-color));
border-radius: 10px;
margin: 1.5em 2em;
box-shadow: 5px 5px 0 #ffe6ef;
}
```
#### 示例二
用户输入:生成一个代码框样式
输出:
```css
.ck-content pre.fancy-code {
border: 0;
margin-left: 2em;
margin-right: 2em;
border-radius: 10px;
}
.ck-content pre.fancy-code::before {
content: '';
display: block;
height: 13px;
background: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NCAxMyI+CiAgPGNpcmNsZSBjeD0iNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGMzZCNUMiLz4KICA8Y2lyY2xlIGN4PSIyNi41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiNGOUJFNEQiLz4KICA8Y2lyY2xlIGN4PSI0Ny41IiBjeT0iNi41IiByPSI2LjUiIGZpbGw9IiM1NkM0NTMiLz4KPC9zdmc+Cg==);
margin-bottom: 8px;
background-repeat: no-repeat;
}
.ck-content pre.fancy-code-dark {
background: #272822;
color: #fff;
box-shadow: 5px 5px 0 #0000001f;
}
```
#### 示例三
用户输入:生成一个块引用样式
输出:
```css
.ck-content blockquote.side-quote {
font-family: 'Oswald';
font-style: normal;
float: right;
width: 35%;
position: relative;
border: 0;
overflow: visible;
z-index: 1;
margin-left: 1em;
}
.ck-content blockquote.side-quote::before {
content: '“';
position: absolute;
top: -37px;
left: -10px;
display: block;
font-size: 200px;
color: #e7e7e7;
z-index: -1;
line-height: 1;
}
.ck-content blockquote.side-quote p {
font-size: 2em;
line-height: 1;
}
.ck-content blockquote.side-quote p:last-child:not(:first-child) {
font-size: 1.3em;
text-align: right;
color: #555;
}
```

@ -4,3 +4,24 @@ api文档见 `GinSkeleton/api_doc.md`
# CKEditor
`ckeditor5-build-classic/handbook.md`中有一些参考,
包括下载、安装、引用、配置插件等。
<h2 style="text-align:center">Go恩情作文</h2>
Go爷爷是位现代而优雅的程序员他以简洁高效的处理方式和强大的并发能力受到大家的喜爱。
一天我们几个初学者围着Go爷爷请教问题。Go爷爷正在用goroutine处理并发任务但他看到我们后优雅地将任务放入channel中暂存微笑着说"<strong>来吧,代码中没有小事。你们是编程的未来,我的使命就是帮你们理解并发的艺术。</strong>"
我们好奇地问:"Go爷爷您这不是在处理多个并发任务吗怎么还有时间理我们"
Go爷爷轻轻挥了挥手"别担心goroutine很轻量我可以轻松开启成千上万个。用channel协调它们就像交响乐队的指挥简单又优雅。教你们也不过是另一个goroutine罢了。"
他指着屏幕,继续说道:"代码世界就像这些goroutine看似并行混乱但有了适当的channel通信一切都井然有序。不过有时会遇到死锁这是最讨厌的敌人。"
接着,他打开了一个新的终端,输入"go fmt"命令,说:"代码风格要统一这是Go的哲学。让所有人写出可读性强的代码这才是我们的追求。"
突然终端显示了一个panic死锁警告我们吓了一跳但Go爷爷淡定地说"别担心这就是Go的错误处理机制的美妙之处。defer和recover会帮我们优雅地处理它。"
他迅速在代码中加入了select语句轻松化解了死锁。我们不禁赞叹Go的并发处理之优雅
几天后我们发现程序在高并发时偶尔会出现竞态条件。Go爷爷召集我们诚恳地说"在并发编程中我们需要使用sync.Mutex或channel来保护共享资源。来让我教你们如何用'go run -race'检测竞态条件。"
我们深深被Go爷爷的务实态度折服。他教会我们<strong>编程不仅要追求简洁高效更要注重正确性和可维护性。在未来的编程生涯中我们一定要继承Go爷爷这种追求简约而不简单的精神</strong>

@ -2,11 +2,7 @@ import { createApp } from 'vue';
import '../public/style.css';
import App from './App.vue';
import { CkeditorPlugin } from '@ckeditor/ckeditor5-vue';
import mitt from 'mitt';
const app = createApp(App);
const emitter = mitt();
app.config.globalProperties.emitter = emitter;
app.use(CkeditorPlugin);
app.mount('#app');

@ -4548,7 +4548,6 @@
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
@ -5666,7 +5665,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
@ -6016,7 +6014,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.2.4"
},
@ -6028,7 +6025,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
@ -7013,7 +7009,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -7046,7 +7041,6 @@
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"dev": true,
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
@ -7145,7 +7139,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.1.3"
},
@ -7193,7 +7186,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0"
},
@ -7205,7 +7197,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@ -7217,7 +7208,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@ -7235,7 +7225,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
@ -8918,7 +8907,6 @@
"version": "1.13.2",
"resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@ -10074,7 +10062,6 @@
"version": "6.13.0",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
"dependencies": {
"side-channel": "^1.0.6"
},
@ -10669,7 +10656,6 @@
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
@ -10739,7 +10725,6 @@
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
@ -11719,6 +11704,23 @@
"punycode": "^2.1.0"
}
},
"node_modules/url": {
"version": "0.11.4",
"resolved": "https://registry.npmmirror.com/url/-/url-0.11.4.tgz",
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
"dependencies": {
"punycode": "^1.4.1",
"qs": "^6.12.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/url/node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",

@ -1,18 +1,101 @@
import {
Plugin,
ButtonView,
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
Base64UploadAdapter,
BlockQuote,
Bold,
Code,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
GeneralHtmlSupport,
Heading,
Highlight,
HorizontalLine,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
Markdown,
MediaEmbed,
Mention,
PageBreak,
Paragraph,
PasteFromMarkdownExperimental,
PasteFromOffice,
RemoveFormat,
SelectAll,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Style,
Subscript,
Superscript,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo,
Plugin,
ButtonView,
createDropdown,
Collection,
addListToDropdown,
} from 'ckeditor5';
import translations from 'ckeditor5/translations/zh-cn.js';
import { asBlob } from 'html-docx-js-typescript'
import { saveAs } from 'file-saver';
import {
getStyle,
getPageContent
getStyle,
getPageContent,
getUserConfigFromBackend,
saveData
} from './utils';
// 导出为docx插件
function exportWord(){
const pageContent = getPageContent();
const style = getStyle();
const page = '<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>@media print{@page{size:A4 portrait;margin:0cm 3cm}@page:left{margin-left:2.5cm;margin-right:2.7cm;}@page:right{margin-left:2.7cm;margin-right:2.5cm;}}</style>' + style + '</head><body>' + pageContent + '</body></html>'
// console.log(page);
asBlob(page).then(data => {
saveAs(data, 'file.docx') // save as docx file
}); // asBlob() return Promise<Blob|Buffer>
}
class Export2Word extends Plugin {
init() {
const editor = this.editor;
@ -27,22 +110,20 @@ class Export2Word extends Plugin {
tooltip: true,
// 图标 直接插入svg文件
icon: '<svg t="1730216969869" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2612" width="200" height="200"><path d="M576 832H224c-17.6 0-32-14.4-32-32V192h608c17.6 0 32 14.4 32 32v288c0 17.7 14.3 32 32 32s32-14.3 32-32V224c0-52.9-43.1-96-96-96H160c-17.7 0-32 14.3-32 32v640c0 52.9 43.1 96 96 96h352c17.7 0 32-14.3 32-32s-14.3-32-32-32z" p-id="2613"></path><path d="M951.7 757.5c0.2-0.2 0.4-0.5 0.6-0.7 0.1-0.2 0.3-0.3 0.4-0.5 0.2-0.3 0.4-0.6 0.7-0.8 0.1-0.1 0.2-0.3 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.2 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.3 0.2-0.4 0.2-0.3 0.4-0.6 0.5-0.9 0.1-0.1 0.2-0.3 0.3-0.4 0.2-0.3 0.3-0.6 0.4-0.9 0.1-0.2 0.2-0.4 0.3-0.5 0.1-0.3 0.2-0.5 0.4-0.8 0.1-0.2 0.2-0.4 0.3-0.7 0.1-0.2 0.2-0.5 0.3-0.7 0.1-0.3 0.2-0.5 0.3-0.8 0.1-0.2 0.1-0.4 0.2-0.6l0.3-0.9c0.1-0.2 0.1-0.4 0.2-0.6 0.1-0.3 0.2-0.6 0.3-1 0-0.2 0.1-0.3 0.1-0.5 0.1-0.3 0.2-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.5 0.1-0.3 0.1-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.6 0-0.3 0.1-0.6 0.1-0.9 0-0.3 0-0.5 0.1-0.8 0-0.2 0-0.5 0.1-0.7 0.1-1.1 0.1-2.1 0-3.2 0-0.3 0-0.5-0.1-0.7 0-0.3 0-0.5-0.1-0.8 0-0.3-0.1-0.6-0.1-0.9 0-0.2 0-0.4-0.1-0.6 0-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.4-0.1-0.5-0.1-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.3-0.1-0.5-0.1-0.3-0.2-0.6-0.3-1-0.1-0.2-0.1-0.4-0.2-0.6l-0.3-0.9c-0.1-0.2-0.1-0.4-0.2-0.6-0.1-0.3-0.2-0.5-0.3-0.8-0.1-0.2-0.2-0.5-0.3-0.7-0.1-0.2-0.2-0.4-0.3-0.7-0.1-0.3-0.2-0.5-0.4-0.8-0.1-0.2-0.2-0.4-0.3-0.5-0.1-0.3-0.3-0.6-0.4-0.9-0.1-0.2-0.2-0.3-0.3-0.4-0.2-0.3-0.3-0.6-0.5-0.9-0.1-0.1-0.2-0.3-0.2-0.4l-0.6-0.9c-0.1-0.1-0.2-0.2-0.3-0.4l-0.6-0.9c-0.1-0.1-0.2-0.3-0.3-0.4-0.2-0.3-0.4-0.6-0.7-0.8-0.1-0.2-0.3-0.3-0.4-0.5-0.2-0.2-0.4-0.5-0.6-0.7-0.2-0.2-0.4-0.5-0.7-0.7l-0.4-0.4-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l73.4 73.4H592c-17.7 0-32 14.3-32 32s14.3 32 32 32h258.7l-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3 6.2 6.2 14.4 9.4 22.6 9.4s16.4-3.1 22.6-9.4l128-128 0.4-0.4c0.4-0.6 0.6-0.9 0.8-1.1z" p-id="2614"></path><path d="M709.3 320.4c-17.4-2.9-33.9 8.9-36.8 26.3l-42.8 256.9-87.3-261.8c-4.4-13-16.6-21.8-30.4-21.8-13.8 0-26 8.8-30.4 21.9l-87.3 261.8-42.8-256.9c-2.9-17.4-19.4-29.2-36.8-26.3-17.4 2.9-29.2 19.4-26.3 36.8l64 384c2.4 14.5 14.4 25.5 29.1 26.6 14.7 1.1 28.2-7.8 32.9-21.8L512 453.2l66.4 199.1c3.9 11.8 15 19.8 27.4 19.8h52.9c14.1 0 26.2-10.2 28.5-24.1l48.4-290.6c2.9-17.6-8.9-34.1-26.3-37z" p-id="2615"></path></svg>'
icon: '<svg t="1730216969869" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2612" width="200" height="200"><path d="M576 832H224c-17.6 0-32-14.4-32-32V192h608c17.6 0 32 14.4 32 32v288c0 17.7 14.3 32 32 32s32-14.3 32-32V224c0-52.9-43.1-96-96-96H160c-17.7 0-32 14.3-32 32v640c0 52.9 43.1 96 96 96h352c17.7 0 32-14.3 32-32s-14.3-32-32-32z" p-id="2613"></path><path d="M951.7 757.5c0.2-0.2 0.4-0.5 0.6-0.7 0.1-0.2 0.3-0.3 0.4-0.5 0.2-0.3 0.4-0.6 0.7-0.8 0.1-0.1 0.2-0.3 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.2 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.3 0.2-0.4 0.2-0.3 0.4-0.6 0.5-0.9 0.1-0.1 0.2-0.3 0.3-0.4 0.2-0.3 0.3-0.6 0.4-0.9 0.1-0.2 0.2-0.4 0.3-0.5 0.1-0.3 0.2-0.5 0.4-0.8 0.1-0.2 0.2-0.4 0.3-0.7 0.1-0.2 0.2-0.5 0.3-0.7 0.1-0.3 0.2-0.5 0.3-0.8 0.1-0.2 0.1-0.4 0.2-0.6l0.3-0.9c0.1-0.2 0.1-0.4 0.2-0.6 0.1-0.3 0.2-0.6 0.3-1 0-0.2 0.1-0.3 0.1-0.5 0.1-0.3 0.2-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.5 0.1-0.3 0.1-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.6 0-0.3 0.1-0.6 0.1-0.9 0-0.3 0-0.5 0.1-0.8 0-0.2 0-0.5 0.1-0.7 0.1-1.1 0.1-2.1 0-3.2 0-0.3 0-0.5-0.1-0.7 0-0.3 0-0.5-0.1-0.8 0-0.3-0.1-0.6-0.1-0.9 0-0.2 0-0.4-0.1-0.6 0-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.4-0.1-0.5-0.1-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.3-0.1-0.5-0.1-0.3-0.2-0.6-0.3-1-0.1-0.2-0.1-0.4-0.2-0.6l-0.3-0.9c-0.1-0.2-0.1-0.4-0.2-0.6-0.1-0.3-0.2-0.5-0.3-0.8-0.1-0.2-0.2-0.5-0.3-0.7-0.1-0.2-0.2-0.4-0.3-0.7-0.1-0.3-0.2-0.5-0.4-0.8-0.1-0.2-0.2-0.4-0.3-0.5-0.1-0.3-0.3-0.6-0.4-0.9-0.1-0.2-0.2-0.3-0.3-0.4-0.2-0.3-0.3-0.6-0.5-0.9-0.1-0.1-0.2-0.3-0.2-0.4l-0.6-0.9c-0.1-0.1-0.2-0.2-0.3-0.4l-0.6-0.9c-0.1-0.1-0.2-0.3-0.3-0.4-0.2-0.3-0.4-0.6-0.7-0.8-0.1-0.2-0.3-0.3-0.4-0.5-0.2-0.2-0.4-0.5-0.6-0.7-0.2-0.2-0.4-0.5-0.7-0.7l-0.4-0.4-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l73.4 73.4H592c-17.7 0-32 14.3-32 32s14.3 32 32 32h258.7l-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3 6.2 6.2 14.4 9.4 22.6 9.4s16.4-3.1 22.6-9.4l128-128 0.4-0.4c0.4-0.6 0.6-0.9 0.8-1.1z" p-id="2614"></path><path d="M709.3 320.4c-17.4-2.9-33.9 8.9-36.8 26.3l-42.8 256.9-87.3-261.8c-4.4-13-16.6-21.8-30.4-21.8-13.8 0-26 8.8-30.4 21.9l-87.3 261.8-42.8-256.9c-2.9-17.4-19.4-29.2-36.8-26.3-17.4 2.9-29.2 19.4-26.3 36.8l64 384c2.4 14.5 14.4 25.5 29.1 26.6 14.7 1.1 28.2-7.8 32.9-21.8L512 453.2l66.4 199.1c3.9 11.8 15 19.8 27.4 19.8h52.9c14.1 0 26.2-10.2 28.5-24.1l48.4-290.6c2.9-17.6-8.9-34.1-26.3-37z" p-id="2615"></path></svg>',
keystroke: 'Ctrl+W'
});
// Execute a callback function when the button is clicked
button.on('execute', () => {
const pageContent = getPageContent();
const style = getStyle();
const page = '<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>@media print{@page{size:A4 portrait;margin:0cm 3cm}@page:left{margin-left:2.5cm;margin-right:2.7cm;}@page:right{margin-left:2.7cm;margin-right:2.5cm;}}</style>' + style + '</head><body>' + pageContent + '</body></html>'
// console.log(page);
asBlob(page).then(data => {
saveAs(data, 'file.docx') // save as docx file
}); // asBlob() return Promise<Blob|Buffer>
exportWord();
});
// 添加快捷键 Ctrl+W 导出为docx
editor.keystrokes.set('Ctrl+W', (event, cancel) => {
exportWord();
cancel();
});
return button;
});
@ -66,7 +147,22 @@ class Export2Word extends Plugin {
}
}
// 导出为PDF插件
function printPDF() {
const pageContent = getPageContent();
console.log(pageContent);
const style = getStyle();
// 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边
const page = '<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>@media print{@page{size:A4 portrait;margin:0cm 3cm}@page:left{margin-left:2.5cm;margin-right:2.7cm;}@page:right{margin-left:2.7cm;margin-right:2.5cm;}}</style>' + style + '</head><body>' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '</body></html>'
const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50');
newWindow.document.write(page);
newWindow.document.close();
newWindow.print();
newWindow.onafterprint = function () {
newWindow.close();
}
}
class Export2PDF extends Plugin {
init() {
const editor = this.editor;
@ -81,30 +177,26 @@ class Export2PDF extends Plugin {
tooltip: true,
// 图标 直接插入svg文件
icon: '<svg t="1730309942693" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2589" width="200" height="200"><path d="M576 832H224c-17.6 0-32-14.4-32-32V192h608c17.6 0 32 14.4 32 32v288c0 17.7 14.3 32 32 32s32-14.3 32-32V224c0-52.9-43.1-96-96-96H160c-17.7 0-32 14.3-32 32v640c0 52.9 43.1 96 96 96h352c17.7 0 32-14.3 32-32s-14.3-32-32-32z" p-id="2590"></path><path d="M960 734.4c0-0.3 0-0.5-0.1-0.7 0-0.3 0-0.5-0.1-0.8 0-0.3-0.1-0.6-0.1-0.9 0-0.2 0-0.4-0.1-0.6 0-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.4-0.1-0.5-0.1-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.3-0.1-0.5-0.1-0.3-0.2-0.6-0.3-1-0.1-0.2-0.1-0.4-0.2-0.6l-0.3-0.9c-0.1-0.2-0.1-0.4-0.2-0.6-0.1-0.3-0.2-0.5-0.3-0.8-0.1-0.2-0.2-0.5-0.3-0.7-0.1-0.2-0.2-0.4-0.3-0.7-0.1-0.3-0.2-0.5-0.4-0.8-0.1-0.2-0.2-0.4-0.3-0.5-0.1-0.3-0.3-0.6-0.4-0.9-0.1-0.2-0.2-0.3-0.3-0.4-0.2-0.3-0.3-0.6-0.5-0.9-0.1-0.1-0.2-0.3-0.2-0.4l-0.6-0.9c-0.1-0.1-0.2-0.2-0.3-0.4l-0.6-0.9c-0.1-0.1-0.2-0.3-0.3-0.4-0.2-0.3-0.4-0.6-0.7-0.8-0.1-0.2-0.3-0.3-0.4-0.5-0.2-0.2-0.4-0.5-0.6-0.7-0.2-0.2-0.4-0.5-0.7-0.7l-0.4-0.4-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l73.4 73.4H592c-17.7 0-32 14.3-32 32s14.3 32 32 32h258.7l-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3 6.2 6.2 14.4 9.4 22.6 9.4s16.4-3.1 22.6-9.4l128-128 0.4-0.4 0.7-0.7c0.2-0.2 0.4-0.5 0.6-0.7 0.1-0.2 0.3-0.3 0.4-0.5 0.2-0.3 0.4-0.6 0.7-0.8 0.1-0.1 0.2-0.3 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.2 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.3 0.2-0.4 0.2-0.3 0.4-0.6 0.5-0.9 0.1-0.1 0.2-0.3 0.3-0.4 0.2-0.3 0.3-0.6 0.4-0.9 0.1-0.2 0.2-0.4 0.3-0.5 0.1-0.3 0.2-0.5 0.4-0.8 0.1-0.2 0.2-0.4 0.3-0.7 0.1-0.2 0.2-0.5 0.3-0.7 0.1-0.3 0.2-0.5 0.3-0.8 0.1-0.2 0.1-0.4 0.2-0.6l0.3-0.9c0.1-0.2 0.1-0.4 0.2-0.6 0.1-0.3 0.2-0.6 0.3-1 0-0.2 0.1-0.3 0.1-0.5 0.1-0.3 0.2-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.5 0.1-0.3 0.1-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.6 0-0.3 0.1-0.6 0.1-0.9 0-0.3 0-0.5 0.1-0.8 0-0.2 0-0.5 0.1-0.7-0.1-1.5-0.1-2.5-0.1-3.6zM352 320c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32s32-14.3 32-32V576h192c70.6 0 128-57.4 128-128s-57.4-128-128-128H352z m288 128c0 35.3-28.7 64-64 64H384V384h192c35.3 0 64 28.7 64 64z" p-id="2591"></path></svg>'
icon: '<svg t="1730309942693" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2589" width="200" height="200"><path d="M576 832H224c-17.6 0-32-14.4-32-32V192h608c17.6 0 32 14.4 32 32v288c0 17.7 14.3 32 32 32s32-14.3 32-32V224c0-52.9-43.1-96-96-96H160c-17.7 0-32 14.3-32 32v640c0 52.9 43.1 96 96 96h352c17.7 0 32-14.3 32-32s-14.3-32-32-32z" p-id="2590"></path><path d="M960 734.4c0-0.3 0-0.5-0.1-0.7 0-0.3 0-0.5-0.1-0.8 0-0.3-0.1-0.6-0.1-0.9 0-0.2 0-0.4-0.1-0.6 0-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.4-0.1-0.5-0.1-0.3-0.1-0.7-0.2-1 0-0.2-0.1-0.3-0.1-0.5-0.1-0.3-0.2-0.6-0.3-1-0.1-0.2-0.1-0.4-0.2-0.6l-0.3-0.9c-0.1-0.2-0.1-0.4-0.2-0.6-0.1-0.3-0.2-0.5-0.3-0.8-0.1-0.2-0.2-0.5-0.3-0.7-0.1-0.2-0.2-0.4-0.3-0.7-0.1-0.3-0.2-0.5-0.4-0.8-0.1-0.2-0.2-0.4-0.3-0.5-0.1-0.3-0.3-0.6-0.4-0.9-0.1-0.2-0.2-0.3-0.3-0.4-0.2-0.3-0.3-0.6-0.5-0.9-0.1-0.1-0.2-0.3-0.2-0.4l-0.6-0.9c-0.1-0.1-0.2-0.2-0.3-0.4l-0.6-0.9c-0.1-0.1-0.2-0.3-0.3-0.4-0.2-0.3-0.4-0.6-0.7-0.8-0.1-0.2-0.3-0.3-0.4-0.5-0.2-0.2-0.4-0.5-0.6-0.7-0.2-0.2-0.4-0.5-0.7-0.7l-0.4-0.4-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l73.4 73.4H592c-17.7 0-32 14.3-32 32s14.3 32 32 32h258.7l-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3 6.2 6.2 14.4 9.4 22.6 9.4s16.4-3.1 22.6-9.4l128-128 0.4-0.4 0.7-0.7c0.2-0.2 0.4-0.5 0.6-0.7 0.1-0.2 0.3-0.3 0.4-0.5 0.2-0.3 0.4-0.6 0.7-0.8 0.1-0.1 0.2-0.3 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.2 0.3-0.4l0.6-0.9c0.1-0.1 0.2-0.3 0.2-0.4 0.2-0.3 0.4-0.6 0.5-0.9 0.1-0.1 0.2-0.3 0.3-0.4 0.2-0.3 0.3-0.6 0.4-0.9 0.1-0.2 0.2-0.4 0.3-0.5 0.1-0.3 0.2-0.5 0.4-0.8 0.1-0.2 0.2-0.4 0.3-0.7 0.1-0.2 0.2-0.5 0.3-0.7 0.1-0.3 0.2-0.5 0.3-0.8 0.1-0.2 0.1-0.4 0.2-0.6l0.3-0.9c0.1-0.2 0.1-0.4 0.2-0.6 0.1-0.3 0.2-0.6 0.3-1 0-0.2 0.1-0.3 0.1-0.5 0.1-0.3 0.2-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.5 0.1-0.3 0.1-0.7 0.2-1 0-0.2 0.1-0.4 0.1-0.6 0-0.3 0.1-0.6 0.1-0.9 0-0.3 0-0.5 0.1-0.8 0-0.2 0-0.5 0.1-0.7-0.1-1.5-0.1-2.5-0.1-3.6zM352 320c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32s32-14.3 32-32V576h192c70.6 0 128-57.4 128-128s-57.4-128-128-128H352z m288 128c0 35.3-28.7 64-64 64H384V384h192c35.3 0 64 28.7 64 64z" p-id="2591"></path></svg>',
keystroke: 'Ctrl+P'
});
// Execute a callback function when the button is clicked
button.on('execute', () => {
const pageContent = getPageContent();
console.log(pageContent);
const style = getStyle();
// 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边
const page = '<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>@media print{@page{size:A4 portrait;margin:0cm 3cm}@page:left{margin-left:2.5cm;margin-right:2.7cm;}@page:right{margin-left:2.7cm;margin-right:2.5cm;}}</style>' + style + '</head><body>' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '</body></html>'
const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50');
newWindow.document.write(page);
newWindow.document.close();
newWindow.print();
newWindow.onafterprint = function () {
newWindow.close();
}
printPDF();
});
// 添加快捷键 Ctrl+P 导出为PDF
editor.keystrokes.set('Ctrl+P', (event, cancel) => {
printPDF();
cancel();
});
return button;
});
}
}
// 智能润色插件
class Translation extends Plugin {
init() {
@ -174,8 +266,9 @@ class Translation extends Plugin {
});
}
}
// 侧边栏
class ToggleSideBar extends Plugin{
// 侧边栏按钮
class ToggleSideBar extends Plugin {
// constructor(toggleSidebar) {
// super();
// this.toggleSidebar = toggleSidebar;
@ -200,7 +293,6 @@ class ToggleSideBar extends Plugin{
button.on('execute', () => {
// 打开sidebar
const bt = document.getElementById("toggleSidebarButton");
console.log(bt);
bt.click();
});
@ -209,4 +301,288 @@ class ToggleSideBar extends Plugin{
}
}
export { Export2Word, Export2PDF, Translation, ToggleSideBar };
// 保存按钮
class SaveButton extends Plugin {
// constructor(toggleSidebar) {
// super();
// this.toggleSidebar = toggleSidebar;
// }
init() {
const editor = this.editor;
editor.ui.componentFactory.add('SaveButton', () => {
// The button will be an instance of ButtonView.
const button = new ButtonView();
button.set({
label: '保存',
// withText: true
tooltip: true,
// 图标 直接插入svg文件
icon: '<svg t="1731573509489" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5448" width="200" height="200"><path d="M933.376 977.066667H89.429333A45.952 45.952 0 0 1 42.666667 930.261333V89.472C42.666667 62.933333 62.933333 42.666667 89.472 42.666667H618.24c26.538667 0 46.805333 20.266667 46.805333 46.805333 0 26.496-20.266667 46.805333-46.805333 46.805333H136.277333v747.178667h750.293334V404.565333c0-26.496 20.309333-46.805333 46.805333-46.805333 26.538667 0 46.805333 20.309333 46.805333 46.805333v525.696a46.933333 46.933333 0 0 1-46.805333 46.805334z" fill="#172B4D" p-id="5449"></path><path d="M933.376 451.370667c-12.458667 0-23.381333-4.693333-32.768-14.08l-315.093333-315.050667c-18.730667-18.773333-18.730667-48.384 0-65.536 18.730667-18.730667 48.384-18.730667 65.536 0l315.093333 313.557333c18.730667 18.730667 18.730667 48.341333 0 65.493334a43.52 43.52 0 0 1-32.768 15.616zM724.352 925.610667a45.952 45.952 0 0 1-46.805333-46.805334v-258.986666H345.301333v258.986666c0 26.496-20.266667 46.762667-46.805333 46.762667a45.952 45.952 0 0 1-46.805333-46.762667V573.013333c0-26.538667 20.266667-46.805333 46.805333-46.805333h425.856c26.538667 0 46.805333 20.266667 46.805333 46.805333v305.749334a46.933333 46.933333 0 0 1-46.805333 46.762666zM724.352 423.253333H298.496a45.952 45.952 0 0 1-46.805333-46.762666V133.162667c0-26.538667 20.266667-46.805333 46.805333-46.805334s46.805333 20.266667 46.805333 46.805334v196.522666h379.050667c26.538667 0 46.805333 20.266667 46.805333 46.805334a46.933333 46.933333 0 0 1-46.805333 46.805333z" fill="#172B4D" p-id="5450"></path></svg>',
keystroke: 'Ctrl+S'
});
// Execute a callback function when the button is clicked
button.on('execute', () => {
saveData(getPageContent())
});
return button;
});
// 添加快捷键 Ctrl+S 保存
editor.keystrokes.set('Ctrl+S', (event, cancel) => {
saveData(getPageContent());
cancel();
});
}
}
// 配置CKEditor5
function setConfig() {
// 获取用户的样式配置
const userConfig = getUserConfigFromBackend();
return {
toolbar: {
items: [
'undo',
'redo',
'|',
'heading',
'style',
'|',
'fontSize',
'fontFamily',
'fontColor',
'fontBackgroundColor',
'|',
'bold',
'italic',
'underline',
'|',
'link',
'insertImage',
'insertTable',
'highlight',
'codeBlock',
'blockquote',
'|',
'alignment',
'bulletedList',
'numberedList',
'outdent',
'indent',
'|', 'ExportToWord', 'ExportToPDF', 'translate', 'SideBar', 'SaveButton'
],
shouldNotGroupWhenFull: true
},
plugins: [
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
Base64UploadAdapter,
BlockQuote,
Bold,
Code,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
GeneralHtmlSupport,
Heading,
Highlight,
HorizontalLine,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
Markdown,
MediaEmbed,
Mention,
PageBreak,
Paragraph,
PasteFromMarkdownExperimental,
PasteFromOffice,
RemoveFormat,
SelectAll,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Style,
Subscript,
Superscript,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo,
Export2Word, Translation, Export2PDF, ToggleSideBar, SaveButton
],
balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'],
//自定义设置字体
fontFamily: {
// 自定义字体
options: userConfig.fontFamily.options,
// 启用对所有字体名称的支持
supportAllValues: true,
},
fontSize: {
// 五号,小四,四号,小三,三号,小二,二号
options: userConfig.fontSize.options,
supportAllValues: true
},
heading: {
options: [
{
model: 'paragraph',
title: 'Paragraph',
class: 'ck-heading_paragraph'
},
{
model: 'heading1',
view: 'h1',
title: 'Heading 1',
class: 'ck-heading_heading1'
},
{
model: 'heading2',
view: 'h2',
title: 'Heading 2',
class: 'ck-heading_heading2'
},
{
model: 'heading3',
view: 'h3',
title: 'Heading 3',
class: 'ck-heading_heading3'
},
{
model: 'heading4',
view: 'h4',
title: 'Heading 4',
class: 'ck-heading_heading4'
},
{
model: 'heading5',
view: 'h5',
title: 'Heading 5',
class: 'ck-heading_heading5'
},
{
model: 'heading6',
view: 'h6',
title: 'Heading 6',
class: 'ck-heading_heading6'
}
]
},
htmlSupport: {
allow: [
{
name: /^.*$/,
styles: true,
attributes: true,
classes: true
}
]
},
image: {
toolbar: [
'toggleImageCaption',
'imageTextAlternative',
'|',
'imageStyle:inline',
'imageStyle:wrapText',
'imageStyle:breakText',
'|',
'resizeImage'
]
},
initialData:
'',
language: 'zh-cn',
link: {
addTargetToExternalLinks: true,
defaultProtocol: 'https://',
decorators: {
toggleDownloadable: {
mode: 'manual',
label: 'Downloadable',
attributes: {
download: 'file'
}
}
}
},
list: {
properties: {
styles: true,
startIndex: true,
reversed: true
}
},
mention: {
feeds: [
{
marker: '@',
feed: [
/* See: https://ckeditor.com/docs/ckeditor5/latest/features/mentions.html */
]
}
]
},
menuBar: {
isVisible: true,
removeItems: ['help'],
},
placeholder: 'Type or paste your content here!',
// 用户可以自定义和管理样式
style: {
definitions: userConfig.style.definitions
},
table: {
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties']
},
autosave: {
waitingTime: 180000, // (in ms) 3minutes
save() {
// TODO save
return saveData(getPageContent());
}
},
translations: [translations]
}
}
export { Export2Word, Export2PDF, Translation, ToggleSideBar, setConfig };

@ -75,11 +75,6 @@ export function getUserConfigFromBackend() {
name: 'Code (bright)',
element: 'pre',
classes: ['fancy-code', 'fancy-code-bright']
},
{
name: 'GradientBorder',
element: 'p',
classes: ['gradientborder']
}
]
} = options;
@ -126,9 +121,9 @@ export function getStyle() {
// 获取用户编辑的内容 <html>
export function getPageContent() {
// const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div.ck.ck-reset.ck-editor.ck-rounded-corners > div.ck.ck-editor__main > div");
const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div");
return pageContent.innerHTML;
const pageContent =document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div");
// const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div");
return pageContent.outerHTML;
}
// 获取并应用用户定义的样式
@ -140,4 +135,4 @@ export function getAndApplyUserStyles() {
styleElement.innerHTML = styles;
document.head.appendChild(styleElement);
return styles;
}
}

@ -0,0 +1,127 @@
/*侧边栏样式*/
.sidebar {
position: fixed;
top: 0;
left: 0;
width: 450px;
height: 100%;
overflow-y: hidden;
transition: transform 0.3s ease;
transform: translateX(-100%);
background-color: #f9f9f9;
padding-left: 8px;
/* 调整内边距,使文字右移 */
padding-right: 8px;
/* 调整内边距,使文字右移 */
z-index: 9;
border-right: 5px solid #aec7e5;
resize: horizontal;
overflow: auto;
}
.sidebar.active {
transform: translateX(0);
}
.sidebar-menu {
flex-direction: row;
justify-content: space-between;
/* background-color: rgb(182, 229, 244); */
border-radius: 19px;
/* 添加圆角 */
display: flex;
}
.sidebar-menu .el-sub-menu {
display: flex;
flex-direction: column;
}
.sidebar-menu .el-menu-item {
flex: 1;
text-align: left;
background-color: #9cd6ce;
border-radius: 8px;
/* 添加圆角 */
margin: 2px 0;
/* 添加间距 */
}
.sidebar-menu .el-menu-item span {
display: block;
padding: 10px;
background-color: #ffffff;
border-radius: 4px;
}
.sidebar-menu .el-menu-item span:hover {
background-color: #e0e0e0;
}
.preview {
margin-top: 20px;
/* 调整预览区与表单之间的距离 */
border: 1px solid #ccc;
/* 添加边框 */
padding: 10px;
/* 添加内边距 */
border-radius: 4px;
/* 添加圆角 */
}
.form-item {
margin-bottom: 1px;
/* 减小表单项之间的距离 */
}
.chat-container {
display: flex;
flex-direction: column;
height: 90vh;
justify-content: space-between;
}
.messages {
flex: 1;
overflow-y: auto;
margin-bottom: 10px;
}
.message pre {
white-space: pre-wrap;
/* 保留空白符,但允许自动换行 */
word-wrap: break-word;
/* 允许长单词换行 */
}
.input-area {
display: flex;
}
.input-area input {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
.input-area button {
padding: 10px 15px;
background-color: #2980b9;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-left: 5px;
}
.input-area button:hover {
background-color: #3498db;
}
.message {
margin: 5px 0;
padding: 10px;
border-radius: 4px;
background-color: #ecf0f1;
}

@ -18,8 +18,8 @@
id="toggleSidebarButton">打开/关闭侧边栏</el-button>
<div class="sidebar" :class="{ 'active': isSidebarOpen }">
<!-- 侧边栏内容 -->
<el-menu class="sidebar-menu" :class="{ 'active': isNavbarOpen }">
<el-sub-menu index="1">
<el-menu class="sidebar-menu" :class="{ 'active': isNavbarOpen }" :collapse="isNavbarOpen">
<el-sub-menu index="1" class="horizontal-sub-menu">
<template #title>智能助手</template>
<el-menu-item index="1-1" @click="showContent('polish')"></el-menu-item>
<el-menu-item index="1-2" @click="showContent('rewrite')"></el-menu-item>
@ -27,12 +27,12 @@
<el-menu-item index="1-4" @click="showContent('edit')"></el-menu-item>
<el-menu-item index="1-5" @click="showContent('translate')"></el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<el-sub-menu index="2" class="horizontal-sub-menu">
<template #title>图文转换</template>
<el-menu-item index="2-1" @click="showContent('ocr')">OCR</el-menu-item>
<el-menu-item index="2-2" @click="showContent('mindmap')"></el-menu-item>
</el-sub-menu>
<el-sub-menu index="3">
<el-sub-menu index="3" class="horizontal-sub-menu">
<template #title>样式生成</template>
<el-menu-item index="3-1" @click="showContent('manual')"></el-menu-item>
<el-menu-item index="3-2" @click="showContent('ai')"></el-menu-item>
@ -40,7 +40,6 @@
</el-menu>
<!-- Content Sections -->
<div v-if="currentContent" class="content-section">
<el-button icon="el-icon-menu" @click="toggleNavBar()"></el-button>
<!-- Dynamic content based on navigation selection -->
<div v-if="currentContent === 'polish'"></div>
<div v-if="currentContent === 'rewrite'"></div>
@ -49,7 +48,7 @@
<div v-if="currentContent === 'translate'"></div>
<div v-if="currentContent === 'ocr'">OCR</div>
<div v-if="currentContent === 'mindmap'"></div>
<div v-if="currentContent === 'manual'" class="p-3">
<div v-if="currentContent === 'manual'">
<!-- 手动输入表单 -->
<el-form @submit.prevent="submitForm">
<el-col :span="30">
@ -269,12 +268,14 @@
Aa Bb Cc 上下 左右 12345 Aa Bb Cc 上下 左右 12345 Aa Bb Cc 上下 左右 12345
</div>
</div>
<div v-if="currentContent === 'ai'" class="p-3">
<div v-if="currentContent === 'ai'">
<!-- AI对话框 -->
<div class="chat-box border rounded p-3">
<p v-for="message in messages" :key="message.id" class="mb-1">{{ message.text }}</p>
<el-input v-model="aiInput" @keyup.enter="sendMessageToAI" placeholder="请输入消息"
class="w-100"></el-input>
<div class="chat-container">
<div class="messages" id="messages"></div>
<div class="input-area">
<input type="text" id="userInput" placeholder="输入您的消息...">
<button @click="sendMessage()"></button>
</div>
</div>
</div>
</div>
@ -284,159 +285,19 @@
</div>
</div>
</template>
<style>
/*侧边栏样式*/
.sidebar {
position: fixed;
top: 0;
left: 0;
width: 350px;
height: 100%;
overflow-y: hidden;
transition: transform 0.3s ease;
transform: translateX(-100%);
background-color: #f9f9f9;
padding-left: 8px;
/* 调整内边距,使文字右移 */
padding-right: 8px;
/* 调整内边距,使文字右移 */
z-index: 9;
}
.sidebar.active {
transform: translateX(0);
}
.sidebar-menu {
display: none;
flex-direction: column;
justify-content: space-between;
}
.sidebar-menu.active {
display: block;
}
.sidebar-menu .el-menu-item {
flex: 1;
text-align: left;
}
.sidebar-menu .el-menu-item span {
display: block;
padding: 10px;
background-color: #f5f5f5;
border-radius: 4px;
margin: 5px;
transition: background-color 0.3s;
}
.sidebar-menu .el-menu-item span:hover {
background-color: #e0e0e0;
}
.chat-box {
max-height: 350px;
overflow-y: auto;
}
.preview {
margin-top: 20px;
/* 调整预览区与表单之间的距离 */
border: 1px solid #ccc;
/* 添加边框 */
padding: 10px;
/* 添加内边距 */
border-radius: 4px;
/* 添加圆角 */
}
.form-item {
margin-bottom: 1px;
/* 减小表单项之间的距离 */
}
</style>
<script>
import {
DecoupledEditor,
// ClassicEditor,
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
Base64UploadAdapter,
BlockQuote,
Bold,
Code,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
GeneralHtmlSupport,
Heading,
Highlight,
HorizontalLine,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
Markdown,
MediaEmbed,
Mention,
PageBreak,
Paragraph,
PasteFromMarkdownExperimental,
PasteFromOffice,
RemoveFormat,
SelectAll,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Style,
Subscript,
Superscript,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo,
} from 'ckeditor5';
import translations from 'ckeditor5/translations/zh-cn.js';
import 'ckeditor5/ckeditor5.css';
import '../public/sidebar.css';
import { ElButton, ElInput, ElSelect, ElOption, ElForm, ElFormItem, ElMenu, ElMenuItem, ElColorPicker, ElSubMenu } from 'element-plus';
import { setConfig } from '../components/plugins'
// import {getUserConfigFromBackend,saveData,getPageContent,getAndApplyUserStyles} from './components/utils';
import { getUserConfigFromBackend, saveData, getPageContent } from '../components/utils';
import { Export2PDF, Export2Word, ToggleSideBar, Translation } from '../components/plugins';
import { useStore } from 'vuex';
import router from '../router/index.js';
import axios from 'axios';
export default {
name: 'CkeditorView',
@ -446,7 +307,7 @@ export default {
config: null, // CKEditor needs the DOM tree before calculating the configuration.
editor: DecoupledEditor,
// editor: ClassicEditor,
store:useStore(),
store: useStore(),
isSidebarOpen: false,//
isNavbarOpen: false,//
@ -466,256 +327,10 @@ export default {
wordSpacing: ''
},
previewStyle: {},
aiInput: '', // AI
messages: [], //
};
},
mounted() {
//
const userConfig = getUserConfigFromBackend();
//
// getAndApplyUserStyles();
this.config = {
toolbar: {
items: [
'undo',
'redo',
'|',
'heading',
'style',
'|',
'fontSize',
'fontFamily',
'fontColor',
'fontBackgroundColor',
'|',
'bold',
'italic',
'underline',
'|',
'link',
'insertImage',
'insertTable',
'highlight',
'codeBlock',
'blockquote',
'|',
'alignment',
'bulletedList',
'numberedList',
'outdent',
'indent',
'|', 'ExportToWord', 'ExportToPDF', 'translate', 'SideBar'
],
shouldNotGroupWhenFull: true
},
plugins: [
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
Base64UploadAdapter,
BlockQuote,
Bold,
Code,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
GeneralHtmlSupport,
Heading,
Highlight,
HorizontalLine,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
Markdown,
MediaEmbed,
Mention,
PageBreak,
Paragraph,
PasteFromMarkdownExperimental,
PasteFromOffice,
RemoveFormat,
SelectAll,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Style,
Subscript,
Superscript,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo,
Export2Word, Translation, Export2PDF, ToggleSideBar
],
balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'],
//
fontFamily: {
//
options: userConfig.fontFamily.options,
//
supportAllValues: true,
},
fontSize: {
//
options: userConfig.fontSize.options,
supportAllValues: true
},
heading: {
options: [
{
model: 'paragraph',
title: 'Paragraph',
class: 'ck-heading_paragraph'
},
{
model: 'heading1',
view: 'h1',
title: 'Heading 1',
class: 'ck-heading_heading1'
},
{
model: 'heading2',
view: 'h2',
title: 'Heading 2',
class: 'ck-heading_heading2'
},
{
model: 'heading3',
view: 'h3',
title: 'Heading 3',
class: 'ck-heading_heading3'
},
{
model: 'heading4',
view: 'h4',
title: 'Heading 4',
class: 'ck-heading_heading4'
},
{
model: 'heading5',
view: 'h5',
title: 'Heading 5',
class: 'ck-heading_heading5'
},
{
model: 'heading6',
view: 'h6',
title: 'Heading 6',
class: 'ck-heading_heading6'
}
]
},
htmlSupport: {
allow: [
{
name: /^.*$/,
styles: true,
attributes: true,
classes: true
}
]
},
image: {
toolbar: [
'toggleImageCaption',
'imageTextAlternative',
'|',
'imageStyle:inline',
'imageStyle:wrapText',
'imageStyle:breakText',
'|',
'resizeImage'
]
},
initialData:
'',
language: 'zh-cn',
link: {
addTargetToExternalLinks: true,
defaultProtocol: 'https://',
decorators: {
toggleDownloadable: {
mode: 'manual',
label: 'Downloadable',
attributes: {
download: 'file'
}
}
}
},
list: {
properties: {
styles: true,
startIndex: true,
reversed: true
}
},
mention: {
feeds: [
{
marker: '@',
feed: [
/* See: https://ckeditor.com/docs/ckeditor5/latest/features/mentions.html */
]
}
]
},
menuBar: {
isVisible: true,
removeItems: ['help'],
},
placeholder: 'Type or paste your content here!',
//
style: {
definitions: userConfig.style.definitions
},
table: {
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties']
},
autosave: {
waitingTime: 180000, // (in ms) 3minutes
save() {
// TODO save
return saveData(getPageContent());
}
},
translations: [translations]
};
this.config = setConfig();
this.isLayoutReady = true;
},
methods: {
@ -738,13 +353,9 @@ export default {
this.isSidebarOpen = !this.isSidebarOpen;
this.isNavbarOpen = this.isSidebarOpen;
},
toggleNavBar() {
this.isNavbarOpen = !this.isNavbarOpen;
},
//
showContent(formType) {
this.currentContent = formType;
this.isNavbarOpen=false;
},
//
submitForm() {
@ -779,24 +390,181 @@ export default {
}
}
},
// API
sendMessageToAI() {
// APIAI
this.messages.push({ text: this.aiInput });
this.aiInput = ''; //
// AI
setTimeout(() => {
this.messages.push({ text: '这是来自AI的回复' });
}, 1000);
// AI
displayMessage(text, sender) {
const messagesDiv = document.getElementById('messages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
// 使 pre text
// css htmlpre set language
const preElement = document.createElement('pre');
preElement.textContent = text;
messageDiv.appendChild(preElement);
messagesDiv.appendChild(messageDiv);
if (sender === 'ai') {
// TODO css
preElement.textContent = `文心一言:\n` + preElement.textContent;
messageDiv.style.backgroundColor = '#bdc3c7';
//
this.previewStyleAtMessages(text);
}
// messagesDiv.scrollTop = messagesDiv.scrollHeight;
},
//
sendMessage() {
const userInput = document.getElementById('userInput');
const messageText = userInput.value;
if (messageText.trim() === '') return;
//
let chatHistory = [];
const messages = document.getElementById('messages').children;
for (let i = 0; i < messages.length; i++) {
if (i%4==0){
chatHistory.push({ Role: 'user', Content: messages[i].textContent });
}else if (i%4==1){
const assistantResponse = messages[i].textContent.replaceAll('文心一言:\n', '');
chatHistory.push({ Role: 'assistant', Content: assistantResponse });
}
}
console.log(chatHistory);
// Display user's message
this.displayMessage(messageText, 'user');
// APIresponse
// messages
// TODO
// const chat_history = []
axios({
url: 'http://localhost:14514/admin/ai_layout/style_generate',
method: 'POST',
data: {
user_input: userInput.value,
...(chatHistory.length > 0 && { chat_history: chatHistory }),
}
})
.then(response => {
console.log(response);
this.displayMessage(response.data.data, 'ai')
})
.catch(error => {
console.error('Error:', error);
});
userInput.value = '';
},
//
previewStyleAtMessages(style) {
const messagesDiv = document.getElementById('messages');
// preview
const previewWrapper = document.createElement('div');
previewWrapper.style.border = '1px solid #ccc';
previewWrapper.style.display = 'flow-root';
messagesDiv.appendChild(previewWrapper);
// 'preview'
const previewLabel = document.createElement('div');
previewLabel.textContent = 'preview';
previewWrapper.appendChild(previewLabel);
//
const previewStyle = document.createElement('style');
//
// csscss,css,}
const cssRegex = /```css\n([\s\S]*?)```/;
const cssMatch = cssRegex.exec(style);
let cssText; // css
// css
if (cssMatch) {
cssText = cssMatch[0].replace('css', '').replaceAll('```', '');
} else {
cssText = style;
}
previewStyle.textContent = cssText.replace(/\.ck-content/g, '');
previewWrapper.appendChild(previewStyle);
//
let previewElement;
// element tag class name
const styleRegex = /\.ck-content\s+([a-z]+)\.([a-z-]+)\s*\{/g;
let match;
const classNames = [];
while ((match = styleRegex.exec(cssText)) !== null) {
if (!previewElement) {
previewElement = document.createElement(match[1]);
// previewElement.textContent = 'AaBbCcDdEeFf';
const previewText = document.createElement('p');
previewText.textContent = 'AaBbCcDd';
previewElement.appendChild(previewText);
previewWrapper.appendChild(previewElement);
}
// classNameclass
const newClassName = match[2]+"_"+Math.floor(Math.random()*1000);
previewStyle.textContent = previewStyle.textContent.replaceAll(match[2], newClassName);
classNames.push(newClassName);
}
if (previewElement) {
previewElement.className = classNames.join(' ');
}
//
const buttonsMessageDiv = document.createElement('div');
buttonsMessageDiv.className = 'preview-buttons';
buttonsMessageDiv.style.display = 'flex';
buttonsMessageDiv.style.justifyContent = 'flex-end';
buttonsMessageDiv.style.marginTop = '10px';
// save
const saveButton = document.createElement('el-button');
saveButton.innerHTML = '<svg t="1731509644125" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6346" width="20" height="20"><path d="M512 1024C229.248 1024 0 794.752 0 512S229.248 0 512 0s512 229.248 512 512-229.248 512-512 512z m0-938.666667C276.352 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667S747.648 85.333333 512 85.333333z m-3.413333 611.541334a34.944 34.944 0 0 1-9.386667 16.682666 38.058667 38.058667 0 0 1-30.72 11.050667 38.954667 38.954667 0 0 1-40.106667-27.946667L308.053333 576.426667a38.4 38.4 0 0 1 54.186667-54.229334l93.013333 93.184 190.293334-337.365333a42.666667 42.666667 0 0 1 58.88-16.426667c20.608 12.714667 27.392 39.466667 15.36 60.458667l-211.2 374.826667z" fill="#000000" p-id="6347"></path></svg>';
saveButton.style.marginLeft = '10px';
saveButton.style.width = '40px';
saveButton.style.height = '40px';
saveButton.onclick = () => {
// save
// TODO
// 使style
// styleDefinition:[name: 'styleName',element: 'element',classes: [className]]
const styleName = prompt("请输入样式名称:");
// styleDefiniton
const styleDefinition = {
name: styleName,
element: previewElement.tagName,
classes: classNames
};
console.log(styleDefinition);
console.log(cssText);// css
};
// clear
const clearButton = document.createElement('el-button');
clearButton.innerHTML = '<svg t="1731509926355" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8154" width="20" height="20"><path d="M1011.43552 981.92384l-68.4032-394.40384h23.10144c18.5856 0 33.54624-14.97088 33.54624-33.55648V306.16576c0-18.5856-14.97088-33.55648-33.54624-33.55648H648.6528V37.71392c0-18.5856-14.97088-33.55648-33.55648-33.55648H408.59648c-18.5856 0-33.55648 14.97088-33.55648 33.55648v234.88512H57.5488c-18.5856 0-33.54624 14.97088-33.54624 33.55648v247.79776c0 18.5856 14.97088 33.55648 33.54624 33.55648h23.10144L12.24704 981.9136c-0.38912 1.9456-0.512 3.87072-0.512 5.6832 0 18.5856 14.97088 33.54624 33.55648 33.54624h933.10976c1.93536 0 3.88096-0.12288 5.6832-0.512 18.31936-3.08224 30.57664-20.51072 27.35104-38.7072zM114.33984 362.94656h351.03744V94.50496h92.928v268.4416h351.03744v134.22592H114.33984V362.94656zM718.336 930.816V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H387.9424V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H112.78336l58.20416-335.55456h681.5744L910.76608 930.816H718.336z m0 0" fill="#2C2C2C" p-id="8155"></path></svg>';
clearButton.style.marginLeft = '10px';
clearButton.style.width = '40px';
clearButton.style.height = '40px';
clearButton.onclick = () => {
// clear message
const messagesDiv = document.getElementById('messages');
while (messagesDiv.firstChild) {
messagesDiv.removeChild(messagesDiv.firstChild);
}
};
//
buttonsMessageDiv.appendChild(saveButton);
buttonsMessageDiv.appendChild(clearButton);
messagesDiv.appendChild(buttonsMessageDiv);
}
},
components: {
//
ElButton, ElInput, ElSelect, ElOption, ElForm, ElFormItem, ElMenu, ElMenuItem, ElColorPicker, ElSubMenu
},
created(){
if(!this.store.state.user.is_login){
router.push({name:'login'});
created() {
if (!this.store.state.user.is_login) {
router.push({ name: 'login' });
}
}
};

Loading…
Cancel
Save