Merge branch 'dev' of codeup.aliyun.com:61c14a7efa282c88e103c23f/oak-general-business into dev

This commit is contained in:
wangwenchen 2024-01-24 12:04:41 +08:00
commit 9e31e9f7d9
63 changed files with 467 additions and 1098 deletions

View File

@ -12,7 +12,7 @@ import { shrinkUuidTo32Bytes } from 'oak-domain/lib/utils/uuid';
* @returns * @returns
*/ */
export async function createWechatQrCode(options, context) { export async function createWechatQrCode(options, context) {
const { entity, entityId, tag, permanent = false, props, type: qrCodeType } = options; const { entity, entityId, tag, permanent = false, props, type: qrCodeType, } = options;
const applicationId = context.getApplicationId(); const applicationId = context.getApplicationId();
assert(applicationId); assert(applicationId);
const [system] = await context.select('system', { const [system] = await context.select('system', {
@ -32,7 +32,7 @@ export async function createWechatQrCode(options, context) {
filter: { filter: {
application$system: { application$system: {
id: applicationId, id: applicationId,
} },
}, },
}, { }, {
dontCollect: true, dontCollect: true,
@ -46,24 +46,24 @@ export async function createWechatQrCode(options, context) {
const id = generateNewId(); const id = generateNewId();
if (qrCodeType) { if (qrCodeType) {
switch (qrCodeType) { switch (qrCodeType) {
case 'wechatPublic': case 'wechatPublic': {
{ const self = applications.find((ele) => ele.type === 'wechatPublic');
const self = applications.find((ele) => ele.type === 'wechatPublic'); if (!(self &&
if (!(self && self.type === 'wechatPublic' && self.type === 'wechatPublic' &&
self.config.isService)) { self.config.isService)) {
throw new Error('无法生成公众号二维码,服务号未正确配置'); throw new Error('无法生成公众号二维码,服务号未正确配置');
}
appId = self.id;
appType = 'wechatPublic';
break;
} }
appId = self.id;
appType = 'wechatPublic';
break;
}
case 'wechatMpDomainUrl': { case 'wechatMpDomainUrl': {
const self = applications.find((ele) => ele.type === 'wechatMp'); const self = applications.find((ele) => ele.type === 'wechatMp');
if (!(self.type === 'wechatMp' && if (!(self.type === 'wechatMp' &&
self.config.qrCodePrefix)) { self.config.qrCodePrefix)) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
appId = self.id; appId = self.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
@ -79,12 +79,14 @@ export async function createWechatQrCode(options, context) {
} }
case 'wechatPublicForMp': { case 'wechatPublicForMp': {
const self = applications.find((ele) => ele.type === 'wechatPublic'); const self = applications.find((ele) => ele.type === 'wechatPublic');
if (!(self && self.type === 'wechatPublic' && if (!(self &&
self.type === 'wechatPublic' &&
self.config.isService)) { self.config.isService)) {
throw new Error('无法生成公众号-小程序二维码,服务号未正确配置'); throw new Error('无法生成公众号-小程序二维码,服务号未正确配置');
} }
const selfMp = applications.find((ele) => ele.type === 'wechatMp'); const selfMp = applications.find((ele) => ele.type === 'wechatMp');
if (!(selfMp && selfMp.config.appId && if (!(selfMp &&
selfMp.config.appId &&
selfMp.config.appSecret)) { selfMp.config.appSecret)) {
throw new Error('无法生成公众号-小程序二维码,小程序未正确配置'); throw new Error('无法生成公众号-小程序二维码,小程序未正确配置');
} }
@ -115,7 +117,7 @@ export async function createWechatQrCode(options, context) {
appId = self.id; appId = self.id;
if (self.config.qrCodePrefix) { if (self.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -135,7 +137,7 @@ export async function createWechatQrCode(options, context) {
appId = mpApp.id; appId = mpApp.id;
if (mpApp.config.qrCodePrefix) { if (mpApp.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${mpApp.config.qrCodePrefix}/${id}`; url = `${mpApp.config.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -170,40 +172,6 @@ export async function createWechatQrCode(options, context) {
switch (type) { switch (type) {
case 'wechatMpWxaCode': { case 'wechatMpWxaCode': {
assert(applicationType === 'wechatMp' && config.type === 'wechatMp'); assert(applicationType === 'wechatMp' && config.type === 'wechatMp');
const config2 = config;
const { appId, appSecret } = config2;
// if (process.env.OAK_PLATFORM === 'web') {
// Object.assign(data, {
// buffer: 'develop环境下无法真实获取二维码数据',
// });
// }
// else {
// // 小程序码去实时获取(暂时不考虑缓存)
// const wechatInstance = WechatSDK.getInstance(
// appId,
// 'wechatMp',
// appSecret
// ) as WechatMpInstance;
// const envVersionVersionDict = {
// development: 'develop',
// staging: 'trial',
// production: 'release',
// };
// const buffer = await wechatInstance.getMpUnlimitWxaCode({
// scene: shrinkUuidTo32Bytes(id),
// envVersion:
// envVersionVersionDict[
// process.env
// .NODE_ENV as keyof typeof envVersionVersionDict
// ] as 'release',
// page: 'pages/wechatQrCode/scan/index', // todo这里用其它的页面微信服务器拒绝因为没发布。应该是 pages/wechatQrCode/scan/index
// });
// // 把arrayBuffer转成字符串返回
// const str = String.fromCharCode(...new Uint8Array(buffer));
// Object.assign(data, {
// buffer: str,
// });
// }
break; break;
} }
case 'wechatPublicForMp': case 'wechatPublicForMp':
@ -226,8 +194,8 @@ export async function createWechatQrCode(options, context) {
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(data, { Object.assign(data, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;
@ -243,9 +211,7 @@ export async function createWechatQrCode(options, context) {
id: generateNewId(), id: generateNewId(),
action: 'create', action: 'create',
data, data,
}, { }, {});
dontCollect: true,
});
} }
export async function getMpUnlimitWxaCode(wechatQrCodeId, context) { export async function getMpUnlimitWxaCode(wechatQrCodeId, context) {
const [wechatQrCode] = await context.select('wechatQrCode', { const [wechatQrCode] = await context.select('wechatQrCode', {

View File

@ -1,2 +1,2 @@
declare const checkers: (import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[]; declare const checkers: (import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[];
export default checkers; export default checkers;

View File

@ -60,9 +60,9 @@ export default function Render(props) {
children: (<TemplateList oakAutoUnmount={true} oakPath={`templateUpsert-wechatMp-ApplicationId:${id}`} applicationId={id}/>), children: (<TemplateList oakAutoUnmount={true} oakPath={`templateUpsert-wechatMp-ApplicationId:${id}`} applicationId={id}/>),
}); });
} }
if (id && oakFullpath) { if (id) {
return (<Tabs tabPosition="left" onChange={(key) => { return (<Tabs tabPosition="left" onChange={(key) => {
setTabKey(key); setTabKey(key);
}} items={items} style={{ height: 520 }}/>); }} items={items} style={{ minHeight: 520 }}/>);
} }
} }

View File

@ -1,21 +0,0 @@
import { EntityDict } from '../../../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, false, {
style?: import("react").CSSProperties | undefined;
className?: string | undefined;
title?: React.ReactNode;
showBack?: boolean | undefined;
onBack?: (() => void) | undefined;
backIcon?: React.ReactNode;
delta?: number | undefined;
extra?: React.ReactNode;
subTitle?: React.ReactNode;
contentMargin?: boolean | undefined;
contentStyle?: import("react").CSSProperties | undefined;
contentClassName?: string | undefined;
tags?: React.ReactNode;
children?: React.ReactNode;
showHeader?: boolean | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -1,8 +0,0 @@
export default OakComponent({
isList: false,
methods: {
goBack(delta) {
this.navigateBack(delta);
},
},
});

View File

@ -1,132 +0,0 @@
.oak-pageHeader {
display: flex;
flex-direction: column;
&-header {
margin: 0;
font-size: 0;
height: auto;
line-height: inherit;
min-height: inherit;
position: relative;
padding: 10px 20px;
color: #000;
background: var(--oak-bg-color-container);
&-backIcon {
width: 16px;
height: 16px;
font-size: 16px;
}
&-title {
display: inline-block;
vertical-align: middle;
font-size: 16px;
font-weight: 700;
margin-right: 20px;
max-width: 70%;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
height: 30px;
line-height: 30px;
}
&-subTitle {
font-size: 12px;
display: inline-block;
vertical-align: middle;
margin-right: 20px;
}
&-back {
margin-right: 24px;
}
&-col {
display: flex;
align-items: center;
}
}
&-content {
display: flex;
flex-direction: column;
&-margin {
margin: 10px;
}
}
}
@media (max-width:576px) {
.oak-pageHeader {
display: flex;
flex-direction: column;
&-header {
margin: 0;
font-size: 0;
height: auto;
line-height: inherit;
min-height: inherit;
position: relative;
padding: 10px 20px;
color: #000;
background: var(--oak-bg-color-container);
&-backIcon {
width: 16px;
height: 16px;
font-size: 16px;
}
&-title {
display: inline-block;
vertical-align: middle;
font-size: 16px;
font-weight: 700;
margin-right: 20px;
max-width: 70%;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
height: 30px;
line-height: 30px;
}
&-subTitle {
font-size: 12px;
display: inline-block;
vertical-align: middle;
margin-right: 20px;
}
&-back {
margin-right: 24px;
}
&-col {
display: flex;
align-items: center;
}
}
&-content {
display: flex;
flex-direction: column;
&-margin {
margin: 5px;
}
}
}
}

View File

@ -1,25 +0,0 @@
import React from 'react';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
import './index.less';
type PageHeaderProps = {
style?: React.CSSProperties;
className?: string;
title?: React.ReactNode;
showBack?: boolean;
onBack?: () => void;
backIcon?: React.ReactNode;
delta?: number;
extra?: React.ReactNode;
subTitle?: React.ReactNode;
contentMargin?: boolean;
contentStyle?: React.CSSProperties;
contentClassName?: string;
tags?: React.ReactNode;
children?: React.ReactNode;
showHeader?: boolean;
};
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, PageHeaderProps, {
goBack: (delta?: number) => void;
}>): React.JSX.Element;
export {};

View File

@ -1,41 +0,0 @@
import React from 'react';
import { Row, Col, Button } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import './index.less';
export default function Render(props) {
const { style, className, children, title, subTitle, extra, showBack = false, onBack, backIcon, delta, contentMargin = true, contentStyle, contentClassName, tags, showHeader = true, } = props.data;
const { t, goBack } = props.methods;
const prefixCls = 'oak';
return (<div style={style} className={classNames(`${prefixCls}-pageHeader`, className)}>
{showHeader && (title || showBack || subTitle || tags || extra) && (<div className={`${prefixCls}-pageHeader-header`}>
<Row justify="center">
<Col flex="auto" className={`${prefixCls}-pageHeader-header-col`}>
{showBack && (<Button type="text" className={`${prefixCls}-pageHeader-header-back`} onClick={() => {
if (typeof onBack === 'function') {
onBack();
return;
}
goBack(delta);
}}>
{backIcon || (<ArrowLeftOutlined className={`${prefixCls}-pageHeader-header-backIcon`}/>)}
</Button>)}
{title && (<span className={`${prefixCls}-pageHeader-header-title`}>
{title}
</span>)}
{subTitle && (<span className={`${prefixCls}-pageHeader-header-subTitle`}>
{subTitle}
</span>)}
{tags}
</Col>
<Col flex="auto">{extra}</Col>
</Row>
</div>)}
<div style={contentStyle} className={classNames(`${prefixCls}-pageHeader-content`, contentClassName, {
[`${prefixCls}-pageHeader-content-margin`]: contentMargin,
})}>
{children}
</div>
</div>);
}

View File

@ -19,10 +19,8 @@ function QrCode(props) {
const expiresAtStr = dayjs(expiresAt).format('YYYY年MM月DD日 HH:mm'); const expiresAtStr = dayjs(expiresAt).format('YYYY年MM月DD日 HH:mm');
V = (<span className={`${prefixCls}-qrCodeBox-caption`}> V = (<span className={`${prefixCls}-qrCodeBox-caption`}>
该二维码 该二维码
<span>{diff}</span>
天内(
<span>{expiresAtStr}</span> <span>{expiresAtStr}</span>
)有效失效请重新生成 前有效
</span>); </span>);
} }
else { else {
@ -30,14 +28,14 @@ function QrCode(props) {
const expiresAtStr = dayjs(expiresAt).format('HH:mm'); const expiresAtStr = dayjs(expiresAt).format('HH:mm');
if (diff2 > 0) { if (diff2 > 0) {
V = (<span className={`${prefixCls}-qrCodeBox_caption`}> V = (<span className={`${prefixCls}-qrCodeBox_caption`}>
该二维码1天内( 该二维码
<span>{expiresAtStr}</span> <span>{expiresAtStr}</span>
)有效失效请重新生成 有效
</span>); </span>);
} }
else { else {
V = (<span className={`${prefixCls}-qrCodeBox_caption`}> V = (<span className={`${prefixCls}-qrCodeBox_caption`}>
该二维码已失效请重新生成 该二维码已失效
</span>); </span>);
} }
} }

View File

@ -29,9 +29,9 @@ export default function WechatMp(props) {
<Input placeholder="请输入原始ID" type="text" value={config?.originalId} onChange={(e) => setValue(`originalId`, e.target.value)}/> <Input placeholder="请输入原始ID" type="text" value={config?.originalId} onChange={(e) => setValue(`originalId`, e.target.value)}/>
</> </>
</Form.Item> </Form.Item>
<Form.Item label="qrCodePrefix"> <Form.Item label="普通链接二维码规则" tooltip="扫普通链接二维码打开小程序,如原有二维码链接为 http://www.qq.com/a/123456 其中12345为uuid则可配置规则 http://www.qq.com/a/ 。 请在输入框中填写 http://www.qq.com/a ,系统将在生成二维码时,在链接末尾加上'/'和uuid从而实现扫码打开小程序的规则。">
<> <>
<Input placeholder="请输入qrCodePrefix" type="text" value={config?.qrCodePrefix} onChange={(e) => setValue(`qrCodePrefix`, e.target.value)}/> <Input placeholder="请输入普通链接二维码规则" type="text" value={config?.qrCodePrefix} onChange={(e) => setValue(`qrCodePrefix`, e.target.value)}/>
</> </>
</Form.Item> </Form.Item>
</Form> </Form>

View File

@ -1,7 +1,6 @@
import { EntityDict } from '../../../oak-app-domain'; import { EntityDict } from '../../../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity'; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page'; import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
import { MessageProps } from 'oak-frontend-base/lib/types/Message';
import { ButtonProps } from 'antd'; import { ButtonProps } from 'antd';
import { ButtonProps as AmButtonProps } from 'antd-mobile'; import { ButtonProps as AmButtonProps } from 'antd-mobile';
type AfterCommit = ((id?: string) => void) | undefined; type AfterCommit = ((id?: string) => void) | undefined;
@ -13,25 +12,24 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
type?: ButtonProps['type'] | AmButtonProps['type']; type?: ButtonProps['type'] | AmButtonProps['type'];
executeText?: string | undefined; executeText?: string | undefined;
buttonProps?: (ButtonProps & { buttonProps?: (ButtonProps & {
color?: "default" | "primary" | "success" | "warning" | "danger" | undefined; color?: "default" | "success" | "primary" | "warning" | "danger" | undefined;
fill?: "none" | "solid" | "outline" | undefined; fill?: "solid" | "outline" | "none" | undefined;
size?: "small" | "large" | "middle" | "mini" | undefined; size?: "small" | "mini" | "middle" | "large" | undefined;
block?: boolean | undefined; block?: boolean | undefined;
loading?: boolean | "auto" | undefined; loading?: boolean | "auto" | undefined;
loadingText?: string | undefined; loadingText?: string | undefined;
loadingIcon?: import("react").ReactNode; loadingIcon?: import("react").ReactNode;
disabled?: boolean | undefined; disabled?: boolean | undefined;
onClick?: ((event: import("react").MouseEvent<HTMLButtonElement, MouseEvent>) => unknown) | undefined; onClick?: ((event: import("react").MouseEvent<HTMLButtonElement, MouseEvent>) => unknown) | undefined;
type?: "button" | "submit" | "reset" | undefined; type?: "submit" | "reset" | "button" | undefined;
shape?: "default" | "rounded" | "rectangular" | undefined; shape?: "default" | "rounded" | "rectangular" | undefined;
children?: import("react").ReactNode; children?: import("react").ReactNode;
} & Pick<import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "id" | "onMouseUp" | "onMouseDown" | "onTouchStart" | "onTouchEnd"> & { } & Pick<import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "id" | "onMouseDown" | "onMouseUp" | "onTouchStart" | "onTouchEnd"> & {
className?: string | undefined; className?: string | undefined;
style?: (import("react").CSSProperties & Partial<Record<"--text-color" | "--background-color" | "--border-radius" | "--border-width" | "--border-style" | "--border-color", string>>) | undefined; style?: (import("react").CSSProperties & Partial<Record<"--text-color" | "--background-color" | "--border-radius" | "--border-width" | "--border-style" | "--border-color", string>>) | undefined;
tabIndex?: number | undefined; tabIndex?: number | undefined;
} & import("react").AriaAttributes) | undefined; } & import("react").AriaAttributes) | undefined;
afterCommit?: AfterCommit; afterCommit?: AfterCommit;
beforeCommit?: BeforeCommit; beforeCommit?: BeforeCommit;
messageProps?: MessageProps | boolean | undefined,
}>) => React.ReactElement; }>) => React.ReactElement;
export default _default; export default _default;

View File

@ -9,7 +9,8 @@ export default OakComponent({
if (ele) { if (ele) {
if (['failed', 'local'].includes(ele.state)) { if (['failed', 'local'].includes(ele.state)) {
state = ele.state; state = ele.state;
} else if (ele.state === 'uploading' && state === 'uploaded') { }
else if (ele.state === 'uploading' && state === 'uploaded') {
state = 'uploading'; state = 'uploading';
} }
} }
@ -50,12 +51,8 @@ export default OakComponent({
}, },
methods: { methods: {
getEfIds() { getEfIds() {
const entity = this.features.runningTree.getEntity( const entity = this.features.runningTree.getEntity(this.state.oakFullpath);
this.state.oakFullpath const operations = this.features.runningTree.getOperations(this.state.oakFullpath);
);
const operations = this.features.runningTree.getOperations(
this.state.oakFullpath
);
const efIds = []; const efIds = [];
const getRecursive = (e, o) => { const getRecursive = (e, o) => {
const { action, data } = o; const { action, data } = o;
@ -69,31 +66,28 @@ export default OakComponent({
for (const attr in data) { for (const attr in data) {
const rel = this.features.cache.judgeRelation(e, attr); const rel = this.features.cache.judgeRelation(e, attr);
if (rel === 2) { if (rel === 2) {
assert( assert(typeof data[attr] === 'object' &&
typeof data[attr] === 'object' && !(data[attr] instanceof Array));
!(data[attr] instanceof Array)
);
getRecursive(attr, data[attr]); getRecursive(attr, data[attr]);
} else if (typeof rel === 'string') { }
assert( else if (typeof rel === 'string') {
typeof data[attr] === 'object' && assert(typeof data[attr] === 'object' &&
!(data[attr] instanceof Array) !(data[attr] instanceof Array));
);
getRecursive(rel, data[attr]); getRecursive(rel, data[attr]);
} else if (rel instanceof Array) { }
else if (rel instanceof Array) {
const [e2] = rel; const [e2] = rel;
if (data[attr] instanceof Array) { if (data[attr] instanceof Array) {
data[attr].forEach((o2) => getRecursive(e2, o2)); data[attr].forEach((o2) => getRecursive(e2, o2));
} else { }
else {
getRecursive(e2, data[attr]); getRecursive(e2, data[attr]);
} }
} }
} }
}; };
if (operations instanceof Array) { if (operations instanceof Array) {
operations.forEach((ele) => operations.forEach((ele) => getRecursive(entity, ele.operation));
getRecursive(entity, ele.operation)
);
} }
return efIds; return efIds;
}, },
@ -103,26 +97,20 @@ export default OakComponent({
} }
const promises = []; const promises = [];
const failureIds = []; const failureIds = [];
const entity = this.features.runningTree.getEntity( const entity = this.features.runningTree.getEntity(this.state.oakFullpath);
this.state.oakFullpath
);
ids.forEach((id) => { ids.forEach((id) => {
const fileState = this.features.extraFile.getFileState(id); const fileState = this.features.extraFile.getFileState(id);
if (fileState) { if (fileState) {
const { state } = fileState; const { state } = fileState;
if (['local', 'failed'].includes(state)) { if (['local', 'failed'].includes(state)) {
promises.push( promises.push((async () => {
(async () => { try {
try { await this.features.extraFile.upload(id, entity);
await this.features.extraFile.upload( }
id, catch (err) {
entity failureIds.push(id);
); }
} catch (err) { })());
failureIds.push(id);
}
})()
);
} }
} }
}); });
@ -159,7 +147,8 @@ export default OakComponent({
if (afterCommit) { if (afterCommit) {
afterCommit(id); afterCommit(id);
} }
} else { }
else {
const { failureIds, currentId } = this.state; const { failureIds, currentId } = this.state;
const id2 = currentId; const id2 = currentId;
assert(failureIds && failureIds.length > 0); assert(failureIds && failureIds.length > 0);

View File

@ -1,6 +1,6 @@
import { WebComponentProps } from 'oak-frontend-base';
import React from 'react'; import React from 'react';
import { ButtonProps } from 'antd-mobile'; import { ButtonProps } from 'antd-mobile';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain'; import { EntityDict } from '../../../oak-app-domain';
import { FileState } from '../../../features/extraFile'; import { FileState } from '../../../features/extraFile';
export default function render(props: WebComponentProps<EntityDict, any, true, { export default function render(props: WebComponentProps<EntityDict, any, true, {

View File

@ -1,34 +1,31 @@
import React from 'react'; import React from 'react';
import { Table, Tag, Button, Modal, Space, Row, Col, Input, } from 'antd'; import { Table, Tag, Button, Modal, Space, Row, Col, Input, } from 'antd';
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import Style from './web.module.less';
import PageHeader from '../../common/pageHeader';
export default function render(props) { export default function render(props) {
const { pagination, articles = [], oakLoading, searchValue, title, showBack = false, } = props.data; const { pagination, articles = [], oakLoading, searchValue, title, showBack = false, } = props.data;
const { pageSize, total, currentPage } = pagination || {}; const { pageSize, total, currentPage } = pagination || {};
const { t, goUpsert, goDetailById, goUpsertById, searchConfirm, searchValueChange, setCurrentPage, setPageSize, onRemove, } = props.methods; const { t, goUpsert, goDetailById, goUpsertById, searchConfirm, searchValueChange, setCurrentPage, setPageSize, onRemove, } = props.methods;
return (<PageHeader title={title || '文章管理'} showBack={showBack}> return (<>
<div className={Style.container}> <Row>
<Row> <Col flex="auto">
<Col flex="auto"> <Space>
<Space> <Button type="primary" onClick={() => {
<Button type="primary" onClick={() => {
goUpsert(); goUpsert();
}}> }}>
{t('action.add')} {t('action.add')}
</Button> </Button>
</Space> </Space>
</Col> </Col>
<Col flex="none"> <Col flex="none">
<Input placeholder="请输入标题" value={searchValue} allowClear onChange={(e) => { <Input placeholder="请输入标题" value={searchValue} allowClear onChange={(e) => {
searchValueChange(e.target.value); searchValueChange(e.target.value);
}} suffix={<SearchOutlined />} onPressEnter={(e) => { }} suffix={<SearchOutlined />} onPressEnter={(e) => {
searchConfirm(); searchConfirm();
}}/> }}/>
</Col> </Col>
</Row> </Row>
<Table loading={oakLoading} dataSource={articles} rowKey="index" columns={[ <Table loading={oakLoading} dataSource={articles} rowKey="index" columns={[
{ {
align: 'center', align: 'center',
dataIndex: 'serial-number', dataIndex: 'serial-number',
@ -42,8 +39,8 @@ export default function render(props) {
title: t('book:attr.iState'), title: t('book:attr.iState'),
render: (value, record, index) => { render: (value, record, index) => {
return (<Tag color="processing"> return (<Tag color="processing">
{t(`book:v.iState.${value}`)} {t(`book:v.iState.${value}`)}
</Tag>); </Tag>);
}, },
}, },
{ {
@ -65,17 +62,17 @@ export default function render(props) {
align: 'center', align: 'center',
render: (value, record, index) => { render: (value, record, index) => {
return (<Space> return (<Space>
<Button type="link" onClick={() => { <Button type="link" onClick={() => {
goDetailById(record.id); goDetailById(record.id);
}}> }}>
详情 详情
</Button> </Button>
<Button type="link" onClick={() => { <Button type="link" onClick={() => {
goUpsertById(record.id); goUpsertById(record.id);
}}> }}>
编辑 编辑
</Button> </Button>
<Button type="link" onClick={() => { <Button type="link" onClick={() => {
const modal = Modal.confirm({ const modal = Modal.confirm({
title: '确认删除该文章吗?', title: '确认删除该文章吗?',
content: '删除后,文章不可恢复', content: '删除后,文章不可恢复',
@ -90,9 +87,9 @@ export default function render(props) {
}, },
}); });
}}> }}>
删除 删除
</Button> </Button>
</Space>); </Space>);
}, },
fixed: 'right', fixed: 'right',
}, },
@ -107,6 +104,5 @@ export default function render(props) {
setCurrentPage(current); setCurrentPage(current);
}, },
}}/> }}/>
</div> </>);
</PageHeader>);
} }

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import QrCode from '../../../components/common/qrCode'; import QrCode from '../../../components/common/qrCode';
import { Spin, Button, Space, Input, Tooltip,Alert } from 'antd'; import { Spin, Button, Space, Input, Tooltip, Alert } from 'antd';
import { CopyOutlined } from '@ant-design/icons'; import { CopyOutlined } from '@ant-design/icons';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
export default function Render(props) { export default function Render(props) {
@ -22,8 +22,8 @@ export default function Render(props) {
}}> }}>
<div style={{ <div style={{
maxWidth: 800 maxWidth: 800
}}> }}>
<Alert message="温馨提示:请扫描二维码或打开链接填写信息!" type="info" /> <Alert message="将二维码或下方链接发送给使用者" type="info"/>
<QrCode url={url} expiresAt={expiresAt}/> <QrCode url={url} expiresAt={expiresAt}/>
<Space.Compact block style={{ marginTop: 16 }}> <Space.Compact block style={{ marginTop: 16 }}>

View File

@ -4,7 +4,7 @@ import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'parasite', true, { export default function render(props: WebComponentProps<EntityDict, 'parasite', true, {
searchValue: string; searchValue: string;
nameLabel: string; nameLabel: string;
list: RowWithActions<EntityDict, 'userEntityGrant'>[]; list: RowWithActions<EntityDict, 'parasite'>[];
}, { }, {
cancel: () => void; cancel: () => void;
getQrCode: () => Promise<void>; getQrCode: () => Promise<void>;

View File

@ -23,7 +23,7 @@ export default function render(props) {
dataIndex: ['user', 'nickname'], dataIndex: ['user', 'nickname'],
title: nameLabel || '名称', title: nameLabel || '名称',
render: (value, record, index) => { render: (value, record, index) => {
return value !== 'shadow_user' && value || '--'; return (value !== 'shadow_user' && value) || '--';
}, },
}, },
{ {
@ -94,7 +94,7 @@ export default function render(props) {
}, },
}, },
{ {
label: '采集码', label: '详情',
action: 'qrcode', action: 'qrcode',
show: record['#oakLegalActions']?.includes('qrcode'), show: record['#oakLegalActions']?.includes('qrcode'),
// alerted: true, // alerted: true,

View File

@ -3,7 +3,7 @@
height: 100%; height: 100%;
.tabLabel { .tabLabel {
writing-mode: vertical-rl; // writing-mode: vertical-rl;
letter-spacing: .2rem; letter-spacing: .2rem;
} }
} }

View File

@ -11,57 +11,33 @@ export default function Render(props) {
const [openStation, setStation] = useState(false); const [openStation, setStation] = useState(false);
const [subwayId, setSubwayId] = useState(''); const [subwayId, setSubwayId] = useState('');
const [stationId, setStationId] = useState(''); const [stationId, setStationId] = useState('');
return ( return (<>
<>
<div style={{ marginBottom: 16 }}> <div style={{ marginBottom: 16 }}>
城市 城市
<Select <Select placeholder={'选择城市'} value={areaId} onChange={(value) => {
placeholder={'选择城市'} setAreaId(value);
value={areaId} setFilterByAreaId(value);
onChange={(value) => { }} style={{ width: '20%' }} options={areaOptions} allowClear></Select>
setAreaId(value);
setFilterByAreaId(value);
}}
style={{ width: '20%' }}
options={areaOptions}
allowClear
></Select>
</div> </div>
<Tree <Tree className={Style.tree} blockNode={true} treeData={treeData} titleRender={(nodeData) => {
className={Style.tree} return (<Row align="middle" style={{ flex: 1 }}>
blockNode={true}
treeData={treeData}
titleRender={(nodeData) => {
return (
<Row align="middle" style={{ flex: 1 }}>
<Col flex="auto">{nodeData.title}</Col> <Col flex="auto">{nodeData.title}</Col>
<Col flex="none"> <Col flex="none">
<Space> <Space>
{!nodeData.isLeaf ? ( {!nodeData.isLeaf ? (<Button onClick={() => {
<Button setSubwayId(nodeData.key);
onClick={() => { setSubway(true);
setSubwayId(nodeData.key); }}>
setSubway(true);
}}
>
编辑 编辑
</Button> </Button>) : (<Button onClick={() => {
) : ( const index = nodeData.key.indexOf('/') + 1;
<Button const temp = nodeData.key.substr(index);
onClick={() => { setStationId(temp);
const index = setStation(true);
nodeData.key.indexOf('/') + }}>
1;
const temp =
nodeData.key.substr(index);
setStationId(temp);
setStation(true);
}}
>
编辑 编辑
</Button> </Button>)}
)}
{/* {!nodeData.isLeaf && ( {/* {!nodeData.isLeaf && (
<Button <Button
@ -88,30 +64,10 @@ export default function Render(props) {
)} */} )} */}
</Space> </Space>
</Col> </Col>
</Row> </Row>);
); }}/>
}} {openSubway && (<UpsertSubway onClose={() => setSubway(false)} openSubway={openSubway} oakId={subwayId} oakPath={`${oakFullpath}.${subwayId}`} oakAutoUnmount={true}/>)}
/>
{openSubway && (
<UpsertSubway
onClose={() => setSubway(false)}
openSubway={openSubway}
oakId={subwayId}
oakPath={`${oakFullpath}.${subwayId}`}
oakAutoUnmount={true}
/>
)}
{openStation && ( {openStation && (<UpsertStation onClose={() => setStation(false)} openStation={openStation} oakId={stationId} subwayId={subwayId} oakPath={`$subwayLine/upsertStation,${stationId}`} oakAutoUnmount={true}/>)}
<UpsertStation </>);
onClose={() => setStation(false)}
openStation={openStation}
oakId={stationId}
subwayId={subwayId}
oakPath={`$subwayLine/upsertStation,${stationId}`}
oakAutoUnmount={true}
/>
)}
</>
);
} }

View File

@ -4,8 +4,8 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
entity: keyof EntityDict; entity: keyof EntityDict;
entityFilter: any; entityFilter: any;
relationIds: string[]; relationIds: string[];
rule: "single" | "all" | "free"; rule: "all" | "single" | "free";
ruleOnRow: "single" | "all" | "free"; ruleOnRow: "all" | "single" | "free";
onPickRelations: (ids: string[]) => void; onPickRelations: (ids: string[]) => void;
onPickRows: (ids: string[]) => void; onPickRows: (ids: string[]) => void;
pickedRowIds: string[] | undefined; pickedRowIds: string[] | undefined;

View File

@ -11,7 +11,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
claimUrl: string; claimUrl: string;
qrCodeType: QrCodeType; qrCodeType: QrCodeType;
multiple: boolean; multiple: boolean;
rule: "single" | "all" | "free"; rule: "all" | "single" | "free";
ruleOnRow: "single" | "all" | "free"; ruleOnRow: "all" | "single" | "free";
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default; export default _default;

View File

@ -4,7 +4,7 @@
<view class="ueg-container"> <view class="ueg-container">
<userEntityGrant-share oakId="{{userEntityGrantId}}" oakAutoUnmount="{{true}}" oakPath="$userEntityGrant/upsert-userEntityGrant/detail" /> <userEntityGrant-share oakId="{{userEntityGrantId}}" oakAutoUnmount="{{true}}" oakPath="$userEntityGrant/upsert-userEntityGrant/detail" />
<view class="share"> <view class="share">
<l-button size="long"type="success" open-type="share"> <l-button size="long" type="success" open-type="share">
分享 分享
</l-button> </l-button>
</view> </view>

View File

@ -5,8 +5,8 @@
"chooseExpiresAt": "请选择有效时长", "chooseExpiresAt": "请选择有效时长",
"expiresHelp": "支持分钟、小时选择", "expiresHelp": "支持分钟、小时选择",
"helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则", "helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则",
"helpMutiple": "是否允许多个用户来认领", "helpMultiple": "是否允许多个用户来认领",
"shareCode": "请将二维码发给待分享权限的用户使用微信扫描", "shareCode": "请将二维码发给待认领权限的用户,让他们使用微信扫描。",
"unit": { "unit": {
"hour": "小时", "hour": "小时",
"minute": "分钟" "minute": "分钟"

View File

@ -42,7 +42,7 @@ export default function render(props) {
</Space> </Space>
</Radio.Group> </Radio.Group>
</Form.Item>)} </Form.Item>)}
{type === 'grant' && (<Form.Item label={t('multiple')} required help={t('helpMutiple')}> {type === 'grant' && (<Form.Item label={t('multiple')} required help={t('helpMultiple')}>
<Switch checked={multiple || false} onChange={(val) => update({ multiple: val })}/> <Switch checked={multiple || false} onChange={(val) => update({ multiple: val })}/>
</Form.Item>)} </Form.Item>)}
<Form.Item label={t('userEntityGrant:attr.expiresAt')} name="period" rules={[ <Form.Item label={t('userEntityGrant:attr.expiresAt')} name="period" rules={[

View File

@ -29,12 +29,14 @@ export default function render(props) {
}))}/> }))}/>
</Form.Item> </Form.Item>
{relationIds?.length > 1 && (<Form.Item label={t('userEntityGrant:attr.rule')} help={t('helpRule')}> {relationIds?.length > 1 && (<Form.Item label={t('userEntityGrant:attr.rule')} help={t('helpRule')}>
<Radio.Group value={rule} onChange={({ target }) => update({ rule: target.value })} options={rules.map((ele) => ({ <Radio.Group value={rule} onChange={({ target }) => update({
rule: target.value,
})} options={rules.map((ele) => ({
value: ele, value: ele,
label: t(`userEntityGrant:v.rule.${ele}`) label: t(`userEntityGrant:v.rule.${ele}`),
}))}/> }))}/>
</Form.Item>)} </Form.Item>)}
{type === 'grant' && (<Form.Item label={t('multiple')} required help={t('helpMutiple')}> {type === 'grant' && (<Form.Item label={t('multiple')} required help={t('helpMultiple')}>
<Switch checked={multiple || false} onChange={(val) => update({ multiple: val })}/> <Switch checked={multiple || false} onChange={(val) => update({ multiple: val })}/>
</Form.Item>)} </Form.Item>)}
<Form.Item label={t('userEntityGrant:attr.expiresAt')} required <Form.Item label={t('userEntityGrant:attr.expiresAt')} required

View File

@ -3,22 +3,13 @@ import { Checkbox } from 'antd-mobile';
export default function Render(props) { export default function Render(props) {
const { entity, relations2 } = props.data; const { entity, relations2 } = props.data;
const { t, onRelationChange } = props.methods; const { t, onRelationChange } = props.methods;
return ( return (<>
<> {relations2?.map(({ relation, isChecked }) => (<Checkbox key={`userRelation_${relation}`} style={{ marginRight: 20 }} checked={isChecked} onChange={(checked) => {
{relations2?.map(({ relation, isChecked }) => ( onRelationChange(relation, checked);
<Checkbox }}>
key={`userRelation_${relation}`}
style={{ marginRight: 20 }}
checked={isChecked}
onChange={(checked) => {
onRelationChange(relation, checked);
}}
>
{relation.name {relation.name
? t(`${entity}:r.${relation.name}`) ? t(`${entity}:r.${relation.name}`)
: relation.display} : relation.display}
</Checkbox> </Checkbox>))}
))} </>);
</>
);
} }

View File

@ -3,23 +3,14 @@ import { Checkbox } from 'antd';
export default function Render(props) { export default function Render(props) {
const { entity, relations2 } = props.data; const { entity, relations2 } = props.data;
const { t, onRelationChange } = props.methods; const { t, onRelationChange } = props.methods;
return ( return (<>
<> {relations2?.map(({ relation, isChecked }) => (<Checkbox key={`userRelation_${relation}`} checked={isChecked} value={relation} onChange={({ target }) => {
{relations2?.map(({ relation, isChecked }) => ( const { checked } = target;
<Checkbox onRelationChange(relation, checked);
key={`userRelation_${relation}`} }}>
checked={isChecked}
value={relation}
onChange={({ target }) => {
const { checked } = target;
onRelationChange(relation, checked);
}}
>
{relation.name {relation.name
? t(`${entity}:r.${relation.name}`) ? t(`${entity}:r.${relation.name}`)
: relation.display} : relation.display}
</Checkbox> </Checkbox>))}
))} </>);
</>
);
} }

View File

@ -32,24 +32,24 @@ export default function Render(props) {
children: <div className={Style.container}>尚未实现</div>, children: <div className={Style.container}>尚未实现</div>,
}, },
{ {
label: '手机号', label: '二维码',
key: 'item-2', key: 'item-2',
children: (<ByMobile entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>), children: (<ByUserEntityGrant entity={entity} entityId={entityId} relations={relations} qrCodeType={qrCodeType} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} claimUrl={claimUrl} rule={rule} ruleOnRow={ruleOnRow}/>),
}, },
{ {
label: '二维码', label: '手机号',
key: 'item-3', key: 'item-3',
children: (<ByUserEntityGrant entity={entity} entityId={entityId} relations={relations} qrCodeType={qrCodeType} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} claimUrl={claimUrl} rule={rule} ruleOnRow={ruleOnRow}/>), children: (<ByMobile entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>),
}, },
]; ];
const items2 = []; const items2 = [];
if (grantByEmail) { if (grantByEmail) {
items2.push(items[0]); items2.push(items[0]);
} }
if (grantByMobile) { if (grantByUserEntityGrant) {
items2.push(items[1]); items2.push(items[1]);
} }
if (grantByUserEntityGrant) { if (grantByMobile) {
items2.push(items[2]); items2.push(items[2]);
} }
SubPart = (<Tabs className={Style.tab}> SubPart = (<Tabs className={Style.tab}>

View File

@ -32,24 +32,24 @@ export default function Render(props) {
children: <div className={Style.container}>尚未实现</div>, children: <div className={Style.container}>尚未实现</div>,
}, },
{ {
label: '手机号', label: '二维码',
key: 'item-2', key: 'item-2',
children: (<ByMobile allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname} passwordRequire={passwordRequire} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>), children: (<ByUserEntityGrant entity={entity} entityId={entityId} relations={relations} qrCodeType={qrCodeType} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} claimUrl={claimUrl} rule={rule} ruleOnRow={ruleOnRow}/>),
}, },
{ {
label: '二维码', label: '手机号',
key: 'item-3', key: 'item-3',
children: (<ByUserEntityGrant entity={entity} entityId={entityId} relations={relations} qrCodeType={qrCodeType} oakPath="$userRelation-upsert-by-userEntityGrant" oakAutoUnmount={true} redirectToAfterConfirm={redirectToAfterConfirm} claimUrl={claimUrl} rule={rule} ruleOnRow={ruleOnRow}/>), children: (<ByMobile allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname} passwordRequire={passwordRequire} entity={entity} entityId={entityId} relations={relations} oakPath="$userRelation-upsert-by-mobile" oakAutoUnmount={true}/>),
}, },
]; ];
const items2 = []; const items2 = [];
if (grantByEmail) { if (grantByEmail) {
items2.push(items[0]); items2.push(items[0]);
} }
if (grantByMobile) { if (grantByUserEntityGrant) {
items2.push(items[1]); items2.push(items[1]);
} }
if (grantByUserEntityGrant) { if (grantByMobile) {
items2.push(items[2]); items2.push(items[2]);
} }
SubPart = <Tabs items={items2}/>; SubPart = <Tabs items={items2}/>;

View File

@ -1,6 +1,6 @@
import { EntityDict } from '../../../oak-app-domain'; import { EntityDict } from '../../../oak-app-domain';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, { declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, false, {
type: "bind" | "login"; type: "login" | "bind";
url: string; url: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default; export default _default;

View File

@ -1,4 +1,5 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "wechatQrCode", true, { declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "wechatQrCode", true, {
scene: string; scene: string;
q: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>; }>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default; export default _default;

View File

@ -15,6 +15,7 @@ export default OakComponent({
isList: true, isList: true,
properties: { properties: {
scene: '', scene: '',
q: '',
}, },
data: { data: {
loading: false, loading: false,
@ -35,8 +36,17 @@ export default OakComponent({
filters: [ filters: [
{ {
filter() { filter() {
const scene = decodeURIComponent(this.props.scene); let uuid;
const uuid = scene && expandUuidTo36Bytes(scene); if (this.props.scene) {
// 小程序码扫码
const scene = decodeURIComponent(this.props.scene);
uuid = expandUuidTo36Bytes(scene);
}
else if (this.props.q) {
// 普通链接二维码扫码
const q = decodeURIComponent(this.props.q);
uuid = expandUuidTo36Bytes(q);
}
return { return {
id: uuid || 'illegal', id: uuid || 'illegal',
}; };

View File

@ -360,8 +360,8 @@ const i18ns = [
"chooseExpiresAt": "请选择有效时长", "chooseExpiresAt": "请选择有效时长",
"expiresHelp": "支持分钟、小时选择", "expiresHelp": "支持分钟、小时选择",
"helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则", "helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则",
"helpMutiple": "是否允许多个用户来认领", "helpMultiple": "是否允许多个用户来认领",
"shareCode": "请将二维码发给待分享权限的用户使用微信扫描", "shareCode": "请将二维码发给待认领权限的用户,让他们使用微信扫描。",
"unit": { "unit": {
"hour": "小时", "hour": "小时",
"minute": "分钟" "minute": "分钟"

View File

@ -32,7 +32,7 @@ const entityDesc = {
}, },
qrCodeType: { qrCodeType: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
@ -40,12 +40,12 @@ const entityDesc = {
rule: { rule: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
ruleOnRow: { ruleOnRow: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
}, },
}, },
@ -59,7 +59,7 @@ const entityDesc = {
}, },
{ {
name: 'expiresAt', name: 'expiresAt',
} },
], ],
}, },
], ],

View File

@ -21,12 +21,12 @@ const entityDesc = {
v: { v: {
type: { type: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
} },
} },
}, },
}, },
indexes: [ indexes: [
@ -41,7 +41,7 @@ const entityDesc = {
}, },
{ {
name: 'tag', name: 'tag',
} },
], ],
}, },
{ {
@ -63,6 +63,6 @@ const entityDesc = {
}, },
], ],
}, },
] ],
}; };
export {}; export {};

View File

@ -1,2 +1,2 @@
declare const _default: (import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[]; declare const _default: (import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[];
export default _default; export default _default;

View File

@ -3,7 +3,7 @@ import { assert } from 'oak-domain/lib/utils/assert';
import { WechatSDK } from 'oak-external-sdk'; import { WechatSDK } from 'oak-external-sdk';
const triggers = [ const triggers = [
{ {
name: '当生成wechatQrCode时,调用外部接口完善数据', name: '当生成wechatQrCode时, 调用外部接口完善数据',
entity: 'wechatQrCode', entity: 'wechatQrCode',
action: 'create', action: 'create',
when: 'before', when: 'before',
@ -62,7 +62,7 @@ const triggers = [
self.config.qrCodePrefix)) { self.config.qrCodePrefix)) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
appId = self.id; appId = self.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
@ -114,7 +114,8 @@ const triggers = [
appId = self.id; appId = self.id;
if (self.config.qrCodePrefix) { if (self.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config
.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -132,9 +133,10 @@ const triggers = [
const mpApp = applications.find((ele) => ele.type === 'wechatMp'); const mpApp = applications.find((ele) => ele.type === 'wechatMp');
if (mpApp) { if (mpApp) {
appId = mpApp.id; appId = mpApp.id;
if (mpApp.config.qrCodePrefix) { const mpConfig = mpApp.config;
if (mpConfig?.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${mpApp.config.qrCodePrefix}/${id}`; url = `${mpConfig.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -190,8 +192,8 @@ const triggers = [
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(updateData, { Object.assign(updateData, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;

View File

@ -15,7 +15,7 @@ const uuid_2 = require("oak-domain/lib/utils/uuid");
* @returns * @returns
*/ */
async function createWechatQrCode(options, context) { async function createWechatQrCode(options, context) {
const { entity, entityId, tag, permanent = false, props, type: qrCodeType } = options; const { entity, entityId, tag, permanent = false, props, type: qrCodeType, } = options;
const applicationId = context.getApplicationId(); const applicationId = context.getApplicationId();
(0, assert_1.assert)(applicationId); (0, assert_1.assert)(applicationId);
const [system] = await context.select('system', { const [system] = await context.select('system', {
@ -35,7 +35,7 @@ async function createWechatQrCode(options, context) {
filter: { filter: {
application$system: { application$system: {
id: applicationId, id: applicationId,
} },
}, },
}, { }, {
dontCollect: true, dontCollect: true,
@ -49,24 +49,24 @@ async function createWechatQrCode(options, context) {
const id = (0, uuid_1.generateNewId)(); const id = (0, uuid_1.generateNewId)();
if (qrCodeType) { if (qrCodeType) {
switch (qrCodeType) { switch (qrCodeType) {
case 'wechatPublic': case 'wechatPublic': {
{ const self = applications.find((ele) => ele.type === 'wechatPublic');
const self = applications.find((ele) => ele.type === 'wechatPublic'); if (!(self &&
if (!(self && self.type === 'wechatPublic' && self.type === 'wechatPublic' &&
self.config.isService)) { self.config.isService)) {
throw new Error('无法生成公众号二维码,服务号未正确配置'); throw new Error('无法生成公众号二维码,服务号未正确配置');
}
appId = self.id;
appType = 'wechatPublic';
break;
} }
appId = self.id;
appType = 'wechatPublic';
break;
}
case 'wechatMpDomainUrl': { case 'wechatMpDomainUrl': {
const self = applications.find((ele) => ele.type === 'wechatMp'); const self = applications.find((ele) => ele.type === 'wechatMp');
if (!(self.type === 'wechatMp' && if (!(self.type === 'wechatMp' &&
self.config.qrCodePrefix)) { self.config.qrCodePrefix)) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${(0, uuid_2.shrinkUuidTo32Bytes)(id)}`;
appId = self.id; appId = self.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
@ -82,12 +82,14 @@ async function createWechatQrCode(options, context) {
} }
case 'wechatPublicForMp': { case 'wechatPublicForMp': {
const self = applications.find((ele) => ele.type === 'wechatPublic'); const self = applications.find((ele) => ele.type === 'wechatPublic');
if (!(self && self.type === 'wechatPublic' && if (!(self &&
self.type === 'wechatPublic' &&
self.config.isService)) { self.config.isService)) {
throw new Error('无法生成公众号-小程序二维码,服务号未正确配置'); throw new Error('无法生成公众号-小程序二维码,服务号未正确配置');
} }
const selfMp = applications.find((ele) => ele.type === 'wechatMp'); const selfMp = applications.find((ele) => ele.type === 'wechatMp');
if (!(selfMp && selfMp.config.appId && if (!(selfMp &&
selfMp.config.appId &&
selfMp.config.appSecret)) { selfMp.config.appSecret)) {
throw new Error('无法生成公众号-小程序二维码,小程序未正确配置'); throw new Error('无法生成公众号-小程序二维码,小程序未正确配置');
} }
@ -118,7 +120,7 @@ async function createWechatQrCode(options, context) {
appId = self.id; appId = self.id;
if (self.config.qrCodePrefix) { if (self.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${(0, uuid_2.shrinkUuidTo32Bytes)(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -138,7 +140,7 @@ async function createWechatQrCode(options, context) {
appId = mpApp.id; appId = mpApp.id;
if (mpApp.config.qrCodePrefix) { if (mpApp.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${mpApp.config.qrCodePrefix}/${id}`; url = `${mpApp.config.qrCodePrefix}/${(0, uuid_2.shrinkUuidTo32Bytes)(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -173,40 +175,6 @@ async function createWechatQrCode(options, context) {
switch (type) { switch (type) {
case 'wechatMpWxaCode': { case 'wechatMpWxaCode': {
(0, assert_1.assert)(applicationType === 'wechatMp' && config.type === 'wechatMp'); (0, assert_1.assert)(applicationType === 'wechatMp' && config.type === 'wechatMp');
const config2 = config;
const { appId, appSecret } = config2;
// if (process.env.OAK_PLATFORM === 'web') {
// Object.assign(data, {
// buffer: 'develop环境下无法真实获取二维码数据',
// });
// }
// else {
// // 小程序码去实时获取(暂时不考虑缓存)
// const wechatInstance = WechatSDK.getInstance(
// appId,
// 'wechatMp',
// appSecret
// ) as WechatMpInstance;
// const envVersionVersionDict = {
// development: 'develop',
// staging: 'trial',
// production: 'release',
// };
// const buffer = await wechatInstance.getMpUnlimitWxaCode({
// scene: shrinkUuidTo32Bytes(id),
// envVersion:
// envVersionVersionDict[
// process.env
// .NODE_ENV as keyof typeof envVersionVersionDict
// ] as 'release',
// page: 'pages/wechatQrCode/scan/index', // todo这里用其它的页面微信服务器拒绝因为没发布。应该是 pages/wechatQrCode/scan/index
// });
// // 把arrayBuffer转成字符串返回
// const str = String.fromCharCode(...new Uint8Array(buffer));
// Object.assign(data, {
// buffer: str,
// });
// }
break; break;
} }
case 'wechatPublicForMp': case 'wechatPublicForMp':
@ -229,8 +197,8 @@ async function createWechatQrCode(options, context) {
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(data, { Object.assign(data, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;
@ -246,9 +214,7 @@ async function createWechatQrCode(options, context) {
id: (0, uuid_1.generateNewId)(), id: (0, uuid_1.generateNewId)(),
action: 'create', action: 'create',
data, data,
}, { }, {});
dontCollect: true,
});
} }
exports.createWechatQrCode = createWechatQrCode; exports.createWechatQrCode = createWechatQrCode;
async function getMpUnlimitWxaCode(wechatQrCodeId, context) { async function getMpUnlimitWxaCode(wechatQrCodeId, context) {

View File

@ -1,2 +1,2 @@
declare const checkers: (import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[]; declare const checkers: (import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "mobile", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "token", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "message", import("..").RuntimeCxt> | import("oak-domain").Checker<import("../oak-app-domain").EntityDict, "parasite", import("..").RuntimeCxt>)[];
export default checkers; export default checkers;

View File

@ -362,8 +362,8 @@ const i18ns = [
"chooseExpiresAt": "请选择有效时长", "chooseExpiresAt": "请选择有效时长",
"expiresHelp": "支持分钟、小时选择", "expiresHelp": "支持分钟、小时选择",
"helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则", "helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则",
"helpMutiple": "是否允许多个用户来认领", "helpMultiple": "是否允许多个用户来认领",
"shareCode": "请将二维码发给待分享权限的用户使用微信扫描", "shareCode": "请将二维码发给待认领权限的用户,让他们使用微信扫描。",
"unit": { "unit": {
"hour": "小时", "hour": "小时",
"minute": "分钟" "minute": "分钟"

View File

@ -34,7 +34,7 @@ const entityDesc = {
}, },
qrCodeType: { qrCodeType: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
@ -42,12 +42,12 @@ const entityDesc = {
rule: { rule: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
ruleOnRow: { ruleOnRow: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
}, },
}, },
@ -61,7 +61,7 @@ const entityDesc = {
}, },
{ {
name: 'expiresAt', name: 'expiresAt',
} },
], ],
}, },
], ],

View File

@ -23,12 +23,12 @@ const entityDesc = {
v: { v: {
type: { type: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
} },
} },
}, },
}, },
indexes: [ indexes: [
@ -43,7 +43,7 @@ const entityDesc = {
}, },
{ {
name: 'tag', name: 'tag',
} },
], ],
}, },
{ {
@ -65,5 +65,5 @@ const entityDesc = {
}, },
], ],
}, },
] ],
}; };

View File

@ -1,2 +1,2 @@
declare const _default: (import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[]; declare const _default: (import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "extraFile", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatQrCode", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "account", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "application", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "address", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "user", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "userEntityGrant", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "message", import("..").BRC> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "notification", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatLogin", import("..").RuntimeCxt> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "articleMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "article", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "parasite", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "sessionMessage", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMenu", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatPublicTag", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>> | import("oak-domain").Trigger<import("../oak-app-domain").EntityDict, "wechatMpJump", import("..").BackendRuntimeContext<import("../oak-app-domain").EntityDict>>)[];
export default _default; export default _default;

View File

@ -5,7 +5,7 @@ const assert_1 = require("oak-domain/lib/utils/assert");
const oak_external_sdk_1 = require("oak-external-sdk"); const oak_external_sdk_1 = require("oak-external-sdk");
const triggers = [ const triggers = [
{ {
name: '当生成wechatQrCode时,调用外部接口完善数据', name: '当生成wechatQrCode时, 调用外部接口完善数据',
entity: 'wechatQrCode', entity: 'wechatQrCode',
action: 'create', action: 'create',
when: 'before', when: 'before',
@ -64,7 +64,7 @@ const triggers = [
self.config.qrCodePrefix)) { self.config.qrCodePrefix)) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config.qrCodePrefix}/${(0, uuid_1.shrinkUuidTo32Bytes)(id)}`;
appId = self.id; appId = self.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
@ -116,7 +116,8 @@ const triggers = [
appId = self.id; appId = self.id;
if (self.config.qrCodePrefix) { if (self.config.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${self.config.qrCodePrefix}/${id}`; url = `${self.config
.qrCodePrefix}/${(0, uuid_1.shrinkUuidTo32Bytes)(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -134,9 +135,10 @@ const triggers = [
const mpApp = applications.find((ele) => ele.type === 'wechatMp'); const mpApp = applications.find((ele) => ele.type === 'wechatMp');
if (mpApp) { if (mpApp) {
appId = mpApp.id; appId = mpApp.id;
if (mpApp.config.qrCodePrefix) { const mpConfig = mpApp.config;
if (mpConfig?.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${mpApp.config.qrCodePrefix}/${id}`; url = `${mpConfig.qrCodePrefix}/${(0, uuid_1.shrinkUuidTo32Bytes)(id)}`;
} }
else { else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
@ -192,8 +194,8 @@ const triggers = [
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(updateData, { Object.assign(updateData, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;

View File

@ -21,15 +21,29 @@ import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
* @param context * @param context
* @returns * @returns
*/ */
export async function createWechatQrCode<ED extends EntityDict, T extends keyof ED, Cxt extends BackendRuntimeContext<ED>>(options: { export async function createWechatQrCode<
entity: T; ED extends EntityDict,
entityId: string; T extends keyof ED,
tag?: string; Cxt extends BackendRuntimeContext<ED>
permanent?: boolean; >(
type?: QrCodeType; options: {
props: WechatQrCodeProps; entity: T;
}, context: Cxt) { entityId: string;
const { entity, entityId, tag, permanent = false, props, type: qrCodeType } = options; tag?: string;
permanent?: boolean;
type?: QrCodeType;
props: WechatQrCodeProps;
},
context: Cxt
) {
const {
entity,
entityId,
tag,
permanent = false,
props,
type: qrCodeType,
} = options;
const applicationId = context.getApplicationId(); const applicationId = context.getApplicationId();
assert(applicationId); assert(applicationId);
const [system] = await context.select( const [system] = await context.select(
@ -51,7 +65,7 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
filter: { filter: {
application$system: { application$system: {
id: applicationId, id: applicationId,
} },
}, },
}, },
{ {
@ -59,37 +73,40 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
} }
); );
let appId: string = '', appType: QrCodeType | undefined = undefined; let appId: string = '',
appType: QrCodeType | undefined = undefined;
let url: string | undefined = undefined; let url: string | undefined = undefined;
const { application$system: applications, config: sysConfig } = system as { const { application$system: applications, config: sysConfig } = system as {
application$system: Application[]; application$system: Application[];
config: SysConfig; config: SysConfig;
}; };
if (!applications || applications?.length === 0) { if (!applications || applications?.length === 0) {
throw new Error( throw new Error('无法生成二维码找不到此system下的应用信息');
'无法生成二维码找不到此system下的应用信息'
);
} }
const id = generateNewId(); const id = generateNewId();
if (qrCodeType) { if (qrCodeType) {
switch (qrCodeType) { switch (qrCodeType) {
case 'wechatPublic': case 'wechatPublic': {
{ const self = applications.find(
const self = applications.find((ele) => ele.type === 'wechatPublic'); (ele) => ele.type === 'wechatPublic'
if ( );
!( if (
self && self!.type === 'wechatPublic' && !(
(self!.config as WechatPublicConfig).isService self &&
) self!.type === 'wechatPublic' &&
) { (self!.config as WechatPublicConfig).isService
throw new Error('无法生成公众号二维码,服务号未正确配置'); )
} ) {
appId = self.id; throw new Error('无法生成公众号二维码,服务号未正确配置');
appType = 'wechatPublic';
break;
} }
appId = self.id;
appType = 'wechatPublic';
break;
}
case 'wechatMpDomainUrl': { case 'wechatMpDomainUrl': {
const self = applications.find((ele) => ele.type === 'wechatMp'); const self = applications.find(
(ele) => ele.type === 'wechatMp'
);
if ( if (
!( !(
self!.type === 'wechatMp' && self!.type === 'wechatMp' &&
@ -98,13 +115,15 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
) { ) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${(self!.config as WechatMpConfig).qrCodePrefix}/${id}`; url = `${(self!.config as WechatMpConfig).qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
appId = self!.id; appId = self!.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
} }
case 'wechatMpWxaCode': { case 'wechatMpWxaCode': {
const self = applications.find((ele) => ele.type === 'wechatMp'); const self = applications.find(
(ele) => ele.type === 'wechatMp'
);
if (self!.type !== 'wechatMp') { if (self!.type !== 'wechatMp') {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
@ -113,19 +132,27 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
break; break;
} }
case 'wechatPublicForMp': { case 'wechatPublicForMp': {
const self = applications.find((ele) => ele.type === 'wechatPublic'); const self = applications.find(
(ele) => ele.type === 'wechatPublic'
);
if ( if (
!( !(
self && self!.type === 'wechatPublic' && self &&
self!.type === 'wechatPublic' &&
(self!.config as WechatPublicConfig).isService (self!.config as WechatPublicConfig).isService
) )
) { ) {
throw new Error('无法生成公众号-小程序二维码,服务号未正确配置'); throw new Error(
'无法生成公众号-小程序二维码,服务号未正确配置'
);
} }
const selfMp = applications.find((ele) => ele.type === 'wechatMp'); const selfMp = applications.find(
(ele) => ele.type === 'wechatMp'
);
if ( if (
!( !(
selfMp && (selfMp!.config as WechatMpConfig).appId && selfMp &&
(selfMp!.config as WechatMpConfig).appId &&
(selfMp!.config as WechatMpConfig).appSecret (selfMp!.config as WechatMpConfig).appSecret
) )
) { ) {
@ -159,8 +186,9 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
appId = self.id; appId = self.id;
if ((self!.config as WechatMpConfig).qrCodePrefix) { if ((self!.config as WechatMpConfig).qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${(self!.config as WechatMpConfig).qrCodePrefix url = `${
}/${id}`; (self!.config as WechatMpConfig).qrCodePrefix
}/${shrinkUuidTo32Bytes(id)}`;
} else { } else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
} }
@ -182,8 +210,9 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
appId = mpApp.id; appId = mpApp.id;
if ((mpApp!.config as WechatMpConfig).qrCodePrefix) { if ((mpApp!.config as WechatMpConfig).qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${(mpApp!.config as WechatMpConfig).qrCodePrefix url = `${
}/${id}`; (mpApp!.config as WechatMpConfig).qrCodePrefix
}/${shrinkUuidTo32Bytes(id)}`;
} else { } else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
} }
@ -194,7 +223,9 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
} }
if (!appId || !appType) { if (!appId || !appType) {
throw new Error('无法生成二维码找不到此system下的服务号或者小程序信息'); throw new Error(
'无法生成二维码找不到此system下的服务号或者小程序信息'
);
} }
const data: CreateWechatQrcodeData = { const data: CreateWechatQrcodeData = {
@ -208,7 +239,7 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
permanent, permanent,
url, url,
expired: false, expired: false,
expiresAt: Date.now() + 2592000 * 1000, // wecharQrCode里的过期时间都放到最大由上层关联对象来主动过期by Xc, 20230131) expiresAt: Date.now() + 2592000 * 1000, // wecharQrCode里的过期时间都放到最大由上层关联对象来主动过期by Xc, 20230131)
props, props,
}; };
@ -228,58 +259,20 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
assert( assert(
applicationType === 'wechatMp' && config!.type === 'wechatMp' applicationType === 'wechatMp' && config!.type === 'wechatMp'
); );
const config2 = config as WechatMpConfig;
const { appId, appSecret } = config2;
// if (process.env.OAK_PLATFORM === 'web') {
// Object.assign(data, {
// buffer: 'develop环境下无法真实获取二维码数据',
// });
// }
// else {
// // 小程序码去实时获取(暂时不考虑缓存)
// const wechatInstance = WechatSDK.getInstance(
// appId,
// 'wechatMp',
// appSecret
// ) as WechatMpInstance;
// const envVersionVersionDict = {
// development: 'develop',
// staging: 'trial',
// production: 'release',
// };
// const buffer = await wechatInstance.getMpUnlimitWxaCode({
// scene: shrinkUuidTo32Bytes(id),
// envVersion:
// envVersionVersionDict[
// process.env
// .NODE_ENV as keyof typeof envVersionVersionDict
// ] as 'release',
// page: 'pages/wechatQrCode/scan/index', // todo这里用其它的页面微信服务器拒绝因为没发布。应该是 pages/wechatQrCode/scan/index
// });
// // 把arrayBuffer转成字符串返回
// const str = String.fromCharCode(...new Uint8Array(buffer));
// Object.assign(data, {
// buffer: str,
// });
// }
break; break;
} }
case 'wechatPublicForMp': case 'wechatPublicForMp':
case 'wechatPublic': { case 'wechatPublic': {
assert( assert(
applicationType === 'wechatPublic' && applicationType === 'wechatPublic' &&
config!.type === 'wechatPublic' config!.type === 'wechatPublic'
); );
if (process.env.OAK_PLATFORM === 'web') { if (process.env.OAK_PLATFORM === 'web') {
Object.assign(data, { Object.assign(data, {
ticket: 'develop环境下无法真实获取二维码数据', ticket: 'develop环境下无法真实获取二维码数据',
url: `http://localhost:3000/wechatQrCode/scan?scene=${shrinkUuidTo32Bytes(id)}`, url: `http://localhost:3000/wechatQrCode/scan?scene=${shrinkUuidTo32Bytes(id)}`,
}); });
} } else {
else {
const config2 = config as WechatPublicConfig; const config2 = config as WechatPublicConfig;
const { appId, appSecret } = config2; const { appId, appSecret } = config2;
const wechatInstance = WechatSDK.getInstance( const wechatInstance = WechatSDK.getInstance(
@ -294,8 +287,8 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(data, { Object.assign(data, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;
@ -315,9 +308,7 @@ export async function createWechatQrCode<ED extends EntityDict, T extends keyof
action: 'create', action: 'create',
data, data,
}, },
{ {}
dontCollect: true,
}
); );
} }

View File

@ -133,7 +133,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'application
), ),
}); });
} }
if (id && oakFullpath) { if (id) {
return ( return (
<Tabs <Tabs
tabPosition="left" tabPosition="left"
@ -141,7 +141,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'application
setTabKey(key); setTabKey(key);
}} }}
items={items} items={items}
style={{ height: 520 }} style={{ minHeight: 520 }}
/> />
); );
} }

View File

@ -1,132 +0,0 @@
.oak-pageHeader {
display: flex;
flex-direction: column;
&-header {
margin: 0;
font-size: 0;
height: auto;
line-height: inherit;
min-height: inherit;
position: relative;
padding: 10px 20px;
color: #000;
background: var(--oak-bg-color-container);
&-backIcon {
width: 16px;
height: 16px;
font-size: 16px;
}
&-title {
display: inline-block;
vertical-align: middle;
font-size: 16px;
font-weight: 700;
margin-right: 20px;
max-width: 70%;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
height: 30px;
line-height: 30px;
}
&-subTitle {
font-size: 12px;
display: inline-block;
vertical-align: middle;
margin-right: 20px;
}
&-back {
margin-right: 24px;
}
&-col {
display: flex;
align-items: center;
}
}
&-content {
display: flex;
flex-direction: column;
&-margin {
margin: 10px;
}
}
}
@media (max-width:576px) {
.oak-pageHeader {
display: flex;
flex-direction: column;
&-header {
margin: 0;
font-size: 0;
height: auto;
line-height: inherit;
min-height: inherit;
position: relative;
padding: 10px 20px;
color: #000;
background: var(--oak-bg-color-container);
&-backIcon {
width: 16px;
height: 16px;
font-size: 16px;
}
&-title {
display: inline-block;
vertical-align: middle;
font-size: 16px;
font-weight: 700;
margin-right: 20px;
max-width: 70%;
overflow: hidden;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
height: 30px;
line-height: 30px;
}
&-subTitle {
font-size: 12px;
display: inline-block;
vertical-align: middle;
margin-right: 20px;
}
&-back {
margin-right: 24px;
}
&-col {
display: flex;
align-items: center;
}
}
&-content {
display: flex;
flex-direction: column;
&-margin {
margin: 5px;
}
}
}
}

View File

@ -1,35 +0,0 @@
import { EntityDict } from '../../../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base';
export default OakComponent({
isList: false,
methods: {
goBack(delta?: number) {
this.navigateBack(delta);
},
},
}) as <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(
props: ReactComponentProps<
ED2,
T2,
false,
{
style?: React.CSSProperties;
className?: string;
title?: React.ReactNode;
showBack?: boolean;
onBack?: () => void;
backIcon?: React.ReactNode;
delta?: number; //有返回按钮时,返回第几层
extra?: React.ReactNode;
subTitle?: React.ReactNode;
contentMargin?: boolean; // 设置内容是否有边距 默认true 边距为20px
contentStyle?: React.CSSProperties;
contentClassName?: string;
tags?: React.ReactNode;
children?: React.ReactNode;
showHeader?: boolean; //默认true 显示头部
}
>
) => React.ReactElement;

View File

@ -1,126 +0,0 @@
import React, { memo } from 'react';
import { Row, Col, Button } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
import './index.less';
type PageHeaderProps = {
style?: React.CSSProperties;
className?: string;
title?: React.ReactNode;
showBack?: boolean;
onBack?: () => void;
backIcon?: React.ReactNode;
delta?: number; //有返回按钮时,返回第几层
extra?: React.ReactNode;
subTitle?: React.ReactNode;
contentMargin?: boolean; // 设置内容是否有边距 默认true 边距为20px
contentStyle?: React.CSSProperties;
contentClassName?: string;
tags?: React.ReactNode;
children?: React.ReactNode;
showHeader?: boolean; //默认true 显示头部
};
export default function Render(
props: WebComponentProps<
EntityDict,
keyof EntityDict,
false,
PageHeaderProps,
{
goBack: (delta?: number) => void;
}
>
) {
const {
style,
className,
children,
title,
subTitle,
extra,
showBack = false,
onBack,
backIcon,
delta,
contentMargin = true,
contentStyle,
contentClassName,
tags,
showHeader = true,
} = props.data;
const { t, goBack } = props.methods;
const prefixCls = 'oak';
return (
<div
style={style}
className={classNames(`${prefixCls}-pageHeader`, className)}
>
{showHeader && (title || showBack || subTitle || tags || extra) && (
<div className={`${prefixCls}-pageHeader-header`}>
<Row justify="center">
<Col
flex="auto"
className={`${prefixCls}-pageHeader-header-col`}
>
{showBack && (
<Button
type="text"
className={`${prefixCls}-pageHeader-header-back`}
onClick={() => {
if (typeof onBack === 'function') {
onBack();
return;
}
goBack(delta);
}}
>
{backIcon || (
<ArrowLeftOutlined
className={`${prefixCls}-pageHeader-header-backIcon`}
/>
)}
</Button>
)}
{title && (
<span
className={`${prefixCls}-pageHeader-header-title`}
>
{title}
</span>
)}
{subTitle && (
<span
className={`${prefixCls}-pageHeader-header-subTitle`}
>
{subTitle}
</span>
)}
{tags}
</Col>
<Col flex="auto">{extra}</Col>
</Row>
</div>
)}
<div
style={contentStyle}
className={classNames(
`${prefixCls}-pageHeader-content`,
contentClassName,
{
[`${prefixCls}-pageHeader-content-margin`]:
contentMargin,
}
)}
>
{children}
</div>
</div>
);
}

View File

@ -43,9 +43,10 @@ export default function WechatMp(props: {
layout="vertical" layout="vertical"
style={{ marginTop: 10 }} style={{ marginTop: 10 }}
> >
<Form.Item label="appId" <Form.Item
//name="appId" label="appId"
> //name="appId"
>
<> <>
<Input <Input
placeholder="请输入appId" placeholder="请输入appId"
@ -57,9 +58,10 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="appSecret" <Form.Item
//name="appSecret" label="appSecret"
> //name="appSecret"
>
<> <>
<Input <Input
placeholder="请输入appSecret" placeholder="请输入appSecret"
@ -71,9 +73,10 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="原始ID" <Form.Item
//name="originalId" label="原始ID"
> //name="originalId"
>
<> <>
<Input <Input
placeholder="请输入原始ID" placeholder="请输入原始ID"
@ -85,12 +88,14 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="qrCodePrefix" <Form.Item
// name="qrCodePrefix" label="普通链接二维码规则"
> tooltip="扫普通链接二维码打开小程序,如原有二维码链接为 http://www.qq.com/a/123456 其中12345为uuid则可配置规则 http://www.qq.com/a/ 。 请在输入框中填写 http://www.qq.com/a ,系统将在生成二维码时,在链接末尾加上'/'和uuid从而实现扫码打开小程序的规则。"
// name="qrCodePrefix"
>
<> <>
<Input <Input
placeholder="请输入qrCodePrefix" placeholder="请输入普通链接二维码规则"
type="text" type="text"
value={config?.qrCodePrefix} value={config?.qrCodePrefix}
onChange={(e) => onChange={(e) =>
@ -111,8 +116,9 @@ export default function WechatMp(props: {
layout="vertical" layout="vertical"
style={{ marginTop: 10 }} style={{ marginTop: 10 }}
> >
<Form.Item label="服务器地址(URL)" <Form.Item
//name="url" label="服务器地址(URL)"
//name="url"
> >
<> <>
<Input <Input
@ -125,9 +131,10 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="令牌(Token)" <Form.Item
//name="token" label="令牌(Token)"
> //name="token"
>
<> <>
<Input <Input
placeholder="请输入令牌(Token)" placeholder="请输入令牌(Token)"
@ -141,7 +148,7 @@ export default function WechatMp(props: {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="消息加解密密钥(EncodingAESKey)" label="消息加解密密钥(EncodingAESKey)"
// name="encodingAESKey" // name="encodingAESKey"
tooltip="消息加解密密钥将用于消息体加解密过程。具体功能请参见微信文档" tooltip="消息加解密密钥将用于消息体加解密过程。具体功能请参见微信文档"
> >
<> <>
@ -158,9 +165,10 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="消息加解密方式" <Form.Item
//name="mode" label="消息加解密方式"
> //name="mode"
>
<> <>
<Select <Select
placeholder="请选择消息加解密方式" placeholder="请选择消息加解密方式"
@ -185,9 +193,10 @@ export default function WechatMp(props: {
/> />
</> </>
</Form.Item> </Form.Item>
<Form.Item label="数据格式" <Form.Item
//name="dataFormat" label="数据格式"
> //name="dataFormat"
>
<> <>
<Select <Select
placeholder="请选择消息加解密方式" placeholder="请选择消息加解密方式"

View File

@ -15,7 +15,7 @@ export default function render(
{ {
searchValue: string; searchValue: string;
nameLabel: string; nameLabel: string;
list: RowWithActions<EntityDict, 'userEntityGrant'>[]; list: RowWithActions<EntityDict, 'parasite'>[];
}, },
{ {
cancel: () => void; cancel: () => void;
@ -31,10 +31,10 @@ export default function render(
nameLabel, nameLabel,
} = props.data; } = props.data;
const { pageSize, total, currentPage } = oakPagination || {}; const { pageSize, total, currentPage } = oakPagination || {};
const { t, setPageSize, setCurrentPage, updateItem, execute, getQrCode } = props.methods; const { t, setPageSize, setCurrentPage, updateItem, execute, getQrCode } =
props.methods;
const [qrCodeOpen, setQrCodeOpen] = useState(false); const [qrCodeOpen, setQrCodeOpen] = useState(false);
const [parasiteId, setParasiteId] = useState(''); const [parasiteId, setParasiteId] = useState('');
return ( return (
@ -55,7 +55,7 @@ export default function render(
dataIndex: ['user', 'nickname'], dataIndex: ['user', 'nickname'],
title: nameLabel || '名称', title: nameLabel || '名称',
render: (value, record, index) => { render: (value, record, index) => {
return value !== 'shadow_user' && value || '--'; return (value !== 'shadow_user' && value) || '--';
}, },
}, },
{ {

View File

@ -3,7 +3,7 @@
height: 100%; height: 100%;
.tabLabel { .tabLabel {
writing-mode: vertical-rl; // writing-mode: vertical-rl;
letter-spacing: .2rem; letter-spacing: .2rem;
} }
} }

View File

@ -4,7 +4,7 @@
<view class="ueg-container"> <view class="ueg-container">
<userEntityGrant-share oakId="{{userEntityGrantId}}" oakAutoUnmount="{{true}}" oakPath="$userEntityGrant/upsert-userEntityGrant/detail" /> <userEntityGrant-share oakId="{{userEntityGrantId}}" oakAutoUnmount="{{true}}" oakPath="$userEntityGrant/upsert-userEntityGrant/detail" />
<view class="share"> <view class="share">
<l-button size="long"type="success" open-type="share"> <l-button size="long" type="success" open-type="share">
分享 分享
</l-button> </l-button>
</view> </view>

View File

@ -5,8 +5,8 @@
"chooseExpiresAt": "请选择有效时长", "chooseExpiresAt": "请选择有效时长",
"expiresHelp": "支持分钟、小时选择", "expiresHelp": "支持分钟、小时选择",
"helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则", "helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则",
"helpMutiple": "是否允许多个用户来认领", "helpMultiple": "是否允许多个用户来认领",
"shareCode": "请将二维码发给待分享权限的用户使用微信扫描", "shareCode": "请将二维码发给待认领权限的用户,让他们使用微信扫描。",
"unit": { "unit": {
"hour": "小时", "hour": "小时",
"minute": "分钟" "minute": "分钟"

View File

@ -83,10 +83,7 @@ export default function render(
</> </>
) : ( ) : (
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 8 }}> <Form labelCol={{ span: 4 }} wrapperCol={{ span: 8 }}>
<Form.Item <Form.Item label={t('userEntityGrant:attr.relationIds')} required>
label={t('userEntityGrant:attr.relationIds')}
required
>
<Checkbox.Group <Checkbox.Group
value={relationIds || []} value={relationIds || []}
onChange={(val) => { onChange={(val) => {
@ -106,14 +103,18 @@ export default function render(
help={t('helpRule')} help={t('helpRule')}
> >
<Radio.Group <Radio.Group
value={rule as EntityDict['userEntityGrant']['OpSchema']['rule']} value={
onChange={({ target }) => update({ rule: target.value as EntityDict['userEntityGrant']['OpSchema']['rule']})} rule as EntityDict['userEntityGrant']['OpSchema']['rule']
options={rules.map( }
(ele) => ({ onChange={({ target }) =>
value: ele, update({
label: t(`userEntityGrant:v.rule.${ele}`) rule: target.value as EntityDict['userEntityGrant']['OpSchema']['rule'],
}) })
)} }
options={rules.map((ele) => ({
value: ele,
label: t(`userEntityGrant:v.rule.${ele}`),
}))}
/> />
</Form.Item> </Form.Item>
)} )}
@ -121,7 +122,7 @@ export default function render(
<Form.Item <Form.Item
label={t('multiple')} label={t('multiple')}
required required
help={t('helpMutiple')} help={t('helpMultiple')}
> >
<Switch <Switch
checked={multiple || false} checked={multiple || false}

View File

@ -128,7 +128,7 @@ export default function render(
<Form.Item <Form.Item
label={t('multiple')} label={t('multiple')}
required required
help={t('helpMutiple')} help={t('helpMultiple')}
> >
<Switch <Switch
checked={multiple || false} checked={multiple || false}

View File

@ -96,25 +96,9 @@ export default function Render(
key: 'item-1', key: 'item-1',
children: <div className={Style.container}></div>, children: <div className={Style.container}></div>,
}, },
{
label: '手机号',
key: 'item-2',
children: (
<ByMobile
allowUpdateName={allowUpdateName}
allowUpdateNickname={allowUpdateNickname}
passwordRequire={passwordRequire}
entity={entity}
entityId={entityId}
relations={relations}
oakPath="$userRelation-upsert-by-mobile"
oakAutoUnmount={true}
/>
),
},
{ {
label: '二维码', label: '二维码',
key: 'item-3', key: 'item-2',
children: ( children: (
<ByUserEntityGrant <ByUserEntityGrant
entity={entity} entity={entity}
@ -130,15 +114,31 @@ export default function Render(
/> />
), ),
}, },
{
label: '手机号',
key: 'item-3',
children: (
<ByMobile
allowUpdateName={allowUpdateName}
allowUpdateNickname={allowUpdateNickname}
passwordRequire={passwordRequire}
entity={entity}
entityId={entityId}
relations={relations}
oakPath="$userRelation-upsert-by-mobile"
oakAutoUnmount={true}
/>
),
},
]; ];
const items2: typeof items = []; const items2: typeof items = [];
if (grantByEmail) { if (grantByEmail) {
items2.push(items[0]); items2.push(items[0]);
} }
if (grantByMobile) { if (grantByUserEntityGrant) {
items2.push(items[1]); items2.push(items[1]);
} }
if (grantByUserEntityGrant) { if (grantByMobile) {
items2.push(items[2]); items2.push(items[2]);
} }
SubPart = <Tabs items={items2} />; SubPart = <Tabs items={items2} />;

View File

@ -94,22 +94,9 @@ export default function Render(
key: 'item-1', key: 'item-1',
children: <div className={Style.container}></div>, children: <div className={Style.container}></div>,
}, },
{
label: '手机号',
key: 'item-2',
children: (
<ByMobile
entity={entity}
entityId={entityId}
relations={relations}
oakPath="$userRelation-upsert-by-mobile"
oakAutoUnmount={true}
/>
),
},
{ {
label: '二维码', label: '二维码',
key: 'item-3', key: 'item-2',
children: ( children: (
<ByUserEntityGrant <ByUserEntityGrant
entity={entity} entity={entity}
@ -125,15 +112,28 @@ export default function Render(
/> />
), ),
}, },
{
label: '手机号',
key: 'item-3',
children: (
<ByMobile
entity={entity}
entityId={entityId}
relations={relations}
oakPath="$userRelation-upsert-by-mobile"
oakAutoUnmount={true}
/>
),
},
]; ];
const items2: typeof items = []; const items2: typeof items = [];
if (grantByEmail) { if (grantByEmail) {
items2.push(items[0]); items2.push(items[0]);
} }
if (grantByMobile) { if (grantByUserEntityGrant) {
items2.push(items[1]); items2.push(items[1]);
} }
if (grantByUserEntityGrant) { if (grantByMobile) {
items2.push(items[2]); items2.push(items[2]);
} }
SubPart = ( SubPart = (

View File

@ -17,6 +17,7 @@ export default OakComponent({
isList: true, isList: true,
properties: { properties: {
scene: '', scene: '',
q: '',
}, },
data: { data: {
loading: false, loading: false,
@ -37,8 +38,17 @@ export default OakComponent({
filters: [ filters: [
{ {
filter() { filter() {
const scene = decodeURIComponent(this.props.scene!); let uuid;
const uuid = scene && expandUuidTo36Bytes(scene!); if (this.props.scene) {
// 小程序码扫码
const scene = decodeURIComponent(this.props.scene!);
uuid = expandUuidTo36Bytes(scene!);
} else if (this.props.q) {
// 普通链接二维码扫码
const q = decodeURIComponent(this.props.q!);
uuid = expandUuidTo36Bytes(q!);
}
return { return {
id: uuid! || 'illegal', id: uuid! || 'illegal',
}; };

View File

@ -362,8 +362,8 @@ const i18ns: I18n[] = [
"chooseExpiresAt": "请选择有效时长", "chooseExpiresAt": "请选择有效时长",
"expiresHelp": "支持分钟、小时选择", "expiresHelp": "支持分钟、小时选择",
"helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则", "helpRule": "当一次分享多个权限时,可规定单个用户(对多个权限)的认领规则",
"helpMutiple": "是否允许多个用户来认领", "helpMultiple": "是否允许多个用户来认领",
"shareCode": "请将二维码发给待分享权限的用户使用微信扫描", "shareCode": "请将二维码发给待认领权限的用户,让他们使用微信扫描。",
"unit": { "unit": {
"hour": "小时", "hour": "小时",
"minute": "分钟" "minute": "分钟"

View File

@ -37,12 +37,17 @@ export interface Schema extends EntityShape {
type Action = 'claim' | 'disable'; type Action = 'claim' | 'disable';
const entityDesc: EntityDesc<Schema, Action, '', { const entityDesc: EntityDesc<
type: Schema['type']; Schema,
qrCodeType: QrCodeType; Action,
rule: Schema['rule']; '',
ruleOnRow: Schema['ruleOnRow']; {
}> = { type: Schema['type'];
qrCodeType: QrCodeType;
rule: Schema['rule'];
ruleOnRow: Schema['ruleOnRow'];
}
> = {
locales: { locales: {
zh_CN: { zh_CN: {
name: '用户授权', name: '用户授权',
@ -76,7 +81,7 @@ const entityDesc: EntityDesc<Schema, Action, '', {
}, },
qrCodeType: { qrCodeType: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
@ -84,12 +89,12 @@ const entityDesc: EntityDesc<Schema, Action, '', {
rule: { rule: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
ruleOnRow: { ruleOnRow: {
single: '单选', single: '单选',
all: '全选', all: '全选',
free: '自由选择' free: '自由选择',
}, },
}, },
}, },
@ -103,7 +108,7 @@ const entityDesc: EntityDesc<Schema, Action, '', {
}, },
{ {
name: 'expiresAt', name: 'expiresAt',
} },
], ],
}, },
], ],

View File

@ -28,9 +28,14 @@ export interface Schema extends EntityShape {
props: WechatQrCodeProps; props: WechatQrCodeProps;
} }
const entityDesc: EntityDesc<Schema, '', '', { const entityDesc: EntityDesc<
type: QrCodeType, Schema,
}> = { '',
'',
{
type: QrCodeType;
}
> = {
locales: { locales: {
zh_CN: { zh_CN: {
name: '微信识别码', name: '微信识别码',
@ -53,12 +58,12 @@ const entityDesc: EntityDesc<Schema, '', '', {
v: { v: {
type: { type: {
webForWechatPublic: '网站引流到公众号', webForWechatPublic: '网站引流到公众号',
wechatMpDomainUrl: '小程序url码', wechatMpDomainUrl: '小程序普通链接二维码',
wechatMpWxaCode: '小程序码', wechatMpWxaCode: '小程序码',
wechatPublic: '公众号关注码', wechatPublic: '公众号关注码',
wechatPublicForMp: '公众号回复小程序码', wechatPublicForMp: '公众号回复小程序码',
} },
} },
}, },
}, },
indexes: [ indexes: [
@ -73,7 +78,7 @@ const entityDesc: EntityDesc<Schema, '', '', {
}, },
{ {
name: 'tag', name: 'tag',
} },
], ],
}, },
{ {
@ -95,5 +100,5 @@ const entityDesc: EntityDesc<Schema, '', '', {
}, },
], ],
}, },
] ],
}; };

View File

@ -13,7 +13,7 @@ import { Config as SysConfig, QrCodeType } from '../types/Config';
const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
{ {
name: '当生成wechatQrCode时,调用外部接口完善数据', name: '当生成wechatQrCode时, 调用外部接口完善数据',
entity: 'wechatQrCode', entity: 'wechatQrCode',
action: 'create', action: 'create',
when: 'before', when: 'before',
@ -87,7 +87,7 @@ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
) { ) {
throw new Error('无法生成小程序地址码,未配置跳转前缀'); throw new Error('无法生成小程序地址码,未配置跳转前缀');
} }
url = `${(self!.config as WechatMpConfig).qrCodePrefix}/${id}`; url = `${(self!.config as WechatMpConfig).qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
appId = self!.id; appId = self!.id;
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
break; break;
@ -148,8 +148,10 @@ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
appId = self.id; appId = self.id;
if ((self!.config as WechatMpConfig).qrCodePrefix) { if ((self!.config as WechatMpConfig).qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${(self!.config as WechatMpConfig).qrCodePrefix url = `${
}/${id}`; (self!.config as WechatMpConfig)
.qrCodePrefix
}/${shrinkUuidTo32Bytes(id)}`;
} else { } else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
} }
@ -169,10 +171,10 @@ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
); );
if (mpApp) { if (mpApp) {
appId = mpApp.id; appId = mpApp.id;
if ((mpApp!.config as WechatMpConfig).qrCodePrefix) { const mpConfig = mpApp!.config as WechatMpConfig;
if (mpConfig?.qrCodePrefix) {
appType = 'wechatMpDomainUrl'; appType = 'wechatMpDomainUrl';
url = `${(mpApp!.config as WechatMpConfig).qrCodePrefix url = `${mpConfig.qrCodePrefix}/${shrinkUuidTo32Bytes(id)}`;
}/${id}`;
} else { } else {
appType = 'wechatMpWxaCode'; appType = 'wechatMpWxaCode';
} }
@ -198,11 +200,9 @@ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
} }
if (!wechatQrCode.type) { if (!wechatQrCode.type) {
Object.assign( Object.assign(updateData, {
updateData, {
type: appType, type: appType,
} });
)
} }
// 直接创建 // 直接创建
@ -248,8 +248,8 @@ const triggers: Trigger<EntityDict, 'wechatQrCode', RuntimeCxt>[] = [
expireSeconds: 2592000, expireSeconds: 2592000,
}); });
Object.assign(updateData, { Object.assign(updateData, {
ticket: result?.ticket, ticket: result.ticket,
url: result?.url, url: result.url,
}); });
} }
break; break;