Major Changes: - Add StreamingService with OpenAI Compatible format - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Update API routes to unified /api/v1 prefix - Update system documentation Backend (~1300 lines): - common/streaming: OpenAI Compatible adapter - modules/aia: 12 agents, conversation service, streaming integration - Update route versions (RVW, PKB to v1) Frontend (~3500 lines): - modules/aia: AgentHub + ChatWorkspace (100% prototype restoration) - shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook - Update API endpoints to v1 Documentation: - AIA module status guide - Universal capabilities catalog - System overview updates - All module documentation sync Tested: Stream response verified, authentication working Status: AIA V2.0 core completed (85%)
1224 lines
32 KiB
Markdown
1224 lines
32 KiB
Markdown
# REDCap撖寞𦻖憌𡡞埯霂<E59FAF>摯銝擧<E98A9D><E693A7>舀<EFBFBD><E88880>䀹楛摨血<E691A8><E8A180>?
|
||
|
||
> **<2A><>﹝<EFBFBD><EFB99D>𧋦嚗?* v1.0
|
||
> **<2A>𥕦遣<F0A595A6>交<EFBFBD>嚗?* 2025-12-30
|
||
> **<2A><>﹝<EFBFBD>桃<EFBFBD>嚗?* <20><><EFBFBD><EFBFBD>萘輕<E89098><E8BC95><EFBFBD>REDCap撖寞𦻖<E5AF9E><F0A6BB96><EFBFBD><EFBFBD>舫𠗕<E888AB>嫘<EFBFBD><E5AB98><EFBFBD><EFBFBD>舀綉<E88880>删<EFBFBD><E588A0><EFBFBD><EFBFBD><EFBFBD>券<EFBFBD><E588B8>?
|
||
> **<2A><>粉<EFBFBD>園𡢿嚗?* 20<32><30><EFBFBD>
|
||
> **<2A>滩<EFBFBD><E6BBA9>改<EFBFBD>** 潃鐥<E6BD83>潃鐥<E6BD83>潃?**<2A>嗆<EFBFBD><E59786>喟<EFBFBD>敹<EFBFBD>粉**
|
||
|
||
---
|
||
|
||
## <20><> <20><>﹝霂湔<E99C82>
|
||
|
||
<EFBFBD>祆<EFBFBD>獢<EFBFBD><EFBFBD><EFBFBD>?*<2A><><EFBFBD><EFBFBD>萘輕<E89098>屸<EFBFBD><E5B1B8>拐<EFBFBD><E68B90>?*<2A><><EFBFBD><EFBFBD>鞉䲮瘜𤏪<E7989C>霂<EFBFBD><E99C82>REDCap撖寞𦻖憿寧𤌍<E5AFA7><F0A48C8D><EFBFBD>
|
||
1. **<EFBFBD><EFBFBD><EFBFBD>舫𠗕<EFBFBD>?*嚗?憭扳瓲敹<E793B2>𠗕憸矋<E686B8>
|
||
2. **銝滚虾<E6BB9A>批<EFBFBD>蝝?*嚗?銝芷<E98A9D><E88AB7>㘾<EFBFBD><E398BE>抬<EFBFBD>
|
||
3. **憭齿<E686AD>摨西<E691A8>隡?*嚗<><E59A97><EFBFBD>芰<EFBFBD>EDC撖寞<E69296>嚗?
|
||
4. **憭梯揖獢<E68F96><E78DA2><EFBFBD><EFBFBD><EFBFBD>**嚗<><E59A97><EFBFBD>諹萱<E8ABB9>𤑳<EFBFBD>撉䕘<E69289>
|
||
5. **閫<><E996AB>蝑𣇉裦**嚗<><E59A97>雿閖<E99BBF>雿𡡞<E99BBF><F0A1A19E>抬<EFBFBD>
|
||
|
||
**<EFBFBD>詨<EFBFBD><EFBFBD>桅<EFBFBD>**嚗?
|
||
- <20>?REDCap<61><70>AV璅∪<E79285><E288AA>臬炏隡𡁏<E99AA1>銝箸<E98A9D>扯<EFBFBD><E689AF>園<EFBFBD>嚗?
|
||
- <20>?External Module獢<65>沲<EFBFBD><E6B2B2><EFBFBD><EFBFBD>嗆<EFBFBD>憭𡁜之嚗?
|
||
- <20>?<3F><>𧋦<EFBFBD><F0A78BA6>漣隡帋<E99AA1>隡𡁶聦<F0A181B6>𤩺<EFBFBD>隞祉<E99A9E><E7A589><EFBFBD><EFBFBD>嚗?
|
||
- <20>?<3F>唳旿銝<E697BF><E98A9D>湔<EFBFBD>批<EFBFBD>雿蓥<E99BBF>霂<EFBFBD><E99C82>
|
||
- <20>?<3F>臬炏<E887AC>澆<EFBFBD><E6BE86>訫<EFBFBD>嚗㇌OI<4F><49><EFBFBD>嚗㚁<E59A97>
|
||
|
||
---
|
||
|
||
## <20>辶 <20>詨<EFBFBD>憌𡡞埯璁<E59FAF><E79281>嚗<EFBFBD>滯<EFBFBD>航郎<E888AA>𠺪<EFBFBD>
|
||
|
||
### 憌𡡞埯蝑厩漣<E58EA9><E6BCA3>掩
|
||
|
||
| 憌𡡞埯蝐餃<E89D90> | 憌𡡞埯蝑厩漣 | 敶勗<E695B6><E58B97><EFBFBD>凒 | <20>舀綉<E88880>?| 撱箄悅 |
|
||
|---------|---------|---------|--------|------|
|
||
| **EAV璅∪<E79285><E288AA>扯<EFBFBD>** | <20>𣞁 擃?| <20>唳旿<E594B3>?10銝<30>辺<EFBFBD>?| <20>𩤃<EFBFBD> <20>典<EFBFBD><E585B8>舀綉 | 敹<>◆霈曇恣蝻枏<E89DBB><E69E8F>諹<EFBFBD><E8ABB9><EFBFBD><EFBFBD><EFBFBD>?|
|
||
| **REDCap<61><70>漣<EFBFBD>澆捆<E6BE86>?* | <20>𣞁 擃?| 瘥𤩺活REDCap<61><70>漣 | <20>?銝滚虾<E6BB9A>?| 銝交聢<E4BAA4><E881A2>𧋦<EFBFBD><F0A78BA6><EFBFBD>+<2B>𧼮<EFBFBD>瘚贝<E7989A> |
|
||
| **<EFBFBD>唳旿銝<EFBFBD><EFBFBD>湔<EFBFBD>?* | <20>椬 銝?| <20><><EFBFBD><EFBFBD>峕郊<E5B395>箸艶 | <20>?<3F>舀綉 | 霈曇恣撟<E681A3><E6929F><EFBFBD>?<3F>脩<EFBFBD>閫<EFBFBD><E996AB><EFBFBD>箏<EFBFBD> |
|
||
| **API<50>鞉<EFBFBD>** | <20>椬 銝?| <20>寥<EFBFBD><E5AFA5>滢<EFBFBD> | <20>?<3F>舀綉 | 摰䂿緵<E482BF>毺<EFBFBD><E6AFBA>𣂼<EFBFBD><F0A382BC>峕鸌憭<E9B88C><E686AD> |
|
||
| **摰匧<E691B0><E58CA7><EFBFBD><EFBFBD>** | <20>𣞁 擃?| PHI<48>唳旿瘜<E697BF>蠧 | <20>?<3F>舀綉 | 銝交聢摰∟恣+<2B>惩<EFBFBD>+HIPAA<41><41><EFBFBD> |
|
||
| **蝏湔擪<E6B994>鞉𧋦** | <20>椬 銝?| <20>踵<EFBFBD>餈鞱𨯫 | <20>𩤃<EFBFBD> <20>典<EFBFBD><E585B8>舀綉 | 蝏<>遣銝㮖<E98A9D><E3AE96>a<EFBFBD> |
|
||
| **<EFBFBD>冽<EFBFBD><EFBFBD>亙<EFBFBD>摨?* | <20>叚 雿?| <20>冽<EFBFBD><E586BD>寡悌 | <20>?<3F>舀綉 | 皜鞱<E79A9C>撘𤩺綫撟?|
|
||
|
||
---
|
||
|
||
## <20>𣞁 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗鍃AV璅∪<E79285><E288AA><EFBFBD><EFBFBD>扯<EFBFBD>瘛望<E7989B>
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
REDCap雿輻鍂**Entity-Attribute-Value (EAV)** 璅∪<E79285>摮睃<E691AE><E79D83>唳旿嚗諹<E59A97><E8ABB9>舀<EFBFBD>憭抒<E686AD><E68A92><EFBFBD><EFBFBD>舀<EFBFBD><E88880>塩<EFBFBD>?
|
||
|
||
#### REDCap<61><70>㺭<EFBFBD>桀<EFBFBD><E6A180>冽䲮撘?
|
||
|
||
```sql
|
||
-- redcap_data銵函<E98AB5><E587BD><EFBFBD><EFBFBD><EFBFBD>詨<EFBFBD>銵剁<E98AB5>
|
||
CREATE TABLE redcap_data (
|
||
project_id INT,
|
||
event_id INT,
|
||
record VARCHAR(100),
|
||
field_name VARCHAR(100),
|
||
value TEXT,
|
||
PRIMARY KEY (project_id, event_id, record, field_name)
|
||
);
|
||
|
||
-- 摮睃<E691AE>蝷箔<E89DB7>嚗帋<E59A97>銝芣<E98A9D><E88AA3><EFBFBD><EFBFBD>3銝芸<E98A9D>畾菟<E795BE>閬?銵?
|
||
| project_id | event_id | record | field_name | value |
|
||
|------------|----------|---------|------------|----------|
|
||
| 123 | 1 | PAT001 | age | 45 |
|
||
| 123 | 1 | PAT001 | gender | male |
|
||
| 123 | 1 | PAT001 | diagnosis | diabetes |
|
||
```
|
||
|
||
撖寞<EFBFBD>**隡删<E99AA1><E588A0>喟頂<E5969F>𧢲芋<F0A7A2B2>?*嚗?
|
||
```sql
|
||
-- 隡删<E99AA1>摰質”摮睃<E691AE>嚗<EFBFBD><E59A97>銵峕<E98AB5>摰𡄯<E691B0>
|
||
CREATE TABLE patients (
|
||
record_id VARCHAR(100) PRIMARY KEY,
|
||
age INT,
|
||
gender VARCHAR(10),
|
||
diagnosis VARCHAR(100)
|
||
);
|
||
|
||
| record_id | age | gender | diagnosis |
|
||
|-----------|-----|--------|-----------|
|
||
| PAT001 | 45 | male | diabetes |
|
||
```
|
||
|
||
### <20>扯<EFBFBD><E689AF>桅<EFBFBD>嚗<EFBFBD><E59A97>摰𧼮㦤<F0A7BCAE>荔<EFBFBD>
|
||
|
||
#### <20>箸艶1嚗𡁏䰻霂W<E99C82>銝芣<E98A9D><E88AA3><EFBFBD><EFBFBD>摰峕㟲<E5B395>唳旿
|
||
|
||
```sql
|
||
-- EAV璅∪<E79285>嚗𡁻<E59A97>閬<EFBFBD>䌊<EFBFBD>唾<EFBFBD>JOIN嚗<4E><E59A97>嚗?
|
||
SELECT
|
||
MAX(CASE WHEN field_name = 'age' THEN value END) AS age,
|
||
MAX(CASE WHEN field_name = 'gender' THEN value END) AS gender,
|
||
MAX(CASE WHEN field_name = 'diagnosis' THEN value END) AS diagnosis
|
||
FROM redcap_data
|
||
WHERE project_id = 123
|
||
AND record = 'PAT001'
|
||
GROUP BY record;
|
||
|
||
-- <20>扯<EFBFBD><E689AF>園𡢿嚗?00銝芸<E98A9D>畾蛛<E795BE>嚗鰺50-200ms
|
||
-- 摰質”<E8B3AA>扯<EFBFBD><E689AF>園𡢿嚗鰺1-5ms嚗<73>翰40-200<30>㵪<EFBFBD>
|
||
```
|
||
|
||
#### <20>箸艶2嚗𡁏鸌<F0A1818F>誩紡<E8AAA9>?000銝芣<E98A9D><E88AA3>?
|
||
|
||
```sql
|
||
-- EAV璅∪<E79285>嚗𡁶<E59A97><F0A181B6>暹<EFBFBD>抒<EFBFBD><E68A92>扯<EFBFBD>
|
||
SELECT * FROM redcap_data
|
||
WHERE project_id = 123
|
||
AND record IN ('PAT001', 'PAT002', ..., 'PAT1000');
|
||
|
||
-- 蝏𤘪<E89D8F>嚗朞<E59A97><E69C9E>?00銝<30><E98A9D>嚗?000<30><30><EFBFBD>?<3F> 100摮埈挾 <20> 10鈭衤辣嚗?
|
||
-- <20>扯<EFBFBD><E689AF>園𡢿嚗?0-60蝘?
|
||
-- <20><><EFBFBD><EFBFBD>删鍂嚗?00MB - 2GB
|
||
-- 蝵𤑳<E89DB5>隡㰘<E99AA1>嚗𡁜楊憭抒<E686AD>JSON payload
|
||
```
|
||
|
||
#### <20>箸艶3嚗𡁶<E59A97>霈∪<E99C88><E288AA>鞉䰻霂?
|
||
|
||
```sql
|
||
-- <20>亥砭撟湧<E6929F>>50撗<30><E69297><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㺭<EFBFBD>?
|
||
SELECT COUNT(DISTINCT record)
|
||
FROM redcap_data
|
||
WHERE project_id = 123
|
||
AND field_name = 'age'
|
||
AND CAST(value AS UNSIGNED) > 50;
|
||
|
||
-- <20>桅<EFBFBD>嚗𡁜<E59A97>銵冽醌<E586BD>𧶏<EFBFBD><F0A7B68F>䭾<EFBFBD><E4ADBE>拍鍂蝝W<E89D9D>
|
||
-- <20>扯<EFBFBD><E689AF>園𡢿嚗?0銝<30><E98A9D><EFBFBD><EFBFBD><EFBFBD>嚗?-30蝘?
|
||
```
|
||
|
||
### 撖農I撟喳蝱<E596B3><E89DB1>蔣<EFBFBD>?
|
||
|
||
1. **DC璅∪<E79285>嚗<EFBFBD>㺭<EFBFBD>格<EFBFBD>瘣梹<E798A3>**嚗?
|
||
- <20>?<3F>䭾<EFBFBD><E4ADBE>湔𦻖撖遂AV<41>唳旿<E594B3>𡁶<EFBFBD>霈∪<E99C88><E288AA>?
|
||
- <20>?瘥𤩺活皜<E6B4BB><E79A9C><EFBFBD>賡<EFBFBD>閬<EFBFBD><E996AC>"<22>匧像"<22>唳旿嚗𠄌TL餈<4C><E9A488>嚗?
|
||
- <20>梧<EFBFBD> 1000<30>∟扇敶閧<E695B6>皜<EFBFBD><E79A9C>嚗<EFBFBD>虾<EFBFBD>賡<EFBFBD>閬?-10<31><30><EFBFBD>憸<EFBFBD><E686B8><EFBFBD>?
|
||
|
||
2. **SSA璅∪<E79285>嚗<EFBFBD><E59A97>霈∪<E99C88><E288AA>琜<EFBFBD>**嚗?
|
||
- <20>?R/Python<6F>𡁏𧋦<F0A1818F>䭾<EFBFBD><E4ADBE>湔𦻖<E6B994>滢<EFBFBD>EAV銵?
|
||
- <20>?敹<>◆<EFBFBD><E29786>蓮<EFBFBD>V蛹DataFrame<6D>澆<EFBFBD>
|
||
- <20>𩤃<EFBFBD> <20><><EFBFBD>瘨<EFBFBD><E798A8>堒楊憭改<E686AD>10銝<30>扇敶𨰝<E695B6>2-5GB嚗?
|
||
|
||
3. **摰墧𧒄<E5A2A7>峕郊**嚗?
|
||
- <20>?瘥𤩺活靽嘥<E99DBD><E598A5>質圻<E8B3AA>穃<EFBFBD><E7A983>渲扇敶閙䰻霂g<E99C82><EFBD87>g<EFBFBD>
|
||
- <20>𩤃<EFBFBD> 擃㗛<E69383>敶訫<E695B6><E8A8AB>箸艶銝衤<E98A9D><E8A1A4>硋𡆇<E7A18B>唳旿摨?
|
||
|
||
### 閫<><E996AB><EFBFBD>寞<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD><EFBFBD>虾<EFBFBD>改<EFBFBD>
|
||
|
||
#### 蝑𣇉裦A嚗𡁶<E59A97><F0A181B6>𤥁<EFBFBD><F0A4A581>?+ 摰𡁏𧒄<F0A1818F>瑟鰵
|
||
|
||
```sql
|
||
-- <20>𥕦遣摰質”<E8B3AA>拙<EFBFBD>閫<EFBFBD>㦛嚗<E3A69B><E59A97>撠𤩺𧒄<F0A4A9BA>瑟鰵銝<E9B0B5>甈∴<E79488>
|
||
CREATE MATERIALIZED VIEW patient_data_flat AS
|
||
SELECT
|
||
record,
|
||
MAX(CASE WHEN field_name = 'age' THEN value END) AS age,
|
||
MAX(CASE WHEN field_name = 'gender' THEN value END) AS gender,
|
||
-- ... <20>嗡<EFBFBD>摮埈挾
|
||
FROM redcap_data
|
||
WHERE project_id = 123
|
||
GROUP BY record;
|
||
|
||
-- AI撟喳蝱<E596B3>亥砭摰質”嚗<E2809D>翰嚗?
|
||
SELECT * FROM patient_data_flat WHERE age > 50;
|
||
```
|
||
|
||
**<EFBFBD>桅<EFBFBD>**嚗?
|
||
- <20>𩤃<EFBFBD> <20>唳旿撱嗉<E692B1>嚗<EFBFBD><E59A97>憭?撠𤩺𧒄嚗?
|
||
- <20>𩤃<EFBFBD> 摮睃<E691AE>蝛粹𡢿蝧餃<E89DA7>?
|
||
- <20>𩤃<EFBFBD> <20>瑟鰵餈<E9B0B5><E9A488>隡𡁻<E99AA1>銵?
|
||
|
||
#### 蝑𣇉裦B嚗鋫I撟喳蝱靘抒<E99D98>摮?
|
||
|
||
```typescript
|
||
// <20>杗I撟喳蝱PostgreSQL銝剔<E98A9D>摮?<3F>匧像"<22>𡒊<EFBFBD><F0A1928A>唳旿
|
||
model RedcapDataCache {
|
||
id String @id
|
||
projectId String
|
||
recordId String
|
||
flatData Json // 摮睃<E691AE>摰質”<E8B3AA>澆<EFBFBD>
|
||
lastSyncAt DateTime
|
||
|
||
@@unique([projectId, recordId])
|
||
@@index([lastSyncAt])
|
||
}
|
||
|
||
// 憓鮋<E68693><E9AE8B>峕郊蝑𣇉裦
|
||
async function syncFromRedcap(projectId: string) {
|
||
const lastSyncTime = await getLastSyncTime(projectId);
|
||
|
||
// <20>芣䰻霂W<E99C82><EFBCB7>誩<EFBFBD><E8AAA9>湛<EFBFBD><E6B99B>朞<EFBFBD>redcap_log銵剁<E98AB5>
|
||
const changedRecords = await redcapApi.getChangedRecords({
|
||
projectId,
|
||
since: lastSyncTime
|
||
});
|
||
|
||
// <20>寥<EFBFBD><E5AFA5>湔鰵蝻枏<E89DBB>
|
||
await batchUpdateCache(changedRecords);
|
||
}
|
||
```
|
||
|
||
**隡睃飵**嚗?
|
||
- <20>?<3F>亥砭<E4BAA5>笔漲敹恬<E695B9>PostgreSQL JSONB蝝W<E89D9D>嚗?
|
||
- <20>?<3F>誩<EFBFBD>REDCap<61>唳旿摨枏<E691A8><E69E8F>?
|
||
- <20>?<3F>舀<EFBFBD><E88880>冽<EFBFBD><E586BD>𦦵揣<F0A6A6B5><E68FA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>皛?
|
||
|
||
**<EFBFBD>桅<EFBFBD>**嚗?
|
||
- <20>𩤃<EFBFBD> <20>唳旿<E594B3>𦯀<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD>函蕃<E587BD>㵪<EFBFBD>
|
||
- <20>𩤃<EFBFBD> <20>峕郊撱嗉<E692B1>嚗?-30蝘𡜐<E89D98>
|
||
- <20>𩤃<EFBFBD> 蝏湔擪憭齿<E686AD>摨血<E691A8><E8A180>?
|
||
|
||
#### 蝑𣇉裦C嚗鑹EDCap API<50>孵<EFBFBD><E5ADB5><EFBFBD><EFBFBD><EFBFBD>?
|
||
|
||
```php
|
||
// External Module銝哨<E98A9D><E593A8>寥<EFBFBD><E5AFA5>瑕<EFBFBD><E79195>唳旿嚗<E697BF><E59A97>憿蛛<E686BF>
|
||
function getBatchRecords($projectId, $recordIds, $batchSize = 100) {
|
||
$batches = array_chunk($recordIds, $batchSize);
|
||
$allData = [];
|
||
|
||
foreach ($batches as $batch) {
|
||
// 雿輻鍂REDCap API嚗<49>歇隡睃<E99AA1>嚗?
|
||
$data = REDCap::getData([
|
||
'project_id' => $projectId,
|
||
'return_format' => 'json',
|
||
'records' => $batch,
|
||
'exportDataAccessGroups' => false,
|
||
'exportSurveyFields' => false
|
||
]);
|
||
|
||
$allData = array_merge($allData, $data);
|
||
|
||
// <20>踹<EFBFBD>頞<EFBFBD>𧒄
|
||
usleep(100000); // 100ms撱嗉<E692B1>
|
||
}
|
||
|
||
return $allData;
|
||
}
|
||
```
|
||
|
||
### 憌𡡞埯霂<E59FAF>摯
|
||
|
||
| <20><><EFBFBD> | 霂<>摯 | 霂湔<E99C82> |
|
||
|------|------|------|
|
||
| **<EFBFBD>扯<EFBFBD><EFBFBD>園<EFBFBD>** | <20>𣞁 擃㗛<E69383><E3979B>?| <20>唳旿<E594B3>?5銝<35>辺<EFBFBD>嗆<EFBFBD><E59786>?|
|
||
| **<EFBFBD>航圾<EFBFBD>單<EFBFBD>?* | <20>椬 <20>典<EFBFBD> | <20><>閬<EFBFBD><E996AC><EFBFBD><EFBFBD><EFBFBD>蝻枏<E89DBB><E69E8F>嗆<EFBFBD> |
|
||
| **撘<><E69298>烐<EFBFBD><E78390>?* | <20>𣞁 擃?| <20><><EFBFBD>訫<EFBFBD>2-3<>刻挽霈∠<E99C88>摮睃<E691AE> |
|
||
| **餈鞟輕<E99E9F>鞉𧋦** | <20>椬 銝?| <20><>閬<EFBFBD><E996AC><EFBFBD>批<EFBFBD>甇亙辣餈?|
|
||
|
||
---
|
||
|
||
## <20>𣞁 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗鑹EDCap<61><70>𧋦<EFBFBD><F0A78BA6>漣<EFBFBD>?<3F>游<EFBFBD><E6B8B8>?
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
REDCap<EFBFBD>?*敹恍<E695B9>蠘翮隞?*嚗<><E59A97>撟?-4銝芸之<E88AB8><E4B98B>𧋦嚗劐<E59A97>撣行䔉<E8A18C>澆捆<E6BE86>批埯璇艾<E79287>?
|
||
|
||
### <20>笔<EFBFBD>獢<EFBFBD><E78DA2>嚗<EFBFBD><E59A97>瘜芣<E7989C>霈哨<E99C88>
|
||
|
||
#### 獢<><E78DA2>1嚗䥅ook<6F>賣㺭蝑曉<E89D91><E69B89>䀹凒
|
||
|
||
```php
|
||
// REDCap 10.x<><78>𧋦
|
||
function redcap_save_record($project_id, $record, $instrument, $event_id) {
|
||
// 4銝芸<E98A9D><E88AB8>?
|
||
}
|
||
|
||
// REDCap 11.0<EFBFBD><EFBFBD>𧋦嚗?021撟湛<E6929F>
|
||
function redcap_save_record($project_id, $record, $instrument, $event_id,
|
||
$group_id, $survey_hash, $response_id, $repeat_instance) {
|
||
// 蝒<><E89D92><EFBFBD>䀹<EFBFBD>8銝芸<E98A9D><E88AB8>堆<EFBFBD>
|
||
}
|
||
```
|
||
|
||
**敶勗<E695B6>**嚗?
|
||
- <20>?<3F><><EFBFBD>劐<EFBFBD>韏𡝗迨Hook<6F><6B>xternal Module<6C>券<EFBFBD>撏拇<E6928F>
|
||
- <20>梧<EFBFBD> <20><>閬<EFBFBD>揮<EFBFBD>乩耨憭滚僎瘚贝<E7989A>
|
||
- <20><> 憒<><E68692>瘝⊥<E7989D>銝交聢<E4BAA4><E881A2><EFBFBD><EFBFBD>祇<EFBFBD>摰𡄯<E691B0><F0A184AF>煺漣<E785BA>臬<EFBFBD><E887AC>湔𦻖<E6B994><F0A6BB96><EFBFBD>
|
||
|
||
#### 獢<><E78DA2>2嚗鋫PI<50>滚<EFBFBD><E6BB9A>澆<EFBFBD><E6BE86>䀹凒
|
||
|
||
```json
|
||
// REDCap 12.x API<50>滚<EFBFBD>
|
||
{
|
||
"record_id": "PAT001",
|
||
"age": "45",
|
||
"gender": "1" // 摮㛖泵銝脩掩<E884A9>?
|
||
}
|
||
|
||
// REDCap 13.0 API<50>滚<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD>亦掩<E4BAA6>贝蓮<E8B49D>g<EFBFBD>
|
||
{
|
||
"record_id": "PAT001",
|
||
"age": 45, // <20>䀹<EFBFBD><E480B9>湔㺭蝐餃<E89D90>
|
||
"gender": "1" // 隞齿糓摮㛖泵銝?
|
||
}
|
||
```
|
||
|
||
**敶勗<E695B6>**嚗?
|
||
- <20>?蝐餃<E89D90><E9A483>剛<EFBFBD>憭梯揖嚗㇍ypeScript銝交聢璅∪<E79285>嚗?
|
||
- <20>?<3F>唳旿撉諹<E69289><E8ABB9>餉<EFBFBD>憭望<E686AD>
|
||
- <20><> <20>鞱𤪖<E99EB1><F0A4AA96>ug嚗?0" vs 0 撣<><E692A3><EFBFBD>斗鱏<E69697>桅<EFBFBD>嚗?
|
||
|
||
#### 獢<><E78DA2>3嚗𡁏㺭<F0A1818F>桀<EFBFBD>銵函<E98AB5><E587BD><EFBFBD><EFBFBD><EFBFBD>?
|
||
|
||
```sql
|
||
-- REDCap 14.x銋见<E98A8B>
|
||
SELECT * FROM redcap_projects WHERE project_id = 123;
|
||
|
||
-- REDCap 15.0<EFBFBD>啣<EFBFBD>摮埈挾
|
||
ALTER TABLE redcap_projects
|
||
ADD COLUMN project_language VARCHAR(10) DEFAULT 'English';
|
||
|
||
-- 憒<><E68692>雿删<E99BBF>External Module<6C>湔𦻖<E6B994>滢<EFBFBD><E6BBA2>唳旿摨橒<E691A8>
|
||
INSERT INTO redcap_projects (project_id, app_title)
|
||
VALUES (456, 'Test Project');
|
||
-- <20>?<3F>仿<EFBFBD>嚗䮝roject_language摮埈挾NOT NULL蝥行<E89DA5>憭梯揖
|
||
```
|
||
|
||
### 銝滚虾<E6BB9A>扳<EFBFBD>批<EFBFBD><E689B9>?
|
||
|
||
| <20><>漣蝐餃<E89D90> | 憸𤑳<E686B8> | 敶勗<E695B6><E58B97><EFBFBD>凒 | <20>墧<EFBFBD><E5A2A7>曉漲 | 憌𡡞埯蝑厩漣 |
|
||
|---------|------|---------|---------|---------|
|
||
| **憭抒<E686AD><E68A92>砍<EFBFBD>蝥?* | 瘥誩僑3-4甈?| <20>𣞁 <20>券𢒰敶勗<E695B6> | <20>𣞁 <20>圈𠗕 | <20>𣞁<EFBFBD>𣞁<EFBFBD>𣞁<EFBFBD>𣞁<EFBFBD>𣞁 |
|
||
| **撠讐<E692A0><E8AE90>祈‘銝?* | 瘥𤩺<E798A5>1-2甈?| <20>椬 撅<><E69285>典蔣<E585B8>?| <20>椬 銝剔<E98A9D> | <20>椬<EFBFBD>椬<EFBFBD>椬 |
|
||
| **摰匧<E691B0>銵乩<E98AB5>** | 蝝扳<E89D9D>亙<EFBFBD>撣?| <20>叚 頧餃凝敶勗<E695B6> | <20>叚 摰寞<E691B0> | <20>叚<EFBFBD>叚 |
|
||
|
||
### 摨𥪜笆蝑𣇉裦嚗<E8A3A6><E59A97>雿𡡞<E99BBF><F0A1A19E>抬<EFBFBD>
|
||
|
||
#### 蝑𣇉裦1嚗帋艇<E5B88B>潛<EFBFBD><E6BD9B><EFBFBD>𧋦<EFBFBD><F0A78BA6><EFBFBD>
|
||
|
||
```json
|
||
// config.json銝剜<E98A9D>蝖桀ㄟ<E6A180>𤾸<EFBFBD>摰寧<E691B0><E5AFA7>?
|
||
{
|
||
"name": "AI Research Assistant",
|
||
"framework-version": 16,
|
||
"compatibility": {
|
||
"redcap-version-min": "15.8.0",
|
||
"redcap-version-max": "15.9.99",
|
||
"php-version-min": "7.4",
|
||
"php-version-max": "8.2"
|
||
}
|
||
}
|
||
```
|
||
|
||
```php
|
||
// <20>冽芋<E586BD>堒<EFBFBD>憪见<E686AA><E8A781>嗆<EFBFBD><E59786>亦<EFBFBD><E4BAA6>?
|
||
public function __construct() {
|
||
$redcapVersion = REDCAP_VERSION;
|
||
$minVersion = '15.8.0';
|
||
$maxVersion = '15.9.99';
|
||
|
||
if (version_compare($redcapVersion, $minVersion, '<') ||
|
||
version_compare($redcapVersion, $maxVersion, '>')) {
|
||
throw new Exception(
|
||
"甇斗芋<EFBFBD>𦯀<EFBFBD><EFBFBD>舀<EFBFBD>REDCap {$minVersion} - {$maxVersion}嚗? .
|
||
"敶枏<EFBFBD><EFBFBD><EFBFBD>𧋦嚗㝯$redcapVersion}"
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 蝑𣇉裦2嚗𡁏<E59A97>撠誩<E692A0><E8AAA9>湔𦻖靘肽<E99D98>
|
||
|
||
```php
|
||
// <20>?<3F>躰秤嚗𡁶凒<F0A181B6>交<EFBFBD>雿𨀣㺭<F0A880A3>桀<EFBFBD>
|
||
$sql = "SELECT * FROM redcap_data WHERE project_id = $pid";
|
||
$result = db_query($sql);
|
||
|
||
// <20>?甇<>&嚗帋蝙<E5B88B>沖EDCap撠<70><E692A0><EFBFBD><EFBFBD>PI
|
||
$data = REDCap::getData($pid, 'array');
|
||
```
|
||
|
||
**<EFBFBD>笔<EFBFBD>**嚗?
|
||
- REDCap API隡𡁜<E99AA1><F0A1819C><EFBFBD><EFBFBD><EFBFBD>砍<EFBFBD>摰寞<E691B0>?
|
||
- <20>湔𦻖<E6B994>滢<EFBFBD><E6BBA2>唳旿摨梶<E691A8>餈<EFBFBD><E9A488>REDCap<61><70><EFBFBD><EFBFBD>文<EFBFBD>
|
||
|
||
#### 蝑𣇉裦3嚗𡁜<E59A97><F0A1819C><EFBFBD><EFBFBD><EFBFBD>𧼮<EFBFBD>瘚贝<E7989A>
|
||
|
||
```bash
|
||
# CI/CD Pipeline嚗<65><E59A97>甈∪<E79488>蝥批<E89DA5>頝𡢅<E9A09D>
|
||
tests/
|
||
<EFBFBD>鎿<EFBFBD><EFBFBD><EFBFBD> integration/
|
||
<EFBFBD>? <20>鎿<EFBFBD><E98EBF><EFBFBD> test_redcap_15.8.0.php # 敶枏<E695B6><E69E8F><EFBFBD>𧋦瘚贝<E7989A>
|
||
<EFBFBD>? <20>鎿<EFBFBD><E98EBF><EFBFBD> test_redcap_15.9.0.php # 憸<><E686B8>霂蓥<E99C82>銝<EFBFBD><E98A9D><EFBFBD>𧋦
|
||
<EFBFBD>? <20>婙<EFBFBD><E5A999><EFBFBD> test_redcap_16.0.0.php # 憸<><E686B8>霂閙𧊋<E99699>亦<EFBFBD><E4BAA6>?
|
||
<EFBFBD>鎿<EFBFBD><EFBFBD><EFBFBD> api/
|
||
<EFBFBD>? <20>鎿<EFBFBD><E98EBF><EFBFBD> test_export_records.php
|
||
<EFBFBD>? <20>婙<EFBFBD><E5A999><EFBFBD> test_import_records.php
|
||
<EFBFBD>婙<EFBFBD><EFBFBD><EFBFBD> hooks/
|
||
<20>鎿<EFBFBD><E98EBF><EFBFBD> test_save_record.php
|
||
<20>婙<EFBFBD><E5A999><EFBFBD> test_every_page_top.php
|
||
```
|
||
|
||
```php
|
||
// <20>芸𢆡<E88AB8>𡝗<EFBFBD>霂閧內靘?
|
||
class RedcapCompatibilityTest extends TestCase {
|
||
public function testSaveRecordHook() {
|
||
// 璅⊥<E79285>REDCap靚<70>鍂Hook
|
||
$result = $this->module->redcap_save_record(
|
||
123, 'PAT001', 'demographics', 1,
|
||
null, null, null, null
|
||
);
|
||
|
||
$this->assertNotNull($result);
|
||
$this->assertTrue($result['success']);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 蝑𣇉裦4嚗𡁜<E59A97>蝥折<E89DA5>蝳餌㴓憓?
|
||
|
||
```
|
||
<EFBFBD>煺漣<EFBFBD>臬<EFBFBD>嚗㇌EDCap 15.8.0嚗?
|
||
<20>?
|
||
憸<EFBFBD><EFBFBD>鈭抒㴓憓<EFBFBD><EFBFBD>REDCap 15.9.0嚗争<EFBFBD> <20><><EFBFBD>蝥扳<E89DA5>霂?
|
||
<20>?
|
||
撘<EFBFBD><EFBFBD>𤑳㴓憓<EFBFBD><EFBFBD>REDCap 16.0.0嚗? <20>?<3F>𣂼<EFBFBD><F0A382BC><EFBFBD><EFBFBD>
|
||
```
|
||
|
||
**瘚<><E7989A>**嚗?
|
||
1. REDCap摰䀹䲮<E480B9>穃<EFBFBD><E7A983>啁<EFBFBD><E59581>?
|
||
2. <20>典<EFBFBD><E585B8>𤑳㴓憓<E3B493><E68693>鋆<EFBFBD>僎瘚贝<E7989A>嚗?<3F>剁<EFBFBD>
|
||
3. 憸<><E686B8>鈭抒㴓憓<E3B493><E68693>霂<EFBFBD><E99C82>1<EFBFBD>剁<EFBFBD>
|
||
4. <20>煺漣<E785BA>臬<EFBFBD><E887AC><EFBFBD>漣嚗<E6BCA3>恣<EFBFBD>鍦<EFBFBD><E98DA6>箇<EFBFBD><E7AE87><EFBFBD><EFBFBD>
|
||
|
||
### 憌𡡞埯霂<E59FAF>摯
|
||
|
||
| <20><><EFBFBD> | 霂<>摯 | 霂湔<E99C82> |
|
||
|------|------|------|
|
||
| **銝滚虾<E6BB9A>扳<EFBFBD>?* | <20>𣞁 <20><><EFBFBD> | REDCap<61><70>漣<EFBFBD>園𡢿銝滨眏<E6BBA8>睲賑<E79DB2>喳<EFBFBD> |
|
||
| **敶勗<E695B6><E58B97><EFBFBD>凒** | <20>𣞁 <20>券𢒰 | <20>航<EFBFBD><E888AA>游<EFBFBD><E6B8B8><EFBFBD><EFBFBD>厰<EFBFBD><E58EB0>𣂼<EFBFBD><F0A382BC>?|
|
||
| **摨𥪜笆<F0A5AA9C>鞉𧋦** | <20>𣞁 擃?| 瘥𤩺活<F0A4A9BA><E6B4BB>漣<EFBFBD><E6BCA3><EFBFBD>訫<EFBFBD>1-2<>冽<EFBFBD>霂?|
|
||
| **<EFBFBD>踵<EFBFBD>蝏湔擪** | <20>𣞁 擃?| 蝏<>澈隡湧<E99AA1><E6B9A7><EFBFBD>輕<EFBFBD>方<EFBFBD><E696B9>?|
|
||
|
||
---
|
||
|
||
## <20>椬 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗𡁏㺭<F0A1818F>桐<EFBFBD><E6A190>湔<EFBFBD>抒<EFBFBD>"<22><>仍<EFBFBD>?
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
敶𣫮EDCap<EFBFBD>淾I撟喳蝱**<2A>峕𧒄**摮睃<E691AE><E79D83>唳旿<E594B3>塚<EFBFBD>隡𡁻𢒰銝渡<E98A9D><E6B8A1>貊<EFBFBD>**<2A><><EFBFBD>撘譍<E69298><E8AD8D>湔<EFBFBD>折䔮憸?*<2A>?
|
||
|
||
### 銝<><E98A9D>湔<EFBFBD>批㦤<E689B9>臬<EFBFBD><E887AC>?
|
||
|
||
#### <20>箸艶1嚗𡁜<E59A97><F0A1819C>穃<EFBFBD>甇亦<E79487><E4BAA6>脩<EFBFBD>
|
||
|
||
```
|
||
<EFBFBD>園𡢿頧湛<EFBFBD>
|
||
T1: <20>冽<EFBFBD>A<EFBFBD>沖EDCap靽格㺿<E6A0BC><E3BABF><EFBFBD><EFBFBD>AT001<30><31>僑樴<E58391>蛹45撗?
|
||
<20>?External Module<6C>券<EFBFBD><E588B8><EFBFBD>AI撟喳蝱
|
||
|
||
T2: <20>冽<EFBFBD>B<EFBFBD>杗I撟喳蝱DC璅∪<E79285>皜<EFBFBD><E79A9C><EFBFBD>唳旿嚗<E697BF><E59A97><EFBFBD>啣僑樴<E58391><E6A8B4>撣賂<E692A3>靽格㺿銝?6撗?
|
||
<20>?<3F>𧼮<EFBFBD><F0A7BCAE>訌EDCap嚗?
|
||
|
||
T3: REDCap銝剖僑樴<E58391>緵<EFBFBD>冽糓嚗?5餈䀹糓46嚗?
|
||
<20>?憒<><E68692>瘝⊥<E7989D><E28AA5>脩<EFBFBD>閫<EFBFBD><E996AB><EFBFBD>箏<EFBFBD>嚗峕㺭<E5B395>桐<EFBFBD>銝<EFBFBD><E98A9D>湛<EFBFBD>
|
||
```
|
||
|
||
#### <20>箸艶2嚗𡁜<E59A97>甇亙辣餈笔紡<E7AC94>渡<EFBFBD><E6B8A1>讛粉
|
||
|
||
```
|
||
T1: <20>冽<EFBFBD><E586BD>沖EDCap敶訫<E695B6>摰峕㟲<E5B395><E39FB2><EFBFBD>嚗?0銝芾”<E88ABE>𤏪<EFBFBD>50銝芸<E98A9D>畾蛛<E795BE>
|
||
<20>?瘥譍葵摮埈挾靽嘥<E99DBD><E598A5>園<EFBFBD>閫血<E996AB>redcap_save_record
|
||
<20>?External Module<6C>券<EFBFBD>?0甈∪<E79488>AI撟喳蝱
|
||
|
||
T2: AI撟喳蝱<E596B3>交𤣰鈭<F0A4A3B0><E988AD>30銝芸<E98A9D>畾蛛<E795BE><E89B9B>?0銝芸<E98A9D>畾菔<E795BE><E88F94>其<EFBFBD>颲㮖葉
|
||
<20>?<3F>冽<EFBFBD><E586BD>杗I撟喳蝱<E596B3>亦<EFBFBD><E4BAA6><EFBFBD><EFBFBD>嚗𡁏遬蝷箔<E89DB7>摰峕㟲<E5B395>唳旿
|
||
<20>?<3F>冽<EFBFBD>霂臭誑銝箸㺭<E7AEB8>桐腺憭梧<E686AD><E6A2A7>齿活敶訫<E695B6>
|
||
|
||
T3: <20>?0銝芸<E98A9D>畾萄<E795BE>颲橘<E9A2B2>雿<EFBFBD>鍂<EFBFBD>瑕歇蝏誯<E89D8F>憭滚<E686AD><E6BB9A>?
|
||
<20>?<3F>唳旿<E594B3>滚<EFBFBD>嚗?
|
||
```
|
||
|
||
#### <20>箸艶3嚗𡁶<E59A97>蝏𨀣<E89D8F><F0A880A3>𨅯紡<F0A885AF>渡<EFBFBD><E6B8A1>唳旿銝W仃
|
||
|
||
```
|
||
T1: <20>冽<EFBFBD><E586BD>沖EDCap靽嘥<E99DBD><E598A5>唳旿
|
||
<20>?External Module<6C>券<EFBFBD><E588B8><EFBFBD>AI撟喳蝱
|
||
<20>?蝵𤑳<E89DB5>頞<EFBFBD>𧒄嚗㇌EDCap<61>淾I撟喳蝱銋钅𡢿<E99285><F0A1A2BF><EFBFBD>蝏靝<E89D8F>蝔喳<E89D94>嚗?
|
||
|
||
T2: External Module<6C>嗅<EFBFBD>頞<EFBFBD>𧒄<EFBFBD>躰秤
|
||
<20>?<3F>臬炏<E887AC>滩<EFBFBD>嚗罸<E59A97>霂訫<E99C82>甈∴<E79488>
|
||
<20>?憒<><E68692><EFBFBD>滩<EFBFBD>嚗䔶<E59A97>銝滢<E98A9D>撖潸稲<E6BDB8>滚<EFBFBD><E6BB9A>坔<EFBFBD>嚗?
|
||
|
||
T3: AI撟喳蝱<E596B3>唳旿蝻箏仃
|
||
<20>?<3F>𡒊賒<F0A1928A><E8B392><EFBFBD>蝏𤘪<E89D8F>銝滚<E98A9D>蝖?
|
||
```
|
||
|
||
### 銝<><E98A9D>湔<EFBFBD>找<EFBFBD>霂<EFBFBD><E99C82><EFBFBD>?
|
||
|
||
#### 蝑𣇉裦A嚗𡁜<E59A97>蝑㗇<E89D91>扯挽霈∴<E99C88>Idempotency嚗?
|
||
|
||
```typescript
|
||
// AI撟喳蝱Webhook<6F>交𤣰<E4BAA4>剁<EFBFBD>撟<EFBFBD><E6929F><EFBFBD>找<EFBFBD>霂<EFBFBD><E99C82>
|
||
async function receiveRecordUpdate(req, res) {
|
||
const { project_id, record_id, data, timestamp } = req.body;
|
||
|
||
// <20><><EFBFBD>撟<EFBFBD><E6929F><EFBFBD>免ey嚗<79>俈甇a<E79487>憭滚<E686AD><E6BB9A><EFBFBD><EFBFBD>
|
||
const idempotencyKey = `${project_id}:${record_id}:${timestamp}`;
|
||
|
||
// 璉<><E79289>交糓<E4BAA4>血歇憭<E6AD87><E686AD>餈?
|
||
const existing = await prisma.redcapSyncRecord.findUnique({
|
||
where: { idempotencyKey }
|
||
});
|
||
|
||
if (existing) {
|
||
// 撌脣<E6928C><E884A3><EFBFBD><EFBFBD>嚗𣬚凒<F0A3AC9A>亥<EFBFBD><E4BAA5>墧<EFBFBD><E5A2A7>?
|
||
return res.send({
|
||
success: true,
|
||
message: '<27>唳旿撌脣<E6928C><E884A3>剁<EFBFBD>撟<EFBFBD><E6929F><EFBFBD>改<EFBFBD>'
|
||
});
|
||
}
|
||
|
||
// <20>笔<EFBFBD><E7AC94>扳<EFBFBD>雿頣<E99BBF><E9A0A3>𥕦遣<F0A595A6>峕郊霈啣<E99C88>+<2B>湔鰵<E6B994>唳旿
|
||
await prisma.$transaction(async (tx) => {
|
||
// 1. <20>𥕦遣<F0A595A6>峕郊霈啣<E99C88>嚗<EFBFBD>蒂<EFBFBD>臭<EFBFBD>蝥行<E89DA5>嚗?
|
||
await tx.redcapSyncRecord.create({
|
||
data: {
|
||
idempotencyKey,
|
||
projectId: project_id,
|
||
recordId: record_id,
|
||
redcapData: data,
|
||
status: 'success',
|
||
syncedAt: new Date()
|
||
}
|
||
});
|
||
|
||
// 2. <20>湔鰵銝𡁜𦛚<F0A1819C>唳旿
|
||
await tx.patientData.upsert({
|
||
where: { recordId: record_id },
|
||
update: data,
|
||
create: data
|
||
});
|
||
});
|
||
|
||
return res.send({ success: true });
|
||
}
|
||
```
|
||
|
||
#### 蝑𣇉裦B嚗𡁶<E59A97><F0A181B6>砍噡<E7A08D>箏<EFBFBD>嚗㇉ptimistic Locking嚗?
|
||
|
||
```typescript
|
||
// 瘥𤩺辺霈啣<E99C88><E595A3>賣<EFBFBD><E8B3A3><EFBFBD>𧋦<EFBFBD>?
|
||
model PatientData {
|
||
recordId String @id
|
||
age Int
|
||
gender String
|
||
version Int @default(0) // <20><>𧋦<EFBFBD>?
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@index([version])
|
||
}
|
||
|
||
// <20>湔鰵<E6B994>嗆<EFBFBD><E59786>亦<EFBFBD><E4BAA6>砍噡
|
||
async function updateRecord(recordId: string, newData: any, expectedVersion: number) {
|
||
const result = await prisma.patientData.updateMany({
|
||
where: {
|
||
recordId,
|
||
version: expectedVersion // <20>芣<EFBFBD><E88AA3><EFBFBD>𧋦<EFBFBD>瑕龪<E79195>齿<EFBFBD><E9BDBF>湔鰵
|
||
},
|
||
data: {
|
||
...newData,
|
||
version: expectedVersion + 1 // <20><>𧋦<EFBFBD>?1
|
||
}
|
||
});
|
||
|
||
if (result.count === 0) {
|
||
// <20><>𧋦<EFBFBD>瑚<EFBFBD><E7919A>寥<EFBFBD>嚗諹秩<E8ABB9>擧<EFBFBD><E693A7>脩<EFBFBD>
|
||
throw new ConflictError('<EFBFBD>唳旿撌脰◤<EFBFBD>嗡<EFBFBD><EFBFBD>冽<EFBFBD>靽格㺿嚗諹窈<EFBFBD>瑟鰵<EFBFBD>𡡞<EFBFBD>霂?);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 蝑𣇉裦C嚗𡁏<E59A97>蝏<EFBFBD><E89D8F><EFBFBD>湔<EFBFBD>?+ <20>脩<EFBFBD><E884A9>亙<EFBFBD>
|
||
|
||
```typescript
|
||
// <20>脩<EFBFBD>閫<EFBFBD><E996AB>蝑𣇉裦嚗朞扇敶閙<E695B6><E99699>匧<EFBFBD>蝒<EFBFBD><E89D92>鈭箏極鋆<E6A5B5><E98B86>
|
||
model DataConflict {
|
||
id String @id @default(cuid())
|
||
recordId String
|
||
fieldName String
|
||
|
||
redcapValue String // REDCap銝剔<E98A9D><E58994>?
|
||
aiPlatformValue String // AI撟喳蝱銝剔<E98A9D><E58994>?
|
||
|
||
redcapTimestamp DateTime // REDCap靽格㺿<E6A0BC>園𡢿
|
||
aiPlatformTimestamp DateTime // AI撟喳蝱靽格㺿<E6A0BC>園𡢿
|
||
|
||
status String // pending, resolved, ignored
|
||
resolution String? // 鈭箏極鋆<E6A5B5><E98B86>蝏𤘪<E89D8F>
|
||
resolvedBy String?
|
||
resolvedAt DateTime?
|
||
|
||
createdAt DateTime @default(now())
|
||
}
|
||
|
||
// 璉<>瘚见<E7989A>蝒?
|
||
async function detectConflict(recordId: string) {
|
||
const redcapData = await fetchFromRedcap(recordId);
|
||
const aiPlatformData = await fetchFromAIPlatform(recordId);
|
||
|
||
const conflicts = [];
|
||
|
||
for (const field of Object.keys(redcapData)) {
|
||
if (redcapData[field] !== aiPlatformData[field]) {
|
||
conflicts.push({
|
||
recordId,
|
||
fieldName: field,
|
||
redcapValue: redcapData[field],
|
||
aiPlatformValue: aiPlatformData[field],
|
||
redcapTimestamp: redcapData._timestamp,
|
||
aiPlatformTimestamp: aiPlatformData._timestamp
|
||
});
|
||
}
|
||
}
|
||
|
||
if (conflicts.length > 0) {
|
||
// 霈啣<E99C88><E595A3>脩<EFBFBD>嚗𣬚<E59A97>敺<EFBFBD>犖撌亙<E6928C><E4BA99>?
|
||
await prisma.dataConflict.createMany({ data: conflicts });
|
||
|
||
// <20>煾<EFBFBD><E785BE><EFBFBD>霅阡<E99C85>𡁶䰻
|
||
await notifyAdmin('璉<>瘚见<E7989A><E8A781>唳旿<E594B3>脩<EFBFBD>', { recordId, conflicts });
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 蝑𣇉裦D嚗𡁜<E59A97><F0A1819C>睲蜓隞擧芋撘𧶏<E69298><F0A7B68F>滢<EFBFBD>憭齿<E686AD>摨佗<E691A8>
|
||
|
||
```
|
||
<EFBFBD>㗇𥋘銝<EFBFBD>銝?銝餌頂蝏?嚗𠄎ource of Truth嚗㚁<E59A97>
|
||
|
||
<EFBFBD>寞<EFBFBD>1嚗鑹EDCap銝箔蜓
|
||
- <20>唳旿敶訫<E695B6>嚗𡁜蘨<F0A1819C>沖EDCap銝剛<E98A9D>銵?
|
||
- AI撟喳蝱嚗𡁜蘨霂餅芋撘𧶏<E69298>銝滚<E98A9D>霈訾耨<E8A8BE>孵<EFBFBD>憪𧢲㺭<F0A7A2B2>?
|
||
- AI憭<49><E686AD>蝏𤘪<E89D8F>嚗𡁜<E59A97><F0A1819C>典銁<E585B8>閧𡠺<E996A7><F0A1A0BA>”銝哨<E98A9D>銝滚<E98A9D><E6BB9A>筻EDCap
|
||
|
||
隡睃飵嚗?
|
||
<20>?銝<><E98A9D>湔<EFBFBD>折䔮憸䀹<E686B8>憭?
|
||
<20>?<3F>嗆<EFBFBD>蝞<EFBFBD><E89D9E>?
|
||
<20>?<3F>扯<EFBFBD>憟?
|
||
|
||
<20><>飵嚗?
|
||
<20>?AI撟喳蝱<E596B3><E89DB1>㺭<EFBFBD>格<EFBFBD>瘣㛖<E798A3><E39B96>𨀣<EFBFBD>瘜閗䌊<E99697>典<EFBFBD><E585B8>?
|
||
<20>?<3F>冽<EFBFBD>雿㯄<E99BBF><E3AF84>脰<EFBFBD>嚗<EFBFBD>舅銝芰頂蝏<E9A082>䔉<EFBFBD>𧼮<EFBFBD><F0A7BCAE>g<EFBFBD>
|
||
|
||
<EFBFBD>寞<EFBFBD>2嚗鋫I撟喳蝱銝箔蜓
|
||
- <20>唳旿敶訫<E695B6>嚗𡁻<E59A97>朞<EFBFBD>AI撟喳蝱<E596B3>屸𢒰嚗<F0A292B0><E59A97>撋朙EDCap iFrame<6D>䨝PI嚗?
|
||
- REDCap嚗帋<E59A97>銝箏<E98A9D>撅<EFBFBD><E69285><EFBFBD>剁<EFBFBD><E58981>朞<EFBFBD>API<50>滢<EFBFBD>
|
||
- 蝏煺<E89D8F><E785BA>杗I撟喳蝱憭<E89DB1><E686AD><EFBFBD><EFBFBD><EFBFBD>劐<EFBFBD><E58A90>⊿<EFBFBD>餉<EFBFBD>
|
||
|
||
隡睃飵嚗?
|
||
<20>?<3F>冽<EFBFBD>雿㯄<E99BBF>蝏煺<E89D8F>
|
||
<20>?<3F>臭誑<E887AD><E8AA91><EFBFBD><EFBFBD>拍鍂AI<41>賢<EFBFBD>
|
||
|
||
<20><>飵嚗?
|
||
<20>?<3F><>閬<EFBFBD><E996AC>撱摧EDCap<61><70><EFBFBD><EFBFBD>务I嚗<49>極雿𣈯<E99BBF>撌典之嚗?
|
||
<20>?憭勗縧REDCap<61><70>”<EFBFBD>閗挽霈∪膥蝑㗇瓲敹<E793B2><E695B9><EFBFBD>?
|
||
```
|
||
|
||
### 憌𡡞埯霂<E59FAF>摯
|
||
|
||
| <20><><EFBFBD> | 霂<>摯 | 霂湔<E99C82> |
|
||
|------|------|------|
|
||
| **憭齿<E686AD>摨?* | <20>𣞁 擃?| <20><><EFBFBD>撘譍<E69298><E8AD8D>湔<EFBFBD>扳糓霈∠<E99C88><E288A0>箇<EFBFBD>摮阡𠗕憸?|
|
||
| **<EFBFBD>舀綉<EFBFBD>?* | <20>椬 銝?| <20>臭誑霈曇恣蝑𣇉裦嚗䔶<E59A97><E494B6>䭾<EFBFBD>100%<25>踹<EFBFBD> |
|
||
| **撘<><E69298>烐<EFBFBD><E78390>?* | <20>椬 銝?| <20><>閬?-3<>刻挽霈?瘚贝<E7989A> |
|
||
| **<EFBFBD>冽<EFBFBD>敶勗<EFBFBD>** | <20>椬 銝?| <20>航<EFBFBD><E888AA><EFBFBD>閬<EFBFBD>犖撌乩<E6928C><E4B9A9>亥圾<E4BAA5>喳<EFBFBD>蝒?|
|
||
|
||
**撱箄悅**嚗?
|
||
- <20>㴓 **隡睃<E99AA1><E79D83>刻<EFBFBD><E588BB>寞<EFBFBD>1嚗㇌EDCap銝箔蜓嚗<E89C93><E59A97><EFBFBD>穃<EFBFBD>甇伐<E79487>**
|
||
- <20>𩤃<EFBFBD> <20>踹<EFBFBD><E8B8B9><EFBFBD><EFBFBD>摰墧𧒄<E5A2A7>峕郊嚗<E9838A><E59A97><EFBFBD><EFBFBD>漲<EFBFBD><E6BCB2><EFBFBD>嚗?
|
||
- <20><> 憒<><E68692>敹<EFBFBD>◆<EFBFBD><E29786><EFBFBD>嚗䔶蝙<E494B6>?*<2A><>蝏<EFBFBD><E89D8F><EFBFBD>湔<EFBFBD>?鈭箏極摰⊥瓲**璅∪<E79285>
|
||
|
||
---
|
||
|
||
## <20>椬 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗鋫PI<50>鞉<EFBFBD>銝擧鸌<E693A7>𤩺<EFBFBD>雿𨀣<E99BBF>扯<EFBFBD>
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
REDCap API<50>厰<EFBFBD><E58EB0>怎<EFBFBD>**<2A>毺<EFBFBD><E6AFBA>𣂼<EFBFBD>**嚗峕鸌<E5B395>𤩺<EFBFBD>雿𨀣𧒄摰寞<E691B0>閫血<E996AB><E8A180>?
|
||
|
||
### <20>鞉<EFBFBD>閫<EFBFBD><E996AB>嚗<EFBFBD>𧊋<EFBFBD>砍<EFBFBD><E7A08D><EFBFBD>﹝嚗?
|
||
|
||
```
|
||
<EFBFBD>寞旿蝷曉躹<EFBFBD>漤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>瘚页<EFBFBD>
|
||
- 瘥讐<E798A5>霂瑟<E99C82><E7919F>堆<EFBFBD>QPS嚗㚁<E59A97>~10-50甈∴<E79488><E288B4>硋<EFBFBD>鈭擧<E988AD><E693A7>∪膥<E288AA>滨蔭嚗?
|
||
- <20>閙活撖澆枂霈啣<E99C88><E595A3>堆<EFBFBD>撱箄悅<1000<30>?
|
||
- <20>閙活撖澆<E69296>霈啣<E99C88><E595A3>堆<EFBFBD>撱箄悅<500<30>?
|
||
- 撟嗅<E6929F>餈墧𦻖<E5A2A7>堆<EFBFBD>~5-10銝?
|
||
- 頞<>𧒄<EFBFBD>園𡢿嚗?0-60蝘?
|
||
|
||
頞<EFBFBD>枂<EFBFBD>𣂼<EFBFBD>嚗?
|
||
- HTTP 429 (Too Many Requests)
|
||
- <20>𣇉凒<F0A38789>亥<EFBFBD><E4BAA5>嗆<EFBFBD><E59786>滚<EFBFBD>
|
||
```
|
||
|
||
### <20>笔<EFBFBD><E7AC94>箸艶<E7AEB8>桅<EFBFBD>
|
||
|
||
#### <20>箸艶1嚗𡁜<E59A97><F0A1819C>誩<EFBFBD>甇?0銝<30>辺霈啣<E99C88>
|
||
|
||
```php
|
||
// <20>?<3F>躰秤<E8BAB0>𡁏<EFBFBD>嚗帋<E59A97>甈⊥<E79488>批紡<E689B9>箏<EFBFBD><E7AE8F>?
|
||
$data = $redcapApi->exportRecords([
|
||
'format' => 'json',
|
||
'type' => 'flat'
|
||
]);
|
||
// 蝏𤘪<E89D8F>嚗朞<E59A97><E69C9E>嗚<EFBFBD><E5979A><EFBFBD>摮䀹滯<E480B9>箝<EFBFBD><E7AE9D><EFBFBD><EFBFBD>∪膥撏拇<E6928F>
|
||
```
|
||
|
||
```php
|
||
// <20>?甇<>&<EFBFBD>𡁏<EFBFBD>嚗𡁜<E59A97>憿?<3F>鞉<EFBFBD>
|
||
function exportAllRecords($projectId, $batchSize = 500) {
|
||
$offset = 0;
|
||
$allData = [];
|
||
|
||
while (true) {
|
||
// <20><>鸌撖澆枂
|
||
$batch = $redcapApi->exportRecords([
|
||
'format' => 'json',
|
||
'records' => range($offset, $offset + $batchSize - 1)
|
||
]);
|
||
|
||
if (empty($batch)) break;
|
||
|
||
$allData = array_merge($allData, $batch);
|
||
$offset += $batchSize;
|
||
|
||
// <20>鞉<EFBFBD>嚗𡁏<E59A97><F0A1818F>寥𡢿<E5AFA5>?蝘?
|
||
sleep(2);
|
||
|
||
// 餈𥕦漲<F0A595A6>亙<EFBFBD>
|
||
$progress = count($allData);
|
||
error_log("撌脣紡<EFBFBD>?{$progress} <20>∟扇敶?);
|
||
}
|
||
|
||
return $allData;
|
||
}
|
||
|
||
// 10銝<30>辺霈啣<E99C88> = 200<30>?<3F> 2蝘?= 6.7<EFBFBD><EFBFBD><EFBFBD>
|
||
```
|
||
|
||
#### <20>箸艶2嚗𡁜<E59A97><F0A1819C>嗅<EFBFBD>甇仿<E79487>憸穃<E686B8><E7A983>?
|
||
|
||
```
|
||
<EFBFBD>駁堺<EFBFBD>箸艶嚗?
|
||
- 20銝芰<E98A9D>蝛嗅𨭌<E59785>见<EFBFBD><E8A781>嗅<EFBFBD><E59785>交㺭<E4BAA4>?
|
||
- 瘥譍犖瘥誩<E798A5><E8AAA9>煺<EFBFBD>摮?甈?
|
||
- <20>舔PS = 20 <20> 5 / 60 <20>?1.67甈?蝘?
|
||
|
||
<EFBFBD>贝絲<EFBFBD>乩<EFBFBD>擃矋<EFBFBD>雿<EFBFBD><EFBFBD>
|
||
- 瘥𤩺活靽嘥<E99DBD>閫血<E996AB>redcap_save_record Hook
|
||
- Hook靚<6B>鍂AI撟喳蝱API嚗<49><E59A97>埈𧒄500ms嚗?
|
||
- 憒<><E68692>Hook<6F>扯<EFBFBD><E689AF>園𡢿>1蝘𡜐<E89D98>隡𡁻獈憛冚EDCap<61>滚<EFBFBD>
|
||
- <20>冽<EFBFBD><E586BD>蠘<EFBFBD>"<22>⊿▼"
|
||
```
|
||
|
||
**閫<><E996AB><EFBFBD>寞<EFBFBD>嚗𡁜<E59A97>甇亙<E79487>**
|
||
|
||
```php
|
||
// <20>?<3F>躰秤嚗𡁜<E59A97>甇亥<E79487><E4BAA5>剁<EFBFBD><E58981>餃<EFBFBD>嚗?
|
||
function redcap_save_record($project_id, $record, ...) {
|
||
$data = REDCap::getData($project_id, 'array', $record);
|
||
|
||
// <20>峕郊HTTP霂瑟<E99C82>嚗<EFBFBD>獈憛?-5蝘𡜐<E89D98>
|
||
$this->apiClient->post('/webhook/records', $data);
|
||
}
|
||
|
||
// <20>?甇<>&嚗𡁜<E59A97>甇仿<E79487><E4BBBF>?
|
||
function redcap_save_record($project_id, $record, ...) {
|
||
// 蝡见朖餈𥪜<E9A488>嚗䔶<E59A97><E494B6>餃<EFBFBD>
|
||
$this->enqueueSync($project_id, $record);
|
||
}
|
||
|
||
function enqueueSync($project_id, $record) {
|
||
// <20>坔<EFBFBD><E59D94>砍𧑐<E7A08D>笔<EFBFBD>銵?
|
||
db_query("INSERT INTO em_sync_queue (project_id, record, status)
|
||
VALUES (?, ?, 'pending')", [$project_id, $record]);
|
||
}
|
||
|
||
// Cron隞餃𦛚瘥誩<E798A5><E8AAA9>笔<EFBFBD><E7AC94><EFBFBD><EFBFBD><EFBFBD>?
|
||
function processSyncQueue() {
|
||
$queue = db_query("SELECT * FROM em_sync_queue
|
||
WHERE status = 'pending'
|
||
LIMIT 100");
|
||
|
||
foreach ($queue as $item) {
|
||
try {
|
||
$data = REDCap::getData($item['project_id'], 'array', $item['record']);
|
||
$this->apiClient->post('/webhook/records', $data);
|
||
|
||
// <20><>扇<EFBFBD>𣂼<EFBFBD>
|
||
db_query("UPDATE em_sync_queue SET status = 'success'
|
||
WHERE id = ?", [$item['id']]);
|
||
} catch (Exception $e) {
|
||
// <20><>扇憭梯揖
|
||
db_query("UPDATE em_sync_queue SET status = 'failed', error = ?
|
||
WHERE id = ?", [$e->getMessage(), $item['id']]);
|
||
}
|
||
|
||
// <20>鞉<EFBFBD>
|
||
usleep(500000); // 500ms
|
||
}
|
||
}
|
||
```
|
||
|
||
### 憌𡡞埯霂<E59FAF>摯
|
||
|
||
| <20><><EFBFBD> | 霂<>摯 | 霂湔<E99C82> |
|
||
|------|------|------|
|
||
| **<EFBFBD>扯<EFBFBD><EFBFBD>園<EFBFBD>** | <20>椬 銝?| 憭扳㺭<E689B3>桅<EFBFBD><E6A185>嗆<EFBFBD><E59786>?|
|
||
| **<EFBFBD>舀綉<EFBFBD>?* | <20>?<3F>舀綉 | <20>舫<EFBFBD>朞<EFBFBD><E69C9E><EFBFBD>鸌+<2B>鞉<EFBFBD>閫<EFBFBD><E996AB> |
|
||
| **撘<><E69298>烐<EFBFBD><E78390>?* | <20>叚 雿?| 1-2憭拙<E686AD><E68B99>?|
|
||
| **<EFBFBD>冽<EFBFBD>敶勗<EFBFBD>** | <20>叚 雿?| <20>冽<EFBFBD><E586BD>䭾<EFBFBD><E4ADBE>伐<EFBFBD>撘<EFBFBD>郊憭<E9838A><E686AD>嚗?|
|
||
|
||
---
|
||
|
||
## <20>𣞁 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗鍃xternal Module獢<65>沲<EFBFBD><E6B2B2><EFBFBD><EFBFBD>?
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
External Module獢<65>沲<EFBFBD>賜<EFBFBD>撘箏之嚗䔶<E59A97><E494B6>?*銝滚虾<E6BB9A>曇<EFBFBD><E69B87><EFBFBD>器<EFBFBD>?*<2A>?
|
||
|
||
### <20>𣂼<EFBFBD>皜<EFBFBD><E79A9C>
|
||
|
||
#### <20>𣂼<EFBFBD>1嚗𡁏<E59A97>瘜蓥耨<E893A5>鄗EDCap<61>詨<EFBFBD><E8A9A8>屸𢒰
|
||
|
||
```php
|
||
// <20>?<3F>䭾<EFBFBD><E4ADBE>𡁜<EFBFBD>嚗𡁜<E59A97><F0A1819C>冽𤜯<E586BD>㎞EDCap<61><70>㺭<EFBFBD>桀<EFBFBD><E6A180>亦<EFBFBD><E4BAA6>?
|
||
// <20>芾<EFBFBD><E88ABE>朞<EFBFBD>JavaScript瘜典<E7989C><E585B8>?憓𧼮撩"嚗峕<E59A97>瘜?<3F>踵揢"
|
||
|
||
function redcap_every_page_top($project_id) {
|
||
?>
|
||
<script>
|
||
// <20>芾<EFBFBD>靽格㺿DOM嚗峕<E59A97>瘜閙𤜯<E99699>X㟲銝芷△<E88AB7>?
|
||
$('#data_entry_form').append('<div>AI<41>拇<EFBFBD></div>');
|
||
</script>
|
||
<?php
|
||
}
|
||
```
|
||
|
||
**敶勗<E695B6>**嚗?
|
||
- <20>?<3F>䭾<EFBFBD>摰䂿緵"摰<><E691B0>摰𡁜<E691B0><F0A1819C>?<3F><>I
|
||
- <20>𩤃<EFBFBD> <20>烾<EFBFBD>鈭竃EDCap<61>毺<EFBFBD><E6AFBA>屸𢒰<E5B1B8><F0A292B0><EFBFBD>撅<EFBFBD><E69285>峕甅撘?
|
||
- <20>𩤃<EFBFBD> REDCap<61>屸𢒰<E5B1B8><F0A292B0>漣<EFBFBD>航<EFBFBD><E888AA>游<EFBFBD><E6B8B8>睲賑<E79DB2><E8B391>OM<4F>滢<EFBFBD>
|
||
|
||
#### <20>𣂼<EFBFBD>2嚗𡁏<E59A97>瘜閗挪<E99697>格<EFBFBD>鈭𥟇瓲敹<E793B2>遆<EFBFBD>?
|
||
|
||
```php
|
||
// <20>?<3F>𣂷<EFBFBD>REDCap<61><70><EFBFBD><EFBFBD>賣㺭<E8B3A3>舐<EFBFBD><E88890>厩<EFBFBD>嚗袏xternal Module<6C>䭾<EFBFBD>靚<EFBFBD>鍂
|
||
// 靘见<E99D98>嚗鋽ataQuality蝐餌<E89D90><E9A48C>𣂷<EFBFBD><F0A382B7>寞<EFBFBD>
|
||
|
||
// REDCap<61>詨<EFBFBD>隞<EFBFBD><E99A9E>嚗<EFBFBD><E59A97>瘜閗挪<E99697>殷<EFBFBD>
|
||
namespace REDCap\Internal;
|
||
class DataQuality {
|
||
private function executeRule($ruleId) {
|
||
// External Module<6C>䭾<EFBFBD>靚<EFBFBD>鍂甇斗䲮瘜?
|
||
}
|
||
}
|
||
```
|
||
|
||
#### <20>𣂼<EFBFBD>3嚗𡁏<E59A97>扯<EFBFBD>撘<EFBFBD><E69298><EFBFBD>
|
||
|
||
```php
|
||
// External Module<6C><65>ook隡𡁜<E99AA1><F0A1819C>𣳇<EFBFBD>憭硋<E686AD><E7A18B><EFBFBD>
|
||
function redcap_every_page_top($project_id) {
|
||
// 餈嗘葵<E59798>賣㺭<E8B3A3>冽<EFBFBD>銝芷△<E88AB7>a<EFBFBD><EFBD81>扯<EFBFBD>
|
||
// 憒<><E68692><EFBFBD>餉<EFBFBD>憭齿<E686AD>嚗䔶<E59A97><E494B6>𡝗<EFBFBD>憿菟𢒰<E88F9F>㰘蝸
|
||
}
|
||
|
||
// 瘚贝<E7989A>蝏𤘪<E89D8F>嚗?
|
||
// - 蝛慵ook嚗?5-10ms
|
||
// - <20>㗇㺭<E39787>桀<EFBFBD><E6A180>亥砭<E4BAA5><E7A0AD>ook嚗?50-200ms
|
||
// - <20>鵎TTP霂瑟<E99C82><E7919F><EFBFBD>ook嚗?500-2000ms
|
||
```
|
||
|
||
**蝏栞捏**嚗?
|
||
- <20>𩤃<EFBFBD> 銝滩<E98A9D><E6BBA9>沈ook銝剜<E98A9D>銵諹<E98AB5>埈𧒄<E59F88>滢<EFBFBD>
|
||
- <20>?敹<>◆撘<E29786>郊<EFBFBD>?
|
||
|
||
#### <20>𣂼<EFBFBD>4嚗𡁜<E59A97><F0A1819C>冽<EFBFBD>蝞?
|
||
|
||
```php
|
||
// <20>?External Module餈鞱<E9A488><E99EB1>典<EFBFBD><E585B8>鞟㴓憓<E3B493>葉
|
||
// <20>䭾<EFBFBD>霈輸䔮嚗?
|
||
// - REDCap摰㕑<E691B0><E39591>桀<EFBFBD>憭𣇉<E686AD><F0A38789><EFBFBD>辣
|
||
// - <20>𣂷<EFBFBD>蝟餌<E89D9F><E9A48C>賣㺭嚗Ềxec<65><63>hell_exec蝑㚁<E89D91>
|
||
// - <20>湔𦻖<E6B994>滢<EFBFBD>PHP隡朞<E99AA1>
|
||
```
|
||
|
||
### 摨𥪜笆蝑𣇉裦
|
||
|
||
**蝑𣇉裦1嚗𡁏𥅾<F0A1818F>梢<EFBFBD><E6A2A2>塚<EFBFBD><E5A19A>刻器<E588BB><E599A8><EFBFBD><EFBFBD>𥟇鰵**
|
||
- <20><><EFBFBD><EFBFBD>拍鍂Hook<6F>箏<EFBFBD>
|
||
- <20>朞<EFBFBD>JavaScript憓𧼮撩UI嚗<49><E59A97><EFBFBD>舀𤜯<E88880>g<EFBFBD>
|
||
- 雿輻鍂API雿靝蛹"<22><><EFBFBD><EFBFBD>?
|
||
|
||
**蝑𣇉裦2嚗𡁏毽<F0A1818F><E6AFBD>沲<EFBFBD>?*
|
||
```
|
||
REDCap (<28>唳旿敶訫<E695B6>) + AI撟喳蝱 (<28><><EFBFBD>撅閧內)
|
||
<20>?
|
||
<EFBFBD>冽<EFBFBD><EFBFBD>沖EDCap敶訫<EFBFBD> <20>?<3F>唳旿<E594B3>峕郊 <20>?<3F>杗I撟喳蝱<E596B3>亦<EFBFBD><E4BAA6><EFBFBD><EFBFBD>蝏𤘪<E89D8F>
|
||
```
|
||
|
||
餈蹱甅<EFBFBD>臭誑嚗?
|
||
- <20>?<3F>拍鍂REDCap<61><70>”<EFBFBD>閗挽霈∪膥嚗<E886A5>撩憭改<E686AD>
|
||
- <20>?<3F>拍鍂AI撟喳蝱<E596B3><E89DB1><EFBFBD><EFBFBD>鞱<EFBFBD><E99EB1>𨥈<EFBFBD><F0A8A588>菜暑嚗?
|
||
- <20>?閫<><E996AB>External Module<6C><65><EFBFBD><EFBFBD>?
|
||
|
||
---
|
||
|
||
## <20>𣞁 <20><><EFBFBD>舀<EFBFBD><E88880>?嚗𡁜<E59A97><F0A1819C>典<EFBFBD>閫<EFBFBD><E996AB>改<EFBFBD>HIPAA/GDPR嚗?
|
||
|
||
### <20>桅<EFBFBD><E6A185>讛膩
|
||
|
||
REDCap<EFBFBD>𡁜虜摮睃<EFBFBD>**PHI嚗㇊rotected Health Information嚗匧<E59A97>靽脲擪<E884B2>亙熒靽⊥<E99DBD>**嚗<>笆<EFBFBD>交𧒄<E4BAA4><F0A79284><EFBFBD><EFBFBD>刻<EFBFBD>瘙<EFBFBD><E79899>擃塩<E69383>?
|
||
|
||
### <20><><EFBFBD>閬<EFBFBD><E996AC>
|
||
|
||
#### HIPAA閬<41><E996AC>嚗<EFBFBD><E59A97><EFBFBD>踝<EFBFBD>
|
||
|
||
```
|
||
1. 霈輸䔮<E8BCB8>批<EFBFBD>嚗㇁ccess Control嚗?
|
||
- <20>冽<EFBFBD>霈方<E99C88>嚗<EFBFBD>撩撖<E692A9><E69296>+2FA嚗?
|
||
- <20><>撠𤩺<E692A0><F0A4A9BA>𣂼<EFBFBD><F0A382BC>?
|
||
- 摰∟恣<E2889F>亙<EFBFBD>嚗<EFBFBD><E59A97><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嗚<EFBFBD><E5979A>挪<EFBFBD>桐<EFBFBD>隞<EFBFBD>銋<EFBFBD><E98A8B>
|
||
|
||
2. <20>唳旿<E594B3>惩<EFBFBD>嚗𠄌ncryption嚗?
|
||
- 隡㰘<E99AA1><E3B098>惩<EFBFBD>嚗関LS 1.2+
|
||
- <20>蹱<EFBFBD><E8B9B1><EFBFBD>撖<EFBFBD><E69296>AES-256
|
||
- 撖<>𤨎蝞∠<E89D9E>嚗𡁜<E59A97><F0A1819C>蠘蔭<E8A098>?
|
||
|
||
3. <20>唳旿摰峕㟲<E5B395>改<EFBFBD>Integrity嚗?
|
||
- <20>脩砥<E884A9>對<EFBFBD><E5B08D>啣<EFBFBD>蝑曉<E89D91>
|
||
- <20><>𧋦<EFBFBD>批<EFBFBD>嚗𡁏<E59A97><F0A1818F>劐耨<E58A90>孵虾餈賣滲
|
||
|
||
4. 摰∟恣<E2889F>亙<EFBFBD>嚗㇁udit Logs嚗?
|
||
- 靽嘥<E99DBD><E598A5>喳<EFBFBD>6撟?
|
||
- 銝滚虾<E6BB9A>𣳇膄
|
||
- 摰𡁏<E691B0>摰⊥䰻
|
||
```
|
||
|
||
### 瞏𨅯銁憌𡡞埯<F0A1A19E>?
|
||
|
||
#### 憌𡡞埯1嚗𡁏㺭<F0A1818F>格<EFBFBD><E6A0BC>莎<EFBFBD>隡㰘<E99AA1>餈<EFBFBD><E9A488>嚗?
|
||
|
||
```typescript
|
||
// <20>?<3F>躰秤嚗䥅TTP隡㰘<E99AA1>嚗<EFBFBD><E59A97><EFBFBD><EFBFBD><EFBFBD>
|
||
const response = await fetch('http://ai-platform.com/api/webhook', {
|
||
method: 'POST',
|
||
body: JSON.stringify(patientData) // PHI<48>擧<EFBFBD>隡㰘<E99AA1>嚗?
|
||
});
|
||
|
||
// <20>?甇<>&嚗䥅TTPS + TLS 1.3
|
||
const response = await fetch('https://ai-platform.com/api/webhook', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-API-Key': encryptedApiKey,
|
||
'X-Signature': hmacSignature
|
||
},
|
||
body: JSON.stringify(patientData)
|
||
});
|
||
|
||
// <20>?<3F>渲<EFBFBD>銝<EFBFBD>甇伐<E79487>蝡臬<E89DA1>蝡臬<E89DA1>撖?
|
||
const encryptedPayload = await encrypt(patientData, publicKey);
|
||
await fetch('https://ai-platform.com/api/webhook', {
|
||
method: 'POST',
|
||
body: encryptedPayload
|
||
});
|
||
```
|
||
|
||
#### 憌𡡞埯2嚗𡁏𠯫敹埈<E695B9><E59F88>?
|
||
|
||
```php
|
||
// <20>?<3F>躰秤嚗䥪HI霈啣<E99C88><E595A3>冽𠯫敹𦯀葉
|
||
$this->log("<EFBFBD><EFBFBD><EFBFBD>?撘牐<E69298> <20><>僑樴<E58391>蛹 45 撗?);
|
||
// 餈肽<E9A488>嚗<EFBFBD>𠯫敹𦯀葉銝滩<E98A9D><E6BBA9><EFBFBD>鉄PHI
|
||
|
||
// <20>?甇<>&嚗朞<E59A97><E69C9E>誩<EFBFBD>霈啣<E99C88>
|
||
$this->log("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>扇敶閙凒<EFBFBD>?, [
|
||
'record_id' => hash('sha256', $record), // <20><><EFBFBD><EFBFBD>?
|
||
'field_count' => count($data),
|
||
'timestamp' => time()
|
||
]);
|
||
```
|
||
|
||
#### 憌𡡞埯3嚗鋫PI Token瘜<6E>蠧
|
||
|
||
```php
|
||
// <20>?<3F>躰秤嚗𡁏<E59A97><F0A1818F><EFBFBD><EFBFBD><EFBFBD>杗PI Token
|
||
$apiToken = 'ABC123DEF456...'; // 摮睃<E691AE><E79D83>其誨<E585B6><E8AAA8>葉
|
||
|
||
// <20>?<3F>躰秤嚗𡁏<E59A97><F0A1818F><EFBFBD><EFBFBD><EFBFBD>典銁<E585B8>唳旿摨?
|
||
INSERT INTO settings (key, value)
|
||
VALUES ('api_token', 'ABC123DEF456...');
|
||
|
||
// <20>?甇<>&嚗𡁜<E59A97>撖<EFBFBD><E69296><EFBFBD>?
|
||
$encrypted = openssl_encrypt(
|
||
$apiToken,
|
||
'AES-256-CBC',
|
||
$encryptionKey,
|
||
0,
|
||
$iv
|
||
);
|
||
INSERT INTO settings (key, value, iv)
|
||
VALUES ('api_token', $encrypted, $iv);
|
||
```
|
||
|
||
### <20><><EFBFBD><EFBFBD>鞉𧋦
|
||
|
||
| <20><><EFBFBD>閬<EFBFBD><E996AC> | 摰墧鴌<E5A2A7>曉漲 | 撘<><E69298>烐<EFBFBD><E78390>?| 摰∟恣<E2889F>鞉𧋦 | <20>餅<EFBFBD><E9A485>?|
|
||
|---------|---------|---------|---------|--------|
|
||
| **霈輸䔮<E8BCB8>批<EFBFBD>** | <20>椬 銝?| 1-2<>?| 瘥誩僑1甈?| $$$ |
|
||
| **<EFBFBD>唳旿<EFBFBD>惩<EFBFBD>** | <20>椬 銝?| 2-3<>?| 瘥誩僑1甈?| $$$ |
|
||
| **摰∟恣<E2889F>亙<EFBFBD>** | <20>叚 雿?| 3-5憭?| 瘥誩僑2甈?| $$ |
|
||
| **摰匧<E691B0>霂<EFBFBD>摯** | <20>𣞁 擃?| 4-6<>?| 瘥誩僑1甈?| $$$$ |
|
||
| **蝚砌<E89D9A><E7A08C>孵恣霈?* | <20>𣞁 擃?| N/A | 瘥誩僑1甈?| $$$$$ |
|
||
| **<EFBFBD>餉恣** | <20>𣞁 擃?| **2-3銝芣<E98A9D>** | **<EFBFBD><EFBFBD>賒** | **$10K-50K/撟?* |
|
||
|
||
---
|
||
|
||
## <20><> 憭齿<E686AD>摨血笆瘥䈑<E798A5>REDCap撖寞𦻖 vs <20>芰<EFBFBD>EDC
|
||
|
||
### 摰𡁻<E691B0><F0A181BB><EFBFBD><EFBFBD>
|
||
|
||
| 蝏游漲 | REDCap撖寞𦻖 | <20>芰<EFBFBD>EDC | 撖寞<E69296> |
|
||
|------|-----------|---------|------|
|
||
| **撘<><E69298>穃𪂹<E7A983>?* | 2-3銝芣<E98A9D> | 6-12銝芣<E98A9D> | <20>叚 REDCap敹?-5<>?|
|
||
| **撘<><E69298>烐<EFBFBD><E78390>?* | $50K-100K | $300K-500K | <20>叚 REDCap<61>?200K+ |
|
||
| **蝏湔擪<E6B994>鞉𧋦/撟?* | $30K-50K | $50K-80K | <20>椬 REDCap<61>乩<EFBFBD> |
|
||
| **<EFBFBD><EFBFBD><EFBFBD>臬<EFBFBD>箏𦛚** | <20>𣞁 擃矋<E69383>靘肽<E99D98>REDCap<61><70>漣嚗?| <20>叚 雿𠬍<E99BBF>摰<EFBFBD><E691B0><EFBFBD>芯蜓嚗?| <20>𣞁 REDCap憌𡡞埯擃?|
|
||
| **<EFBFBD>菜暑<EFBFBD>?* | <20>椬 銝哨<E98A9D><E593A8>㜬M獢<4D>沲<EFBFBD>𣂼<EFBFBD>嚗?| <20>叚 擃矋<E69383>摰<EFBFBD><E691B0><EFBFBD>芰眏嚗?| <20>𣞁 REDCap<61>烾<EFBFBD> |
|
||
| **<EFBFBD>蠘<EFBFBD>摰峕㟲<EFBFBD>?* | <20>叚 擃矋<E69383>REDCap<61>鞟<EFBFBD>嚗?| <20>椬 銝哨<E98A9D><E593A8><EFBFBD>隞𡡞妟撘<E5A69F><E69298>𡢅<EFBFBD> | <20>叚 REDCap隡睃飵 |
|
||
| **AI<41><49><EFBFBD>摨?* | <20>椬 銝哨<E98A9D><E593A8><EFBFBD>獢交𦻖嚗?| <20>叚 擃矋<E69383><E79F8B>毺<EFBFBD><E6AFBA><EFBFBD><EFBFBD>嚗?| <20>𣞁 REDCap暻餌<E69ABB> |
|
||
| **<EFBFBD>冽<EFBFBD>雿㯄<EFBFBD>** | <20>椬 銝哨<E98A9D>銝文<E98A9D>蝟餌<E89D9F>嚗?| <20>叚 擃矋<E69383>蝏煺<E89D8F>雿㯄<E99BBF>嚗?| <20>𣞁 REDCap<61>脰<EFBFBD> |
|
||
|
||
### <20>颱<EFBFBD>霂<EFBFBD>摯
|
||
|
||
```
|
||
REDCap撖寞𦻖<EFBFBD><EFBFBD>OI<EFBFBD><EFBFBD><EFBFBD>嚗?
|
||
|
||
<EFBFBD>鞉𧋦嚗?
|
||
- 撘<><E69298>𡢅<EFBFBD>$80K
|
||
- 撟渡輕<E6B8A1>歹<EFBFBD>$40K
|
||
- 5撟湔<E6929F>餅<EFBFBD><E9A485>穿<EFBFBD>$280K
|
||
|
||
<EFBFBD>嗥<EFBFBD>嚗?
|
||
- <20><><EFBFBD>撘<EFBFBD><E69298>烐𧒄<E78390>湛<EFBFBD>9銝芣<E98A9D>嚗<EFBFBD>𣪧<EFBFBD>笔虾銝𤘪釣AI<41>蠘<EFBFBD>嚗?
|
||
- <20>拍鍂REDCap<61>鞟<EFBFBD><E99E9F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銵典<E98AB5>霈曇恣<E69B87>具<EFBFBD><E585B7><EFBFBD><EFBFBD>鞟恣<E99E9F><E681A3><EFBFBD><EFBFBD>恣霈⊥𠯫敹?
|
||
- 敹恍<E695B9>煺<EFBFBD>撣<EFBFBD><E692A3>2-3銝芣<E98A9D> vs 12銝芣<E98A9D>
|
||
|
||
憌𡡞埯嚗?
|
||
- <20><><EFBFBD>臬<EFBFBD>箏𦛚嚗帋<E59A97>韏餸EDCap
|
||
- <20>冽<EFBFBD>雿㯄<E99BBF>嚗𡁜<E59A97>蝟餌<E89D9F><E9A48C><EFBFBD>揢
|
||
- <20>扯<EFBFBD><E689AF>園<EFBFBD>嚗鍃AV璅∪<E79285>
|
||
|
||
蝏栞捏嚗?
|
||
<EFBFBD>?憒<><E68692><EFBFBD>格<EFBFBD><E6A0BC>?敹恍<E695B9>罸<EFBFBD>霂<EFBFBD><E99C82><EFBFBD>?嚗朙EDCap撖寞𦻖<E5AF9E>舀<EFBFBD><E88880>粹<EFBFBD>㗇𥋘
|
||
<EFBFBD>?憒<><E68692><EFBFBD>格<EFBFBD><E6A0BC>?<3F>踵<EFBFBD>鈭批<E988AD>蝡硺<E89DA1><E7A1BA>?嚗諹䌊<E8ABB9>漋DC<44>游末
|
||
<EFBFBD>㴓 <20>刻<EFBFBD>蝑𣇉裦嚗𡁜<E59A97><F0A1819C>沖EDCap撖寞𦻖敹恍<E695B9>𠵱VP嚗<50><E59A97><EFBFBD>粹<EFBFBD>霂<EFBFBD><E99C82><EFBFBD>滩䌊<E6BBA9>?
|
||
```
|
||
|
||
---
|
||
|
||
## <20>㴓 <20><>蝏<EFBFBD>遣霈桐<E99C88><E6A190>喟<EFBFBD><E5969F>?
|
||
|
||
### <20>喟<EFBFBD><E5969F>?
|
||
|
||
```
|
||
Q1: <20>臬炏撌脫<E6928C>REDCap<61>冽<EFBFBD><E586BD>箇<EFBFBD>嚗?
|
||
<20>鎿<EFBFBD> <20>?<3F>?撘箇<E69298><E7AE87>刻<EFBFBD>撖寞𦻖嚗<F0A6BB96>鍂<EFBFBD>瑁<EFBFBD>蝘餅<E89D98><E9A485>砌<EFBFBD>嚗?
|
||
<20>婙<EFBFBD> <20>?<3F>?蝏抒賒Q2
|
||
|
||
Q2: <20>臬炏<E887AC><E7828F>閬<EFBFBD>銁6銝芣<E98A9D><E88AA3><EFBFBD><EFBFBD>撣<EFBFBD><E692A3>
|
||
<20>鎿<EFBFBD> <20>?<3F>?<3F>刻<EFBFBD>撖寞𦻖嚗<F0A6BB96><E59A97><EFBFBD>煾<EFBFBD>笔漲敹恬<E695B9>
|
||
<20>婙<EFBFBD> <20>?<3F>?蝏抒賒Q3
|
||
|
||
Q3: <20>臬炏<E887AC><E7828F>閬<EFBFBD><E996AC><EFBFBD>渡<EFBFBD><E6B8A1>冽<EFBFBD>雿㯄<E99BBF><E3AF84>峕楛摨再I<E5868D><49><EFBFBD>嚗?
|
||
<20>鎿<EFBFBD> <20>?<3F>?<3F>刻<EFBFBD><E588BB>芰<EFBFBD>嚗<EFBFBD><E59A97>撉峕凒憟踝<E6869F>
|
||
<20>婙<EFBFBD> <20>?<3F>?<3F>刻<EFBFBD>撖寞𦻖
|
||
|
||
Q4: <20><><EFBFBD>臬𣪧<E887AC><F0A3AAA7>糓<EFBFBD>行<EFBFBD>PHP + REDCap蝏誯<E89D8F>嚗?
|
||
<20>鎿<EFBFBD> <20>?<3F>?撖寞𦻖憌𡡞埯<F0A1A19E>滢<EFBFBD>
|
||
<20>婙<EFBFBD> <20>?<3F>?摮虫<E691AE><E899AB>鞉𧋦+2<>?
|
||
|
||
Q5: <20>臬炏<E887AC>賣𦻖<E8B3A3>妔EDCap<61><70>漣撣行䔉<E8A18C><E49489>鵭<EFBFBD>毺輕<E6AFBA>斗<EFBFBD><E69697>穿<EFBFBD>
|
||
<20>鎿<EFBFBD> <20>?<3F>?<3F>臭誑撖寞𦻖
|
||
<20>婙<EFBFBD> <20>?<3F>?銝齿綫<E9BDBF>𣂼笆<F0A382BC>?
|
||
```
|
||
|
||
### 銝厩<E98A9D>蝑𣇉裦
|
||
|
||
#### 蝑𣇉裦1嚗帋<E59A97>摰<EFBFBD><E691B0><EFBFBD>伐<EFBFBD><E4BC90>刻<EFBFBD>嚗?
|
||
|
||
```
|
||
<EFBFBD>嗆挾1嚗?-3銝芣<E98A9D>嚗㚁<E59A97>REDCap撖寞𦻖MVP
|
||
- 摰䂿緵<E482BF>箇<EFBFBD><E7AE87>唳旿<E594B3>峕郊
|
||
- <20><><EFBFBD>DC璅∪<E79285>嚗<EFBFBD>㺭<EFBFBD>格<EFBFBD>瘣梹<E798A3>
|
||
- <20>格<EFBFBD>嚗𡁻<E59A97>霂<EFBFBD><E99C82><EFBFBD>粹<EFBFBD>瘙?
|
||
|
||
<EFBFBD>嗆挾2嚗?-6銝芣<E98A9D>嚗㚁<E59A97>瘛勗漲<E58B97><E6BCB2><EFBFBD>
|
||
- <20><><EFBFBD>SSA璅∪<E79285>嚗<EFBFBD><E59A97>霈∪<E99C88><E288AA>琜<EFBFBD>
|
||
- 隡睃<E99AA1><E79D83>扯<EFBFBD><E689AF>𣬚鍂<F0A3AC9A>瑚<EFBFBD>撉?
|
||
- <20>格<EFBFBD>嚗𡁶妖蝝舐鍂<E88890>瑕<EFBFBD><E79195>唳旿
|
||
|
||
<EFBFBD>嗆挾3嚗?-18銝芣<E98A9D>嚗㚁<E59A97>霂<EFBFBD>摯<EFBFBD>芰<EFBFBD>
|
||
- <20>寞旿<E5AF9E>冽<EFBFBD><E586BD>漤<EFBFBD><E6BCA4>喳<EFBFBD><E596B3>臬炏<E887AC>芰<EFBFBD>EDC
|
||
- 憒<><E68692>撣<EFBFBD>㦤撉諹<E69289><E8ABB9>𣂼<EFBFBD>嚗<EFBFBD>鍳<EFBFBD>刻䌊<E588BB>?
|
||
- <20>格<EFBFBD>嚗𡁻鵭<F0A181BB>毺<EFBFBD>鈭匧<E988AD>
|
||
|
||
隡睃飵嚗?
|
||
<EFBFBD>?憌𡡞埯<F0A1A19E>舀綉嚗<E7B689><E59A97><EFBFBD>嗆挾<E59786>訫<EFBFBD>嚗?
|
||
<EFBFBD>?韏<><E99F8F>擃䀹<E69383>嚗<EFBFBD><E59A97>瘚芾晶<E88ABE>其<EFBFBD>蝖桀<E89D96><E6A180><EFBFBD>★<EFBFBD>桐<EFBFBD>嚗?
|
||
<EFBFBD>?敹恍<E695B9>罸<EFBFBD>霂<EFBFBD><E99C82>3銝芣<E98A9D>閫<EFBFBD><E996AB><EFBFBD>頣<EFBFBD>
|
||
```
|
||
|
||
#### 蝑𣇉裦2嚗𡁏<E59A97>餈𤤿<E9A488><F0A4A4BF>伐<EFBFBD>銝齿綫<E9BDBF>琜<EFBFBD>
|
||
|
||
```
|
||
<EFBFBD>湔𦻖<EFBFBD>訫<EFBFBD><EFBFBD>芰<EFBFBD>EDC嚗?-12銝芣<E98A9D>嚗?
|
||
|
||
憌𡡞埯嚗?
|
||
<EFBFBD>?撣<>㦤<EFBFBD><E3A6A4>瘙<EFBFBD>𧊋撉諹<E69289>
|
||
<EFBFBD>?蝡𧼮<E89DA1><F0A7BCAE>航<EFBFBD><E888AA>W<EFBFBD>
|
||
<EFBFBD>?韏<><E99F8F><EFBFBD>见<EFBFBD>憭?
|
||
```
|
||
|
||
#### 蝑𣇉裦3嚗𡁏毽<F0A1818F><E6AFBD><EFBFBD><EFBFBD>伐<EFBFBD><E4BC90>䀝葉嚗?
|
||
|
||
```
|
||
<EFBFBD>峕𧒄餈𥡝<EFBFBD>嚗?
|
||
- 撠誩𣪧<E8AAA9><F0A3AAA7><EFBFBD>2鈭綽<E988AD>撖寞𦻖REDCap嚗<70>翰<EFBFBD>𠵱VP嚗?
|
||
- 憭批𣪧<E689B9><F0A3AAA7><EFBFBD>5鈭綽<E988AD><E7B6BD>芰<EFBFBD>EDC嚗<43>鵭<EFBFBD>煺漣<E785BA><E6BCA3><EFBFBD>
|
||
|
||
<EFBFBD>格<EFBFBD>嚗?
|
||
- REDCap皛∟雲<E2889F>拇<EFBFBD>摰X<E691B0>
|
||
- <20>芰<EFBFBD>EDC雿靝蛹<E99D9D><E89BB9>漣頝臬<E9A09D>
|
||
|
||
憌𡡞埯嚗?
|
||
<EFBFBD>𩤃<EFBFBD> 韏<><E99F8F><EFBFBD><EFBFBD>袇
|
||
<EFBFBD>𩤃<EFBFBD> 銝文<E98A9D>蝟餌<E89D9F>蝏湔擪<E6B994>鞉𧋦擃?
|
||
```
|
||
|
||
---
|
||
|
||
## <20><> 憌𡡞埯<F0A1A19E>拚猐<E68B9A>餌<EFBFBD>
|
||
|
||
| 憌𡡞埯憿?| 敶勗<E695B6>蝔见漲 | <20>𤑳<EFBFBD>璁<EFBFBD><E79281> | 隡睃<E99AA1>蝥?| 蝻栞圾<E6A09E>芣鴌 |
|
||
|-------|---------|---------|--------|---------|
|
||
| **EAV<41>扯<EFBFBD><E689AF>園<EFBFBD>** | <20>𣞁 擃?| <20>𣞁 擃?| P0 | 霈曇恣蝻枏<E89DBB>撅?+ <20>拙<EFBFBD>閫<EFBFBD>㦛 |
|
||
| **<EFBFBD><EFBFBD>𧋦<EFBFBD><EFBFBD>漣<EFBFBD>游<EFBFBD>** | <20>𣞁 擃?| <20>椬 銝?| P0 | <20><>𧋦<EFBFBD><F0A78BA6><EFBFBD> + <20>𧼮<EFBFBD>瘚贝<E7989A> |
|
||
| **<EFBFBD>唳旿銝<EFBFBD><EFBFBD>湔<EFBFBD>?* | <20>椬 銝?| <20>椬 銝?| P1 | <20>訫<EFBFBD><E8A8AB>峕郊 + 撟<><E6929F><EFBFBD>扯挽霈?|
|
||
| **API<50>鞉<EFBFBD>** | <20>椬 銝?| <20>椬 銝?| P2 | <20><>鸌憭<E9B88C><E686AD> + <20>鞉<EFBFBD> |
|
||
| **EM獢<4D>沲<EFBFBD>𣂼<EFBFBD>** | <20>椬 銝?| <20>叚 雿?| P3 | 瘛瑕<E7989B><E79195>嗆<EFBFBD>嚗㇌EDCap + AI撟喳蝱嚗?|
|
||
| **摰匧<E691B0><E58CA7><EFBFBD><EFBFBD>** | <20>𣞁 擃?| <20>叚 雿?| P0 | <20>惩<EFBFBD> + 摰∟恣 + <20><><EFBFBD>霈方<E99C88> |
|
||
| **蝏湔擪<E6B994>鞉𧋦** | <20>椬 銝?| <20>𣞁 擃?| P1 | 蝏<>遣銝㮖<E98A9D><E3AE96>a<EFBFBD> |
|
||
|
||
---
|
||
|
||
## <20>𤁗 <20><>蝏<EFBFBD><E89D8F>霈?
|
||
|
||
### 蝑娍<E89D91><E5A88D>函<EFBFBD><E587BD>桅<EFBFBD>
|
||
|
||
**Q: 銝竃EDCap撖寞𦻖<E5AF9E>劐<EFBFBD>銋<EFBFBD><E98A8B><EFBFBD>矋<EFBFBD>**
|
||
A: **7憭扳<E686AD><E689B3>舀<EFBFBD><E88880>?*嚗<><E59A97>銝?銝芣糓擃㗛<E69383><E3979B>抬<EFBFBD>EAV<41>扯<EFBFBD><E689AF><EFBFBD><EFBFBD><EFBFBD>砍<EFBFBD>蝥扼<E89DA5><E689BC><EFBFBD><EFBFBD>典<EFBFBD>閫<EFBFBD><E996AB>
|
||
|
||
**Q: 銝滚虾<E6BB9A>抒<EFBFBD><E68A92>唳䲮嚗?*
|
||
A: **REDCap<61><70>𧋦<EFBFBD><F0A78BA6>漣**<EFBFBD>舀<EFBFBD>銝滚虾<EFBFBD>抒<EFBFBD>嚗<EFBFBD><EFBFBD>撟?-4甈∴<E79488><E288B4>航<EFBFBD><E888AA>游<EFBFBD><E6B8B8><EFBFBD><EFBFBD>嚗?
|
||
|
||
**Q: <20><><EFBFBD>舫𠗕<E888AB>對<EFBFBD>**
|
||
A: **EAV璅∪<E79285><E288AA><EFBFBD><EFBFBD>扯<EFBFBD>隡睃<E99AA1>**<EFBFBD>?*<2A><><EFBFBD>撘𤩺㺭<F0A4A9BA>桐<EFBFBD><E6A190>湔<EFBFBD>?*<2A>舀<EFBFBD>憭折𠗕<E68A98>?
|
||
|
||
**Q: 憭齿<E686AD><E9BDBF>折<EFBFBD><E68A98>梹<EFBFBD>**
|
||
A: **銝剔<E98A9D><E58994>誯<EFBFBD>憭齿<E686AD>摨?*嚗?/5嚗?
|
||
- 瘥磰䌊<E7A3B0>漋DC蝞<43><E89D9E>𤏪<EFBFBD>REDCap<61>踵<EFBFBD>鈭?0%撌乩<E6928C>嚗?
|
||
- 瘥𥪜<E798A5>蝥涉PI<50><49><EFBFBD>憭齿<E686AD>嚗<EFBFBD><E59A97>憭<EFBFBD><E686AD>銝<EFBFBD><E98A9D>湔<EFBFBD>扼<EFBFBD><E689BC><EFBFBD>扯<EFBFBD><E689AF><EFBFBD><EFBFBD>蝥抒<E89DA5><E68A92>桅<EFBFBD>嚗?
|
||
|
||
### <20>𤑳<EFBFBD>撱箄悅
|
||
|
||
**<EFBFBD>㴓 <20>刻<EFBFBD><E588BB>寞<EFBFBD>嚗𡁜<E59A97><F0A1819C>嗆挾蝑𣇉裦**
|
||
|
||
```
|
||
Phase 1 (0-2銝芣<E98A9D>): <20>航<EFBFBD><E888AA>折<EFBFBD>霂?
|
||
- <20>剖遣REDCap瘚贝<E7989A><E8B49D>臬<EFBFBD>
|
||
- 撘<><E69298>烐<EFBFBD>撠㛁xternal Module嚗<65>蘨<EFBFBD>𡁜<EFBFBD><F0A1819C>穃<EFBFBD>甇伐<E79487>
|
||
- 瘚贝<E7989A>EAV<41>扯<EFBFBD><E689AF>園<EFBFBD>嚗<EFBFBD>鍂10銝<30>辺<EFBFBD>笔<EFBFBD><E7AC94>唳旿嚗?
|
||
- 霂<>摯嚗𡁏糓<F0A1818F>衣誧蝏哨<E89D8F>
|
||
|
||
Phase 2 (2-3銝芣<E98A9D>): MVP撘<50><E69298>?
|
||
- <20>芸笆<E88AB8>主C璅∪<E79285>嚗<EFBFBD><E59A97><EFBFBD>劐遠<E58A90>潘<EFBFBD>
|
||
- <20>訫<EFBFBD><E8A8AB>峕郊嚗㇌EDCap <20>?AI嚗?
|
||
- 銝滩<E98A9D><E6BBA9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>摰墧𧒄
|
||
- <20>格<EFBFBD>嚗?-10銝芾<E98A9D><E88ABE>孵恥<E5ADB5>?
|
||
|
||
Phase 3 (3-6銝芣<E98A9D>): <20>寞旿<E5AF9E>漤<EFBFBD><E6BCA4>喳<EFBFBD>
|
||
- 憒<><E68692>摰X<E691B0><EFBCB8>漤<EFBFBD>憟?<3F>?瘛勗漲<E58B97><E6BCB2><EFBFBD>
|
||
- 憒<><E68692><EFBFBD>扯<EFBFBD><E689AF>園<EFBFBD><E59C92>擧遬 <20>?<3F><><EFBFBD><EFBFBD>芰<EFBFBD>
|
||
- 憒<><E68692>蝏湔擪<E6B994>鞉𧋦憭芷<E686AD> <20>?頧砍<E9A0A7><E7A08D>芰<EFBFBD>
|
||
```
|
||
|
||
**<EFBFBD>働 <20>喲睸撱箄悅**嚗?
|
||
1. <20>?銝滩<E98A9D>銝<EFBFBD>撘<EFBFBD>憪见停餈賣<E9A488>"摰𣬚<E691B0>撖寞𦻖"
|
||
2. <20>?<3F><>鍂<EFBFBD><E98D82>蝞<EFBFBD><E89D9E>閙䲮獢<E4B2AE><E78DA2>霂<EFBFBD><E99C82>瘙<EFBFBD><E79899><EFBFBD>訫<EFBFBD><E8A8AB>峕郊頞喳<E9A09E>嚗?
|
||
3. <20>?<3F>𣂼<EFBFBD>閫<EFBFBD><E996AB>"<22><><EFBFBD>箇<EFBFBD><E7AE87>?嚗<><E59A97><EFBFBD>𨅯笆<F0A885AF>亙仃韐伐<E99F90>憒<EFBFBD><E68692><EFBFBD><EFBFBD>揢<EFBFBD>啗䌊<E59597>䈑<EFBFBD>
|
||
4. <20>𩤃<EFBFBD> 蝏<>遣<EFBFBD>侨HP + REDCap蝏誯<E89D8F><E8AAAF><EFBFBD>𣪧<EFBFBD><F0A3AAA7><EFBFBD><EFBFBD>喳<EFBFBD>1鈭綽<E988AD>
|
||
5. <20>𩤃<EFBFBD> 憸<><E686B8>20-30%<25><>𧒄<EFBFBD>游<EFBFBD>撖?<3F>誩<EFBFBD>"嚗<><E59A97><EFBFBD>砍<EFBFBD>蝥扼<E89DA5><E689BC>ug嚗?
|
||
|
||
---
|
||
|
||
**<EFBFBD><EFBFBD>﹝<EFBFBD><EFBFBD>𧋦**嚗鯝1.0
|
||
**<EFBFBD><EFBFBD><EFBFBD>擧凒<EFBFBD>?*嚗?025-12-30
|
||
**銝𧢲活霂<E6B4BB>恣**嚗䥪hase 1摰峕<E691B0><E5B395>𠬍<EFBFBD>2銝芣<E98A9D>嚗?
|
||
|
||
---
|
||
|
||
**<EFBFBD>辶 霈唬<E99C88>嚗𡁏<E59A97><F0A1818F>舫<EFBFBD>匧<EFBFBD>瘝⊥<E7989D>摰𣬚<E691B0><F0A3AC9A>寞<EFBFBD>嚗<EFBFBD>蘨<EFBFBD>厰<EFBFBD><E58EB0><EFBFBD>敶枏<E695B6><E69E8F>嗆挾<E59786><E68CBE>䲮獢<E4B2AE><E78DA2>?*
|
||
|
||
|
||
|
||
|
||
|