build
This commit is contained in:
parent
1e83328323
commit
e0e11ad0da
|
|
@ -1,2 +1,2 @@
|
|||
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
||||
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
||||
export default checkers;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
import { Config } from '../../../../types/Config';
|
||||
export default function Email(props: {
|
||||
emails: Required<Config>['Emails'];
|
||||
setValue: (path: string, value: any) => void;
|
||||
removeItem: (path: string, index: number) => void;
|
||||
cleanKey: (path: string, key: string) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import React from 'react';
|
||||
import { Tabs, Col, Divider, Input, Form, Space, Modal, } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
const { confirm } = Modal;
|
||||
export default function Email(props) {
|
||||
const { emails, setValue, removeItem, cleanKey, } = props;
|
||||
return (<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
{/* <Row>
|
||||
<Card className={Styles.tips}>
|
||||
每种均可配置一个,相应的服务所使用的帐号请准确对应
|
||||
</Card>
|
||||
</Row> */}
|
||||
<Col flex="auto">
|
||||
<Divider orientation="left" className={Styles.title}>
|
||||
邮箱配置
|
||||
</Divider>
|
||||
<Tabs tabPosition={'top'} size={'middle'} type="editable-card" hideAdd={!(emails.length > 0)} onEdit={(targetKey, action) => {
|
||||
if (action === 'add') {
|
||||
setValue(`${emails.length}`, {});
|
||||
}
|
||||
else {
|
||||
removeItem('', parseInt(targetKey, 10));
|
||||
}
|
||||
}} items={emails.length > 0
|
||||
? emails.map((ele, idx) => ({
|
||||
key: `${idx}`,
|
||||
label: ele.account ? ele.account : `邮箱${idx + 1}`,
|
||||
children: (<Form colon={false} labelAlign="left" layout="vertical" style={{ marginTop: 10 }}>
|
||||
<Form.Item label="主机名">
|
||||
<>
|
||||
<Input placeholder="请输入主机名(例:smtp.163.com)" type="text" value={ele.host} onChange={(e) => {
|
||||
setValue(`${idx}.host`, e.target.value);
|
||||
}}/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="端口">
|
||||
<Input placeholder="请输入端口号(例:465)" value={ele.port} onChange={(e) => {
|
||||
setValue(`${idx}.port`, Number(e.target.value));
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="账号">
|
||||
<Input placeholder="请输入邮箱账号(例:xxxx@163.com)" type="text" value={ele.account} onChange={(e) => {
|
||||
setValue(`${idx}.account`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="授权码">
|
||||
<Input type="password" value={ele.password} onChange={(e) => {
|
||||
setValue(`${idx}.password`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="发件人名称" tooltip="选填,若未填写则显示邮箱账号">
|
||||
<Input placeholder="请输入发件人名称" type="text" value={ele.name} onChange={(e) => {
|
||||
setValue(`${idx}.name`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Form>),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
label: '新建帐号',
|
||||
key: '0',
|
||||
children: (<Form colon={true} labelAlign="left" layout="vertical" style={{ marginTop: 10 }}>
|
||||
|
||||
<Form.Item label="主机名">
|
||||
<>
|
||||
<Input placeholder="请输入主机名(例:smtp.163.com)" type="text" value="" onChange={(e) => {
|
||||
setValue(`0.host`, e.target.value);
|
||||
}}/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="端口">
|
||||
<Input placeholder="请输入端口号(例:465)" value="" onChange={(e) => {
|
||||
setValue(`0.port`, Number(e.target.value));
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="账号">
|
||||
<Input placeholder="请输入邮箱账号(例:xxxx@163.com)" type="text" value="" onChange={(e) => {
|
||||
setValue(`0.account`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="授权码">
|
||||
<Input type="password" value="" onChange={(e) => {
|
||||
setValue(`0.password`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="发件人名称" tooltip="选填,若未填写则显示邮箱账号">
|
||||
<Input placeholder="请输入发件人名称" type="text" value="" onChange={(e) => {
|
||||
setValue(`0.name`, e.target.value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Form>),
|
||||
},
|
||||
]}></Tabs>
|
||||
</Col>
|
||||
</Space>);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
.label {
|
||||
color: var(--oak-text-color-primary);
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: var(--oak-text-color-placeholder);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 0px;
|
||||
margin-top:36px;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import React from "react";
|
||||
import { EmailConfig, MfwConfig, PfwConfig, SmsConfig } from "../../../entities/Passport";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
import '@wangeditor/editor/dist/css/style.css';
|
||||
export default function Email(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
updateConfig: (id: string, config: SmsConfig | EmailConfig | PfwConfig | MfwConfig, path: string, value: any) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Space, Switch, Alert, Typography, Form, Input, Radio, Tag } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
|
||||
const { TextArea } = Input;
|
||||
const { Text } = Typography;
|
||||
export default function Email(props) {
|
||||
const { passport, t, changeEnabled, updateConfig } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
const config = passport.config || {};
|
||||
const [subject, setSubject] = useState(config?.subject || '');
|
||||
const [eContentType, setEContentType] = useState('text');
|
||||
const [text, setText] = useState(config?.text || '');
|
||||
const [html, setHtml] = useState(config?.html || '');
|
||||
const [emailCodeDuration, setEmailCodeDuration] = useState(config?.codeDuration || '');
|
||||
const [emailDigit, setEmailDigit] = useState(config?.digit || '');
|
||||
// editor 实例
|
||||
const [editor, setEditor] = useState(null); // TS 语法
|
||||
// 工具栏配置
|
||||
const toolbarConfig = {}; // TS 语法
|
||||
// 编辑器配置
|
||||
const editorConfig = {
|
||||
autoFocus: false,
|
||||
placeholder: '请输入内容...',
|
||||
};
|
||||
// 及时销毁 editor
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (editor == null)
|
||||
return;
|
||||
editor.destroy();
|
||||
setEditor(null);
|
||||
};
|
||||
}, [editor]);
|
||||
useEffect(() => {
|
||||
setSubject(config?.subject || '');
|
||||
setText(config?.text || '');
|
||||
setHtml(config?.html || '');
|
||||
setEmailCodeDuration(config?.codeDuration || '');
|
||||
setEmailDigit(config?.digit || '');
|
||||
if (config?.html) {
|
||||
setEContentType('html');
|
||||
}
|
||||
else {
|
||||
setEContentType('text');
|
||||
}
|
||||
}, [config]);
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
<Switch checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
</div>
|
||||
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} style={{ maxWidth: 900, marginTop: 16 }}>
|
||||
<Form.Item label="账号">
|
||||
<Input type="text" value={config.account} disabled={true}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
{enabled &&
|
||||
<div>
|
||||
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} style={{ maxWidth: 900, marginTop: 16 }}>
|
||||
<Form.Item label="邮件主题">
|
||||
<Input placeholder="请输入邮件主题" type="text" value={subject} onChange={(e) => {
|
||||
setSubject(e.target.value);
|
||||
}} onBlur={() => {
|
||||
if (subject !== config?.subject) {
|
||||
updateConfig(id, config, 'subject', subject);
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="邮件内容模板">
|
||||
<>
|
||||
<Space size={8} style={{ marginBottom: 8 }}>
|
||||
<Radio.Group onChange={(e) => setEContentType(e.target.value)} value={eContentType}>
|
||||
<Radio.Button value="text">纯文本</Radio.Button>
|
||||
<Radio.Button value="html">HTML</Radio.Button>
|
||||
</Radio.Group>
|
||||
<Alert message={<div>
|
||||
<span>请使用</span>
|
||||
<Text mark> ${'{code}'}</Text>
|
||||
<span>作为验证码占位符,</span>
|
||||
<Text mark> ${'{duration}'}</Text>
|
||||
<span>作为验证码有效时间占位符(包含单位分钟)。</span>
|
||||
</div>} type="info"/>
|
||||
</Space>
|
||||
{eContentType === 'text' ? (<TextArea rows={6} value={text} onChange={(e) => {
|
||||
setText(e.target.value);
|
||||
}} onBlur={() => {
|
||||
if (text !== config?.text) {
|
||||
updateConfig(id, config, 'text', text);
|
||||
}
|
||||
}}/>) : (<div style={{ border: '1px solid #ccc' }}>
|
||||
<Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default" style={{ borderBottom: '1px solid #ccc' }}/>
|
||||
<Editor defaultConfig={editorConfig} value={html} onCreated={setEditor} onChange={editor => {
|
||||
setHtml(editor.getHtml());
|
||||
updateConfig(id, config, 'html', editor.getHtml());
|
||||
}} mode="default" style={{ height: '260px', overflowY: 'hidden' }}/>
|
||||
</div>)}
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="验证码有效时间" tooltip="邮箱验证码发送有效时间,不填为5分钟">
|
||||
<Input placeholder="请输入验证码有效时间" type="number" value={emailCodeDuration} min={0} onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val) {
|
||||
setEmailCodeDuration(Number(val));
|
||||
}
|
||||
else {
|
||||
setEmailCodeDuration('');
|
||||
}
|
||||
}} onBlur={() => {
|
||||
if (Number(emailCodeDuration) > 0) {
|
||||
updateConfig(id, config, 'codeDuration', emailCodeDuration);
|
||||
}
|
||||
else {
|
||||
updateConfig(id, config, 'codeDuration', undefined);
|
||||
}
|
||||
}} suffix="分钟"/>
|
||||
</Form.Item>
|
||||
<Form.Item label="验证码位数" tooltip="邮箱验证码位数,可设置4~8位">
|
||||
<Input placeholder="请输入验证码有效位数" type="number" value={emailDigit} min={4} max={8} onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val) {
|
||||
setEmailDigit(Number(val));
|
||||
}
|
||||
else {
|
||||
setEmailDigit('');
|
||||
}
|
||||
}} onBlur={() => {
|
||||
if (Number(emailDigit) > 0) {
|
||||
updateConfig(id, config, 'digit', emailDigit);
|
||||
}
|
||||
else {
|
||||
updateConfig(id, config, 'digit', undefined);
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>}
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import React from "react";
|
||||
import { EmailConfig, MfwConfig, PfwConfig, SmsConfig } from "../../../entities/Passport";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
export default function Sms(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
updateConfig: (id: string, config: SmsConfig | EmailConfig | PfwConfig | MfwConfig, path: string, value: any) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Switch, Form, Input, Select, Tag } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
export default function Sms(props) {
|
||||
const { passport, t, changeEnabled, updateConfig } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
const config = passport.config || {};
|
||||
const [templateName, setTemplateName] = useState(config?.templateName || '');
|
||||
const [smsCodeDuration, setSmsCodeDuration] = useState(config?.codeDuration || '');
|
||||
const [smsDigit, setSmsDigit] = useState(config?.digit || '');
|
||||
useEffect(() => {
|
||||
setTemplateName(config?.templateName || '');
|
||||
setSmsCodeDuration(config?.codeDuration || '');
|
||||
setSmsDigit(config?.digit || '');
|
||||
}, [config]);
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
<Switch checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
</div>
|
||||
{enabled &&
|
||||
<div>
|
||||
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} style={{ maxWidth: 900, marginTop: 16 }}>
|
||||
<Form.Item label="模拟发送" tooltip="开启模拟发送短信,发短信不会调用api">
|
||||
<Switch checkedChildren="是" unCheckedChildren="否" checked={config?.mockSend} onChange={(checked) => {
|
||||
updateConfig(id, config, 'mockSend', checked);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="默认渠道" tooltip="发送短信渠道,如阿里云、腾讯云、天翼云">
|
||||
<>
|
||||
<Select placeholder="请选择渠道" value={config?.defaultOrigin} style={{ width: 120 }} onChange={(value) => {
|
||||
updateConfig(id, config, 'defaultOrigin', value);
|
||||
}} options={[
|
||||
{ value: 'ali', label: '阿里云' },
|
||||
{ value: 'tencent', label: '腾讯云' },
|
||||
{ value: 'ctyun', label: '天翼云' },
|
||||
]}/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item label="验证码模版名" tooltip="短信验证码模版名">
|
||||
<Input placeholder="请输入验证码模版名" type="text" value={templateName} onChange={(e) => {
|
||||
setTemplateName(e.target.value);
|
||||
}} onBlur={() => {
|
||||
if (templateName !== config?.templateName) {
|
||||
updateConfig(id, config, 'templateName', templateName);
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="验证码有效时间" tooltip="短信验证码发送有效时间,不填为1分钟">
|
||||
<Input placeholder="请输入验证码有效时间" type="number" value={smsCodeDuration} min={0} onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val) {
|
||||
setSmsCodeDuration(Number(val));
|
||||
}
|
||||
else {
|
||||
setSmsCodeDuration('');
|
||||
}
|
||||
}} onBlur={() => {
|
||||
if (Number(smsCodeDuration) > 0) {
|
||||
updateConfig(id, config, 'codeDuration', smsCodeDuration);
|
||||
}
|
||||
else {
|
||||
updateConfig(id, config, 'codeDuration', undefined);
|
||||
}
|
||||
}} suffix="分钟"/>
|
||||
</Form.Item>
|
||||
<Form.Item label="验证码位数" tooltip="短信验证码位数,可设置4~8位">
|
||||
<Input placeholder="请输入验证码有效位数" type="number" value={smsDigit} min={4} max={8} onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
if (val) {
|
||||
setSmsDigit(Number(val));
|
||||
}
|
||||
else {
|
||||
setSmsDigit('');
|
||||
}
|
||||
}} onBlur={() => {
|
||||
if (Number(smsDigit) > 0) {
|
||||
updateConfig(id, config, 'digit', smsDigit);
|
||||
}
|
||||
else {
|
||||
updateConfig(id, config, 'digit', undefined);
|
||||
}
|
||||
}}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>}
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from "react";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
export default function wechatMp(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import React from "react";
|
||||
import { Switch, Tag } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
export default function wechatMp(props) {
|
||||
const { passport, t, changeEnabled, } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
{/* <Tooltip title={(mpAppIds && mpAppIds.length > 0) ? '' : '如需启用小程序登录,请先前往应用管理,创建小程序application,并完成基础配置'}> */}
|
||||
<Switch
|
||||
// disabled={!(mpAppIds && mpAppIds.length > 0)}
|
||||
checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
{/* </Tooltip> */}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import React from "react";
|
||||
import { EmailConfig, MfwConfig, PfwConfig, SmsConfig } from "../../../entities/Passport";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
export default function wechatMpForWeb(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
appIdStr: string;
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
updateConfig: (id: string, config: SmsConfig | EmailConfig | PfwConfig | MfwConfig, path: string, value: any) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import React from "react";
|
||||
import { Switch, Form, Tag, Input } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
export default function wechatMpForWeb(props) {
|
||||
const { passport, appIdStr, t, changeEnabled, updateConfig } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
const config = passport.config || {};
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
{/* <Tooltip title={(mpAppIds && mpAppIds.length > 0) ? '' : '如需启用小程序授权登录,请先前往应用管理,创建小程序application,并完成基础配置'}> */}
|
||||
<Switch
|
||||
// disabled={!(mpAppIds && mpAppIds.length > 0)}
|
||||
checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
{/* </Tooltip> */}
|
||||
</div>
|
||||
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} style={{ maxWidth: 900, marginTop: 16 }}>
|
||||
<Form.Item label="appId">
|
||||
<Input value={appIdStr} disabled={true}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from "react";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
export default function wechatPublic(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import React from "react";
|
||||
import { Switch, Tag } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
export default function wechatPublic(props) {
|
||||
const { passport, t, changeEnabled, } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
{/* <Tooltip title={(publicAppIds && publicAppIds.length > 0) ? '' : '如需启用公众号登录,请先前往应用管理,创建是服务号的公众号application,并完成基础配置'}> */}
|
||||
<Switch
|
||||
// disabled={!(publicAppIds && publicAppIds.length > 0)}
|
||||
checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
{/* </Tooltip> */}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import React from "react";
|
||||
import { EmailConfig, MfwConfig, PfwConfig, SmsConfig } from "../../../entities/Passport";
|
||||
import { EntityDict } from "../../../oak-app-domain";
|
||||
export default function wechatPublicForWeb(props: {
|
||||
passport: EntityDict['passport']['OpSchema'] & {
|
||||
stateColor: string;
|
||||
};
|
||||
appIdStr: string;
|
||||
t: (k: string, params?: any) => string;
|
||||
changeEnabled: (enabled: boolean) => void;
|
||||
updateConfig: (id: string, config: SmsConfig | EmailConfig | PfwConfig | MfwConfig, path: string, value: any) => void;
|
||||
}): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
import { Switch, Form, Tag, Input } from 'antd';
|
||||
import Styles from './web.module.less';
|
||||
export default function wechatPublicForWeb(props) {
|
||||
const { passport, appIdStr, t, changeEnabled, updateConfig } = props;
|
||||
const { id, type, enabled, stateColor } = passport;
|
||||
const config = passport.config || {};
|
||||
return (<div className={Styles.item}>
|
||||
<div className={Styles.title}>
|
||||
<Tag color={stateColor}>{t(`passport:v.type.${type}`)}</Tag>
|
||||
{/* <Tooltip title={(publicAppIds && publicAppIds.length > 0) ? '' : '如需启用公众号授权登录,请先前往应用管理,创建是服务号的公众号application,并完成基础配置'}> */}
|
||||
<Switch
|
||||
// disabled={!(publicAppIds && publicAppIds.length > 0)}
|
||||
checkedChildren="开启" unCheckedChildren="关闭" checked={enabled} onChange={(checked) => {
|
||||
changeEnabled(checked);
|
||||
}}/>
|
||||
{/* </Tooltip> */}
|
||||
</div>
|
||||
|
||||
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} style={{ maxWidth: 900, marginTop: 16 }}>
|
||||
<Form.Item label="appId">
|
||||
<Input value={appIdStr} disabled={true}/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.item {
|
||||
padding: 10px 16px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--oak-border-color);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
@ -16,15 +16,6 @@ export default OakComponent({
|
|||
url: 1,
|
||||
},
|
||||
},
|
||||
// passport$system: {
|
||||
// $entity: 'passport',
|
||||
// data: {
|
||||
// id: 1,
|
||||
// type: 1,
|
||||
// config: 1,
|
||||
// enabled: 1,
|
||||
// },
|
||||
// }
|
||||
// application$system: {
|
||||
// $entity: 'application',
|
||||
// data: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { EntityDict } from "../../../../oak-app-domain";
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, {
|
||||
disabled: string;
|
||||
url: string;
|
||||
callback: (() => void) | undefined;
|
||||
setLoginMode: (value: string) => void;
|
||||
digit: number;
|
||||
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
import { LOCAL_STORAGE_KEYS } from '../../../../config/constants';
|
||||
import { isCaptcha, isEmail } from "oak-domain/lib/utils/validator";
|
||||
const SEND_KEY = LOCAL_STORAGE_KEYS.captchaSendAt;
|
||||
const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
|
||||
export default OakComponent({
|
||||
isList: false,
|
||||
projection: {
|
||||
id: 1,
|
||||
email: 1,
|
||||
userId: 1,
|
||||
},
|
||||
data: {
|
||||
counter: 0,
|
||||
loading: false,
|
||||
lastSendAt: undefined,
|
||||
email: '',
|
||||
captcha: '',
|
||||
validEmail: false,
|
||||
validCaptcha: false,
|
||||
allowSubmit: false,
|
||||
},
|
||||
properties: {
|
||||
disabled: '',
|
||||
url: '', // 登录系统之后要返回的页面
|
||||
callback: undefined, // 登录成功回调,排除微信登录方式
|
||||
setLoginMode: (value) => undefined,
|
||||
digit: 4, //验证码位数
|
||||
},
|
||||
formData({ features, props }) {
|
||||
const { lastSendAt } = this.state;
|
||||
let counter = 0;
|
||||
if (typeof lastSendAt === 'number') {
|
||||
const now = Date.now();
|
||||
counter = Math.max(SEND_CAPTCHA_LATENCY - Math.ceil((now - lastSendAt) / 1000), 0);
|
||||
if (counter > 0) {
|
||||
this.counterHandler = setTimeout(() => this.reRender(), 1000);
|
||||
}
|
||||
else if (this.counterHandler) {
|
||||
clearTimeout(this.counterHandler);
|
||||
this.counterHandler = undefined;
|
||||
}
|
||||
}
|
||||
return {
|
||||
counter,
|
||||
};
|
||||
},
|
||||
lifetimes: {},
|
||||
listeners: {
|
||||
'validEmail,validCaptcha'(prev, next) {
|
||||
const { allowSubmit } = this.state;
|
||||
if (allowSubmit) {
|
||||
if (!(next.validEmail && next.validCaptcha)) {
|
||||
this.setState({
|
||||
allowSubmit: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (next.validEmail && next.validCaptcha) {
|
||||
this.setState({
|
||||
allowSubmit: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async sendCaptcha() {
|
||||
const { email } = this.state;
|
||||
try {
|
||||
const result = await this.features.token.sendCaptcha('email', email, 'login');
|
||||
// 显示返回消息
|
||||
this.setMessage({
|
||||
type: 'success',
|
||||
content: result,
|
||||
});
|
||||
const lastSendAt = Date.now();
|
||||
await this.save(SEND_KEY, lastSendAt);
|
||||
this.setState({
|
||||
lastSendAt,
|
||||
}, () => this.reRender());
|
||||
}
|
||||
catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: err.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
async loginByEmail() {
|
||||
const { url, callback } = this.props;
|
||||
const { email, captcha } = this.state;
|
||||
try {
|
||||
this.setState({
|
||||
loading: true,
|
||||
});
|
||||
await this.features.token.loginByEmail(email, captcha);
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
if (callback) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (url) {
|
||||
this.redirectTo({
|
||||
url,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: err.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
inputChange(type, value) {
|
||||
const { digit } = this.props;
|
||||
switch (type) {
|
||||
case 'email':
|
||||
const validEmail = !!isEmail(value);
|
||||
this.setState({
|
||||
email: value,
|
||||
validEmail,
|
||||
});
|
||||
break;
|
||||
case 'captcha':
|
||||
const validCaptcha = !!isCaptcha(value, digit);
|
||||
this.setState({
|
||||
captcha: value,
|
||||
validCaptcha
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
inputChangeMp(event) {
|
||||
const { detail, target: { dataset }, } = event;
|
||||
const { attr } = dataset;
|
||||
const { value } = detail;
|
||||
this.inputChange(attr, value);
|
||||
},
|
||||
changeLoginMp(e) {
|
||||
const { setLoginMode } = this.props;
|
||||
const { value } = e.currentTarget.dataset;
|
||||
setLoginMode && setLoginMode(value);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"navigationBarTitleText": "登录",
|
||||
"enablePullDownRefresh": false,
|
||||
"usingComponents": {
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-input": "@oak-frontend-base/miniprogram_npm/lin-ui/input/index",
|
||||
"oak-icon": "@oak-frontend-base/components/icon/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/** index.wxss **/
|
||||
@import "../../../../config/styles/mp/index.less";
|
||||
@import "../../../../config/styles/mp/mixins.less";
|
||||
|
||||
.page-body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
background-color: @oak-bg-color-container;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
.inputItem {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 10rpx;
|
||||
border: 1rpx solid @oak-text-color-placeholder;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 28rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.my-input {
|
||||
padding-right: 0rpx !important;
|
||||
padding-left: 0rpx !important;
|
||||
height: 56rpx !important;
|
||||
line-height: 56rpx !important;
|
||||
}
|
||||
|
||||
.captcha {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.methods {
|
||||
width: 100%;
|
||||
padding: 0rpx 8rpx;
|
||||
font-size: 28rpx;
|
||||
margin-top: 28rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<view class="inputItem">
|
||||
<oak-icon name="mobilephone" size="28" color="#808080" />
|
||||
<l-input
|
||||
hide-label="{{true}}"
|
||||
placeholder="{{t('placeholder.Mobile')}}"
|
||||
clear="{{true}}"
|
||||
showRow="{{false}}"
|
||||
l-class="my-input"
|
||||
style="flex:1;"
|
||||
data-attr="mobile"
|
||||
maxlength="11"
|
||||
value="{{mobile}}"
|
||||
bind:lininput="inputChangeMp"
|
||||
bind:linclear="inputChangeMp"
|
||||
/>
|
||||
</view>
|
||||
<view class="inputItem">
|
||||
<l-input
|
||||
hide-label="{{true}}"
|
||||
placeholder="{{t('placeholder.Captcha')}}"
|
||||
clear="{{true}}"
|
||||
showRow="{{false}}"
|
||||
l-class="my-input"
|
||||
width="380"
|
||||
data-attr="captcha"
|
||||
maxlength="4"
|
||||
value="{{captcha}}"
|
||||
bind:lininput="inputChangeMp"
|
||||
bind:linclear="inputChangeMp"
|
||||
>
|
||||
<l-button slot="right" plain="{{true}}" bg-color="#fff" height="56" disabled="{{!!disabled || !validMobile || counter > 0}}" l-class="captcha" catch:lintap="sendCaptcha">
|
||||
{{counter > 0 ? counter + t('resendAfter'): t('Send')}}
|
||||
</l-button>
|
||||
</input>
|
||||
</view>
|
||||
<l-button size="long" disabled="{{!!disabled || !allowSubmit || loading}}" catch:lintap="loginByCaptcha" height="{{80}}" style="width:100%">
|
||||
{{t('Login')}}
|
||||
</l-button>
|
||||
<view class="methods">
|
||||
<view wx:if="{{allowWechatMp}}" style="color:#8F976A" bindtap="changeLoginMp" data-value="wechatMp">一键登录</view>
|
||||
<view wx:else></view>
|
||||
<view wx:if="{{allowPassword}}" style="color:#835D01" bindtap="changeLoginMp" data-value="password">密码登录</view>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Login": "登录",
|
||||
"Send": "发送验证码",
|
||||
"placeholder": {
|
||||
"Captcha": "输入4位验证码",
|
||||
"email": "请输入邮箱"
|
||||
},
|
||||
"resendAfter": "秒后可重发"
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'token', false, {
|
||||
counter: number;
|
||||
loading: boolean;
|
||||
disabled?: string;
|
||||
email: string;
|
||||
captcha: string;
|
||||
validEmail: boolean;
|
||||
validCaptcha: boolean;
|
||||
allowSubmit: boolean;
|
||||
digit: number;
|
||||
}, {
|
||||
sendCaptcha: () => Promise<void>;
|
||||
loginByEmail: () => Promise<void>;
|
||||
inputChange: (type: 'mobile' | 'captcha', value: string) => void;
|
||||
}>): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
import { MailOutlined, } from '@ant-design/icons';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { data, methods } = props;
|
||||
const { counter, loading, disabled, email, captcha, validEmail, validCaptcha, allowSubmit, digit } = data;
|
||||
const { sendCaptcha, loginByEmail, t, inputChange } = methods;
|
||||
return (<Form colon={true}>
|
||||
<Form.Item name="email">
|
||||
<Input allowClear value={email} type="email" size="large" prefix={<MailOutlined />} placeholder={t('placeholder.Email')} onChange={(e) => {
|
||||
inputChange('email', e.target.value);
|
||||
}} className={Style['loginbox-input']}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="captcha">
|
||||
<Input allowClear value={captcha} size="large" maxLength={digit} placeholder={t('placeholder.Captcha')} onChange={(e) => {
|
||||
inputChange('captcha', e.target.value);
|
||||
}} className={Style['loginbox-input']} suffix={<Button size="small" type="link" disabled={!!disabled || !validEmail || counter > 0} onClick={() => sendCaptcha()}>
|
||||
{counter > 0
|
||||
? counter + t('resendAfter')
|
||||
: t('Send')}
|
||||
</Button>}/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button block size="large" type="primary" disabled={disabled || !allowSubmit || loading} loading={loading} onClick={() => loginByEmail()}>
|
||||
{t('Login')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>);
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
.loginbox {
|
||||
&-main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background: var(--oak-bg-color-container);
|
||||
}
|
||||
|
||||
&-logo {
|
||||
width: 194px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&-wrap {
|
||||
width: 400px;
|
||||
display: block;
|
||||
background: var(--oak-bg-color-container);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgb(0 0 0 / 8%), 0 0 4px rgb(0 0 0 / 8%);
|
||||
}
|
||||
|
||||
&-hd {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
&-bd {
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
&-only {
|
||||
padding-top: 32px !important;
|
||||
}
|
||||
|
||||
&-mobile {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
&-password {
|
||||
position: relative;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
&-qrcode {
|
||||
padding: 0 32px;
|
||||
font-size: 14px;
|
||||
|
||||
&__sociallogin {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
||||
&__refresh {
|
||||
color: var(--oak-text-color-brand);
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
&-icon {
|
||||
color: var(--oak-text-color-brand);
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&__iframe {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-input {
|
||||
// background-color: rgba(0, 0, 0, .04) !important;
|
||||
}
|
||||
|
||||
&-ft {
|
||||
height: 54px;
|
||||
border-top: 1px solid #f2f3f5;
|
||||
font-size: 14px;
|
||||
|
||||
&__btn {}
|
||||
}
|
||||
|
||||
&-protocal {
|
||||
padding: 20px 32px;
|
||||
}
|
||||
|
||||
&-current {
|
||||
color: var(--oak-text-color-brand) !important;
|
||||
cursor: default;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@ export const entityDesc = {
|
|||
zh_CN: {
|
||||
name: '直播流',
|
||||
attr: {
|
||||
title: '名称',
|
||||
title: '名称', // 用户定义直播间名称,
|
||||
streamTitle: '直播流名称',
|
||||
liveonly: '活跃状态',
|
||||
hub: '直播空间名称',
|
||||
hub: '直播空间名称', // 所属直播空间名称
|
||||
entity: '所属实体',
|
||||
entityId: '所属实体id',
|
||||
rtmpPushUrl: '推流地址',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { String } from 'oak-domain/lib/types/DataType';
|
||||
import { Schema as User } from './User';
|
||||
import { Schema as Token } from './Token';
|
||||
import { EntityShape } from 'oak-domain/lib/types/Entity';
|
||||
import { AbleAction, AbleState } from 'oak-domain/lib/actions/action';
|
||||
import { ActionDef } from 'oak-domain/lib/types';
|
||||
import { EntityDesc } from 'oak-domain/lib/types/EntityDesc';
|
||||
export interface Schema extends EntityShape {
|
||||
name: String<32>;
|
||||
user: User;
|
||||
tokens: Array<Token>;
|
||||
}
|
||||
export type Action = AbleAction;
|
||||
export declare const AbleActionDef: ActionDef<AbleAction, AbleState>;
|
||||
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
||||
ableState: AbleState;
|
||||
}>;
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import { makeAbleActionDef } from 'oak-domain/lib/actions/action';
|
||||
;
|
||||
export const AbleActionDef = makeAbleActionDef('enabled');
|
||||
export const entityDesc = {
|
||||
locales: {
|
||||
zh_CN: {
|
||||
name: '账号',
|
||||
attr: {
|
||||
name: '账号',
|
||||
user: '关联用户',
|
||||
tokens: '相关令牌',
|
||||
ableState: '是否可用',
|
||||
},
|
||||
action: {
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
},
|
||||
v: {
|
||||
ableState: {
|
||||
enabled: '可用的',
|
||||
disabled: '禁用的',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
indexes: [
|
||||
{
|
||||
name: 'index_name_ableState',
|
||||
attributes: [
|
||||
{
|
||||
name: 'name',
|
||||
direction: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'ableState',
|
||||
direction: 'ASC',
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
style: {
|
||||
icon: {
|
||||
enable: '',
|
||||
disable: '',
|
||||
},
|
||||
color: {
|
||||
ableState: {
|
||||
enabled: '#008000',
|
||||
disabled: '#A9A9A9',
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { AbleState, AbleAction } from "oak-domain/lib/actions/action";
|
||||
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||
import { GenericAction } from "oak-domain/lib/actions/action";
|
||||
export type ParticularAction = AbleAction;
|
||||
export declare const actions: string[];
|
||||
export declare const AbleActionDef: ActionDef<AbleAction, AbleState>;
|
||||
export type Action = GenericAction | ParticularAction | string;
|
||||
export declare const actionDefDict: {
|
||||
ableState: ActionDef<AbleAction, AbleState>;
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { makeAbleActionDef } from "oak-domain/lib/actions/action";
|
||||
export const actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "enable", "disable"];
|
||||
export const AbleActionDef = makeAbleActionDef('enabled');
|
||||
export const actionDefDict = {
|
||||
ableState: AbleActionDef
|
||||
};
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
import { ForeignKey } from "oak-domain/lib/types/DataType";
|
||||
import { Q_DateValue, Q_NumberValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey, SubQueryPredicateMetadata } from "oak-domain/lib/types/Demand";
|
||||
import { OneOf } from "oak-domain/lib/types/Polyfill";
|
||||
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, AggregationResult, EntityShape } from "oak-domain/lib/types/Entity";
|
||||
import { Action, ParticularAction } from "./Action";
|
||||
import { AbleState } from "oak-domain/lib/actions/action";
|
||||
import { String } from "oak-domain/lib/types/DataType";
|
||||
import * as User from "../User/Schema";
|
||||
import * as Token from "../Token/Schema";
|
||||
export type OpSchema = EntityShape & {
|
||||
name: String<32>;
|
||||
userId: ForeignKey<"user">;
|
||||
ableState?: AbleState | null;
|
||||
};
|
||||
export type OpAttr = keyof OpSchema;
|
||||
export type Schema = EntityShape & {
|
||||
name: String<32>;
|
||||
userId: ForeignKey<"user">;
|
||||
ableState?: AbleState | null;
|
||||
user: User.Schema;
|
||||
token$entity?: Array<Token.Schema>;
|
||||
token$entity$$aggr?: AggregationResult<Token.Schema>;
|
||||
} & {
|
||||
[A in ExpressionKey]?: any;
|
||||
};
|
||||
type AttrFilter = {
|
||||
id: Q_StringValue;
|
||||
$$createAt$$: Q_DateValue;
|
||||
$$seq$$: Q_NumberValue;
|
||||
$$updateAt$$: Q_DateValue;
|
||||
name: Q_StringValue;
|
||||
userId: Q_StringValue;
|
||||
user: User.Filter;
|
||||
ableState: Q_EnumValue<AbleState>;
|
||||
token$entity: Token.Filter & SubQueryPredicateMetadata;
|
||||
};
|
||||
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
|
||||
export type Projection = {
|
||||
"#id"?: NodeId;
|
||||
[k: string]: any;
|
||||
id?: number;
|
||||
$$createAt$$?: number;
|
||||
$$updateAt$$?: number;
|
||||
$$seq$$?: number;
|
||||
name?: number;
|
||||
userId?: number;
|
||||
user?: User.Projection;
|
||||
ableState?: number;
|
||||
token$entity?: Token.Selection & {
|
||||
$entity: "token";
|
||||
};
|
||||
token$entity$$aggr?: Token.Aggregation & {
|
||||
$entity: "token";
|
||||
};
|
||||
} & Partial<ExprOp<OpAttr | string>>;
|
||||
type LoginNameIdProjection = OneOf<{
|
||||
id: number;
|
||||
}>;
|
||||
type UserIdProjection = OneOf<{
|
||||
userId: number;
|
||||
}>;
|
||||
export type SortAttr = {
|
||||
id: number;
|
||||
} | {
|
||||
$$createAt$$: number;
|
||||
} | {
|
||||
$$seq$$: number;
|
||||
} | {
|
||||
$$updateAt$$: number;
|
||||
} | {
|
||||
name: number;
|
||||
} | {
|
||||
userId: number;
|
||||
} | {
|
||||
user: User.SortAttr;
|
||||
} | {
|
||||
ableState: number;
|
||||
} | {
|
||||
[k: string]: any;
|
||||
} | OneOf<ExprOp<OpAttr | string>>;
|
||||
export type SortNode = {
|
||||
$attr: SortAttr;
|
||||
$direction?: "asc" | "desc";
|
||||
};
|
||||
export type Sorter = SortNode[];
|
||||
export type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
|
||||
export type Selection<P extends Object = Projection> = SelectOperation<P>;
|
||||
export type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
|
||||
export type CreateOperationData = FormCreateData<Omit<OpSchema, "userId">> & (({
|
||||
userId?: never;
|
||||
user: User.CreateSingleOperation;
|
||||
} | {
|
||||
userId: ForeignKey<"user">;
|
||||
user?: User.UpdateOperation;
|
||||
} | {
|
||||
user?: never;
|
||||
userId: ForeignKey<"user">;
|
||||
})) & {
|
||||
token$entity?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">>>;
|
||||
};
|
||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "userId">> & (({
|
||||
user?: User.CreateSingleOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: User.UpdateOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: User.RemoveOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: never;
|
||||
userId?: ForeignKey<"user">;
|
||||
})) & {
|
||||
[k: string]: any;
|
||||
token$entity?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">>>;
|
||||
};
|
||||
export type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
user?: User.UpdateOperation | User.RemoveOperation;
|
||||
}));
|
||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||
export type UserIdSubQuery = Selection<UserIdProjection>;
|
||||
export type LoginNameIdSubQuery = Selection<LoginNameIdProjection>;
|
||||
export type EntityDef = {
|
||||
Schema: Schema;
|
||||
OpSchema: OpSchema;
|
||||
Action: OakMakeAction<Action> | string;
|
||||
Selection: Selection;
|
||||
Aggregation: Aggregation;
|
||||
Operation: Operation;
|
||||
Create: CreateOperation;
|
||||
Update: UpdateOperation;
|
||||
Remove: RemoveOperation;
|
||||
CreateSingle: CreateSingleOperation;
|
||||
CreateMulti: CreateMultipleOperation;
|
||||
ParticularAction: ParticularAction;
|
||||
};
|
||||
export {};
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { StorageDesc } from "oak-domain/lib/types/Storage";
|
||||
import { OpSchema } from "./Schema";
|
||||
export declare const desc: StorageDesc<OpSchema>;
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import { actions } from "./Action";
|
||||
export const desc = {
|
||||
attributes: {
|
||||
name: {
|
||||
notNull: true,
|
||||
type: "varchar",
|
||||
params: {
|
||||
length: 32
|
||||
}
|
||||
},
|
||||
userId: {
|
||||
notNull: true,
|
||||
type: "ref",
|
||||
ref: "user"
|
||||
},
|
||||
ableState: {
|
||||
type: "enum",
|
||||
enumeration: ["enabled", "disabled"]
|
||||
}
|
||||
},
|
||||
actionType: "crud",
|
||||
actions,
|
||||
indexes: [
|
||||
{
|
||||
name: 'index_name_ableState',
|
||||
attributes: [
|
||||
{
|
||||
name: 'name',
|
||||
direction: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'ableState',
|
||||
direction: 'ASC',
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { EntityDef } from "./Schema";
|
||||
import { StyleDef } from "oak-domain/lib/types/Style";
|
||||
export declare const style: StyleDef<EntityDef["OpSchema"], EntityDef["Action"]>;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
export const style = {
|
||||
icon: {
|
||||
enable: '',
|
||||
disable: '',
|
||||
},
|
||||
color: {
|
||||
ableState: {
|
||||
enabled: '#008000',
|
||||
disabled: '#A9A9A9',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
{ "name": "账号", "attr": { "name": "账号", "user": "关联用户", "tokens": "相关令牌", "ableState": "是否可用" }, "action": { "enable": "启用", "disable": "禁用" }, "v": { "ableState": { "enabled": "可用的", "disabled": "禁用的" } } }
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { BRC } from '../types/RuntimeCxt';
|
||||
export type EmailOptions = {
|
||||
host: string;
|
||||
port: number;
|
||||
account: string;
|
||||
password: string;
|
||||
subject: string;
|
||||
from: string;
|
||||
to: string;
|
||||
text?: string;
|
||||
html?: string;
|
||||
};
|
||||
/**
|
||||
* 邮箱发送
|
||||
*/
|
||||
export default interface Email<ED extends EntityDict> {
|
||||
name: string;
|
||||
sendEmail(options: EmailOptions, context: BRC<ED>): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}>;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import Cos from '../../types/Cos';
|
||||
import { Config } from '../../types/Config';
|
||||
/**
|
||||
* 注入一个其它OSS上实现的uploader类
|
||||
* @param clazz
|
||||
*/
|
||||
export declare function registerCos<ED extends EntityDict>(clazz: new () => Cos<ED>): void;
|
||||
export declare function getCos<ED extends EntityDict>(origin: string): Cos<ED>;
|
||||
export declare function composeFileUrl<ED extends EntityDict>(extraFile: ED['extraFile']['OpSchema'], config: Config, style?: string): string;
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
import { assert } from 'oak-domain/lib/utils/assert';
|
||||
const CosDict = {};
|
||||
/**
|
||||
* 注入一个其它OSS上实现的uploader类
|
||||
* @param clazz
|
||||
*/
|
||||
export function registerCos(clazz) {
|
||||
const instance = new clazz();
|
||||
CosDict[instance.name] = instance;
|
||||
}
|
||||
export function getCos(origin) {
|
||||
assert(CosDict.hasOwnProperty(origin));
|
||||
return CosDict[origin];
|
||||
}
|
||||
export function composeFileUrl(extraFile, config, style) {
|
||||
const { origin } = extraFile;
|
||||
if (origin === 'unknown') {
|
||||
// 扯淡的代码 by Xc 20240521
|
||||
return extraFile.extra1;
|
||||
}
|
||||
const cos = CosDict[origin];
|
||||
return cos.composeFileUrl(extraFile, config, style);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import Email, { EmailOptions } from '../../types/Email';
|
||||
/**
|
||||
* 注入一个其它发送邮件类
|
||||
* @param clazz
|
||||
*/
|
||||
export declare function registerEmail<ED extends EntityDict>(clazz: new () => Email<ED>): void;
|
||||
export declare function getEmail<ED extends EntityDict>(origin: string): Email<ED>;
|
||||
export declare function getOrigin(): string[];
|
||||
export declare function sendEmail<ED extends EntityDict>(options: EmailOptions, context: BRC<ED>): Promise<{
|
||||
success: boolean;
|
||||
error?: string | undefined;
|
||||
} | {
|
||||
success: boolean;
|
||||
error: unknown;
|
||||
}>;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import { EmailOptions } from '../../types/Email';
|
||||
export declare function sendEmail<ED extends EntityDict>(options: EmailOptions, context: BRC<ED>): Promise<void>;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export async function sendEmail(options, context) {
|
||||
const { text, html } = options;
|
||||
console.log('邮件内容:', html || text);
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { assert } from 'oak-domain/lib/utils/assert';
|
||||
import Nodemailer from './node-mailer';
|
||||
const EmailDict = {
|
||||
nodemailer: Nodemailer,
|
||||
};
|
||||
/**
|
||||
* 注入一个其它发送邮件类
|
||||
* @param clazz
|
||||
*/
|
||||
export function registerEmail(clazz) {
|
||||
const instance = new clazz();
|
||||
EmailDict[instance.name] = instance;
|
||||
}
|
||||
export function getEmail(origin) {
|
||||
assert(EmailDict.hasOwnProperty(origin));
|
||||
return EmailDict[origin];
|
||||
}
|
||||
export function getOrigin() {
|
||||
return Object.keys(EmailDict);
|
||||
}
|
||||
export async function sendEmail(options, context) {
|
||||
try {
|
||||
const instance = getEmail('nodemailer');
|
||||
const result = await instance.sendEmail(options, context);
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
return {
|
||||
success: false,
|
||||
error: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import Email, { EmailOptions } from '../../types/Email';
|
||||
export default class Nodemailer implements Email<EntityDict> {
|
||||
name: string;
|
||||
sendEmail(options: EmailOptions, context: BRC<EntityDict>): Promise<{
|
||||
success: boolean;
|
||||
error?: undefined;
|
||||
} | {
|
||||
success: boolean;
|
||||
error: any;
|
||||
}>;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
//https://www.nodemailer.com/
|
||||
import nodemailer from 'nodemailer';
|
||||
export default class Nodemailer {
|
||||
name = 'nodemailer';
|
||||
async sendEmail(options, context) {
|
||||
const { host, port, account, password, subject, from, text, html, to } = options;
|
||||
const transporter = nodemailer.createTransport({
|
||||
host,
|
||||
port,
|
||||
secure: port === 465, //true for 465, false for other ports
|
||||
auth: {
|
||||
user: account,
|
||||
pass: password,
|
||||
},
|
||||
});
|
||||
async function verifyTransporter() {
|
||||
return new Promise((resolve, reject) => {
|
||||
transporter.verify((error, success) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
else {
|
||||
resolve(success);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
try {
|
||||
await verifyTransporter();
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log('Server is ready to take our messages');
|
||||
}
|
||||
let mailOptions = {
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
};
|
||||
try {
|
||||
let info = await transporter.sendMail(mailOptions);
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log('info', info);
|
||||
console.log('Message sent: %s', info.messageId);
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
console.log('sendMailError', err);
|
||||
return {
|
||||
success: false,
|
||||
error: err?.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('verifyError', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error?.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
||||
declare const checkers: (import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "applicationPassport", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt<import("../oak-app-domain").EntityDict>>)[];
|
||||
export default checkers;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ exports.entityDesc = {
|
|||
zh_CN: {
|
||||
name: '直播流',
|
||||
attr: {
|
||||
title: '名称',
|
||||
title: '名称', // 用户定义直播间名称,
|
||||
streamTitle: '直播流名称',
|
||||
liveonly: '活跃状态',
|
||||
hub: '直播空间名称',
|
||||
hub: '直播空间名称', // 所属直播空间名称
|
||||
entity: '所属实体',
|
||||
entityId: '所属实体id',
|
||||
rtmpPushUrl: '推流地址',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { String } from 'oak-domain/lib/types/DataType';
|
||||
import { Schema as User } from './User';
|
||||
import { Schema as Token } from './Token';
|
||||
import { EntityShape } from 'oak-domain/lib/types/Entity';
|
||||
import { AbleAction, AbleState } from 'oak-domain/lib/actions/action';
|
||||
import { ActionDef } from 'oak-domain/lib/types';
|
||||
import { EntityDesc } from 'oak-domain/lib/types/EntityDesc';
|
||||
export interface Schema extends EntityShape {
|
||||
name: String<32>;
|
||||
user: User;
|
||||
tokens: Array<Token>;
|
||||
}
|
||||
export type Action = AbleAction;
|
||||
export declare const AbleActionDef: ActionDef<AbleAction, AbleState>;
|
||||
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
||||
ableState: AbleState;
|
||||
}>;
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.entityDesc = exports.AbleActionDef = void 0;
|
||||
const action_1 = require("oak-domain/lib/actions/action");
|
||||
;
|
||||
exports.AbleActionDef = (0, action_1.makeAbleActionDef)('enabled');
|
||||
exports.entityDesc = {
|
||||
locales: {
|
||||
zh_CN: {
|
||||
name: '账号',
|
||||
attr: {
|
||||
name: '账号',
|
||||
user: '关联用户',
|
||||
tokens: '相关令牌',
|
||||
ableState: '是否可用',
|
||||
},
|
||||
action: {
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
},
|
||||
v: {
|
||||
ableState: {
|
||||
enabled: '可用的',
|
||||
disabled: '禁用的',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
indexes: [
|
||||
{
|
||||
name: 'index_name_ableState',
|
||||
attributes: [
|
||||
{
|
||||
name: 'name',
|
||||
direction: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'ableState',
|
||||
direction: 'ASC',
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
style: {
|
||||
icon: {
|
||||
enable: '',
|
||||
disable: '',
|
||||
},
|
||||
color: {
|
||||
ableState: {
|
||||
enabled: '#008000',
|
||||
disabled: '#A9A9A9',
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { AbleState, AbleAction } from "oak-domain/lib/actions/action";
|
||||
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||
import { GenericAction } from "oak-domain/lib/actions/action";
|
||||
export type ParticularAction = AbleAction;
|
||||
export declare const actions: string[];
|
||||
export declare const AbleActionDef: ActionDef<AbleAction, AbleState>;
|
||||
export type Action = GenericAction | ParticularAction | string;
|
||||
export declare const actionDefDict: {
|
||||
ableState: ActionDef<AbleAction, AbleState>;
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.actionDefDict = exports.AbleActionDef = exports.actions = void 0;
|
||||
const action_1 = require("oak-domain/lib/actions/action");
|
||||
exports.actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "enable", "disable"];
|
||||
exports.AbleActionDef = (0, action_1.makeAbleActionDef)('enabled');
|
||||
exports.actionDefDict = {
|
||||
ableState: exports.AbleActionDef
|
||||
};
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
import { ForeignKey } from "oak-domain/lib/types/DataType";
|
||||
import { Q_DateValue, Q_NumberValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey, SubQueryPredicateMetadata } from "oak-domain/lib/types/Demand";
|
||||
import { OneOf } from "oak-domain/lib/types/Polyfill";
|
||||
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, AggregationResult, EntityShape } from "oak-domain/lib/types/Entity";
|
||||
import { Action, ParticularAction } from "./Action";
|
||||
import { AbleState } from "oak-domain/lib/actions/action";
|
||||
import { String } from "oak-domain/lib/types/DataType";
|
||||
import * as User from "../User/Schema";
|
||||
import * as Token from "../Token/Schema";
|
||||
export type OpSchema = EntityShape & {
|
||||
name: String<32>;
|
||||
userId: ForeignKey<"user">;
|
||||
ableState?: AbleState | null;
|
||||
};
|
||||
export type OpAttr = keyof OpSchema;
|
||||
export type Schema = EntityShape & {
|
||||
name: String<32>;
|
||||
userId: ForeignKey<"user">;
|
||||
ableState?: AbleState | null;
|
||||
user: User.Schema;
|
||||
token$entity?: Array<Token.Schema>;
|
||||
token$entity$$aggr?: AggregationResult<Token.Schema>;
|
||||
} & {
|
||||
[A in ExpressionKey]?: any;
|
||||
};
|
||||
type AttrFilter = {
|
||||
id: Q_StringValue;
|
||||
$$createAt$$: Q_DateValue;
|
||||
$$seq$$: Q_NumberValue;
|
||||
$$updateAt$$: Q_DateValue;
|
||||
name: Q_StringValue;
|
||||
userId: Q_StringValue;
|
||||
user: User.Filter;
|
||||
ableState: Q_EnumValue<AbleState>;
|
||||
token$entity: Token.Filter & SubQueryPredicateMetadata;
|
||||
};
|
||||
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
|
||||
export type Projection = {
|
||||
"#id"?: NodeId;
|
||||
[k: string]: any;
|
||||
id?: number;
|
||||
$$createAt$$?: number;
|
||||
$$updateAt$$?: number;
|
||||
$$seq$$?: number;
|
||||
name?: number;
|
||||
userId?: number;
|
||||
user?: User.Projection;
|
||||
ableState?: number;
|
||||
token$entity?: Token.Selection & {
|
||||
$entity: "token";
|
||||
};
|
||||
token$entity$$aggr?: Token.Aggregation & {
|
||||
$entity: "token";
|
||||
};
|
||||
} & Partial<ExprOp<OpAttr | string>>;
|
||||
type LoginNameIdProjection = OneOf<{
|
||||
id: number;
|
||||
}>;
|
||||
type UserIdProjection = OneOf<{
|
||||
userId: number;
|
||||
}>;
|
||||
export type SortAttr = {
|
||||
id: number;
|
||||
} | {
|
||||
$$createAt$$: number;
|
||||
} | {
|
||||
$$seq$$: number;
|
||||
} | {
|
||||
$$updateAt$$: number;
|
||||
} | {
|
||||
name: number;
|
||||
} | {
|
||||
userId: number;
|
||||
} | {
|
||||
user: User.SortAttr;
|
||||
} | {
|
||||
ableState: number;
|
||||
} | {
|
||||
[k: string]: any;
|
||||
} | OneOf<ExprOp<OpAttr | string>>;
|
||||
export type SortNode = {
|
||||
$attr: SortAttr;
|
||||
$direction?: "asc" | "desc";
|
||||
};
|
||||
export type Sorter = SortNode[];
|
||||
export type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
|
||||
export type Selection<P extends Object = Projection> = SelectOperation<P>;
|
||||
export type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
|
||||
export type CreateOperationData = FormCreateData<Omit<OpSchema, "userId">> & (({
|
||||
userId?: never;
|
||||
user: User.CreateSingleOperation;
|
||||
} | {
|
||||
userId: ForeignKey<"user">;
|
||||
user?: User.UpdateOperation;
|
||||
} | {
|
||||
user?: never;
|
||||
userId: ForeignKey<"user">;
|
||||
})) & {
|
||||
token$entity?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">>>;
|
||||
};
|
||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "userId">> & (({
|
||||
user?: User.CreateSingleOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: User.UpdateOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: User.RemoveOperation;
|
||||
userId?: never;
|
||||
} | {
|
||||
user?: never;
|
||||
userId?: ForeignKey<"user">;
|
||||
})) & {
|
||||
[k: string]: any;
|
||||
token$entity?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "entity" | "entityId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "entity" | "entityId">, Omit<Token.Filter, "entity" | "entityId">>>;
|
||||
};
|
||||
export type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
user?: User.UpdateOperation | User.RemoveOperation;
|
||||
}));
|
||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||
export type UserIdSubQuery = Selection<UserIdProjection>;
|
||||
export type LoginNameIdSubQuery = Selection<LoginNameIdProjection>;
|
||||
export type EntityDef = {
|
||||
Schema: Schema;
|
||||
OpSchema: OpSchema;
|
||||
Action: OakMakeAction<Action> | string;
|
||||
Selection: Selection;
|
||||
Aggregation: Aggregation;
|
||||
Operation: Operation;
|
||||
Create: CreateOperation;
|
||||
Update: UpdateOperation;
|
||||
Remove: RemoveOperation;
|
||||
CreateSingle: CreateSingleOperation;
|
||||
CreateMulti: CreateMultipleOperation;
|
||||
ParticularAction: ParticularAction;
|
||||
};
|
||||
export {};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { StorageDesc } from "oak-domain/lib/types/Storage";
|
||||
import { OpSchema } from "./Schema";
|
||||
export declare const desc: StorageDesc<OpSchema>;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.desc = void 0;
|
||||
const Action_1 = require("./Action");
|
||||
exports.desc = {
|
||||
attributes: {
|
||||
name: {
|
||||
notNull: true,
|
||||
type: "varchar",
|
||||
params: {
|
||||
length: 32
|
||||
}
|
||||
},
|
||||
userId: {
|
||||
notNull: true,
|
||||
type: "ref",
|
||||
ref: "user"
|
||||
},
|
||||
ableState: {
|
||||
type: "enum",
|
||||
enumeration: ["enabled", "disabled"]
|
||||
}
|
||||
},
|
||||
actionType: "crud",
|
||||
actions: Action_1.actions,
|
||||
indexes: [
|
||||
{
|
||||
name: 'index_name_ableState',
|
||||
attributes: [
|
||||
{
|
||||
name: 'name',
|
||||
direction: 'ASC',
|
||||
},
|
||||
{
|
||||
name: 'ableState',
|
||||
direction: 'ASC',
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { EntityDef } from "./Schema";
|
||||
import { StyleDef } from "oak-domain/lib/types/Style";
|
||||
export declare const style: StyleDef<EntityDef["OpSchema"], EntityDef["Action"]>;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.style = void 0;
|
||||
exports.style = {
|
||||
icon: {
|
||||
enable: '',
|
||||
disable: '',
|
||||
},
|
||||
color: {
|
||||
ableState: {
|
||||
enabled: '#008000',
|
||||
disabled: '#A9A9A9',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
{ "name": "账号", "attr": { "name": "账号", "user": "关联用户", "tokens": "相关令牌", "ableState": "是否可用" }, "action": { "enable": "启用", "disable": "禁用" }, "v": { "ableState": { "enabled": "可用的", "disabled": "禁用的" } } }
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||
declare const _default: (import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "system", import("..").BRC<import("../oak-app-domain").EntityDict>> | import("oak-domain/lib/types").Trigger<import("../oak-app-domain").EntityDict, "passport", import("..").BRC<import("../oak-app-domain").EntityDict>>)[];
|
||||
export default _default;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { BRC } from '../types/RuntimeCxt';
|
||||
export type EmailOptions = {
|
||||
host: string;
|
||||
port: number;
|
||||
account: string;
|
||||
password: string;
|
||||
subject: string;
|
||||
from: string;
|
||||
to: string;
|
||||
text?: string;
|
||||
html?: string;
|
||||
};
|
||||
/**
|
||||
* 邮箱发送
|
||||
*/
|
||||
export default interface Email<ED extends EntityDict> {
|
||||
name: string;
|
||||
sendEmail(options: EmailOptions, context: BRC<ED>): Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}>;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import Cos from '../../types/Cos';
|
||||
import { Config } from '../../types/Config';
|
||||
/**
|
||||
* 注入一个其它OSS上实现的uploader类
|
||||
* @param clazz
|
||||
*/
|
||||
export declare function registerCos<ED extends EntityDict>(clazz: new () => Cos<ED>): void;
|
||||
export declare function getCos<ED extends EntityDict>(origin: string): Cos<ED>;
|
||||
export declare function composeFileUrl<ED extends EntityDict>(extraFile: ED['extraFile']['OpSchema'], config: Config, style?: string): string;
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.composeFileUrl = exports.getCos = exports.registerCos = void 0;
|
||||
const assert_1 = require("oak-domain/lib/utils/assert");
|
||||
const CosDict = {};
|
||||
/**
|
||||
* 注入一个其它OSS上实现的uploader类
|
||||
* @param clazz
|
||||
*/
|
||||
function registerCos(clazz) {
|
||||
const instance = new clazz();
|
||||
CosDict[instance.name] = instance;
|
||||
}
|
||||
exports.registerCos = registerCos;
|
||||
function getCos(origin) {
|
||||
(0, assert_1.assert)(CosDict.hasOwnProperty(origin));
|
||||
return CosDict[origin];
|
||||
}
|
||||
exports.getCos = getCos;
|
||||
function composeFileUrl(extraFile, config, style) {
|
||||
const { origin } = extraFile;
|
||||
if (origin === 'unknown') {
|
||||
// 扯淡的代码 by Xc 20240521
|
||||
return extraFile.extra1;
|
||||
}
|
||||
const cos = CosDict[origin];
|
||||
return cos.composeFileUrl(extraFile, config, style);
|
||||
}
|
||||
exports.composeFileUrl = composeFileUrl;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import Email, { EmailOptions } from '../../types/Email';
|
||||
/**
|
||||
* 注入一个其它发送邮件类
|
||||
* @param clazz
|
||||
*/
|
||||
export declare function registerEmail<ED extends EntityDict>(clazz: new () => Email<ED>): void;
|
||||
export declare function getEmail<ED extends EntityDict>(origin: string): Email<ED>;
|
||||
export declare function getOrigin(): string[];
|
||||
export declare function sendEmail<ED extends EntityDict>(options: EmailOptions, context: BRC<ED>): Promise<{
|
||||
success: boolean;
|
||||
error?: string | undefined;
|
||||
} | {
|
||||
success: boolean;
|
||||
error: unknown;
|
||||
}>;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import { EmailOptions } from '../../types/Email';
|
||||
export declare function sendEmail<ED extends EntityDict>(options: EmailOptions, context: BRC<ED>): Promise<void>;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sendEmail = void 0;
|
||||
async function sendEmail(options, context) {
|
||||
const { text, html } = options;
|
||||
console.log('邮件内容:', html || text);
|
||||
}
|
||||
exports.sendEmail = sendEmail;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.sendEmail = exports.getOrigin = exports.getEmail = exports.registerEmail = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const assert_1 = require("oak-domain/lib/utils/assert");
|
||||
const node_mailer_1 = tslib_1.__importDefault(require("./node-mailer"));
|
||||
const EmailDict = {
|
||||
nodemailer: node_mailer_1.default,
|
||||
};
|
||||
/**
|
||||
* 注入一个其它发送邮件类
|
||||
* @param clazz
|
||||
*/
|
||||
function registerEmail(clazz) {
|
||||
const instance = new clazz();
|
||||
EmailDict[instance.name] = instance;
|
||||
}
|
||||
exports.registerEmail = registerEmail;
|
||||
function getEmail(origin) {
|
||||
(0, assert_1.assert)(EmailDict.hasOwnProperty(origin));
|
||||
return EmailDict[origin];
|
||||
}
|
||||
exports.getEmail = getEmail;
|
||||
function getOrigin() {
|
||||
return Object.keys(EmailDict);
|
||||
}
|
||||
exports.getOrigin = getOrigin;
|
||||
async function sendEmail(options, context) {
|
||||
try {
|
||||
const instance = getEmail('nodemailer');
|
||||
const result = await instance.sendEmail(options, context);
|
||||
return result;
|
||||
}
|
||||
catch (err) {
|
||||
return {
|
||||
success: false,
|
||||
error: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.sendEmail = sendEmail;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
import Email, { EmailOptions } from '../../types/Email';
|
||||
export default class Nodemailer implements Email<EntityDict> {
|
||||
name: string;
|
||||
sendEmail(options: EmailOptions, context: BRC<EntityDict>): Promise<{
|
||||
success: boolean;
|
||||
error?: undefined;
|
||||
} | {
|
||||
success: boolean;
|
||||
error: any;
|
||||
}>;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tslib_1 = require("tslib");
|
||||
//https://www.nodemailer.com/
|
||||
const nodemailer_1 = tslib_1.__importDefault(require("nodemailer"));
|
||||
class Nodemailer {
|
||||
name = 'nodemailer';
|
||||
async sendEmail(options, context) {
|
||||
const { host, port, account, password, subject, from, text, html, to } = options;
|
||||
const transporter = nodemailer_1.default.createTransport({
|
||||
host,
|
||||
port,
|
||||
secure: port === 465, //true for 465, false for other ports
|
||||
auth: {
|
||||
user: account,
|
||||
pass: password,
|
||||
},
|
||||
});
|
||||
async function verifyTransporter() {
|
||||
return new Promise((resolve, reject) => {
|
||||
transporter.verify((error, success) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
else {
|
||||
resolve(success);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
try {
|
||||
await verifyTransporter();
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log('Server is ready to take our messages');
|
||||
}
|
||||
let mailOptions = {
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
};
|
||||
try {
|
||||
let info = await transporter.sendMail(mailOptions);
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.log('info', info);
|
||||
console.log('Message sent: %s', info.messageId);
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
console.log('sendMailError', err);
|
||||
return {
|
||||
success: false,
|
||||
error: err?.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('verifyError', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error?.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = Nodemailer;
|
||||
Loading…
Reference in New Issue