Skip to content

Commit c3bce9d

Browse files
authored
v1.0.3 (#31)
feat: 重大功能更新 - 变量输入组件、微信小程序支持、页面编辑增强和 AppDev 优化 主要变更: - 新增 VariableInferenceInput 和 TiptapVariableInput 变量输入组件 - 添加微信小程序 JS-SDK 支持和回到首页功能 - 增强页面编辑功能(封面图片、预览优化、描述限制) - 优化 AppDev Web IDE(日志处理、文件管理、版本检查) - 重构代码结构,提取自定义 Hooks,提升可维护性 - 修复多个 Bug(变量引用、日志轮询、页面刷新等) - 清理 80+ 调试日志,优化开发体验
1 parent 7e3ca1a commit c3bce9d

File tree

81 files changed

+10139
-355
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+10139
-355
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@
5656
"@dnd-kit/utilities": "^3.2.2",
5757
"@microsoft/fetch-event-source": "^2.0.1",
5858
"@monaco-editor/react": "^4.6.0",
59+
"@tiptap/core": "^2.27.1",
60+
"@tiptap/pm": "^2.27.1",
61+
"@tiptap/react": "^2.27.1",
62+
"@tiptap/starter-kit": "^2.27.1",
63+
"@tiptap/suggestion": "^2.27.1",
5964
"@umijs/max": "^4.4.2",
6065
"@umijs/utils": "^4.4.11",
6166
"ahooks": "^3.8.4",

pnpm-lock.yaml

Lines changed: 558 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/sdk/dev-monitor.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,134 @@
989989
},
990990
});
991991
}
992+
993+
/**
994+
* 获取 URL 指定参数的值(支持 search 与 hash)
995+
* @param {string} url - 要处理的 URL
996+
* @param {string} key - 参数名
997+
* @returns {string|null} - 返回参数值,不存在返回 null
998+
*/
999+
function getQueryParam(url, key) {
1000+
try {
1001+
const u = new URL(url, window.location.origin);
1002+
1003+
// 1. 优先从 ?a=1&b=2 中读取
1004+
if (u.searchParams.has(key)) {
1005+
return u.searchParams.get(key);
1006+
}
1007+
1008+
// 2. 再从 hash 中读取: #/page?id=100&type=1
1009+
if (u.hash.includes('?')) {
1010+
const hashQuery = u.hash.split('?')[1]; // 取 ? 后部分
1011+
const hashParams = new URLSearchParams(hashQuery);
1012+
1013+
if (hashParams.has(key)) {
1014+
return hashParams.get(key);
1015+
}
1016+
}
1017+
1018+
return null;
1019+
} catch (e) {
1020+
console.warn('无效 URL:', url);
1021+
return null;
1022+
}
1023+
}
1024+
function handleBackToHome() {
1025+
// 如果当前 URL 中不包含 _ticket 参数,则不显示按钮
1026+
const currentUrl = window.location.href;
1027+
const _ticket = getQueryParam(currentUrl, '_ticket');
1028+
// 跳转类型主要区别是否是系统内部跳转还是分享链接跳转
1029+
const jump_type = getQueryParam(currentUrl, 'jump_type');
1030+
1031+
if (!_ticket || !jump_type) {
1032+
console.warn(
1033+
'[dev-monitor] 未检测到 _ticket 或 jump_type,跳过首页按钮渲染',
1034+
);
1035+
return;
1036+
}
1037+
1038+
// 跳转类型主要区别是否是系统内部跳转还是分享链接跳转
1039+
if (jump_type === 'inner') {
1040+
// 内部页面在路由变化后添加按钮
1041+
onceHistoryChange(() => {
1042+
addBackToHomeButton(jump_type);
1043+
});
1044+
}
1045+
// 跳转类型主要区别是否是系统内部跳转还是分享链接跳转
1046+
if (jump_type === 'outer') {
1047+
// 外部页面直接添加按钮
1048+
addBackToHomeButton(jump_type);
1049+
}
1050+
}
1051+
1052+
/**
1053+
* 添加「回到首页」悬浮图标
1054+
* - 默认固定在页面右下角
1055+
* - 单击 / 轻触:回到首页
1056+
*/
1057+
function addBackToHomeButton(jump_type) {
1058+
const icon = document.createElement('div');
1059+
icon.innerHTML = 'X';
1060+
1061+
// 基础样式:右下角悬浮小圆角块
1062+
Object.assign(icon.style, {
1063+
position: 'fixed',
1064+
bottom: '16px',
1065+
right: '16px',
1066+
width: '30px',
1067+
height: '30px',
1068+
lineHeight: '30px',
1069+
textAlign: 'center',
1070+
borderRadius: '22px',
1071+
background: 'rgba(0, 0, 0, 0.15)',
1072+
color: '#fff',
1073+
fontSize: '14px',
1074+
zIndex: '99999',
1075+
cursor: 'pointer',
1076+
userSelect: 'none',
1077+
WebkitUserSelect: 'none',
1078+
});
1079+
1080+
// 回到首页
1081+
function goHome() {
1082+
icon.remove();
1083+
setTimeout(() => {
1084+
if (jump_type === 'outer') {
1085+
// 如果是分享链接跳转,则使用 wx.miniProgram.reLaunch 跳转到首页
1086+
window.wx.miniProgram.reLaunch({ url: '/pages/index/index' });
1087+
}
1088+
1089+
if (jump_type === 'inner') {
1090+
// 如果是系统内部跳转,则使用 wx.miniProgram.navigateBack 回退
1091+
window.wx.miniProgram.navigateBack();
1092+
}
1093+
}, 50);
1094+
}
1095+
1096+
// 点击 / 轻触:回到首页(PC + 移动端)
1097+
icon.addEventListener('click', () => {
1098+
try {
1099+
goHome();
1100+
} catch (e) {
1101+
// 静默失败,避免影响页面
1102+
}
1103+
});
1104+
icon.addEventListener(
1105+
'touchend',
1106+
(event) => {
1107+
event?.preventDefault();
1108+
try {
1109+
goHome();
1110+
} catch (e) {
1111+
// 静默失败,避免影响页面
1112+
}
1113+
},
1114+
{ passive: false },
1115+
);
1116+
1117+
document.body.appendChild(icon);
1118+
}
1119+
9921120
/**
9931121
* 注入微信 JS-SDK
9941122
*/
@@ -1000,6 +1128,9 @@
10001128

10011129
// 脚本加载成功回调
10021130
script.onload = function () {
1131+
// 添加回到首页按钮
1132+
handleBackToHome();
1133+
10031134
// 等待 wx 对象可用
10041135
setTimeout(() => {
10051136
let timer = null;
@@ -1046,6 +1177,49 @@
10461177
}
10471178
}
10481179

1180+
/**
1181+
* 监听一次历史记录变化
1182+
* @param callback
1183+
*/
1184+
function onceHistoryChange(callback) {
1185+
let called = false;
1186+
1187+
const handler = () => {
1188+
if (called) return;
1189+
called = true;
1190+
callback();
1191+
1192+
// 移除监听
1193+
window.removeEventListener('popstate', handler);
1194+
window.removeEventListener('hashchange', handler);
1195+
1196+
history.pushState = originalPushState;
1197+
// history.replaceState = originalReplaceState;
1198+
};
1199+
1200+
const originalPushState = history.pushState;
1201+
// const originalReplaceState = history.replaceState;
1202+
1203+
history.pushState = function (...args) {
1204+
const result = originalPushState.apply(this, args);
1205+
handler();
1206+
return result;
1207+
};
1208+
1209+
// history.replaceState = function (...args) {
1210+
// const result = originalReplaceState.apply(this, args);
1211+
// handler();
1212+
// return result;
1213+
// };
1214+
1215+
window.addEventListener('popstate', () => {
1216+
handler();
1217+
});
1218+
window.addEventListener('hashchange', () => {
1219+
handler();
1220+
});
1221+
}
1222+
10491223
// 简化的初始化
10501224
function init() {
10511225
// ⭐ 关键:优先设置 Console 拦截,确保在 React Router 加载之前就拦截

src/app.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import { unifiedThemeService } from './services/unifiedThemeService';
1212
* 在应用运行期间保持活跃,处理全局事件
1313
*/
1414
const GlobalEventPolling: React.FC = () => {
15-
// 启动事件轮询
16-
useEventPolling();
17-
return null; // 这个组件不渲染任何内容
15+
// 启动事件轮询,返回 contextHolder 用于渲染 Modal 上下文
16+
const contextHolder = useEventPolling();
17+
return contextHolder; // 返回 contextHolder 以支持 Modal 的动态主题
1818
};
1919

2020
/**
@@ -192,8 +192,8 @@ export function render(oldRender: () => void) {
192192
* 路由变化监听
193193
* 可以在这里处理页面切换逻辑
194194
*/
195-
export function onRouteChange(...params: any[]) {
196-
console.info('[router] onRouteChange', ...params);
195+
export function onRouteChange() {
196+
// console.info('[router] onRouteChange', ...params);
197197

198198
// 如果是登录成功后的路由变化,确保轮询启动
199199
if (localStorage.getItem(ACCESS_TOKEN) && location.pathname !== '/login') {

src/components/ExpandTextArea/expandTextarea.tsx

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
// import { ICON_OPTIMIZE } from '@/constants/images.constants';
2+
import TiptapVariableInput from '@/components/TiptapVariableInput';
23
import { CloseOutlined } from '@ant-design/icons';
34
import { ConfigProvider, Space } from 'antd';
45
import { Form } from 'antd/lib';
56
import { PromptEditorProvider, PromptEditorRender } from 'prompt-kit-editor';
67
import React from 'react';
78
import './expandTextarea.less';
89
import type { ExpandableInputTextareaState } from './type';
10+
911
const ExpandTextArea: React.FC<
10-
ExpandableInputTextareaState & { visible: boolean }
12+
ExpandableInputTextareaState & {
13+
visible: boolean;
14+
useTiptap?: boolean;
15+
skills?: any[];
16+
}
1117
> = ({
1218
marginRight,
1319
title,
1420
inputFieldName,
1521
placeholder,
1622
visible, // 接收 visible 属性
1723
onClose,
24+
variables,
25+
skills,
26+
useTiptap = false,
1827
}) => {
1928
return (
2029
<div
@@ -39,24 +48,33 @@ const ExpandTextArea: React.FC<
3948
</ConfigProvider>
4049
</div>
4150
</div>
42-
{/*<Form.Item name={inputFieldName} className="expand-textarea-pre-style">*/}
43-
{/* <Input.TextArea*/}
44-
{/* placeholder={placeholder}*/}
45-
{/* className="no-resize-textarea"*/}
46-
{/* />*/}
47-
{/*</Form.Item>*/}
48-
<PromptEditorProvider>
51+
{useTiptap ? (
4952
<Form.Item
5053
name={inputFieldName}
5154
className="expand-textarea-pre-style scroll-container"
5255
>
53-
<PromptEditorRender
56+
<TiptapVariableInput
5457
className="prompt-editor-provider"
55-
isControled={true}
5658
placeholder={placeholder}
59+
variables={variables}
60+
skills={skills}
61+
style={{ height: '100%', minHeight: '400px' }}
5762
/>
5863
</Form.Item>
59-
</PromptEditorProvider>
64+
) : (
65+
<PromptEditorProvider>
66+
<Form.Item
67+
name={inputFieldName}
68+
className="expand-textarea-pre-style scroll-container"
69+
>
70+
<PromptEditorRender
71+
className="prompt-editor-provider"
72+
isControled={true}
73+
placeholder={placeholder}
74+
/>
75+
</Form.Item>
76+
</PromptEditorProvider>
77+
)}
6078
</div>
6179
);
6280
};

src/components/ExpandTextArea/index.tsx

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import TiptapVariableInput from '@/components/TiptapVariableInput';
12
import { ICON_OPTIMIZE } from '@/constants/images.constants';
23
import { ExpandAltOutlined } from '@ant-design/icons';
34
import { Button, Form } from 'antd';
@@ -11,16 +12,27 @@ import styles from './index.less';
1112
import { ExpandableInputTextareaProps } from './type';
1213
const cx = classNames.bind(styles);
1314

15+
// 特性开关:是否使用 Tiptap 编辑器
16+
// 如果遇到问题,将此值设置为 false 可回退到旧版 Input.TextArea
17+
const USE_TIPTAP_EDITOR = false; //TODO: 先切换回老的版本 下周再切换回来
18+
/**
19+
* TODO:周再切换回来
20+
* 1. 提交后台时要用 rawValue 而不是 value
21+
22+
*/
23+
1424
export const ExpandableInputTextarea: React.FC<
1525
ExpandableInputTextareaProps
1626
> = ({
1727
title,
1828
inputFieldName,
1929
placeholder,
20-
// rows = 3,
30+
rows = 3,
2131
onExpand,
2232
onOptimize,
2333
onOptimizeClick,
34+
variables,
35+
skills,
2436
}) => {
2537
const [uuid, setUuid] = useState('');
2638
const { setExpanded, expanded } = useModel('workflow'); // 添加本地状态
@@ -62,22 +74,30 @@ export const ExpandableInputTextarea: React.FC<
6274
</div>
6375
</div>
6476
{/* 输入框 */}
65-
{/*<Form.Item name={inputFieldName}>*/}
66-
{/* <Input.TextArea*/}
67-
{/* placeholder={placeholder}*/}
68-
{/* autoSize={{ minRows: rows, maxRows: rows }}*/}
69-
{/* />*/}
70-
{/*</Form.Item>*/}
71-
72-
<PromptEditorProvider>
77+
{USE_TIPTAP_EDITOR ? (
7378
<Form.Item name={inputFieldName}>
74-
<PromptEditorRender
75-
className={cx(styles['prompt-editor-provider'], 'scroll-container')}
76-
isControled={true}
79+
<TiptapVariableInput
7780
placeholder={placeholder}
81+
variables={variables}
82+
skills={skills}
83+
className={cx(styles['prompt-editor-provider'])}
84+
style={{ minHeight: rows * 24 + 10 }} // 估算高度
7885
/>
7986
</Form.Item>
80-
</PromptEditorProvider>
87+
) : (
88+
<PromptEditorProvider>
89+
<Form.Item name={inputFieldName}>
90+
<PromptEditorRender
91+
className={cx(
92+
styles['prompt-editor-provider'],
93+
'scroll-container',
94+
)}
95+
isControled={true}
96+
placeholder={placeholder}
97+
/>
98+
</Form.Item>
99+
</PromptEditorProvider>
100+
)}
81101

82102
{/* 如果有展开,就要调用展开的组件 */}
83103
{expanded &&
@@ -89,6 +109,9 @@ export const ExpandableInputTextarea: React.FC<
89109
placeholder={placeholder}
90110
visible={expanded === uuid}
91111
onClose={() => setExpanded('')}
112+
variables={variables}
113+
skills={skills}
114+
useTiptap={USE_TIPTAP_EDITOR}
92115
/>
93116
)}
94117
</div>

0 commit comments

Comments
 (0)