| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /*global Dingdocs*/
- import { useEffect, useState, useCallback } from 'react';
- import { initView } from 'dingtalk-docs-cool-app';
- import { Typography, Button, Card, Select, Input, Spin } from 'dingtalk-design-desktop';
- import './style.css';
- interface ApiParam {
- paramName: string;
- paramDesc: string;
- exampleValue?: string;
- valueList?: string[];
- value?: string;
- }
- interface ApiItem {
- id: string;
- apiName: string;
- url: string;
- description: string;
- aiTableId: string;
- aiTablename: string;
- apiParamAuth: ApiParam[];
- }
- interface ApiResponse {
- code: number;
- msg: string;
- data?: any;
- }
- interface UserInfo {
- userId: string;
- name?: string;
- avatar?: string;
- mobile?: string;
- jobnumber?: string;
- department?: number[];
- permissions?: string[];
- [key: string]: any;
- }
- function App() {
- const [loading, setLoading] = useState<boolean>(true);
- const [apiList, setApiList] = useState<ApiItem[]>([]);
- const [currentApi, setCurrentApi] = useState<ApiItem | null>(null);
- const [apiParams, setApiParams] = useState<Record<string, string>>({});
- const [result, setResult] = useState<string>('');
- const [callLoading, setCallLoading] = useState<boolean>(false);
- const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
- const [error, setError] = useState<string>('');
- const [documentInfo, setDocumentInfo] = useState<{ uuid: string; currentSheet: string } | null>(null);
- const [customTableId, setCustomTableId] = useState<string>('');
- const [customTableName, setCustomTableName] = useState<string>('');
- const [authCode, setAuthCode] = useState('');
- const loadApiList = useCallback(async () => {
- try {
- const list = await Dingdocs.script.run('getApiList');
- setApiList(list);
- } catch (error: any) {
- console.error('加载 API 列表失败:', error);
- setError(error.message || '加载 API 列表失败');
- }
- }, []);
- const handleAutoLogin = useCallback(async () => {
- try {
- const urlParams = new URLSearchParams(window.location.search);
- const corpId = urlParams.get('corpId') || '';
- const authResult = await Dingdocs.base.host.getAuthCode(corpId);
- const authCode = authResult.code;
-
- const user = await Dingdocs.script.run('login', authCode);
- setUserInfo(user);
- console.log('自动登录成功:', user);
- } catch (error: any) {
- console.error('自动登录失败:', error);
- setError(error.message || '登录失败');
- throw error;
- }
- }, []);
- const loadDocumentInfo = useCallback(async () => {
- try {
- const info = await Dingdocs.script.run('getDocumentInfo');
- setDocumentInfo({
- uuid: info?.uuid || '',
- currentSheet: info?.currentSheet || ''
- });
- setCustomTableId(info?.uuid || '');
- setCustomTableName(info?.currentSheet || '');
- } catch (error: any) {
- console.error('获取文档信息失败:', error);
- }
- }, []);
- const handleGetAuthCode = useCallback(async () => {
- try {
- const urlParams = new URLSearchParams(window.location.search);
- const corpId = urlParams.get('corpId') || '';
- console.log('corpId:', corpId);
- const result = await Dingdocs.base.host.getAuthCode(corpId);
- console.log('免登录码:', result);
- const authCode = result.code;
- setAuthCode(authCode || '获取失败');
- } catch (error: any) {
- console.error('获取免登录码失败:', error);
- setAuthCode('获取失败: ' + error);
- }
- }, []);
- const handleApiChange = (apiId: string) => {
- const api = apiList.find(item => item.id === apiId);
- if (api) {
- setCurrentApi(api);
- const params: Record<string, string> = {};
- api.apiParamAuth.forEach(param => {
- params[param.paramName] = param.value || '';
- });
- setApiParams(params);
- setResult('');
- } else {
- setCurrentApi(null);
- setApiParams({});
- setResult('');
- }
- };
- const handleParamChange = (paramName: string, value: string) => {
- setApiParams(prev => ({
- ...prev,
- [paramName]: value
- }));
- };
- const handleCallApi = async () => {
- if (!currentApi || callLoading) return;
-
- setCallLoading(true);
- setResult('');
-
- const apiItem = {
- ...currentApi,
- aiTableId: customTableId || currentApi.aiTableId,
- aiTablename: customTableName || currentApi.aiTablename,
- apiParamAuth: currentApi.apiParamAuth.map(p => ({
- paramName: p.paramName,
- value: apiParams[p.paramName] || p.value || ''
- }))
- };
-
- try {
- const response: ApiResponse = await Dingdocs.script.run('callApi', apiItem);
- setResult(JSON.stringify(response, null, 2));
- } catch (error: any) {
- setResult(`调用失败: ${error.message}`);
- } finally {
- setCallLoading(false);
- }
- };
- useEffect(() => {
- initView({
- onReady: async () => {
- setLoading(true);
- setError('');
-
- try {
- await handleAutoLogin();
- await loadApiList();
- loadDocumentInfo();
- } catch (error: any) {
- console.error('初始化失败:', error);
- setError(error.message || '初始化失败');
- } finally {
- setLoading(false);
- }
- },
- });
- }, [handleAutoLogin, loadApiList, loadDocumentInfo]);
- if (loading) {
- return (
- <div className="page">
- <div className="loading">
- <Spin size="small" />
- <Typography.Text className="loading-text">加载中...</Typography.Text>
- </div>
- </div>
- );
- }
- if (error) {
- return (
- <div className="page">
- <div className="login-container">
- <Card size="small" className="login-card">
- <Typography.Text type="danger">{error}</Typography.Text>
- </Card>
- </div>
- </div>
- );
- }
- return (
- <div className="page">
- <div className="header">
- <div className="header-content">
- <Typography.Title level={4}>API 调用测试</Typography.Title>
- <div className="user-info">
- <Typography.Text className="user-name">{userInfo?.name || userInfo?.userId || '用户'}</Typography.Text>
- </div>
- </div>
- </div>
-
- <div className="content">
- <Card size="small" className="main-card">
- <div className="auth-code-section">
- <Typography.Title level={5} className="auth-code-title">免登录码获取</Typography.Title>
- <Button
- type="primary"
- onClick={handleGetAuthCode}
- className="auth-code-btn"
- >
- 获取免登录码
- </Button>
- {authCode && (
- <div className="auth-code-result">
- <Typography.Text className="auth-code-label">免登录码:</Typography.Text>
- <code className="auth-code-value">{authCode}</code>
- </div>
- )}
- </div>
-
- <div className="form-item">
- <Typography.Text className="label">选择 API</Typography.Text>
- <Select
- className="api-select"
- placeholder="请选择要调用的 API 接口"
- onChange={handleApiChange}
- value={currentApi?.id || ''}
- >
- {apiList.map(api => (
- <Select.Option key={api.id} value={api.id}>
- {api.apiName}
- </Select.Option>
- ))}
- </Select>
- </div>
- {currentApi && (
- <div className="api-detail">
- <Card size="small" className="info-card">
- <div className="info-row">
- <Typography.Text className="info-label">API 名称:</Typography.Text>
- <Typography.Text strong>{currentApi.apiName}</Typography.Text>
- </div>
-
- <div className="info-row">
- <Typography.Text className="info-label">功能描述:</Typography.Text>
- <Typography.Text>{currentApi.description}</Typography.Text>
- </div>
- </Card>
- <Typography.Title level={5} className="params-title">文档信息</Typography.Title>
- <div className="params-container">
- <div className="param-item">
- <Typography.Text className="param-label">
- 文档 ID
- <span className="param-name">(documentId)</span>
- </Typography.Text>
- <Input
- className="param-input"
- placeholder="请输入文档 ID"
- value={customTableId || ''}
- onChange={(e) => setCustomTableId(e.target.value)}
- />
- </div>
- <div className="param-item">
- <Typography.Text className="param-label">
- 表格名称
- <span className="param-name">(tableName)</span>
- </Typography.Text>
- <Input
- className="param-input"
- placeholder="请输入表格名称"
- value={customTableName || ''}
- onChange={(e) => setCustomTableName(e.target.value)}
- />
- </div>
- </div>
- <Typography.Title level={5} className="params-title">请求参数</Typography.Title>
- <div className="params-container">
- {currentApi.apiParamAuth.map(param => (
- <div key={param.paramName} className="param-item">
- <Typography.Text className="param-label">
- {param.paramDesc}
- <span className="param-name">({param.paramName})</span>
- </Typography.Text>
- {param.valueList && param.valueList.length > 0 && param.valueList.some(v => v) ? (
- <Select
- className="param-select"
- placeholder="请选择"
- value={apiParams[param.paramName] || ''}
- onChange={(value) => handleParamChange(param.paramName, value)}
- >
- {param.valueList.map(val => (
- <Select.Option key={val} value={val}>
- {val}
- </Select.Option>
- ))}
- </Select>
- ) : (
- <Input
- className="param-input"
- placeholder={param.exampleValue || '请输入'}
- value={apiParams[param.paramName] || ''}
- onChange={(e) => handleParamChange(param.paramName, e.target.value)}
- />
- )}
- </div>
- ))}
- </div>
- <div className="action-bar">
- <Button
- type="primary"
- loading={callLoading}
- onClick={handleCallApi}
- className="call-btn"
- >
- 执行调用
- </Button>
- </div>
- {result && (
- <Card size="small" className="result-card">
- <Typography.Title level={5} className="result-title">返回结果</Typography.Title>
- <pre className="result-content">{result}</pre>
- </Card>
- )}
- </div>
- )}
- </Card>
- </div>
- </div>
- );
- }
- export default App;
|