mirror of https://github.com/chaitin/PandaWiki.git
Compare commits
1 Commits
487db8e944
...
c9a6b6e403
| Author | SHA1 | Date |
|---|---|---|
|
|
c9a6b6e403 |
|
|
@ -4964,34 +4964,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.BlockGridConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.BrandGroup": {
|
"domain.BrandGroup": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -6778,31 +6750,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.QuestionConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"question": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.RagInfo": {
|
"domain.RagInfo": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -7283,9 +7230,6 @@ const docTemplate = `{
|
||||||
"basic_doc_config": {
|
"basic_doc_config": {
|
||||||
"$ref": "#/definitions/domain.BasicDocConfig"
|
"$ref": "#/definitions/domain.BasicDocConfig"
|
||||||
},
|
},
|
||||||
"block_grid_config": {
|
|
||||||
"$ref": "#/definitions/domain.BlockGridConfig"
|
|
||||||
},
|
|
||||||
"carousel_config": {
|
"carousel_config": {
|
||||||
"$ref": "#/definitions/domain.CarouselConfig"
|
"$ref": "#/definitions/domain.CarouselConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7322,9 +7266,6 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question_config": {
|
|
||||||
"$ref": "#/definitions/domain.QuestionConfig"
|
|
||||||
},
|
|
||||||
"simple_doc_config": {
|
"simple_doc_config": {
|
||||||
"$ref": "#/definitions/domain.SimpleDocConfig"
|
"$ref": "#/definitions/domain.SimpleDocConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7348,9 +7289,6 @@ const docTemplate = `{
|
||||||
"basic_doc_config": {
|
"basic_doc_config": {
|
||||||
"$ref": "#/definitions/domain.BasicDocConfig"
|
"$ref": "#/definitions/domain.BasicDocConfig"
|
||||||
},
|
},
|
||||||
"block_grid_config": {
|
|
||||||
"$ref": "#/definitions/domain.BlockGridConfig"
|
|
||||||
},
|
|
||||||
"carousel_config": {
|
"carousel_config": {
|
||||||
"$ref": "#/definitions/domain.CarouselConfig"
|
"$ref": "#/definitions/domain.CarouselConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7393,9 +7331,6 @@ const docTemplate = `{
|
||||||
"$ref": "#/definitions/domain.RecommendNodeListResp"
|
"$ref": "#/definitions/domain.RecommendNodeListResp"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question_config": {
|
|
||||||
"$ref": "#/definitions/domain.QuestionConfig"
|
|
||||||
},
|
|
||||||
"simple_doc_config": {
|
"simple_doc_config": {
|
||||||
"$ref": "#/definitions/domain.SimpleDocConfig"
|
"$ref": "#/definitions/domain.SimpleDocConfig"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4957,34 +4957,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.BlockGridConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.BrandGroup": {
|
"domain.BrandGroup": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -6771,31 +6743,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.QuestionConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"list": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"question": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.RagInfo": {
|
"domain.RagInfo": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -7276,9 +7223,6 @@
|
||||||
"basic_doc_config": {
|
"basic_doc_config": {
|
||||||
"$ref": "#/definitions/domain.BasicDocConfig"
|
"$ref": "#/definitions/domain.BasicDocConfig"
|
||||||
},
|
},
|
||||||
"block_grid_config": {
|
|
||||||
"$ref": "#/definitions/domain.BlockGridConfig"
|
|
||||||
},
|
|
||||||
"carousel_config": {
|
"carousel_config": {
|
||||||
"$ref": "#/definitions/domain.CarouselConfig"
|
"$ref": "#/definitions/domain.CarouselConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7315,9 +7259,6 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question_config": {
|
|
||||||
"$ref": "#/definitions/domain.QuestionConfig"
|
|
||||||
},
|
|
||||||
"simple_doc_config": {
|
"simple_doc_config": {
|
||||||
"$ref": "#/definitions/domain.SimpleDocConfig"
|
"$ref": "#/definitions/domain.SimpleDocConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7341,9 +7282,6 @@
|
||||||
"basic_doc_config": {
|
"basic_doc_config": {
|
||||||
"$ref": "#/definitions/domain.BasicDocConfig"
|
"$ref": "#/definitions/domain.BasicDocConfig"
|
||||||
},
|
},
|
||||||
"block_grid_config": {
|
|
||||||
"$ref": "#/definitions/domain.BlockGridConfig"
|
|
||||||
},
|
|
||||||
"carousel_config": {
|
"carousel_config": {
|
||||||
"$ref": "#/definitions/domain.CarouselConfig"
|
"$ref": "#/definitions/domain.CarouselConfig"
|
||||||
},
|
},
|
||||||
|
|
@ -7386,9 +7324,6 @@
|
||||||
"$ref": "#/definitions/domain.RecommendNodeListResp"
|
"$ref": "#/definitions/domain.RecommendNodeListResp"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question_config": {
|
|
||||||
"$ref": "#/definitions/domain.QuestionConfig"
|
|
||||||
},
|
|
||||||
"simple_doc_config": {
|
"simple_doc_config": {
|
||||||
"$ref": "#/definitions/domain.SimpleDocConfig"
|
"$ref": "#/definitions/domain.SimpleDocConfig"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -833,24 +833,6 @@ definitions:
|
||||||
- ids
|
- ids
|
||||||
- kb_id
|
- kb_id
|
||||||
type: object
|
type: object
|
||||||
domain.BlockGridConfig:
|
|
||||||
properties:
|
|
||||||
list:
|
|
||||||
items:
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
url:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
title:
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.BrandGroup:
|
domain.BrandGroup:
|
||||||
properties:
|
properties:
|
||||||
links:
|
links:
|
||||||
|
|
@ -2011,22 +1993,6 @@ definitions:
|
||||||
model:
|
model:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
domain.QuestionConfig:
|
|
||||||
properties:
|
|
||||||
list:
|
|
||||||
items:
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
question:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
title:
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.RagInfo:
|
domain.RagInfo:
|
||||||
properties:
|
properties:
|
||||||
message:
|
message:
|
||||||
|
|
@ -2343,8 +2309,6 @@ definitions:
|
||||||
$ref: '#/definitions/domain.BannerConfig'
|
$ref: '#/definitions/domain.BannerConfig'
|
||||||
basic_doc_config:
|
basic_doc_config:
|
||||||
$ref: '#/definitions/domain.BasicDocConfig'
|
$ref: '#/definitions/domain.BasicDocConfig'
|
||||||
block_grid_config:
|
|
||||||
$ref: '#/definitions/domain.BlockGridConfig'
|
|
||||||
carousel_config:
|
carousel_config:
|
||||||
$ref: '#/definitions/domain.CarouselConfig'
|
$ref: '#/definitions/domain.CarouselConfig'
|
||||||
case_config:
|
case_config:
|
||||||
|
|
@ -2369,8 +2333,6 @@ definitions:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
question_config:
|
|
||||||
$ref: '#/definitions/domain.QuestionConfig'
|
|
||||||
simple_doc_config:
|
simple_doc_config:
|
||||||
$ref: '#/definitions/domain.SimpleDocConfig'
|
$ref: '#/definitions/domain.SimpleDocConfig'
|
||||||
text_config:
|
text_config:
|
||||||
|
|
@ -2386,8 +2348,6 @@ definitions:
|
||||||
$ref: '#/definitions/domain.BannerConfig'
|
$ref: '#/definitions/domain.BannerConfig'
|
||||||
basic_doc_config:
|
basic_doc_config:
|
||||||
$ref: '#/definitions/domain.BasicDocConfig'
|
$ref: '#/definitions/domain.BasicDocConfig'
|
||||||
block_grid_config:
|
|
||||||
$ref: '#/definitions/domain.BlockGridConfig'
|
|
||||||
carousel_config:
|
carousel_config:
|
||||||
$ref: '#/definitions/domain.CarouselConfig'
|
$ref: '#/definitions/domain.CarouselConfig'
|
||||||
case_config:
|
case_config:
|
||||||
|
|
@ -2416,8 +2376,6 @@ definitions:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/domain.RecommendNodeListResp'
|
$ref: '#/definitions/domain.RecommendNodeListResp'
|
||||||
type: array
|
type: array
|
||||||
question_config:
|
|
||||||
$ref: '#/definitions/domain.QuestionConfig'
|
|
||||||
simple_doc_config:
|
simple_doc_config:
|
||||||
$ref: '#/definitions/domain.SimpleDocConfig'
|
$ref: '#/definitions/domain.SimpleDocConfig'
|
||||||
text_config:
|
text_config:
|
||||||
|
|
|
||||||
|
|
@ -293,23 +293,6 @@ type TextImgConfig struct {
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
} `json:"item"`
|
} `json:"item"`
|
||||||
}
|
}
|
||||||
type QuestionConfig struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
List []struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Question string `json:"question"`
|
|
||||||
} `json:"list"`
|
|
||||||
}
|
|
||||||
type BlockGridConfig struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
List []struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
} `json:"list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebAppLandingConfig struct {
|
type WebAppLandingConfig struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
@ -327,8 +310,6 @@ type WebAppLandingConfig struct {
|
||||||
FeatureConfig *FeatureConfig `json:"feature_config,omitempty"`
|
FeatureConfig *FeatureConfig `json:"feature_config,omitempty"`
|
||||||
ImgTextConfig *ImgTextConfig `json:"img_text_config,omitempty"`
|
ImgTextConfig *ImgTextConfig `json:"img_text_config,omitempty"`
|
||||||
TextImgConfig *TextImgConfig `json:"text_img_config,omitempty"`
|
TextImgConfig *TextImgConfig `json:"text_img_config,omitempty"`
|
||||||
QuestionConfig *QuestionConfig `json:"question_config,omitempty"`
|
|
||||||
BlockGridConfig *BlockGridConfig `json:"block_grid_config,omitempty"`
|
|
||||||
ComConfigOrder []string `json:"com_config_order"`
|
ComConfigOrder []string `json:"com_config_order"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,8 +524,6 @@ type WebAppLandingConfigResp struct {
|
||||||
FeatureConfig *FeatureConfig `json:"feature_config,omitempty"`
|
FeatureConfig *FeatureConfig `json:"feature_config,omitempty"`
|
||||||
ImgTextConfig *ImgTextConfig `json:"img_text_config,omitempty"`
|
ImgTextConfig *ImgTextConfig `json:"img_text_config,omitempty"`
|
||||||
TextImgConfig *TextImgConfig `json:"text_img_config,omitempty"`
|
TextImgConfig *TextImgConfig `json:"text_img_config,omitempty"`
|
||||||
QuestionConfig *QuestionConfig `json:"question_config,omitempty"`
|
|
||||||
BlockGridConfig *BlockGridConfig `json:"block_grid_config,omitempty"`
|
|
||||||
ComConfigOrder []string `json:"com_config_order"`
|
ComConfigOrder []string `json:"com_config_order"`
|
||||||
NodeIds []string `json:"node_ids"`
|
NodeIds []string `json:"node_ids"`
|
||||||
Nodes []*RecommendNodeListResp `json:"nodes" gorm:"-"`
|
Nodes []*RecommendNodeListResp `json:"nodes" gorm:"-"`
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit b6e6fb64429a827fb4a95fa9ee3bb4379ac18cd9
|
Subproject commit e7bf0a030242425c83291b369770c113fd503a5a
|
||||||
|
|
@ -422,8 +422,6 @@ func (u *AppUsecase) GetAppDetailByKBIDAndAppType(ctx context.Context, kbID stri
|
||||||
FeatureConfig: app.Settings.WebAppLandingConfigs[i].FeatureConfig,
|
FeatureConfig: app.Settings.WebAppLandingConfigs[i].FeatureConfig,
|
||||||
ImgTextConfig: app.Settings.WebAppLandingConfigs[i].ImgTextConfig,
|
ImgTextConfig: app.Settings.WebAppLandingConfigs[i].ImgTextConfig,
|
||||||
TextImgConfig: app.Settings.WebAppLandingConfigs[i].TextImgConfig,
|
TextImgConfig: app.Settings.WebAppLandingConfigs[i].TextImgConfig,
|
||||||
QuestionConfig: app.Settings.WebAppLandingConfigs[i].QuestionConfig,
|
|
||||||
BlockGridConfig: app.Settings.WebAppLandingConfigs[i].BlockGridConfig,
|
|
||||||
ComConfigOrder: app.Settings.WebAppLandingConfigs[i].ComConfigOrder,
|
ComConfigOrder: app.Settings.WebAppLandingConfigs[i].ComConfigOrder,
|
||||||
NodeIds: app.Settings.WebAppLandingConfigs[i].NodeIds,
|
NodeIds: app.Settings.WebAppLandingConfigs[i].NodeIds,
|
||||||
}
|
}
|
||||||
|
|
@ -554,8 +552,6 @@ func (u *AppUsecase) ShareGetWebAppInfo(ctx context.Context, kbID string, authId
|
||||||
ImgTextConfig: app.Settings.WebAppLandingConfigs[i].ImgTextConfig,
|
ImgTextConfig: app.Settings.WebAppLandingConfigs[i].ImgTextConfig,
|
||||||
TextImgConfig: app.Settings.WebAppLandingConfigs[i].TextImgConfig,
|
TextImgConfig: app.Settings.WebAppLandingConfigs[i].TextImgConfig,
|
||||||
MetricsConfig: app.Settings.WebAppLandingConfigs[i].MetricsConfig,
|
MetricsConfig: app.Settings.WebAppLandingConfigs[i].MetricsConfig,
|
||||||
QuestionConfig: app.Settings.WebAppLandingConfigs[i].QuestionConfig,
|
|
||||||
BlockGridConfig: app.Settings.WebAppLandingConfigs[i].BlockGridConfig,
|
|
||||||
ComConfigOrder: app.Settings.WebAppLandingConfigs[i].ComConfigOrder,
|
ComConfigOrder: app.Settings.WebAppLandingConfigs[i].ComConfigOrder,
|
||||||
NodeIds: app.Settings.WebAppLandingConfigs[i].NodeIds,
|
NodeIds: app.Settings.WebAppLandingConfigs[i].NodeIds,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
"@emoji-mart/data": "^1.2.1",
|
"@emoji-mart/data": "^1.2.1",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
"@reduxjs/toolkit": "^2.5.0",
|
"@reduxjs/toolkit": "^2.5.0",
|
||||||
|
"@tiptap/extension-collaboration": "^3.3.0",
|
||||||
|
"@tiptap/extension-collaboration-caret": "^3.3.0",
|
||||||
|
"ace-builds": "^1.43.4",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^5.6.0",
|
||||||
|
|
@ -29,9 +32,9 @@
|
||||||
"lottie-react": "^2.4.1",
|
"lottie-react": "^2.4.1",
|
||||||
"lowlight": "^3.3.0",
|
"lowlight": "^3.3.0",
|
||||||
"prosemirror-state": "^1.4.3",
|
"prosemirror-state": "^1.4.3",
|
||||||
|
"react-ace": "^14.0.1",
|
||||||
"react-color-palette": "^7.3.1",
|
"react-color-palette": "^7.3.1",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-diff-viewer": "^3.1.1",
|
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-image-crop": "^11.0.10",
|
"react-image-crop": "^11.0.10",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const Config = ({ setIsEdit, id }: ConfigProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleListChange = (
|
const handleListChange = (
|
||||||
newList: (typeof DEFAULT_DATA.block_grid)['list'],
|
newList: (typeof DEFAULT_DATA.blockGrid)['list'],
|
||||||
) => {
|
) => {
|
||||||
setValue('list', newList);
|
setValue('list', newList);
|
||||||
setIsEdit(true);
|
setIsEdit(true);
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ const FaqDragList: FC<FaqDragListProps> = ({ data, onChange, setIsEdit }) => {
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
<DragOverlay adjustScale style={{ transformOrigin: '0 0' }}>
|
{/* <DragOverlay adjustScale style={{ transformOrigin: '0 0' }}>
|
||||||
{activeId ? (
|
{activeId ? (
|
||||||
<Item
|
<Item
|
||||||
isDragging
|
isDragging
|
||||||
|
|
@ -105,7 +105,7 @@ const FaqDragList: FC<FaqDragListProps> = ({ data, onChange, setIsEdit }) => {
|
||||||
handleUpdateItem={handleUpdateItem}
|
handleUpdateItem={handleUpdateItem}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</DragOverlay>
|
</DragOverlay> */}
|
||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
import {
|
|
||||||
ConstsContributeStatus,
|
|
||||||
ConstsContributeType,
|
|
||||||
getApiProV1ContributeDetail,
|
|
||||||
GithubComChaitinPandaWikiProApiContributeV1ContributeDetailResp,
|
|
||||||
GithubComChaitinPandaWikiProApiContributeV1ContributeItem,
|
|
||||||
} from '@/request/pro';
|
|
||||||
import { useAppSelector } from '@/store';
|
|
||||||
import { Modal } from '@ctzhian/ui';
|
|
||||||
import { Box, Button, Stack } from '@mui/material';
|
|
||||||
import { IconWenjian } from '@panda-wiki/icons';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import ReactDiffViewer from 'react-diff-viewer';
|
|
||||||
|
|
||||||
type MarkdownPreviewModalProps = {
|
|
||||||
open: boolean;
|
|
||||||
row: GithubComChaitinPandaWikiProApiContributeV1ContributeItem | null;
|
|
||||||
onClose: () => void;
|
|
||||||
onAccept: () => void;
|
|
||||||
onReject: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MarkdownPreviewModal = ({
|
|
||||||
open,
|
|
||||||
row,
|
|
||||||
onClose,
|
|
||||||
onAccept,
|
|
||||||
onReject,
|
|
||||||
}: MarkdownPreviewModalProps) => {
|
|
||||||
const { kb_id = '' } = useAppSelector(state => state.config);
|
|
||||||
const [data, setData] =
|
|
||||||
useState<GithubComChaitinPandaWikiProApiContributeV1ContributeDetailResp | null>(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (open && row) {
|
|
||||||
getApiProV1ContributeDetail({ id: row.id!, kb_id }).then(res => {
|
|
||||||
setData(res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [open, row, kb_id]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={open}
|
|
||||||
onCancel={onClose}
|
|
||||||
width={'1200px'}
|
|
||||||
sx={{
|
|
||||||
'.MuiDialogContent-root': {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
title={
|
|
||||||
<Stack direction='row' alignItems='center' gap={2}>
|
|
||||||
<Box>
|
|
||||||
来自 {row?.auth_name || '匿名用户'} 的
|
|
||||||
{row?.type === ConstsContributeType.ContributeTypeAdd
|
|
||||||
? '新增'
|
|
||||||
: '修改'}
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ fontSize: 14, color: 'text.auxiliary', fontWeight: 400 }}>
|
|
||||||
{dayjs(row?.created_at).fromNow()}
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
}
|
|
||||||
footer={
|
|
||||||
row?.status === ConstsContributeStatus.ContributeStatusPending ||
|
|
||||||
row?.status === ConstsContributeStatus.ContributeStatusRejected ? (
|
|
||||||
<Stack
|
|
||||||
direction='row'
|
|
||||||
gap={1}
|
|
||||||
justifyContent='flex-end'
|
|
||||||
sx={{ p: 3, pt: 0 }}
|
|
||||||
>
|
|
||||||
{row?.status === ConstsContributeStatus.ContributeStatusPending ? (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
size='small'
|
|
||||||
variant='outlined'
|
|
||||||
color='error'
|
|
||||||
onClick={onReject}
|
|
||||||
>
|
|
||||||
拒绝
|
|
||||||
</Button>
|
|
||||||
<Button size='small' variant='contained' onClick={onAccept}>
|
|
||||||
采纳
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Button onClick={onClose} size='small' variant='contained'>
|
|
||||||
关闭
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
) : null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Stack direction='row'>
|
|
||||||
<Stack
|
|
||||||
spacing={2}
|
|
||||||
sx={{
|
|
||||||
overflow: 'auto',
|
|
||||||
flex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack
|
|
||||||
direction='row'
|
|
||||||
gap={1}
|
|
||||||
sx={{ bgcolor: 'background.paper2', p: 1, borderRadius: '10px' }}
|
|
||||||
>
|
|
||||||
<Box sx={{ fontSize: 14, fontWeight: 'bold', flexShrink: 0 }}>
|
|
||||||
提交说明:
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{ fontSize: 14, color: 'text.tertiary' }}>
|
|
||||||
{data?.reason || '-'}
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
<Stack
|
|
||||||
direction='row'
|
|
||||||
alignItems='center'
|
|
||||||
gap={1}
|
|
||||||
sx={{ fontSize: 24, fontWeight: 700, pb: 2 }}
|
|
||||||
>
|
|
||||||
<IconWenjian /> {row?.node_name || '-'}
|
|
||||||
</Stack>
|
|
||||||
<Box sx={{ overflowY: 'auto', maxHeight: 'calc(100vh - 400px)' }}>
|
|
||||||
<ReactDiffViewer
|
|
||||||
oldValue={data?.original_node?.content || ''}
|
|
||||||
newValue={data?.content || ''}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MarkdownPreviewModal;
|
|
||||||
|
|
@ -1,27 +1,26 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
import Logo from '@/assets/images/logo.png';
|
import Logo from '@/assets/images/logo.png';
|
||||||
|
import { Box, Chip, Stack, TextField } from '@mui/material';
|
||||||
import Card from '@/components/Card';
|
import Card from '@/components/Card';
|
||||||
import { tableSx } from '@/constant/styles';
|
import { tableSx } from '@/constant/styles';
|
||||||
import { Ellipsis, message, Modal, Table } from '@ctzhian/ui';
|
|
||||||
import type { ColumnType } from '@ctzhian/ui/dist/Table';
|
|
||||||
import { Box, Chip, Stack, TextField } from '@mui/material';
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useEffect, useState } from 'react';
|
import { Table, Ellipsis, message, Modal } from '@ctzhian/ui';
|
||||||
|
import type { ColumnType } from '@ctzhian/ui/dist/Table';
|
||||||
import DocModal from './DocModal';
|
import DocModal from './DocModal';
|
||||||
|
|
||||||
import { useURLSearchParams } from '@/hooks';
|
|
||||||
import {
|
import {
|
||||||
getApiProV1ContributeList,
|
getApiProV1ContributeList,
|
||||||
postApiProV1ContributeAudit,
|
postApiProV1ContributeAudit,
|
||||||
} from '@/request/pro/Contribute';
|
} from '@/request/pro/Contribute';
|
||||||
import {
|
import {
|
||||||
|
GithubComChaitinPandaWikiProApiContributeV1ContributeItem,
|
||||||
ConstsContributeStatus,
|
ConstsContributeStatus,
|
||||||
ConstsContributeType,
|
ConstsContributeType,
|
||||||
GithubComChaitinPandaWikiProApiContributeV1ContributeItem,
|
|
||||||
} from '@/request/pro/types';
|
} from '@/request/pro/types';
|
||||||
|
import { useURLSearchParams } from '@/hooks';
|
||||||
import { useAppSelector } from '@/store';
|
import { useAppSelector } from '@/store';
|
||||||
import ContributePreviewModal from './ContributePreviewModal';
|
import ContributePreviewModal from './ContributePreviewModal';
|
||||||
import MarkdownPreviewModal from './MarkdownPreviewModal';
|
|
||||||
|
|
||||||
const StyledSearchRow = styled(Stack)(({ theme }) => ({
|
const StyledSearchRow = styled(Stack)(({ theme }) => ({
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
|
|
@ -366,15 +365,6 @@ export default function ContributionPage() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{previewRow?.meta?.content_type === 'md' ? (
|
|
||||||
<MarkdownPreviewModal
|
|
||||||
open={open}
|
|
||||||
row={previewRow}
|
|
||||||
onClose={closeDialog}
|
|
||||||
onAccept={handleAccept}
|
|
||||||
onReject={handleReject}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ContributePreviewModal
|
<ContributePreviewModal
|
||||||
open={open}
|
open={open}
|
||||||
row={previewRow}
|
row={previewRow}
|
||||||
|
|
@ -382,7 +372,6 @@ export default function ContributionPage() {
|
||||||
onAccept={handleAccept}
|
onAccept={handleAccept}
|
||||||
onReject={handleReject}
|
onReject={handleReject}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
<DocModal
|
<DocModal
|
||||||
open={docModalOpen}
|
open={docModalOpen}
|
||||||
onClose={() => setDocModalOpen(false)}
|
onClose={() => setDocModalOpen(false)}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { DomainNodeListItemResp, V1NodeDetailResp } from '@/request/types';
|
||||||
import { useAppSelector } from '@/store';
|
import { useAppSelector } from '@/store';
|
||||||
import { addOpacityToColor } from '@/utils';
|
import { addOpacityToColor } from '@/utils';
|
||||||
import { convertToTree } from '@/utils/drag';
|
import { convertToTree } from '@/utils/drag';
|
||||||
|
import { filterEmptyFolders } from '@/utils/tree';
|
||||||
import { Ellipsis, Icon } from '@ctzhian/ui';
|
import { Ellipsis, Icon } from '@ctzhian/ui';
|
||||||
import { alpha, Box, IconButton, Stack, useTheme } from '@mui/material';
|
import { alpha, Box, IconButton, Stack, useTheme } from '@mui/material';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
@ -65,7 +66,7 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
kb_id: kb_id || localStorage.getItem('kb_id') || '',
|
kb_id: kb_id || localStorage.getItem('kb_id') || '',
|
||||||
};
|
};
|
||||||
getApiV1NodeList(params).then(res => {
|
getApiV1NodeList(params).then(res => {
|
||||||
const v = convertToTree(res || []);
|
const v = filterEmptyFolders(convertToTree(res || []));
|
||||||
setData(v);
|
setData(v);
|
||||||
// 计算当前文档的所有父级文件夹,并默认展开
|
// 计算当前文档的所有父级文件夹,并默认展开
|
||||||
try {
|
try {
|
||||||
|
|
@ -109,75 +110,6 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderAdd = (parentId: string) => {
|
|
||||||
return (
|
|
||||||
<Box sx={{ flexShrink: 0 }} onClick={e => e.stopPropagation()}>
|
|
||||||
<Cascader
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'bottom',
|
|
||||||
horizontal: 'left',
|
|
||||||
}}
|
|
||||||
transformOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'left',
|
|
||||||
}}
|
|
||||||
context={
|
|
||||||
<IconButton>
|
|
||||||
<Icon
|
|
||||||
className='catalog-folder-add-icon'
|
|
||||||
type='icon-icon_tool_close'
|
|
||||||
sx={{
|
|
||||||
fontSize: 16,
|
|
||||||
color: 'action.selected',
|
|
||||||
transform: 'rotate(45deg)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
list={Object.entries(ImportContentWays).map(([key, value]) => ({
|
|
||||||
key,
|
|
||||||
label: (
|
|
||||||
<Box key={key}>
|
|
||||||
<Stack
|
|
||||||
direction={'row'}
|
|
||||||
alignItems={'center'}
|
|
||||||
gap={1}
|
|
||||||
sx={{
|
|
||||||
fontSize: 14,
|
|
||||||
px: 2,
|
|
||||||
lineHeight: '40px',
|
|
||||||
height: 40,
|
|
||||||
width: 180,
|
|
||||||
borderRadius: '5px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
':hover': {
|
|
||||||
bgcolor: addOpacityToColor(
|
|
||||||
theme.palette.primary.main,
|
|
||||||
0.1,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
onClick={() => value.onClick(parentId)}
|
|
||||||
>
|
|
||||||
{value.label}
|
|
||||||
</Stack>
|
|
||||||
{key === 'OfflineFile' && (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
borderTop: '1px solid',
|
|
||||||
borderColor: theme.palette.divider,
|
|
||||||
my: 0.5,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
),
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTree = (items: ITreeItem[], pl = 2.5, depth = 1) => {
|
const renderTree = (items: ITreeItem[], pl = 2.5, depth = 1) => {
|
||||||
const sortedItems = [...items].sort(
|
const sortedItems = [...items].sort(
|
||||||
(a, b) => (a.order ?? 0) - (b.order ?? 0),
|
(a, b) => (a.order ?? 0) - (b.order ?? 0),
|
||||||
|
|
@ -278,7 +210,72 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
MD
|
MD
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{item.type === 1 && renderAdd(item.id)}
|
{item.type === 1 && (
|
||||||
|
<Box sx={{ flexShrink: 0 }} onClick={e => e.stopPropagation()}>
|
||||||
|
<Cascader
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'left',
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'left',
|
||||||
|
}}
|
||||||
|
context={
|
||||||
|
<IconButton>
|
||||||
|
<Icon
|
||||||
|
className='catalog-folder-add-icon'
|
||||||
|
type='icon-icon_tool_close'
|
||||||
|
sx={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: 'action.selected',
|
||||||
|
transform: 'rotate(45deg)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
}
|
||||||
|
list={Object.entries(ImportContentWays).map(([key, value]) => ({
|
||||||
|
key,
|
||||||
|
label: (
|
||||||
|
<Box key={key}>
|
||||||
|
<Stack
|
||||||
|
direction={'row'}
|
||||||
|
alignItems={'center'}
|
||||||
|
gap={1}
|
||||||
|
sx={{
|
||||||
|
fontSize: 14,
|
||||||
|
px: 2,
|
||||||
|
lineHeight: '40px',
|
||||||
|
height: 40,
|
||||||
|
width: 180,
|
||||||
|
borderRadius: '5px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
':hover': {
|
||||||
|
bgcolor: addOpacityToColor(
|
||||||
|
theme.palette.primary.main,
|
||||||
|
0.1,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onClick={() => value.onClick(item.id)}
|
||||||
|
>
|
||||||
|
{value.label}
|
||||||
|
</Stack>
|
||||||
|
{key === 'OfflineFile' && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
borderTop: '1px solid',
|
||||||
|
borderColor: theme.palette.divider,
|
||||||
|
my: 0.5,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
{item.children &&
|
{item.children &&
|
||||||
item.children.length > 0 &&
|
item.children.length > 0 &&
|
||||||
|
|
@ -344,12 +341,6 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack
|
|
||||||
direction={'row'}
|
|
||||||
alignItems={'center'}
|
|
||||||
justifyContent={'space-between'}
|
|
||||||
sx={{ pr: 1 }}
|
|
||||||
>
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
px: 2,
|
px: 2,
|
||||||
|
|
@ -360,8 +351,6 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
>
|
>
|
||||||
目录
|
目录
|
||||||
</Box>
|
</Box>
|
||||||
{renderAdd('')}
|
|
||||||
</Stack>
|
|
||||||
<Stack
|
<Stack
|
||||||
sx={{
|
sx={{
|
||||||
my: 1,
|
my: 1,
|
||||||
|
|
@ -379,13 +368,11 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
open={customDocOpen}
|
open={customDocOpen}
|
||||||
parentId={opraParentId}
|
parentId={opraParentId}
|
||||||
onCreated={node => {
|
onCreated={node => {
|
||||||
if (opraParentId) {
|
|
||||||
// 复用工具方法:findItemDeep / setProperty
|
// 复用工具方法:findItemDeep / setProperty
|
||||||
setData(prev => {
|
setData(prev => {
|
||||||
const parent = findItemDeep(prev, opraParentId);
|
const parent = findItemDeep(prev, opraParentId);
|
||||||
if (!parent) return prev;
|
if (!parent) return prev;
|
||||||
const children =
|
const children = (parent.children as ITreeItem[] | undefined) ?? [];
|
||||||
(parent.children as ITreeItem[] | undefined) ?? [];
|
|
||||||
const lastOrder = children.length
|
const lastOrder = children.length
|
||||||
? (children[children.length - 1].order ?? children.length - 1)
|
? (children[children.length - 1].order ?? children.length - 1)
|
||||||
: -1;
|
: -1;
|
||||||
|
|
@ -413,25 +400,6 @@ const Catalog = ({ curNode, setCatalogOpen }: CatalogProps) => {
|
||||||
if (opraParentId) ns.add(opraParentId);
|
if (opraParentId) ns.add(opraParentId);
|
||||||
return ns;
|
return ns;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
const newChild: ITreeItem = {
|
|
||||||
id: node.id,
|
|
||||||
name: node.name,
|
|
||||||
content_type: node.content_type,
|
|
||||||
type: node.type,
|
|
||||||
emoji: node.emoji,
|
|
||||||
parentId: '',
|
|
||||||
level: 1,
|
|
||||||
order: data.length
|
|
||||||
? (data[data.length - 1].order ?? data.length - 1)
|
|
||||||
: -1,
|
|
||||||
status: 1,
|
|
||||||
children: node.type === 1 ? [] : undefined,
|
|
||||||
};
|
|
||||||
setData(prev => {
|
|
||||||
return [...prev, newChild];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
onClose={() => setCustomDocOpen(false)}
|
onClose={() => setCustomDocOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {
|
import { Editor, UseTiptapReturn } from '@ctzhian/tiptap';
|
||||||
EditorMarkdown,
|
import { alpha, Box, Divider, Stack, useTheme } from '@mui/material';
|
||||||
MarkdownEditorRef,
|
import { useState } from 'react';
|
||||||
UseTiptapReturn,
|
import AceEditor from 'react-ace';
|
||||||
} from '@ctzhian/tiptap';
|
|
||||||
import { Box } from '@mui/material';
|
import 'ace-builds/src-noconflict/ext-language_tools';
|
||||||
import { forwardRef } from 'react';
|
import 'ace-builds/src-noconflict/mode-markdown';
|
||||||
|
import 'ace-builds/src-noconflict/theme-github';
|
||||||
|
|
||||||
interface MarkdownEditorProps {
|
interface MarkdownEditorProps {
|
||||||
editor: UseTiptapReturn['editor'];
|
editor: UseTiptapReturn['editor'];
|
||||||
|
|
@ -13,8 +14,17 @@ interface MarkdownEditorProps {
|
||||||
header: React.ReactNode;
|
header: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>(
|
const MarkdownEditor = ({
|
||||||
({ editor, value, onChange, header }, ref) => {
|
editor,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
header,
|
||||||
|
}: MarkdownEditorProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [displayMode, setDisplayMode] = useState<'edit' | 'preview' | 'split'>(
|
||||||
|
'split',
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -25,17 +35,111 @@ const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>(
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{}}>{header}</Box>
|
<Box sx={{}}>{header}</Box>
|
||||||
<EditorMarkdown
|
<Stack
|
||||||
editor={editor}
|
direction={'row'}
|
||||||
|
alignItems={'stretch'}
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
flex: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
direction='row'
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
p: 0.5,
|
||||||
|
top: -32,
|
||||||
|
left: -1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
borderBottom: 'none',
|
||||||
|
borderRadius: '4px 4px 0 0',
|
||||||
|
fontSize: 12,
|
||||||
|
color: 'text.tertiary',
|
||||||
|
'.md-display-mode-active': {
|
||||||
|
color: 'primary.main',
|
||||||
|
bgcolor: alpha(theme.palette.primary.main, 0.1),
|
||||||
|
},
|
||||||
|
'& :hover:not(.md-display-mode-active)': {
|
||||||
|
borderRadius: '4px',
|
||||||
|
bgcolor: 'background.paper3',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
className={displayMode === 'split' ? 'md-display-mode-active' : ''}
|
||||||
|
sx={{ px: 1, py: 0.25, cursor: 'pointer', borderRadius: '4px' }}
|
||||||
|
onClick={() => setDisplayMode('split')}
|
||||||
|
>
|
||||||
|
分屏模式
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
className={displayMode === 'edit' ? 'md-display-mode-active' : ''}
|
||||||
|
sx={{ px: 1, py: 0.25, cursor: 'pointer', borderRadius: '4px' }}
|
||||||
|
onClick={() => setDisplayMode('edit')}
|
||||||
|
>
|
||||||
|
编辑模式
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
className={
|
||||||
|
displayMode === 'preview' ? 'md-display-mode-active' : ''
|
||||||
|
}
|
||||||
|
sx={{ px: 1, py: 0.25, cursor: 'pointer', borderRadius: '4px' }}
|
||||||
|
onClick={() => setDisplayMode('preview')}
|
||||||
|
>
|
||||||
|
预览模式
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
{['edit', 'split'].includes(displayMode) && (
|
||||||
|
<Stack
|
||||||
|
direction='column'
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AceEditor
|
||||||
|
mode='markdown'
|
||||||
|
theme='twilight'
|
||||||
value={value}
|
value={value}
|
||||||
onAceChange={onChange}
|
onChange={onChange}
|
||||||
height='calc(100vh - 340px)'
|
name='project-doc-editor'
|
||||||
|
wrapEnabled={true}
|
||||||
|
showPrintMargin={false}
|
||||||
|
fontSize={16}
|
||||||
|
editorProps={{ $blockScrolling: true }}
|
||||||
|
setOptions={{
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableLiveAutocompletion: true,
|
||||||
|
showLineNumbers: true,
|
||||||
|
tabSize: 2,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: 'calc(100vh - 56px)',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
{displayMode === 'split' && <Divider orientation='vertical' flexItem />}
|
||||||
|
{['split', 'preview'].includes(displayMode) && (
|
||||||
|
<Box
|
||||||
|
id='markdown-preview-container'
|
||||||
|
sx={{
|
||||||
|
overflowY: 'scroll',
|
||||||
|
flex: 1,
|
||||||
|
p: 2,
|
||||||
|
height: 'calc(100vh - 56px)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Editor editor={editor} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
);
|
|
||||||
|
|
||||||
MarkdownEditor.displayName = 'MarkdownEditor';
|
|
||||||
|
|
||||||
export default MarkdownEditor;
|
export default MarkdownEditor;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ interface TocProps {
|
||||||
setFixed: (fixed: boolean) => void;
|
setFixed: (fixed: boolean) => void;
|
||||||
setShowSummary: (showSummary: boolean) => void;
|
setShowSummary: (showSummary: boolean) => void;
|
||||||
isMarkdown: boolean;
|
isMarkdown: boolean;
|
||||||
scrollToHeading?: (headingText: string) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeadingIcon = [
|
const HeadingIcon = [
|
||||||
|
|
@ -35,13 +34,7 @@ const HeadingSx = [
|
||||||
{ fontSize: 14, fontWeight: 400, color: 'text.disabled' },
|
{ fontSize: 14, fontWeight: 400, color: 'text.disabled' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const Toc = ({
|
const Toc = ({ headings, fixed, setFixed, isMarkdown }: TocProps) => {
|
||||||
headings,
|
|
||||||
fixed,
|
|
||||||
setFixed,
|
|
||||||
isMarkdown,
|
|
||||||
scrollToHeading,
|
|
||||||
}: TocProps) => {
|
|
||||||
const storageTocOpen = localStorage.getItem('toc-open');
|
const storageTocOpen = localStorage.getItem('toc-open');
|
||||||
const [open, setOpen] = useState(!!storageTocOpen);
|
const [open, setOpen] = useState(!!storageTocOpen);
|
||||||
const levels = Array.from(
|
const levels = Array.from(
|
||||||
|
|
@ -198,10 +191,6 @@ const Toc = ({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 同时滚动 AceEditor
|
|
||||||
if (scrollToHeading) {
|
|
||||||
scrollToHeading(it.textContent);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 在富文本编辑器模式下,滚动整个窗口
|
// 在富文本编辑器模式下,滚动整个窗口
|
||||||
const offset = 100;
|
const offset = 100;
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,7 @@ import Emoji from '@/components/Emoji';
|
||||||
import { postApiV1CreationTabComplete, putApiV1NodeDetail } from '@/request';
|
import { postApiV1CreationTabComplete, putApiV1NodeDetail } from '@/request';
|
||||||
import { V1NodeDetailResp } from '@/request/types';
|
import { V1NodeDetailResp } from '@/request/types';
|
||||||
import { useAppSelector } from '@/store';
|
import { useAppSelector } from '@/store';
|
||||||
import {
|
import { TocList, useTiptap, UseTiptapReturn } from '@ctzhian/tiptap';
|
||||||
EditorMarkdown,
|
|
||||||
MarkdownEditorRef,
|
|
||||||
TocList,
|
|
||||||
useTiptap,
|
|
||||||
UseTiptapReturn,
|
|
||||||
} from '@ctzhian/tiptap';
|
|
||||||
import { Icon, message } from '@ctzhian/ui';
|
import { Icon, message } from '@ctzhian/ui';
|
||||||
import { Box, Stack, TextField, Tooltip } from '@mui/material';
|
import { Box, Stack, TextField, Tooltip } from '@mui/material';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
@ -25,6 +19,7 @@ import { WrapContext } from '..';
|
||||||
import AIGenerate from './AIGenerate';
|
import AIGenerate from './AIGenerate';
|
||||||
import FullTextEditor from './FullTextEditor';
|
import FullTextEditor from './FullTextEditor';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
|
import MarkdownEditor from './MarkdownEditor';
|
||||||
import Summary from './Summary';
|
import Summary from './Summary';
|
||||||
import Toc from './Toc';
|
import Toc from './Toc';
|
||||||
import Toolbar from './Toolbar';
|
import Toolbar from './Toolbar';
|
||||||
|
|
@ -48,8 +43,6 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const markdownEditorRef = useRef<MarkdownEditorRef>(null);
|
|
||||||
|
|
||||||
const isMarkdown = useMemo(() => {
|
const isMarkdown = useMemo(() => {
|
||||||
return defaultDetail.meta?.content_type === 'md';
|
return defaultDetail.meta?.content_type === 'md';
|
||||||
}, [defaultDetail.meta?.content_type]);
|
}, [defaultDetail.meta?.content_type]);
|
||||||
|
|
@ -192,7 +185,7 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
|
||||||
editable: !isMarkdown,
|
editable: !isMarkdown,
|
||||||
contentType: isMarkdown ? 'markdown' : 'html',
|
contentType: isMarkdown ? 'markdown' : 'html',
|
||||||
immediatelyRender: true,
|
immediatelyRender: true,
|
||||||
content: defaultDetail.content,
|
content: defaultDetail.content || '',
|
||||||
exclude: ['invisibleCharacters', 'youtube', 'mention'],
|
exclude: ['invisibleCharacters', 'youtube', 'mention'],
|
||||||
onCreate: ({ editor: tiptapEditor }) => {
|
onCreate: ({ editor: tiptapEditor }) => {
|
||||||
const characterCount = (
|
const characterCount = (
|
||||||
|
|
@ -591,27 +584,17 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ ...(fixedToc && { display: 'flex' }) }}>
|
<Box sx={{ ...(fixedToc && { display: 'flex' }) }}>
|
||||||
{isMarkdown ? (
|
{isMarkdown ? (
|
||||||
<Box
|
<MarkdownEditor
|
||||||
sx={{
|
|
||||||
mt: '56px',
|
|
||||||
px: 10,
|
|
||||||
pt: 4,
|
|
||||||
flex: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box sx={{}}>{renderEditorTitleEmojiSummary()}</Box>
|
|
||||||
<EditorMarkdown
|
|
||||||
ref={markdownEditorRef}
|
|
||||||
editor={editorRef.editor}
|
editor={editorRef.editor}
|
||||||
value={nodeDetail?.content || ''}
|
value={nodeDetail?.content || ''}
|
||||||
onAceChange={value => {
|
onChange={value => {
|
||||||
updateDetail({
|
updateDetail({
|
||||||
content: value,
|
content: value,
|
||||||
});
|
});
|
||||||
|
editorRef.setContent(value);
|
||||||
}}
|
}}
|
||||||
height='calc(100vh - 340px)'
|
header={renderEditorTitleEmojiSummary()}
|
||||||
/>
|
/>
|
||||||
</Box>
|
|
||||||
) : (
|
) : (
|
||||||
<FullTextEditor
|
<FullTextEditor
|
||||||
editor={editorRef.editor}
|
editor={editorRef.editor}
|
||||||
|
|
@ -626,12 +609,6 @@ const Wrap = ({ detail: defaultDetail }: WrapProps) => {
|
||||||
isMarkdown={isMarkdown}
|
isMarkdown={isMarkdown}
|
||||||
setFixed={setFixedToc}
|
setFixed={setFixedToc}
|
||||||
setShowSummary={setShowSummary}
|
setShowSummary={setShowSummary}
|
||||||
scrollToHeading={
|
|
||||||
isMarkdown
|
|
||||||
? headingText =>
|
|
||||||
markdownEditorRef.current?.scrollToHeading(headingText)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<AIGenerate
|
<AIGenerate
|
||||||
open={aiGenerateOpen}
|
open={aiGenerateOpen}
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,6 @@ export interface GithubComChaitinPandaWikiProApiContributeV1ContributeListResp {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GithubComChaitinPandaWikiProApiContributeV1NodeMeta {
|
export interface GithubComChaitinPandaWikiProApiContributeV1NodeMeta {
|
||||||
content_type?: string;
|
|
||||||
doc_width?: string;
|
doc_width?: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +492,6 @@ export type GithubComChaitinPandaWikiProApiShareV1OAuthCallbackResp = Record<
|
||||||
export interface GithubComChaitinPandaWikiProApiShareV1SubmitContributeReq {
|
export interface GithubComChaitinPandaWikiProApiShareV1SubmitContributeReq {
|
||||||
captcha_token: string;
|
captcha_token: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
content_type: "html" | "md";
|
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
node_id?: string;
|
node_id?: string;
|
||||||
|
|
|
||||||
|
|
@ -134,25 +134,6 @@ export enum ConstsSourceType {
|
||||||
SourceTypeOpenAIAPI = "openai_api",
|
SourceTypeOpenAIAPI = "openai_api",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ConstsNodeRagInfoStatus {
|
|
||||||
/** 等待基础处理 */
|
|
||||||
NodeRagStatusBasicPending = "BASIC_PENDING",
|
|
||||||
/** 正在进行基础处理(文本分割、向量化等) */
|
|
||||||
NodeRagStatusBasicRunning = "BASIC_RUNNING",
|
|
||||||
/** 基础处理失败 */
|
|
||||||
NodeRagStatusBasicFailed = "BASIC_FAILED",
|
|
||||||
/** 基础处理成功 */
|
|
||||||
NodeRagStatusBasicSucceeded = "BASIC_SUCCEEDED",
|
|
||||||
/** 基础处理完成,等待增强处理 */
|
|
||||||
NodeRagStatusEnhancePending = "ENHANCE_PENDING",
|
|
||||||
/** 正在进行增强处理(关键词提取等) */
|
|
||||||
NodeRagStatusEnhanceRunning = "ENHANCE_RUNNING",
|
|
||||||
/** 增强处理失败 */
|
|
||||||
NodeRagStatusEnhanceFailed = "ENHANCE_FAILED",
|
|
||||||
/** 增强处理成功 */
|
|
||||||
NodeRagStatusEnhanceSucceeded = "ENHANCE_SUCCEEDED",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ConstsNodePermName {
|
export enum ConstsNodePermName {
|
||||||
/** 导航内可见 */
|
/** 导航内可见 */
|
||||||
NodePermNameVisible = "visible",
|
NodePermNameVisible = "visible",
|
||||||
|
|
@ -493,16 +474,6 @@ export interface DomainBatchMoveReq {
|
||||||
parent_id?: string;
|
parent_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DomainBlockGridConfig {
|
|
||||||
list?: {
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
url?: string;
|
|
||||||
}[];
|
|
||||||
title?: string;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainBrandGroup {
|
export interface DomainBrandGroup {
|
||||||
links?: DomainLink[];
|
links?: DomainLink[];
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -966,7 +937,6 @@ export interface DomainNodeListItemResp {
|
||||||
parent_id?: string;
|
parent_id?: string;
|
||||||
permissions?: DomainNodePermissions;
|
permissions?: DomainNodePermissions;
|
||||||
position?: number;
|
position?: number;
|
||||||
rag_info?: DomainRagInfo;
|
|
||||||
status?: DomainNodeStatus;
|
status?: DomainNodeStatus;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
type?: DomainNodeType;
|
type?: DomainNodeType;
|
||||||
|
|
@ -1112,20 +1082,6 @@ export interface DomainProviderModelListItem {
|
||||||
model?: string;
|
model?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DomainQuestionConfig {
|
|
||||||
list?: {
|
|
||||||
id?: string;
|
|
||||||
question?: string;
|
|
||||||
}[];
|
|
||||||
title?: string;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainRagInfo {
|
|
||||||
message?: string;
|
|
||||||
status?: ConstsNodeRagInfoStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainRecommendNodeListResp {
|
export interface DomainRecommendNodeListResp {
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
@ -1285,7 +1241,6 @@ export interface DomainWebAppCustomSettings {
|
||||||
export interface DomainWebAppLandingConfig {
|
export interface DomainWebAppLandingConfig {
|
||||||
banner_config?: DomainBannerConfig;
|
banner_config?: DomainBannerConfig;
|
||||||
basic_doc_config?: DomainBasicDocConfig;
|
basic_doc_config?: DomainBasicDocConfig;
|
||||||
block_grid_config?: DomainBlockGridConfig;
|
|
||||||
carousel_config?: DomainCarouselConfig;
|
carousel_config?: DomainCarouselConfig;
|
||||||
case_config?: DomainCaseConfig;
|
case_config?: DomainCaseConfig;
|
||||||
com_config_order?: string[];
|
com_config_order?: string[];
|
||||||
|
|
@ -1296,7 +1251,6 @@ export interface DomainWebAppLandingConfig {
|
||||||
img_text_config?: DomainImgTextConfig;
|
img_text_config?: DomainImgTextConfig;
|
||||||
metrics_config?: DomainMetricsConfig;
|
metrics_config?: DomainMetricsConfig;
|
||||||
node_ids?: string[];
|
node_ids?: string[];
|
||||||
question_config?: DomainQuestionConfig;
|
|
||||||
simple_doc_config?: DomainSimpleDocConfig;
|
simple_doc_config?: DomainSimpleDocConfig;
|
||||||
text_config?: DomainTextConfig;
|
text_config?: DomainTextConfig;
|
||||||
text_img_config?: DomainTextImgConfig;
|
text_img_config?: DomainTextImgConfig;
|
||||||
|
|
@ -1306,7 +1260,6 @@ export interface DomainWebAppLandingConfig {
|
||||||
export interface DomainWebAppLandingConfigResp {
|
export interface DomainWebAppLandingConfigResp {
|
||||||
banner_config?: DomainBannerConfig;
|
banner_config?: DomainBannerConfig;
|
||||||
basic_doc_config?: DomainBasicDocConfig;
|
basic_doc_config?: DomainBasicDocConfig;
|
||||||
block_grid_config?: DomainBlockGridConfig;
|
|
||||||
carousel_config?: DomainCarouselConfig;
|
carousel_config?: DomainCarouselConfig;
|
||||||
case_config?: DomainCaseConfig;
|
case_config?: DomainCaseConfig;
|
||||||
com_config_order?: string[];
|
com_config_order?: string[];
|
||||||
|
|
@ -1318,7 +1271,6 @@ export interface DomainWebAppLandingConfigResp {
|
||||||
metrics_config?: DomainMetricsConfig;
|
metrics_config?: DomainMetricsConfig;
|
||||||
node_ids?: string[];
|
node_ids?: string[];
|
||||||
nodes?: DomainRecommendNodeListResp[];
|
nodes?: DomainRecommendNodeListResp[];
|
||||||
question_config?: DomainQuestionConfig;
|
|
||||||
simple_doc_config?: DomainSimpleDocConfig;
|
simple_doc_config?: DomainSimpleDocConfig;
|
||||||
text_config?: DomainTextConfig;
|
text_config?: DomainTextConfig;
|
||||||
text_img_config?: DomainTextImgConfig;
|
text_img_config?: DomainTextImgConfig;
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,21 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
import React, { useState } from 'react';
|
||||||
import { useStore } from '@/provider';
|
import { useStore } from '@/provider';
|
||||||
import { Modal } from '@ctzhian/ui';
|
import { Stack, Tooltip, Fab, Zoom } from '@mui/material';
|
||||||
|
import { usePathname, useParams } from 'next/navigation';
|
||||||
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
|
||||||
import {
|
|
||||||
Fab,
|
|
||||||
FormControlLabel,
|
|
||||||
Radio,
|
|
||||||
RadioGroup,
|
|
||||||
Stack,
|
|
||||||
Tooltip,
|
|
||||||
Zoom,
|
|
||||||
} from '@mui/material';
|
|
||||||
import { useParams, usePathname } from 'next/navigation';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
const DocFab = () => {
|
const DocFab = () => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const { id: docId } = useParams() || {};
|
const { id: docId } = useParams() || {};
|
||||||
const { kbDetail, mobile } = useStore();
|
const { kbDetail, mobile } = useStore();
|
||||||
const [showActions, setShowActions] = useState(false);
|
const [showActions, setShowActions] = useState(false);
|
||||||
const [contentType, setContentType] = useState<'html' | 'md'>('html');
|
|
||||||
const [openSelectContentTypeModal, setOpenSelectContentTypeModal] =
|
|
||||||
useState(false);
|
|
||||||
|
|
||||||
if (mobile) return null;
|
if (mobile) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
title='新建文档类型'
|
|
||||||
open={openSelectContentTypeModal}
|
|
||||||
onCancel={() => {
|
|
||||||
setOpenSelectContentTypeModal(false);
|
|
||||||
setContentType('html');
|
|
||||||
}}
|
|
||||||
onOk={() => {
|
|
||||||
setOpenSelectContentTypeModal(false);
|
|
||||||
window.open(`/editor?contentType=${contentType}`, '_blank');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<RadioGroup
|
|
||||||
value={contentType}
|
|
||||||
onChange={e => setContentType(e.target.value as 'html' | 'md')}
|
|
||||||
>
|
|
||||||
<FormControlLabel
|
|
||||||
value='html'
|
|
||||||
control={<Radio size='small' />}
|
|
||||||
label='富文本'
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
value='md'
|
|
||||||
control={<Radio size='small' />}
|
|
||||||
label='Markdown'
|
|
||||||
/>
|
|
||||||
</RadioGroup>
|
|
||||||
</Modal>
|
|
||||||
<Stack
|
<Stack
|
||||||
gap={1}
|
gap={1}
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -78,7 +37,7 @@ const DocFab = () => {
|
||||||
color='primary'
|
color='primary'
|
||||||
size='small'
|
size='small'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenSelectContentTypeModal(true);
|
window.open(`/editor`, '_blank');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
|
|
@ -122,7 +81,6 @@ const DocFab = () => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,6 @@ export interface GithubComChaitinPandaWikiProApiContributeV1ContributeListResp {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GithubComChaitinPandaWikiProApiContributeV1NodeMeta {
|
export interface GithubComChaitinPandaWikiProApiContributeV1NodeMeta {
|
||||||
content_type?: string;
|
|
||||||
doc_width?: string;
|
doc_width?: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +492,6 @@ export type GithubComChaitinPandaWikiProApiShareV1OAuthCallbackResp = Record<
|
||||||
export interface GithubComChaitinPandaWikiProApiShareV1SubmitContributeReq {
|
export interface GithubComChaitinPandaWikiProApiShareV1SubmitContributeReq {
|
||||||
captcha_token: string;
|
captcha_token: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
content_type: "html" | "md";
|
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
node_id?: string;
|
node_id?: string;
|
||||||
|
|
|
||||||
|
|
@ -134,25 +134,6 @@ export enum ConstsSourceType {
|
||||||
SourceTypeOpenAIAPI = "openai_api",
|
SourceTypeOpenAIAPI = "openai_api",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ConstsNodeRagInfoStatus {
|
|
||||||
/** 等待基础处理 */
|
|
||||||
NodeRagStatusBasicPending = "BASIC_PENDING",
|
|
||||||
/** 正在进行基础处理(文本分割、向量化等) */
|
|
||||||
NodeRagStatusBasicRunning = "BASIC_RUNNING",
|
|
||||||
/** 基础处理失败 */
|
|
||||||
NodeRagStatusBasicFailed = "BASIC_FAILED",
|
|
||||||
/** 基础处理成功 */
|
|
||||||
NodeRagStatusBasicSucceeded = "BASIC_SUCCEEDED",
|
|
||||||
/** 基础处理完成,等待增强处理 */
|
|
||||||
NodeRagStatusEnhancePending = "ENHANCE_PENDING",
|
|
||||||
/** 正在进行增强处理(关键词提取等) */
|
|
||||||
NodeRagStatusEnhanceRunning = "ENHANCE_RUNNING",
|
|
||||||
/** 增强处理失败 */
|
|
||||||
NodeRagStatusEnhanceFailed = "ENHANCE_FAILED",
|
|
||||||
/** 增强处理成功 */
|
|
||||||
NodeRagStatusEnhanceSucceeded = "ENHANCE_SUCCEEDED",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ConstsNodePermName {
|
export enum ConstsNodePermName {
|
||||||
/** 导航内可见 */
|
/** 导航内可见 */
|
||||||
NodePermNameVisible = "visible",
|
NodePermNameVisible = "visible",
|
||||||
|
|
@ -493,16 +474,6 @@ export interface DomainBatchMoveReq {
|
||||||
parent_id?: string;
|
parent_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DomainBlockGridConfig {
|
|
||||||
list?: {
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
url?: string;
|
|
||||||
}[];
|
|
||||||
title?: string;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainBrandGroup {
|
export interface DomainBrandGroup {
|
||||||
links?: DomainLink[];
|
links?: DomainLink[];
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -966,7 +937,6 @@ export interface DomainNodeListItemResp {
|
||||||
parent_id?: string;
|
parent_id?: string;
|
||||||
permissions?: DomainNodePermissions;
|
permissions?: DomainNodePermissions;
|
||||||
position?: number;
|
position?: number;
|
||||||
rag_info?: DomainRagInfo;
|
|
||||||
status?: DomainNodeStatus;
|
status?: DomainNodeStatus;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
type?: DomainNodeType;
|
type?: DomainNodeType;
|
||||||
|
|
@ -1112,20 +1082,6 @@ export interface DomainProviderModelListItem {
|
||||||
model?: string;
|
model?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DomainQuestionConfig {
|
|
||||||
list?: {
|
|
||||||
id?: string;
|
|
||||||
question?: string;
|
|
||||||
}[];
|
|
||||||
title?: string;
|
|
||||||
type?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainRagInfo {
|
|
||||||
message?: string;
|
|
||||||
status?: ConstsNodeRagInfoStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainRecommendNodeListResp {
|
export interface DomainRecommendNodeListResp {
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
@ -1285,7 +1241,6 @@ export interface DomainWebAppCustomSettings {
|
||||||
export interface DomainWebAppLandingConfig {
|
export interface DomainWebAppLandingConfig {
|
||||||
banner_config?: DomainBannerConfig;
|
banner_config?: DomainBannerConfig;
|
||||||
basic_doc_config?: DomainBasicDocConfig;
|
basic_doc_config?: DomainBasicDocConfig;
|
||||||
block_grid_config?: DomainBlockGridConfig;
|
|
||||||
carousel_config?: DomainCarouselConfig;
|
carousel_config?: DomainCarouselConfig;
|
||||||
case_config?: DomainCaseConfig;
|
case_config?: DomainCaseConfig;
|
||||||
com_config_order?: string[];
|
com_config_order?: string[];
|
||||||
|
|
@ -1296,7 +1251,6 @@ export interface DomainWebAppLandingConfig {
|
||||||
img_text_config?: DomainImgTextConfig;
|
img_text_config?: DomainImgTextConfig;
|
||||||
metrics_config?: DomainMetricsConfig;
|
metrics_config?: DomainMetricsConfig;
|
||||||
node_ids?: string[];
|
node_ids?: string[];
|
||||||
question_config?: DomainQuestionConfig;
|
|
||||||
simple_doc_config?: DomainSimpleDocConfig;
|
simple_doc_config?: DomainSimpleDocConfig;
|
||||||
text_config?: DomainTextConfig;
|
text_config?: DomainTextConfig;
|
||||||
text_img_config?: DomainTextImgConfig;
|
text_img_config?: DomainTextImgConfig;
|
||||||
|
|
@ -1306,7 +1260,6 @@ export interface DomainWebAppLandingConfig {
|
||||||
export interface DomainWebAppLandingConfigResp {
|
export interface DomainWebAppLandingConfigResp {
|
||||||
banner_config?: DomainBannerConfig;
|
banner_config?: DomainBannerConfig;
|
||||||
basic_doc_config?: DomainBasicDocConfig;
|
basic_doc_config?: DomainBasicDocConfig;
|
||||||
block_grid_config?: DomainBlockGridConfig;
|
|
||||||
carousel_config?: DomainCarouselConfig;
|
carousel_config?: DomainCarouselConfig;
|
||||||
case_config?: DomainCaseConfig;
|
case_config?: DomainCaseConfig;
|
||||||
com_config_order?: string[];
|
com_config_order?: string[];
|
||||||
|
|
@ -1318,7 +1271,6 @@ export interface DomainWebAppLandingConfigResp {
|
||||||
metrics_config?: DomainMetricsConfig;
|
metrics_config?: DomainMetricsConfig;
|
||||||
node_ids?: string[];
|
node_ids?: string[];
|
||||||
nodes?: DomainRecommendNodeListResp[];
|
nodes?: DomainRecommendNodeListResp[];
|
||||||
question_config?: DomainQuestionConfig;
|
|
||||||
simple_doc_config?: DomainSimpleDocConfig;
|
simple_doc_config?: DomainSimpleDocConfig;
|
||||||
text_config?: DomainTextConfig;
|
text_config?: DomainTextConfig;
|
||||||
text_img_config?: DomainTextImgConfig;
|
text_img_config?: DomainTextImgConfig;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Box, Drawer, IconButton, Stack } from '@mui/material';
|
||||||
import {
|
import {
|
||||||
H1Icon,
|
H1Icon,
|
||||||
H2Icon,
|
H2Icon,
|
||||||
|
|
@ -8,15 +9,12 @@ import {
|
||||||
TocList,
|
TocList,
|
||||||
} from '@ctzhian/tiptap';
|
} from '@ctzhian/tiptap';
|
||||||
import { Ellipsis, Icon } from '@ctzhian/ui';
|
import { Ellipsis, Icon } from '@ctzhian/ui';
|
||||||
import { Box, Drawer, IconButton, Stack } from '@mui/material';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
interface TocProps {
|
interface TocProps {
|
||||||
headings: TocList;
|
headings: TocList;
|
||||||
fixed: boolean;
|
fixed: boolean;
|
||||||
setFixed: (fixed: boolean) => void;
|
setFixed: (fixed: boolean) => void;
|
||||||
isMarkdown: boolean;
|
|
||||||
scrollToHeading?: (headingText: string) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeadingIcon = [
|
const HeadingIcon = [
|
||||||
|
|
@ -34,13 +32,7 @@ const HeadingSx = [
|
||||||
{ fontSize: 14, fontWeight: 400, color: 'text.disabled' },
|
{ fontSize: 14, fontWeight: 400, color: 'text.disabled' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const Toc = ({
|
const Toc = ({ headings, fixed, setFixed }: TocProps) => {
|
||||||
headings,
|
|
||||||
fixed,
|
|
||||||
setFixed,
|
|
||||||
scrollToHeading,
|
|
||||||
isMarkdown,
|
|
||||||
}: TocProps) => {
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const levels = Array.from(
|
const levels = Array.from(
|
||||||
new Set(headings.map(it => it.level).sort((a, b) => a - b)),
|
new Set(headings.map(it => it.level).sort((a, b) => a - b)),
|
||||||
|
|
@ -172,30 +164,6 @@ const Toc = ({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const element = document.getElementById(it.id);
|
const element = document.getElementById(it.id);
|
||||||
if (element) {
|
if (element) {
|
||||||
if (isMarkdown) {
|
|
||||||
const container = document.getElementById(
|
|
||||||
'markdown-preview-container',
|
|
||||||
);
|
|
||||||
if (container) {
|
|
||||||
const containerRect =
|
|
||||||
container.getBoundingClientRect();
|
|
||||||
const elementRect = element.getBoundingClientRect();
|
|
||||||
const offset = 20; // 顶部偏移
|
|
||||||
const scrollTop =
|
|
||||||
container.scrollTop +
|
|
||||||
elementRect.top -
|
|
||||||
containerRect.top -
|
|
||||||
offset;
|
|
||||||
container.scrollTo({
|
|
||||||
top: scrollTop,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 同时滚动 AceEditor
|
|
||||||
if (scrollToHeading) {
|
|
||||||
scrollToHeading(it.textContent);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const offset = 100;
|
const offset = 100;
|
||||||
const elementPosition =
|
const elementPosition =
|
||||||
element.getBoundingClientRect().top;
|
element.getBoundingClientRect().top;
|
||||||
|
|
@ -206,7 +174,6 @@ const Toc = ({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,13 @@
|
||||||
import Emoji from '@/components/emoji';
|
import Emoji from '@/components/emoji';
|
||||||
import { postShareProV1FileUploadWithProgress } from '@/request/pro/otherCustomer';
|
import { postShareProV1FileUploadWithProgress } from '@/request/pro/otherCustomer';
|
||||||
import { V1NodeDetailResp } from '@/request/types';
|
import { V1NodeDetailResp } from '@/request/types';
|
||||||
import {
|
import { Editor, TocList, useTiptap, UseTiptapReturn } from '@ctzhian/tiptap';
|
||||||
Editor,
|
|
||||||
EditorMarkdown,
|
|
||||||
MarkdownEditorRef,
|
|
||||||
TocList,
|
|
||||||
useTiptap,
|
|
||||||
UseTiptapReturn,
|
|
||||||
} from '@ctzhian/tiptap';
|
|
||||||
import { message } from '@ctzhian/ui';
|
import { message } from '@ctzhian/ui';
|
||||||
import { Box, Stack, TextField } from '@mui/material';
|
import { Box, Stack, TextField } from '@mui/material';
|
||||||
import { IconAShijian2, IconZiti } from '@panda-wiki/icons';
|
import { IconAShijian2, IconZiti } from '@panda-wiki/icons';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useParams, useSearchParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useWrapContext } from '..';
|
import { useWrapContext } from '..';
|
||||||
import AIGenerate from './AIGenerate';
|
import AIGenerate from './AIGenerate';
|
||||||
import ConfirmModal from './ConfirmModal';
|
import ConfirmModal from './ConfirmModal';
|
||||||
|
|
@ -28,12 +21,9 @@ interface WrapProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
const searchParams = useSearchParams();
|
const { catalogOpen, nodeDetail, setNodeDetail, onSave } = useWrapContext();
|
||||||
const contentType = searchParams.get('contentType') || 'html';
|
|
||||||
const { nodeDetail, setNodeDetail, onSave } = useWrapContext();
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
const markdownEditorRef = useRef<MarkdownEditorRef>(null);
|
|
||||||
const [characterCount, setCharacterCount] = useState(0);
|
const [characterCount, setCharacterCount] = useState(0);
|
||||||
const [headings, setHeadings] = useState<TocList>([]);
|
const [headings, setHeadings] = useState<TocList>([]);
|
||||||
const [fixedToc, setFixedToc] = useState(false);
|
const [fixedToc, setFixedToc] = useState(false);
|
||||||
|
|
@ -41,14 +31,6 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
const [aiGenerateOpen, setAiGenerateOpen] = useState(false);
|
const [aiGenerateOpen, setAiGenerateOpen] = useState(false);
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [confirmModalOpen, setConfirmModalOpen] = useState(false);
|
const [confirmModalOpen, setConfirmModalOpen] = useState(false);
|
||||||
|
|
||||||
const isMarkdown = useMemo(() => {
|
|
||||||
if (!id && contentType === 'md') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return defaultDetail.meta?.content_type === 'md';
|
|
||||||
}, [defaultDetail.meta?.content_type, contentType]);
|
|
||||||
|
|
||||||
const updateDetail = (value: V1NodeDetailResp) => {
|
const updateDetail = (value: V1NodeDetailResp) => {
|
||||||
setNodeDetail({
|
setNodeDetail({
|
||||||
...nodeDetail,
|
...nodeDetail,
|
||||||
|
|
@ -91,9 +73,8 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const editorRef = useTiptap({
|
const editorRef = useTiptap({
|
||||||
|
editable: true,
|
||||||
immediatelyRender: false,
|
immediatelyRender: false,
|
||||||
editable: !isMarkdown,
|
|
||||||
contentType: isMarkdown ? 'markdown' : 'html',
|
|
||||||
content: defaultDetail?.content || '',
|
content: defaultDetail?.content || '',
|
||||||
exclude: ['invisibleCharacters', 'youtube', 'mention'],
|
exclude: ['invisibleCharacters', 'youtube', 'mention'],
|
||||||
onCreate: ({ editor: tiptapEditor }) => {
|
onCreate: ({ editor: tiptapEditor }) => {
|
||||||
|
|
@ -125,33 +106,17 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (editorRef && editorRef.editor) {
|
if (editorRef && editorRef.editor) {
|
||||||
const value = editorRef.getContent();
|
const html = editorRef.getHTML();
|
||||||
updateDetail({
|
updateDetail({
|
||||||
content: value,
|
content: html,
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
|
||||||
if (checkRequiredFields()) {
|
|
||||||
setConfirmModalOpen(true);
|
setConfirmModalOpen(true);
|
||||||
}
|
}
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[editorRef],
|
[editorRef, onSave],
|
||||||
);
|
);
|
||||||
|
|
||||||
const checkRequiredFields = useCallback(() => {
|
|
||||||
if (!nodeDetail?.name?.trim()) {
|
|
||||||
message.error('请先输入文档名称');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!nodeDetail?.content?.trim()) {
|
|
||||||
message.error('请先输入文档内容');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}, [nodeDetail]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('keydown', handleGlobalSave);
|
document.addEventListener('keydown', handleGlobalSave);
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -183,14 +148,10 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
detail={nodeDetail!}
|
detail={nodeDetail!}
|
||||||
updateDetail={updateDetail}
|
updateDetail={updateDetail}
|
||||||
handleSave={async () => {
|
handleSave={async () => {
|
||||||
if (checkRequiredFields()) {
|
|
||||||
setConfirmModalOpen(true);
|
setConfirmModalOpen(true);
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{!isMarkdown && (
|
|
||||||
<Toolbar editorRef={editorRef} handleAiGenerate={handleAiGenerate} />
|
<Toolbar editorRef={editorRef} handleAiGenerate={handleAiGenerate} />
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -202,8 +163,8 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: `calc(100vw - 160px - ${fixedToc ? 292 : 0}px)`,
|
width: `calc(100vw - 160px - ${fixedToc ? 292 : 0}px)`,
|
||||||
p: isMarkdown ? '72px 80px' : '72px 80px 150px',
|
p: '72px 80px 150px',
|
||||||
mt: isMarkdown ? '56px' : '102px',
|
mt: '102px',
|
||||||
mx: 'auto',
|
mx: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -292,21 +253,7 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
{characterCount} 字
|
{characterCount} 字
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
{editorRef.editor && (
|
|
||||||
<Box sx={{ ...(fixedToc && { display: 'flex' }) }}>
|
|
||||||
{isMarkdown ? (
|
|
||||||
<EditorMarkdown
|
|
||||||
ref={markdownEditorRef}
|
|
||||||
editor={editorRef.editor}
|
|
||||||
value={nodeDetail?.content || defaultDetail?.content || ''}
|
|
||||||
onAceChange={value => {
|
|
||||||
updateDetail({
|
|
||||||
content: value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
height='calc(100vh - 340px)'
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
wordBreak: 'break-all',
|
wordBreak: 'break-all',
|
||||||
|
|
@ -320,24 +267,10 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Editor editor={editorRef.editor} />
|
{editorRef.editor && <Editor editor={editorRef.editor} />}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
<Toc headings={headings} fixed={fixedToc} setFixed={setFixedToc} />
|
||||||
</Box>
|
|
||||||
<Toc
|
|
||||||
headings={headings}
|
|
||||||
fixed={fixedToc}
|
|
||||||
setFixed={setFixedToc}
|
|
||||||
isMarkdown={isMarkdown}
|
|
||||||
scrollToHeading={
|
|
||||||
isMarkdown
|
|
||||||
? headingText =>
|
|
||||||
markdownEditorRef.current?.scrollToHeading(headingText)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<AIGenerate
|
<AIGenerate
|
||||||
|
|
@ -351,11 +284,11 @@ const Wrap = ({ detail: defaultDetail = {} }: WrapProps) => {
|
||||||
open={confirmModalOpen}
|
open={confirmModalOpen}
|
||||||
onCancel={() => setConfirmModalOpen(false)}
|
onCancel={() => setConfirmModalOpen(false)}
|
||||||
onOk={async (reason: string, token: string) => {
|
onOk={async (reason: string, token: string) => {
|
||||||
const value = editorRef.getContent();
|
const value = editorRef.getHTML();
|
||||||
updateDetail({
|
updateDetail({
|
||||||
content: value,
|
content: value,
|
||||||
});
|
});
|
||||||
await onSave(value, reason, token, isMarkdown ? 'md' : 'html');
|
await onSave(value, reason, token);
|
||||||
setConfirmModalOpen(false);
|
setConfirmModalOpen(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
import { postShareProV1ContributeSubmit } from '@/request/pro/ShareContribute';
|
import { postShareProV1ContributeSubmit } from '@/request/pro/ShareContribute';
|
||||||
import { V1NodeDetailResp } from '@/request/types';
|
import { V1NodeDetailResp } from '@/request/types';
|
||||||
import { message } from '@ctzhian/ui';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { Box, Stack, useMediaQuery } from '@mui/material';
|
import { Box, Stack, useMediaQuery } from '@mui/material';
|
||||||
import { useParams } from 'next/navigation';
|
import { message } from '@ctzhian/ui';
|
||||||
import { createContext, useContext, useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import Edit from './edit';
|
import Edit from './edit';
|
||||||
|
|
||||||
export interface WrapContext {
|
export interface WrapContext {
|
||||||
|
|
@ -12,12 +13,7 @@ export interface WrapContext {
|
||||||
setCatalogOpen: (open: boolean) => void;
|
setCatalogOpen: (open: boolean) => void;
|
||||||
nodeDetail: V1NodeDetailResp | null;
|
nodeDetail: V1NodeDetailResp | null;
|
||||||
setNodeDetail: (detail: V1NodeDetailResp) => void;
|
setNodeDetail: (detail: V1NodeDetailResp) => void;
|
||||||
onSave: (
|
onSave: (content: string, reason: string, token: string) => void;
|
||||||
content: string,
|
|
||||||
reason: string,
|
|
||||||
token: string,
|
|
||||||
contentType?: 'html' | 'md',
|
|
||||||
) => void;
|
|
||||||
saveLoading: boolean;
|
saveLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,12 +41,7 @@ const DocEditor = () => {
|
||||||
);
|
);
|
||||||
const [catalogOpen, setCatalogOpen] = useState(true);
|
const [catalogOpen, setCatalogOpen] = useState(true);
|
||||||
|
|
||||||
const onSave = (
|
const onSave = (content: string, reason: string, token: string) => {
|
||||||
content: string,
|
|
||||||
reason: string,
|
|
||||||
token: string,
|
|
||||||
contentType?: 'html' | 'md',
|
|
||||||
) => {
|
|
||||||
setSaveLoading(true);
|
setSaveLoading(true);
|
||||||
return postShareProV1ContributeSubmit({
|
return postShareProV1ContributeSubmit({
|
||||||
node_id: id ? id[0] : undefined,
|
node_id: id ? id[0] : undefined,
|
||||||
|
|
@ -60,7 +51,6 @@ const DocEditor = () => {
|
||||||
reason,
|
reason,
|
||||||
emoji: nodeDetail?.meta?.emoji,
|
emoji: nodeDetail?.meta?.emoji,
|
||||||
captcha_token: token,
|
captcha_token: token,
|
||||||
content_type: contentType || 'html',
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
message.success('保存成功, 即将关闭页面');
|
message.success('保存成功, 即将关闭页面');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"packageManager": "pnpm@10.12.1",
|
"packageManager": "pnpm@10.12.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ctzhian/tiptap": "^1.11.4",
|
"@ctzhian/tiptap": "^1.10.3",
|
||||||
"@ctzhian/ui": "^7.0.5",
|
"@ctzhian/ui": "^7.0.5",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,9 @@ const Carousel = ({ title, items }: CarouselProps) => {
|
||||||
|
|
||||||
document.body.removeChild(measureContainer);
|
document.body.removeChild(measureContainer);
|
||||||
|
|
||||||
|
// 获取目标背景色(从计算样式获取)
|
||||||
|
const targetBgColor = alpha(theme.palette.text.primary, 0.5).toString();
|
||||||
|
|
||||||
// 设置容器初始状态(只有 padding,背景色透明)
|
// 设置容器初始状态(只有 padding,背景色透明)
|
||||||
gsap.set(descElement, {
|
gsap.set(descElement, {
|
||||||
width: padding,
|
width: padding,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue