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

This commit is contained in:
Xu Chang 2024-02-07 14:33:12 +08:00
commit 9ac44edb0d
40 changed files with 709 additions and 453 deletions

View File

@ -531,6 +531,7 @@ export async function loginByMobile(params, context) {
}
async function setUserInfoFromWechat(user, userInfo, context) {
const application = context.getApplication();
const applicationId = context.getApplicationId();
const config = application?.system?.config || application?.system?.platform?.config;
const { nickname, gender, avatar } = userInfo;
const { nickname: originalNickname, gender: originalGender, extraFile$entity, } = user;
@ -564,6 +565,7 @@ async function setUserInfoFromWechat(user, userInfo, context) {
type: 'image',
filename: '',
bucket: '',
applicationId: applicationId,
}),
},
];
@ -1328,7 +1330,6 @@ function checkTokenEnvConsistency(env1, env2) {
return false;
}
}
return true;
}
export async function refreshToken(params, context) {
const { env, tokenValue } = params;

View File

@ -2,39 +2,56 @@ const SEND_KEY = 'captcha:sendAt';
const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
export default OakComponent({
isList: false,
entity: 'user',
projection: {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
},
filter: {
ableState: 'enabled'
}
}
},
formData: function ({ data: user, features, props }) {
return {
user,
};
},
// entity: 'user',
// projection: {
// id: 1,
// name: 1,
// nickname: 1,
// mobile$user: {
// $entity: 'mobile',
// data: {
// id: 1,
// mobile: 1,
// },
// filter: {
// ableState: 'enabled'
// }
// }
// },
// formData: function ({ data: user, features, props }) {
// return {
// user,
// };
// },
data: {
channels: [],
},
properties: {
oakId: '',
},
lifetimes: {
async attached() {
const userId = this.props.oakId;
const { result } = await this.features.cache.exec('getChangePasswordChannels', {
userId,
});
this.setState({
channels: result
loading: true,
});
try {
const { result } = await this.features.cache.exec(
'getChangePasswordChannels',
{
userId: userId,
}
);
this.setState({
channels: result,
loading: false,
});
} catch {
this.setState({
loading: false,
channels: [],
});
}
},
},
methods: {

View File

@ -1,10 +1,18 @@
import React from 'react';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../oak-app-domain';
export default function Render(props: WebComponentProps<EntityDict, 'message', false, {
user: EntityDict['user']['Schema'];
channels: string[];
oakId: string;
}, {
goToMobile: () => void;
}>): React.JSX.Element;
export default function Render(
props: WebComponentProps<
EntityDict,
'user',
false,
{
loading: boolean;
channels: string[];
oakId: string;
},
{
goToMobile: () => void;
}
>
): React.JSX.Element;

View File

@ -4,18 +4,35 @@ import ByMobile from './byMobile';
import ByPassword from './byPassword';
export default function Render(props) {
const { data, methods } = props;
const { channels, user, oakFullpath, oakId } = data;
const { channels, oakFullpath, oakId, loading } = data;
const { goToMobile } = methods;
if (loading) {
return null;
}
const items = [
{
key: 'password',
label: '原密码验证',
children: <ByPassword oakId={oakId} oakPath={oakFullpath}/>,
children: (
<ByPassword
oakId={oakId}
oakPath={oakFullpath + '.user'}
oakAutoUnmount={true}
/>
),
},
{
key: 'mobile',
label: '手机号验证',
children: <ByMobile oakId={oakId} oakPath={oakFullpath}/>,
children: (
<ByMobile
oakId={oakId}
oakPath={oakFullpath + '.user'}
oakAutoUnmount={true}
/>
),
},
];
if (channels.length === 0) {

View File

@ -5,6 +5,7 @@ export default OakComponent({
id: 1,
userId: 1,
playerId: 1,
value: 1,
user: {
id: 1,
nickname: 1,
@ -64,14 +65,9 @@ export default OakComponent({
filters: [
{
filter() {
const tokenId = this.features.token.getTokenValue();
if (tokenId) {
return {
id: tokenId,
};
}
const value = this.features.token.getTokenValue();
return {
id: 'none',
value,
};
},
},

View File

@ -11,6 +11,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'mobile', fa
passwordRequire: boolean;
allowUpdateName?: boolean;
allowUpdateNickname?: boolean;
isNew: boolean;
}, {
onMobileChange: (value: string) => Promise<void>;
onConfirm: () => Promise<void>;

View File

@ -3,7 +3,7 @@ import { Form, Input, Button } from 'antd-mobile';
import Style from './web.module.less';
import OnUser from '../onUser/index';
export default function Render(props) {
const { mobileValue, mobileValueReady, relations, entity, entityId, userId, oakFullpath, oakExecutable, oakDirty, passwordRequire, allowUpdateName, allowUpdateNickname, } = props.data;
const { mobileValue, mobileValueReady, relations, entity, entityId, userId, oakFullpath, oakExecutable, oakDirty, passwordRequire, allowUpdateName, allowUpdateNickname,isNew } = props.data;
const { onConfirm, onMobileChange, onReset, t } = props.methods;
return (<Form footer={<div className={Style.btnContainer}>
<Button color="primary" style={{ flex: 2 }} onClick={() => {
@ -35,6 +35,6 @@ export default function Render(props) {
}} placeholder={t('inputMobile')} type="tel" clearable/>
</>
</Form.Item>
{mobileValueReady && (<OnUser oakAutoUnmount={true} oakPath={`${oakFullpath}.user`} entity={entity} entityId={entityId} relations={relations} passwordRequire={passwordRequire} allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname}/>)}
{mobileValueReady && (<OnUser oakAutoUnmount={true} oakPath={`${oakFullpath}.user`} entity={entity} entityId={entityId} relations={relations} passwordRequire={passwordRequire} allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname} isNew={isNew} />)}
</Form>);
}

View File

@ -29,7 +29,7 @@ export default function Render(props) {
}} placeholder="请输入手机号码" type="tel"/>
</Form.Item>
</Form>
{mobileValueReady && (<OnUser oakAutoUnmount={true} oakPath={`${oakFullpath}.user`} entity={entity} entityId={entityId} relations={relations} setPasswordConfirm={setPasswordConfirm} passwordRequire={passwordRequire} allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname}/>)}
{mobileValueReady && (<OnUser oakAutoUnmount={true} oakPath={`${oakFullpath}.user`} entity={entity} entityId={entityId} relations={relations} setPasswordConfirm={setPasswordConfirm} passwordRequire={passwordRequire} allowUpdateName={allowUpdateName} allowUpdateNickname={allowUpdateNickname} isNew={isNew} />)}
<Form colon labelCol={{ span: 4 }} wrapperCol={{ span: 8 }}>
<Form.Item wrapperCol={{ offset: 4 }}>
<Space>

View File

@ -63,7 +63,7 @@ export default OakComponent({
password,
name,
nickname,
isNew: $$createAt$$ === 1,
// isNew: $$createAt$$ === 1,
};
},
properties: {
@ -75,5 +75,6 @@ export default OakComponent({
passwordRequire: false,
allowUpdateName: false,
allowUpdateNickname: false,
isNew: false,
},
});

View File

@ -23,19 +23,23 @@ export default function Render(props) {
},
]}>
<>
<Input disabled={!isNew && !allowUpdateName} onChange={(value) => {
update({
name: value,
});
<Input disabled={!isNew && !allowUpdateName} onChange={(value) => {
if (isNew) {
update({
name: value,
});
}
}} value={name} placeholder={t('placeholder.name')}/>
</>
</Form.Item>
<Form.Item label={t('user:attr.nickname')} name="nickname">
<>
<Input disabled={!isNew && !allowUpdateNickname} value={nickname} onChange={(value) => {
update({
nickname: value,
});
<Input disabled={!isNew && !allowUpdateNickname} value={nickname} onChange={(value) => {
if (isNew) {
update({
nickname: value,
});
}
}} placeholder={t('placeholder.nickname')}/>
</>
</Form.Item>

View File

@ -17,8 +17,8 @@ export default OakComponent({
this.setState({
loading: true,
});
const { features, t } = this;
const token = features.token.getToken(true);
// const { features, t } = this;
const token = this.features.token.getToken(true);
const url = window.location.href;
const urlParse = new URL(url);
//格式 xx?code=xx&state=/xx/xx?d=xx
@ -27,7 +27,7 @@ export default OakComponent({
const wechatLoginId = urlParse?.searchParams?.get('wechatLoginId');
if (!code) {
this.setState({
error: t('missingCodeParameter'),
error: this.t('missingCodeParameter'),
loading: false,
});
return;
@ -42,7 +42,7 @@ export default OakComponent({
else {
try {
// web微信扫码跟公众号授权
await features.token.loginWechat(code, {
await this.features.token.loginWechat(code, {
wechatLoginId,
});
this.setState({
@ -52,7 +52,7 @@ export default OakComponent({
}
catch (err) {
this.setState({
error: t('weChatLoginFailed'),
error: this.t('weChatLoginFailed'),
loading: false,
});
throw err;

View File

@ -203,7 +203,7 @@ async function setUserSubscribed(openId, eventKey, context) {
nickname: 1,
},
expired: 1,
relationalEntity: 1,
relationEntity: 1,
},
filter: {
id: entityId,

View File

@ -130,7 +130,7 @@ export class Token extends Feature {
return this.tokenValue;
}
getToken(allowUnloggedIn) {
if (this.tokenValue === '') {
if (!allowUnloggedIn && this.tokenValue === '') {
throw new OakUserInfoLoadingException();
}
if (this.tokenValue) {

View File

@ -17,7 +17,7 @@ type ConfigOptions = {
jsApiList?: wx.jsApiList;
openTagList?: wx.openTagList;
};
type ParamOptions = wx.IcheckJsApi | wx.IaddCard | wx.IchooseCard | wx.IonMenuShareTimeline | wx.IonMenuShareAppMessage | wx.IonMenuShareQQ | wx.IonMenuShareWeibo | wx.IonMenuShareQZone | wx.IchooseImage | wx.IpreviewImage | wx.IuploadImage | wx.IdownloadImage | wx.IgetLocalImgData | wx.IplaypausestopVoice | wx.IupdownloadVoice | wx.IopenLocation | wx.IgetLocation | wx.IscanQRCode | wx.IopenProductSpecificView | wx.IchooseCard | wx.IopenCard | wx.IchooseWXPay;
type ParamOptions = wx.IcheckJsApi | wx.IaddCard | wx.IchooseCard | wx.IonMenuShareTimeline | wx.IonMenuShareAppMessage | wx.IonMenuShareQQ | wx.IonMenuShareWeibo | wx.IonMenuShareQZone | wx.IchooseImage | wx.IpreviewImage | wx.IgetLocalImgData | wx.IplaypausestopVoice | wx.IopenLocation | wx.IgetLocation | wx.IscanQRCode | wx.IopenProductSpecificView | wx.IchooseCard | wx.IopenCard | wx.IchooseWXPay;
export declare class WeiXinJsSdk<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>, FrontCxt extends FrontendRuntimeContext<ED, Cxt, AD>, AD extends AspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>> extends Feature {
private cache;
private storage;

View File

@ -14,11 +14,14 @@
"detail": "详情",
"editor": "编辑",
"newAdd": "新增",
"add": "添加"
"add": "添加",
"submit": "提交"
},
"operate": "操作",
"submit": "提交",
"reset": "重置",
"select": "查询",
"search": "搜索",
"expand": "展开",
"shrink": "收起",
"back": "返回",
@ -34,5 +37,6 @@
"true": "是",
"false": "否",
"open": "开",
"close": "关"
"close": "关",
"other": "其他"
}

View File

@ -1,5 +1,9 @@
import { OakMpHaveToSubscribeMessage } from './types/Exception';
import {
OakMpHaveToSubscribeMessage,
OakApplicationLoadingException,
} from './types/Exception';
import { createComponent as createBaseComponent } from 'oak-frontend-base/es/page.mp';
/**
* 这里的逻辑暴露出去是为了让general可以被其它库重载
* @param this
@ -63,98 +67,134 @@ export function createComponent(option, features) {
const { wechatMp, data, methods, lifetimes, userInsensitive, ...rest } = option;
const { relatedMessageTypes } = wechatMp || {};
const { ready, attached, show, hide, ...restLifeTimes } = lifetimes || {};
return createBaseComponent({
data: typeof data === 'function' ? function () {
return {
__userId: undefined,
...(data.call(this)),
};
} : {
__userId: undefined,
...data,
},
methods: {
async subscribeMpMessage(messageTypes, haveToAccept, tip) {
return await subscribeMpMessage.call(this, messageTypes, haveToAccept, tip);
return createBaseComponent(
{
data:
typeof data === 'function'
? function () {
return {
__userId: null,
...data.call(this),
};
}
: {
__userId: null,
...data,
},
methods: {
async subscribeMpMessage(messageTypes, haveToAccept, tip) {
return await subscribeMpMessage.call(
this,
messageTypes,
haveToAccept,
tip
);
},
getMessageTypeTemplate() {
if (relatedMessageTypes) {
try {
const applicationId =
this.features.application.getApplicationId();
const existedOnes = this.features.cache.get(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
if (existedOnes.length === 0) {
this.features.cache.refresh(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
}
} catch (err) {
if (err instanceof OakApplicationLoadingException) {
if (process.env.NODE_ENV === 'development') {
console.warn(
'当Application全局应用程序对象正在加载和配置时为了确保正确地获取模板消息类型的数据我们会在Application准备就绪之后重新执行getMessageTypeTemplate方法来安全地获取并应用所需模版'
);
}
} else {
throw err;
}
}
}
},
...methods,
},
...methods,
},
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
attached && attached.call(this);
},
ready() {
if (relatedMessageTypes) {
const applicationId = this.features.application.getApplicationId();
const existedOnes = this.features.cache.get('messageTypeTemplate', {
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
});
if (existedOnes.length === 0) {
this.features.cache.refresh('messageTypeTemplate', {
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
this.addFeatureSub('application', () =>
this.getMessageTypeTemplate()
);
attached && attached.call(this);
},
ready() {
this.getMessageTypeTemplate();
ready && ready.call(this);
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
}
}
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId,
});
}
}
ready && ready.call(this);
},
...restLifeTimes,
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
}
}
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId,
});
}
},
...restLifeTimes,
wechatMp,
...rest,
},
wechatMp,
...rest,
}, features);
features
);
}

View File

@ -40,6 +40,9 @@ const userProjection = {
user$ref: {
$entity: 'user',
data: {
id: 1,
userState: 1,
refId: 1,
mobile$user: {
$entity: 'mobile',
data: {

View File

@ -535,6 +535,7 @@ async function loginByMobile(params, context) {
exports.loginByMobile = loginByMobile;
async function setUserInfoFromWechat(user, userInfo, context) {
const application = context.getApplication();
const applicationId = context.getApplicationId();
const config = application?.system?.config || application?.system?.platform?.config;
const { nickname, gender, avatar } = userInfo;
const { nickname: originalNickname, gender: originalGender, extraFile$entity, } = user;
@ -568,6 +569,7 @@ async function setUserInfoFromWechat(user, userInfo, context) {
type: 'image',
filename: '',
bucket: '',
applicationId: applicationId,
}),
},
];

View File

@ -208,7 +208,7 @@ async function setUserSubscribed(openId, eventKey, context) {
nickname: 1,
},
expired: 1,
relationalEntity: 1,
relationEntity: 1,
},
filter: {
id: entityId,

View File

@ -133,7 +133,7 @@ class Token extends oak_frontend_base_1.Feature {
return this.tokenValue;
}
getToken(allowUnloggedIn) {
if (this.tokenValue === '') {
if (!allowUnloggedIn && this.tokenValue === '') {
throw new Exception_2.OakUserInfoLoadingException();
}
if (this.tokenValue) {

View File

@ -17,7 +17,7 @@ type ConfigOptions = {
jsApiList?: wx.jsApiList;
openTagList?: wx.openTagList;
};
type ParamOptions = wx.IcheckJsApi | wx.IaddCard | wx.IchooseCard | wx.IonMenuShareTimeline | wx.IonMenuShareAppMessage | wx.IonMenuShareQQ | wx.IonMenuShareWeibo | wx.IonMenuShareQZone | wx.IchooseImage | wx.IpreviewImage | wx.IuploadImage | wx.IdownloadImage | wx.IgetLocalImgData | wx.IplaypausestopVoice | wx.IupdownloadVoice | wx.IopenLocation | wx.IgetLocation | wx.IscanQRCode | wx.IopenProductSpecificView | wx.IchooseCard | wx.IopenCard | wx.IchooseWXPay;
type ParamOptions = wx.IcheckJsApi | wx.IaddCard | wx.IchooseCard | wx.IonMenuShareTimeline | wx.IonMenuShareAppMessage | wx.IonMenuShareQQ | wx.IonMenuShareWeibo | wx.IonMenuShareQZone | wx.IchooseImage | wx.IpreviewImage | wx.IgetLocalImgData | wx.IplaypausestopVoice | wx.IopenLocation | wx.IgetLocation | wx.IscanQRCode | wx.IopenProductSpecificView | wx.IchooseCard | wx.IopenCard | wx.IchooseWXPay;
export declare class WeiXinJsSdk<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>, FrontCxt extends FrontendRuntimeContext<ED, Cxt, AD>, AD extends AspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>> extends Feature {
private cache;
private storage;

View File

@ -14,11 +14,14 @@
"detail": "详情",
"editor": "编辑",
"newAdd": "新增",
"add": "添加"
"add": "添加",
"submit": "提交"
},
"operate": "操作",
"submit": "提交",
"reset": "重置",
"select": "查询",
"search": "搜索",
"expand": "展开",
"shrink": "收起",
"back": "返回",
@ -34,5 +37,6 @@
"true": "是",
"false": "否",
"open": "开",
"close": "关"
"close": "关",
"other": "其他"
}

View File

@ -67,99 +67,140 @@ function createComponent(option, features) {
const { wechatMp, data, methods, lifetimes, userInsensitive, ...rest } = option;
const { relatedMessageTypes } = wechatMp || {};
const { ready, attached, show, hide, ...restLifeTimes } = lifetimes || {};
return (0, page_mp_1.createComponent)({
data: typeof data === 'function' ? function () {
return {
__userId: undefined,
...(data.call(this)),
};
} : {
__userId: undefined,
...data,
},
methods: {
async subscribeMpMessage(messageTypes, haveToAccept, tip) {
return await subscribeMpMessage.call(this, messageTypes, haveToAccept, tip);
return (0, page_mp_1.createComponent)(
{
data:
typeof data === 'function'
? function () {
return {
__userId: null,
...data.call(this),
};
}
: {
__userId: null,
...data,
},
methods: {
async subscribeMpMessage(messageTypes, haveToAccept, tip) {
return await subscribeMpMessage.call(
this,
messageTypes,
haveToAccept,
tip
);
},
getMessageTypeTemplate() {
if (relatedMessageTypes) {
try {
const applicationId =
this.features.application.getApplicationId();
const existedOnes = this.features.cache.get(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
if (existedOnes.length === 0) {
this.features.cache.refresh(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
}
} catch (err) {
if (
err instanceof
Exception_1.OakApplicationLoadingException
) {
if (
process.env.NODE_ENV === 'development'
) {
console.warn(
'当Application全局应用程序对象正在加载和配置时为了确保正确地获取模板消息类型的数据我们会在Application准备就绪之后重新执行getMessageTypeTemplate方法来安全地获取并应用所需模版'
);
}
} else {
throw err;
}
}
}
},
...methods,
},
...methods,
},
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
attached && attached.call(this);
},
ready() {
if (relatedMessageTypes) {
const applicationId = this.features.application.getApplicationId();
const existedOnes = this.features.cache.get('messageTypeTemplate', {
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
});
if (existedOnes.length === 0) {
this.features.cache.refresh('messageTypeTemplate', {
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
this.addFeatureSub('application', () =>
this.getMessageTypeTemplate()
);
attached && attached.call(this);
},
ready() {
this.getMessageTypeTemplate()
ready && ready.call(this);
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
}
}
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId,
});
}
}
ready && ready.call(this);
},
...restLifeTimes,
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
}
}
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId,
});
}
},
...restLifeTimes,
wechatMp,
...rest,
},
wechatMp,
...rest,
}, features);
features
);
}
exports.createComponent = createComponent;

View File

@ -43,6 +43,9 @@ const userProjection = {
user$ref: {
$entity: 'user',
data: {
id: 1,
userState: 1,
refId: 1,
mobile$user: {
$entity: 'mobile',
data: {

View File

@ -742,6 +742,7 @@ async function setUserInfoFromWechat<
context: Cxt
) {
const application = context.getApplication();
const applicationId = context.getApplicationId();
const config =
application?.system?.config || application?.system?.platform?.config;
const { nickname, gender, avatar } = userInfo;
@ -782,6 +783,7 @@ async function setUserInfoFromWechat<
type: 'image',
filename: '',
bucket: '',
applicationId: applicationId!,
}),
},
];
@ -1899,7 +1901,7 @@ export async function refreshToken<
) {
const { env, tokenValue } = params;
const fn = context.openRootMode();
let [ token ] = await context.select('token', {
let [token] = await context.select('token', {
data: Object.assign({
env: 1,
...tokenProjection,
@ -1936,7 +1938,7 @@ export async function refreshToken<
filter: {
id: token.id,
}
}, { });
}, {});
fn();
return newValue;
}

View File

@ -5,48 +5,64 @@ const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
export default OakComponent({
isList: false,
entity: 'user',
projection: {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
},
filter: {
ableState: 'enabled'
}
}
},
formData: function ({ data: user, features, props }) {
return {
user,
};
},
// entity: 'user',
// projection: {
// id: 1,
// name: 1,
// nickname: 1,
// mobile$user: {
// $entity: 'mobile',
// data: {
// id: 1,
// mobile: 1,
// },
// filter: {
// ableState: 'enabled'
// }
// }
// },
// formData: function ({ data: user, features, props }) {
// return {
// user,
// };
// },
data: {
channels: [] as string[],
loading: false,
},
properties: {
oakId: '',
},
lifetimes: {
async attached() {
const userId = this.props.oakId as string;
const { result } = await this.features.cache.exec('getChangePasswordChannels', {
userId,
});
const userId = this.props.oakId;
this.setState({
channels: result
loading: true,
});
try {
const { result } = await this.features.cache.exec(
'getChangePasswordChannels',
{
userId: userId!,
}
);
this.setState({
channels: result,
loading: false,
});
} catch {
this.setState({
loading: false,
channels: [],
});
}
},
},
methods: {
goToMobile() {
this.navigateTo(
{
url: '/mobile/me',
}
)
this.navigateTo({
url: '/mobile/me',
});
},
},
});

View File

@ -9,12 +9,12 @@ import ByPassword from './byPassword';
export default function Render(
props: WebComponentProps<
EntityDict,
'message',
'user',
false,
{
user: EntityDict['user']['Schema'];
channels: string[];
oakId: string;
loading: boolean;
},
{
goToMobile: () => void;
@ -22,18 +22,36 @@ export default function Render(
>
) {
const { data, methods } = props;
const { channels, user, oakFullpath, oakId } = data;
const { channels, oakFullpath, oakId, loading } = data;
const { goToMobile } = methods;
if (loading) {
return null
}
const items = [
{
key: 'password',
label: '原密码验证',
children: <ByPassword oakId={oakId} oakPath={oakFullpath} />,
children: (
<ByPassword
oakId={oakId}
oakPath={oakFullpath + '.user'}
oakAutoUnmount={true}
/>
),
},
{
key: 'mobile',
label: '手机号验证',
children: <ByMobile oakId={oakId} oakPath={oakFullpath} />,
children: (
<ByMobile
oakId={oakId}
oakPath={oakFullpath + '.user'}
oakAutoUnmount={true}
/>
),
},
];
if (channels.length === 0) {

View File

@ -6,6 +6,7 @@ export default OakComponent({
id: 1,
userId: 1,
playerId: 1,
value: 1,
user: {
id: 1,
nickname: 1,
@ -65,18 +66,25 @@ export default OakComponent({
filters: [
{
filter() {
const tokenId = this.features.token.getTokenValue();
if (tokenId) {
return {
id: tokenId,
};
}
const value = this.features.token.getTokenValue();
// if (tokenId) {
// return {
// id: tokenId,
// };
// }
// return {
// id: 'none',
// };
return {
id: 'none',
value,
};
},
},
],
features: [{
feature: 'token',
behavior: 'refresh',
}],
formData: ({ data, features }) => {
const [token] = data || [];
const user = token?.user;

View File

@ -91,6 +91,7 @@ export default function Render(
passwordRequire={passwordRequire}
allowUpdateName={allowUpdateName}
allowUpdateNickname={allowUpdateNickname}
isNew={isNew}
/>
)}
<Form colon labelCol={{ span: 4 }} wrapperCol={{ span: 8 }}>

View File

@ -20,6 +20,7 @@ export default function Render(
passwordRequire: boolean;
allowUpdateName?: boolean;
allowUpdateNickname?: boolean;
isNew: boolean;
},
{
onMobileChange: (value: string) => Promise<void>;
@ -41,6 +42,7 @@ export default function Render(
passwordRequire,
allowUpdateName,
allowUpdateNickname,
isNew,
} = props.data;
const { onConfirm, onMobileChange, onReset, t } = props.methods;
return (
@ -104,6 +106,7 @@ export default function Render(
passwordRequire={passwordRequire}
allowUpdateName={allowUpdateName}
allowUpdateNickname={allowUpdateNickname}
isNew={isNew}
/>
)}
</Form>

View File

@ -101,32 +101,32 @@ export default OakComponent({
rule,
ruleOnRow,
} = this.props;
if (this.isCreation()) {
this.update({
entity,
entityId,
relationEntity: entity,
relationEntityFilter: {
id: entityId,
},
type: type || 'grant',
multiple,
rule: rule || 'single',
ruleOnRow: ruleOnRow || 'single',
granterId: userId,
redirectTo:
redirectToAfterConfirm as EntityDict['userEntityGrant']['Schema']['redirectTo'],
qrCodeType: qrCodeType as QrCodeType,
claimUrl,
});
// if (this.isCreation()) {
this.update({
entity,
entityId,
relationEntity: entity,
relationEntityFilter: {
id: entityId,
},
type: type || 'grant',
multiple,
rule: rule || 'single',
ruleOnRow: ruleOnRow || 'single',
granterId: userId,
redirectTo:
redirectToAfterConfirm as EntityDict['userEntityGrant']['Schema']['redirectTo'],
qrCodeType: qrCodeType as QrCodeType,
claimUrl,
});
this.setState({
userEntityGrantId: '',
});
if (process.env.OAK_PLATFORM === 'wechatMp') {
wx.hideShareMenu();
}
this.setState({
userEntityGrantId: '',
});
if (process.env.OAK_PLATFORM === 'wechatMp') {
wx.hideShareMenu();
}
// }
},
setRelation(value: any) {
this.update({

View File

@ -68,7 +68,7 @@ export default OakComponent({
password,
name,
nickname,
isNew: $$createAt$$ === 1,
// isNew: $$createAt$$ === 1,
};
},
properties: {
@ -76,9 +76,10 @@ export default OakComponent({
entityId: '',
relations: [] as EntityDict['relation']['OpSchema'][],
mobile: '',
setPasswordConfirm: (value: boolean) => {},
setPasswordConfirm: (value: boolean) => { },
passwordRequire: false,
allowUpdateName: false,
allowUpdateNickname: false,
isNew: false,
},
});

View File

@ -96,9 +96,11 @@ export default function Render(
disabled={!isNew && !allowUpdateName}
onChange={(e) => {
const strValue = e.target.value;
update({
name: strValue,
});
if (isNew) {
update({
name: strValue,
});
}
}}
value={name}
placeholder={t('placeholder.name')}
@ -112,9 +114,11 @@ export default function Render(
value={nickname}
onChange={(e) => {
const strValue = e.target.value;
update({
nickname: strValue,
});
if (isNew) {
update({
nickname: strValue,
});
}
}}
placeholder={t('placeholder.nickname')}
/>

View File

@ -18,8 +18,7 @@ export default OakComponent({
this.setState({
loading: true,
});
const { features, t } = this;
const token = features.token.getToken(true);
const token = this.features.token.getToken(true);
const url = window.location.href;
const urlParse = new URL(url);
//格式 xx?code=xx&state=/xx/xx?d=xx
@ -28,7 +27,7 @@ export default OakComponent({
const wechatLoginId = urlParse?.searchParams?.get('wechatLoginId') as string;
if (!code) {
this.setState({
error: t('missingCodeParameter'),
error: this.t('missingCodeParameter'),
loading: false,
});
return;
@ -45,7 +44,7 @@ export default OakComponent({
} else {
try {
// web微信扫码跟公众号授权
await features.token.loginWechat(code, {
await this.features.token.loginWechat(code, {
wechatLoginId,
});
this.setState({
@ -54,7 +53,7 @@ export default OakComponent({
this.go(state);
} catch (err) {
this.setState({
error: t('weChatLoginFailed'),
error: this.t('weChatLoginFailed'),
loading: false,
});
throw err;

View File

@ -280,7 +280,7 @@ async function setUserSubscribed(
nickname: 1,
},
expired: 1,
relationalEntity: 1,
relationEntity: 1,
},
filter: {
id: entityId,
@ -518,17 +518,17 @@ async function setClickEventKey(openId: string, eventKey: string, context: BRC)
filter:
indexOfDollarSign !== -1
? {
applicationId,
wechatPublicTag: {
wechatId: Number(resultString),
},
}
applicationId,
wechatPublicTag: {
wechatId: Number(resultString),
},
}
: {
applicationId,
wechatPublicTagId: {
$exists: false,
},
},
applicationId,
wechatPublicTagId: {
$exists: false,
},
},
},
{ dontCollect: true }
);
@ -714,9 +714,9 @@ async function onWeChatPublicEvent(data: WechatPublicEventData, context: BRC) {
break;
}
}
if (process.env.NODE_ENV === 'development') {
console.log(evt);
}
if (process.env.NODE_ENV === 'development') {
console.log(evt);
}
try {
await createSession(
{
@ -923,7 +923,7 @@ const endpoints: Record<string, Endpoint<EntityDict, BRC>> = {
const applicationId = searchParams.get('applicationId');
const mediaId = searchParams.get('mediaId');
const isPermanent = searchParams.get('isPermanent');
const base64 = await getMaterial(
{
applicationId: applicationId!,

View File

@ -188,7 +188,7 @@ export class Token<
}
getToken(allowUnloggedIn?: boolean) {
if (this.tokenValue === '') {
if (!allowUnloggedIn && this.tokenValue === '') {
throw new OakUserInfoLoadingException();
}
if (this.tokenValue) {

View File

@ -40,11 +40,8 @@ type ParamOptions =
| wx.IonMenuShareQZone
| wx.IchooseImage
| wx.IpreviewImage
| wx.IuploadImage
| wx.IdownloadImage
| wx.IgetLocalImgData
| wx.IplaypausestopVoice
| wx.IupdownloadVoice
| wx.IopenLocation
| wx.IgetLocation
| wx.IscanQRCode
@ -112,12 +109,17 @@ export class WeiXinJsSdk<
async init(options?: {
jsApiList?: wx.jsApiList;
openTagList?: wx.openTagList;
debug?: boolean;
}) {
if (!isWeiXin) {
console.warn('只能在微信客户端初始化JSSDK');
return;
}
const { jsApiList, openTagList } = options || {};
const {
jsApiList,
openTagList,
debug = process.env.NODE_ENV === 'development',
} = options || {};
let url = window.location.href;
//在ios上 实际真正有效的的签名URL是【第一次进入应用时的URL】
@ -153,7 +155,7 @@ export class WeiXinJsSdk<
}
return this.getConfig({
debug: process.env.NODE_ENV === 'development',
debug: debug,
appId: result.appId,
timestamp: result.timestamp,
nonceStr: result.noncestr,

View File

@ -14,11 +14,14 @@
"detail": "详情",
"editor": "编辑",
"newAdd": "新增",
"add": "添加"
"add": "添加",
"submit": "提交"
},
"operate": "操作",
"submit": "提交",
"reset": "重置",
"select": "查询",
"search": "搜索",
"expand": "展开",
"shrink": "收起",
"back": "返回",
@ -34,5 +37,6 @@
"true": "是",
"false": "否",
"open": "开",
"close": "关"
"close": "关",
"other": "其他"
}

View File

@ -5,7 +5,7 @@ import { BasicFeatures } from 'oak-frontend-base';
import { CommonAspectDict } from 'oak-common-aspect';
import { BackendRuntimeContext } from './context/BackendRuntimeContext';
import { FrontendRuntimeContext } from './context/FrontendRuntimeContext';
import { OakMpHaveToSubscribeMessage } from './types/Exception';
import { OakMpHaveToSubscribeMessage, OakApplicationLoadingException } from './types/Exception';
import { GAD, GFD, OakComponentOption } from './types/Page';
import { createComponent as createBaseComponent } from 'oak-frontend-base/es/page.mp';
@ -128,111 +128,164 @@ export function createComponent<
const { relatedMessageTypes } = wechatMp || {};
const { ready, attached, show, hide, ...restLifeTimes } = lifetimes || {};
return createBaseComponent<IsList, ED, T, Cxt, FrontCxt, AD, FD, FormedData, TData & {
__userId: string | undefined;
}, TProperty, TMethod & {
subscribeMpMessage: (messageTypes: string[], haveToAccept?: boolean, tip?: string) => Promise<boolean>;
}>({
data: typeof data === 'function' ? function() {
return {
__userId: undefined,
...(data.call(this)),
} as TData & {
__userId: string | undefined;
}
} : {
__userId: undefined,
...data,
} as TData & {
__userId: string | undefined;
return createBaseComponent<
IsList,
ED,
T,
Cxt,
FrontCxt,
AD,
FD,
FormedData,
TData & {
__userId: string | undefined | null;
},
methods: {
async subscribeMpMessage(messageTypes: string[], haveToAccept?: boolean, tip?: string) {
return await subscribeMpMessage.call(this as any, messageTypes, haveToAccept, tip);
},
...(methods as TMethod),
},
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
attached && attached.call(this);
},
ready() {
if (relatedMessageTypes) {
const applicationId = this.features.application.getApplicationId();
const existedOnes = this.features.cache.get(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
TProperty,
TMethod & {
subscribeMpMessage: (
messageTypes: string[],
haveToAccept?: boolean,
tip?: string
) => Promise<boolean>;
}
>(
{
data:
typeof data === 'function'
? function () {
return {
__userId: null,
...data.call(this),
} as TData & {
__userId: string | undefined | null;
};
}
: ({
__userId: null,
...data,
} as TData & {
__userId: string | undefined | null;
}),
methods: {
async subscribeMpMessage(
messageTypes: string[],
haveToAccept?: boolean,
tip?: string
) {
return await subscribeMpMessage.call(
this as any,
messageTypes,
haveToAccept,
tip
);
if (existedOnes.length === 0) {
this.features.cache.refresh('messageTypeTemplate', {
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
});
},
getMessageTypeTemplate() {
if (relatedMessageTypes) {
try {
const applicationId =
this.features.application.getApplicationId();
const existedOnes = this.features.cache.get(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
if (existedOnes.length === 0) {
this.features.cache.refresh(
'messageTypeTemplate',
{
data: {
id: 1,
templateId: 1,
template: {
id: 1,
applicationId: 1,
wechatId: 1,
},
type: 1,
},
filter: {
type: {
$in: relatedMessageTypes,
},
template: {
applicationId,
},
},
}
);
}
} catch (err) {
if (err instanceof OakApplicationLoadingException) {
if (process.env.NODE_ENV === 'development') {
console.warn(
'当Application全局应用程序对象正在加载和配置时为了确保正确地获取模板消息类型的数据我们会在Application准备就绪之后重新执行getMessageTypeTemplate方法来安全地获取并应用所需模版'
);
}
} else {
throw err;
}
}
}
}
ready && ready.call(this);
},
...(methods as TMethod),
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
lifetimes: {
attached() {
if (!userInsensitive) {
this.addFeatureSub('token', () => this.refresh());
}
}
this.addFeatureSub('application', () =>
this.getMessageTypeTemplate()
);
attached && attached.call(this);
},
ready() {
this.getMessageTypeTemplate();
ready && ready.call(this);
},
show() {
show && show.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
if (userId !== this.state.__userId) {
this.refresh();
}
}
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId as string | undefined,
} as any);
}
},
...restLifeTimes,
},
hide() {
hide && hide.call(this);
if (!userInsensitive) {
const userId = this.features.token.getUserId(true);
this.setState({
__userId: userId as string | undefined,
} as any);
}
},
...restLifeTimes,
wechatMp,
...rest,
},
wechatMp,
...rest,
}, features);
features
);
}

View File

@ -45,6 +45,9 @@ const userProjection: EntityDict['user']['Selection']['data'] = {
user$ref: {
$entity: 'user',
data: {
id: 1,
userState: 1,
refId: 1,
mobile$user: {
$entity: 'mobile',
data: {