mirror of https://github.com/chaitin/PandaWiki.git
Compare commits
7 Commits
e80cbf9f47
...
95bd31b8ed
| Author | SHA1 | Date |
|---|---|---|
|
|
95bd31b8ed | |
|
|
8457544a30 | |
|
|
55abd7452c | |
|
|
6224d713b6 | |
|
|
3f93246d85 | |
|
|
3196f2d130 | |
|
|
4a9a1ff78b |
|
|
@ -7764,6 +7764,12 @@ const docTemplate = `{
|
|||
"btn_text": {
|
||||
"type": "string"
|
||||
},
|
||||
"copyright_hide_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"copyright_info": {
|
||||
"type": "string"
|
||||
},
|
||||
"disclaimer": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7757,6 +7757,12 @@
|
|||
"btn_text": {
|
||||
"type": "string"
|
||||
},
|
||||
"copyright_hide_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"copyright_info": {
|
||||
"type": "string"
|
||||
},
|
||||
"disclaimer": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2536,6 +2536,10 @@ definitions:
|
|||
type: string
|
||||
btn_text:
|
||||
type: string
|
||||
copyright_hide_enabled:
|
||||
type: boolean
|
||||
copyright_info:
|
||||
type: string
|
||||
disclaimer:
|
||||
type: string
|
||||
is_open:
|
||||
|
|
|
|||
|
|
@ -399,19 +399,21 @@ type FooterSettings struct {
|
|||
}
|
||||
|
||||
type WidgetBotSettings struct {
|
||||
IsOpen bool `json:"is_open,omitempty"`
|
||||
ThemeMode string `json:"theme_mode,omitempty"`
|
||||
BtnText string `json:"btn_text,omitempty"`
|
||||
BtnLogo string `json:"btn_logo,omitempty"`
|
||||
RecommendQuestions []string `json:"recommend_questions,omitempty"`
|
||||
RecommendNodeIDs []string `json:"recommend_node_ids,omitempty"`
|
||||
BtnStyle string `json:"btn_style,omitempty"`
|
||||
BtnID string `json:"btn_id,omitempty"`
|
||||
BtnPosition string `json:"btn_position,omitempty"`
|
||||
ModalPosition string `json:"modal_position,omitempty"`
|
||||
SearchMode string `json:"search_mode,omitempty"`
|
||||
Placeholder string `json:"placeholder,omitempty"`
|
||||
Disclaimer string `json:"disclaimer,omitempty"`
|
||||
IsOpen bool `json:"is_open,omitempty"`
|
||||
ThemeMode string `json:"theme_mode,omitempty"`
|
||||
BtnText string `json:"btn_text,omitempty"`
|
||||
BtnLogo string `json:"btn_logo,omitempty"`
|
||||
RecommendQuestions []string `json:"recommend_questions,omitempty"`
|
||||
RecommendNodeIDs []string `json:"recommend_node_ids,omitempty"`
|
||||
BtnStyle string `json:"btn_style,omitempty"`
|
||||
BtnID string `json:"btn_id,omitempty"`
|
||||
BtnPosition string `json:"btn_position,omitempty"`
|
||||
ModalPosition string `json:"modal_position,omitempty"`
|
||||
SearchMode string `json:"search_mode,omitempty"`
|
||||
Placeholder string `json:"placeholder,omitempty"`
|
||||
Disclaimer string `json:"disclaimer,omitempty"`
|
||||
CopyrightInfo string `json:"copyright_info,omitempty"`
|
||||
CopyrightHideEnabled bool `json:"copyright_hide_enabled,omitempty"`
|
||||
}
|
||||
|
||||
type BrandGroup struct {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
const (
|
||||
SettingKeySystemPrompt = "system_prompt"
|
||||
SettingBlockWords = "block_words"
|
||||
SettingCopyrightInfo = "本网站由 PandaWiki 提供技术支持"
|
||||
)
|
||||
|
||||
// table: settings
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit bb1b17dd5c7d72d40f6a1198b1604f4d3c44116e
|
||||
Subproject commit f6497a225d4b6ad76fe2dbedb427bd0e464a7662
|
||||
|
|
@ -120,6 +120,13 @@ func (u *AppUsecase) ValidateUpdateApp(ctx context.Context, id string, req *doma
|
|||
return domain.ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
if !limitation.AllowCustomCopyright {
|
||||
if app.Settings.WidgetBotSettings.CopyrightHideEnabled != req.Settings.WidgetBotSettings.CopyrightHideEnabled || app.Settings.WidgetBotSettings.CopyrightInfo != req.Settings.WidgetBotSettings.CopyrightInfo {
|
||||
return domain.ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -664,6 +671,12 @@ func (u *AppUsecase) GetWidgetAppInfo(ctx context.Context, kbID string) (*domain
|
|||
}
|
||||
appInfo.RecommendNodes = nodes
|
||||
}
|
||||
|
||||
if !domain.GetBaseEditionLimitation(ctx).AllowCustomCopyright {
|
||||
appInfo.Settings.WidgetBotSettings.CopyrightHideEnabled = false
|
||||
appInfo.Settings.WidgetBotSettings.CopyrightInfo = domain.SettingCopyrightInfo
|
||||
}
|
||||
|
||||
return appInfo, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { styled } from '@mui/material';
|
||||
import { useVersionInfo } from '@/hooks';
|
||||
import { VersionInfoMap } from '@/constant/version';
|
||||
import { useVersionInfo } from '@/hooks';
|
||||
import { ConstsLicenseEdition } from '@/request/types';
|
||||
import { SxProps } from '@mui/material';
|
||||
import { styled, SxProps } from '@mui/material';
|
||||
import React from 'react';
|
||||
|
||||
const StyledMaskWrapper = styled('div')(({ theme }) => ({
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledMask = styled('div')(({ theme }) => ({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { FreeSoloAutocomplete } from '@/components/FreeSoloAutocomplete';
|
||||
import ShowText from '@/components/ShowText';
|
||||
import UploadFile from '@/components/UploadFile';
|
||||
import VersionMask from '@/components/VersionMask';
|
||||
import { PROFESSION_VERSION_PERMISSION } from '@/constant/version';
|
||||
import { useCommitPendingInput } from '@/hooks';
|
||||
import { getApiV1AppDetail, putApiV1App } from '@/request/App';
|
||||
import {
|
||||
|
|
@ -24,7 +26,6 @@ import {
|
|||
import { useEffect, useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { FormItem, SettingCardItem } from '../../Common';
|
||||
import RecommendDocDragList from './RecommendDocDragList';
|
||||
|
||||
interface CardRobotWebComponentProps {
|
||||
kb: DomainKnowledgeBaseDetail;
|
||||
|
|
@ -48,25 +49,28 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
defaultValues: {
|
||||
is_open: 0,
|
||||
theme_mode: 'light',
|
||||
btn_style: 'hover_ball',
|
||||
btn_style: 'side_sticky',
|
||||
btn_id: '',
|
||||
btn_position: 'bottom_right',
|
||||
disclaimer: '',
|
||||
btn_text: '',
|
||||
btn_logo: '',
|
||||
modal_position: 'follow',
|
||||
copyright_hide_enabled: '0',
|
||||
copyright_info: '',
|
||||
search_mode: 'all',
|
||||
placeholder: '',
|
||||
recommend_questions: [] as string[],
|
||||
recommend_node_ids: [] as string[],
|
||||
// recommend_node_ids: [] as string[],
|
||||
},
|
||||
});
|
||||
|
||||
const [url, setUrl] = useState<string>('');
|
||||
|
||||
const recommend_questions = watch('recommend_questions') || [];
|
||||
const recommend_node_ids = watch('recommend_node_ids') || [];
|
||||
const btn_style = watch('btn_style') || 'hover_ball';
|
||||
// const recommend_node_ids = watch('recommend_node_ids') || [];
|
||||
const btn_style = watch('btn_style') || 'side_sticky';
|
||||
const copyright_hide_enabled = watch('copyright_hide_enabled') || '0';
|
||||
const isCustomButton = btn_style === 'btn_trigger';
|
||||
|
||||
const recommendQuestionsField = useCommitPendingInput<string>({
|
||||
|
|
@ -98,24 +102,24 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
const getDetail = () => {
|
||||
getApiV1AppDetail({ kb_id: kb.id!, type: '2' }).then(res => {
|
||||
setDetail(res);
|
||||
const widget = res.settings?.widget_bot_settings;
|
||||
reset({
|
||||
is_open: res.settings?.widget_bot_settings?.is_open ? 1 : 0,
|
||||
theme_mode: res.settings?.widget_bot_settings?.theme_mode || 'light',
|
||||
btn_style: res.settings?.widget_bot_settings?.btn_style || 'hover_ball',
|
||||
btn_id: res.settings?.widget_bot_settings?.btn_id || '',
|
||||
btn_position:
|
||||
res.settings?.widget_bot_settings?.btn_position || 'bottom_right',
|
||||
btn_text: res.settings?.widget_bot_settings?.btn_text || '在线客服',
|
||||
btn_logo: res.settings?.widget_bot_settings?.btn_logo || '',
|
||||
modal_position:
|
||||
res.settings?.widget_bot_settings?.modal_position || 'follow',
|
||||
search_mode: res.settings?.widget_bot_settings?.search_mode || 'all',
|
||||
placeholder: res.settings?.widget_bot_settings?.placeholder || '',
|
||||
disclaimer: res.settings?.widget_bot_settings?.disclaimer || '',
|
||||
recommend_questions:
|
||||
res.settings?.widget_bot_settings?.recommend_questions || [],
|
||||
recommend_node_ids:
|
||||
res.settings?.widget_bot_settings?.recommend_node_ids || [],
|
||||
is_open: widget?.is_open ? 1 : 0,
|
||||
theme_mode: widget?.theme_mode || 'light',
|
||||
btn_style: widget?.btn_style || 'side_sticky',
|
||||
btn_id: widget?.btn_id || '',
|
||||
btn_position: widget?.btn_position || 'bottom_right',
|
||||
btn_text: widget?.btn_text || '在线客服',
|
||||
btn_logo: widget?.btn_logo || '',
|
||||
modal_position: widget?.modal_position || 'follow',
|
||||
search_mode: widget?.search_mode || 'all',
|
||||
placeholder: widget?.placeholder || '',
|
||||
disclaimer: widget?.disclaimer || '',
|
||||
copyright_hide_enabled:
|
||||
widget?.copyright_hide_enabled === true ? '1' : '0',
|
||||
copyright_info: widget?.copyright_info || '',
|
||||
recommend_questions: widget?.recommend_questions || [],
|
||||
// recommend_node_ids: widget?.recommend_node_ids || [],
|
||||
});
|
||||
setIsEnabled(res.settings?.widget_bot_settings?.is_open ? true : false);
|
||||
});
|
||||
|
|
@ -129,19 +133,10 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
kb_id,
|
||||
settings: {
|
||||
widget_bot_settings: {
|
||||
...data,
|
||||
is_open: data.is_open === 1 ? true : false,
|
||||
theme_mode: data.theme_mode as 'light' | 'dark',
|
||||
btn_style: data.btn_style,
|
||||
btn_id: data.btn_id,
|
||||
btn_position: data.btn_position,
|
||||
btn_text: data.btn_text,
|
||||
btn_logo: data.btn_logo,
|
||||
modal_position: data.modal_position,
|
||||
search_mode: data.search_mode,
|
||||
placeholder: data.placeholder,
|
||||
disclaimer: data.disclaimer,
|
||||
recommend_questions: data.recommend_questions || [],
|
||||
recommend_node_ids: data.recommend_node_ids || [],
|
||||
copyright_hide_enabled:
|
||||
data.copyright_hide_enabled === '1' ? true : false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -241,14 +236,45 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
}}
|
||||
>
|
||||
<Icon type='icon-jinggao' />
|
||||
未配置域名,可在右侧
|
||||
未配置域名,可在
|
||||
<Box component={'span'} sx={{ fontWeight: 500 }}>
|
||||
服务监听方式
|
||||
门户网站 / 服务监听方式
|
||||
</Box>{' '}
|
||||
中配置
|
||||
</Stack>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label='配色方案'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='theme_mode'
|
||||
render={({ field }) => (
|
||||
<RadioGroup
|
||||
row
|
||||
{...field}
|
||||
onChange={e => {
|
||||
field.onChange(e.target.value);
|
||||
setIsEdit(true);
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value='light'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>浅色模式</Box>}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value='dark'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>深色模式</Box>}
|
||||
/>
|
||||
</RadioGroup>
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label='挂件配置'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
|
|
@ -450,37 +476,6 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
)}
|
||||
<Collapse in={modalConfigOpen}>
|
||||
<Stack spacing={2.5}>
|
||||
<FormItem
|
||||
label='配色方案'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='theme_mode'
|
||||
render={({ field }) => (
|
||||
<RadioGroup
|
||||
row
|
||||
{...field}
|
||||
onChange={e => {
|
||||
field.onChange(e.target.value);
|
||||
setIsEdit(true);
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value='light'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>浅色模式</Box>}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value='dark'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>深色模式</Box>}
|
||||
/>
|
||||
</RadioGroup>
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label='弹窗位置'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
|
|
@ -563,7 +558,7 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label='搜索提示语'
|
||||
label='搜索提示'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
|
|
@ -574,7 +569,7 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
<TextField
|
||||
fullWidth
|
||||
{...field}
|
||||
placeholder='输入搜索提示语'
|
||||
placeholder='问问 AI 吧'
|
||||
error={!!errors.placeholder}
|
||||
helperText={errors.placeholder?.message}
|
||||
onChange={event => {
|
||||
|
|
@ -595,7 +590,7 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
placeholder='回车确认,填写下一个推荐问题'
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{/* <FormItem
|
||||
label='推荐文档'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
|
|
@ -607,30 +602,90 @@ const CardRobotWebComponent = ({ kb }: CardRobotWebComponentProps) => {
|
|||
setValue('recommend_node_ids', value);
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label='免责声明'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='disclaimer'
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...field}
|
||||
placeholder='输入免责声明'
|
||||
error={!!errors.disclaimer}
|
||||
helperText={errors.disclaimer?.message}
|
||||
onChange={event => {
|
||||
setIsEdit(true);
|
||||
field.onChange(event);
|
||||
}}
|
||||
</FormItem> */}
|
||||
<VersionMask permission={PROFESSION_VERSION_PERMISSION}>
|
||||
<FormItem
|
||||
label='版权信息'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='copyright_hide_enabled'
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<RadioGroup
|
||||
row
|
||||
{...field}
|
||||
onChange={e => {
|
||||
field.onChange(e.target.value);
|
||||
setIsEdit(true);
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value='0'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>显示</Box>}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value='1'
|
||||
control={<Radio size='small' />}
|
||||
label={<Box sx={{ width: 100 }}>隐藏</Box>}
|
||||
/>
|
||||
</RadioGroup>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
{copyright_hide_enabled === '0' && (
|
||||
<FormItem
|
||||
label='版权文字'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='copyright_info'
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...field}
|
||||
placeholder='本网站由 PandaWiki 提供技术支持'
|
||||
error={!!errors.copyright_info}
|
||||
helperText={errors.copyright_info?.message}
|
||||
onChange={event => {
|
||||
setIsEdit(true);
|
||||
field.onChange(event);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
</FormItem>
|
||||
)}
|
||||
<FormItem
|
||||
label='免责声明'
|
||||
sx={{ alignItems: 'flex-start' }}
|
||||
labelSx={{ mt: 1 }}
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name='disclaimer'
|
||||
render={({ field }) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...field}
|
||||
placeholder='本回答由 PandaWiki AI 自动生成,仅供参考。'
|
||||
error={!!errors.disclaimer}
|
||||
helperText={errors.disclaimer?.message}
|
||||
onChange={event => {
|
||||
setIsEdit(true);
|
||||
field.onChange(event);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
</VersionMask>
|
||||
</Stack>
|
||||
</Collapse>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -919,6 +919,8 @@ export interface DomainLink {
|
|||
url?: string;
|
||||
}
|
||||
|
||||
export type DomainMessageContent = Record<string, any>;
|
||||
|
||||
export interface DomainMetricsConfig {
|
||||
list?: {
|
||||
id?: string;
|
||||
|
|
@ -1038,6 +1040,7 @@ export interface DomainOpenAICompletionsRequest {
|
|||
response_format?: DomainOpenAIResponseFormat;
|
||||
stop?: string[];
|
||||
stream?: boolean;
|
||||
stream_options?: DomainOpenAIStreamOptions;
|
||||
temperature?: number;
|
||||
tool_choice?: DomainOpenAIToolChoice;
|
||||
tools?: DomainOpenAITool[];
|
||||
|
|
@ -1081,7 +1084,7 @@ export interface DomainOpenAIFunctionChoice {
|
|||
}
|
||||
|
||||
export interface DomainOpenAIMessage {
|
||||
content?: string;
|
||||
content?: DomainMessageContent;
|
||||
name?: string;
|
||||
role: string;
|
||||
tool_call_id?: string;
|
||||
|
|
@ -1092,6 +1095,10 @@ export interface DomainOpenAIResponseFormat {
|
|||
type: string;
|
||||
}
|
||||
|
||||
export interface DomainOpenAIStreamOptions {
|
||||
include_usage?: boolean;
|
||||
}
|
||||
|
||||
export interface DomainOpenAITool {
|
||||
function?: DomainOpenAIFunction;
|
||||
type: string;
|
||||
|
|
@ -1189,9 +1196,11 @@ export interface DomainShareConversationMessage {
|
|||
role?: SchemaRoleType;
|
||||
}
|
||||
|
||||
export interface DomainShareNodeListItemResp {
|
||||
export interface DomainShareNodeDetailItem {
|
||||
children?: DomainShareNodeDetailItem[];
|
||||
emoji?: string;
|
||||
id?: string;
|
||||
meta?: DomainNodeMeta;
|
||||
name?: string;
|
||||
parent_id?: string;
|
||||
permissions?: DomainNodePermissions;
|
||||
|
|
@ -1382,6 +1391,8 @@ export interface DomainWidgetBotSettings {
|
|||
btn_position?: string;
|
||||
btn_style?: string;
|
||||
btn_text?: string;
|
||||
copyright_hide_enabled?: boolean;
|
||||
copyright_info?: string;
|
||||
disclaimer?: string;
|
||||
is_open?: boolean;
|
||||
modal_position?: string;
|
||||
|
|
@ -1694,7 +1705,7 @@ export interface V1ShareNodeDetailResp {
|
|||
editor_id?: string;
|
||||
id?: string;
|
||||
kb_id?: string;
|
||||
list?: DomainShareNodeListItemResp[];
|
||||
list?: DomainShareNodeDetailItem[];
|
||||
meta?: DomainNodeMeta;
|
||||
name?: string;
|
||||
parent_id?: string;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
will-change: transform;
|
||||
backface-visibility: hidden;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.widget-bot-button:hover {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
'use strict';
|
||||
|
||||
const defaultModalPosition = 'follow';
|
||||
const defaultBtnPosition = 'bottom_left';
|
||||
const defaultBtnPosition = 'bottom_right';
|
||||
const defaultBtnStyle = 'side_sticky';
|
||||
|
||||
// 获取当前脚本的域名
|
||||
|
|
@ -98,16 +98,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// 创建两行文字(每行两个字)
|
||||
function createTwoLineText(text) {
|
||||
const chars = text.split('').filter(it => !!it.trim());
|
||||
const lines = [];
|
||||
for (let i = 0; i < chars.length; i += 2) {
|
||||
lines.push(chars.slice(i, i + 2).join(''));
|
||||
}
|
||||
return lines.map(line => `<span>${line}</span>`).join('');
|
||||
}
|
||||
|
||||
// 应用按钮位置
|
||||
function applyButtonPosition(button, position) {
|
||||
const pos = position || defaultBtnPosition;
|
||||
|
|
@ -170,7 +160,11 @@
|
|||
// 添加文字
|
||||
const textDiv = document.createElement('div');
|
||||
textDiv.className = 'widget-bot-text';
|
||||
textDiv.innerHTML = createTwoLineText(widgetInfo.btn_text || '在线客服');
|
||||
textDiv.textContent = widgetInfo.btn_text || '在线客服';
|
||||
// 设置固定宽度、自动换行和居中
|
||||
textDiv.style.wordWrap = 'break-word';
|
||||
textDiv.style.whiteSpace = 'normal';
|
||||
textDiv.style.textAlign = 'center';
|
||||
buttonContent.appendChild(textDiv);
|
||||
|
||||
widgetButton.appendChild(buttonContent);
|
||||
|
|
@ -695,25 +689,41 @@
|
|||
dragStartPos.x = clientX;
|
||||
dragStartPos.y = clientY;
|
||||
|
||||
// 缓存按钮尺寸,避免拖拽过程中频繁读取
|
||||
buttonSize.width = rect.width;
|
||||
buttonSize.height = rect.height;
|
||||
// 由于 transform-origin 是 center,scale 不会改变元素中心位置
|
||||
// 但 getBoundingClientRect() 返回的尺寸是放大后的,需要计算原始尺寸
|
||||
// 假设当前可能有 scale(1.1),计算原始尺寸
|
||||
const scale = 1.1; // hover 时的 scale 值
|
||||
const originalWidth = rect.width / scale;
|
||||
const originalHeight = rect.height / scale;
|
||||
|
||||
const realRect = widgetButton.getBoundingClientRect();
|
||||
initialPosition.left = realRect.left;
|
||||
initialPosition.top = realRect.top;
|
||||
// 缓存按钮原始尺寸(未缩放)
|
||||
buttonSize.width = originalWidth;
|
||||
buttonSize.height = originalHeight;
|
||||
|
||||
dragOffset.x = clientX - realRect.left;
|
||||
dragOffset.y = clientY - realRect.top;
|
||||
// 由于 transform-origin 是 center,元素的左上角位置需要考虑 scale 的影响
|
||||
// 中心点位置不变,但左上角会向左上移动
|
||||
const centerX = rect.left + rect.width / 2;
|
||||
const centerY = rect.top + rect.height / 2;
|
||||
const originalLeft = centerX - originalWidth / 2;
|
||||
const originalTop = centerY - originalHeight / 2;
|
||||
|
||||
initialPosition.left = originalLeft;
|
||||
initialPosition.top = originalTop;
|
||||
|
||||
// 计算鼠标相对于原始尺寸(未缩放)按钮左上角的偏移
|
||||
dragOffset.x = clientX - originalLeft;
|
||||
dragOffset.y = clientY - originalTop;
|
||||
|
||||
widgetButton.style.position = 'fixed';
|
||||
widgetButton.style.top = realRect.top + 'px';
|
||||
widgetButton.style.left = realRect.left + 'px';
|
||||
widgetButton.style.top = originalTop + 'px';
|
||||
widgetButton.style.left = originalLeft + 'px';
|
||||
widgetButton.style.right = 'auto';
|
||||
widgetButton.style.bottom = 'auto';
|
||||
// 保持 scale 效果
|
||||
widgetButton.style.transform = 'scale(1.1)';
|
||||
|
||||
widgetButton.style.transition = 'none';
|
||||
widgetButton.style.willChange = 'left, top';
|
||||
widgetButton.style.willChange = 'left, top, transform';
|
||||
|
||||
document.addEventListener('mousemove', drag, { passive: false });
|
||||
document.addEventListener('mouseup', stopDrag);
|
||||
|
|
@ -764,6 +774,8 @@
|
|||
widgetButton.style.top = constrainedTop + 'px';
|
||||
widgetButton.style.right = 'auto';
|
||||
widgetButton.style.bottom = 'auto';
|
||||
// 保持 scale 效果
|
||||
widgetButton.style.transform = 'scale(1.1)';
|
||||
}
|
||||
|
||||
// 停止拖拽
|
||||
|
|
@ -787,6 +799,8 @@
|
|||
// 恢复过渡效果
|
||||
widgetButton.style.transition = '';
|
||||
widgetButton.style.willChange = '';
|
||||
// 移除 transform,让 CSS hover 效果可以正常工作
|
||||
widgetButton.style.transform = '';
|
||||
|
||||
// 根据按钮类型和当前位置进行最终定位
|
||||
requestAnimationFrame(() => {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ export type WidgetInfo = {
|
|||
search_mode?: string;
|
||||
placeholder?: string;
|
||||
disclaimer?: string;
|
||||
copyright_hide_enabled?: boolean;
|
||||
copyright_info?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1391,6 +1391,8 @@ export interface DomainWidgetBotSettings {
|
|||
btn_position?: string;
|
||||
btn_style?: string;
|
||||
btn_text?: string;
|
||||
copyright_hide_enabled?: boolean;
|
||||
copyright_info?: string;
|
||||
disclaimer?: string;
|
||||
is_open?: boolean;
|
||||
modal_position?: string;
|
||||
|
|
|
|||
|
|
@ -931,7 +931,8 @@ const AiQaContent: React.FC<{
|
|||
)}
|
||||
</Stack>
|
||||
<Box>
|
||||
{widget?.settings?.widget_bot_settings?.disclaimer}
|
||||
{widget?.settings?.widget_bot_settings?.disclaimer ||
|
||||
'本回答由 PandaWiki AI 自动生成,仅供参考。'}
|
||||
</Box>
|
||||
</StyledActionStack>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ const Widget = () => {
|
|||
})}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{/* 顶部标签栏 */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
|
@ -192,30 +191,33 @@ const Widget = () => {
|
|||
>
|
||||
<SearchDocContent inputRef={inputRef} placeholder={placeholder} />
|
||||
</Box>
|
||||
|
||||
{/* 底部AI生成提示 */}
|
||||
<Box
|
||||
sx={{
|
||||
px: 3,
|
||||
pt: widget?.settings?.widget_bot_settings?.disclaimer ? 2 : 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant='caption'
|
||||
{!widget?.settings?.widget_bot_settings?.copyright_hide_enabled && (
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.disabled',
|
||||
fontSize: 12,
|
||||
px: 3,
|
||||
pt: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Box>本网站由 PandaWiki 提供技术支持</Box>
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
variant='caption'
|
||||
sx={{
|
||||
color: 'text.disabled',
|
||||
fontSize: 12,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
{widget?.settings?.widget_bot_settings?.copyright_info ||
|
||||
'本网站由 PandaWiki 提供技术支持'}
|
||||
</Box>
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.12.1",
|
||||
"dependencies": {
|
||||
"@ctzhian/tiptap": "^1.13.3",
|
||||
"@ctzhian/tiptap": "^1.13.4",
|
||||
"@ctzhian/ui": "^7.0.5",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ importers:
|
|||
.:
|
||||
dependencies:
|
||||
'@ctzhian/tiptap':
|
||||
specifier: ^1.13.3
|
||||
version: 1.13.3(cd47b5fad786e7bd41819ffa7bed30ac)
|
||||
specifier: ^1.13.4
|
||||
version: 1.13.4(cd47b5fad786e7bd41819ffa7bed30ac)
|
||||
'@ctzhian/ui':
|
||||
specifier: ^7.0.5
|
||||
version: 7.0.5(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/icons-material@7.3.4(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@mui/utils@7.3.3(@types/react@19.2.2)(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
|
|
@ -523,8 +523,8 @@ packages:
|
|||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
'@ctzhian/tiptap@1.13.3':
|
||||
resolution: {integrity: sha512-amCg2nN0YRYp9qBH/9zj5PHoghIabIWf75cnDuTU08WqXTV/BISReDflEdE5nNMCvxm7pFbY0G7o0FtB6acd9w==}
|
||||
'@ctzhian/tiptap@1.13.4':
|
||||
resolution: {integrity: sha512-NdwLGaUU+v90Yo3+ae/7QBvhOBC3WfNpwNwSBWRLIAkIwBGexva7AM6CVP+G8rVeJMDpKa7sk11TexIoGNpEUw==}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11
|
||||
'@emotion/styled': ^11
|
||||
|
|
@ -6136,7 +6136,7 @@ snapshots:
|
|||
- react-native
|
||||
- typescript
|
||||
|
||||
'@ctzhian/tiptap@1.13.3(cd47b5fad786e7bd41819ffa7bed30ac)':
|
||||
'@ctzhian/tiptap@1.13.4(cd47b5fad786e7bd41819ffa7bed30ac)':
|
||||
dependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@19.2.0)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue