修改了user相关的一些页面和上下文中增加了allowUserUpdate的接口

This commit is contained in:
Xu Chang 2022-12-14 18:06:00 +08:00
parent 844729b0ce
commit 807321ac2f
39 changed files with 565 additions and 382 deletions

View File

@ -13,7 +13,7 @@ var checkers = [
}, },
{ {
type: 'relation', type: 'relation',
action: ['play', 'remove', 'disable', 'enable'], action: ['remove', 'disable', 'enable'],
entity: 'user', entity: 'user',
relationFilter: function () { relationFilter: function () {
// 只有root才能进行操作 // 只有root才能进行操作
@ -22,17 +22,17 @@ var checkers = [
errMsg: '越权操作', errMsg: '越权操作',
}, },
{ {
type: 'data', type: 'relation',
action: 'play', action: ['play'],
entity: 'user', entity: 'user',
checker: function (data) { relationFilter: function (operation, context) {
// 不记得什么意思了 if (!context.isReallyRoot()) {
/* const token = context.getToken(); // 只有root才能进行操作
const { userId } = token!; throw new types_1.OakUserUnpermittedException();
if (userId === operation.filter!.id) { }
throw new OakRowInconsistencyException(); return undefined;
} */
}, },
errMsg: '越权操作'
}, },
{ {
type: 'data', type: 'data',

View File

@ -5,15 +5,13 @@ exports.default = OakComponent({
properties: { properties: {
actions: Array, actions: Array,
actionDescriptions: Object, actionDescriptions: Object,
show: { iconSize: String,
type: Boolean,
value: false,
},
}, },
methods: { methods: {
onClick: function (action) { onClickMp: function (e) {
var onActionClick = this.props.onActionClick; var index = e.detail.index;
onActionClick(action); var action = this.props.actions[index];
this.triggerEvent('action', { action: action });
}, },
}, },
observers: { observers: {

View File

@ -1,6 +1,7 @@
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"oak-icon": "../../icon/index",
"l-button": "../../../miniprogram_npm/lin-ui/button/index", "l-button": "../../../miniprogram_npm/lin-ui/button/index",
"l-icon": "../../../miniprogram_npm/lin-ui/icon/index", "l-icon": "../../../miniprogram_npm/lin-ui/icon/index",
"l-grid": "../../../miniprogram_npm/lin-ui/grid/index", "l-grid": "../../../miniprogram_npm/lin-ui/grid/index",

View File

@ -1,24 +1,10 @@
@import "../../../config/styles/mp/index.less"; @import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less"; @import "../../../config/styles/mp/mixins.less";
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.grid-item {
min-width: 25%;
padding: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
}
.block { .block {
width: 176rpx; width: 176rpx;
height: 176rpx; height: 176rpx;
background: #fff; background: transparent;
color: #333; color: #333;
display: flex; display: flex;
} }
@ -36,20 +22,9 @@
flex-direction: column; flex-direction: column;
padding: 32rpx; padding: 32rpx;
} }
.five-grid {
position: unset;
}
.external-class-content { .label {
padding: 32rpx 0 !important; margin-top: 16rpx;
} font-size: xx-small;
color: @oak-color-primary;
.image-icon {
width: 96rpx !important;
height: 96rpx !important;
}
.image {
width: 100%;
height: 100%;
} }

View File

@ -8,7 +8,6 @@ exports.default = OakComponent({
}, },
methods: { methods: {
printDebugStore: function (e) { printDebugStore: function (e) {
console.log(e);
console.log(this.features.cache.getFullData()); console.log(this.features.cache.getFullData());
}, },
printCachedStore: function () { printCachedStore: function () {

View File

@ -9,6 +9,7 @@ export declare class BackendRuntimeContext<ED extends EntityDict> extends AsyncC
private application?; private application?;
private token?; private token?;
private amIRoot?; private amIRoot?;
private amIReallyRoot?;
private rootMode?; private rootMode?;
protected initialize(data?: SerializedData): Promise<void>; protected initialize(data?: SerializedData): Promise<void>;
getApplicationId(): ED["application"]["Schema"]["id"] | undefined; getApplicationId(): ED["application"]["Schema"]["id"] | undefined;
@ -19,5 +20,7 @@ export declare class BackendRuntimeContext<ED extends EntityDict> extends AsyncC
getCurrentUserId(allowUnloggedIn?: boolean): string; getCurrentUserId(allowUnloggedIn?: boolean): string;
toString(): string; toString(): string;
isRoot(): boolean; isRoot(): boolean;
isReallyRoot(): boolean;
sendMessage(data: ED['message']['CreateSingle']['data']): Promise<import("oak-domain/lib/types").OperationResult<ED>>; sendMessage(data: ED['message']['CreateSingle']['data']): Promise<import("oak-domain/lib/types").OperationResult<ED>>;
allowUserUpdate(): boolean;
} }

View File

@ -17,17 +17,17 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
} }
BackendRuntimeContext.prototype.initialize = function (data) { BackendRuntimeContext.prototype.initialize = function (data) {
return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__awaiter(this, void 0, void 0, function () {
var appId, tokenValue, result, result, token, user, _a, userState, userRole$user, err_1; var appId, tokenValue, result, result, token, user, player, userRole$user, userRole$player, err_1;
return tslib_1.__generator(this, function (_b) { return tslib_1.__generator(this, function (_a) {
switch (_b.label) { switch (_a.label) {
case 0: case 0:
if (!data) return [3 /*break*/, 11]; if (!data) return [3 /*break*/, 11];
return [4 /*yield*/, this.begin()]; return [4 /*yield*/, this.begin()];
case 1: case 1:
_b.sent(); _a.sent();
_b.label = 2; _a.label = 2;
case 2: case 2:
_b.trys.push([2, 8, , 10]); _a.trys.push([2, 8, , 10]);
appId = data.a, tokenValue = data.t; appId = data.a, tokenValue = data.t;
if (!appId) return [3 /*break*/, 4]; if (!appId) return [3 /*break*/, 4];
return [4 /*yield*/, this.select('application', { return [4 /*yield*/, this.select('application', {
@ -61,10 +61,10 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
blockTrigger: true, blockTrigger: true,
})]; })];
case 3: case 3:
result = _b.sent(); result = _a.sent();
(0, assert_1.default)(result.length > 0, "\u6784\u5EFABackendRuntimeContext\u5BF9\u5E94appId\u300C".concat(appId, "\u300D\u627E\u4E0D\u5230application")); (0, assert_1.default)(result.length > 0, "\u6784\u5EFABackendRuntimeContext\u5BF9\u5E94appId\u300C".concat(appId, "\u300D\u627E\u4E0D\u5230application"));
this.application = result[0]; this.application = result[0];
_b.label = 4; _a.label = 4;
case 4: case 4:
if (!tokenValue) return [3 /*break*/, 6]; if (!tokenValue) return [3 /*break*/, 6];
return [4 /*yield*/, this.select('token', { return [4 /*yield*/, this.select('token', {
@ -72,6 +72,22 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
id: 1, id: 1,
userId: 1, userId: 1,
playerId: 1, playerId: 1,
player: {
id: 1,
userState: 1,
userRole$user: {
$entity: 'userRole',
data: {
id: 1,
userId: 1,
roleId: 1,
role: {
id: 1,
name: 1,
}
},
},
},
ableState: 1, ableState: 1,
user: { user: {
id: 1, id: 1,
@ -98,7 +114,7 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
blockTrigger: true, blockTrigger: true,
})]; })];
case 5: case 5:
result = _b.sent(); result = _a.sent();
if (result.length === 0) { if (result.length === 0) {
console.log("\u6784\u5EFABackendRuntimeContext\u5BF9\u5E94tokenValue\u300C".concat(tokenValue, "\u627E\u4E0D\u5230\u76F8\u5173\u7684user")); console.log("\u6784\u5EFABackendRuntimeContext\u5BF9\u5E94tokenValue\u300C".concat(tokenValue, "\u627E\u4E0D\u5230\u76F8\u5173\u7684user"));
throw new Exception_1.OakTokenExpiredException(); throw new Exception_1.OakTokenExpiredException();
@ -107,29 +123,28 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
if (token.ableState === 'disabled') { if (token.ableState === 'disabled') {
throw new Exception_1.OakTokenExpiredException(); throw new Exception_1.OakTokenExpiredException();
} }
user = token.user; user = token.user, player = token.player;
_a = user, userState = _a.userState, userRole$user = _a.userRole$user; userRole$user = user.userRole$user;
/* if (['disabled', 'merged'].includes(userState as string)) {
throw new OakUserDisabledException();
} */
this.amIRoot = userRole$user.length > 0 && userRole$user.find(function (ele) { return ele.role.name === 'root'; }); this.amIRoot = userRole$user.length > 0 && userRole$user.find(function (ele) { return ele.role.name === 'root'; });
userRole$player = player.userRole$user;
this.amIReallyRoot = userRole$player.length > 0 && userRole$player.find(function (ele) { return ele.role.name === 'root'; });
this.token = token; this.token = token;
_b.label = 6; _a.label = 6;
case 6: return [4 /*yield*/, this.commit()]; case 6: return [4 /*yield*/, this.commit()];
case 7: case 7:
_b.sent(); _a.sent();
return [3 /*break*/, 10]; return [3 /*break*/, 10];
case 8: case 8:
err_1 = _b.sent(); err_1 = _a.sent();
return [4 /*yield*/, this.rollback()]; return [4 /*yield*/, this.rollback()];
case 9: case 9:
_b.sent(); _a.sent();
throw err_1; throw err_1;
case 10: return [3 /*break*/, 12]; case 10: return [3 /*break*/, 12];
case 11: case 11:
// 否则是后台模式默认用root // 否则是后台模式默认用root
this.rootMode = true; this.rootMode = true;
_b.label = 12; _a.label = 12;
case 12: return [2 /*return*/]; case 12: return [2 /*return*/];
} }
}); });
@ -188,6 +203,9 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
} }
return !!this.amIRoot; return !!this.amIRoot;
}; };
BackendRuntimeContext.prototype.isReallyRoot = function () {
return !!this.amIReallyRoot;
};
BackendRuntimeContext.prototype.sendMessage = function (data) { BackendRuntimeContext.prototype.sendMessage = function (data) {
return this.operate('message', { return this.operate('message', {
action: 'create', action: 'create',
@ -196,6 +214,24 @@ var BackendRuntimeContext = /** @class */ (function (_super) {
dontCollect: true, dontCollect: true,
}); });
}; };
BackendRuntimeContext.prototype.allowUserUpdate = function () {
var _a;
var userInfo = (_a = this.token) === null || _a === void 0 ? void 0 : _a.user;
if (userInfo) {
var userState = userInfo.userState;
if (userState === 'disabled') {
throw new Exception_1.OakUserDisabledException('您的帐号已经被禁用,请联系客服');
}
else if (['shadow', 'merged'].includes(userState)) {
throw new Exception_1.OakTokenExpiredException('您的登录状态有异常,请重新登录 ');
}
else {
(0, assert_1.default)(userState === 'normal');
}
return true;
}
throw new Exception_2.OakUnloggedInException('您尚未登录');
};
return BackendRuntimeContext; return BackendRuntimeContext;
}(AsyncRowStore_1.AsyncContext)); }(AsyncRowStore_1.AsyncContext));
exports.BackendRuntimeContext = BackendRuntimeContext; exports.BackendRuntimeContext = BackendRuntimeContext;

View File

@ -23,5 +23,7 @@ export declare class FrontendRuntimeContext<ED extends EntityDict, Cxt extends B
getCurrentUserId(allowUnloggedIn?: boolean): string | undefined; getCurrentUserId(allowUnloggedIn?: boolean): string | undefined;
toString(): string; toString(): string;
isRoot(): boolean; isRoot(): boolean;
isReallyRoot(): boolean;
allowUserUpdate(): boolean;
} }
export {}; export {};

View File

@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.FrontendRuntimeContext = void 0; exports.FrontendRuntimeContext = void 0;
var tslib_1 = require("tslib"); var tslib_1 = require("tslib");
var SyncRowStore_1 = require("oak-domain/lib/store/SyncRowStore"); var SyncRowStore_1 = require("oak-domain/lib/store/SyncRowStore");
var Exception_1 = require("../types/Exception");
var console_1 = require("console");
var types_1 = require("oak-domain/lib/types");
var FrontendRuntimeContext = /** @class */ (function (_super) { var FrontendRuntimeContext = /** @class */ (function (_super) {
tslib_1.__extends(FrontendRuntimeContext, _super); tslib_1.__extends(FrontendRuntimeContext, _super);
function FrontendRuntimeContext(store, application, token) { function FrontendRuntimeContext(store, application, token) {
@ -57,6 +60,28 @@ var FrontendRuntimeContext = /** @class */ (function (_super) {
var _a; var _a;
return ((_a = this.token) === null || _a === void 0 ? void 0 : _a.isRoot()) || false; return ((_a = this.token) === null || _a === void 0 ? void 0 : _a.isRoot()) || false;
}; };
FrontendRuntimeContext.prototype.isReallyRoot = function () {
var _a;
return ((_a = this.token) === null || _a === void 0 ? void 0 : _a.isReallyRoot()) || false;
};
FrontendRuntimeContext.prototype.allowUserUpdate = function () {
var _a;
var userInfo = (_a = this.token) === null || _a === void 0 ? void 0 : _a.getUserInfo();
if (userInfo) {
var userState = userInfo.userState;
if (userState === 'disabled') {
throw new Exception_1.OakUserDisabledException('您的帐号已经被禁用,请联系客服');
}
else if (['shadow', 'merged'].includes(userState)) {
throw new Exception_1.OakTokenExpiredException('您的登录状态有异常,请重新登录 ');
}
else {
(0, console_1.assert)(userState === 'normal');
}
return true;
}
throw new types_1.OakUnloggedInException('您尚未登录');
};
return FrontendRuntimeContext; return FrontendRuntimeContext;
}(SyncRowStore_1.SyncContext)); }(SyncRowStore_1.SyncContext));
exports.FrontendRuntimeContext = FrontendRuntimeContext; exports.FrontendRuntimeContext = FrontendRuntimeContext;

View File

@ -6,4 +6,5 @@ export interface RuntimeContext {
getToken(allowUnloggedIn?: boolean): Partial<EntityDict['token']['Schema']> | undefined; getToken(allowUnloggedIn?: boolean): Partial<EntityDict['token']['Schema']> | undefined;
getTokenValue(allowUnloggedIn?: boolean): string | undefined; getTokenValue(allowUnloggedIn?: boolean): string | undefined;
isRoot(): boolean; isRoot(): boolean;
isReallyRoot(): boolean;
} }

View File

@ -22,5 +22,10 @@ export declare class Token<ED extends EntityDict, Cxt extends BackendRuntimeCont
getUserId(allowUnloggedIn?: boolean): NonNullable<ED["token"]["Schema"]["userId"]> | undefined; getUserId(allowUnloggedIn?: boolean): NonNullable<ED["token"]["Schema"]["userId"]> | undefined;
getUserInfo(): ED["token"]["Schema"]["user"] | undefined; getUserInfo(): ED["token"]["Schema"]["user"] | undefined;
isRoot(): boolean; isRoot(): boolean;
/**
* token的player到底是不是root
* @returns
*/
isReallyRoot(): boolean;
sendCaptcha(mobile: string): Promise<string>; sendCaptcha(mobile: string): Promise<string>;
} }

View File

@ -39,6 +39,14 @@ var userProjection = {
userId: 1, userId: 1,
}, },
}, },
userRole$user: {
$entity: 'userRole',
data: {
id: 1,
userId: 1,
roleId: 1,
},
},
}; };
var tokenProjection = { var tokenProjection = {
id: 1, id: 1,
@ -227,6 +235,18 @@ var Token = /** @class */ (function (_super) {
} }
}; };
Token.prototype.isRoot = function () { Token.prototype.isRoot = function () {
var _a;
var token = this.getToken(true);
var userRole$user = (_a = token === null || token === void 0 ? void 0 : token.user) === null || _a === void 0 ? void 0 : _a.userRole$user;
return !!(userRole$user &&
(userRole$user === null || userRole$user === void 0 ? void 0 : userRole$user.length) > 0 &&
userRole$user.find(function (ele) { return ele.roleId === constants_1.ROOT_ROLE_ID; }));
};
/**
* 这个是指token的player到底是不是root
* @returns
*/
Token.prototype.isReallyRoot = function () {
var _a; var _a;
var token = this.getToken(true); var token = this.getToken(true);
var userRole$user = (_a = token === null || token === void 0 ? void 0 : token.player) === null || _a === void 0 ? void 0 : _a.userRole$user; var userRole$user = (_a = token === null || token === void 0 ? void 0 : token.player) === null || _a === void 0 ? void 0 : _a.userRole$user;

View File

@ -91,31 +91,34 @@ exports.default = OakComponent({
actionDescriptions: { actionDescriptions: {
accept: { accept: {
icon: { icon: {
name: 'pan_tool', name: 'circle-check',
type: 'far',
}, },
label: '通过', label: '通过',
}, },
activate: { activate: {
icon: { icon: {
name: 'check', name: 'chart-line',
}, },
label: '激活', label: '激活',
}, },
disable: { disable: {
icon: { icon: {
name: 'flash_off', name: 'bell-slash',
type: 'far',
}, },
label: '禁用', label: '禁用',
}, },
enable: { enable: {
icon: { icon: {
name: 'flash_on', name: 'bell',
type: 'far',
}, },
label: '启用', label: '启用',
}, },
remove: { remove: {
icon: { icon: {
name: 'clear', name: 'trash',
}, },
label: '删除', label: '删除',
}, },
@ -127,13 +130,13 @@ exports.default = OakComponent({
}, },
verify: { verify: {
icon: { icon: {
name: 'how_to_reg', name: 'certificate',
}, },
label: '验证', label: '验证',
}, },
play: { play: {
icon: { icon: {
name: 'play_circle', name: 'person-praying',
}, },
label: '切换', label: '切换',
}, },
@ -184,5 +187,9 @@ exports.default = OakComponent({
}); });
}); });
}, },
onActionClickMp: function (e) {
var action = e.detail.action;
return this.onActionClick(action);
}
}, },
}); });

View File

@ -32,6 +32,40 @@
padding: 0rpx 10rpx; padding: 0rpx 10rpx;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0;
background-color: #fff; 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;
}
}
} }

View File

@ -60,10 +60,10 @@
font-size: small; font-size: small;
.label { .label {
min-width: 140rpx; min-width: 140rpx;
color: @oak-text-color-secondary; color: @oak-text-color-primary;
} }
.value { .value {
color: @oak-text-color-primary; color: @oak-text-color-secondary;
margin-left: 30rpx; margin-left: 30rpx;
} }
} }

View File

@ -20,11 +20,6 @@ var IDCardTypeOptions = [
value: 'Mainland-passport', label: '港澳通行证', value: 'Mainland-passport', label: '港澳通行证',
} }
]; ];
var PICKER_KEY = {
SEX: 'sex',
IDCARD: 'idCard',
BIRTH: 'birth'
};
exports.default = OakComponent({ exports.default = OakComponent({
entity: 'user', entity: 'user',
projection: { projection: {
@ -41,89 +36,81 @@ exports.default = OakComponent({
formData: function (_a) { formData: function (_a) {
var user = _a.data; var user = _a.data;
var _b = user || {}, birth = _b.birth, gender = _b.gender, idCardType = _b.idCardType; var _b = user || {}, birth = _b.birth, gender = _b.gender, idCardType = _b.idCardType;
var birthText = birth && new Date(birth).toLocaleDateString(); var birthDate = birth && new Date(birth);
var birthText = birthDate && birthDate.toLocaleDateString();
var birthDayValue = birthDate && "".concat(birthDate.getFullYear(), "-").concat(birthDate.getMonth() + 1, "-").concat(birthDate.getDate());
var GenderDict = { var GenderDict = {
male: '男', male: '男',
female: '女', female: '女',
}; };
var genderText = gender && GenderDict[gender]; var genderOption = gender && GenderOptions.find(function (ele) { return ele.value === gender; });
var genderIndex = gender && GenderOptions.find(function (ele) { return ele.value === gender; }); var genderText = genderOption && genderOption.label;
var IdCardTypeDict = { var genderOptionIndex = genderOption && GenderOptions.indexOf(genderOption);
'ID-Card': '身份证', var idCardTypeOption = idCardType && IDCardTypeOptions.find(function (ele) { return ele.value === idCardType; });
passport: '护照', var idCardTypeText = idCardTypeOption && idCardTypeOption.label;
'Mainland-passport': '港澳通行证', var idCardTypeOptionIndex = idCardTypeOption && IDCardTypeOptions.indexOf(idCardTypeOption);
};
var idCardTypeText = idCardType && IdCardTypeDict[idCardType];
var idCardTypeIndex = idCardType && IDCardTypeOptions.find(function (ele) { return ele.value === gender; }); var idCardTypeIndex = idCardType && IDCardTypeOptions.find(function (ele) { return ele.value === gender; });
var now = new Date(); var now = new Date();
return Object.assign({}, user, { return Object.assign({}, user, {
birthText: birthText, birthText: birthText,
birthDayValue: birthDayValue,
genderText: genderText, genderText: genderText,
idCardTypeText: idCardTypeText, idCardTypeText: idCardTypeText,
idCardTypeOptionIndex: idCardTypeOptionIndex,
oldestBirthday: "".concat(now.getFullYear() - 120, "-01-01"), oldestBirthday: "".concat(now.getFullYear() - 120, "-01-01"),
today: "".concat(now.getFullYear(), "-").concat(now.getMonth() + 1, "-").concat(now.getDate()), today: "".concat(now.getFullYear(), "-").concat(now.getMonth() + 1, "-").concat(now.getDate()),
genderIndex: genderIndex, genderOptionIndex: genderOptionIndex,
idCardTypeIndex: idCardTypeIndex, idCardTypeIndex: idCardTypeIndex,
}); });
}, },
data: { data: {
birthEnd: '',
GenderOptions: GenderOptions, GenderOptions: GenderOptions,
IDCardTypeOptions: IDCardTypeOptions, IDCardTypeOptions: IDCardTypeOptions,
PICKER_KEY: PICKER_KEY,
birthVisible: false, birthVisible: false,
}, },
lifetimes: {
ready: function () {
var today = new Date();
var birthEnd = "".concat(today.getFullYear(), "-").concat(today.getMonth() + 1, "-").concat(today.getDate());
this.setState({ birthEnd: birthEnd });
}
},
methods: { methods: {
setValue: function (input) { setValueMp: function (input) {
var _a, _b, _c; var _a;
console.log(input, 123); var detail = input.detail, dataset = input.target.dataset;
var _d = this.resolveInput(input), dataset = _d.dataset, value = _d.value; var attr = dataset.attr;
var key = dataset.key; var value = detail.value;
if (['sex', 'idCard'].includes(key)) { this.update((_a = {}, _a[attr] = value, _a));
this.update((_a = {}, _a[dataset.attr] = value[0], _a));
return;
}
if (key === 'birth') {
this.update((_b = {}, _b[dataset.attr] = value, _b));
this.setState({
birthVisible: false,
});
return;
}
this.update((_c = {}, _c[dataset.attr] = value[0], _c));
}, },
confirm: function () { confirmMp: function () {
return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) { return tslib_1.__generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: return [4 /*yield*/, this.execute()]; case 0: return [4 /*yield*/, this.execute()];
case 1: case 1:
_a.sent(); _a.sent();
if (this.props.oakFrom === 'user:manage:list') {
this.navigateBack(); this.navigateBack();
}
else if (this.props.oakFrom === 'user:manage:detail') {
this.navigateBack();
}
return [2 /*return*/]; return [2 /*return*/];
} }
}); });
}); });
}, },
onClickPicker: function (e) { onBirthChange: function (e) {
var _a; var value = e.detail.value;
var _b; var birth = new Date(value);
var key = ((_b = e === null || e === void 0 ? void 0 : e.currentTarget) === null || _b === void 0 ? void 0 : _b.dataset).key; this.update({ birth: birth });
this.setState((_a = {},
_a["".concat(key, "Visible")] = true,
_a));
}, },
onPickerClose: function (e) { onIdCardTypeChange: function (e) {
var _a; var index = e.detail.value;
var _b; var value = IDCardTypeOptions[index].value;
var key = ((_b = e === null || e === void 0 ? void 0 : e.currentTarget) === null || _b === void 0 ? void 0 : _b.dataset).key; this.update({ idCardType: value });
this.setState((_a = {}, },
_a["".concat(key, "Visible")] = false, onGenderChange: function (e) {
_a)); var index = e.detail.value;
var value = GenderOptions[index].value;
this.update({ gender: value });
}, },
}, },
}); });

View File

@ -1,12 +1,9 @@
{ {
"navigationBarTitleText": "修改用户信息", "navigationBarTitleText": "修改用户信息",
"usingComponents": { "usingComponents": {
"t-button": "../../../../miniprogram_npm/tdesign/button/button", "l-button": "../../../../miniprogram_npm/lin-ui/button/index",
"t-picker": "../../../../miniprogram_npm/tdesign/picker/picker", "l-list": "../../../../miniprogram_npm/lin-ui/list/index",
"t-picker-item": "../../../../miniprogram_npm/tdesign/picker/picker-item", "l-input": "../../../../miniprogram_npm/lin-ui/input/index",
"t-date-time-picker": "../../../../miniprogram_npm/tdesign/date-time-picker/date-time-picker", "l-icon": "../../../../miniprogram_npm/lin-ui/icon/index"
"t-cell": "../../../../miniprogram_npm/tdesign/cell/cell",
"t-input": "../../../../miniprogram_npm/tdesign/input/input",
"t-icon": "../../../../miniprogram_npm/tdesign/icon/icon"
} }
} }

View File

@ -16,22 +16,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #fff; background-color: #fff;
}
.pannel-item {
display: flex;
align-items: center;
height: 96rpx;
padding: 0 32rpx;
font-size: 32rpx;
background-color: #fff;
}
.pannel-label { .label {
width: 160rpx; color: @oak-text-color-primary;
margin-right: 32rpx;
} }
.pannel-text {
flex: 1;
opacity: 0.9;
} }

View File

@ -5,6 +5,7 @@ var uuid_1 = require("oak-domain/lib/utils/uuid");
var assert_1 = require("oak-domain/lib/utils/assert"); var assert_1 = require("oak-domain/lib/utils/assert");
var constants_1 = require("../constants"); var constants_1 = require("../constants");
var randomUser_1 = require("../utils/randomUser"); var randomUser_1 = require("../utils/randomUser");
var types_1 = require("oak-domain/lib/types");
var NO_ANY_USER = true; var NO_ANY_USER = true;
var triggers = [ var triggers = [
{ {
@ -116,16 +117,20 @@ var triggers = [
entity: 'user', entity: 'user',
action: 'play', action: 'play',
when: 'after', when: 'after',
fn: function (_a, context) { fn: function (_a, context, option) {
var operation = _a.operation; var operation = _a.operation;
return tslib_1.__awaiter(void 0, void 0, void 0, function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
var filter, id; var filter, token, id, userId;
return tslib_1.__generator(this, function (_b) { return tslib_1.__generator(this, function (_b) {
switch (_b.label) { switch (_b.label) {
case 0: case 0:
filter = operation.filter; filter = operation.filter;
(0, assert_1.assert)(filter.id); (0, assert_1.assert)(filter.id);
id = context.getToken().id; token = context.getToken();
id = token.id, userId = token.userId;
if (userId === filter.id) {
throw new types_1.OakRowInconsistencyException(undefined, '您已经是当前用户');
}
return [4 /*yield*/, context.operate('token', { return [4 /*yield*/, context.operate('token', {
id: (0, uuid_1.generateNewId)(), id: (0, uuid_1.generateNewId)(),
action: 'update', action: 'update',
@ -135,9 +140,7 @@ var triggers = [
filter: { filter: {
id: id, id: id,
} }
}, { }, option)];
dontCollect: true,
})];
case 1: case 1:
_b.sent(); _b.sent();
return [2 /*return*/, 1]; return [2 /*return*/, 1];

View File

@ -14,7 +14,7 @@ const checkers: Checker<EntityDict, 'user', RuntimeCxt> [] = [
}, },
{ {
type: 'relation', type: 'relation',
action: ['play', 'remove', 'disable', 'enable'], action: ['remove', 'disable', 'enable'],
entity: 'user', entity: 'user',
relationFilter: () => { relationFilter: () => {
// 只有root才能进行操作 // 只有root才能进行操作
@ -23,17 +23,17 @@ const checkers: Checker<EntityDict, 'user', RuntimeCxt> [] = [
errMsg: '越权操作', errMsg: '越权操作',
}, },
{ {
type: 'data', type: 'relation',
action: 'play', action: ['play'],
entity: 'user', entity: 'user',
checker: (data) => { relationFilter: (operation, context) => {
// 不记得什么意思了 if (!context.isReallyRoot()) {
/* const token = context.getToken(); // 只有root才能进行操作
const { userId } = token!; throw new OakUserUnpermittedException();
if (userId === operation.filter!.id) { }
throw new OakRowInconsistencyException(); return undefined;
} */
}, },
errMsg: '越权操作'
}, },
{ {
type: 'data', type: 'data',

View File

@ -1,6 +1,7 @@
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"oak-icon": "../../icon/index",
"l-button": "../../../miniprogram_npm/lin-ui/button/index", "l-button": "../../../miniprogram_npm/lin-ui/button/index",
"l-icon": "../../../miniprogram_npm/lin-ui/icon/index", "l-icon": "../../../miniprogram_npm/lin-ui/icon/index",
"l-grid": "../../../miniprogram_npm/lin-ui/grid/index", "l-grid": "../../../miniprogram_npm/lin-ui/grid/index",

View File

@ -1,24 +1,10 @@
@import "../../../config/styles/mp/index.less"; @import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less"; @import "../../../config/styles/mp/mixins.less";
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
}
.grid-item {
min-width: 25%;
padding: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
}
.block { .block {
width: 176rpx; width: 176rpx;
height: 176rpx; height: 176rpx;
background: #fff; background: transparent;
color: #333; color: #333;
display: flex; display: flex;
} }
@ -36,20 +22,9 @@
flex-direction: column; flex-direction: column;
padding: 32rpx; padding: 32rpx;
} }
.five-grid {
position: unset;
}
.external-class-content { .label {
padding: 32rpx 0 !important; margin-top: 16rpx;
} font-size: xx-small;
color: @oak-color-primary;
.image-icon {
width: 96rpx !important;
height: 96rpx !important;
}
.image {
width: 100%;
height: 100%;
} }

View File

@ -3,15 +3,13 @@ export default OakComponent({
properties: { properties: {
actions: Array, actions: Array,
actionDescriptions: Object, actionDescriptions: Object,
show: { iconSize: String,
type: Boolean,
value: false,
},
}, },
methods: { methods: {
onClick(action: string) { onClickMp(e: WechatMiniprogram.TouchEvent) {
const { onActionClick } = this.props; const { index } = e.detail;
onActionClick(action); const action = this.props.actions[index];
this.triggerEvent('action', { action });
}, },
}, },

View File

@ -1,10 +1,10 @@
<view class="block block--bottom"> <view class="block block--bottom">
<view class="btn-box"> <view class="btn-box">
<l-grid row-num="{{5}}"> <l-grid row-num="{{4}}">
<block wx:for="{{actionss}}" wx:key="index"> <block wx:for="{{actionss}}" wx:key="index">
<l-grid-item bind:lintap="onClick" data-index="{{index}}" key="{{index}}" slot="{{index}}"> <l-grid-item bind:linitemtap="onClickMp" data-index="{{index}}" key="{{index}}" slot="{{index}}">
<l-icon class="image" name="{{item.icon.name}}" slot="image" /> <oak-icon class="image" name="{{item.icon.name}}" type="{{item.icon.type || 'fas'}}" size="{{iconSize || 66}}" slot="image" />
<text>{{item.text}}</text> <text class='label'>{{item.label}}</text>
</l-grid-item> </l-grid-item>
</block> </block>
</l-grid> </l-grid>

View File

@ -7,7 +7,6 @@ export default OakComponent({
}, },
methods: { methods: {
printDebugStore(e: any) { printDebugStore(e: any) {
console.log(e);
console.log(this.features.cache.getFullData()); console.log(this.features.cache.getFullData());
}, },
printCachedStore() { printCachedStore() {

View File

@ -14,6 +14,7 @@ export class BackendRuntimeContext<ED extends EntityDict> extends AsyncContext<E
private application?: Partial<ED['application']['Schema']>; private application?: Partial<ED['application']['Schema']>;
private token?: Partial<ED['token']['Schema']>; private token?: Partial<ED['token']['Schema']>;
private amIRoot?: boolean; private amIRoot?: boolean;
private amIReallyRoot?: boolean;
private rootMode?: boolean; private rootMode?: boolean;
protected async initialize(data?: SerializedData) { protected async initialize(data?: SerializedData) {
@ -65,6 +66,22 @@ export class BackendRuntimeContext<ED extends EntityDict> extends AsyncContext<E
id: 1, id: 1,
userId: 1, userId: 1,
playerId: 1, playerId: 1,
player: {
id: 1,
userState: 1,
userRole$user: {
$entity: 'userRole',
data: {
id: 1,
userId: 1,
roleId: 1,
role: {
id: 1,
name: 1,
}
},
},
},
ableState: 1, ableState: 1,
user: { user: {
id: 1, id: 1,
@ -98,14 +115,15 @@ export class BackendRuntimeContext<ED extends EntityDict> extends AsyncContext<E
if (token.ableState === 'disabled') { if (token.ableState === 'disabled') {
throw new OakTokenExpiredException(); throw new OakTokenExpiredException();
} }
const { user } = token; const { user, player } = token;
const { userState, userRole$user } = user!; const { userRole$user } = user!;
/* if (['disabled', 'merged'].includes(userState as string)) {
throw new OakUserDisabledException();
} */
this.amIRoot = (userRole$user as any).length > 0 && (userRole$user as any).find( this.amIRoot = (userRole$user as any).length > 0 && (userRole$user as any).find(
(ele: any) => ele.role.name === 'root' (ele: any) => ele.role.name === 'root'
); );
const { userRole$user: userRole$player} = player!;
this.amIReallyRoot = (userRole$player as any).length > 0 && (userRole$player as any).find(
(ele: any) => ele.role.name === 'root'
);
this.token = token; this.token = token;
} }
await this.commit(); await this.commit();
@ -178,6 +196,10 @@ export class BackendRuntimeContext<ED extends EntityDict> extends AsyncContext<E
return !!this.amIRoot; return !!this.amIRoot;
} }
isReallyRoot(): boolean {
return !!this.amIReallyRoot;
}
sendMessage(data: ED['message']['CreateSingle']['data']) { sendMessage(data: ED['message']['CreateSingle']['data']) {
return this.operate('message', { return this.operate('message', {
action: 'create', action: 'create',
@ -186,4 +208,22 @@ export class BackendRuntimeContext<ED extends EntityDict> extends AsyncContext<E
dontCollect: true, dontCollect: true,
}); });
} }
allowUserUpdate(): boolean {
const userInfo = this.token?.user;
if (userInfo) {
const { userState } = userInfo;
if (userState === 'disabled') {
throw new OakUserDisabledException('您的帐号已经被禁用,请联系客服');
}
else if (['shadow', 'merged'].includes(userState!)) {
throw new OakTokenExpiredException('您的登录状态有异常,请重新登录 ');
}
else {
assert(userState === 'normal');
}
return true;
}
throw new OakUnloggedInException('您尚未登录');
}
} }

View File

@ -9,6 +9,9 @@ import { CommonAspectDict } from 'oak-common-aspect';
import { SyncContext, SyncRowStore } from 'oak-domain/lib/store/SyncRowStore'; import { SyncContext, SyncRowStore } from 'oak-domain/lib/store/SyncRowStore';
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore'; import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
import { BackendRuntimeContext } from './BackendRuntimeContext'; import { BackendRuntimeContext } from './BackendRuntimeContext';
import { OakTokenExpiredException, OakUserDisabledException } from '../types/Exception';
import { assert } from 'console';
import { OakUnloggedInException } from 'oak-domain/lib/types';
type AspectDict<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>> = GeneralAspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>; type AspectDict<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>> = GeneralAspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>;
// 上下文被serialize后的数据内容 // 上下文被serialize后的数据内容
@ -76,4 +79,26 @@ export class FrontendRuntimeContext<
isRoot() { isRoot() {
return this.token?.isRoot() || false; return this.token?.isRoot() || false;
} }
isReallyRoot(): boolean {
return this.token?.isReallyRoot() || false;
}
allowUserUpdate(): boolean {
const userInfo = this.token?.getUserInfo();
if (userInfo) {
const { userState } = userInfo;
if (userState === 'disabled') {
throw new OakUserDisabledException('您的帐号已经被禁用,请联系客服');
}
else if (['shadow', 'merged'].includes(userState!)) {
throw new OakTokenExpiredException('您的登录状态有异常,请重新登录 ');
}
else {
assert(userState === 'normal');
}
return true;
}
throw new OakUnloggedInException('您尚未登录');
}
}; };

View File

@ -13,4 +13,6 @@ export interface RuntimeContext {
getTokenValue(allowUnloggedIn?: boolean): string | undefined; getTokenValue(allowUnloggedIn?: boolean): string | undefined;
isRoot(): boolean; isRoot(): boolean;
isReallyRoot(): boolean;
}; };

View File

@ -45,6 +45,14 @@ const userProjection: EntityDict['user']['Selection']['data'] = {
userId: 1, userId: 1,
}, },
}, },
userRole$user: {
$entity: 'userRole',
data: {
id: 1,
userId: 1,
roleId: 1,
},
},
}; };
const tokenProjection: EntityDict['token']['Selection']['data'] = { const tokenProjection: EntityDict['token']['Selection']['data'] = {
id: 1, id: 1,
@ -196,6 +204,20 @@ export class Token<
} }
isRoot(): boolean { isRoot(): boolean {
const token = this.getToken(true);
const userRole$user = token?.user?.userRole$user;
return !!(
userRole$user &&
userRole$user?.length > 0 &&
userRole$user.find((ele) => ele.roleId === ROOT_ROLE_ID)
);
}
/**
* token的player到底是不是root
* @returns
*/
isReallyRoot(): boolean {
const token = this.getToken(true); const token = this.getToken(true);
const userRole$user = token?.player?.userRole$user; const userRole$user = token?.player?.userRole$user;
return !!( return !!(

View File

@ -15,7 +15,7 @@
</block> </block>
</view> </view>
<view class="cell"> <view class="cell">
<l-list title="手机号" icon="phone" desc="{{mobileText}}" bind:lintap="goMyMobile" > <l-list title="手机号" icon="phone" right-desc="{{mobileText}}" bind:lintap="goMyMobile" >
</l-list> </l-list>
<block wx:if="{{isRoot}}"> <block wx:if="{{isRoot}}">
<l-list title="用户管理" icon="user" hover bind:lintap="goUserManage" /> <l-list title="用户管理" icon="user" hover bind:lintap="goUserManage" />

View File

@ -32,6 +32,40 @@
padding: 0rpx 10rpx; padding: 0rpx 10rpx;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0;
background-color: #fff; 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;
}
}
} }

View File

@ -100,31 +100,34 @@ export default OakComponent({
actionDescriptions: { actionDescriptions: {
accept: { accept: {
icon: { icon: {
name: 'pan_tool', name: 'circle-check',
type: 'far',
}, },
label: '通过', label: '通过',
}, },
activate: { activate: {
icon: { icon: {
name: 'check', name: 'chart-line',
}, },
label: '激活', label: '激活',
}, },
disable: { disable: {
icon: { icon: {
name: 'flash_off', name: 'bell-slash',
type: 'far',
}, },
label: '禁用', label: '禁用',
}, },
enable: { enable: {
icon: { icon: {
name: 'flash_on', name: 'bell',
type: 'far',
}, },
label: '启用', label: '启用',
}, },
remove: { remove: {
icon: { icon: {
name: 'clear', name: 'trash',
}, },
label: '删除', label: '删除',
}, },
@ -136,13 +139,13 @@ export default OakComponent({
}, },
verify: { verify: {
icon: { icon: {
name: 'how_to_reg', name: 'certificate',
}, },
label: '验证', label: '验证',
}, },
play: { play: {
icon: { icon: {
name: 'play_circle', name: 'person-praying',
}, },
label: '切换', label: '切换',
}, },
@ -175,5 +178,9 @@ export default OakComponent({
this.navigateBack(2); this.navigateBack(2);
} }
}, },
onActionClickMp(e: WechatMiniprogram.TouchEvent) {
const { action } = e.detail;
return this.onActionClick(action);
}
}, },
}); });

View File

@ -9,37 +9,81 @@
</block> </block>
</view> </view>
<view class="col"> <view class="col">
<l-list right-desc="{{nickname || '未设置'}}" is-link="{{false}}"> <l-list is-link="{{false}}">
<view slot="left-section"> <view slot="left-section" class="left">
<oak-icon name="user" /> <view class="icon">
<oak-icon name="comment-dots" />
</view>
<view class="label">
昵称 昵称
</view> </view>
</view>
<view slot="right-section" class="value">{{nickname || '未设置'}}</view>
</l-list> </l-list>
<l-list right-desc="{{name || '未设置'}}" is-link="{{false}}"> <l-list is-link="{{false}}">
<view slot="left-section"> <view slot="left-section" class="left">
<oak-icon name="signature" /> <view class="icon">
<oak-icon name="file-signature" />
</view>
<view class="label">
姓名 姓名
</view> </view>
</view>
<view slot="right-section" class="value">{{name || '未设置'}}</view>
</l-list> </l-list>
<l-list right-desc="{{mobileText}}" is-link="{{false}}"> <l-list is-link="{{false}}">
<view slot="left-section"> <view slot="left-section" class="left">
<oak-icon name="mobile" /> <view class="icon">
<oak-icon name="person-half-dress" />
</view>
<view class="label">
性别
</view>
</view>
<view slot="right-section" class="value">{{gender || '未设置'}}</view>
</l-list>
<l-list is-link="{{false}}">
<view slot="left-section" class="left">
<view class="icon">
<oak-icon name="mobile-screen" />
</view>
<view class="label">
手机号 手机号
</view> </view>
</view>
<view slot="right-section" class="value">{{mobileText}}</view>
</l-list> </l-list>
<l-list tag-position="right" tag-content="{{userState}}" tag-plain="{{true}}" is-link="{{false}}"> <l-list tag-position="right" is-link="{{false}}">
<view slot="left-section"> <view slot="left-section" class="left">
<oak-icon name="artstation" /> <view class="icon">
<oak-icon name="info" />
</view>
<view class="label">
用户状态 用户状态
</view> </view>
</view>
<view slot="right-section" class="value">
<l-tag l-class="{{stateColor[userState]}}" size="mini" shape="circle">
{{userState || '未设置'}}
</l-tag>
</view>
</l-list> </l-list>
<l-list tag-position="right" tag-content="{{idState}}" tag-plain="{{true}}" is-link="{{false}}"> <l-list tag-position="right" is-link="{{false}}">
<view slot="left-section"> <view slot="left-section" class="left">
<view class="icon">
<oak-icon name="chess-bishop" /> <oak-icon name="chess-bishop" />
</view>
<view class="label">
认证状态 认证状态
</view> </view>
</view>
<view slot="right-section" class="value">
<l-tag l-class="{{idStateColor[idState]}}" size="mini" shape="circle">
{{idState || '未设置'}}
</l-tag>
</view>
</l-list> </l-list>
</view> </view>
<view style="flex:1" /> <view style="flex:1" />
<actionPanel actions="{{oakLegalActions}}" actionDescriptions="{{actionDescriptions}}" bind:click="onActionClick" /> <actionPanel actions="{{oakLegalActions}}" actionDescriptions="{{actionDescriptions}}" bind:action="onActionClickMp" />
</view> </view>

View File

@ -60,10 +60,10 @@
font-size: small; font-size: small;
.label { .label {
min-width: 140rpx; min-width: 140rpx;
color: @oak-text-color-secondary; color: @oak-text-color-primary;
} }
.value { .value {
color: @oak-text-color-primary; color: @oak-text-color-secondary;
margin-left: 30rpx; margin-left: 30rpx;
} }
} }

View File

@ -1,12 +1,9 @@
{ {
"navigationBarTitleText": "修改用户信息", "navigationBarTitleText": "修改用户信息",
"usingComponents": { "usingComponents": {
"t-button": "../../../../miniprogram_npm/tdesign/button/button", "l-button": "../../../../miniprogram_npm/lin-ui/button/index",
"t-picker": "../../../../miniprogram_npm/tdesign/picker/picker", "l-list": "../../../../miniprogram_npm/lin-ui/list/index",
"t-picker-item": "../../../../miniprogram_npm/tdesign/picker/picker-item", "l-input": "../../../../miniprogram_npm/lin-ui/input/index",
"t-date-time-picker": "../../../../miniprogram_npm/tdesign/date-time-picker/date-time-picker", "l-icon": "../../../../miniprogram_npm/lin-ui/icon/index"
"t-cell": "../../../../miniprogram_npm/tdesign/cell/cell",
"t-input": "../../../../miniprogram_npm/tdesign/input/input",
"t-icon": "../../../../miniprogram_npm/tdesign/icon/icon"
} }
} }

View File

@ -16,22 +16,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #fff; background-color: #fff;
}
.pannel-item {
display: flex;
align-items: center;
height: 96rpx;
padding: 0 32rpx;
font-size: 32rpx;
background-color: #fff;
}
.pannel-label { .label {
width: 160rpx; color: @oak-text-color-primary;
margin-right: 32rpx;
} }
.pannel-text {
flex: 1;
opacity: 0.9;
} }

View File

@ -1,4 +1,5 @@
import {DateTime} from 'luxon'; import { EntityDict } from "../../../../general-app-domain";
const GenderOptions = [ const GenderOptions = [
{ {
value: 'male', label: '男', value: 'male', label: '男',
@ -20,12 +21,6 @@ const IDCardTypeOptions = [
} }
]; ];
const PICKER_KEY = {
SEX: 'sex',
IDCARD: 'idCard',
BIRTH: 'birth'
};
export default OakComponent({ export default OakComponent({
entity: 'user', entity: 'user',
projection: { projection: {
@ -41,79 +36,78 @@ export default OakComponent({
isList: false, isList: false,
formData: ({ data: user }) => { formData: ({ data: user }) => {
const { birth, gender, idCardType } = user || {}; const { birth, gender, idCardType } = user || {};
const birthText = birth && new Date(birth).toLocaleDateString(); const birthDate = birth && new Date(birth);
const birthText = birthDate && birthDate.toLocaleDateString();
const birthDayValue = birthDate && `${birthDate.getFullYear()}-${birthDate.getMonth() + 1}-${birthDate.getDate()}`;
const GenderDict = { const GenderDict = {
male: '男', male: '男',
female: '女', female: '女',
}; };
const genderText = gender && GenderDict[gender]; const genderOption = gender && GenderOptions.find(
const genderIndex = ele => ele.value === gender
gender && GenderOptions.find((ele) => ele.value === gender); );
const IdCardTypeDict = { const genderText = genderOption && genderOption.label;
'ID-Card': '身份证', const genderOptionIndex = genderOption && GenderOptions.indexOf(genderOption);
passport: '护照', const idCardTypeOption = idCardType && IDCardTypeOptions.find(
'Mainland-passport': '港澳通行证', ele => ele.value === idCardType
}; );
const idCardTypeText = idCardType && IdCardTypeDict[idCardType]; const idCardTypeText = idCardTypeOption && idCardTypeOption.label;
const idCardTypeOptionIndex = idCardTypeOption && IDCardTypeOptions.indexOf(idCardTypeOption);
const idCardTypeIndex = const idCardTypeIndex =
idCardType && IDCardTypeOptions.find((ele) => ele.value === gender); idCardType && IDCardTypeOptions.find((ele) => ele.value === gender);
const now = new Date(); const now = new Date();
return Object.assign({}, user, { return Object.assign({}, user, {
birthText, birthText,
birthDayValue,
genderText, genderText,
idCardTypeText, idCardTypeText,
idCardTypeOptionIndex,
oldestBirthday: `${now.getFullYear() - 120}-01-01`, oldestBirthday: `${now.getFullYear() - 120}-01-01`,
today: `${now.getFullYear()}-${ today: `${now.getFullYear()}-${
now.getMonth() + 1 now.getMonth() + 1
}-${now.getDate()}`, }-${now.getDate()}`,
genderIndex, genderOptionIndex,
idCardTypeIndex, idCardTypeIndex,
}); });
}, },
data: { data: {
birthEnd: '', // for小程序的picker
GenderOptions, GenderOptions,
IDCardTypeOptions, IDCardTypeOptions,
PICKER_KEY,
birthVisible: false, birthVisible: false,
}, },
lifetimes: {
ready() {
const today = new Date();
const birthEnd = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
this.setState({ birthEnd });
}
},
methods: { methods: {
setValue(input: any) { setValueMp(input: WechatMiniprogram.Input) {
console.log(input, 123); const { detail, target: { dataset }} = input;
const { dataset, value } = this.resolveInput(input); const { attr } = dataset!;
const { key } = dataset; const { value } = detail;
if (['sex', 'idCard'].includes(key)) { this.update({[attr]: value});
this.update({[dataset!.attr]: value[0]});
return;
}
if (key === 'birth') {
this.update({[dataset!.attr]: value});
this.setState({
birthVisible: false,
});
return;
}
this.update({[dataset!.attr]: value[0]});
}, },
async confirm() { async confirmMp() {
await this.execute(); await this.execute();
if (this.props.oakFrom === 'user:manage:list') {
this.navigateBack(); this.navigateBack();
} else if (this.props.oakFrom === 'user:manage:detail') {
this.navigateBack();
}
}, },
onClickPicker(e: any) { onBirthChange(e: WechatMiniprogram.Input) {
const { key } = e?.currentTarget?.dataset; const { detail: { value }} = e;
const birth = new Date(value);
this.setState({ this.update({ birth });
[`${key}Visible`]: true,
});
}, },
onPickerClose(e: any) { onIdCardTypeChange(e: any) {
const { key } = e?.currentTarget?.dataset; const { detail: { value: index }} = e;
this.setState({ const { value } = IDCardTypeOptions[index];
[`${key}Visible`]: false, this.update({ idCardType: value as EntityDict['user']['OpSchema']['idCardType'] });
}); },
onGenderChange(e: any) {
const { detail: { value: index }} = e;
const { value } = GenderOptions[index];
this.update({ gender: value as EntityDict['user']['OpSchema']['gender'] });
}, },
}, },
}); });

View File

@ -1,50 +1,27 @@
<!-- index.wxml --> <!-- index.wxml -->
<view class="page-body"> <view class="page-body">
<view class="col"> <view class="col">
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" oak:value="nickname" bind:change="setValue"> <l-input placeholder="请输入昵称" label="昵称" value="{{nickname}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="nickname" />
<text slot="label"> <l-input placeholder="请输入姓名" label="姓名" value="{{name}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="name" />
<text style="color: #e34d59">*</text>昵称 <picker range="{{GenderOptions}}" range-key="label" value="{{genderOptionIndex}}" bind:change="onGenderChange">
</text> <l-input label="性别" value="{{genderText || '选择证件类别'}}" disabled="{{true}}" l-label-class="label" >
</t-input> <l-icon slot="right" name="right" size="20" />
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" oak:value="name" bind:change="setValue"> </l-input>
<text slot="label"> </picker>
<text style="color: #e34d59">*</text>姓名 <picker mode="date" end="{{birthEnd}}" value="{{birthDayValue}}" bind:change="onBirthChange">
</text> <l-input label="出生日期" value="{{birthText || '选择日期'}}" disabled="{{true}}" l-label-class="label">
</t-input> <l-icon slot="right" name="right" size="20" />
<view class="pannel-item" bind:tap="onClickPicker" data-key="{{PICKER_KEY.SEX}}"> </l-input>
<view class="pannel-label"> </picker>
<text style="color: #e34d59">*</text>性别 <picker range="{{IDCardTypeOptions}}" range-key="label" value="{{idCardTypeOptionIndex}}" bind:change="onIdCardTypeChange">
</view> <l-input label="证件类别" value="{{idCardTypeText || '选择证件类别'}}" disabled="{{true}}" l-label-class="label" >
<view class="pannel-text">{{genderText || '选择性别'}}</view> <l-icon slot="right" name="right" size="20" />
<t-icon name="chevron-right" color="rgba(0, 0, 0, 0.26)" size="24px" /> </l-input>
</view> </picker>
<view class="pannel-item" bind:tap="onClickPicker" data-key="{{PICKER_KEY.IDCARD}}"> <l-input placeholder="请输入证件号" label="证件号" value="{{idNumber}}" confirm-type="next" bind:lininput="setValueMp" l-label-class="label" data-attr="idNumber" />
<view class="pannel-label">
<text style="color: #e34d59">*</text>证件类别
</view>
<view class="pannel-text">{{idCardTypeText || '选择证件类别'}}</view>
<t-icon name="chevron-right" color="rgba(0, 0, 0, 0.26)" size="24px" />
</view>
<view class="pannel-item" bind:tap="onClickPicker" data-key="{{PICKER_KEY.BIRTH}}">
<view class="pannel-label">
<text style="color: #e34d59">*</text>出生日期
</view>
<view class="pannel-text">{{birthText || '选择日期'}}</view>
<t-icon name="chevron-right" color="rgba(0, 0, 0, 0.26)" size="24px" />
</view>
<t-picker data-key="{{PICKER_KEY.SEX}}" visible="{{sexVisible}}" oak:value="gender" title="选择性别" cancelBtn="取消" confirmBtn="确认" bindchange="setValue" bindcancel="onPickerClose" bindconfirm="onPickerClose">
<t-picker-item options="{{GenderOptions}}"></t-picker-item>
</t-picker>
<t-picker data-key="{{PICKER_KEY.IDCARD}}" visible="{{idCardVisible}}" oak:value="idCardType" title="选择证件类型" cancelBtn="取消" confirmBtn="确认" bindchange="setValue" bindcancel="onPickerClose" bindconfirm="onPickerClose">
<t-picker-item options="{{IDCardTypeOptions}}"></t-picker-item>
</t-picker>
<t-input placeholder="请输入" label="slot" size="medium" type="number" confirm-type="done" oak:value="idNumber" bind:change="setValue">
<text slot="label">
<text style="color: #e34d59">*</text>证件号
</text>
</t-input>
<t-date-time-picker title="选择日期和时间" data-key="{{PICKER_KEY.BIRTH}}" data-attr="birth" visible="{{birthVisible}}" default-value="{{today}}" mode="date" value="{{birthText}}" format="YYYY-MM-DD" bindchange="setValue" bindcancel="onPickerClose" start="{{oldestBirthday}}" end="{{today}}"></t-date-time-picker>
</view> </view>
<view style="flex: 1" /> <view style="flex: 1" />
<t-button theme="primary" disabled="{{oakExecuting || !oakDirty}}" style="margin: 16rpx" loading="{{oakExecuting}}" block size="large" bind:tap="confirm" content="确定" /> <l-button type="default" disabled="{{oakExecuting || !oakDirty}}" loading="{{oakExecuting}}" size="long" bind:lintap="confirmMp">
{{t('common:action.confirm')}}
</l-button>
</view> </view>

View File

@ -9,6 +9,7 @@ import { ROOT_ROLE_ID, ROOT_USER_ID } from '../constants';
import { addFilterSegment } from 'oak-domain/lib/store/filter'; import { addFilterSegment } from 'oak-domain/lib/store/filter';
import { randomName } from '../utils/randomUser'; import { randomName } from '../utils/randomUser';
import { RuntimeCxt } from '../types/RuntimeCxt'; import { RuntimeCxt } from '../types/RuntimeCxt';
import { OakRowInconsistencyException } from 'oak-domain/lib/types';
let NO_ANY_USER = true; let NO_ANY_USER = true;
const triggers: Trigger<EntityDict, 'user', RuntimeCxt>[] = [ const triggers: Trigger<EntityDict, 'user', RuntimeCxt>[] = [
@ -105,10 +106,14 @@ const triggers: Trigger<EntityDict, 'user', RuntimeCxt>[] = [
entity: 'user', entity: 'user',
action: 'play', action: 'play',
when: 'after', when: 'after',
fn: async ({ operation }, context) => { fn: async ({ operation }, context, option) => {
const { filter } = operation; const { filter } = operation;
assert(filter!.id); assert(filter!.id);
const { id } = context.getToken()!; const token = context.getToken()!;
const { id, userId } = token;
if (userId === filter!.id) {
throw new OakRowInconsistencyException(undefined, '您已经是当前用户');
}
await context.operate('token', { await context.operate('token', {
id: generateNewId(), id: generateNewId(),
action: 'update', action: 'update',
@ -118,9 +123,7 @@ const triggers: Trigger<EntityDict, 'user', RuntimeCxt>[] = [
filter: { filter: {
id, id,
} }
}, { }, option);
dontCollect: true,
});
return 1; return 1;
} }
} as UpdateTrigger<EntityDict, 'user', RuntimeCxt>, } as UpdateTrigger<EntityDict, 'user', RuntimeCxt>,