feat: 补上元素key

This commit is contained in:
wkj 2025-12-23 10:49:58 +08:00
parent 97fd741a3b
commit d347e19ede
52 changed files with 147 additions and 162 deletions

View File

@ -20,7 +20,7 @@ export default function render(props) {
</Space> </Space>
<img id="previewImg" src={src} alt="previewImg" className={Style.previewImg} style={{ display: src ? 'inline-block' : 'none' }}/> <img id="previewImg" src={src} alt="previewImg" className={Style.previewImg} style={{ display: src ? 'inline-block' : 'none' }}/>
<div className={Style.methodList}> <div className={Style.methodList}>
{methods && methods.map((ele) => (<div className={Style.methodListItem} onClick={() => { {methods && methods.map((ele) => (<div key={ele} className={Style.methodListItem} onClick={() => {
chooseMethod(ele); chooseMethod(ele);
}}> }}>
{t(ele)} {t(ele)}

View File

@ -7,7 +7,7 @@ export default function render(props) {
const imageViewerMultiRef = useRef(null); const imageViewerMultiRef = useRef(null);
return (<> return (<>
<Space> <Space>
{files?.map((ele, index) => (<Image src={ele.thumbUrl} width={100} height={100} fit="contain" onClick={!disablePreview ? () => { {files?.map((ele, index) => (<Image key={`file_image_${index}`} src={ele.thumbUrl} width={100} height={100} fit="contain" onClick={!disablePreview ? () => {
setVisible(true); setVisible(true);
imageViewerMultiRef.current.swipeTo(index); imageViewerMultiRef.current.swipeTo(index);
} : undefined}/>))} } : undefined}/>))}

View File

@ -8,7 +8,7 @@ export default function render(props) {
onChange: (current, prev) => { }, onChange: (current, prev) => { },
}}> }}>
<Space> <Space>
{files?.map((ele) => (<Image width={120} src={ele.thumbUrl} preview={!disablePreview {files?.map((ele, index) => (<Image key={`file_image_${index}`} width={120} src={ele.thumbUrl} preview={!disablePreview
? { ? {
src: ele.url, src: ele.url,
} }

View File

@ -104,7 +104,7 @@ export default function Render(props) {
setUpdateValue(value); setUpdateValue(value);
}}> }}>
<Space direction="horizontal"> <Space direction="horizontal">
{GenderOptions.map(ele => <Radio value={ele.value}>{ele.label}</Radio>)} {GenderOptions.map(ele => <Radio key={ele.value} value={ele.value}>{ele.label}</Radio>)}
</Space> </Space>
</Radio.Group>} </Radio.Group>}
</Form.Item> </Form.Item>

View File

@ -16,5 +16,5 @@ export default function render(props: WebComponentProps<EntityDict, 'passport',
type: EntityDict['passport']['Schema']['type']; type: EntityDict['passport']['Schema']['type'];
tip: string; tip: string;
}[]; }[];
myConfirm: (ids: string[]) => void; myConfirm: (ids: string[]) => Promise<void>;
}>): React.JSX.Element; }>): React.JSX.Element;

View File

@ -18,7 +18,7 @@ export default function render(props) {
label: ele.name, label: ele.name,
children: (<Space size={[0, 16]} wrap> children: (<Space size={[0, 16]} wrap>
{stations?.map((ele) => { {stations?.map((ele) => {
return (<Checkbox disabled={selectIds?.includes(ele.value)} onChange={(e) => { return (<Checkbox key={ele.value} disabled={selectIds?.includes(ele.value)} onChange={(e) => {
setCheckedList(e.target.value, e.target.checked); setCheckedList(e.target.value, e.target.checked);
}} checked={stationIds }} checked={stationIds
.concat(selectIds || []) .concat(selectIds || [])

View File

@ -26,7 +26,7 @@ export default function Render(props) {
}); });
}} value={idCardType}> }} value={idCardType}>
{idCardTypeArr.map((ele, index) => { {idCardTypeArr.map((ele, index) => {
return <Radio value={ele.value}>{ele.label}</Radio>; return <Radio key={ele.value} value={ele.value}>{ele.label}</Radio>;
})} })}
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>

View File

@ -36,7 +36,7 @@ export default function render(props) {
cancelEdit(); cancelEdit();
}}> }}>
<Space direction="horizontal"> <Space direction="horizontal">
{genderOptions.map((ele) => (<Radio value={ele.value}> {genderOptions.map((ele) => (<Radio key={ele.value} value={ele.value}>
{ele.label} {ele.label}
</Radio>))} </Radio>))}
</Space> </Space>

View File

@ -14,7 +14,7 @@ export default function Render(props) {
: (<div> : (<div>
<Form.Header>{t('pickRow', { entity: t(`${entity}:name`) })}</Form.Header> <Form.Header>{t('pickRow', { entity: t(`${entity}:name`) })}</Form.Header>
<CheckList value={pickedRowIds || []} disabled={disablePickRow || disabled} onChange={(val) => onPickRows(val)}> <CheckList value={pickedRowIds || []} disabled={disablePickRow || disabled} onChange={(val) => onPickRows(val)}>
{rows.map((row) => (<CheckList.Item value={row.id}> {rows.map((row) => (<CheckList.Item key={row.id} value={row.id}>
{row.value} {row.value}
</CheckList.Item>))} </CheckList.Item>))}
</CheckList> </CheckList>
@ -22,7 +22,7 @@ export default function Render(props) {
const Relation = (<div> const Relation = (<div>
<List mode='card' header={t(`pickRelation.${pickRelationRule}`)}> <List mode='card' header={t(`pickRelation.${pickRelationRule}`)}>
<CheckList multiple={rule !== 'single'} value={pickedRelationIds || []} disabled={disablePickRelation || disabled} onChange={(val) => onPickRelations(val)}> <CheckList multiple={rule !== 'single'} value={pickedRelationIds || []} disabled={disablePickRelation || disabled} onChange={(val) => onPickRelations(val)}>
{relations.map((relation) => (<CheckList.Item value={relation.id}> {relations.map((relation) => (<CheckList.Item key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</CheckList.Item>))} </CheckList.Item>))}
</CheckList> </CheckList>

View File

@ -17,7 +17,7 @@ export default function Render(props) {
{t('pickRow', { entity: t(`${entity}:name`) })} {t('pickRow', { entity: t(`${entity}:name`) })}
</Divider> </Divider>
<Checkbox.Group value={pickedRowIds || []} disabled={disablePickRow || disabled} onChange={(val) => onPickRows(val)}> <Checkbox.Group value={pickedRowIds || []} disabled={disablePickRow || disabled} onChange={(val) => onPickRows(val)}>
{rows.map((row) => (<Checkbox value={row.id}>{row.value}</Checkbox>))} {rows.map((row) => (<Checkbox key={row.id} value={row.id}>{row.value}</Checkbox>))}
</Checkbox.Group> </Checkbox.Group>
</>); </>);
const Relation = (<> const Relation = (<>
@ -26,14 +26,14 @@ export default function Render(props) {
</Divider> </Divider>
<List> <List>
{rule !== 'single' ? (<Checkbox.Group value={pickedRelationIds || []} disabled={disablePickRelation || disabled} onChange={(val) => onPickRelations(val)}> {rule !== 'single' ? (<Checkbox.Group value={pickedRelationIds || []} disabled={disablePickRelation || disabled} onChange={(val) => onPickRelations(val)}>
{relations.map((relation) => (<Checkbox value={relation.id}> {relations.map((relation) => (<Checkbox key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</Checkbox>))} </Checkbox>))}
</Checkbox.Group>) : (<Radio.Group onChange={(e) => { </Checkbox.Group>) : (<Radio.Group onChange={(e) => {
const val = e.target.value; const val = e.target.value;
onPickRelations([val]); onPickRelations([val]);
}} value={pickedRelationIds?.[0] || undefined}> }} value={pickedRelationIds?.[0] || undefined}>
{relations.map((relation) => (<Radio value={relation.id}> {relations.map((relation) => (<Radio key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</Radio>))} </Radio>))}
</Radio.Group>)} </Radio.Group>)}

View File

@ -25,16 +25,13 @@ export default function Render(props) {
</span> </span>
<List> <List>
{users?.map((ele, index) => { {users?.map((ele, index) => {
return (<List.Item prefix={ele.avatar ? (<Avatar className={Style.avatar} src={ele.avatar}/>) : (<UserCircleOutline className={Style.avatar}/>)} extra={ele.mobile || '--'} description={<div style={{ return (<List.Item key={ele.id} prefix={ele.avatar ? (<Avatar className={Style.avatar} src={ele.avatar}/>) : (<UserCircleOutline className={Style.avatar}/>)} extra={ele.mobile || '--'} description={<div style={{
display: 'flex', display: 'flex',
flexWrap: 'wrap', flexWrap: 'wrap',
}}> }}>
{ele.userRelation$user?.map((ele2, index2) => (<Tag key={index} fill="outline"> {ele.userRelation$user?.map((ele2, index2) => (<Tag key={ele2.id} fill="outline">
{ele2.relation?.name {ele2.relation?.name
? t(entity + ? t(entity + ':r.' + ele2.relation.name)
':r.' +
ele2.relation
.name)
: ele2.relation?.display} : ele2.relation?.display}
</Tag>))} </Tag>))}
</div>} onClick={() => goUpdate(ele.id)}> </div>} onClick={() => goUpdate(ele.id)}>

View File

@ -49,11 +49,9 @@ export default function Render(props) {
title: t('relations'), title: t('relations'),
render: (value, record, index) => { render: (value, record, index) => {
return (<Space> return (<Space>
{record.userRelation$user?.map((ele, index) => (<Tag key={index}> {record.userRelation$user?.map((ele, index) => (<Tag key={ele.id}>
{ele.relation.name {ele.relation.name
? t(entity + ? t(entity + ':r.' + ele.relation.name)
':r.' +
ele.relation.name)
: ele.relation.display} : ele.relation.display}
</Tag>))} </Tag>))}
</Space>); </Space>);

View File

@ -24,9 +24,8 @@ export default function render(props) {
update({ relationIds: val }); update({ relationIds: val });
}}> }}>
<Space direction="vertical"> <Space direction="vertical">
{relations?.map((ele) => (<Checkbox value={ele.id}> {relations?.map((ele) => (<Checkbox key={ele.id} value={ele.id}>
{ele.display || {ele.display || t(`${relationEntity}:r.${ele.name}`)}
t(`${relationEntity}:r.${ele.name}`)}
</Checkbox>))} </Checkbox>))}
</Space> </Space>
</Checkbox.Group> </Checkbox.Group>
@ -36,7 +35,7 @@ export default function render(props) {
rule: val, rule: val,
})}> })}>
<Space direction="vertical"> <Space direction="vertical">
{rules.map((ele) => (<Radio value={ele}> {rules.map((ele) => (<Radio key={ele} value={ele}>
{t(`userEntityGrant:v.rule.${ele}`)} {t(`userEntityGrant:v.rule.${ele}`)}
</Radio>))} </Radio>))}
</Space> </Space>

View File

@ -24,8 +24,7 @@ export default function render(props) {
update({ relationIds: val }); update({ relationIds: val });
}} options={relations?.map((ele) => ({ }} options={relations?.map((ele) => ({
value: ele.id, value: ele.id,
label: ele.display || label: ele.display || relationEntity && t(`${relationEntity}:r.${ele.name}`),
relationEntity && t(`${relationEntity}:r.${ele.name}`),
}))}/> }))}/>
</Form.Item> </Form.Item>
{relationIds?.length > 1 && (<Form.Item label={t('userEntityGrant:attr.rule')} help={t('helpRule')}> {relationIds?.length > 1 && (<Form.Item label={t('userEntityGrant:attr.rule')} help={t('helpRule')}>

View File

@ -14,13 +14,13 @@ export default function Render(props) {
const SubParts = enabled.map((ele) => { const SubParts = enabled.map((ele) => {
switch (ele) { switch (ele) {
case 'email': { case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>; return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
} }
case 'mobile': { case 'mobile': {
return (<ByMobile passwordRequired={passwordRequired} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>); return (<ByMobile key={ele} passwordRequired={passwordRequired} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>);
} }
case 'userEntityGrant': { case 'userEntityGrant': {
return (<ByUserEntityGrant qrCodeType={qrCodeType} entity={entity} entityId={entityId} relations={relations} claimUrl={claimUrl} rule={rule} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} onUserEntityGrantCreated={onUserEntityGrantCreated}/>); return (<ByUserEntityGrant key={ele} qrCodeType={qrCodeType} entity={entity} entityId={entityId} relations={relations} claimUrl={claimUrl} rule={rule} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} onUserEntityGrantCreated={onUserEntityGrantCreated}/>);
} }
} }
}); });

View File

@ -14,13 +14,13 @@ export default function Render(props) {
const SubParts = enabled.map((ele) => { const SubParts = enabled.map((ele) => {
switch (ele) { switch (ele) {
case 'email': { case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>; return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
} }
case 'mobile': { case 'mobile': {
return (<ByMobile passwordRequired={passwordRequired} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>); return (<ByMobile key={ele} passwordRequired={passwordRequired} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>);
} }
case 'userEntityGrant': { case 'userEntityGrant': {
return (<ByUserEntityGrant qrCodeType={qrCodeType} entity={entity} entityId={entityId} relations={relations} claimUrl={claimUrl} rule={rule} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} onUserEntityGrantCreated={onUserEntityGrantCreated}/>); return (<ByUserEntityGrant key={ele} qrCodeType={qrCodeType} entity={entity} entityId={entityId} relations={relations} claimUrl={claimUrl} rule={rule} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} onUserEntityGrantCreated={onUserEntityGrantCreated}/>);
} }
} }
}); });

View File

@ -42,7 +42,7 @@ export default function Render(props) {
return (<div> return (<div>
{value && value.length > 0 {value && value.length > 0
? value.map((ele) => { ? value.map((ele) => {
return <Tag>{ele.text}</Tag>; return <Tag key={ele.id}>{ele.text}</Tag>;
}) })
: '暂无标签'} : '暂无标签'}
</div>); </div>);
@ -136,7 +136,7 @@ export default function Render(props) {
<Descriptions.Item label="用户标签"> <Descriptions.Item label="用户标签">
{user.tags && user.tags.length > 0 {user.tags && user.tags.length > 0
? user.tags.map((tag) => { ? user.tags.map((tag) => {
return <Tag>{tag.text}</Tag>; return <Tag key={tag.id}>{tag.text}</Tag>;
}) })
: '暂无标签'} : '暂无标签'}
</Descriptions.Item> </Descriptions.Item>

View File

@ -112,7 +112,7 @@ export default function Render(props) {
title: '封面图', title: '封面图',
render: (value, record, index) => { render: (value, record, index) => {
return (<div> return (<div>
{record.content.news_item.map((ele) => (<div><img style={{ width: 100 }} src={ele.coverUrl}/></div>))} {record.content.news_item.map((ele, index) => (<div key={`coverUrl${index}`}><img style={{ width: 100 }} src={ele.coverUrl}/></div>))}
</div>); </div>);
} }
}, },
@ -121,7 +121,7 @@ export default function Render(props) {
title: '图文消息标题', title: '图文消息标题',
render: (value, record, index) => { render: (value, record, index) => {
return (<div> return (<div>
{record.content.news_item.map((ele) => (<div>{ele.title}</div>))} {record.content.news_item.map((ele, index) => (<div key={`title${index}`}>{ele.title}</div>))}
</div>); </div>);
} }
}, },
@ -130,7 +130,7 @@ export default function Render(props) {
title: '作者', title: '作者',
render: (value, record, index) => { render: (value, record, index) => {
return (<div> return (<div>
{record.content.news_item.map((ele) => (<div>{ele.author}</div>))} {record.content.news_item.map((ele, index) => (<div key={`author${index}`}>{ele.author}</div>))}
</div>); </div>);
} }
}, },
@ -139,7 +139,7 @@ export default function Render(props) {
title: '图文信息摘要', title: '图文信息摘要',
render: (value, record, index) => { render: (value, record, index) => {
return (<div> return (<div>
{record.content.news_item.map((ele) => (<div>{ele.digest}</div>))} {record.content.news_item.map((ele, index) => (<div key={`digest${index}`}>{ele.digest}</div>))}
</div>); </div>);
} }
}, },

View File

@ -59,9 +59,9 @@ export default function Render(props) {
<div className={Style.keyBoard}> <div className={Style.keyBoard}>
</div> </div>
{config && config.button && config.button.length > 0 ? (<div className={Style.menu}> {config && config.button && config.button.length > 0 ? (<div className={Style.menu}>
{config.button.map((ele, index) => (<Popover open={!open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)) && tabKey === 'menu'} trigger={'click'} content={<div className={Style.subMenu}> {config.button.map((ele, index) => (<Popover key={`config_btn_${index}`} open={!open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)) && tabKey === 'menu'} trigger={'click'} content={<div className={Style.subMenu}>
{config.button[index].sub_button.length > 0 ? (<> {config.button[index].sub_button.length > 0 ? (<>
{config.button[index].sub_button.map((ele, index2) => (<div className={Style.subMenuContent}> {config.button[index].sub_button.map((ele, index2) => (<div key={`config_${index}_sub_button_${index2}`} className={Style.subMenuContent}>
<div className={Style.subMenuItem} style={errorIndex?.includes((index + 1) * 10 + index2) ? { <div className={Style.subMenuItem} style={errorIndex?.includes((index + 1) * 10 + index2) ? {
border: '1px solid #FF4D4F', border: '1px solid #FF4D4F',
color: '#FF4D4F' color: '#FF4D4F'

View File

@ -1,15 +1,13 @@
import React from 'react'; import React from 'react';
import { EntityDict } from "../../../oak-app-domain"; import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base'; import { WebComponentProps } from 'oak-frontend-base';
import { WechatPublicInstance } from 'oak-external-sdk/es/WechatSDK';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, { export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
button: any[]; button: any[];
wechatInstance: WechatPublicInstance;
}, { }, {
getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>; getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>;
getArticle: (article_id: string) => Promise<any[]>; getArticle: (article_id: string) => Promise<any[]>;
getMaterialVideo: (mediaId: string) => { getMaterialVideo: (mediaId: string) => Promise<{
url: string; url: string;
media_id: string; media_id: string;
}; }>;
}>): React.JSX.Element; }>): React.JSX.Element;

View File

@ -44,19 +44,23 @@ export default function Render(props) {
return; return;
} }
if (menu.subType === 'image' && menu.media_id) { if (menu.subType === 'image' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'image', content: await getMaterialImgAndVoice('image', menu.media_id) }]); const result = await getMaterialImgAndVoice('image', menu.media_id);
setSendMsg([...sendMsg, { type: 'image', content: result }]);
return; return;
} }
if (menu.type === 'article_id' && menu.article_id) { if (menu.type === 'article_id' && menu.article_id) {
setSendMsg([...sendMsg, { type: 'article_id', content: await getArticle(menu.article_id) }]); const result = await getArticle(menu.article_id);
setSendMsg([...sendMsg, { type: 'article_id', content: result }]);
return; return;
} }
if (menu.subType === 'voice' && menu.media_id) { if (menu.subType === 'voice' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'voice', content: { url: await getMaterialImgAndVoice('voice', menu.media_id), media_id: menu.media_id } }]); const result = await getMaterialImgAndVoice('voice', menu.media_id);
setSendMsg([...sendMsg, { type: 'voice', content: { url: result, media_id: menu.media_id } }]);
return; return;
} }
if (menu.subType === 'video' && menu.media_id) { if (menu.subType === 'video' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'video', content: { url: await getMaterialVideo(menu.media_id).url, media_id: menu.media_id } }]); const result = await getMaterialVideo(menu.media_id);
setSendMsg([...sendMsg, { type: 'video', content: { url: result.url, media_id: menu.media_id } }]);
return; return;
} }
}; };
@ -74,33 +78,34 @@ export default function Render(props) {
</div> </div>
<div className={Style.page}> <div className={Style.page}>
{(sendMsg && sendMsg.length > 0) && {(sendMsg && sendMsg.length > 0) &&
sendMsg.map((ele) => { sendMsg.map((ele, index) => {
if (ele.type === 'text') { if (ele.type === 'text') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<Editor defaultConfig={editorConfig} value={ele.content} mode="default" className={Style.editor}/> <Editor defaultConfig={editorConfig} value={ele.content} mode="default" className={Style.editor}/>
</div>; </div>;
} }
else if (ele.type === 'image') { else if (ele.type === 'image') {
return <img src={ele.content} className={Style.img}/>; return <img key={`${ele.type}_${index}`} src={ele.content} className={Style.img}/>;
} }
else if (ele.type === 'article_id') { else if (ele.type === 'article_id') {
return <div className={Style.news}> return <div key={`${ele.type}_${index}`} className={Style.news}>
<ShowNews news={ele.content}/> <ShowNews news={ele.content}/>
</div>; </div>;
} }
else if (ele.type === 'voice') { else if (ele.type === 'voice') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<a style={{ color: '#1677ff' }} href={ele.content.url} download={true}>{ele.content.media_id}</a> <a style={{ color: '#1677ff' }} href={ele.content.url} download={true}>{ele.content.media_id}</a>
</div>; </div>;
} }
else if (ele.type === 'video') { else if (ele.type === 'video') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<a style={{ color: '#1677ff' }} href={ele.content.url} download={true}>{ele.content.media_id}</a> <a style={{ color: '#1677ff' }} href={ele.content.url} download={true}>{ele.content.media_id}</a>
</div>; </div>;
} }
else if (ele.type === 'miniprogram') { else if (ele.type === 'miniprogram') {
return <div className={Style.msg}>{ele.content}</div>; return <div key={`${ele.type}_${index}`} className={Style.msg}>{ele.content}</div>;
} }
return null;
})} })}
</div> </div>
<div className={Style.bottomBar}> <div className={Style.bottomBar}>
@ -116,7 +121,7 @@ export default function Render(props) {
key: `${index * 10 + index2}`, key: `${index * 10 + index2}`,
}; };
}); });
return <Dropdown arrow={false} menu={{ items, onClick }} placement='top'> return <Dropdown key={`wechatMenu_button_${index}`} arrow={false} menu={{ items, onClick }} placement='top'>
<div className={Style.button}> <div className={Style.button}>
<MenuOutlined style={{ fontSize: 12, color: '#d0d0d0' }}/> <MenuOutlined style={{ fontSize: 12, color: '#d0d0d0' }}/>
<div className={Style.buttonName} style={{ marginLeft: 5 }}>{ele.name}</div> <div className={Style.buttonName} style={{ marginLeft: 5 }}>{ele.name}</div>
@ -124,7 +129,7 @@ export default function Render(props) {
</Dropdown>; </Dropdown>;
} }
else { else {
return <div className={Style.button} onClick={() => { return <div key={`menu_button_${index}`} className={Style.button} onClick={() => {
menuAction(ele); menuAction(ele);
}}> }}>
<div className={Style.buttonName}>{ele.name}</div> <div className={Style.buttonName}>{ele.name}</div>

View File

@ -1,6 +1,5 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { Button, Table, Space, Input, Popover, Select } from 'antd'; import { Button, Table, Space, Popover, Select } from 'antd';
const { TextArea } = Input;
import Style from './web.module.less'; import Style from './web.module.less';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import ShowNews from '../showNews'; import ShowNews from '../showNews';
@ -30,7 +29,7 @@ export default function Render(props) {
}); });
return (<div className={Style.selectArticle}> return (<div className={Style.selectArticle}>
<Select ref={selectRef} style={{ width: 160 }} bordered={false} value={urlList.includes(url) ? url : '请选择一篇文章'} dropdownRender={() => <div className={Style.select}> <Select ref={selectRef} style={{ width: 160 }} bordered={false} value={urlList.includes(url) ? url : '请选择一篇文章'} dropdownRender={() => <div className={Style.select}>
{record.content.news_item.map((ele, index) => (<Popover content={<div style={{ padding: 12 }}><ShowNews oakAutoUnmount={true} news={record.content.news_item.filter((ele, index2) => index === index2)}/></div>} placement='right'> {record.content.news_item.map((ele, index) => (<Popover key={`news_item_${index}`} content={<div style={{ padding: 12 }}><ShowNews oakAutoUnmount={true} news={record.content.news_item.filter((ele, index2) => index === index2)}/></div>} placement='right'>
<div className={Style.selectItem} onClick={() => { <div className={Style.selectItem} onClick={() => {
selectRef.current.blur(); selectRef.current.blur();
setUrl(ele.url); setUrl(ele.url);

View File

@ -7,23 +7,21 @@ export default function Render(props) {
<div className={Style.multiNews}> <div className={Style.multiNews}>
{news.map((ele, index) => { {news.map((ele, index) => {
if (index === 0) { if (index === 0) {
return (<div className={Style.cover}> return (<div key={`news_${index}`} className={Style.cover}>
<img className={Style.img} src={ele.coverUrl}/> <img className={Style.img} src={ele.coverUrl}/>
<div className={Style.articleTitle}> <div className={Style.articleTitle}>
{ele.title} {ele.title}
</div> </div>
</div>); </div>);
} }
else { return (<div key={`news_${index}`} className={Style.newsItem}>
return (<div className={Style.newsItem}> <div className={Style.articleTitle}>
<div className={Style.articleTitle}> {ele.title}
{ele.title} </div>
</div> <div className={Style.imgCover}>
<div className={Style.imgCover}> <img className={Style.img} src={ele.coverUrl}/>
<img className={Style.img} src={ele.coverUrl}/> </div>
</div> </div>);
</div>);
}
})} })}
</div> </div>
: :

View File

@ -122,7 +122,7 @@ export default function Render(props) {
}, [type, content]); }, [type, content]);
return (<div className={Style.container}> return (<div className={Style.container}>
<div className={Style.typeBar}> <div className={Style.typeBar}>
{types.map((ele) => (<div className={Style.item} style={type === ele.key ? { color: '#1677FF' } : {}} onClick={() => { {types.map((ele) => (<div key={ele.key} className={Style.item} style={type === ele.key ? { color: '#1677FF' } : {}} onClick={() => {
changeType(ele.key); changeType(ele.key);
}}> }}>
{ele.value} {ele.value}

View File

@ -4,6 +4,6 @@ import UnbindBtn from '../unbindBtn';
export default function Render(props) { export default function Render(props) {
const { wechatUsers, oakFullpath } = props.data; const { wechatUsers, oakFullpath } = props.data;
return (<Space> return (<Space>
{wechatUsers && wechatUsers.map((ele) => (<UnbindBtn oakId={ele.id} oakPath={`${oakFullpath}.${ele.id}`}/>))} {wechatUsers && wechatUsers.map((ele) => (<UnbindBtn key={ele.id} oakId={ele.id} oakPath={`${oakFullpath}.${ele.id}`}/>))}
</Space>); </Space>);
} }

View File

@ -109,8 +109,7 @@ export default function Render(
editor.getElemsByTypePrefix("header"); editor.getElemsByTypePrefix("header");
const tocItems = headers.map( const tocItems = headers.map(
(header: any) => { (header: any) => {
const text = const text = SlateNode.string(header);
SlateNode.string(header);
const { id, type } = header; const { id, type } = header;
return { return {
text, text,

View File

@ -100,8 +100,7 @@ export default function Render(
editor.getElemsByTypePrefix("header"); editor.getElemsByTypePrefix("header");
const tocItems = headers.map( const tocItems = headers.map(
(header: any) => { (header: any) => {
const text = const text = SlateNode.string(header);
SlateNode.string(header);
const { id, type } = header; const { id, type } = header;
return { return {
text, text,

View File

@ -82,8 +82,7 @@ export default OakComponent({
size, size,
} = tempExtraFile; } = tempExtraFile;
const filePath = tempFilePath || thumbTempFilePath; const filePath = tempFilePath || thumbTempFilePath;
const fileFullName = const fileFullName = filePath.match(/[^/]+(?!.*\/)/g)![0];
filePath.match(/[^/]+(?!.*\/)/g)![0];
this.pushExtraFile({ this.pushExtraFile({
name: fileFullName, name: fileFullName,
fileType, fileType,

View File

@ -60,6 +60,7 @@ export default function render(
<div className={Style.methodList}> <div className={Style.methodList}>
{methods && methods.map((ele) => ( {methods && methods.map((ele) => (
<div <div
key={ele}
className={Style.methodListItem} className={Style.methodListItem}
onClick={() => { onClick={() => {
chooseMethod(ele); chooseMethod(ele);

View File

@ -49,8 +49,9 @@ export default function render(
}} }}
> >
<Space> <Space>
{files?.map((ele) => ( {files?.map((ele, index) => (
<Image <Image
key={`file_image_${index}`}
width={120} width={120}
src={ele.thumbUrl} src={ele.thumbUrl}
preview={ preview={

View File

@ -48,6 +48,7 @@ export default function render(
<Space> <Space>
{files?.map((ele, index) => ( {files?.map((ele, index) => (
<Image <Image
key={`file_image_${index}`}
src={ele.thumbUrl} src={ele.thumbUrl}
width={100} width={100}
height={100} height={100}

View File

@ -169,7 +169,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'token', fal
<Space direction="horizontal"> <Space direction="horizontal">
{ {
GenderOptions.map( GenderOptions.map(
ele => <Radio value={ele.value}>{ele.label}</Radio> ele => <Radio key={ele.value} value={ele.value}>{ele.label}</Radio>
) )
} }
</Space> </Space>

View File

@ -56,7 +56,7 @@ export default function render(props: WebComponentProps<
type: EntityDict['passport']['Schema']['type']; type: EntityDict['passport']['Schema']['type'];
tip: string; tip: string;
}[]; }[];
myConfirm: (ids: string[]) => void; myConfirm: (ids: string[]) => Promise<void>;
} }
>) { >) {
const { data, methods } = props; const { data, methods } = props;

View File

@ -61,6 +61,7 @@ export default function render(
{stations?.map((ele: any) => { {stations?.map((ele: any) => {
return ( return (
<Checkbox <Checkbox
key={ele.value}
disabled={selectIds?.includes( disabled={selectIds?.includes(
ele.value ele.value
)} )}

View File

@ -71,7 +71,7 @@ export default function Render(
value={idCardType} value={idCardType}
> >
{idCardTypeArr.map((ele, index) => { {idCardTypeArr.map((ele, index) => {
return <Radio value={ele.value}>{ele.label}</Radio>; return <Radio key={ele.value} value={ele.value}>{ele.label}</Radio>;
})} })}
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>

View File

@ -192,7 +192,7 @@ export default function render(
> >
{genderOptions.map( {genderOptions.map(
(ele: { value: string; label: string }) => ( (ele: { value: string; label: string }) => (
<Radio value={ele.value}> <Radio key={ele.value} value={ele.value}>
{ele.label} {ele.label}
</Radio> </Radio>
) )

View File

@ -68,7 +68,7 @@ export default function Render(
onChange={(val) => onPickRows(val as string[])} onChange={(val) => onPickRows(val as string[])}
> >
{rows.map((row) => ( {rows.map((row) => (
<Checkbox value={row.id}>{row.value}</Checkbox> <Checkbox key={row.id} value={row.id}>{row.value}</Checkbox>
))} ))}
</Checkbox.Group> </Checkbox.Group>
</> </>
@ -86,7 +86,7 @@ export default function Render(
onChange={(val) => onPickRelations(val as string[])} onChange={(val) => onPickRelations(val as string[])}
> >
{relations.map((relation) => ( {relations.map((relation) => (
<Checkbox value={relation.id}> <Checkbox key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</Checkbox> </Checkbox>
))} ))}
@ -100,7 +100,7 @@ export default function Render(
value={pickedRelationIds?.[0] || undefined} value={pickedRelationIds?.[0] || undefined}
> >
{relations.map((relation) => ( {relations.map((relation) => (
<Radio value={relation.id}> <Radio key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</Radio> </Radio>
))} ))}

View File

@ -52,7 +52,7 @@ export default function Render(
{ {
rows.map( rows.map(
(row) => ( (row) => (
<CheckList.Item value={row.id}> <CheckList.Item key={row.id} value={row.id}>
{row.value} {row.value}
</CheckList.Item> </CheckList.Item>
) )
@ -73,7 +73,7 @@ export default function Render(
{ {
relations.map( relations.map(
(relation) => ( (relation) => (
<CheckList.Item value={relation.id}> <CheckList.Item key={relation.id} value={relation.id}>
{t(`${entity}:r.${relation.name}`)} {t(`${entity}:r.${relation.name}`)}
</CheckList.Item> </CheckList.Item>
) )

View File

@ -109,13 +109,9 @@ export default function Render(
<Space> <Space>
{record.userRelation$user?.map( {record.userRelation$user?.map(
(ele, index) => ( (ele, index) => (
<Tag key={index}> <Tag key={ele.id}>
{ele.relation.name {ele.relation.name
? t( ? t( entity +':r.' + ele.relation.name)
entity +
':r.' +
ele.relation.name
)
: ele.relation.display} : ele.relation.display}
</Tag> </Tag>
) )

View File

@ -76,6 +76,7 @@ export default function Render(
{users?.map((ele, index) => { {users?.map((ele, index) => {
return ( return (
<List.Item <List.Item
key={ele.id}
prefix={ prefix={
ele.avatar ? ( ele.avatar ? (
<Avatar <Avatar
@ -98,14 +99,9 @@ export default function Render(
> >
{ele.userRelation$user?.map( {ele.userRelation$user?.map(
(ele2, index2) => ( (ele2, index2) => (
<Tag key={index} fill="outline"> <Tag key={ele2.id} fill="outline">
{ele2.relation?.name {ele2.relation?.name
? t( ? t(entity + ':r.' + ele2.relation!.name)
entity +
':r.' +
ele2.relation!
.name
)
: ele2.relation?.display} : ele2.relation?.display}
</Tag> </Tag>
) )

View File

@ -92,9 +92,7 @@ export default function render(
}} }}
options={relations?.map((ele) => ({ options={relations?.map((ele) => ({
value: ele.id, value: ele.id,
label: label: ele.display || relationEntity && t(`${relationEntity as string}:r.${ele.name}`),
ele.display ||
relationEntity && t(`${relationEntity as string}:r.${ele.name}`),
}))} }))}
/> />
</Form.Item> </Form.Item>

View File

@ -87,12 +87,8 @@ export default function render(
> >
<Space direction="vertical"> <Space direction="vertical">
{relations?.map((ele) => ( {relations?.map((ele) => (
<Checkbox value={ele.id}> <Checkbox key={ele.id} value={ele.id}>
{ele.display || {ele.display || t(`${relationEntity as string}:r.${ele.name}`)}
t(
`${relationEntity as string}:r.${ele.name
}`
)}
</Checkbox> </Checkbox>
))} ))}
</Space> </Space>
@ -116,7 +112,7 @@ export default function render(
> >
<Space direction="vertical"> <Space direction="vertical">
{rules.map((ele) => ( {rules.map((ele) => (
<Radio value={ele}> <Radio key={ele} value={ele}>
{t(`userEntityGrant:v.rule.${ele}`)} {t(`userEntityGrant:v.rule.${ele}`)}
</Radio> </Radio>
))} ))}

View File

@ -53,11 +53,12 @@ export default function Render(
(ele) => { (ele) => {
switch (ele) { switch (ele) {
case 'email': { case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>; return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
} }
case 'mobile': { case 'mobile': {
return ( return (
<ByMobile <ByMobile
key={ele}
passwordRequired={passwordRequired} passwordRequired={passwordRequired}
entity={entity} entity={entity}
entityId={entityId} entityId={entityId}
@ -70,6 +71,7 @@ export default function Render(
case 'userEntityGrant': { case 'userEntityGrant': {
return ( return (
<ByUserEntityGrant <ByUserEntityGrant
key={ele}
qrCodeType={qrCodeType} qrCodeType={qrCodeType}
entity={entity} entity={entity}
entityId={entityId} entityId={entityId}

View File

@ -53,11 +53,12 @@ export default function Render(
(ele) => { (ele) => {
switch (ele) { switch (ele) {
case 'email': { case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>; return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
} }
case 'mobile': { case 'mobile': {
return ( return (
<ByMobile <ByMobile
key={ele}
passwordRequired={passwordRequired} passwordRequired={passwordRequired}
entity={entity} entity={entity}
entityId={entityId} entityId={entityId}
@ -70,6 +71,7 @@ export default function Render(
case 'userEntityGrant': { case 'userEntityGrant': {
return ( return (
<ByUserEntityGrant <ByUserEntityGrant
key={ele}
qrCodeType={qrCodeType} qrCodeType={qrCodeType}
entity={entity} entity={entity}
entityId={entityId} entityId={entityId}

View File

@ -93,7 +93,7 @@ export default function Render(
id: string; id: string;
text: string; text: string;
}) => { }) => {
return <Tag>{ele.text}</Tag>; return <Tag key={ele.id}>{ele.text}</Tag>;
} }
) )
: '暂无标签'} : '暂无标签'}
@ -217,7 +217,7 @@ export default function Render(
<Descriptions.Item label="用户标签"> <Descriptions.Item label="用户标签">
{user.tags && user.tags.length > 0 {user.tags && user.tags.length > 0
? user.tags.map((tag) => { ? user.tags.map((tag) => {
return <Tag>{tag.text}</Tag>; return <Tag key={tag.id}>{tag.text}</Tag>;
}) })
: '暂无标签'} : '暂无标签'}
</Descriptions.Item> </Descriptions.Item>

View File

@ -135,8 +135,8 @@ export default function Render(
return ( return (
<div> <div>
{ {
record.content.news_item.map((ele: any) => ( record.content.news_item.map((ele: any, index: number) => (
<div><img style={{ width: 100 }} src={ele.coverUrl} /></div> <div key={`coverUrl${index}`}><img style={{ width: 100 }} src={ele.coverUrl} /></div>
)) ))
} }
</div> </div>
@ -150,8 +150,8 @@ export default function Render(
return ( return (
<div> <div>
{ {
record.content.news_item.map((ele: any) => ( record.content.news_item.map((ele: any, index: number) => (
<div>{ele.title}</div> <div key={`title${index}`}>{ele.title}</div>
)) ))
} }
</div> </div>
@ -165,8 +165,8 @@ export default function Render(
return ( return (
<div> <div>
{ {
record.content.news_item.map((ele: any) => ( record.content.news_item.map((ele: any, index: number) => (
<div>{ele.author}</div> <div key={`author${index}`}>{ele.author}</div>
)) ))
} }
</div> </div>
@ -180,8 +180,8 @@ export default function Render(
return ( return (
<div> <div>
{ {
record.content.news_item.map((ele: any) => ( record.content.news_item.map((ele: any, index: number) => (
<div>{ele.digest}</div> <div key={`digest${index}`}>{ele.digest}</div>
)) ))
} }
</div> </div>

View File

@ -122,6 +122,7 @@ export default function Render(
{ {
config.button.map((ele: any, index: number) => ( config.button.map((ele: any, index: number) => (
<Popover <Popover
key={`config_btn_${index}`}
open={!open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)) && tabKey === 'menu'} open={!open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)) && tabKey === 'menu'}
trigger={'click'} trigger={'click'}
content={ content={
@ -131,7 +132,7 @@ export default function Render(
<> <>
{ {
config.button[index].sub_button.map((ele: { name: string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | React.ReactFragment | React.ReactPortal | null | undefined; }, index2: number) => ( config.button[index].sub_button.map((ele: { name: string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | React.ReactFragment | React.ReactPortal | null | undefined; }, index2: number) => (
<div className={Style.subMenuContent}> <div key={`config_${index}_sub_button_${index2}`} className={Style.subMenuContent}>
<div className={Style.subMenuItem} <div className={Style.subMenuItem}
style={ style={
errorIndex?.includes((index + 1) * 10 + index2) ? { errorIndex?.includes((index + 1) * 10 + index2) ? {

View File

@ -1,12 +1,11 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { EntityDict } from "../../../oak-app-domain"; import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base'; import { WebComponentProps } from 'oak-frontend-base';
import { Modal, Button, Table, Space, Upload, Form, Input, Dropdown, MenuProps } from 'antd'; import { Dropdown, MenuProps } from 'antd';
import { WifiOutlined, LeftOutlined, UserOutlined, MenuOutlined } from '@ant-design/icons' import { WifiOutlined, LeftOutlined, UserOutlined, MenuOutlined } from '@ant-design/icons'
import Style from './web.module.less'; import Style from './web.module.less';
import { Editor } from '@wangeditor/editor-for-react'; import { Editor } from '@wangeditor/editor-for-react';
import { IEditorConfig } from '@wangeditor/editor'; import { IEditorConfig } from '@wangeditor/editor';
import WechatSDK, { WechatMpInstance, WechatPublicInstance } from 'oak-external-sdk/es/WechatSDK';
import ShowNews from '../showNews'; import ShowNews from '../showNews';
export default function Render( export default function Render(
@ -16,12 +15,11 @@ export default function Render(
false, false,
{ {
button: any[]; button: any[];
wechatInstance: WechatPublicInstance,
}, },
{ {
getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>; getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>;
getArticle: (article_id: string) => Promise<any[]>; getArticle: (article_id: string) => Promise<any[]>;
getMaterialVideo: (mediaId: string) => { url: string, media_id: string }; getMaterialVideo: (mediaId: string) => Promise<{ url: string, media_id: string }>;
} }
> >
) { ) {
@ -63,19 +61,23 @@ export default function Render(
return; return;
} }
if (menu.subType === 'image' && menu.media_id) { if (menu.subType === 'image' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'image', content: await getMaterialImgAndVoice('image', menu.media_id) }]); const result = await getMaterialImgAndVoice('image', menu.media_id);
setSendMsg([...sendMsg, { type: 'image', content: result }]);
return; return;
} }
if (menu.type === 'article_id' && menu.article_id) { if (menu.type === 'article_id' && menu.article_id) {
setSendMsg([...sendMsg, { type: 'article_id', content: await getArticle(menu.article_id) }]) const result = await getArticle(menu.article_id);
setSendMsg([...sendMsg, { type: 'article_id', content: result }])
return; return;
} }
if (menu.subType === 'voice' && menu.media_id) { if (menu.subType === 'voice' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'voice', content: { url: await getMaterialImgAndVoice('voice', menu.media_id), media_id: menu.media_id } }]); const result = await getMaterialImgAndVoice('voice', menu.media_id);
setSendMsg([...sendMsg, { type: 'voice', content: { url: result, media_id: menu.media_id } }]);
return; return;
} }
if (menu.subType === 'video' && menu.media_id) { if (menu.subType === 'video' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'video', content: { url: await getMaterialVideo(menu.media_id).url, media_id: menu.media_id } }]); const result = await getMaterialVideo(menu.media_id);
setSendMsg([...sendMsg, { type: 'video', content: { url: result.url, media_id: menu.media_id } }]);
return; return;
} }
} }
@ -95,9 +97,9 @@ export default function Render(
<div className={Style.page}> <div className={Style.page}>
{ {
(sendMsg && sendMsg.length > 0) && (sendMsg && sendMsg.length > 0) &&
sendMsg.map((ele) => { sendMsg.map((ele, index) => {
if (ele.type === 'text') { if (ele.type === 'text') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<Editor <Editor
defaultConfig={editorConfig} defaultConfig={editorConfig}
value={ele.content as string} value={ele.content as string}
@ -106,24 +108,25 @@ export default function Render(
/> />
</div> </div>
} else if (ele.type === 'image') { } else if (ele.type === 'image') {
return <img src={ele.content as string} className={Style.img} /> return <img key={`${ele.type}_${index}`} src={ele.content as string} className={Style.img} />
} else if (ele.type === 'article_id') { } else if (ele.type === 'article_id') {
return <div className={Style.news}> return <div key={`${ele.type}_${index}`} className={Style.news}>
<ShowNews <ShowNews
news={ele.content as any[]} news={ele.content as any[]}
/> />
</div> </div>
} else if (ele.type === 'voice') { } else if (ele.type === 'voice') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<a style={{ color: '#1677ff' }} href={(ele.content as { url: string, media_id: string }).url} download={true}>{(ele.content as { url: string, media_id: string }).media_id}</a> <a style={{ color: '#1677ff' }} href={(ele.content as { url: string, media_id: string }).url} download={true}>{(ele.content as { url: string, media_id: string }).media_id}</a>
</div> </div>
} else if (ele.type === 'video') { } else if (ele.type === 'video') {
return <div className={Style.msg}> return <div key={`${ele.type}_${index}`} className={Style.msg}>
<a style={{ color: '#1677ff' }} href={(ele.content as { url: string, media_id: string }).url} download={true}>{(ele.content as { url: string, media_id: string }).media_id}</a> <a style={{ color: '#1677ff' }} href={(ele.content as { url: string, media_id: string }).url} download={true}>{(ele.content as { url: string, media_id: string }).media_id}</a>
</div> </div>
} else if (ele.type === 'miniprogram') { } else if (ele.type === 'miniprogram') {
return <div className={Style.msg}>{ele.content as string}</div> return <div key={`${ele.type}_${index}`} className={Style.msg}>{ele.content as string}</div>
} }
return null
}) })
} }
</div> </div>
@ -142,6 +145,7 @@ export default function Render(
} }
}) })
return <Dropdown return <Dropdown
key={`wechatMenu_button_${index}`}
arrow={false} arrow={false}
menu={{ items, onClick }} menu={{ items, onClick }}
placement='top' placement='top'
@ -152,7 +156,7 @@ export default function Render(
</div> </div>
</Dropdown> </Dropdown>
} else { } else {
return <div className={Style.button} onClick={() => { return <div key={`menu_button_${index}`} className={Style.button} onClick={() => {
menuAction(ele) menuAction(ele)
}}> }}>
<div className={Style.buttonName}>{ele.name}</div> <div className={Style.buttonName}>{ele.name}</div>

View File

@ -2,14 +2,9 @@ import React, { useState, useEffect, useRef } from 'react';
import { EntityDict } from "../../../oak-app-domain"; import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base'; import { WebComponentProps } from 'oak-frontend-base';
import { Modal, Button, Table, Space, Upload, Form, Input, Popover, Select } from 'antd'; import { Modal, Button, Table, Space, Upload, Form, Input, Popover, Select } from 'antd';
const { TextArea } = Input;
import type { ColumnsType } from 'antd/es/table'; import type { ColumnsType } from 'antd/es/table';
import { DownloadOutlined } from '@ant-design/icons'
import Style from './web.module.less'; import Style from './web.module.less';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import fs from 'fs';
import { RcFile, UploadChangeParam } from 'antd/lib/upload/interface';
import type { UploadFile } from 'antd/es/upload/interface';
import ShowNews from '../showNews'; import ShowNews from '../showNews';
@ -65,6 +60,7 @@ export default function Render(
{ {
record.content.news_item.map((ele: any, index: number) => ( record.content.news_item.map((ele: any, index: number) => (
<Popover <Popover
key={`news_item_${index}`}
content={<div style={{ padding: 12 }}><ShowNews oakAutoUnmount={true} news={record.content.news_item.filter((ele: any, index2: number) => index === index2)} /></div>} content={<div style={{ padding: 12 }}><ShowNews oakAutoUnmount={true} news={record.content.news_item.filter((ele: any, index2: number) => index === index2)} /></div>}
placement='right' placement='right'
> >

View File

@ -26,25 +26,24 @@ export default function Render(
news.map((ele: any, index: number) => { news.map((ele: any, index: number) => {
if (index === 0) { if (index === 0) {
return ( return (
<div className={Style.cover}> <div key={`news_${index}`} className={Style.cover}>
<img className={Style.img} src={ele.coverUrl} /> <img className={Style.img} src={ele.coverUrl} />
<div className={Style.articleTitle}> <div className={Style.articleTitle}>
{ele.title} {ele.title}
</div> </div>
</div> </div>
) )
} else {
return (
<div className={Style.newsItem}>
<div className={Style.articleTitle}>
{ele.title}
</div>
<div className={Style.imgCover}>
<img className={Style.img} src={ele.coverUrl} />
</div>
</div>
)
} }
return (
<div key={`news_${index}`} className={Style.newsItem}>
<div className={Style.articleTitle}>
{ele.title}
</div>
<div className={Style.imgCover}>
<img className={Style.img} src={ele.coverUrl} />
</div>
</div>
)
}) })
} }
</div> </div>

View File

@ -166,7 +166,7 @@ export default function Render(
<div className={Style.typeBar}> <div className={Style.typeBar}>
{ {
types.map((ele) => ( types.map((ele) => (
<div className={Style.item} <div key={ele.key} className={Style.item}
style={type === ele.key ? { color: '#1677FF' } : {}} style={type === ele.key ? { color: '#1677FF' } : {}}
onClick={() => { onClick={() => {
changeType(ele.key as ReplyType); changeType(ele.key as ReplyType);

View File

@ -22,6 +22,7 @@ export default function Render(
<Space> <Space>
{wechatUsers && wechatUsers.map((ele) => ( {wechatUsers && wechatUsers.map((ele) => (
<UnbindBtn <UnbindBtn
key={ele.id}
oakId={ele.id} oakId={ele.id}
oakPath={`${oakFullpath}.${ele.id}`} oakPath={`${oakFullpath}.${ele.id}`}
/> />