This commit is contained in:
Xu Chang 2024-08-28 12:26:15 +08:00
parent 1e83328323
commit e0e11ad0da
79 changed files with 1934 additions and 89 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

12
es/components/passport/email/index.d.ts vendored Normal file
View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

11
es/components/passport/sms/index.d.ts vendored Normal file
View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}

View File

@ -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: {

View File

@ -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;

View File

@ -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);
}
},
});

View File

@ -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"
}
}

View File

@ -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;
}

View File

@ -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>

View File

@ -0,0 +1,9 @@
{
"Login": "登录",
"Send": "发送验证码",
"placeholder": {
"Captcha": "输入4位验证码",
"email": "请输入邮箱"
},
"resendAfter": "秒后可重发"
}

18
es/components/user/login/email/web.d.ts vendored Normal file
View File

@ -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;

View File

@ -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>);
}

View File

@ -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;
}
}

View File

@ -3,10 +3,10 @@ export const entityDesc = {
zh_CN: {
name: '直播流',
attr: {
title: '名称',
title: '名称', // 用户定义直播间名称,
streamTitle: '直播流名称',
liveonly: '活跃状态',
hub: '直播空间名称',
hub: '直播空间名称', // 所属直播空间名称
entity: '所属实体',
entityId: '所属实体id',
rtmpPushUrl: '推流地址',

17
es/entities/LoginName.d.ts vendored Normal file
View File

@ -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;
}>;

53
es/entities/LoginName.js Normal file
View File

@ -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',
}
}
}
};

10
es/oak-app-domain/LoginName/Action.d.ts vendored Normal file
View File

@ -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>;
};

View File

@ -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
};

142
es/oak-app-domain/LoginName/Schema.d.ts vendored Normal file
View File

@ -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 {};

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,3 @@
import { StorageDesc } from "oak-domain/lib/types/Storage";
import { OpSchema } from "./Schema";
export declare const desc: StorageDesc<OpSchema>;

View File

@ -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',
}
],
}
]
};

View File

@ -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"]>;

View File

@ -0,0 +1,12 @@
export const style = {
icon: {
enable: '',
disable: '',
},
color: {
ableState: {
enabled: '#008000',
disabled: '#A9A9A9',
}
}
};

View File

@ -0,0 +1 @@
{ "name": "账号", "attr": { "name": "账号", "user": "关联用户", "tokens": "相关令牌", "ableState": "是否可用" }, "action": { "enable": "启用", "disable": "禁用" }, "v": { "ableState": { "enabled": "可用的", "disabled": "禁用的" } } }

View File

@ -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;

23
es/types/Email.d.ts vendored Normal file
View File

@ -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;
}>;
}

1
es/types/Email.js Normal file
View File

@ -0,0 +1 @@
export {};

View File

@ -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;

View File

@ -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);
}

17
es/utils/email/index.d.ts vendored Normal file
View File

@ -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;
}>;

4
es/utils/email/index.frontend.d.ts vendored Normal file
View File

@ -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>;

View File

@ -0,0 +1,4 @@
export async function sendEmail(options, context) {
const { text, html } = options;
console.log('邮件内容:', html || text);
}

33
es/utils/email/index.js Normal file
View File

@ -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,
};
}
}

13
es/utils/email/node-mailer.d.ts vendored Normal file
View File

@ -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;
}>;
}

View File

@ -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,
};
}
}
}

View File

@ -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;

View File

@ -6,10 +6,10 @@ exports.entityDesc = {
zh_CN: {
name: '直播流',
attr: {
title: '名称',
title: '名称', // 用户定义直播间名称,
streamTitle: '直播流名称',
liveonly: '活跃状态',
hub: '直播空间名称',
hub: '直播空间名称', // 所属直播空间名称
entity: '所属实体',
entityId: '所属实体id',
rtmpPushUrl: '推流地址',

17
lib/entities/LoginName.d.ts vendored Normal file
View File

@ -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;
}>;

56
lib/entities/LoginName.js Normal file
View File

@ -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',
}
}
}
};

View File

@ -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>;
};

View File

@ -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
};

142
lib/oak-app-domain/LoginName/Schema.d.ts vendored Normal file
View File

@ -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 {};

View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -0,0 +1,3 @@
import { StorageDesc } from "oak-domain/lib/types/Storage";
import { OpSchema } from "./Schema";
export declare const desc: StorageDesc<OpSchema>;

View File

@ -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',
}
],
}
]
};

View File

@ -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"]>;

View File

@ -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',
}
}
};

View File

@ -0,0 +1 @@
{ "name": "账号", "attr": { "name": "账号", "user": "关联用户", "tokens": "相关令牌", "ableState": "是否可用" }, "action": { "enable": "启用", "disable": "禁用" }, "v": { "ableState": { "enabled": "可用的", "disabled": "禁用的" } } }

View File

@ -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;

23
lib/types/Email.d.ts vendored Normal file
View File

@ -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;
}>;
}

2
lib/types/Email.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -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;

View File

@ -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;

17
lib/utils/email/index.d.ts vendored Normal file
View File

@ -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;
}>;

4
lib/utils/email/index.frontend.d.ts vendored Normal file
View File

@ -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>;

View File

@ -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;

41
lib/utils/email/index.js Normal file
View File

@ -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;

13
lib/utils/email/node-mailer.d.ts vendored Normal file
View File

@ -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;
}>;
}

View File

@ -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;