This commit is contained in:
梁朝伟 2022-07-26 19:21:51 +08:00
parent 0ca74d9787
commit 5545291a92
20 changed files with 1102 additions and 45 deletions

View File

@ -1,3 +1,5 @@
@import "../../miniprogram_npm/tdesign/common/style/_variables.less";
@import "./_theme.less";
// Color

View File

@ -3,81 +3,47 @@
<view class="col">
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" oak:value="nickname" bind:change="setValue">
<text slot="label">
<text style="color: #e34d59"> *</text>昵称
<text style="color: #e34d59">*</text>昵称
</text>
</t-input>
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" oak:value="name" bind:change="setValue">
<text slot="label">
<text style="color: #e34d59"> *</text>姓名
<text style="color: #e34d59">*</text>姓名
</text>
</t-input>
<view class="pannel-item" bind:tap="onClickPicker" data-key="{{PICKER_KEY.SEX}}">
<view class="pannel-label">
<text style="color: #e34d59"> *</text>性别
<text style="color: #e34d59">*</text>性别
</view>
<view class="pannel-text">{{genderText || '选择性别'}}</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.IDCARD}}">
<view class="pannel-label">
<text style="color: #e34d59"> *</text>证件类别
<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>出生日期
<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 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 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 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>
<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 style="flex: 1" />
<t-button theme="primary" disabled="{{oakExecuting || !oakDirty}}" style="margin: 16rpx" loading="{{oakExecuting}}" block size="large" bind:tap="confirm" content="确定" />

View File

@ -0,0 +1,11 @@
{
"navigationBarTitleText": "修改权限",
"usingComponents": {
"t-checkbox": "../../../miniprogram_npm/tdesign/checkbox/checkbox",
"t-checkbox-group": "../../../miniprogram_npm/tdesign/checkbox-group/checkbox-group",
"t-tag": "../../../miniprogram_npm/tdesign/tag/tag",
"t-icon": "../../../miniprogram_npm/tdesign/icon/icon",
"t-divider": "../../../miniprogram_npm/tdesign/divider/divider",
"t-button": "../../../miniprogram_npm/tdesign/button/button"
}
}

View File

@ -0,0 +1,65 @@
/** index.wxss **/
@import "../../../config/styles/_base.less";
@import "../../../config/styles/_mixins.less";
page {
height: 100%;
background-color: #fff;
}
.container {
height: 100%;
display: flex;
flex: 1;
flex-direction: column;
box-sizing: border-box;
align-items: stretch;
padding: 0;
.safe-area-inset-bottom();
}
.content {
display: flex;
flex-direction: column;
flex: 1;
}
.row {
display: flex;
align-items: center;
padding: @spacer-2;
}
.col {
display: flex;
flex: 1;
flex-direction: column;
margin-left: @spacer-2;
}
.nickname {
margin-right: @spacer-1;
font-size: @font-size-l;
}
.mobile {
font-size: @font-size-base;
color: @text-level-3-color;
}
.avatar {
height: 140rpx;
width: 140rpx;
border-radius: 50%;
}
.img-view {
display: flex;
align-items: center;
justify-content: center;
height: 140rpx;
width: 140rpx;
border-radius: 50%;
background-color: @bg-color;
}
.row2 {
display: flex;
align-items: center;
margin-bottom: @spacer-1;
}

View File

@ -0,0 +1,125 @@
import { firstLetterUpperCase } from "oak-domain/lib/utils/string";
import { composeFileUrl } from "../../../../src/utils/extraFile";
export default OakPage(
{
path: 'userRelation:detail',
entity: 'user',
projection: async ({ props }) => {
const { entity, entityId } = props;
const entityStr = firstLetterUpperCase(entity!);
return {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
userId: 1,
mobile: 1,
},
},
[`user${entityStr}$user`]: {
$entity: `user${entityStr}`,
data: {
id: 1,
userId: 1,
[`${entity}Id`]: 1,
relation: 1,
},
filter: {
[`${entity}Id`]: entityId,
}
},
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: async ({ data: user, props }) => {
const { entity, relations } = props;
const entityStr = firstLetterUpperCase(entity!);
const relationArr: Array<any> = [];
const {
id,
nickname,
idState,
userState,
name,
mobile$user,
extraFile$entity,
} = user || {};
let userRelations = user && user[`user${entityStr}$user`] as Array<any>;
userRelations = userRelations?.map(ele => ele.relation);
relations.forEach(ele => {
relationArr.push({
checked: userRelations.includes(ele),
value: ele,
});
})
const mobile = mobile$user && mobile$user[0]?.mobile;
const avatar =
extraFile$entity &&
extraFile$entity[0] &&
composeFileUrl(extraFile$entity[0]);
return {
id,
nickname,
name,
mobile,
avatar,
userState,
idState,
relationArr,
};
},
properties: {
entity: String,
entityId: String,
relations: Array,
},
data: {
stateColor: {
shadow: 'primary',
normal: 'success',
disabled: ''
},
},
methods: {
onChange(event: any) {
const { entity, entityId } = this.props;
const { value } = event.currentTarget.dataset.value;
const { checked } = event.detail;
const entityStr = firstLetterUpperCase(entity!);
const nodeData = {
[`${entity}Id`]: entityId,
relation: value,
}
this.toggleNode(nodeData, checked, `user${entityStr}$user`);
},
async onConfirm() {
await this.execute('grant');
await this.navigateBack();
}
},
}
);

View File

@ -0,0 +1,34 @@
import React, { Component } from 'react';
import { Input, Card, Avatar } from 'antd';
const Search = Input.Search;
const Meta = Card.Meta;
export default function render() {
const { rows } = this.state;
return (
<div>
<Search
placeholder="请输入"
value={this.state.searchValue || ''}
enterButton="搜索"
size="middle"
loading={this.state.oakLoading}
onChange={this.searchChange}
allowClear
onSearch={(value, event) => {
// value清空
if (value) {
this.searchConfirm();
} else {
this.searchCancel();
}
}}
/>
{rows?.map((item, index) => {
<Card key={index} onClick={this.handleCardClick}>
<Meta title={item.name} />
</Card>;
})}
</div>
);
}

View File

@ -0,0 +1,31 @@
<!-- index.wxml -->
<view class="container">
<view class="content">
<view class="row">
<block wx:if="{{avatar}}">
<image class="avatar" src="{{avatar}}" mode="aspectFit" />
</block>
<block wx:else>
<view class="img-view">
<t-icon name="icon" size="xl" />
</view>
</block>
<view class="col">
<view class="row2">
<text class="nickname">{{nickname || '未设置'}}</text>
<t-tag theme="{{stateColor[userState]}}" shape="round">{{userState}}</t-tag>
</view>
<text class="mobile">姓名: {{name || '未设置'}}</text>
<text class="mobile">手机: {{mobile || '未设置'}}</text>
</view>
</view>
<t-divider t-class="demo-1" t-class-content="t-class-content">
<text slot="content">权限设置</text>
</t-divider>
<block wx:for="{{relationArr}}">
<t-checkbox data-value="{{item}}" checked="{{item.checked}}" label="{{item.value}}" bind:change="onChange" />
</block>
</view>
<view class=""></view>
<t-button theme="primary" bind:tap="onConfirm" block>保存</t-button>
</view>

View File

