增加 tsconfig.lib,json 及user、token、mobile移到components下
This commit is contained in:
parent
fa89f269ce
commit
83559d4b17
|
|
@ -13,7 +13,7 @@
|
|||
z-index: 999;
|
||||
|
||||
width: 750rpx;
|
||||
height: calc(106rpx + env(safe-area-inset-bottom));
|
||||
height: 106rpx;
|
||||
display: flex;
|
||||
background-color: white;
|
||||
background-size: 100% 100%;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
|
||||
onlyCaptcha: boolean;
|
||||
onlyPassword: boolean;
|
||||
eventLoggedIn: string;
|
||||
callback: (() => void) | undefined;
|
||||
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import { LOCAL_STORAGE_KEYS } from '../../../config/constants';
|
||||
const SEND_KEY = LOCAL_STORAGE_KEYS.captchaSendAt;
|
||||
const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
|
||||
export default OakComponent({
|
||||
isList: false,
|
||||
projection: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
},
|
||||
data: {
|
||||
mobile: '',
|
||||
captcha: '',
|
||||
counter: 0,
|
||||
refreshing: false,
|
||||
password: '',
|
||||
},
|
||||
properties: {
|
||||
onlyCaptcha: false,
|
||||
onlyPassword: false,
|
||||
eventLoggedIn: '',
|
||||
callback: undefined,
|
||||
},
|
||||
formData({ features }) {
|
||||
const lastSendAt = features.localStorage.load(SEND_KEY);
|
||||
const now = Date.now();
|
||||
let counter = 0;
|
||||
if (typeof lastSendAt === 'number') {
|
||||
counter = Math.max(SEND_CAPTCHA_LATENCY - Math.ceil((now - lastSendAt) / 1000), 0);
|
||||
if (counter > 0) {
|
||||
this.counterHandler = setTimeout(() => this.reRender(), 1000);
|
||||
}
|
||||
else if (this.counterHandler) {
|
||||
clearTimeout(this.counterHandler);
|
||||
this.counterHandler = undefined;
|
||||
}
|
||||
}
|
||||
return {
|
||||
counter,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setMobile(value) {
|
||||
this.setState({
|
||||
mobile: value,
|
||||
});
|
||||
},
|
||||
setCaptcha(value) {
|
||||
this.setState({
|
||||
captcha: value,
|
||||
});
|
||||
},
|
||||
async sendCaptcha() {
|
||||
const { mobile } = this.state;
|
||||
try {
|
||||
const result = await this.features.token.sendCaptcha(mobile, 'login');
|
||||
// 显示返回消息
|
||||
this.setMessage({
|
||||
type: 'success',
|
||||
content: result,
|
||||
});
|
||||
this.save(SEND_KEY, Date.now());
|
||||
this.reRender();
|
||||
}
|
||||
catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: err.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
async loginByMobile() {
|
||||
const { eventLoggedIn, callback } = this.props;
|
||||
const { mobile, password, captcha } = this.state;
|
||||
try {
|
||||
await this.features.token.loginByMobile(mobile, password, captcha);
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
else if (eventLoggedIn) {
|
||||
this.pubEvent(eventLoggedIn);
|
||||
}
|
||||
else {
|
||||
this.navigateBack();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: err.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
async onRefreshMobile(e) {
|
||||
this.setState({
|
||||
refreshing: true,
|
||||
});
|
||||
try {
|
||||
const { code, errMsg } = e.detail;
|
||||
if (errMsg !== 'getPhoneNumber:ok') {
|
||||
console.error(errMsg);
|
||||
this.setMessage({
|
||||
title: '获取手机号失败',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
else {
|
||||
await this.features.token.getWechatMpUserPhoneNumber(code);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'token', false, {
|
||||
counter: number;
|
||||
loginMode?: number;
|
||||
loginAgreed?: boolean;
|
||||
appId: string;
|
||||
onlyCaptcha?: boolean;
|
||||
onlyPassword?: boolean;
|
||||
loading: boolean;
|
||||
backUrl?: string;
|
||||
mobile: string;
|
||||
captcha: string;
|
||||
password: string;
|
||||
}, {
|
||||
setCaptcha: (mobile: string) => void;
|
||||
setMobile: (mobile: string) => void;
|
||||
sendCaptcha: () => Promise<void>;
|
||||
loginByMobile: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { isMobile, isCaptcha, } from 'oak-domain/lib/utils/validator';
|
||||
import { MobileOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
import Style from './mobile.module.less';
|
||||
export default function render(props) {
|
||||
const { mobile, captcha, password, counter } = props.data;
|
||||
const { t, setMobile, setCaptcha, sendCaptcha, loginByMobile } = props.methods;
|
||||
const validMobile = isMobile(mobile);
|
||||
const validCaptcha = isCaptcha(captcha);
|
||||
const allowSubmit = validMobile && validCaptcha;
|
||||
const LoginCaptcha = (_jsxs(Form, { colon: true, children: [_jsx(Form.Item, { name: "mobile", children: _jsx(Input, { allowClear: true, value: mobile, "data-attr": "mobile", type: "tel", maxLength: 11, prefix: _jsx(MobileOutlined, {}), placeholder: t('placeholder.Mobile'), size: "large", onChange: (e) => {
|
||||
setMobile(e.target.value);
|
||||
}, className: Style['loginbox-input'] }) }), _jsx(Form.Item, { name: "captcha", children: _jsx(Input, { allowClear: true, value: captcha, "data-attr": "captcha",
|
||||
// type="number"
|
||||
maxLength: 4, placeholder: t('placeholder.Captcha'), size: "large", onChange: (e) => {
|
||||
setCaptcha(e.target.value);
|
||||
}, className: Style['loginbox-input'], suffix: _jsx(Button, { type: "link", disabled: !validMobile || counter > 0, onClick: () => sendCaptcha(), children: counter > 0 ? `${counter}秒后可重发` : t('Send') }) }) }), _jsx(Form.Item, { children: _jsx(Button, { block: true, size: "large", type: "primary", htmlType: "submit", disabled: !allowSubmit, onClick: () => loginByMobile(), children: t('Login') }) })] }));
|
||||
return (_jsx("div", { className: Style['loginbox-main'], children: _jsxs("div", { className: Style['loginbox-wrap'], children: [_jsx("div", { className: Style['loginbox-hd'], children: "\u4E3A\u4E86\u66F4\u597D\u7684\u4F53\u9A8C\uFF0C\u8BF7\u7ED1\u5B9A\u624B\u673A\u53F7" }), _jsx("div", { className: Style['loginbox-bd'], children: _jsx("div", { className: Style['loginbox-mobile'], children: LoginCaptcha }) })] }) }));
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'token', false, {
|
||||
counter: number;
|
||||
loginMode?: number;
|
||||
loginAgreed?: boolean;
|
||||
appId: string;
|
||||
onlyCaptcha?: boolean;
|
||||
onlyPassword?: boolean;
|
||||
loading: boolean;
|
||||
backUrl?: string;
|
||||
mobile: string;
|
||||
captcha: string;
|
||||
}, {
|
||||
setCaptcha: (mobile: string) => void;
|
||||
setMobile: (mobile: string) => void;
|
||||
sendCaptcha: () => Promise<void>;
|
||||
loginByMobile: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { isMobile, isCaptcha, } from 'oak-domain/lib/utils/validator';
|
||||
import { MobileOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button } from 'antd';
|
||||
import Style from './web.module.less';
|
||||
export default function render(props) {
|
||||
const { mobile, captcha, counter } = props.data;
|
||||
const { t, setMobile, setCaptcha, sendCaptcha, loginByMobile } = props.methods;
|
||||
const validMobile = isMobile(mobile);
|
||||
const validCaptcha = isCaptcha(captcha);
|
||||
const allowSubmit = validMobile && validCaptcha;
|
||||
const LoginCaptcha = (_jsxs(Form, { colon: true, children: [_jsx(Form.Item, { name: "mobile", children: _jsx(Input, { allowClear: true, value: mobile, "data-attr": "mobile", type: "tel", maxLength: 11, prefix: _jsx(MobileOutlined, {}), placeholder: t('placeholder.Mobile'), size: "large", onChange: (e) => {
|
||||
setMobile(e.target.value);
|
||||
}, className: Style['loginbox-input'] }) }), _jsx(Form.Item, { name: "captcha", children: _jsx(Input, { allowClear: true, value: captcha, "data-attr": "captcha",
|
||||
// type="number"
|
||||
maxLength: 4, placeholder: t('placeholder.Captcha'), size: "large", onChange: (e) => {
|
||||
setCaptcha(e.target.value);
|
||||
}, className: Style['loginbox-input'], suffix: _jsx(Button, { type: "link", disabled: !validMobile || counter > 0, onClick: () => sendCaptcha(), children: counter > 0 ? `${counter}秒后可重发` : t('Send') }) }) }), _jsx(Form.Item, { children: _jsx(Button, { block: true, size: "large", type: "primary", htmlType: "submit", disabled: !allowSubmit, onClick: () => loginByMobile(), children: t('Login') }) })] }));
|
||||
return (_jsx("div", { className: Style['loginbox-main'], children: _jsxs("div", { className: Style['loginbox-wrap'], children: [_jsx("div", { className: Style['loginbox-hd'], children: "\u4E3A\u4E86\u66F4\u597D\u7684\u4F53\u9A8C\uFF0C\u8BF7\u7ED1\u5B9A\u624B\u673A\u53F7" }), _jsx("div", { className: Style['loginbox-bd'], children: _jsx("div", { className: Style['loginbox-mobile'], children: LoginCaptcha }) })] }) }));
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "mobile", true, {
|
||||
showBack: boolean;
|
||||
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
export default OakComponent({
|
||||
entity: 'mobile',
|
||||
isList: true,
|
||||
projection: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
ableState: 1,
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
filter() {
|
||||
// const token = this.features.token.getToken();
|
||||
const userId = this.features.token.getUserId();
|
||||
return {
|
||||
userId,
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
formData: ({ data: mobiles, features }) => {
|
||||
const token = features.token.getToken();
|
||||
const tokenMobileId = token.entity === 'mobile' && token.entityId;
|
||||
return {
|
||||
tokenMobileId,
|
||||
mobiles,
|
||||
allowRemove: mobiles.length > 1,
|
||||
};
|
||||
},
|
||||
data: {
|
||||
confirmDeleteModalVisible: false,
|
||||
refreshing: false,
|
||||
deleteIdx: undefined,
|
||||
},
|
||||
properties: {
|
||||
showBack: false,
|
||||
},
|
||||
methods: {
|
||||
async onRefreshMobile(e) {
|
||||
this.setState({
|
||||
refreshing: true,
|
||||
});
|
||||
try {
|
||||
const { code, errMsg } = e.detail;
|
||||
if (errMsg !== 'getPhoneNumber:ok') {
|
||||
console.error(errMsg);
|
||||
this.setMessage({
|
||||
title: '获取手机号失败',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
else {
|
||||
await this.features.token.getWechatMpUserPhoneNumber(code);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
},
|
||||
goAddMobile() {
|
||||
const eventLoggedIn = `mobile:me:login:${Date.now()}`;
|
||||
this.subEvent(eventLoggedIn, () => {
|
||||
this.navigateBack();
|
||||
});
|
||||
this.navigateTo({
|
||||
url: '/mobile/login',
|
||||
eventLoggedIn,
|
||||
});
|
||||
},
|
||||
async onRemoveConfirm() {
|
||||
const { mobileId } = this.state;
|
||||
this.removeItem(mobileId);
|
||||
await this.execute();
|
||||
this.setState({
|
||||
confirmDeleteModalVisible: false,
|
||||
mobileId: '',
|
||||
});
|
||||
},
|
||||
onRemoveModalOpen(e) {
|
||||
const mobileId = e.currentTarget.dataset.id;
|
||||
this.setState({
|
||||
confirmDeleteModalVisible: true,
|
||||
mobileId,
|
||||
});
|
||||
},
|
||||
onRemoveModalClose() {
|
||||
this.setState({
|
||||
confirmDeleteModalVisible: false,
|
||||
mobileId: '',
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'mobile', true, {
|
||||
mobiles?: EntityDict['mobile']['OpSchema'][];
|
||||
allowRemove: boolean;
|
||||
tokenMobileId?: string;
|
||||
}, {
|
||||
goAddMobile: () => void;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, Button, Dialog } from 'antd-mobile';
|
||||
import { MobileOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import Style from './mobile.module.less';
|
||||
export default function render(props) {
|
||||
const { mobiles, allowRemove, tokenMobileId } = props.data;
|
||||
const { goAddMobile, removeItem, recoverItem, execute } = props.methods;
|
||||
return (_jsxs("div", { className: Style.container, children: [mobiles && mobiles.length > 0 ? (_jsxs(_Fragment, { children: [_jsx(List, { className: Style.list, children: mobiles?.map((ele, index) => (_jsx(List.Item, { prefix: _jsx(MobileOutlined, {}), extra: allowRemove && tokenMobileId !== ele.id && (_jsx("div", { onClick: async () => {
|
||||
const result = await Dialog.confirm({
|
||||
content: '确认删除吗?删除后无法用此号码登录',
|
||||
});
|
||||
if (result) {
|
||||
removeItem(ele.id);
|
||||
try {
|
||||
await execute();
|
||||
}
|
||||
catch (err) {
|
||||
recoverItem(ele.id);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}, children: _jsx(DeleteOutlined, {}) })), children: ele.mobile }, index))) }), _jsx("div", { style: { flex: 1 } })] })) : (_jsx("div", { className: Style.noData, children: _jsx("span", { children: "\u5C1A\u672A\u7ED1\u5B9A\u624B\u673A\u53F7" }) })), _jsx(Button, { block: true, size: "large", color: "primary", onClick: () => goAddMobile(), children: "\u7ED1\u5B9A" })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'mobile', true, {
|
||||
mobiles?: EntityDict['mobile']['OpSchema'][];
|
||||
allowRemove: boolean;
|
||||
showBack: boolean;
|
||||
tokenMobileId?: string;
|
||||
}, {
|
||||
goAddMobile: () => void;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useState } from 'react';
|
||||
import { List, Button, Modal, Row, Col } from 'antd';
|
||||
import { MobileOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import MobileLogin from '../login';
|
||||
export default function render(props) {
|
||||
const { mobiles, allowRemove, tokenMobileId, showBack = false } = props.data;
|
||||
const { goAddMobile, removeItem, recoverItem, execute, subEvent } = props.methods;
|
||||
const [open, setOpen] = useState(false);
|
||||
const eventLoggedIn = `user:info:login:${Date.now()}`;
|
||||
return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "primary", onClick: () => {
|
||||
setOpen(true);
|
||||
}, style: { marginBottom: 16 }, children: "\u7ED1\u5B9A" }), _jsx(Row, { children: _jsx(Col, { xs: 24, sm: 12, children: _jsx(List, { bordered: true, children: mobiles?.map((ele, index) => (_jsx(List.Item, { extra: allowRemove &&
|
||||
tokenMobileId !== ele.id && (_jsx("div", { onClick: () => {
|
||||
const modal = Modal.confirm({
|
||||
title: `确认删除吗?删除后无法用此号码登录`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: async (e) => {
|
||||
removeItem(ele.id);
|
||||
try {
|
||||
await execute();
|
||||
}
|
||||
catch (err) {
|
||||
recoverItem(ele.id);
|
||||
throw err;
|
||||
}
|
||||
modal.destroy();
|
||||
},
|
||||
onCancel: (e) => {
|
||||
modal.destroy();
|
||||
},
|
||||
});
|
||||
}, children: _jsx(DeleteOutlined, {}) })), children: _jsx(List.Item.Meta, { avatar: _jsx(MobileOutlined, {}), title: ele.mobile }) }, index))) }) }) }), _jsx(Modal, { title: "\u7ED1\u5B9A\u624B\u673A\u53F7", open: open, destroyOnClose: true, footer: null, onCancel: () => {
|
||||
setOpen(false);
|
||||
}, children: _jsx("div", { style: { padding: 16 }, children: _jsx(MobileLogin, { callback: () => {
|
||||
setOpen(false);
|
||||
}, oakPath: "$mobile/me-mobile/login", oakAutoUnmount: true }) }) })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "token", true, WechatMiniprogram.Component.DataOption>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
export default OakComponent({
|
||||
entity: 'token',
|
||||
isList: true,
|
||||
projection: {
|
||||
id: 1,
|
||||
userId: 1,
|
||||
playerId: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
nickname: 1,
|
||||
name: 1,
|
||||
birth: 1,
|
||||
gender: 1,
|
||||
idState: 1,
|
||||
userState: 1,
|
||||
isRoot: 1,
|
||||
extraFile$entity: {
|
||||
$entity: 'extraFile',
|
||||
data: {
|
||||
id: 1,
|
||||
tag1: 1,
|
||||
origin: 1,
|
||||
bucket: 1,
|
||||
objectId: 1,
|
||||
filename: 1,
|
||||
extra1: 1,
|
||||
type: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
extension: 1,
|
||||
},
|
||||
filter: {
|
||||
tag1: 'avatar',
|
||||
},
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
},
|
||||
mobile$user: {
|
||||
$entity: 'mobile',
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
player: {
|
||||
id: 1,
|
||||
isRoot: 1,
|
||||
},
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
filter() {
|
||||
const tokenId = this.features.token.getTokenValue();
|
||||
if (tokenId) {
|
||||
return {
|
||||
id: tokenId,
|
||||
};
|
||||
}
|
||||
return {
|
||||
id: 'none',
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
formData: ({ data, features }) => {
|
||||
const [token] = data || [];
|
||||
const user = token?.user;
|
||||
const player = token?.player;
|
||||
const avatarFile = user?.extraFile$entity && user?.extraFile$entity[0];
|
||||
const avatar = features.extraFile.getUrl(avatarFile);
|
||||
const nickname = user && user.nickname;
|
||||
const mobileData = user && user.mobile$user && user.mobile$user[0];
|
||||
const { mobile } = mobileData || {};
|
||||
const mobileCount = user?.mobile$user?.length || 0;
|
||||
const isLoggedIn = !!token;
|
||||
const isPlayingAnother = token && token.userId !== token.playerId;
|
||||
const isRoot = !!player?.isRoot;
|
||||
const mobileText = mobileCount && mobileCount > 1
|
||||
? `${mobileCount}条手机号`
|
||||
: mobile || '未绑定';
|
||||
return {
|
||||
tokenId: token?.id,
|
||||
userId: user?.id,
|
||||
avatar,
|
||||
nickname,
|
||||
mobile,
|
||||
mobileCount,
|
||||
mobileText,
|
||||
isLoggedIn,
|
||||
isPlayingAnother,
|
||||
isRoot,
|
||||
};
|
||||
},
|
||||
data: {
|
||||
refreshing: false,
|
||||
},
|
||||
methods: {
|
||||
async doLogin() {
|
||||
this.setState({
|
||||
refreshing: true,
|
||||
});
|
||||
try {
|
||||
switch (process.env.OAK_PLATFORM) {
|
||||
case 'wechatMp': {
|
||||
await this.features.token.loginWechatMp();
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'web': {
|
||||
const eventLoggedIn = `token:me:login:${Date.now()}`;
|
||||
this.subEvent(eventLoggedIn, () => {
|
||||
this.navigateBack();
|
||||
});
|
||||
this.navigateTo({
|
||||
url: '/login',
|
||||
eventLoggedIn,
|
||||
}, undefined, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
},
|
||||
goMyMobile() {
|
||||
this.navigateTo({
|
||||
url: '/mobile/me',
|
||||
});
|
||||
},
|
||||
goUserManage() {
|
||||
this.navigateTo({
|
||||
url: '/user/manage',
|
||||
});
|
||||
},
|
||||
goSetting() {
|
||||
this.navigateTo({
|
||||
url: '/setting',
|
||||
});
|
||||
},
|
||||
goMyInfo() {
|
||||
if (!this.state.isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
this.navigateTo({
|
||||
url: '/user/info',
|
||||
oakId: this.state.userId,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'token', true, {
|
||||
avatar: string;
|
||||
nickname?: string;
|
||||
isLoggedIn?: boolean;
|
||||
mobile?: string;
|
||||
mobileCount?: number;
|
||||
refreshing?: boolean;
|
||||
isRoot: boolean;
|
||||
tokenId?: string;
|
||||
mobileText: string;
|
||||
}, {
|
||||
goMyInfo: () => Promise<void>;
|
||||
doLogin: () => Promise<void>;
|
||||
goMyMobile: () => Promise<void>;
|
||||
goUserManage: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, Button, Avatar } from 'antd-mobile';
|
||||
import { UserOutlined, MobileOutlined } from '@ant-design/icons';
|
||||
import Style from './mobile.module.less';
|
||||
export default function Render(props) {
|
||||
const { avatar, isLoggedIn, refreshing, mobileText, isRoot, oakExecuting, tokenId, nickname, oakDirty, } = props.data;
|
||||
const { doLogin, t, goMyMobile, goUserManage, goMyInfo } = props.methods;
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsxs("div", { className: Style.userInfo, children: [_jsx(Avatar, { className: Style.avatar, src: avatar }), _jsx("span", { className: Style.nickname, children: nickname || '未设置' }), isLoggedIn ? (_jsx(Button, { color: "primary", size: "small", disabled: refreshing, loading: refreshing, onClick: () => goMyInfo(), children: t('common::action.update') })) : (_jsx(Button, { size: "small", disabled: refreshing, loading: refreshing, onClick: () => doLogin(), children: t('login') }))] }), _jsxs(List, { className: Style.list, children: [_jsx(List.Item, { onClick: () => goMyMobile(), prefix: _jsx(MobileOutlined, {}), title: "\u624B\u673A\u53F7", extra: mobileText }), isRoot && (_jsx(List.Item, { onClick: () => goUserManage(), prefix: _jsx(UserOutlined, {}), title: "\u7528\u6237\u7BA1\u7406" }))] })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'token', true, {
|
||||
avatar?: string;
|
||||
nickname?: string;
|
||||
isLoggedIn?: boolean;
|
||||
mobile?: string;
|
||||
mobileCount?: number;
|
||||
refreshing?: boolean;
|
||||
isRoot: boolean;
|
||||
tokenId?: string;
|
||||
mobileText: string;
|
||||
}, {
|
||||
goMyInfo: () => Promise<void>;
|
||||
doLogin: () => Promise<void>;
|
||||
goMyMobile: () => Promise<void>;
|
||||
goUserManage: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, Button, Avatar } from 'antd';
|
||||
import { UserOutlined, MobileOutlined } from '@ant-design/icons';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { avatar, isLoggedIn, refreshing, mobileText, isRoot, oakExecuting, tokenId, nickname, oakDirty, } = props.data;
|
||||
const { doLogin, t, goMyMobile, goUserManage, goMyInfo } = props.methods;
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsxs("div", { className: Style.userInfo, children: [avatar ? (_jsx(Avatar, { className: Style.avatar, src: avatar })) : (_jsx(Avatar, { className: Style.avatar, icon: _jsx(UserOutlined, { className: Style.userIcon }) })), _jsx("span", { className: Style.nickname, children: nickname || '未设置' }), isLoggedIn ? (_jsx(Button, { type: "primary", size: "small", disabled: refreshing, loading: refreshing, onClick: () => goMyInfo(), children: t('common::action.update') })) : (_jsx(Button, { size: "small", disabled: refreshing, loading: refreshing, onClick: () => doLogin(), children: t('login') }))] }), _jsxs(List, { className: Style.list, split: true, children: [_jsx(List.Item, { onClick: () => goMyMobile(), children: _jsx(List.Item.Meta, { avatar: _jsx(MobileOutlined, {}), title: "\u624B\u673A\u53F7", description: mobileText }) }), isRoot && (_jsx(List.Item, { onClick: () => goUserManage(), children: _jsx(List.Item.Meta, { avatar: _jsx(UserOutlined, {}), title: "\u7528\u6237\u7BA1\u7406" }) }))] })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "user", false, WechatMiniprogram.Component.DataOption>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,348 @@
|
|||
import { OakUserInvisibleException } from 'oak-domain/lib/types';
|
||||
import dayjs from 'dayjs';
|
||||
import { LOCAL_STORAGE_KEYS } from '../../../config/constants';
|
||||
const SEND_KEY = LOCAL_STORAGE_KEYS.captchaSendAt;
|
||||
const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
|
||||
export default OakComponent({
|
||||
entity: 'user',
|
||||
projection: {
|
||||
id: 1,
|
||||
name: 1,
|
||||
nickname: 1,
|
||||
birth: 1,
|
||||
gender: 1,
|
||||
idState: 1,
|
||||
userState: 1,
|
||||
mobile$user: {
|
||||
$entity: 'mobile',
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
refId: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
user$ref: {
|
||||
$entity: 'user',
|
||||
data: {
|
||||
mobile$user: {
|
||||
$entity: 'mobile',
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
userId: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
refId: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
extraFile$entity: {
|
||||
$entity: 'extraFile',
|
||||
data: {
|
||||
id: 1,
|
||||
tag1: 1,
|
||||
origin: 1,
|
||||
bucket: 1,
|
||||
objectId: 1,
|
||||
filename: 1,
|
||||
extra1: 1,
|
||||
extension: 1,
|
||||
type: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
tag1: 'avatar',
|
||||
},
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
},
|
||||
wechatUser$user: {
|
||||
$entity: 'wechatUser',
|
||||
data: {
|
||||
id: 1,
|
||||
openId: 1,
|
||||
unionId: 1,
|
||||
userId: 1,
|
||||
origin: 1,
|
||||
nickname: 1,
|
||||
user: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
refId: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isList: false,
|
||||
formData({ data: user, features }) {
|
||||
const avatar = user?.extraFile$entity && user?.extraFile$entity[0];
|
||||
const avatarUrl = features.extraFile.getUrl(avatar);
|
||||
const { mobile } = (user?.mobile$user && user?.mobile$user[0]) ||
|
||||
(user?.user$ref &&
|
||||
user?.user$ref[0] &&
|
||||
user?.user$ref[0].mobile$user &&
|
||||
user?.user$ref[0].mobile$user[0]) ||
|
||||
{};
|
||||
const genderOption = user?.gender &&
|
||||
this.state.genderOptions.find((ele) => ele.value === user?.gender);
|
||||
const lastSendAt = features.localStorage.load(SEND_KEY);
|
||||
const now = Date.now();
|
||||
let counter = 0;
|
||||
if (typeof lastSendAt === 'number') {
|
||||
counter = Math.max(SEND_CAPTCHA_LATENCY - Math.ceil((now - lastSendAt) / 1000), 0);
|
||||
if (counter > 0) {
|
||||
this.counterHandler = setTimeout(() => this.reRender(), 1000);
|
||||
}
|
||||
else if (this.counterHandler) {
|
||||
clearTimeout(this.counterHandler);
|
||||
this.counterHandler = undefined;
|
||||
}
|
||||
}
|
||||
const isRoot = features.token.isReallyRoot();
|
||||
return {
|
||||
id: user?.id,
|
||||
name: user?.name,
|
||||
nickname: user?.nickname,
|
||||
gender: user?.gender,
|
||||
genderStr: genderOption?.label,
|
||||
birthText: user?.birth
|
||||
? dayjs(user.birth).format('YYYY-MM-DD')
|
||||
: '',
|
||||
birth: user?.birth,
|
||||
avatarUrl,
|
||||
mobile,
|
||||
userState: user?.userState,
|
||||
idState: user?.idState,
|
||||
wechatUser: user?.wechatUser$user?.[0],
|
||||
counter,
|
||||
isRoot,
|
||||
};
|
||||
},
|
||||
data: {
|
||||
stateColor: {
|
||||
shadow: 'primary',
|
||||
normal: 'success',
|
||||
disabled: 'danger',
|
||||
},
|
||||
idStateColor: {
|
||||
verifying: 'primary',
|
||||
verified: 'success',
|
||||
unverified: 'warning',
|
||||
},
|
||||
genderOptions: [
|
||||
{
|
||||
value: 'male',
|
||||
label: '男',
|
||||
},
|
||||
{
|
||||
value: 'female',
|
||||
label: '女',
|
||||
},
|
||||
],
|
||||
visible: false,
|
||||
attr: '',
|
||||
attrs: {
|
||||
nickname: '昵称',
|
||||
gender: '性别',
|
||||
birth: '出生日期',
|
||||
},
|
||||
birthEnd: '',
|
||||
refreshing: false,
|
||||
},
|
||||
lifetimes: {
|
||||
async ready() {
|
||||
const { oakId } = this.props;
|
||||
const userId = this.features.token.getUserId();
|
||||
if (userId !== oakId) {
|
||||
throw new OakUserInvisibleException();
|
||||
}
|
||||
this.setState({ birthEnd: dayjs().format('YYYY-MM-DD') });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async refreshWechatPublicUserInfo() {
|
||||
this.setState({
|
||||
refreshing: true,
|
||||
});
|
||||
try {
|
||||
await this.features.token.refreshWechatPublicUserInfo();
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
goUserManage() {
|
||||
this.navigateTo({
|
||||
url: '/user/manage',
|
||||
});
|
||||
},
|
||||
goAddMobile() {
|
||||
this.navigateTo({
|
||||
url: '/mobile/me',
|
||||
}, {
|
||||
showBack: true,
|
||||
});
|
||||
},
|
||||
goChangePassword() {
|
||||
this.navigateTo({
|
||||
url: '/changePassword',
|
||||
}, {
|
||||
showBack: true,
|
||||
});
|
||||
},
|
||||
setVisibleMp(e) {
|
||||
const { target: { dataset }, } = e;
|
||||
const { attr } = dataset;
|
||||
this.setVisible(true, attr);
|
||||
},
|
||||
genderChangeMp(e) {
|
||||
const { detail } = e;
|
||||
const { checked, currentKey } = detail;
|
||||
const { attr } = this.state;
|
||||
this.setCustomData(attr, currentKey);
|
||||
},
|
||||
birthChangeMp(e) {
|
||||
const { detail: { value }, } = e;
|
||||
const birth = dayjs(dayjs(value).format('YYYY-MM-DD')).valueOf();
|
||||
const { attr } = this.state;
|
||||
this.setState({
|
||||
birthText2: dayjs(value).format('YYYY-MM-DD'),
|
||||
});
|
||||
this.setCustomData(attr, birth);
|
||||
},
|
||||
setVisible(visible, attr) {
|
||||
this.setState({
|
||||
visible,
|
||||
attr: visible ? attr : '',
|
||||
[`new_${attr}`]: '',
|
||||
birthText2: '',
|
||||
});
|
||||
},
|
||||
setCustomData(attr, value) {
|
||||
this.setState({
|
||||
[`new_${attr}`]: value,
|
||||
});
|
||||
},
|
||||
setCustomDataMp(e) {
|
||||
const { detail, target: { dataset }, } = e;
|
||||
const { value } = detail;
|
||||
const { attr } = this.state;
|
||||
this.setCustomData(attr, value);
|
||||
},
|
||||
updateData(attr, value) {
|
||||
this.update({
|
||||
[attr]: this.state[`new_${attr}`],
|
||||
});
|
||||
},
|
||||
async onConfirmMp() {
|
||||
const { attr } = this.state;
|
||||
await this.onConfirm(attr);
|
||||
},
|
||||
async onConfirm(attr) {
|
||||
const { oakId } = this.props;
|
||||
if (!this.state[`new_${attr}`]) {
|
||||
this.setMessage({
|
||||
type: 'warning',
|
||||
content: `${this.state.attrs[attr]}不能为空`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.update({
|
||||
[attr]: this.state[`new_${attr}`],
|
||||
});
|
||||
await this.execute();
|
||||
this.setVisible(false, attr);
|
||||
},
|
||||
onPupopCloseMp() {
|
||||
const { attr } = this.state;
|
||||
this.clean();
|
||||
this.setVisible(false, attr);
|
||||
},
|
||||
async updateMyInfo() {
|
||||
if (!this.state.name) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: '请输入姓名',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this.state.nickname) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: '请输入昵称',
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!this.state.gender) {
|
||||
// this.setMessage({
|
||||
// type: 'error',
|
||||
// content: '请选择性别',
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// if (!this.state.birth) {
|
||||
// this.setMessage({
|
||||
// type: 'error',
|
||||
// content: '请选择生日',
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
await this.execute('update');
|
||||
},
|
||||
async sendCaptcha() {
|
||||
const { mobile } = this.state;
|
||||
try {
|
||||
const result = await this.features.token.sendCaptcha(mobile, 'login');
|
||||
// 显示返回消息
|
||||
this.setMessage({
|
||||
type: 'success',
|
||||
content: result,
|
||||
});
|
||||
this.save(SEND_KEY, Date.now());
|
||||
this.reRender();
|
||||
}
|
||||
catch (err) {
|
||||
this.setMessage({
|
||||
type: 'error',
|
||||
content: err.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
async unbindingWechat(captcha) {
|
||||
const { mobile, wechatUser } = this.state;
|
||||
try {
|
||||
await this.features.cache.exec('unbindingWechat', {
|
||||
wechatUserId: wechatUser.id,
|
||||
mobile,
|
||||
captcha,
|
||||
});
|
||||
this.refresh();
|
||||
this.setMessage({
|
||||
content: '解绑成功',
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
this.setMessage({
|
||||
content: '解绑失败',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"navigationBarTitleText": "个人设置",
|
||||
"enablePullDownRefresh": false,
|
||||
"usingComponents": {
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-avatar": "@oak-frontend-base/miniprogram_npm/lin-ui/avatar/index",
|
||||
"l-list": "@oak-frontend-base/miniprogram_npm/lin-ui/list/index",
|
||||
"l-icon": "@oak-frontend-base/miniprogram_npm/lin-ui/icon/index",
|
||||
"l-tag": "@oak-frontend-base/miniprogram_npm/lin-ui/tag/index",
|
||||
"l-popup": "@oak-frontend-base/miniprogram_npm/lin-ui/popup/index",
|
||||
"l-input": "@oak-frontend-base/miniprogram_npm/lin-ui/input/index",
|
||||
"l-radio-group": "@oak-frontend-base/miniprogram_npm/lin-ui/radio-group/index",
|
||||
"l-radio": "@oak-frontend-base/miniprogram_npm/lin-ui/radio/index",
|
||||
"l-form-item": "@oak-frontend-base/miniprogram_npm/lin-ui/form-item/index",
|
||||
"oak-extraFile-avatar": "../../../components/extraFile/avatar/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/** index.wxss **/
|
||||
@import "../../../config/styles/mp/index.less";
|
||||
@import "../../../config/styles/mp/mixins.less";
|
||||
|
||||
.page-body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background-color: @oak-bg-color-page;
|
||||
box-sizing: border-box;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
|
||||
.col {
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0rpx 10rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 16rpx;
|
||||
margin-left: 6rpx;
|
||||
margin-right: 26rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: @oak-text-color-primary;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: @oak-text-color-secondary;
|
||||
margin-right: 16rpx;
|
||||
|
||||
.primary {
|
||||
background-color: @oak-color-primary;
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: @oak-color-success;
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: @oak-color-error;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: @oak-color-warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.pupop-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
min-height: 300rpx;
|
||||
.safe-area-inset-bottom();
|
||||
|
||||
.pupop-header {
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
|
||||
|
||||
.close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.pupop-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<view class="page-body">
|
||||
<view class="col">
|
||||
<l-list title="头像">
|
||||
<view slot="right-section" class="avatar">
|
||||
<oak-extraFile-avatar oakAutoUnmount="{{true}}" oakPath="{{ oakFullpath ? oakFullpath + '.extraFile$entity' : undefined }}" entity="user" entityId="{{id}}" autoUpload="{{true}}"/>
|
||||
</view>
|
||||
</l-list>
|
||||
<l-list title="昵称" data-attr="nickname" bind:lintap="setVisibleMp">
|
||||
<view slot="right-section" class="value">{{nickname || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list title="姓名" data-attr="name" bind:lintap="setVisibleMp">
|
||||
<view slot="right-section" class="value">{{name || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list title="性别" data-attr="gender" bind:lintap="setVisibleMp">
|
||||
<view slot="right-section" class="value">{{genderStr || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list title="生日" data-attr="birth" bind:lintap="setVisibleMp">
|
||||
<view slot="right-section" class="value">{{birthText || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list title="手机号" bind:lintap="goAddMobile">
|
||||
<view slot="right-section" class="value">{{mobile || '未绑定'}}</view>
|
||||
</l-list>
|
||||
<!-- <l-list tag-position="right" is-link="{{false}}" title="用户状态">
|
||||
<view slot="right-section" class="value">
|
||||
<l-tag l-class="{{stateColor[userState]}}" size="mini" shape="circle">
|
||||
{{userState || '未设置'}}
|
||||
</l-tag>
|
||||
</view>
|
||||
</l-list> -->
|
||||
<l-list tag-position="right" is-link="{{false}}" title="认证状态">
|
||||
<view slot="right-section" class="value">
|
||||
<l-tag l-class="{{idStateColor[idState]}}" size="mini" shape="circle">
|
||||
{{t('user:v.idState.' + idState) || '未设置'}}
|
||||
</l-tag>
|
||||
</view>
|
||||
</l-list>
|
||||
</view>
|
||||
<view style="flex:1" />
|
||||
|
||||
<l-popup show="{{visible}}" content-align="bottom" locked="{{false}}">
|
||||
<view class='pupop-content'>
|
||||
<view class="pupop-header">
|
||||
<view class="close" bind:tap="onPupopCloseMp">
|
||||
<l-icon name="close" size="24"></l-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class='pupop-form'>
|
||||
<block wx:if="{{ attr === 'nickname' }}">
|
||||
<l-input label="昵称" value="{{nickname}}" placeholder="请输入昵称" bind:lininput="setCustomDataMp" />
|
||||
</block>
|
||||
<block wx:elif="{{ attr === 'name' }}">
|
||||
<l-input label="姓名" value="{{name}}" placeholder="请输入姓名" bind:lininput="setCustomDataMp" />
|
||||
</block>
|
||||
<block wx:elif="{{ attr === 'gender' }}">
|
||||
<l-form-item label="性别" label-width="100rpx">
|
||||
<l-radio-group current="{{gender}}" placement="row" length="2" bind:linchange="genderChangeMp">
|
||||
<l-radio l-class="l-radio" wx:for="{{genderOptions}}" wx:key="id" key="{{item.value}}" placement="left">
|
||||
{{item.label}}
|
||||
</l-radio>
|
||||
</l-radio-group>
|
||||
</l-form-item>
|
||||
|
||||
</block>
|
||||
|
||||
</block>
|
||||
<block wx:elif="{{ attr === 'birth' }}">
|
||||
<picker mode="date" end="{{birthEnd}}" value="{{birthText}}" bind:change="birthChangeMp">
|
||||
<l-input label="出生日期" value="{{birthText2 || birthText || '选择日期'}}" disabled="{{true}}" l-label-class="label">
|
||||
<l-icon slot="right" name="right" size="20" />
|
||||
</l-input>
|
||||
</picker>
|
||||
|
||||
</block>
|
||||
|
||||
|
||||
</view>
|
||||
<l-button size="long" bind:lintap="onConfirmMp">
|
||||
提交
|
||||
</l-button>
|
||||
</view>
|
||||
</l-popup>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"avatar": "头像",
|
||||
"mobile": "手机号",
|
||||
"password": "密码",
|
||||
"manage": "管理",
|
||||
"bind": "绑定",
|
||||
"syncWeChat": "同步微信信息",
|
||||
"send": "发送验证码",
|
||||
"cancel": "取消",
|
||||
"unbind": "解绑",
|
||||
"Mobile-Number-Verification": "手机号验证",
|
||||
"unbindingWechat": "确定解绑微信账号",
|
||||
"placeholder": {
|
||||
"Captcha": "输入4位短信验证码"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.container {
|
||||
background: var(--oak-bg-color-page);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.syncWeChat {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.avatar_container {
|
||||
height: 220px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.avatar {
|
||||
width: 84px;
|
||||
height: 84px;
|
||||
border-radius: 42px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
background: var(--oak-bg-color-container);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
type DataProps = {
|
||||
visible: boolean;
|
||||
nickname: string;
|
||||
name: string;
|
||||
birth: string;
|
||||
gender: string;
|
||||
mobile: string;
|
||||
avatarUrl: string;
|
||||
attr: string;
|
||||
genderOptions: Array<{
|
||||
label: string;
|
||||
value: string;
|
||||
}>;
|
||||
attrs: Record<string, string>;
|
||||
id: string;
|
||||
refreshing: boolean;
|
||||
isSupportSyncWeChat: boolean;
|
||||
appId: string;
|
||||
};
|
||||
type MethodsProps = {
|
||||
goAddMobile: () => void;
|
||||
goChangePassword: () => void;
|
||||
setAvatar: () => void;
|
||||
setVisible: (visible: boolean, attr: string) => void;
|
||||
setCustomData: (attr: string, value: string | number) => void;
|
||||
onConfirm: (attr: string) => Promise<void>;
|
||||
refreshWechatPublicUserInfo: () => void;
|
||||
};
|
||||
export default function render(props: WebComponentProps<EntityDict, 'user', false, DataProps, MethodsProps>): import("react/jsx-runtime").JSX.Element;
|
||||
export {};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, DatePicker, Popup, Form, Button, Input, Radio, Space, } from 'antd-mobile';
|
||||
import dayjs from 'dayjs';
|
||||
import OakAvatar from '../../../components/extraFile/avatar';
|
||||
import Style from './mobile.module.less';
|
||||
export default function render(props) {
|
||||
const { data, methods } = props;
|
||||
const { t, clean, setAvatar, setVisible, goAddMobile, refreshWechatPublicUserInfo, goChangePassword, } = methods;
|
||||
const { oakFullpath, visible, nickname, name, birth, gender, mobile, avatarUrl, attr, id, isSupportSyncWeChat, refreshing, } = data;
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsxs(List, { className: Style.list, children: [_jsx(List.Item, { extra: _jsx("div", { style: { marginTop: 5, marginBottom: 5 }, children: _jsx(OakAvatar, { oakAutoUnmount: true, oakPath: oakFullpath
|
||||
? oakFullpath + '.extraFile$entity'
|
||||
: undefined, entity: "user", entityId: id, autoUpload: true }) }), children: "\u5934\u50CF" }), _jsx(List.Item, { extra: nickname ? nickname : '未设置', onClick: () => {
|
||||
setVisible(true, 'nickname');
|
||||
}, children: t('user:attr.nickname') }), _jsx(List.Item, { extra: gender ? t(`user:v.gender.${gender}`) : '未设置', onClick: () => {
|
||||
setVisible(true, 'gender');
|
||||
}, children: t('user:attr.gender') }), _jsx(List.Item, { extra: birth ? dayjs(birth).format('YYYY-MM-DD') : '未设置', onClick: () => {
|
||||
setVisible(true, 'birth');
|
||||
}, children: t('user:attr.birth') }), _jsx(List.Item, { extra: mobile ? mobile : '未设置', onClick: () => {
|
||||
goAddMobile();
|
||||
}, children: t('mobile') }), _jsx(List.Item, { extra: '********', onClick: () => {
|
||||
goChangePassword();
|
||||
}, children: t('password') })] }), _jsx(Popup, { visible: visible, onMaskClick: () => {
|
||||
clean();
|
||||
setVisible(false, attr);
|
||||
}, bodyStyle: {
|
||||
borderTopLeftRadius: '8px',
|
||||
borderTopRightRadius: '8px',
|
||||
minHeight: '20vh',
|
||||
}, children: _jsx(AttrUpsert, { data: data, methods: methods }) })] }));
|
||||
}
|
||||
function AttrUpsert(props) {
|
||||
const { data, methods } = props;
|
||||
const { attr, genderOptions, attrs } = data;
|
||||
const { setCustomData, onConfirm, setVisible } = methods;
|
||||
const label = attrs[attr];
|
||||
return (_jsx("div", { children: _jsxs(Form, { footer: _jsx(Button, { block: true, type: "submit", color: "primary", size: "large", onClick: async () => {
|
||||
await onConfirm(attr);
|
||||
}, children: "\u63D0\u4EA4" }), children: [_jsx(Form.Header, { children: "\u4FEE\u6539\u4FE1\u606F" }), attr === 'nickname' && (_jsx(Form.Item, { name: attr, label: label, rules: [{ required: true }], children: _jsx(Input, { placeholder: `请输入${label}`, defaultValue: data[attr], onChange: (value) => {
|
||||
setCustomData(attr, value);
|
||||
} }) })), attr === 'gender' && (_jsx(Form.Item, { name: attr, label: label, rules: [{ required: true }], children: _jsx(Radio.Group, { defaultValue: data[attr], onChange: (value) => {
|
||||
setCustomData(attr, value);
|
||||
}, children: _jsx(Space, { direction: "vertical", children: genderOptions.map((ele) => (_jsx(Radio, { value: ele.value, children: ele.label }))) }) }) })), attr === 'birth' && (_jsx(Form.Item, { name: attr, label: label, onClick: (e, datePickerRef) => {
|
||||
datePickerRef.current?.open();
|
||||
}, children: _jsx(DatePicker, { defaultValue: data[attr] ? dayjs(data[attr]).toDate() : null, onConfirm: (value) => {
|
||||
setCustomData(attr, dayjs(value).startOf('day').valueOf());
|
||||
}, max: dayjs().toDate(), children: (value) => value
|
||||
? dayjs(value).format('YYYY-MM-DD')
|
||||
: '请选择日期' }) }))] }) }));
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
.container {
|
||||
background: var(--oak-bg-color-container);
|
||||
box-shadow: 0 2px 3px #0000001a;
|
||||
border-radius: 3px;
|
||||
padding: 30px 32px;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
visible: boolean;
|
||||
nickname: string;
|
||||
name: string;
|
||||
birth: string;
|
||||
gender: string;
|
||||
mobile: string;
|
||||
avatarUrl: string;
|
||||
attr: string;
|
||||
showBack: boolean;
|
||||
genderOptions: Array<{
|
||||
label: string;
|
||||
value: string;
|
||||
}>;
|
||||
wechatUser: EntityDict['wechatUser']['Schema'];
|
||||
counter: number;
|
||||
isRoot: boolean;
|
||||
}, {
|
||||
goUserManage: () => void;
|
||||
goAddMobile: () => void;
|
||||
sendCaptcha: () => void;
|
||||
goChangePassword: () => void;
|
||||
updateMyInfo: () => void;
|
||||
unbindingWechat: (captcha?: string) => void;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useState } from 'react';
|
||||
import { Space, Button, Input, Radio, DatePicker, Form, Typography, Modal, Descriptions } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import PageHeader from '../../../components/common/pageHeader';
|
||||
import OakAvatar from '../../../components/extraFile/avatar';
|
||||
import ExtraFileCommit from '../../../components/extraFile/commit';
|
||||
import MobileLogin from '../../../components/mobile/login';
|
||||
import WechatLoginQrCode from '../../../components/wechatLogin/qrCode';
|
||||
import WechatUserList from '../../../components/wechatUser/bindingList';
|
||||
import { isCaptcha, } from 'oak-domain/lib/utils/validator';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { data, methods } = props;
|
||||
const { t, updateMyInfo, goAddMobile, sendCaptcha, unbindingWechat, goChangePassword, goUserManage, } = methods;
|
||||
const { nickname, name, birth, gender, mobile, avatarUrl, showBack, oakExecuting, genderOptions, oakFullpath, oakDirty, wechatUser, counter, isRoot, } = data;
|
||||
const [open, setOpen] = useState(false);
|
||||
const [open2, setOpen2] = useState(false);
|
||||
const [open3, setOpen3] = useState(false);
|
||||
const [captcha, setCaptcha] = useState('');
|
||||
return (_jsxs(PageHeader, { title: "\u4E2A\u4EBA\u4FE1\u606F", showBack: showBack, children: [_jsxs("div", { className: Style.container, children: [_jsx(Descriptions, { title: '基本信息' }), _jsxs(Form, { labelCol: { xs: { span: 4 }, md: { span: 6 } }, wrapperCol: { xs: { span: 16 }, md: { span: 12 } }, children: [_jsx(Form.Item, { label: t('avatar'), name: "extraFile$entity", children: _jsx(_Fragment, { children: _jsx(OakAvatar, { oakAutoUnmount: true, oakPath: oakFullpath
|
||||
? oakFullpath + '.extraFile$entity'
|
||||
: undefined, entity: "user" }) }) }), _jsx(Form.Item, { label: t('user:attr.name'), rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
], children: _jsx(_Fragment, { children: _jsx(Input, { placeholder: "", onChange: (e) => methods.update({
|
||||
name: e.target.value,
|
||||
}), value: name }) }) }), _jsx(Form.Item, { label: t('user:attr.nickname'), rules: [
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
], children: _jsx(_Fragment, { children: _jsx(Input, { placeholder: "", onChange: (e) => methods.update({
|
||||
nickname: e.target.value,
|
||||
}), value: nickname }) }) }), _jsx(Form.Item, { label: t('user:attr.gender'), children: _jsx(Space, { direction: "vertical", children: _jsx(Radio.Group, { value: data.gender, options: genderOptions, onChange: ({ target: { value } }) => {
|
||||
methods.update({ gender: value });
|
||||
} }) }) }), _jsx(Form.Item, { label: t('user:attr.birth'), children: _jsx(_Fragment, { children: _jsx(DatePicker, { placeholder: "\u8BF7\u9009\u62E9", format: "YYYY-MM-DD", inputReadOnly: true, allowClear: false, value: birth ? dayjs(birth) : undefined, disabledDate: (current) => {
|
||||
if (dayjs(current).valueOf() >
|
||||
dayjs().valueOf()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, onChange: (value) => {
|
||||
if (value) {
|
||||
methods.update({
|
||||
birth: dayjs(value).valueOf(),
|
||||
});
|
||||
}
|
||||
} }) }) }), _jsx(Form.Item, { wrapperCol: {
|
||||
xs: { offset: 4 },
|
||||
md: { offset: 6 },
|
||||
}, children: _jsx(Space, { children: _jsx(ExtraFileCommit, { oakPath: oakFullpath }) }) })] })] }), _jsx("div", { style: { marginTop: '10px' } }), _jsxs("div", { className: Style.container, children: [_jsx(Descriptions, { title: '安全信息' }), _jsxs(Form, { labelCol: { xs: { span: 4 }, md: { span: 6 } }, wrapperCol: { xs: { span: 16 }, md: { span: 12 } }, children: [_jsx(Form.Item, { label: t('mobile'), children: _jsxs(Space, { children: [_jsx(Typography, { children: mobile || '未设置' }), _jsx(Button, { size: "small", onClick: () => {
|
||||
if (mobile) {
|
||||
goAddMobile();
|
||||
return;
|
||||
}
|
||||
setOpen(true);
|
||||
}, children: mobile ? t('manage') : t('bind') })] }) }), _jsx(Form.Item, { label: t('user:attr.password'), children: _jsxs(Space, { children: [_jsx(Typography, { children: '********' }), _jsx(Button, { size: "small", onClick: () => {
|
||||
goChangePassword();
|
||||
return;
|
||||
}, children: t('manage') })] }) }), process.env.NODE_ENV === 'development' && (_jsx(Form.Item, { label: "\u5FAE\u4FE1\u5E10\u53F7", children: _jsx(_Fragment, { children: wechatUser ? (_jsxs(Space, { children: [_jsx(Typography, { children: wechatUser.nickname }), _jsx(WechatUserList, { oakPath: oakFullpath
|
||||
? `${oakFullpath}.wechatUser$user`
|
||||
: undefined })] })) : (_jsx(Button, { size: "small", onClick: () => {
|
||||
setOpen2(true);
|
||||
}, children: "\u7ED1\u5B9A" })) }) })), isRoot && (_jsx(Form.Item, { label: '系统用户', tooltip: "\u8D85\u7EA7\u7BA1\u7406\u5458\u53EF\u5BF9\u7CFB\u7EDF\u7528\u6237\u8FDB\u884C\u7BA1\u7406", children: _jsx(Button, { size: "small", onClick: () => {
|
||||
goUserManage();
|
||||
}, children: t('manage') }) }))] })] }), _jsx(Modal, { title: "\u7ED1\u5B9A\u624B\u673A\u53F7", open: open, destroyOnClose: true, footer: null, onCancel: () => {
|
||||
setOpen(false);
|
||||
}, children: _jsx(MobileLogin, { callback: () => {
|
||||
setOpen(false);
|
||||
}, oakPath: "$user/info-mobile/login", oakAutoUnmount: true }) }), _jsx(Modal, { title: "\u7ED1\u5B9A\u5FAE\u4FE1", open: open2, destroyOnClose: true, footer: null, maskClosable: false, onCancel: () => {
|
||||
setOpen2(false);
|
||||
}, children: _jsx(WechatLoginQrCode, { oakPath: "$user/info-wechatLogin/qrCode", oakAutoUnmount: true }) }), _jsx(Modal, { title: t('Mobile-Number-Verification'), open: open3, destroyOnClose: true, footer: [
|
||||
_jsx(Button, { onClick: () => setOpen3(false), children: t('cancel') }, "cancel"),
|
||||
_jsx(Button, { type: "primary", disabled: !isCaptcha(captcha), onClick: () => {
|
||||
unbindingWechat(captcha);
|
||||
setOpen3(false);
|
||||
}, children: t('unbind') }, "send"),
|
||||
], maskClosable: false, onCancel: () => {
|
||||
setOpen3(false);
|
||||
}, children: _jsxs(Space, { direction: "vertical", style: { width: '100%' }, children: [_jsxs(Typography, { children: ["\u8BF7\u8F93\u5165", mobile &&
|
||||
mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'), "\u6536\u5230\u7684\u9A8C\u8BC1\u7801"] }), _jsx(Form.Item, { name: "captcha", children: _jsx(Input, { allowClear: true, value: captcha, "data-attr": "captcha",
|
||||
// type="number"
|
||||
maxLength: 4, placeholder: t('placeholder.Captcha'), size: "large", onChange: (e) => {
|
||||
setCaptcha(e.target.value);
|
||||
}, className: Style['loginbox-input'], suffix: _jsx(Button, { type: "link", disabled: counter > 0, onClick: () => sendCaptcha(), children: counter > 0
|
||||
? `${counter}秒后可重发`
|
||||
: t('send') }) }) })] }) })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../../oak-app-domain").EntityDict, "user", false, WechatMiniprogram.Component.DataOption>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
// index.ts
|
||||
export default OakComponent({
|
||||
entity: 'user',
|
||||
projection: {
|
||||
id: 1,
|
||||
nickname: 1,
|
||||
name: 1,
|
||||
userState: 1,
|
||||
birth: 1,
|
||||
idState: 1,
|
||||
gender: 1,
|
||||
isRoot: 1,
|
||||
extraFile$entity: {
|
||||
$entity: 'extraFile',
|
||||
data: {
|
||||
id: 1,
|
||||
tag1: 1,
|
||||
origin: 1,
|
||||
bucket: 1,
|
||||
objectId: 1,
|
||||
filename: 1,
|
||||
extra1: 1,
|
||||
type: 1,
|
||||
entity: 1,
|
||||
extension: 1,
|
||||
},
|
||||
filter: {
|
||||
tag1: 'avatar',
|
||||
},
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
},
|
||||
mobile$user: {
|
||||
$entity: 'mobile',
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
},
|
||||
},
|
||||
ref: {
|
||||
id: 1,
|
||||
userState: 1,
|
||||
},
|
||||
refId: 1,
|
||||
},
|
||||
isList: false,
|
||||
formData: ({ data: user, features }) => {
|
||||
const { id, nickname, idState, userState, name, gender, mobile$user, birth, extraFile$entity, } = user || {};
|
||||
const legalActions = user?.['#oakLegalActions'] || [];
|
||||
const mobile = mobile$user && mobile$user[0]?.mobile;
|
||||
const mobileCount = mobile$user ? mobile$user.length : 0;
|
||||
const mobileText = mobileCount && mobileCount > 1
|
||||
? `${mobileCount}条手机号`
|
||||
: mobile || '未设置';
|
||||
const avatar = features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]);
|
||||
const reallyRoot = features.token.isReallyRoot();
|
||||
const currentUserId = features.token.getUserId();
|
||||
const executableActions = reallyRoot && currentUserId !== id
|
||||
? legalActions.concat('play')
|
||||
: legalActions;
|
||||
return {
|
||||
id,
|
||||
nickname,
|
||||
name,
|
||||
mobile,
|
||||
gender,
|
||||
avatar,
|
||||
birth: birth ? new Date(birth).toLocaleDateString() : '',
|
||||
userState,
|
||||
idState,
|
||||
mobileCount,
|
||||
mobileText,
|
||||
executableActions,
|
||||
};
|
||||
},
|
||||
actions: [
|
||||
'accept',
|
||||
'activate',
|
||||
'disable',
|
||||
'enable',
|
||||
'remove',
|
||||
'update',
|
||||
'verify',
|
||||
],
|
||||
data: {
|
||||
stateColor: {
|
||||
shadow: 'primary',
|
||||
normal: 'success',
|
||||
disabled: 'danger',
|
||||
},
|
||||
idStateColor: {
|
||||
verifying: 'primary',
|
||||
verified: 'success',
|
||||
unverified: 'warning',
|
||||
},
|
||||
show: false,
|
||||
actionDescriptions: {
|
||||
accept: {
|
||||
icon: {
|
||||
name: 'success',
|
||||
},
|
||||
label: '通过',
|
||||
},
|
||||
activate: {
|
||||
icon: {
|
||||
name: 'playon',
|
||||
},
|
||||
label: '激活',
|
||||
},
|
||||
disable: {
|
||||
icon: {
|
||||
name: 'shielding',
|
||||
},
|
||||
label: '禁用',
|
||||
},
|
||||
enable: {
|
||||
icon: {
|
||||
name: 'barrage',
|
||||
},
|
||||
label: '启用',
|
||||
},
|
||||
remove: {
|
||||
icon: {
|
||||
name: 'trash',
|
||||
},
|
||||
label: '删除',
|
||||
},
|
||||
update: {
|
||||
icon: {
|
||||
name: 'editor',
|
||||
},
|
||||
label: '更新',
|
||||
},
|
||||
verify: {
|
||||
icon: {
|
||||
name: 'businesscard',
|
||||
},
|
||||
label: '验证',
|
||||
},
|
||||
play: {
|
||||
icon: {
|
||||
name: 'refresh',
|
||||
},
|
||||
label: '切换',
|
||||
},
|
||||
},
|
||||
genderOptions: {
|
||||
male: '男',
|
||||
female: '女',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onActionClick(action) {
|
||||
switch (action) {
|
||||
case 'update': {
|
||||
this.navigateTo({
|
||||
url: '/user/manage/upsert',
|
||||
oakId: this.props.oakId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case 'enable':
|
||||
case 'disable':
|
||||
case 'accept':
|
||||
case 'verify':
|
||||
case 'activate': {
|
||||
await this.execute(action);
|
||||
break;
|
||||
}
|
||||
case 'play': {
|
||||
const { id } = this.state;
|
||||
await this.features.token.switchTo(id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.error(`尚未实现的action: ${action}`);
|
||||
}
|
||||
}
|
||||
if (action === 'play') {
|
||||
this.navigateBack(2);
|
||||
}
|
||||
},
|
||||
onActionClickMp(e) {
|
||||
const { action } = e.detail;
|
||||
return this.onActionClick(action);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"navigationBarTitleText": "用户详情",
|
||||
"usingComponents": {
|
||||
"actionPanel": "../../../../components/func/actionPanel/index",
|
||||
"oak-icon": "../../../../components/icon/index",
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-avatar": "@oak-frontend-base/miniprogram_npm/lin-ui/avatar/index",
|
||||
"l-list": "@oak-frontend-base/miniprogram_npm/lin-ui/list/index",
|
||||
"l-icon": "@oak-frontend-base/miniprogram_npm/lin-ui/icon/index",
|
||||
"l-tag": "@oak-frontend-base/miniprogram_npm/lin-ui/tag/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/** index.wxss **/
|
||||
@import "../../../../config/styles/mp/index.less";
|
||||
@import "../../../../config/styles/mp/mixins.less";
|
||||
|
||||
.page-body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background-color: @oak-bg-color-page;
|
||||
box-sizing: border-box;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
|
||||
.avatar {
|
||||
font-size: 128rpx;
|
||||
color: @oak-text-color-secondary;
|
||||
height: 140rpx;
|
||||
width: 140rpx;
|
||||
border-radius: 14rpx;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
font-size: 44rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0rpx 10rpx;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
background-color: #fff;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.icon {
|
||||
width: 16rpx;
|
||||
margin-left: 6rpx;
|
||||
margin-right: 26rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.label {
|
||||
color: @oak-text-color-primary;
|
||||
}
|
||||
.value {
|
||||
color: @oak-text-color-secondary;
|
||||
margin-right: 16rpx;
|
||||
|
||||
.primary {
|
||||
background-color: @oak-color-primary;
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: @oak-color-success;
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: @oak-color-error;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: @oak-color-warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.userInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300rpx;
|
||||
}
|
||||
|
||||
.btn-view {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="page-body">
|
||||
<view class="userInfo">
|
||||
<block wx:if="{{avatar}}">
|
||||
<l-avatar src="{{avatar}}" />
|
||||
</block>
|
||||
<block wx:else>
|
||||
<l-avatar icon="user" size="140" icon-size="86" />
|
||||
</block>
|
||||
</view>
|
||||
<view class="col">
|
||||
<l-list is-link="{{false}}" title="昵称">
|
||||
<view slot="right-section" class="value">{{nickname || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list is-link="{{false}}" title="姓名">
|
||||
<view slot="right-section" class="value">{{name || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list is-link="{{false}}" title="性别">
|
||||
<view slot="right-section" class="value">{{genderOptions[gender] || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list is-link="{{false}}" title="生日">
|
||||
<view slot="right-section" class="value">{{birth || '未设置'}}</view>
|
||||
</l-list>
|
||||
<l-list is-link="{{false}}" title="手机号">
|
||||
<view slot="right-section" class="value">{{mobileText}}</view>
|
||||
</l-list>
|
||||
<l-list tag-position="right" is-link="{{false}}" title="用户状态">
|
||||
<view slot="right-section" class="value">
|
||||
<l-tag l-class="{{stateColor[userState]}}" size="mini" shape="circle">
|
||||
{{userState || '未设置'}}
|
||||
</l-tag>
|
||||
</view>
|
||||
</l-list>
|
||||
<l-list tag-position="right" is-link="{{false}}" title="认证状态">
|
||||
<view slot="right-section" class="value">
|
||||
<l-tag l-class="{{idStateColor[idState]}}" size="mini" shape="circle">
|
||||
{{idState || '未设置'}}
|
||||
</l-tag>
|
||||
</view>
|
||||
</l-list>
|
||||
</view>
|
||||
<view style="flex:1" />
|
||||
<actionPanel actions="{{executableActions}}" actionDescriptions="{{actionDescriptions}}" bind:action="onActionClickMp" />
|
||||
</view>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mobile": "手机号",
|
||||
"unset": "未设置",
|
||||
"avatar": "头像"
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--oak-bg-color-page);
|
||||
}
|
||||
|
||||
|
||||
.list {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
nickname?: string;
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
mobile?: string;
|
||||
userState?: string;
|
||||
birth?: string;
|
||||
idState?: string;
|
||||
gender?: string;
|
||||
stateColor: Record<string, string>;
|
||||
idStateColor: Record<string, string>;
|
||||
mobileCount: number;
|
||||
mobileText: string;
|
||||
actionDescriptions: Record<string, {
|
||||
icon: {
|
||||
name: string;
|
||||
};
|
||||
label: string;
|
||||
}>;
|
||||
executableActions: string[];
|
||||
}, {
|
||||
onActionClick: (action: string) => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, Tag, Avatar } from 'antd-mobile';
|
||||
import Style from './mobile.module.less';
|
||||
import ActionPanel from '../../../../components/func/actionPanel';
|
||||
export default function render(props) {
|
||||
const { nickname, avatar, name, userState, idState, gender, stateColor, idStateColor, mobileText, executableActions, actionDescriptions, birth, } = props.data;
|
||||
const { t, onActionClick } = props.methods;
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsxs(List, { className: Style.list, children: [_jsx(List.Item, { extra: avatar ? _jsx(Avatar, { src: avatar }) : t('unset'), children: t('avatar') }), _jsx(List.Item, { extra: nickname || t('unset'), children: t('user:attr.nickname') }), _jsx(List.Item, { extra: name || t('unset'), children: t('user:attr.name') }), _jsx(List.Item, { extra: gender ? t(`user:v.gender.${gender}`) : t('unset'), children: t('user:attr.gender') }), _jsx(List.Item, { extra: birth || t('unset'), children: t('user:attr.birth') }), _jsx(List.Item, { extra: mobileText, children: t('mobile') }), _jsx(List.Item, { extra: _jsx(Tag, { color: stateColor[userState], children: t(`user:v.userState.${userState}`) }), children: t('user:attr.userState') }), _jsx(List.Item, { extra: _jsx(Tag, { color: idStateColor[idState], children: t(`user:v.idState.${idState}`) }), children: t('user:attr.idState') })] }), _jsx(ActionPanel, { actions: executableActions, actionDescriptions: actionDescriptions, onActionClick: (action) => onActionClick(action) })] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
nickname?: string;
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
mobile?: string;
|
||||
userState?: string;
|
||||
birth?: string;
|
||||
idState?: string;
|
||||
gender?: string;
|
||||
stateColor: Record<string, string>;
|
||||
idStateColor: Record<string, string>;
|
||||
mobileCount: number;
|
||||
mobileText: string;
|
||||
actionDescriptions: Record<string, {
|
||||
icon: {
|
||||
name: string;
|
||||
};
|
||||
label: string;
|
||||
}>;
|
||||
executableActions: string[];
|
||||
}, {
|
||||
onActionClick: (action: string) => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Tag, Avatar, Descriptions } from 'antd';
|
||||
import Style from './web.module.less';
|
||||
import ActionPanel from '../../../../components/func/actionPanel';
|
||||
import PageHeader from '../../../../components/common/pageHeader';
|
||||
export default function render(props) {
|
||||
const { nickname, avatar, name, userState, idState, gender, stateColor, idStateColor, mobileText, executableActions, actionDescriptions, birth, } = props.data;
|
||||
const { t, onActionClick } = props.methods;
|
||||
return (_jsx(PageHeader, { children: _jsx("div", { className: Style.container, children: _jsxs(Descriptions, { extra: _jsx(ActionPanel, { actions: executableActions, actionDescriptions: actionDescriptions, onActionClick: (action) => onActionClick(action) }), children: [_jsx(Descriptions.Item, { label: t('avatar'), children: avatar ? _jsx(Avatar, { src: avatar }) : t('unset') }), _jsx(Descriptions.Item, { label: t('user:attr.nickname'), children: nickname || t('unset') }), _jsx(Descriptions.Item, { label: t('user:attr.name'), children: name || t('unset') }), _jsx(Descriptions.Item, { label: t('user:attr.gender'), children: gender ? t(`user:v.gender.${gender}`) : t('unset') }), _jsx(Descriptions.Item, { label: t('user:attr.birth'), children: birth || t('unset') }), _jsx(Descriptions.Item, { label: t('mobile'), children: mobileText || t('unset') }), _jsx(Descriptions.Item, { label: t('user:attr.userState'), children: _jsx(Tag, { color: stateColor[userState], children: t(`user:v.userState.${userState}`) }) }), _jsx(Descriptions.Item, { label: t('user:attr.idState'), children: _jsx(Tag, { color: idStateColor[idState], children: t(`user:v.idState.${idState}`) }) })] }) }) }));
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="react" />
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "user", true, {
|
||||
event: string;
|
||||
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// index.ts
|
||||
export default OakComponent({
|
||||
entity: 'user',
|
||||
projection: {
|
||||
id: 1,
|
||||
nickname: 1,
|
||||
name: 1,
|
||||
userState: 1,
|
||||
idState: 1,
|
||||
extraFile$entity: {
|
||||
$entity: 'extraFile',
|
||||
data: {
|
||||
id: 1,
|
||||
tag1: 1,
|
||||
origin: 1,
|
||||
bucket: 1,
|
||||
objectId: 1,
|
||||
filename: 1,
|
||||
extra1: 1,
|
||||
type: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
extension: 1,
|
||||
},
|
||||
filter: {
|
||||
tag1: 'avatar',
|
||||
},
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
},
|
||||
mobile$user: {
|
||||
$entity: 'mobile',
|
||||
data: {
|
||||
id: 1,
|
||||
mobile: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
sorters: [
|
||||
{
|
||||
sorter: () => ({
|
||||
$attr: {
|
||||
$$createAt$$: 1,
|
||||
},
|
||||
$direction: 'desc',
|
||||
}),
|
||||
},
|
||||
],
|
||||
isList: true,
|
||||
formData: function ({ data: users, features }) {
|
||||
const userArr = users.map((user) => {
|
||||
const { id, nickname, userState, name, mobile$user, extraFile$entity, } = user || {};
|
||||
const mobile = mobile$user && mobile$user[0]?.mobile;
|
||||
const avatar = features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]);
|
||||
return {
|
||||
id,
|
||||
nickname,
|
||||
name,
|
||||
mobile,
|
||||
avatar,
|
||||
userState,
|
||||
};
|
||||
});
|
||||
const isRoot = features.token.isReallyRoot();
|
||||
return {
|
||||
userArr,
|
||||
isRoot,
|
||||
};
|
||||
},
|
||||
properties: {
|
||||
event: '',
|
||||
},
|
||||
data: {
|
||||
stateColor: {
|
||||
shadow: 'primary',
|
||||
normal: 'success',
|
||||
disabled: 'danger',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async bindClicked(input) {
|
||||
// resolveInput拿的是target,原来代码拿的是currentTarget
|
||||
const { dataset } = this.resolveInput(input);
|
||||
const { id } = dataset;
|
||||
this.onCellClicked(id);
|
||||
},
|
||||
async onCellClicked(id) {
|
||||
const { event } = this.props;
|
||||
if (event) {
|
||||
this.pubEvent(event, this.state.userArr.find((ele) => ele.id === id));
|
||||
}
|
||||
else {
|
||||
this.navigateTo({
|
||||
url: '/user/manage/detail',
|
||||
oakId: id,
|
||||
});
|
||||
}
|
||||
},
|
||||
goNewUser() {
|
||||
this.navigateTo({
|
||||
url: '/user/manage/upsert',
|
||||
});
|
||||
},
|
||||
},
|
||||
lifetimes: {
|
||||
detached() {
|
||||
this.unsubAllEvents(this.props.event);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"navigationBarTitleText": "用户管理",
|
||||
"usingComponents": {
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-icon": "@oak-frontend-base/miniprogram_npm/lin-ui/icon/index",
|
||||
"l-tag": "@oak-frontend-base/miniprogram_npm/lin-ui/tag/index",
|
||||
"l-avatar": "@oak-frontend-base/miniprogram_npm/lin-ui/avatar/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/** index.wxss **/
|
||||
@import "../../../config/styles/mp/index.less";
|
||||
@import "../../../config/styles/mp/mixins.less";
|
||||
|
||||
.page-body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background-color: @oak-bg-color-page;
|
||||
box-sizing: border-box;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
.user-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
margin-left: 36rpx;
|
||||
}
|
||||
|
||||
.cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 26rpx;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 300rpx;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.primary {
|
||||
background-color: @oak-color-primary;
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: @oak-color-success;
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: @oak-color-error;
|
||||
}
|
||||
}
|
||||
|
||||
.row2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: small;
|
||||
.label {
|
||||
min-width: 100rpx;
|
||||
color: @oak-text-color-primary;
|
||||
}
|
||||
.value {
|
||||
color: @oak-text-color-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.add {
|
||||
position: fixed;
|
||||
right: 20rpx;
|
||||
z-index: 10;
|
||||
bottom: constant(safe-area-inset-bottom) !important;
|
||||
/* 兼容 iOS < 11.2 */
|
||||
bottom: env(safe-area-inset-bottom) !important;
|
||||
/* 兼容 iOS >= 11.2 */
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="page-body">
|
||||
<view class="user-list">
|
||||
<view wx:for="{{userArr}}" wx:key="index">
|
||||
<view class="cell" bind:tap="bindClicked" data-id="{{item.id}}">
|
||||
<block wx:if="{{item.avatar}}">
|
||||
<l-avatar src="{{item.avatar}}" />
|
||||
</block>
|
||||
<block wx:else>
|
||||
<l-avatar size="120" icon-size="76" icon="user" />
|
||||
</block>
|
||||
<view class="user-info">
|
||||
<view class="row">
|
||||
<view class="nickname">{{item.nickname || '未设置'}}</view>
|
||||
<l-tag l-class="{{stateColor[item.userState]}}" size="mini" shape="circle">
|
||||
{{item.userState || '未设置'}}
|
||||
</l-tag>
|
||||
</view>
|
||||
<view class="row2">
|
||||
<view class="label">姓名:</view>
|
||||
<view class="value">{{item.name || '未设置'}}</view>
|
||||
</view>
|
||||
<view class="row2">
|
||||
<view class="label">手机号:</view>
|
||||
<view class="value">{{item.mobile || '未绑定'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<l-icon name="right" size="18" color="#888" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<l-button l-class="add" special="{{true}}" bind:lintap="goNewUser">
|
||||
<l-icon name="add" size="80" />
|
||||
</l-button>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--oak-bg-color-page);
|
||||
}
|
||||
|
||||
|
||||
.avatar {
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
background-color: var(--oak-color-primary);
|
||||
|
||||
.text {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
.row {
|
||||
.label {
|
||||
color: var(--oak-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: var(--oak-text-color-primary);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fab {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="wechat-miniprogram" />
|
||||
/// <reference types="react" />
|
||||
import { EntityDict } from "../../../../oak-app-domain";
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "user", false, WechatMiniprogram.Component.DataOption>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
const GenderOptions = [
|
||||
{
|
||||
value: 'male', label: '男',
|
||||
},
|
||||
{
|
||||
value: 'female', label: '女',
|
||||
}
|
||||
];
|
||||
const IDCardTypeOptions = [
|
||||
{
|
||||
value: 'ID-Card', label: '身份证',
|
||||
},
|
||||
{
|
||||
value: 'passport', label: '护照',
|
||||
},
|
||||
{
|
||||
value: 'Mainland-passport', label: '港澳通行证',
|
||||
}
|
||||
];
|
||||
export default OakComponent({
|
||||
entity: 'user',
|
||||
projection: {
|
||||
id: 1,
|
||||
name: 1,
|
||||
nickname: 1,
|
||||
birth: 1,
|
||||
gender: 1,
|
||||
idCardType: 1,
|
||||
idNumber: 1,
|
||||
extraFile$entity: {
|
||||
$entity: 'extraFile',
|
||||
data: {
|
||||
id: 1,
|
||||
tag1: 1,
|
||||
origin: 1,
|
||||
bucket: 1,
|
||||
objectId: 1,
|
||||
filename: 1,
|
||||
extra1: 1,
|
||||
type: 1,
|
||||
entity: 1,
|
||||
extension: 1,
|
||||
},
|
||||
filter: {
|
||||
tag1: 'avatar',
|
||||
},
|
||||
indexFrom: 0,
|
||||
count: 1,
|
||||
},
|
||||
},
|
||||
isList: false,
|
||||
formData({ data: user }) {
|
||||
const isRoot = this.features.token.isRoot();
|
||||
const { birth, gender, idCardType } = user || {};
|
||||
const birthDate = birth && new Date(birth);
|
||||
const birthText = birthDate && birthDate.toLocaleDateString();
|
||||
const birthDayValue = birthDate &&
|
||||
`${birthDate.getFullYear()}-${birthDate.getMonth() + 1}-${birthDate.getDate()}`;
|
||||
const genderOption = gender && GenderOptions.find((ele) => ele.value === gender);
|
||||
const genderText = genderOption && genderOption.label;
|
||||
const genderOptionIndex = genderOption && GenderOptions.indexOf(genderOption);
|
||||
const idCardTypeOption = idCardType &&
|
||||
IDCardTypeOptions.find((ele) => ele.value === idCardType);
|
||||
const idCardTypeText = idCardTypeOption && idCardTypeOption.label;
|
||||
const idCardTypeOptionIndex = idCardTypeOption && IDCardTypeOptions.indexOf(idCardTypeOption);
|
||||
const idCardTypeIndex = idCardType && IDCardTypeOptions.find((ele) => ele.value === gender);
|
||||
const now = new Date();
|
||||
return Object.assign({}, user, {
|
||||
isRoot,
|
||||
birthText,
|
||||
birthDayValue,
|
||||
genderText,
|
||||
idCardTypeText,
|
||||
idCardTypeOptionIndex,
|
||||
oldestBirthday: `${now.getFullYear() - 120}-01-01`,
|
||||
today: `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`,
|
||||
genderOptionIndex,
|
||||
idCardTypeIndex,
|
||||
});
|
||||
},
|
||||
data: {
|
||||
birthEnd: '',
|
||||
GenderOptions,
|
||||
IDCardTypeOptions,
|
||||
birthVisible: false,
|
||||
},
|
||||
lifetimes: {
|
||||
ready() {
|
||||
const today = new Date();
|
||||
const birthEnd = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
|
||||
this.setState({ birthEnd });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setValueMp(input) {
|
||||
const { detail, target: { dataset }, } = input;
|
||||
const { attr } = dataset;
|
||||
const { value } = detail;
|
||||
this.update({ [attr]: value });
|
||||
},
|
||||
async confirm() {
|
||||
const { nickname } = this.state;
|
||||
if (!nickname) {
|
||||
this.setMessage({
|
||||
type: 'warning',
|
||||
content: '请输入昵称'
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.execute();
|
||||
this.navigateBack();
|
||||
},
|
||||
onBirthChange(e) {
|
||||
const { detail: { value }, } = e;
|
||||
const birth = new Date(value);
|
||||
this.update({ birth });
|
||||
},
|
||||
onIdCardTypeChange(e) {
|
||||
const { detail: { value: index }, } = e;
|
||||
const { value } = IDCardTypeOptions[index];
|
||||
this.update({
|
||||
idCardType: value,
|
||||
});
|
||||
},
|
||||
onGenderChange(e) {
|
||||
const { detail: { value: index }, } = e;
|
||||
const { value } = GenderOptions[index];
|
||||
this.update({
|
||||
gender: value,
|
||||
});
|
||||
},
|
||||
setMobile() {
|
||||
this.navigateTo({
|
||||
url: '/mobile/me',
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"navigationBarTitleText": "编辑用户信息",
|
||||
"usingComponents": {
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-list": "@oak-frontend-base/miniprogram_npm/lin-ui/list/index",
|
||||
"l-input": "@oak-frontend-base/miniprogram_npm/lin-ui/input/index",
|
||||
"l-icon": "@oak-frontend-base/miniprogram_npm/lin-ui/icon/index",
|
||||
"mobile-manage-list": "../../../../components/mobile/manageList/index",
|
||||
"oak-extraFile-avatar": "../../../../components/extraFile/avatar/index"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/** index.wxss **/
|
||||
@import "../../../../config/styles/mp/index.less";
|
||||
@import "../../../../config/styles/mp/mixins.less";
|
||||
|
||||
.page-body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background-color: @oak-bg-color-page;
|
||||
box-sizing: border-box;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
.list-box {
|
||||
padding-left: 25rpx;
|
||||
padding-right: 25rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
|
||||
.label {
|
||||
color: @oak-text-color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
position: relative;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
min-height: 88rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-right: 25rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.label {
|
||||
width: 100px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
padding-left: 25rpx;
|
||||
padding-right: 15rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mobile-box {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="page-body">
|
||||
<view class="col">
|
||||
<view class="list-box">
|
||||
<l-list title="头像">
|
||||
<view slot="right-section" class="avatar">
|
||||
<oak-extraFile-avatar oakAutoUnmount="{{true}}" oakPath="{{ oakFullpath ? oakFullpath + '.extraFile$entity' : undefined }}" entity="user"/>
|
||||
</view>
|
||||
</l-list>
|
||||
</view>
|
||||
|
||||
<l-input placeholder="请输入昵称" label="昵称" value="{{nickname}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="nickname" />
|
||||
<l-input placeholder="请输入姓名" label="姓名" value="{{name}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="name" />
|
||||
<picker range="{{GenderOptions}}" range-key="label" value="{{genderOptionIndex}}" bind:change="onGenderChange">
|
||||
<l-input label="性别" value="{{genderText || '选择性别'}}" disabled="{{true}}" l-label-class="label">
|
||||
<l-icon slot="right" name="right" size="20" />
|
||||
</l-input>
|
||||
</picker>
|
||||
<picker mode="date" end="{{birthEnd}}" value="{{birthDayValue}}" bind:change="onBirthChange">
|
||||
<l-input label="出生日期" value="{{birthText || '选择日期'}}" disabled="{{true}}" l-label-class="label">
|
||||
<l-icon slot="right" name="right" size="20" />
|
||||
</l-input>
|
||||
</picker>
|
||||
<block wx:if="{{isRoot}}">
|
||||
<picker range="{{IDCardTypeOptions}}" range-key="label" value="{{idCardTypeOptionIndex}}" bind:change="onIdCardTypeChange">
|
||||
<l-input label="证件类别" value="{{idCardTypeText || '选择证件类别'}}" disabled="{{true}}" l-label-class="label">
|
||||
<l-icon slot="right" name="right" size="20" />
|
||||
</l-input>
|
||||
</picker>
|
||||
<l-input placeholder="请输入证件号" label="证件号" value="{{idNumber}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="idNumber" />
|
||||
<view class="list-item">
|
||||
<view class="label">手机号</view>
|
||||
<view class="mobile-box">
|
||||
<mobile-manage-list oakPath="{{oakFullpath ? oakFullpath + '.mobile$user' : undefined }}"/>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="list-box">
|
||||
<l-list title="手机号" bind:lintap="setMobile">
|
||||
<view slot="right-section" class="value">{{mobile || '未绑定'}}</view>
|
||||
</l-list>
|
||||
</view>
|
||||
|
||||
</block>
|
||||
</view>
|
||||
<view style="flex: 1" />
|
||||
<l-button type="default" disabled="{{oakExecuting || !oakDirty}}" loading="{{oakExecuting}}" size="long" bind:lintap="confirm">
|
||||
{{t('common::action.confirm')}}
|
||||
</l-button>
|
||||
</view>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--oak-bg-color-container);
|
||||
}
|
||||
|
||||
.radio {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { EntityDict } from '../../../../oak-app-domain';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
nickname?: string;
|
||||
name?: string;
|
||||
gender?: string;
|
||||
birth?: string;
|
||||
idCardType?: string;
|
||||
idNumber?: string;
|
||||
GenderOptions: Array<{
|
||||
value: 'male' | 'female';
|
||||
label: string;
|
||||
}>;
|
||||
IDCardTypeOptions: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
}>;
|
||||
}, {
|
||||
confirm: () => void;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useState } from 'react';
|
||||
import { Button, Input, Form, Radio, DatePicker, Space } from 'antd-mobile';
|
||||
import dayjs from 'dayjs';
|
||||
import Style from './mobile.module.less';
|
||||
export default function Render(props) {
|
||||
const { data, methods } = props;
|
||||
const { GenderOptions, IDCardTypeOptions } = data;
|
||||
const { t, update, setDisablePulldownRefresh, confirm } = methods;
|
||||
const [birthPickerVisible, setBirthPickerVisible] = useState(false);
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsxs(Form, { layout: "horizontal", children: [_jsx(Form.Item, { label: t('user:attr.nickname'), rules: [{ required: true }], children: _jsx(Input, { onChange: (val) => update({ nickname: val }), value: data.nickname || '' }) }), _jsx(Form.Item, { label: t('user:attr.name'), children: _jsx(Input, { onChange: (val) => update({ name: val }), value: data.name || '' }) }), _jsx(Form.Item, { label: t('user:attr.birth'), onClick: () => {
|
||||
setBirthPickerVisible(true);
|
||||
setDisablePulldownRefresh(true);
|
||||
}, children: _jsx(Input, { value: data.birth
|
||||
? dayjs(data.birth).format('YYYY-MM-DD')
|
||||
: '', readOnly: true }) }), _jsx(Form.Item, { label: t('user:attr.gender'), children: _jsx(Radio.Group, { onChange: (e) => {
|
||||
update({
|
||||
gender: e,
|
||||
});
|
||||
}, value: data.gender, children: _jsx(Space, { direction: "horizontal", children: GenderOptions.map((ele, idx) => (_jsx(Radio, { value: ele.value, className: Style.radio, children: ele.label }, idx))) }) }) }), _jsx(Form.Item, { label: t('user:attr.idCardType'), children: _jsx(Radio.Group, { onChange: (e) => {
|
||||
update({
|
||||
idCardType: e,
|
||||
});
|
||||
}, value: data.idCardType, children: _jsx(Space, { direction: "vertical", children: IDCardTypeOptions.map((ele, idx) => (_jsx(Radio, { value: ele.value, className: Style.radio, children: ele.label }, idx))) }) }) }), _jsx(Form.Item, { label: t('user:attr.idNumber'), children: _jsx(Input, { onChange: (val) => update({ idNumber: val }), value: data.idNumber || '' }) })] }), _jsx(DatePicker, { visible: birthPickerVisible, max: new Date(), min: new Date('1900-01-01'), onConfirm: (value) => {
|
||||
const val = value.valueOf();
|
||||
update({ birth: val });
|
||||
}, onClose: () => {
|
||||
setBirthPickerVisible(false);
|
||||
setDisablePulldownRefresh(false);
|
||||
} }), _jsx("div", { style: { flex: 1 } }), _jsx(Button, { block: true, color: "primary", onClick: () => confirm(), children: t('common::action.confirm') })] }));
|
||||
}
|
||||
|
|
@ -5,4 +5,4 @@
|
|||
box-shadow: 0 2px 3px #0000001a;
|
||||
border-radius: 3px;
|
||||
padding: 30px 32px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', false, {
|
||||
nickname?: string;
|
||||
name?: string;
|
||||
gender?: string;
|
||||
birth?: string;
|
||||
idCardType?: string;
|
||||
idNumber?: string;
|
||||
GenderOptions: Array<{
|
||||
value: 'male' | 'female';
|
||||
label: string;
|
||||
}>;
|
||||
IDCardTypeOptions: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
}>;
|
||||
}, {
|
||||
confirm: () => void;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Button, Input, Form, Radio, DatePicker } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import PageHeader from '../../../../components/common/pageHeader';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { data, methods } = props;
|
||||
const { GenderOptions, IDCardTypeOptions } = data;
|
||||
const { t, update, confirm } = methods;
|
||||
return (_jsx(PageHeader, { children: _jsx("div", { className: Style.container, children: _jsxs(Form, { layout: "horizontal", labelCol: { span: 8 }, wrapperCol: { span: 16 }, style: { maxWidth: 600 }, children: [_jsx(Form.Item, { label: t('user:attr.nickname'), required: true, children: _jsx(Input, { onChange: (e) => update({ nickname: e.target.value }), value: data.nickname || '' }) }), _jsx(Form.Item, { label: t('user:attr.name'), children: _jsx(Input, { onChange: (e) => update({ name: e.target.value }), value: data.name || '' }) }), _jsx(Form.Item, { label: t('user:attr.birth'), children: _jsx(DatePicker, { value: data.birth ? dayjs(data.birth) : undefined, format: 'YYYY/MM/DD', onChange: (value) => update({ birth: dayjs(value).valueOf() }) }) }), _jsx(Form.Item, { label: t('user:attr.gender'), children: _jsx(Radio.Group, { onChange: (e) => {
|
||||
update({
|
||||
gender: e.target
|
||||
.value,
|
||||
});
|
||||
}, value: data.gender, children: GenderOptions.map((ele, idx) => (_jsx(Radio, { value: ele.value, children: ele.label }, idx))) }) }), _jsx(Form.Item, { label: t('user:attr.idCardType'), children: _jsx(Radio.Group, { onChange: (e) => {
|
||||
update({
|
||||
idCardType: e.target
|
||||
.value,
|
||||
});
|
||||
}, value: data.idCardType, children: IDCardTypeOptions.map((ele, idx) => (_jsx(Radio, { value: ele.value, className: Style.radio, children: ele.label }, idx))) }) }), _jsx(Form.Item, { label: t('user:attr.idNumber'), children: _jsx(Input, { onChange: (e) => update({ idNumber: e.target.value }), value: data.idNumber || '' }) }), _jsx(Form.Item, { wrapperCol: { offset: 8, span: 16 }, children: _jsx(Button, { type: "primary", color: "primary", onClick: () => confirm(), children: t('common::action.confirm') }) })] }) }) }));
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function render(props: WebComponentProps<EntityDict, 'user', true, {
|
||||
userArr: Array<EntityDict['user']['OpSchema'] & {
|
||||
avatar: string;
|
||||
mobile: string;
|
||||
}>;
|
||||
stateColor: Record<string, string>;
|
||||
isRoot: boolean;
|
||||
}, {
|
||||
onCellClicked: (id: string) => Promise<void>;
|
||||
goNewUser: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { List, Tag, Avatar, FloatingBubble } from 'antd-mobile';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import Style from './mobile.module.less';
|
||||
export default function render(props) {
|
||||
const { stateColor, userArr, isRoot } = props.data;
|
||||
const { onCellClicked, t, goNewUser } = props.methods;
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsx(List, { children: userArr?.map((ele, index) => {
|
||||
return (_jsx(List.Item, { onClick: () => onCellClicked(ele.id), prefix: _jsx(Avatar, { className: Style.avatar, src: ele.avatar }), title: _jsx("div", { children: ele.name || '--' }), description: _jsxs("div", { className: Style.description, children: [_jsxs("div", { className: Style.row, children: [_jsx("span", { className: Style.label, children: "\u6635\u79F0:\u00A0" }), _jsx("span", { className: Style.value, children: ele.nickname || '--' })] }), _jsxs("div", { className: Style.row, children: [_jsx("span", { className: Style.label, children: "\u624B\u673A\u53F7:\u00A0" }), _jsx("span", { className: Style.value, children: ele.mobile || '--' })] }), _jsx(Tag, { color: stateColor[ele.userState], children: ele.userState
|
||||
? t(`user:v.userState.${ele.userState}`)
|
||||
: '未知' })] }) }, index));
|
||||
}) }), isRoot && (_jsx(FloatingBubble, { axis: "x", magnetic: "x", style: {
|
||||
'--initial-position-bottom': '24px',
|
||||
'--initial-position-right': '24px',
|
||||
'--edge-distance': '24px',
|
||||
}, onClick: () => {
|
||||
goNewUser();
|
||||
}, children: _jsx(PlusOutlined, {}) }))] }));
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
|
||||
.container {
|
||||
background: var(--oak-bg-color-container);
|
||||
box-shadow: 0 2px 3px #0000001a;
|
||||
border-radius: 3px;
|
||||
padding: 30px 32px;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'user', true, {
|
||||
userArr: Array<EntityDict['user']['OpSchema'] & {
|
||||
avatar: string;
|
||||
mobile: string;
|
||||
}>;
|
||||
stateColor: Record<string, string>;
|
||||
isRoot: boolean;
|
||||
}, {
|
||||
onCellClicked: (id: string, event?: string) => Promise<void>;
|
||||
goNewUser: () => Promise<void>;
|
||||
}>): import("react/jsx-runtime").JSX.Element;
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Table, Tag, Button, Space, Avatar } from 'antd';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import FilterPanel from 'oak-frontend-base/es/components/filterPanel';
|
||||
import PageHeader from '../../../components/common/pageHeader';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { methods, data } = props;
|
||||
const { t, setPageSize, setCurrentPage, goNewUser, onCellClicked } = methods;
|
||||
const { oakFullpath, oakLoading, oakPagination, userArr = [], stateColor, isRoot, } = data;
|
||||
const { pageSize, total, currentPage } = oakPagination || {};
|
||||
return (_jsx(PageHeader, { children: _jsxs("div", { className: Style.container, children: [isRoot && (_jsx(Space, { style: { marginBottom: 16 }, children: _jsx(Button, { type: "primary", onClick: () => {
|
||||
goNewUser();
|
||||
}, children: "\u6DFB\u52A0\u7528\u6237" }) })), _jsx(FilterPanel, { entity: "user", oakPath: oakFullpath, columns: [
|
||||
{
|
||||
attr: 'nickname',
|
||||
op: '$includes',
|
||||
},
|
||||
{
|
||||
attr: 'name',
|
||||
op: '$includes',
|
||||
},
|
||||
{
|
||||
attr: 'userState',
|
||||
},
|
||||
] }), _jsx(Table, { loading: oakLoading, dataSource: userArr, rowKey: "id", columns: [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: '#',
|
||||
render: (value, record, index) => {
|
||||
return index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
width: 100,
|
||||
dataIndex: 'avatar',
|
||||
title: '头像',
|
||||
render: (value, record, index) => {
|
||||
if (!value) {
|
||||
return (_jsx(Avatar, { icon: _jsx(UserOutlined, {}) }));
|
||||
}
|
||||
return _jsx(Avatar, { src: value, shape: "circle" });
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'nickname',
|
||||
title: '昵称',
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '姓名',
|
||||
},
|
||||
{
|
||||
dataIndex: 'mobile',
|
||||
title: '手机号',
|
||||
},
|
||||
{
|
||||
dataIndex: 'userState',
|
||||
title: '状态',
|
||||
render: (value, record, index) => {
|
||||
return (_jsx(Tag, { color: stateColor[value], children: t(`user:v.userState.${value}`) }));
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'op',
|
||||
width: 200,
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
render: (value, record, index) => {
|
||||
return (_jsx(_Fragment, { children: _jsx(Button, { type: "link", onClick: () => {
|
||||
onCellClicked(record.id);
|
||||
}, children: "\u8BE6\u60C5" }) }));
|
||||
},
|
||||
fixed: 'right',
|
||||
},
|
||||
], pagination: {
|
||||
total: total,
|
||||
pageSize: pageSize,
|
||||
current: currentPage,
|
||||
onShowSizeChange: (pageSize) => {
|
||||
setPageSize(pageSize);
|
||||
},
|
||||
onChange: (page) => {
|
||||
setCurrentPage(page);
|
||||
},
|
||||
} })] }) }));
|
||||
}
|
||||
|
|
@ -1 +1,8 @@
|
|||
{}
|
||||
{
|
||||
"navigationBarTitleText": "领取权限",
|
||||
"usingComponents": {
|
||||
"l-notice-bar": "@oak-frontend-base/miniprogram_npm/lin-ui/notice-bar/index",
|
||||
"l-button": "@oak-frontend-base/miniprogram_npm/lin-ui/button/index",
|
||||
"l-list": "@oak-frontend-base/miniprogram_npm/lin-ui/list/index"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/** index.wxss **/
|
||||
@import '../../../config/styles/mp/index.less';
|
||||
@import '../../../config/styles/mp/mixins.less';
|
||||
|
||||
.view {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background-color: @oak-bg-color-page;
|
||||
box-sizing: border-box;
|
||||
.safe-area-inset-bottom();
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
// margin: 0 10px;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="view" wx:if="{{userEntityGrant}}">
|
||||
<block>
|
||||
<l-notice-bar show="{{!hideTip && !isGranter && !hasClaimed}}">
|
||||
{{t('tip')}}
|
||||
</l-notice-bar>
|
||||
<l-notice-bar show="{{isGranter}}">
|
||||
{{t('isGranter')}}
|
||||
</l-notice-bar>
|
||||
<l-notice-bar show="{{hasClaimed}}">
|
||||
{{t('hasClaimed')}}
|
||||
</l-notice-bar>
|
||||
</block>
|
||||
<block wx:if="{{!hideInfo}}">
|
||||
<view class="info">
|
||||
<l-list title="{{t('granterName')}}" right-desc="{{userEntityGrant.granter.name || userEntityGrant.granter.nickname}}" is-link="{{false}}" />
|
||||
<l-list title="{{expired ? t('isExpired') : t('counter')}}" right-desc="{{expired ? t('expired') : counterStr}}" is-link="{{false}}" />
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
|
||||
<view style="flex: 1" />
|
||||
<view class="btn">
|
||||
<l-button
|
||||
type="{{isGranter || hasClaimed ? 'error' : (!expired ? 'default' : 'warning')}}"
|
||||
disabled="{{oakExecutable !== true || !!expired || isGranter || hasClaimed}}"
|
||||
size="long" bind:lintap="claim">
|
||||
{{isGranter ? t('isGranter') : ( hasClaimed ? t('hasClaimed') : (!expired ? t('userEntityGrant:action.claim') : t('expired')))}}
|
||||
</l-button>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -17,11 +17,13 @@ export default OakComponent({
|
|||
name: 1,
|
||||
nickname: 1,
|
||||
},
|
||||
granteeId: 1,
|
||||
$$createAt$$: 1,
|
||||
expired: 1,
|
||||
expiresAt: 1,
|
||||
},
|
||||
actions: [
|
||||
'disable',
|
||||
],
|
||||
properties: {
|
||||
entity: '',
|
||||
entityId: '',
|
||||
|
|
|
|||
|
|
@ -1,93 +1,105 @@
|
|||
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
||||
import { Table, Space, Typography } from 'antd';
|
||||
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { useState } from 'react';
|
||||
import { Table, Space, Typography, Modal } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import ActionBtnPanel from 'oak-frontend-base/es/components/actionBtnPanel';
|
||||
import UserEntityGrantShare from '../share';
|
||||
export default function render(props) {
|
||||
const { oakPagination, oakFullpath, list = [], oakLoading, } = props.data;
|
||||
const { pageSize, total, currentPage } = oakPagination || {};
|
||||
const { t, setPageSize, setCurrentPage, execute, updateItem } = props.methods;
|
||||
return (_jsx(Table, { loading: oakLoading, dataSource: list, rowKey: "id", columns: [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: '#',
|
||||
render: (value, record, index) => {
|
||||
return index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '授权人',
|
||||
render: (value, record, index) => {
|
||||
return (_jsxs(Space, { direction: "vertical", children: [_jsxs(Typography.Text, { children: ["\u59D3\u540D\uFF1A", record.granter?.name || '-'] }), _jsxs(Typography.Text, { children: ["\u6635\u79F0\uFF1A", record.granter?.nickname] })] }));
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: '授权类型',
|
||||
render: (value, record, index) => {
|
||||
return t(`userEntityGrant:v.type.${value}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'relation',
|
||||
title: '权限',
|
||||
render: (value, record, index) => {
|
||||
return (value.display ||
|
||||
t(`${record.relationEntity}:r.${value.name}`));
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: '$$createAt$$',
|
||||
title: '创建时间',
|
||||
render: (value, record, index) => {
|
||||
return dayjs(value).format('YYYY-MM-DD HH:mm');
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'expired',
|
||||
title: '状态',
|
||||
render: (value, record, index) => {
|
||||
return (_jsxs(Typography.Text, { type: record.expired ? 'danger' : 'success', children: [record.expired ? '失效' : '有效', !record.expired && (_jsxs(Typography.Text, { children: ["\u00A0", dayjs(record.expiresAt).format('YYYY-MM-DD HH:mm')] }))] }));
|
||||
},
|
||||
},
|
||||
{
|
||||
width: 200,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render: (value, record, rowIndex) => {
|
||||
return (_jsx(ActionBtnPanel, { mode: "table-cell", entity: "parasite", items: [
|
||||
{
|
||||
label: '失效',
|
||||
action: 'disable',
|
||||
// alerted: true,
|
||||
show: record['#oakLegalActions']?.includes('cancel'),
|
||||
onClick: () => {
|
||||
updateItem({ expired: true }, record.id, 'disable');
|
||||
execute();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '二维码',
|
||||
action: 'qrcode',
|
||||
show: record['#oakLegalActions']?.includes('qrcode'),
|
||||
// alerted: true,
|
||||
onClick: async () => {
|
||||
},
|
||||
},
|
||||
] }));
|
||||
},
|
||||
},
|
||||
], pagination: {
|
||||
total,
|
||||
pageSize,
|
||||
current: currentPage,
|
||||
onShowSizeChange: (pageSize) => {
|
||||
setPageSize(pageSize);
|
||||
},
|
||||
onChange: (current) => {
|
||||
setCurrentPage(current);
|
||||
},
|
||||
} }));
|
||||
const [qrCodeOpen, setQrCodeOpen] = useState(false);
|
||||
const [userEntityGrantId, setUserEntityGrantId] = useState('');
|
||||
return (_jsxs(_Fragment, { children: [_jsx(Table, { loading: oakLoading, dataSource: list, rowKey: "id", columns: [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: '#',
|
||||
render: (value, record, index) => {
|
||||
return index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '授权人',
|
||||
render: (value, record, index) => {
|
||||
return (_jsxs(Space, { direction: "vertical", children: [_jsxs(Typography.Text, { children: ["\u59D3\u540D\uFF1A", record.granter?.name || '-'] }), _jsxs(Typography.Text, { children: ["\u6635\u79F0\uFF1A", record.granter?.nickname] })] }));
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: '授权类型',
|
||||
render: (value, record, index) => {
|
||||
return t(`userEntityGrant:v.type.${value}`);
|
||||
},
|
||||
},
|
||||
// {
|
||||
// dataIndex: 'relation',
|
||||
// title: '权限',
|
||||
// render: (value, record, index) => {
|
||||
// return (
|
||||
// // value.display ||
|
||||
// t(`${record.relationEntity}:r.${value.name}`)
|
||||
// );
|
||||
// },
|
||||
// },
|
||||
{
|
||||
dataIndex: '$$createAt$$',
|
||||
title: '创建时间',
|
||||
render: (value, record, index) => {
|
||||
return dayjs(value).format('YYYY-MM-DD HH:mm');
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'expired',
|
||||
title: '状态',
|
||||
render: (value, record, index) => {
|
||||
return (_jsxs(Typography.Text, { type: record.expired ? 'danger' : 'success', children: [record.expired ? '失效' : '有效', !record.expired && (_jsxs(Typography.Text, { children: ["\u00A0", dayjs(record.expiresAt).format('YYYY-MM-DD HH:mm')] }))] }));
|
||||
},
|
||||
},
|
||||
{
|
||||
width: 200,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render: (value, record, rowIndex) => {
|
||||
return (_jsx(ActionBtnPanel, { mode: "table-cell", entity: "userEntityGrant", items: [
|
||||
{
|
||||
label: '失效',
|
||||
action: 'disable',
|
||||
// alerted: true,
|
||||
show: record['#oakLegalActions']?.includes('disable'),
|
||||
onClick: () => {
|
||||
updateItem({ expired: true }, record.id, 'disable');
|
||||
execute();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '二维码',
|
||||
// action: 'qrcode',
|
||||
// show: record[
|
||||
// '#oakLegalActions'
|
||||
// ]?.includes('qrcode'),
|
||||
// alerted: true,
|
||||
onClick: async () => {
|
||||
setUserEntityGrantId(record.id);
|
||||
setQrCodeOpen(true);
|
||||
},
|
||||
},
|
||||
] }));
|
||||
},
|
||||
},
|
||||
], pagination: {
|
||||
total,
|
||||
pageSize,
|
||||
current: currentPage,
|
||||
onShowSizeChange: (pageSize) => {
|
||||
setPageSize(pageSize);
|
||||
},
|
||||
onChange: (current) => {
|
||||
setCurrentPage(current);
|
||||
},
|
||||
} }), _jsx(Modal, { width: 786, open: qrCodeOpen, destroyOnClose: true, onCancel: () => {
|
||||
setQrCodeOpen(false);
|
||||
}, footer: null, children: _jsx(UserEntityGrantShare, { oakId: userEntityGrantId, oakAutoUnmount: true, oakPath: "$userEntityGrant/list-userEntityGrant/detail" }) })] }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="qrcode_view">
|
||||
<!-- <view class="row">
|
||||
<text class="text">分享权限</text>
|
||||
<view class="icon-view">
|
||||
<g-icon name="person_add" size="30" />
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="col">
|
||||
<block wx:if="{{oakLoading}}">
|
||||
<l-loading show="{{true}}" type="circle"></l-loading>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
|
|||
entityId: string;
|
||||
relationEntity: string;
|
||||
relationEntityFilter: any;
|
||||
relations: import("../../../oak-app-domain/Relation/Schema").OpSchema[];
|
||||
relationIds: string[];
|
||||
type: "grant" | "transfer";
|
||||
redirectToAfterConfirm: import("../../../oak-app-domain/UserEntityGrant/Schema").RedirectToProps | null | undefined;
|
||||
claimUrl: string;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default OakComponent({
|
|||
entityId: '',
|
||||
relationEntity: '',
|
||||
relationEntityFilter: {},
|
||||
relations: [],
|
||||
relationIds: [],
|
||||
type: 'grant',
|
||||
redirectToAfterConfirm: {},
|
||||
claimUrl: '',
|
||||
|
|
@ -44,13 +44,17 @@ export default OakComponent({
|
|||
},
|
||||
setInit() {
|
||||
const userId = this.features.token.getUserId();
|
||||
const { entity, entityId, relationEntity, relationEntityFilter, type, redirectToAfterConfirm, qrCodeType, claimUrl, multiple, rule, ruleOnRow, } = this.props;
|
||||
const { entity, entityId, relationEntity, relationEntityFilter, relationIds, type, redirectToAfterConfirm, qrCodeType, claimUrl, multiple, rule, ruleOnRow, } = this.props;
|
||||
this.setState({
|
||||
userEntityGrantId: '',
|
||||
});
|
||||
if (this.isCreation()) {
|
||||
this.update({
|
||||
entity,
|
||||
entityId,
|
||||
relationEntity,
|
||||
relationEntityFilter,
|
||||
relationIds,
|
||||
type: type || 'grant',
|
||||
multiple,
|
||||
rule: rule || 'single',
|
||||
|
|
@ -60,9 +64,9 @@ export default OakComponent({
|
|||
qrCodeType: qrCodeType,
|
||||
claimUrl,
|
||||
});
|
||||
this.setState({
|
||||
userEntityGrantId: '',
|
||||
});
|
||||
// this.setState({
|
||||
// userEntityGrantId: '',
|
||||
// });
|
||||
}
|
||||
},
|
||||
async confirm() {
|
||||
|
|
@ -87,5 +91,5 @@ export default OakComponent({
|
|||
userEntityGrantId: id,
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { Form, Space, Button, InputNumber, Typography, } from 'antd';
|
||||
import UserEntityGrantShare from '../share';
|
||||
import PageHeader from '../../common/pageHeader';
|
||||
import Style from './web.module.less';
|
||||
export default function Render(props) {
|
||||
const { oakId, oakFullpath, entity, entityId, relationEntity, showBack = true, userEntityGrantId, period } = props.data;
|
||||
const { setPeriod, confirm, setInit } = props.methods;
|
||||
console.log(userEntityGrantId);
|
||||
if (!!userEntityGrantId) {
|
||||
return (_jsxs("div", { className: Style.container, children: [_jsx(UserEntityGrantShare, { oakId: userEntityGrantId, oakAutoUnmount: true, oakPath: "$userEntityGrant/upsert-userEntityGrant/detail" }), _jsx("div", { style: {
|
||||
width: '100%',
|
||||
|
|
@ -15,9 +15,9 @@ export default function Render(props) {
|
|||
setInit();
|
||||
}, children: "\u91CD\u65B0\u751F\u6210" }) })] }));
|
||||
}
|
||||
return (_jsx(PageHeader, { title: "\u521B\u5EFA", showBack: showBack, children: _jsx("div", { className: Style.container, children: _jsxs(Form, { labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: [_jsx(Form.Item, { label: "\u6709\u6548\u671F", required: true, children: _jsx(_Fragment, { children: _jsx(InputNumber, { min: 1, max: 30, placeholder: "\u8BF7\u8F93\u5165", onChange: (value) => {
|
||||
setPeriod(value);
|
||||
}, value: period, addonAfter: _jsx(Typography, { children: "\u5929" }) }) }) }), _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsx(Space, { children: _jsx(Button, { type: "primary", onClick: () => {
|
||||
confirm();
|
||||
}, children: "\u63D0\u4EA4" }) }) })] }) }) }));
|
||||
return (_jsx("div", { className: Style.container, children: _jsxs(Form, { labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: [_jsx(Form.Item, { label: "\u6709\u6548\u671F", required: true, children: _jsx(_Fragment, { children: _jsx(InputNumber, { min: 1, max: 30, placeholder: "\u8BF7\u8F93\u5165", onChange: (value) => {
|
||||
setPeriod(value);
|
||||
}, value: period, addonAfter: _jsx(Typography, { children: "\u5929" }) }) }) }), _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsx(Space, { children: _jsx(Button, { type: "primary", onClick: () => {
|
||||
confirm();
|
||||
}, children: "\u63D0\u4EA4" }) }) })] }) }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
style="display: flex;flex-direction: column; flex: 1; margin-top: 30rpx"
|
||||
oakId="{{userId}}"
|
||||
mobile="{{mobileValue}}"
|
||||
oakPath="{{oakFullpath ? oakFullpath + '.user' : undefined}}"
|
||||
oakPath="{{oakFullpath + '.user'}}"
|
||||
oakAutoUnmount="{{true}}"
|
||||
entity="{{entity}}"
|
||||
entityId="{{entityId}}"
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ export default function Render(props) {
|
|||
},
|
||||
], children: _jsx(_Fragment, { children: _jsx(Input, { maxLength: 11, value: mobileValue, onChange: (value) => {
|
||||
onMobileChange(value);
|
||||
}, placeholder: t('inputMobile'), type: "tel", clearable: true }) }) }), mobileValueReady && userId && (_jsx(OnUser, { oakAutoUnmount: true, oakPath: oakFullpath ? `${oakFullpath}.user` : undefined, entity: entity, entityId: entityId, relations: relations, oakId: userId }))] }));
|
||||
}, placeholder: t('inputMobile'), type: "tel", clearable: true }) }) }), mobileValueReady && userId && (_jsx(OnUser, { oakAutoUnmount: true, oakPath: `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: userId }))] }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default function Render(props) {
|
|||
], children: _jsx(Input, { maxLength: 11, value: mobileValue, onChange: (e) => {
|
||||
const strValue = e.target.value;
|
||||
onMobileChange(strValue);
|
||||
}, placeholder: "\u8BF7\u8F93\u5165\u624B\u673A\u53F7\u7801", type: "tel" }) }) }), mobileValueReady && userId && (_jsx(OnUser, { oakAutoUnmount: true, oakPath: oakFullpath ? `${oakFullpath}.user` : undefined, entity: entity, entityId: entityId, relations: relations, oakId: userId, setPasswordConfirm: setPasswordConfirm })), _jsx(Form, { colon: true, labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsxs(Space, { children: [_jsx(Button, { style: { flex: 2 }, type: "primary", htmlType: "reset", onClick: async () => {
|
||||
}, placeholder: "\u8BF7\u8F93\u5165\u624B\u673A\u53F7\u7801", type: "tel" }) }) }), mobileValueReady && userId && (_jsx(OnUser, { oakAutoUnmount: true, oakPath: `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: userId, setPasswordConfirm: setPasswordConfirm })), _jsx(Form, { colon: true, labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsxs(Space, { children: [_jsx(Button, { style: { flex: 2 }, type: "primary", htmlType: "reset", onClick: async () => {
|
||||
await onConfirm();
|
||||
setPasswordConfirm(true);
|
||||
}, disabled: !legal ||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<view class="body">
|
||||
<relation-on-user style="display: flex;flex-direction: column; flex: 1; margin-top: 30rpx" oakAutoUnmount="{{true}}" oakPath="{{oakFullpath ? oakFullpath + '.user' : undefined}}" entity="{{entity}}" entityId="{{entityId}}" relations="{{relations}}" oakId="{{oakId}}" />
|
||||
<relation-on-user style="display: flex;flex-direction: column; flex: 1; margin-top: 30rpx" oakAutoUnmount="{{true}}" oakPath="{{oakFullpath + '.user'}}" entity="{{entity}}" entityId="{{entityId}}" relations="{{relations}}" oakId="{{oakId}}" />
|
||||
|
||||
<view style="flex: 1" />
|
||||
<l-button disabled="{{!oakDirty}}" size="long" bind:lintap="onConfirm">
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ export default function Render(props) {
|
|||
const { onConfirm, onReset, t } = props.methods;
|
||||
return (_jsx(Form, { footer: _jsxs(Space, { children: [_jsx(Button, { color: "primary", style: { flex: 2 }, onClick: () => {
|
||||
onConfirm();
|
||||
}, disabled: oakExecutable !== true, children: t('common::action.confirm') }), _jsx(Button, { style: { flex: 1 }, onClick: () => onReset(), children: t('common::reset') })] }), children: _jsx(OnUser, { oakAutoUnmount: true, oakPath: oakFullpath && `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: oakId }) }));
|
||||
}, disabled: oakExecutable !== true, children: t('common::action.confirm') }), _jsx(Button, { style: { flex: 1 }, onClick: () => onReset(), children: t('common::reset') })] }), children: _jsx(OnUser, { oakAutoUnmount: true, oakPath: `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: oakId }) }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ import OnUser from '../onUser/index';
|
|||
export default function Render(props) {
|
||||
const { relations, entity, entityId, oakId, oakDirty, oakFullpath } = props.data;
|
||||
const { onConfirm, onReset, t } = props.methods;
|
||||
return (_jsxs(_Fragment, { children: [_jsx(OnUser, { oakAutoUnmount: true, oakPath: oakFullpath && `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: oakId }), _jsx(Form, { colon: true, labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsxs(Space, { children: [_jsx(Button, { disabled: !oakDirty, type: "primary", onClick: () => onConfirm(), children: t('common::action.confirm') }), _jsx(Button, { htmlType: "reset", onClick: () => onReset(), children: t('common::reset') })] }) }) })] }));
|
||||
return (_jsxs(_Fragment, { children: [_jsx(OnUser, { oakAutoUnmount: true, oakPath: `${oakFullpath}.user`, entity: entity, entityId: entityId, relations: relations, oakId: oakId }), _jsx(Form, { colon: true, labelCol: { span: 4 }, wrapperCol: { span: 8 }, children: _jsx(Form.Item, { wrapperCol: { offset: 4 }, children: _jsxs(Space, { children: [_jsx(Button, { disabled: !oakDirty, type: "primary", onClick: () => onConfirm(), children: t('common::action.confirm') }), _jsx(Button, { htmlType: "reset", onClick: () => onReset(), children: t('common::reset') })] }) }) })] }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ export default OakComponent({
|
|||
qrCodeType: 1,
|
||||
},
|
||||
isList: false,
|
||||
formData: ({ data: userEntityGrant }) => ({
|
||||
userEntityGrant,
|
||||
}),
|
||||
formData({ data: userEntityGrant, props }) {
|
||||
return {
|
||||
userEntityGrant,
|
||||
};
|
||||
},
|
||||
properties: {
|
||||
entity: '',
|
||||
entityId: '',
|
||||
|
|
@ -106,12 +108,26 @@ export default OakComponent({
|
|||
},
|
||||
setRelation(value) {
|
||||
this.update({
|
||||
relationIds: [value],
|
||||
relationIds: value,
|
||||
});
|
||||
},
|
||||
setRelationMp(e) {
|
||||
const { currentKey } = e.detail;
|
||||
this.setRelation(currentKey);
|
||||
const { key } = e.detail;
|
||||
const { userEntityGrant } = this.state;
|
||||
const relationIds = [...(userEntityGrant?.relationIds || [])];
|
||||
const index = relationIds.findIndex((ele) => ele === key);
|
||||
if (index > -1) {
|
||||
relationIds.splice(index, 1);
|
||||
}
|
||||
else {
|
||||
relationIds.push(key);
|
||||
}
|
||||
// 小程序 多选处理
|
||||
const newRelations = this.props.relations?.map((ele) => Object.assign({}, ele, {
|
||||
checked: relationIds.includes(ele.id),
|
||||
}));
|
||||
this.setState({ relations: newRelations });
|
||||
this.setRelation(relationIds);
|
||||
},
|
||||
setNumber(value) {
|
||||
this.update({
|
||||
|
|
@ -129,6 +145,20 @@ export default OakComponent({
|
|||
const { count } = e.detail;
|
||||
this.setPeriod(count);
|
||||
},
|
||||
setMultiple(m) {
|
||||
this.update({ multiple: m });
|
||||
},
|
||||
setMultipleMp(e) {
|
||||
const { value } = e.detail;
|
||||
this.setMultiple(value);
|
||||
},
|
||||
setRule(m) {
|
||||
this.update({ rule: m });
|
||||
},
|
||||
setRuleMp(e) {
|
||||
const { currentKey } = e.detail;
|
||||
this.setRule(currentKey);
|
||||
},
|
||||
setUnit(u) {
|
||||
const { defaultPeriods } = this.state;
|
||||
this.setState({ unit: u });
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@
|
|||
"l-list": "@oak-frontend-base/miniprogram_npm/lin-ui/list/index",
|
||||
"l-radio": "@oak-frontend-base/miniprogram_npm/lin-ui/radio/index",
|
||||
"l-radio-group": "@oak-frontend-base/miniprogram_npm/lin-ui/radio-group/index",
|
||||
"l-checkbox-group": "@oak-frontend-base/miniprogram_npm/lin-ui/checkbox-group/index",
|
||||
"l-checkbox": "@oak-frontend-base/miniprogram_npm/lin-ui/checkbox/index",
|
||||
"l-counter": "@oak-frontend-base/miniprogram_npm/lin-ui/counter/index",
|
||||
"userEntityGrant-detail": "../../../../pages/userEntityGrant/detail/index"
|
||||
"l-switch": "@oak-frontend-base/miniprogram_npm/lin-ui/switch/index",
|
||||
"userEntityGrant-share": "../../../userEntityGrant/share/index"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,112 +1,68 @@
|
|||
<!-- index.wxml -->
|
||||
<view class="page-body">
|
||||
<block wx:if="{{!!userEntityGrantId}}">
|
||||
<l-notice-bar
|
||||
front-icon-name="notification"
|
||||
show="{{true}}"
|
||||
>
|
||||
<block wx:if="{{!!userEntityGrantId}}">
|
||||
<l-notice-bar front-icon-name="notification" show="{{true}}">
|
||||
请通过分享或者截屏二维码方式分享权限
|
||||
</l-notice-bar>
|
||||
<view class="ueg-container">
|
||||
<userEntityGrant-detail
|
||||
oakId="{{userEntityGrantId}}"
|
||||
oakAutoUnmount="{{true}}"
|
||||
oakPath="$userRelation/upsert/byUserEntityGrant-userEntityGrant/detail"
|
||||
/>
|
||||
<view
|
||||
class="share"
|
||||
>
|
||||
<l-button
|
||||
size="medium"
|
||||
type="success"
|
||||
open-type="share"
|
||||
>
|
||||
<userEntityGrant-share oakId="{{userEntityGrantId}}" oakAutoUnmount="{{true}}" oakPath="$userRelation/upsert/byUserEntityGrant-userEntityGrant/detail" />
|
||||
<view class="share">
|
||||
<l-button size="medium" type="success" open-type="share">
|
||||
分享
|
||||
</l-button>
|
||||
</view
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="list-item">
|
||||
<view class="label">权限:</view>
|
||||
<view class="value">
|
||||
<l-radio-group
|
||||
placement="row"
|
||||
l-class="radio-container"
|
||||
bind:linchange="setRelationMp"
|
||||
current="{{userEntityGrant.relationId}}"
|
||||
>
|
||||
<l-radio
|
||||
wx:for-items="{{relations}}"
|
||||
wx:key="index"
|
||||
key="{{item.id}}"
|
||||
l-class="radio"
|
||||
size="48rpx"
|
||||
>
|
||||
{{item.display || t(entity + ':r.' + item.name)}}
|
||||
</l-radio>
|
||||
</l-radio-group>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="list-item">
|
||||
<view class="label">人次:</view>
|
||||
<view class="label">{{t('userEntityGrant:attr.relationIds')}}:</view>
|
||||
<view class="value">
|
||||
<l-radio-group
|
||||
placement="row"
|
||||
l-class="radio-container"
|
||||
bind:linchange="setNumberMp"
|
||||
current="{{userEntityGrant.number}}"
|
||||
>
|
||||
<l-radio
|
||||
wx:key="1"
|
||||
key="1"
|
||||
size="48rpx"
|
||||
l-class="radio"
|
||||
>
|
||||
单人次
|
||||
</l-radio>
|
||||
<l-radio
|
||||
wx:key="10000"
|
||||
key="10000"
|
||||
size="48rpx"
|
||||
>
|
||||
不限人次
|
||||
</l-radio>
|
||||
</l-radio-group>
|
||||
<l-checkbox-group placement="row" bind:linchange="setRelationMp">
|
||||
<l-checkbox wx:for-items="{{relations}}" wx:key="index" key="{{item.id}}" l-class="radio" size="48rpx" checked="{{item.checked}}">
|
||||
{{item.display || t(entity + ':r.' + item.name)}}
|
||||
</l-checkbox>
|
||||
</l-checkbox-group>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block wx:if="{{userEntityGrant.relationIds && userEntityGrant.relationIds.length > 1}}">
|
||||
<view class="list-item">
|
||||
<view class="label">{{t('userEntityGrant:attr.rule')}}:</view>
|
||||
<view class="value">
|
||||
<l-radio-group placement="row" l-class="radio-container" bind:linchange="setRuleMp" current="{{userEntityGrant.rule}}">
|
||||
<l-radio wx:for-items="{{rules}}" wx:key="index" key="{{item}}" size="48rpx">
|
||||
{{t('userEntityGrant:v.rule.' + item)}}
|
||||
</l-radio>
|
||||
</l-radio-group>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:if="{{ userEntityGrant.type === 'grant' }}">
|
||||
<view class="list-item">
|
||||
<view class="label">{{t('multiple')}}:</view>
|
||||
<view class="value">
|
||||
<l-switch checked="{{ userEntityGrant.multiple || false }}" size="50rpx" bind:linchange="setMultipleMp" />
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="list-item">
|
||||
<view class="label">有效期:</view>
|
||||
<view class="label">{{t('userEntityGrant:attr.expiresAt')}}:</view>
|
||||
<view class="value-period">
|
||||
<l-counter
|
||||
count="{{userEntityGrant.period}}"
|
||||
max="{{ maxes[unit] }}"
|
||||
min="1"
|
||||
round-float="{{true}}"
|
||||
bind:linchange="setPeriodMp"
|
||||
/>
|
||||
<!-- <view style="margin-left: 30rpx">
|
||||
分钟
|
||||
</view> -->
|
||||
<l-counter count="{{period}}" max="{{ maxes[unit] }}" min="1" round-float="{{true}}" bind:linchange="setPeriodMp" />
|
||||
<picker range="{{unitArr}}" range-key="label" value="{{unitIndex}}" bind:change="setUnitMp">
|
||||
<view class="unit-box">
|
||||
<view class="unit">
|
||||
<view class="unit">
|
||||
{{unitArr[unitIndex].label}}
|
||||
</view>
|
||||
|
||||
<l-icon l-class="icon" name="down" size="18" />
|
||||
</view>
|
||||
|
||||
<l-icon l-class="icon" name="down" size="18" />
|
||||
</view>
|
||||
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view style="flex: 1" />
|
||||
<l-button
|
||||
size="long"
|
||||
type="default"
|
||||
bind:lintap="confirm"
|
||||
>
|
||||
确定
|
||||
<l-button size="long" type="default" bind:lintap="confirm">
|
||||
{{t('common::action.confirm')}}
|
||||
</l-button>
|
||||
</block>
|
||||
</view>
|
||||
|
|
@ -6,7 +6,7 @@ export default function render(props) {
|
|||
const { relations, userEntityGrant, userEntityGrantId, period, unit, maxes, oakExecutable, rules, } = props.data;
|
||||
const { relationIds, type, rule, multiple, relationEntity } = userEntityGrant || {};
|
||||
const { update, t, onBack, confirm, setInit, setPeriod, setUnit } = props.methods;
|
||||
const P = !!userEntityGrantId ? (_jsxs(_Fragment, { children: [_jsx(Alert, { showIcon: true, message: t('shareCode'), type: "info", style: { marginBottom: 16 } }), _jsx(UserEntityGrantShare, { showBack: false, oakId: userEntityGrantId, oakAutoUnmount: true, oakPath: "$userRelation/upsert/byUserEntityGrant-userEntityGrant/detail" }), _jsx("div", { style: {
|
||||
const P = !!userEntityGrantId ? (_jsxs(_Fragment, { children: [_jsx(Alert, { showIcon: true, message: t('shareCode'), type: "info", style: { marginBottom: 16 } }), _jsx(UserEntityGrantShare, { oakId: userEntityGrantId, oakAutoUnmount: true, oakPath: "$userRelation/upsert/byUserEntityGrant-userEntityGrant/detail" }), _jsx("div", { style: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue