@ -297,7 +297,6 @@ import { setConfig } from '../components/plugins'
/ / i m p o r t { g e t U s e r C o n f i g F r o m B a c k e n d , s a v e D a t a , g e t P a g e C o n t e n t , g e t A n d A p p l y U s e r S t y l e s } f r o m ' . / c o m p o n e n t s / u t i l s ' ;
import { useStore } from 'vuex' ;
import router from '../router/index.js' ;
import axios from 'axios' ;
export default {
name : 'CkeditorView' ,
@ -327,7 +326,6 @@ export default {
wordSpacing : ''
} ,
previewStyle : { } ,
messages : [ ] , / / 聊 天 记 录
} ;
} ,
mounted ( ) {
@ -347,6 +345,7 @@ export default {
/ / 打 开 已 有 文 本 就 将 p a g e C o n t e n t 替 换
/ / T O D O
editor . setData ( pageContent ) ;
window . editor = editor ;
} ,
/ / s i d e b a r
/ / 打 开 / 关 闭 侧 边 栏
@ -395,10 +394,6 @@ export default {
displayMessage ( text , sender ) {
const messagesDiv = document . getElementById ( 'messages' ) ;
/ / 移 除 m e s s a g e s 中 的 按 钮
const previousButtonsMessage = messagesDiv . querySelectorAll ( '.preview-buttons' ) ;
previousButtonsMessage . forEach ( buttons => buttons . remove ( ) ) ;
const messageDiv = document . createElement ( 'div' ) ;
messageDiv . className = 'message' ;
/ / 使 用 p r e 元 素 来 格 式 化 显 示 t e x t
@ -412,128 +407,214 @@ export default {
/ / T O D O 从 返 回 文 本 中 提 取 出 c s s 部 分
preElement . textContent = ` 文心一言: \ n ` + preElement . textContent ;
messageDiv . style . backgroundColor = '#bdc3c7' ;
/ / p r e v i e w 区 域
const previewWrapper = document . createElement ( 'div' ) ;
previewWrapper . style . border = '1px solid #ccc' ;
previewWrapper . style . display = 'flow-root' ;
/ / 添 加 一 个 标 识 ' p r e v i e w ' 的 元 素
const previewLabel = document . createElement ( 'div' ) ;
previewLabel . textContent = 'preview' ;
previewWrapper . appendChild ( previewLabel ) ;
/ / 应 用 生 成 的 样 式 到 预 览 内 容
const previewStyle = document . createElement ( 'style' ) ;
/ / 对 返 回 文 本 进 行 处 理
/ / 提 取 其 中 c s s 代 码 , 以 c s s 开 头 , 但 不 需 要 ’ c s s ‘ , 最 后 一 个 } 结 尾
const cssRegex = /css([\s\S]*)\}/ ;
const cssMatch = cssRegex . exec ( text ) ;
if ( cssMatch ) {
previewStyle . textContent = cssMatch [ 0 ] . replace ( 'css' , '' ) ;
} else {
previewStyle . textContent = text ;
}
previewStyle . textContent = previewStyle . textContent . replace ( /\.ck-content/g , '' ) ;
document . head . appendChild ( previewStyle ) ;
/ / 预 览 的 内 容
let previewElement ;
/ / 提 取 e l e m e n t t a g 和 c l a s s n a m e
const styleRegex = /\.ck-content\s+([a-z]+)\.([a-z-]+)\s*\{/g ;
let match ;
const classNames = [ ] ;
while ( ( match = styleRegex . exec ( text ) ) !== null ) {
if ( ! previewElement ) {
previewElement = document . createElement ( match [ 1 ] ) ;
previewElement . textContent = 'AaBbCcDdEeFf' ;
previewWrapper . appendChild ( previewElement ) ;
}
classNames . push ( match [ 2 ] ) ;
}
if ( previewElement ) {
previewElement . className = classNames . join ( ' ' ) ;
}
messagesDiv . appendChild ( previewWrapper ) ;
/ / 创 建 按 钮 容 器
const buttonsMessageDiv = document . createElement ( 'div' ) ;
buttonsMessageDiv . className = 'preview-buttons' ;
buttonsMessageDiv . style . display = 'flex' ;
buttonsMessageDiv . style . justifyContent = 'flex-end' ;
buttonsMessageDiv . style . marginTop = '10px' ;
/ / 创 建 s a v e 按 钮
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 = ( ) => {
/ / s a v e
/ / T O D O 将 生 成 的 样 式 保 存 到 后 端
/ / 确 认 样 式 的 名 称 这 是 用 户 选 择 使 用 s t y l e 时 看 到 的
/ / s t y l e D e f i n i t i o n : [ n a m e : ' s t y l e N a m e ' , e l e m e n t : ' e l e m e n t ' , c l a s s e s : [ c l a s s N a m e ] ]
const styleName = prompt ( "请输入样式名称:" ) ;
/ / 构 造 s t y l e D e f i n i t o n 发 送 到 后 端
const styleDefinition = {
name : styleName ,
element : previewElement . tagName ,
classes : classNames
} ;
console . log ( styleDefinition ) ;
} ;
/ / 创 建 c l e a r 按 钮
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 = ( ) => {
/ / c l e a r 清 楚 当 前 所 有 的 m e s s a g e 和 按 钮
const messagesDiv = document . getElementById ( 'messages' ) ;
while ( messagesDiv . firstChild ) {
messagesDiv . removeChild ( messagesDiv . firstChild ) ;
}
/ / 清 除 添 加 的 s t y l e
document . head . removeChild ( previewStyle ) ;
} ;
/ / 显 示 按 钮
buttonsMessageDiv . appendChild ( saveButton ) ;
buttonsMessageDiv . appendChild ( clearButton ) ;
messagesDiv . appendChild ( buttonsMessageDiv ) ;
}
/ / m e s s a g e s D i v . s c r o l l T o p = m e s s a g e s D i v . s c r o l l H e i g h t ;
return preElement ;
} ,
sendMessage ( ) {
/ / 发 送 消 息
async 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 ) ;
/ / D i s p l a y u s e r ' s m e s s a g e
this . displayMessage ( messageText , 'user' ) ;
/ / 向 后 端 调 用 A P I 并 接 受 r e s p o n s e
/ / 根 据 m e s s a g e s 的 内 容 构 造 聊 天 历 史 列 表
/ / T O D O
chat _history = [ ]
/ / c o n s t c h a t _ h i s t o r y = [ ]
try {
const response = await fetch ( 'http://localhost:14514/admin/ai_layout/style_generate' , {
method : 'POST' ,
headers : {
'Content-Type' : 'application/json'
} ,
body : JSON . stringify ( {
user _input : userInput . value ,
... ( chatHistory . length > 0 && { chat _history : chatHistory } )
} )
} ) ;
axios ( {
url : 'http://localhost:14514/admin/ai_layout/style_generate' ,
method : 'POST' ,
data : {
user _input : userInput . value
if ( ! response . body ) {
/ / T O D O
throw new Error ( 'No response body' ) ;
}
} )
. then ( response => {
/ / l e t f o r m a t e d R e s p o n s e = r e s p o n s e . d a t a . r e s p o n s e ;
/ / t h i s . d i s p l a y M e s s a g e ( f o r m a t e d R e s p o n s e , ' a i ' ) ;
console . log ( response ) ;
this . displayMessage ( response . data . data , 'ai' )
} )
. catch ( error => {
console . error ( 'Error:' , error ) ;
} ) ;
const reader = response . body . getReader ( ) ;
const decoder = new TextDecoder ( 'utf-8' ) ;
let result = '' ;
var messageStream ;
/* eslint-disable no-constant-condition */
while ( true ) {
const { done , value } = await reader . read ( ) ;
if ( done ) break ;
const slice = decoder . decode ( value , { stream : true } ) ;
result += slice ;
if ( ! messageStream ) {
messageStream = this . displayMessage ( slice , 'ai' ) ;
} else {
messageStream . textContent += slice ;
}
}
console . log ( '生成的样式:' , result ) ;
/ / 预 览 生 成 的 样 式
this . previewStyleAtMessages ( result ) ;
/* eslint-enable no-constant-condition */
} catch ( error ) {
console . error ( 'Error:' , error ) ;
this . displayError ( error ) ;
}
/ / 清 空 输 入 框
userInput . value = '' ;
} ,
/ / 预 览 生 成 的 样 式
previewStyleAtMessages ( style ) {
const messagesDiv = document . getElementById ( 'messages' ) ;
/ / p r e v i e w 区 域
const previewWrapper = document . createElement ( 'div' ) ;
previewWrapper . style . border = '1px solid #ccc' ;
previewWrapper . style . display = 'flow-root' ;
messagesDiv . appendChild ( previewWrapper ) ;
/ / 添 加 一 个 标 识 ' p r e v i e w ' 的 元 素
const previewLabel = document . createElement ( 'div' ) ;
previewLabel . textContent = 'preview' ;
previewWrapper . appendChild ( previewLabel ) ;
/ / 应 用 生 成 的 样 式 到 预 览 内 容
const previewStyle = document . createElement ( 'style' ) ;
/ / 对 返 回 文 本 进 行 处 理
/ / 提 取 其 中 c s s 代 码 , 以 c s s 开 头 , 但 不 需 要 ’ c s s ‘ , 最 后 一 个 } 结 尾
const cssRegex = /```css\n([\s\S]*?)```/ ;
const cssMatch = cssRegex . exec ( style ) ;
let cssText ; / / 提 取 的 出 的 原 始 c s s 代 码 , 用 于 保 存 到 后 端 或 进 一 步 处 理
/ / 如 果 有 多 个 c s s 代 码 , 只 提 取 第 一 个
if ( cssMatch ) {
cssText = cssMatch [ 0 ] . replace ( 'css' , '' ) . replaceAll ( '```' , '' ) ;
} else {
cssText = style ;
}
previewStyle . textContent = cssText . replace ( /\.ck-content/g , '' ) ;
previewWrapper . appendChild ( previewStyle ) ;
/ / 预 览 的 内 容
let previewElement ;
/ / 提 取 e l e m e n t t a g 和 c l a s s n a m e
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 ] ) ;
if ( match [ 1 ] === 'span' ) {
previewElement . textContent = 'AaBbCcDdEeFf' ;
} else {
const previewText = document . createElement ( 'p' ) ;
previewText . textContent = 'AaBbCcDd' ;
previewElement . appendChild ( previewText ) ;
}
previewWrapper . appendChild ( previewElement ) ;
}
/ / c l a s s N a m e 后 加 一 个 随 机 数 表 明 是 新 的 c l a s s
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' ;
/ / 创 建 s a v e 按 钮
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 = ( ) => {
/ / s a v e
/ / T O D O 将 生 成 的 样 式 保 存 到 后 端
/ / 确 认 样 式 的 名 称 这 是 用 户 选 择 使 用 s t y l e 时 看 到 的
/ / s t y l e D e f i n i t i o n : [ n a m e : ' s t y l e N a m e ' , e l e m e n t : ' e l e m e n t ' , c l a s s e s : [ c l a s s N a m e ] ]
const styleName = prompt ( "请输入样式名称:" ) ;
/ / 构 造 s t y l e D e f i n i t o n 发 送 到 后 端
const styleDefinition = {
name : styleName ,
element : previewElement . tagName ,
classes : classNames
} ;
console . log ( styleDefinition ) ;
console . log ( cssText ) ; / / 保 存 的 c s s 代 码
} ;
/ / 显 示 按 钮
buttonsMessageDiv . appendChild ( saveButton ) ;
buttonsMessageDiv . appendChild ( this . createClearButton ( ) ) ;
messagesDiv . appendChild ( buttonsMessageDiv ) ;
} ,
/ / 错 误 信 息 展 示
displayError ( error ) {
const messagesDiv = document . getElementById ( 'messages' ) ;
const messageDiv = document . createElement ( 'div' ) ;
messageDiv . className = 'message' ;
/ / 发 生 错 误 时 背 景 颜 色 设 置 为 浅 红 色
messageDiv . style . backgroundColor = 'mistyrose' ; / / m i s t y r o s e 是 一 种 浅 红 色
/ / 使 用 p r e 元 素 来 格 式 化 显 示 t e x t
/ / 可 以 将 c s s h t m l 代 码 内 容 新 建 一 个 p r e s e t l a n g u a g e 更 好 地 展 示 输 出
const preElement = document . createElement ( 'pre' ) ;
/ / 错 误 信 息 设 置 为 红 色
preElement . textContent = error ;
preElement . style = "color:red" ;
messageDiv . appendChild ( preElement ) ;
messagesDiv . appendChild ( messageDiv ) ;
/ / 创 建 按 钮 容 器
const buttonsMessageDiv = document . createElement ( 'div' ) ;
buttonsMessageDiv . className = 'preview-buttons' ;
buttonsMessageDiv . style . display = 'flex' ;
buttonsMessageDiv . style . justifyContent = 'flex-end' ;
buttonsMessageDiv . style . marginTop = '10px' ;
buttonsMessageDiv . appendChild ( this . createClearButton ( ) ) ;
messagesDiv . appendChild ( buttonsMessageDiv ) ;
} ,
createClearButton ( ) {
/ / 创 建 c l e a r 按 钮
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 = ( ) => {
/ / c l e a r 清 楚 当 前 所 有 的 m e s s a g e 和 按 钮
const messagesDiv = document . getElementById ( 'messages' ) ;
while ( messagesDiv . firstChild ) {
messagesDiv . removeChild ( messagesDiv . firstChild ) ;
}
} ;
return clearButton ;
}
} ,
components : {
/ / 导 入 组 件