@ -107,11 +107,12 @@ export default OakPage(
},
lifetimes: {},
methods: {
onRemove(event: any) {
const { index } = event.target.dataset;
this.setState({
show: true,
deleteIndex: index,
deleteIndex: Number(index),
})
},
cancelDelete() {
@ -124,7 +125,7 @@ export default OakPage(
const { entity } = this.props;
const entityStr = firstLetterUpperCase(entity);
const { deleteIndex } = this.state;
typeof deleteIndex === 'number' && this.toggleNode({}, false, `${deleteIndex}.user${entityStr}$user`);
typeof deleteIndex === 'number' && this.removeNode(`user.user${entityStr}$user`, deleteIndex);
this.setState({
show: false,
deleteIndex: '',

View File

@ -0,0 +1,12 @@
{
"navigationBarTitleText": "修改权限",
"usingComponents": {
"t-button": "../../../miniprogram_npm/tdesign/button/button",
"t-dialog": "../../../miniprogram_npm/tdesign/dialog/dialog",
"t-divider": "../../../miniprogram_npm/tdesign/divider/divider",
"t-tag": "../../../miniprogram_npm/tdesign/tag/tag",
"t-fab": "../../../miniprogram_npm/tdesign/fab/fab",
"t-icon": "../../../miniprogram_npm/tdesign/icon/icon",
"fab": "../../../components/UI/fab/index"
}
}

View File

@ -0,0 +1,72 @@
/** index.wxss **/
@import "../../../config/styles/_base.less";
@import "../../../config/styles/_mixins.less";
page {
height: 100%;
background-color: @bg-color;
}
.container {
height: 100%;
display: flex;
flex: 1;
flex-direction: column;
box-sizing: border-box;
align-items: stretch;
padding: 0;
.safe-area-inset-bottom();
}
.card-view {
margin: @spacer-2;
margin-bottom: 0rpx;
padding: @spacer-2;
border-radius: 4rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 20rpx 0 rgba(212, 217, 223, 0.5);
background-color: #fff;
}
.row {
margin-left: @spacer-2;
display: flex;
flex: 1;
align-items: center;
}
.col {
display: flex;
flex: 1;
flex-direction: column;
}
.nickname {
margin-bottom: 8rpx;
font-size: @font-size-l;
}
.mobile {
font-size: @font-size-base;
color: @text-level-2-color;
}
.avatar {
height: 140rpx;
width: 140rpx;
border-radius: 50%;
}
.img-view {
display: flex;
align-items: center;
justify-content: center;
height: 140rpx;
width: 140rpx;
border-radius: 50%;
background-color: @bg-color;
}
.realtion {
display: flex;
align-items: center;
flex-wrap: wrap;
font-size: @font-size-base;
color: @text-level-2-color;
}

View File

@ -0,0 +1,224 @@
import React, { useState, useMemo, useRef, useEffect } from 'react';
import { Table, Input, Select, DatePicker, MessagePlugin, Button } from 'tdesign-react';
export default function render() {
function setEditableRowKeys(arr: Array<string>){
this.setState({
editableRowKeys: arr,
})
};
function init() {
const initData = new Array(5).fill(null).map((_, i) => ({
key: String(i + 1),
firstName: ['Eric', 'Gilberta', 'Heriberto', 'Lazarus', 'Zandra'][i % 4],
framework: ['Vue', 'React', 'Miniprogram', 'Flutter'][i % 4],
email: [
'espinke0@apache.org',
'gpurves1@issuu.com',
'hkment2@nsw.gov.au',
'lskures3@apache.org',
'zcroson5@virginia.edu',
][i % 4],
letters: [['A'], ['B', 'E'], ['C'], ['D', 'G', 'H']][i % 4],
createTime: ['2021-11-01', '2021-12-01', '2022-01-01', '2022-02-01', '2022-03-01'][i % 4],
}));
this.setState({
data: [...initData],
});
setEditableRowKeys(['1']);
}
let currentSaveId = '';
// 保存变化过的行信息
const editMap = {};
const onEdit = (e) => {
const { editableRowKeys } = this.state;
const { id } = e.currentTarget.dataset;
if (!editableRowKeys.includes(id)) {
setEditableRowKeys(editableRowKeys.concat(id));
}
};
// 更新 editableRowKeys
const updateEditState = (id) => {
const { editableRowKeys } = this.state;
const index = editableRowKeys.findIndex((t) => t === id);
editableRowKeys.splice(index, 1);
setEditableRowKeys([...editableRowKeys]);
};
const onCancel = (e) => {
const { id } = e.currentTarget.dataset;
updateEditState(id);
this.tableRef.current.clearValidateData();
};
const onSave = (e) => {
const { id } = e.currentTarget.dataset;
currentSaveId = id;
// 触发内部校验,而后在 onRowValidate 中接收异步校验结果
this.tableRef.current.validateRowData(id);
};
const onRowValidate = (params) => {
console.log('validate:', params);
const { data } = this.state;
if (params.result.length) {
const r = params.result[0];
MessagePlugin.error(`${r.col.title} ${r.errorList[0].message}`);
return;
}
// 如果是 table 的父组件主动触发校验
if (params.trigger === 'parent' && !params.result.length) {
const current = editMap[currentSaveId];
if (current) {
data.splice(current.rowIndex, 1, current.editedRow);
this.setState({
data: [...data],
})
MessagePlugin.success('保存成功');
}
updateEditState(currentSaveId);
}
};
const onRowEdit = (params) => {
const { row, col, value } = params;
const oldRowData = editMap[row.key]?.editedRow || row;
editMap[row.key] = {
...params,
editedRow: { ...oldRowData, [col.colKey]: value },
};
};
const columns = useMemo(
() => [
{
title: 'FirstName',
colKey: 'firstName',
align: 'left',
// 编辑状态相关配置,全部集中在 edit
edit: {
// 1. 支持任意组件。需保证组件包含 `value` 和 `onChange` 两个属性,且 onChange 的第一个参数值为 new value。
// 2. 如果希望支持校验,组件还需包含 `status` 和 `tips` 属性。具体 API 含义参考 Input 组件
component: Input,
// props, 透传全部属性到 Input 组件
props: {
clearable: true,
autofocus: true,
autoWidth: true,
},
// 校验规则,此处同 Form 表单
rules: [
{ required: true, message: '不能为空' },
{ max: 10, message: '字符数量不能超过 10', type: 'warning' },
],
showEditIcon: false,
},
},
{
title: 'Framework',
colKey: 'framework',
edit: {
component: Select,
// props, 透传全部属性到 Select 组件
props: {
clearable: true,
autoWidth: true,
options: [
{ label: 'Vue', value: 'Vue' },
{ label: 'React', value: 'React' },
{ label: 'Miniprogram', value: 'Miniprogram' },
{ label: 'Flutter', value: 'Flutter' },
],
},
showEditIcon: false,
},
},
{
title: 'Letters',
colKey: 'letters',
cell: ({ row }) => row?.letters?.join('、'),
edit: {
component: Select,
// props, 透传全部属性到 Select 组件
// props 为函数时参数有col, row, rowIndex, colIndex, editedRow。一般用于实现编辑组件之间的联动
props: ({ editedRow }) => ({
multiple: true,
minCollapsedNum: 1,
autoWidth: true,
options: [
{ label: 'A', value: 'A' },
{ label: 'B', value: 'B' },
{ label: 'C', value: 'C' },
{ label: 'D', value: 'D' },
{ label: 'E', value: 'E' },
// 如果框架选择了 React则 Letters 隐藏 G 和 H
{ label: 'G', value: 'G', show: () => editedRow.framework !== 'React' },
{ label: 'H', value: 'H', show: () => editedRow.framework !== 'React' },
].filter(t => (t.show === undefined ? true : t.show())),
}),
showEditIcon: false,
},
},
{
title: 'Date',
colKey: 'createTime',
className: 't-demo-col__datepicker',
// props, 透传全部属性到 DatePicker 组件
edit: {
component: DatePicker,
showEditIcon: false,
},
},
{
title: 'Operate',
colKey: 'operate',
width: 150,
cell: ({ row }) => {
const {}
const editable = editableRowKeys.includes(row.key);
return (
<div className="table-operations">
{!editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onEdit}>
</Button>
)}
{editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onSave}>
</Button>
)}
{editable && (
<Button theme="primary" variant="text" data-id={row.key} onClick={onCancel}>
</Button>
)}
</div>
);
},
}
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[data, editableRowKeys],
);
// 当前示例包含:输入框、单选、多选、日期 等场景
return (
<div className="t-table-demo__editable-row">
<Table
ref={tableRef}
rowKey="key"
columns={columns}
data={data}
editableRowKeys={editableRowKeys}
onRowEdit={onRowEdit}
onRowValidate={onRowValidate}
bordered
/>
</div>
);
}

View File

@ -0,0 +1,197 @@
import { firstLetterUpperCase } from 'oak-domain/lib/utils/string';
import { composeFileUrl } from '../../../../src/utils/extraFile';
import React from 'react';
export default OakPage(
{
path: 'userRelation:list',
entity: 'user',
projection: async ({ props }) => {
const { entity, entityId, relation } = props;
const entityStr = firstLetterUpperCase(entity!);
return {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
userId: 1,
mobile: 1,
},
},
[`user${entityStr}$user`]: {
$entity: `user${entityStr}`,
data: {
id: 1,
userId: 1,
[`${entity}Id`]: 1,
relation: 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,
},
};
},
filters: [
// 由调用者注入oakFilter
{
filter: async ({ features, props, onLoadOptions }) => {
const { entityId, entity } = props;
const entityStr = firstLetterUpperCase(entity!);
return {
id: {
$in: {
entity: `user${entityStr}`,
data: {
userId: 1,
},
filter: {
[`${entity}Id`]: entityId,
}
},
},
};
},
},
],
isList: true,
formData: async function ({ data: users, props, features }) {
const { entity } = props;
const entityStr = firstLetterUpperCase(entity!);
const filter = await this.getFilterByName('name');
return {
users: users?.map((ele: any) => {
const { mobile$user, extraFile$entity, [`user${entityStr}$user`]: userEntities } =
ele || {};
const mobile = mobile$user && mobile$user[0]?.mobile;
const avatar =
extraFile$entity &&
extraFile$entity[0] &&
composeFileUrl(extraFile$entity[0]);
const user2 = Object.assign({}, ele, {
mobile,
avatar,
relations: userEntities,
hasRelation: userEntities.length > 0,
});
return user2;
}),
};
},
properties: {
entity: String,
entityId: String,
userIds: Array,
relations: Array,
},
data: {
show: false,
searchValue: '',
deleteIndex: '',
},
lifetimes: {
created() {
if (process.env.OAK_PLATFORM === 'web') {
const classStyles = `
<style>
.t-table-demo__editable-row .table-operations > button {
padding: 0 8px;
line-height: 22px;
height: 22px;
}
.t-table-demo__editable-row .t-demo-col__datepicker .t-date-picker {
width: 120px;
}
</style>
`;
this.tableRef = React.createRef();
document.head.insertAdjacentHTML('beforeend', classStyles);
}
}
},
methods: {
goDetail(e: any) {
const { relations, entity, entityId } = this.props;
const { id } = e.currentTarget.dataset;
this.navigateTo({
url: '/userRelation/detail2',
oakId: id,
relations,
entity,
entityId,
})
},
goUpsert() {
const { entity, entityId, relations } = this.props;
this.navigateTo({
url: '/userRelation/upsert',
entity,
entityId,
relations,
})
},
onRemove(event: any) {
const { index } = event.target.dataset;
this.setState({
show: true,
deleteIndex: Number(index),
})
},
cancelDelete() {
this.setState({
show: false,
deleteIndex: '',
})
},
confirmDelete() {
const { entity } = this.props;
const entityStr = firstLetterUpperCase(entity);
const { deleteIndex } = this.state;
typeof deleteIndex === 'number' && this.removeNode(`user.user${entityStr}$user`, deleteIndex);
this.setState({
show: false,
deleteIndex: '',
})
},
onAdd(event: any) {
const { entity, entityId, relation } = this.props;
const entityStr = firstLetterUpperCase(entity);
const { index } = event.target.dataset;
this.toggleNode({
[`${entity}Id`]: entityId,
relation,
}, true, `${index}.user${entityStr}$user`);
},
async confirm() {
await this.execute();
this.navigateBack();
},
goSearch() {
this.navigateTo({
url: '/user/search',
toUrl: '/userRelation/detail'
})
}
},
}
);

View File

@ -0,0 +1,9 @@
import * as React from 'react';
export default function render() {
return (
<div>
userList
</div>
);
}

View File

@ -0,0 +1,34 @@
<!-- index.wxml -->
<view class="container">
<view class="col">
<block wx:for="{{users}}" wx:key="index">
<view class="card-view" data-id="{{item.id}}" bind:tap="goDetail">
<block wx:if="{{item.avatar}}">
<image class="avatar" src="{{item.avatar}}" mode="aspectFit" />
</block>
<block wx:else>
<view class="img-view">
<t-icon name="image" size="xl" />
</view>
</block>
<view class="row">
<view class="col">
<text class="nickname">{{item.nickname || '未设置'}}</text>
<text class="mobile">姓名: {{item.name || '未设置'}}</text>
<text class="mobile">手机: {{item.mobile || '未设置'}}</text>
<view class="realtion">
权限:
<block wx:if="{{item.relations.length}}" wx:for="{{item.relations}}" wx:for-item="item2" wx:for-index="index2" wx:key="index2">
<text>{{item2.relation}}</text>
<block wx:if="{{index2 !== item.relations.length - 1}}">
<t-divider layout="vertical"></t-divider>
</block>
</block>
</view>
</view>
</view>
</view>
</block>
<t-fab icon="add" bind:click="goUpsert" />
</view>
</view>

View File

@ -0,0 +1,11 @@
{
"navigationBarTitleText": "修改权限",
"usingComponents": {
"t-checkbox": "../../../miniprogram_npm/tdesign/checkbox/checkbox",
"t-checkbox-group": "../../../miniprogram_npm/tdesign/checkbox-group/checkbox-group",
"t-input": "../../../miniprogram_npm/tdesign/input/input",
"t-tag": "../../../miniprogram_npm/tdesign/tag/tag",
"t-icon": "../../../miniprogram_npm/tdesign/icon/icon",
"t-button": "../../../miniprogram_npm/tdesign/button/button"
}
}

View File

@ -0,0 +1,28 @@
/** index.wxss **/
@import "../../../config/styles/_base.less";
@import "../../../config/styles/_mixins.less";
page {
height: 100%;
background-color: @bg-color;
}
.container {
height: 100%;
display: flex;
flex: 1;
flex-direction: column;
box-sizing: border-box;
align-items: stretch;
padding: 0;
.safe-area-inset-bottom();
}
.col {
display: flex;
flex-direction: column;
}
.btn-view {
display: flex;
margin: 0rpx @spacer-2;
}

View File

@ -0,0 +1,119 @@
import * as React from 'react';
import { Form, Input, Radio, Checkbox, Button, Switch, MessagePlugin, DatePicker, Tooltip, CheckboxGroup } from 'tdesign-react';
const { FormItem } = Form;
export default function render() {
const { name, mobile } = this.state;
return (
<div>
<Form
colon={false}
labelAlign="right"
labelWidth="100px"
layout="vertical"
preventSubmitDefault
resetType="empty"
showErrorMessage
submitWithWarningMessage={false}
>
<FormItem
label="姓名"
name="name"
successBorder={false}
>
<Input
onChange={(value, context) => {
this.setUpdateData('name', value);
}}
value={name}
align="left"
autoWidth={false}
autofocus={false}
clearable={false}
defaultValue=""
placeholder="请输入内容"
readonly={false}
showClearIconOnEmpty={false}
size="medium"
status="default"
type="text"
/>
</FormItem>
<FormItem
label="手机号码"
name="mobile"
successBorder={false}
>
<Input
value={mobile}
align="left"
autoWidth={false}
autofocus={false}
clearable={false}
defaultValue=""
placeholder="请输入内容"
readonly={false}
showClearIconOnEmpty={false}
size="medium"
status="default"
type="text"
/>
</FormItem>
<FormItem
initialData={[
'1'
]}
label="课程"
name="course"
successBorder={false}
>
<Checkbox.Group
defaultValue={[]}
max={undefined}
>
<Checkbox
checkAll={false}
defaultChecked={false}
disabled={undefined}
indeterminate={false}
readonly={false}
value="1"
>
</Checkbox>
<Checkbox
checkAll={false}
defaultChecked={false}
disabled={undefined}
indeterminate={false}
readonly={false}
value="2"
>
</Checkbox>
<Checkbox
checkAll={false}
defaultChecked={false}
disabled={undefined}
indeterminate={false}
readonly={false}
value="3"
>
</Checkbox>
<Checkbox
checkAll={false}
defaultChecked={false}
disabled={undefined}
indeterminate={false}
readonly={false}
value="4"
>
</Checkbox>
</Checkbox.Group>
</FormItem>
</Form>
</div>
);
}

View File

@ -0,0 +1,74 @@
import { firstLetterUpperCase } from "oak-domain/lib/utils/string";
import { composeFileUrl } from "../../../../src/utils/extraFile";
export default OakPage(
{
path: 'userRelation:upsert',
entity: 'user',
projection: async ({ props }) => {
const { entity, entityId, relation } = props;
const entityStr = firstLetterUpperCase(entity!);
return {
id: 1,
name: 1,
password: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
userId: 1,
mobile: 1,
},
},
[`user${entityStr}$user`]: {
$entity: `user${entityStr}`,
data: {
id: 1,
userId: 1,
[`${entity}Id`]: 1,
relation: 1,
},
},
};
},
isList: false,
formData: async ({ data: user, props }) => {
const { entity, relations } = props;
const {
id,
name,
mobile$user,
password,
} = user || {};
const mobile = mobile$user && mobile$user[0]?.mobile;
return {
id,
name,
mobile,
password,
};
},
properties: {
entity: String,
entityId: String,
relations: Array,
},
data: {
mobile: '',
},
methods: {
setValue(input: any) {
const { dataset, value, Context } = this.resolveInput(input);
this.setUpdateData(dataset!.attr, value);
},
onMobileChange(event:any) {
const { value } = event.detail;
this.setState({
mobile: value,
})
this.setUpdateData('mobile$user.0.mobile', value);
}
},
}
);

View File

@ -0,0 +1,10 @@
import * as React from 'react';
export default function render() {
return (
<div>
userUpsertMobile
</div>
);
}

View File

@ -0,0 +1,32 @@
<!-- index.wxml -->
<view class="container">
<!-- index.wxml -->
<view class="page-body">
<view class="col">
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="done" oak:value="name" bind:change="setValue">
<text slot="label">
<text style="color: #e34d59">*</text>姓名
</text>
</t-input>
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" value="{{mobile}}" bind:change="onMobileChange">
<text slot="label">
<text style="color: #e34d59">*</text>手机号
</text>
</t-input>
<t-input placeholder="请输入" label="slot" size="medium" confirm-type="next" oak:value="password" bind:change="setValue">
<text slot="label">
<text style="color: #e34d59">*</text>密码
</text>
</t-input>
<t-checkbox-group bind:change="onCheckBoxChange">
<block wx:for="{{relations}}">
<t-checkbox value="{{item}}" label="{{item}}" />
</block>
</t-checkbox-group>
</view>
<view style="flex: 1" />
<view class="btn-view">
<t-button theme="primary" bind:tap="onConfirm" block>确定</t-button>
</view>
</view>
</view>