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>
<img id="previewImg" src={src} alt="previewImg" className={Style.previewImg} style={{ display: src ? 'inline-block' : 'none' }}/>
<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);
}}>
{t(ele)}

View File

@ -7,7 +7,7 @@ export default function render(props) {
const imageViewerMultiRef = useRef(null);
return (<>
<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);
imageViewerMultiRef.current.swipeTo(index);
} : undefined}/>))}

View File

@ -8,7 +8,7 @@ export default function render(props) {
onChange: (current, prev) => { },
}}>
<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,
}

View File

@ -104,7 +104,7 @@ export default function Render(props) {
setUpdateValue(value);
}}>
<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>
</Radio.Group>}
</Form.Item>

View File

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

View File

@ -18,7 +18,7 @@ export default function render(props) {
label: ele.name,
children: (<Space size={[0, 16]} wrap>
{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);
}} checked={stationIds
.concat(selectIds || [])

View File

@ -26,7 +26,7 @@ export default function Render(props) {
});
}} value={idCardType}>
{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>
</Form.Item>

View File

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

View File

@ -14,7 +14,7 @@ export default function Render(props) {
: (<div>
<Form.Header>{t('pickRow', { entity: t(`${entity}:name`) })}</Form.Header>
<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}
</CheckList.Item>))}
</CheckList>
@ -22,7 +22,7 @@ export default function Render(props) {
const Relation = (<div>
<List mode='card' header={t(`pickRelation.${pickRelationRule}`)}>
<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}`)}
</CheckList.Item>))}
</CheckList>

View File

@ -17,7 +17,7 @@ export default function Render(props) {
{t('pickRow', { entity: t(`${entity}:name`) })}
</Divider>
<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>
</>);
const Relation = (<>
@ -26,14 +26,14 @@ export default function Render(props) {
</Divider>
<List>
{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}`)}
</Checkbox>))}
</Checkbox.Group>) : (<Radio.Group onChange={(e) => {
const val = e.target.value;
onPickRelations([val]);
}} 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}`)}
</Radio>))}
</Radio.Group>)}

View File

@ -25,16 +25,13 @@ export default function Render(props) {
</span>
<List>
{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',
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
? t(entity +
':r.' +
ele2.relation
.name)
? t(entity + ':r.' + ele2.relation.name)
: ele2.relation?.display}
</Tag>))}
</div>} onClick={() => goUpdate(ele.id)}>

View File

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

View File

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

View File

@ -24,8 +24,7 @@ export default function render(props) {
update({ relationIds: val });
}} options={relations?.map((ele) => ({
value: ele.id,
label: ele.display ||
relationEntity && t(`${relationEntity}:r.${ele.name}`),
label: ele.display || relationEntity && t(`${relationEntity}:r.${ele.name}`),
}))}/>
</Form.Item>
{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) => {
switch (ele) {
case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>;
return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
}
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': {
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) => {
switch (ele) {
case 'email': {
return <div className={Style.container}>{t('not-implemented')}</div>;
return <div key={ele} className={Style.container}>{t('not-implemented')}</div>;
}
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': {
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>
{value && value.length > 0
? value.map((ele) => {
return <Tag>{ele.text}</Tag>;
return <Tag key={ele.id}>{ele.text}</Tag>;
})
: '暂无标签'}
</div>);
@ -136,7 +136,7 @@ export default function Render(props) {
<Descriptions.Item label="用户标签">
{user.tags && user.tags.length > 0
? user.tags.map((tag) => {
return <Tag>{tag.text}</Tag>;
return <Tag key={tag.id}>{tag.text}</Tag>;
})
: '暂无标签'}
</Descriptions.Item>

View File

@ -112,7 +112,7 @@ export default function Render(props) {
title: '封面图',
render: (value, record, index) => {
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>);
}
},
@ -121,7 +121,7 @@ export default function Render(props) {
title: '图文消息标题',
render: (value, record, index) => {
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>);
}
},
@ -130,7 +130,7 @@ export default function Render(props) {
title: '作者',
render: (value, record, index) => {
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>);
}
},
@ -139,7 +139,7 @@ export default function Render(props) {
title: '图文信息摘要',
render: (value, record, index) => {
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>);
}
},

View File

@ -59,9 +59,9 @@ export default function Render(props) {
<div className={Style.keyBoard}>
</div>
{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.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) ? {
border: '1px solid #FF4D4F',
color: '#FF4D4F'

View File

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

View File

@ -44,19 +44,23 @@ export default function Render(props) {
return;
}
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;
}
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;
}
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;
}
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;
}
};
@ -74,33 +78,34 @@ export default function Render(props) {
</div>
<div className={Style.page}>
{(sendMsg && sendMsg.length > 0) &&
sendMsg.map((ele) => {
sendMsg.map((ele, index) => {
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}/>
</div>;
}
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') {
return <div className={Style.news}>
return <div key={`${ele.type}_${index}`} className={Style.news}>
<ShowNews news={ele.content}/>
</div>;
}
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>
</div>;
}
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>
</div>;
}
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 className={Style.bottomBar}>
@ -116,7 +121,7 @@ export default function Render(props) {
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}>
<MenuOutlined style={{ fontSize: 12, color: '#d0d0d0' }}/>
<div className={Style.buttonName} style={{ marginLeft: 5 }}>{ele.name}</div>
@ -124,7 +129,7 @@ export default function Render(props) {
</Dropdown>;
}
else {
return <div className={Style.button} onClick={() => {
return <div key={`menu_button_${index}`} className={Style.button} onClick={() => {
menuAction(ele);
}}>
<div className={Style.buttonName}>{ele.name}</div>

View File

@ -1,6 +1,5 @@
import React, { useState, useRef } from 'react';
import { Button, Table, Space, Input, Popover, Select } from 'antd';
const { TextArea } = Input;
import { Button, Table, Space, Popover, Select } from 'antd';
import Style from './web.module.less';
import dayjs from 'dayjs';
import ShowNews from '../showNews';
@ -30,7 +29,7 @@ export default function Render(props) {
});
return (<div className={Style.selectArticle}>
<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={() => {
selectRef.current.blur();
setUrl(ele.url);

View File

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

View File

@ -122,7 +122,7 @@ export default function Render(props) {
}, [type, content]);
return (<div className={Style.container}>
<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);
}}>
{ele.value}

View File

@ -4,6 +4,6 @@ import UnbindBtn from '../unbindBtn';
export default function Render(props) {
const { wechatUsers, oakFullpath } = props.data;
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>);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -71,7 +71,7 @@ export default function Render(
value={idCardType}
>
{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>
</Form.Item>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -122,6 +122,7 @@ export default function Render(
{
config.button.map((ele: any, index: number) => (
<Popover
key={`config_btn_${index}`}
open={!open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)) && tabKey === 'menu'}
trigger={'click'}
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) => (
<div className={Style.subMenuContent}>
<div key={`config_${index}_sub_button_${index2}`} className={Style.subMenuContent}>
<div className={Style.subMenuItem}
style={
errorIndex?.includes((index + 1) * 10 + index2) ? {

View File

@ -1,12 +1,11 @@
import React, { useState, useEffect } from 'react';
import { EntityDict } from "../../../oak-app-domain";
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 Style from './web.module.less';
import { Editor } from '@wangeditor/editor-for-react';
import { IEditorConfig } from '@wangeditor/editor';
import WechatSDK, { WechatMpInstance, WechatPublicInstance } from 'oak-external-sdk/es/WechatSDK';
import ShowNews from '../showNews';
export default function Render(
@ -16,12 +15,11 @@ export default function Render(
false,
{
button: any[];
wechatInstance: WechatPublicInstance,
},
{
getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>;
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;
}
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;
}
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;
}
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;
}
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;
}
}
@ -95,9 +97,9 @@ export default function Render(
<div className={Style.page}>
{
(sendMsg && sendMsg.length > 0) &&
sendMsg.map((ele) => {
sendMsg.map((ele, index) => {
if (ele.type === 'text') {
return <div className={Style.msg}>
return <div key={`${ele.type}_${index}`} className={Style.msg}>
<Editor
defaultConfig={editorConfig}
value={ele.content as string}
@ -106,24 +108,25 @@ export default function Render(
/>
</div>
} 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') {
return <div className={Style.news}>
return <div key={`${ele.type}_${index}`} className={Style.news}>
<ShowNews
news={ele.content as any[]}
/>
</div>
} 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>
</div>
} 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>
</div>
} 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>
@ -142,6 +145,7 @@ export default function Render(
}
})
return <Dropdown
key={`wechatMenu_button_${index}`}
arrow={false}
menu={{ items, onClick }}
placement='top'
@ -152,7 +156,7 @@ export default function Render(
</div>
</Dropdown>
} else {
return <div className={Style.button} onClick={() => {
return <div key={`menu_button_${index}`} className={Style.button} onClick={() => {
menuAction(ele)
}}>
<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 { WebComponentProps } from 'oak-frontend-base';
import { Modal, Button, Table, Space, Upload, Form, Input, Popover, Select } from 'antd';
const { TextArea } = Input;
import type { ColumnsType } from 'antd/es/table';
import { DownloadOutlined } from '@ant-design/icons'
import Style from './web.module.less';
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';
@ -65,6 +60,7 @@ export default function Render(
{
record.content.news_item.map((ele: any, index: number) => (
<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>}
placement='right'
>

View File

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

View File

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

View File

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